symforce icon indicating copy to clipboard operation
symforce copied to clipboard

Code Generation Question for Matrices with 0s

Open AlonSpinner opened this issue 1 year ago • 2 comments

Hi,

I am implementing an efficent factor chain solver. In the solution I multiply and invert lower triangular matrices. I want to generate efficent CPP code using symforce, but am unable to do that because the code generation treats 0s in the matrices as symbolic variables.

Of course I could create a full matrix instead of a lower triangular, and then edit the generated code, but I was wondering if you have a built in solution for my issue.

I provide exampel code which produces the following error: c = codegen.Codegen( File "/home/alon/.local/lib/python3.10/site-packages/symforce/codegen/codegen.py", line 208, in init assert len(input_symbols) == len( AssertionError: Symbols in inputs must be unique. Duplicate symbols = [0, 0, 0, 0, 0, 0]

import symforce
symforce.set_epsilon_to_symbol()
from symforce import codegen
from symforce.values import Values
import symforce.symbolic as sf
import os

current_dir = os.path.dirname(__file__)
parent_dir = os.path.abspath(os.path.join(current_dir, os.pardir))
generated_dir = os.path.join(parent_dir, "generated")

AtAi = sf.Matrix(4, 4)
for i in range(4):
    for j in range(4):
        AtAi[i, j] = sf.Symbol(f'AtAi_{i}_{j}')
Lim1 = sf.Matrix(4, 4)
for i in range(4):
    for j in range(4):
        if j <= i:
            Lim1[i, j] = sf.Symbol(f'Lim1_{i}_{j}')
        else:
            Lim1[i, j] = 0
Li = AtAi.transpose() * Lim1.transpose().inv()

inputs = Values()
inputs["AtAi"] = AtAi
inputs["Lim1"] = Lim1
ouptuts = Values()
ouptuts["Li"] = Li

c = codegen.Codegen(
    inputs=inputs,
    outputs=ouptuts,
    config = codegen.CppConfig(use_eigen_types=True),
    name = "compute_Li"
)


c.generate_function(
    namespace = "generated",
    output_dir = generated_dir,
    skip_directory_nesting=True,
)

Thanks, Alon.

AlonSpinner avatar Jan 29 '25 14:01 AlonSpinner

So, the inputs currently need to be full matrices; if you want to represent that you only look at the lower triangle, you can do that like this:

AtAi = sf.Matrix44.symbolic('AtAi')
Lim1_input = sf.Matrix44.symbolic('Lim1')
Lim1 = Lim1_input.lower_triangle()
Li = AtAi.transpose() * Lim1.transpose().inv()

inputs = Values()
inputs["AtAi"] = AtAi
inputs["Lim1"] = Lim1
ouptuts = Values()
ouptuts["Li"] = Li

aaron-skydio avatar Jan 29 '25 21:01 aaron-skydio

I think it would be reasonable to just ignore zeroes in the inputs in codegen? That seems like something someone could add at some point

aaron-skydio avatar Jan 29 '25 21:01 aaron-skydio