Summary
This release implements some new features and is an **API breaking release** (see note below about integer arguments).
This release also resolves the issue where `wrenfold-traits` was pinned to `nalegbra` version `0.32`.
Symbolic function invocation expressions
It is now possible to create an abstract symbolic function, which can be invoked with scalar-valued expression arguments. For example:
python
from wrenfold import sym
f = sym.Function('f')
x, y = sym.symbols('x, y')
g = f(x, sym.sin(y))
We can take derivatives of symbolic function invocations:
g.diff(x) produces: Derivative(f(x, y), x)
Taking the derivative of a symbolic function can be used to create abstract derivative expressions. This can be used to represent a function and its temporal derivatives `f(t), f'(t), f''(t)` symbolically as part of a larger expression.
Integer arguments are supported
You may now annotate function arguments (and members on custom types) as integral valued. Integral args will always be generated as `std::int64_t` (or `i64` in Rust) for now.
python
from wrenfold import sym, type_annotations, code_generation
def func(x: type_annotations.FloatScalar, mode: type_annotations.IntScalar):
Switch on the integer value to change behavior, for example...
return sym.where(sym.eq(mode, 1), sym.cos(x), sym.sin(x))
print(code_generation.generate_function(func, generator=code_generation.CppGenerator()))
Will produce:
cpp
template <typename Scalar>
Scalar func(const Scalar x, const std::int64_t mode)
{
// ...
const std::int64_t v001 = mode;
const Scalar v003 = x;
Scalar v009;
if (1 == v001) {
v009 = std::cos(v003);
} else {
v009 = std::sin(v003);
}
return v009;
}
Operations that combine integer and floating point values are automatically promoted to `Scalar` via `static_cast<>`. If float-scalar-valued values are assigned to integral output values, they are demoted via `static_cast<std::in64_t>`.
โ ๏ธ This is an **API breaking change** because all functions previously annotated with `sym.Expr` must now be annotated with `type_annotations.FloatScalar` (or `type_annotations.IntScalar`, in the case of an integer arg).
If previously you wrote:
python
from wrenfold import sym
def foo(x: sym.Expr):
... some expressions ...
`
You should _now_ write:
python
from wrenfold import type_annotations
def foo(x: type_annotations.FloatScalar):
... some expressions ...
conda-build recipe
We have added a conda-build recipe to the repository, and will shortly submit wrenfold `v0.1.0` to conda-forge.
๐ Features
- Add conda recipe and build scripts
- PR: 251
- Add deferred substitution and symbolic function invocation expressions
- PR: 254
- Add `compare()` function to the python wrapper to enable canonical ordering from python
- PR: 259
- Add standalone versions of the sym.subs and sym.distribute functions
- PR: 262
- Get rid of expression_group type, use any_expression to store function outputs
- PR: 263
- Support integer arguments to generated functions
- PR: 260
๐ Fixes
- Fix issue where `distribute` did not recurse, causing some products of fractional powers to not expand
- PR: 258
- Fix `__array__` method on MatrixExpr (missing kwargs)
- PR: 265
๐ Documentation
- Add architecture image to the documentation
- PR: 257
๐งน Cleanup
- Rename `code_numeric_type` --> `numeric_primitive_type` for clarity
- PR: 261