Simple vector algebra with Symbolics/SymbolicUtils

I am trying to define a simple symbolic vector type to use with the Symbolics and/or SymbolicUtils packages. I have looked through the documentation of these packages, but I am still at a loss. I am aware that Symbolics has symbolic arrays, but I don’t think that is quite what I am looking for.

Basically, I want a kind of symbol that represents a vector in Euclidean space. Vectors of the same dimension should be able to be added/subtracted/negated and multiplied by a scalar. Also, I want a dot product operation on two vectors that acts like a (symbolic) scalar and can be included in larger expressions involving other scalar variables. Here is my attempt.

using SymbolicUtils
using StaticArrays

const Vec = StaticVector  # vector type with "known" number of dimensions

@syms a b             # scalar quantities
@syms u::Vec v::Vec   # vector quantities

# dot product maps two vectors to a scalar
@syms ⋅(u::Vec, v::Vec)::Number

Now, I can at least do

julia> a*(u⋅v) + b  # works
b + a*(u ⋅ v)

(though I don’t think my definition above restricts to vectors of the same size).

However, vector addition doesn’t automatically work.

julia> u + v

MethodError: no method matching +(::SymbolicUtils.Sym{StaticVector, Nothing}, ::SymbolicUtils.Sym{StaticVector, Nothing})

A similar method error results from attempting to do a*v. Unfortunately, SymbolicUtils.Add and SymbolicUtils.Mul seem to be undocumented, I am not sure if they are even the correct things to reach for.

I would be grateful if anyone could point me in the right direction.

1 Like

Open a SymbolicUtils issue. You’ll want to discuss this with @shashi

1 Like

So for things like this where you want symbolic counterparts of types outside of what are officially supported (i.e. Real and AbstractArray symbols), you really want to define all the methods yourself.

I think it is a bug that * even works here – it accidentally does.

What you want to do is define all the operators to return op(u,v) = term(op, u, v, type=Vec). where op is the binary operator… You’re right in thinking Mul and Add are not right here – they are meant for Real symbols, and assume associativity and commutativity. term creates a Term which does not assume these properties.

Hi @shashi - thanks for your reply!

For vector addition, that is commutative and associative, so I’d probably want something very much like Add if I cannot use it directly.

With regards to that, it looks like in the master branch of SymbolicUtils that the types which can Add accept has been relaxed from Number to Any since the last stable release (0.19.7), so I am wondering if I could plug in to it by defining an appropriate outer constructor and a method for +.

The inner/dot product is also commutative (but simpler than add because its always binary). Then, it sounds like I might want to make my own ScalarProduct type to somehow reflect that and define methods for TermInterface.

I’ll let you know how I make out.

I would suggest not using the Add type and instead making your own. We make no guarantees about the internal representation of expressions, we only guarantee the expression interface SymbolicUtils.jl — API

In fact, in the next release we will be deleting Add in favor of a Unityper.jl type.

dumb question from a complete beginner: in this context are the input types for u, v to be
u::SymbolicUtils.Sym{StaticVector, Nothing}?
so will we be defining all of the stuff like:

abstract type NovelType end
+(u::Number, v::Sym{NovelType, Nothing}) = term(...)
+(u::Sym{NovelType, Nothing}, v::Sym{NovelType, Nothing}) = term(...)
...

etc?

That’s right.