The following code is a very preliminary attempt at developing an autodiff
library in Nim (at least for now, mainly to learn about Nim's powerful template
and also possibly macro constructs).
type AddOp = object
type SubOp = object
type MulOp = object
type DivOp = object
type
DualExpr = concept x
isDual(x)
Operator = concept x
isOp(x)
Dual[T] = object
val: T
grad: T
DualUnaryExpr[Op: Operator, X: DualExpr] = object
x: X
DualBinaryExpr[Op: Operator, L, R: DualExpr] = object
l: L
r: R
type dual = Dual[float]
template isDual[T](x: T): bool = false
template isDual[T](x: Dual[T]): bool = true
template isDual[Op, X](x: DualUnaryExpr[Op, X]): bool = true
template isDual[Op, L, R](x: DualBinaryExpr[Op, L, R]): bool = true
template isOp[T](x: T): bool = false
template isOp(x: AddOp): bool = true
template isOp(x: SubOp): bool = true
template isOp(x: MulOp): bool = true
template isOp(x: DivOp): bool = true
template `+`[L, R](l: L, r: R) =
DualBinaryExpr[AddOp, L, R](l: l, r: r)
var x = dual(val: 1.0, grad: 1.0)
var y = dual(val: 2.0, grad: 0.0)
var z = x + y
echo isDual(1.0)
echo isDual(x)
echo isDual(y)
echo isDual(z)
Run
I get the following output
([https://play.nim-lang.org/#ix=1TVX)](https://play.nim-lang.org/#ix=1TVX\)):
Hint: used config file '/nim/config/nim.cfg' [Conf]
Hint: system [Processing]
Hint: widestrs [Processing]
Hint: io [Processing]
Hint: in [Processing]
/usercode/in.nim(45, 11) template/generic instantiation of `+` from here
/usercode/in.nim(40, 32) Error: undeclared field: 'x'
Run
What am I missing here?
I want eventually to be able to make autodiff computations such that an
expression tree is created at compile time, and the assignment operator
consumes this expression tree in an optimal way (e.g., avoiding temporaries,
optimizing the mathematical operations, etc.).