altavir
10/22/2020, 6:39 AMbreandan
10/24/2020, 4:51 AMval x = bind(x)
mean, how can you bind x
before it is declared? Or is this just a name shadowing issue? It seems like there are some captured variables from outside the lambda scope being brought inside and rebound:
val x by symbol
val y by symbol
val res: Double = diff(3, x to 1.0, y to 1.0) {
val x = bind(x)//by binding()
val y = symbol("y")
val z = x * (-sin(x * y) + y)
z.derivative(x)
}
When you say,
The binding is unavoidable since many operations (like autodiffs) require forward variable declaration.I don't understand why
val x = bind(x)
is necessary to write inside the lambda, it seems like it should be possible to infer this from the context, or pass into the lambda through a parameter. Also, why does diff(3, x to 1.0, y to 1.0)
have three arguments in the above example? If possible, I would try to get this form somehow:
val x by symbol
val y by symbol
val res: Double = diff(x to 1.0, y to 1.0) { x, y ->
val z = x * (-sin(x * y) + y)
z.derivative(x)
}
Is it necessary to wrap everything inside a diff {...}
context or is there a way to hide this inside the call to .derivative(x)
)? Ideally, it ought to be possible to avoid the wrapper altogether:
val x by symbol
val y by symbol
val z = x * (-sin(x * y) + y)
val res = z.autoDiff(x to 3.0, y to 1.0) // or alternately z.autoDiff(x)(x to 3.0, y to 1.0)
Although I can also understand if this syntax is not possible for API design reasons.
In the second example, if you see val expr = diff{val x = bind(x); x + x}
alone, it is not obvious what diff{ ... }
without any variables is supposed to mean. If we later take diff {...}.derivative(x)
is this the second derivative? Maybe using diff(x to 1.0, y to 2.0) { ... }
upfront make more sense.altavir
10/24/2020, 6:04 AMx
outside the context and x
bound inside the context are two different x from the point of view of the program. The first one is Symbol
, the last one is for example SimpleAutoDiffValue
. We can't operate with Symbol
s because they are not bound to context and do not hold forward declared values.altavir
10/24/2020, 6:09 AMz
and algorithm used to produce it would depend on what library do you use for it. If we, for example, say that operations on symbols would produce commons-math autodiff expressions, I would not be able to use kotlingrad or other symbolic operations.
The meaning of diff
and dx
could be seen from the full test listing: https://github.com/mipt-npm/kmath/blob/feature/diff-api/kmath-core/src/commonTest/kotlin/kscience/kmath/expressions/SimpleAutoDiffTest.kt. They are just type-safe wrappers for the general APIaltavir
10/24/2020, 6:14 AMbind
operations, but it would require to diplicate all operations in the context for Symbol
as well. Actually, it is not so hard to do. And it could be added in a non-breaking way, so I will possibly try to do it. Sadly, I won't be able to just add those operations as extensions due to lack of multi-receivers, otherwise I would just write [ExpressionAlgebra, Symbol].plus()
extensions.