symforce-org / symforce

Fast symbolic computation, code generation, and nonlinear optimization for robotics
https://symforce.org
Apache License 2.0
1.41k stars 145 forks source link

Values accept Dict #359

Closed hflemmen closed 1 year ago

hflemmen commented 1 year ago

Is your feature request related to a problem? Please describe.

Perhaps not a problem, but more of an inconvenience. For many use cases(e.g. measurements of landmarks in a SLAM-like system) it would be practical to be able to give in python Dicts to Values objects for use in the optimizer.

My use case is similar to the localization example on the front readme.md, but since I dynamically add and remove landmarks during the lifetime of the system, it is convenient to store them in a dict. A list can be made work, but then all the indices change when we remove landmarks.

Describe the solution you'd like That the Values object accepts Dict in addition to List. Either by modifying the underlying code generation system to accept it, or by converting it to a list of the accessed elements from the dictionary. (And keeping track of the indices) I don't have an in-depth understanding of how the code generation works, but I would guess that the first one is more difficult and the last one slower.

Describe alternatives you've considered My current workaround is to create a list of all the active landmarks, and a dictionary that maps to an index in this list instead of the landmark position. This admittedly works, but is not particularly elegant and leads to some extra iterations over all landmarks.

aaron-skydio commented 1 year ago

You should be able to put a Values in a Values, which should be similar to putting a Dict in a Values? Is there a reason that doesn't cover what you need?

hflemmen commented 1 year ago

It could be that it cover what I need. I did try to do this, but I struggled with different errors.

How would I reference a key in a Values inside a Values?

E.g. (slightly modified from robot_2d_localization)

    landmarks = Values()
    landmarks["landmark_0"] = sf.V2(-2, 2)
    landmarks["landmark_1"] = sf.V2(1, -3)
    landmarks["landmark_2"] = sf.V2(5, 2)

    initial_values = Values(
        poses=[sf.Pose2.identity()] * num_poses,
        landmarks=landmarks,
        distances=[1.7, 1.4],
        angles=np.deg2rad([[55, 245, -35], [95, 220, -20], [125, 220, -20]]).tolist(),
        epsilon=sf.numeric_epsilon,
    )

How would i reference the key to eg. landmark_0?

When constructing a Factor accessing the key as keys=[f"poses[{i}]", f"landmarks[landmark_{j}]", f"angles[{i}][{j}]", "epsilon"], failed.

The full modified example: robot_2d_localization.txt

aaron-skydio commented 1 year ago

You should be able to do f"landmarks.landmark_{j}"

hflemmen commented 1 year ago

Correct, it works. Thank you.

It covers my use case, so I close this now.