File values.h

namespace sym

Typedefs

using Valuesd = Values<double>
using Valuesf = Values<float>

Functions

template<typename Scalar>
std::ostream &operator<<(std::ostream &os, const Values<Scalar> &v)

Prints entries with their keys, data slices, and values, like:

Valuesd entries=4 array=8 storage_dim=7 tangent_dim=6
  R_1 [0:4] --> <Rot3d [0.563679, 0.0939464, 0, 0.820634]>
  f_1 [5:6] --> 4.2
  f_2 [6:7] --> 4.3
  d_1 [7:8] --> 4.3
>

template<typename Scalar>
class Values
#include <values.h>

Efficient polymorphic data structure to store named types with a dict-like interface and support efficient repeated operations using a key index. Supports on-manifold optimization.

Compatible types are given by the type_t enum. All types implement the StorageOps and LieGroupOps concepts, which are the core operating mechanisms in this class.

Public Types

using MapType = std::unordered_map<Key, index_entry_t>
using ArrayType = std::vector<Scalar>
using LcmType = typename ValuesLcmTypeHelper<Scalar>::Type

Expose the correct LCM type (values_t or valuesf_t)

Public Functions

Values() = default

Default construct as empty.

explicit Values(std::initializer_list<Values<Scalar>> others)

Construct from a list of other Values objects. The order of Keys are preserved by the order of the Values in the initializer list

NOTE(alvin): others Values should not contain overlapping Keys

explicit Values(const LcmType &msg)

Construct from serialized form.

bool Has(const Key &key) const

Return whether the key exists.

template<typename T>
T At(const Key &key) const

Retrieve a value by key.

template<typename T>
std::enable_if_t<!kIsEigenType<T>, bool> Set(const Key &key, const T &value)

Add or update a value by key. Returns true if added, false if updated.

Overload for non-Eigen types

template<typename Derived>
std::enable_if_t<kIsEigenType<Derived>, bool> Set(const Key &key, const Derived &value)

Add or update a value by key. Returns true if added, false if updated.

Overload for Eigen types

template<typename T>
void SetNew(const Key &key, T &&value)

Add a value by key, throws runtime_error if the key already exists.

This is useful when setting up initial values for a problem.

void UpdateOrSet(const index_t &index, const Values<Scalar> &other)

Update or add keys to this Values base on other Values of different structure.

index MUST be valid for other.

NOTE(alvin): it is less efficient than the Update methods below if index objects are created and cached. This method performs map lookup for each key of the index

size_t NumEntries() const

Number of keys.

inline bool Empty() const

Has zero keys.

std::vector<Key> Keys(bool sort_by_offset = true) const

Get all keys.

NOTE(hayk): If we changed key storage to a sorted vector this could automatically be maintained and it would be more embedded friendly, but At(key) would become O(N) for linear search.

Parameters:

sort_by_offset – Sorts by storage order to make iteration safer and more memory efficient

const MapType &Items() const

Expose map type to allow iteration.

const ArrayType &Data() const

Raw data buffer.

template<typename NewScalar>
Values<NewScalar> Cast() const

Cast to another Scalar type (returns a copy)

bool Remove(const Key &key)

Remove the given key.

Only removes the index entry, does not change the data array. Returns true if removed, false if already not present.

Call Cleanup() to re-pack the data array.

void RemoveAll()

Remove all keys and empty out the storage.

size_t Cleanup()

Repack the data array to get rid of empty space from removed keys.

If regularly removing keys, it’s up to the user to call this appropriately to avoid storage growth. Returns the number of Scalar elements cleaned up from the data array.

It will INVALIDATE all indices, offset increments, and pointers. Re-create an index with CreateIndex().

index_t CreateIndex(const std::vector<Key> &keys) const

Create an index from the given ordered subset of keys. This object can then be used for repeated efficient operations on that subset of keys.

If you want an index of all the keys, call values.CreateIndex(values.Keys()).

An index will be INVALIDATED if the following happens:

1) Remove() is called with a contained key, or RemoveAll() is called 2) Cleanup() is called to re-pack the data array

NOTE(hayk): We could also add a simple UpdateIndex(&index) method, since the offset is the only thing that needs to get updated after repacking.

index_entry_t IndexEntryAt(const Key &key) const

Retrieve an index entry by key. This performs a map lookup.

An index entry will be INVALIDATED if the following happens:

1) Remove() is called with the indexed key, or RemoveAll() is called 2) Cleanup() is called to re-pack the data array

optional<index_entry_t> MaybeIndexEntryAt(const Key &key) const

Retrieve an index entry by key, or the empty optional if the key is not present. This performs a map lookup.

An index entry will be INVALIDATED if the following happens:

1) Remove() is called with the indexed key, or RemoveAll() is called 2) Cleanup() is called to re-pack the data array

template<typename T>
T At(const index_entry_t &entry) const

Retrieve a value by index entry. This avoids a map lookup compared to At(key).

template<typename T>
std::enable_if_t<!kIsEigenType<T>> Set(const index_entry_t &key, const T &value)

Update a value by index entry with no map lookup (compared to Set(key)). This does NOT add new values and assumes the key exists already.

Overload for non-Eigen types

template<typename Derived>
std::enable_if_t<kIsEigenType<Derived>> Set(const index_entry_t &key, const Derived &value)

Update a value by index entry with no map lookup (compared to Set(key)). This does NOT add new values and assumes the key exists already.

Overload for Eigen types

void Update(const index_t &index, const Values<Scalar> &other)

Efficiently update the keys given by this index from other into this. This purely copies slices of the data arrays, the index MUST be valid for both objects!

void Update(const index_t &index_this, const index_t &index_other, const Values<Scalar> &other)

Efficiently update the keys from a different structured Values, given by index_this and index_other. This purely copies slices of the data arrays.

index_this MUST be valid for this object; index_other MUST be valid for other object.

void Retract(const index_t &index, const Scalar *delta, Scalar epsilon)

Perform a retraction from an update vector.

Parameters:
  • index – Ordered list of keys in the delta vector

  • delta – Pointer to update vector - MUST be the size of index.tangent_dim!

  • epsilon – Small constant to avoid singularities (do not use zero)

VectorX<Scalar> LocalCoordinates(const Values<Scalar> &others, const index_t &index, Scalar epsilon)

Express this Values in the local coordinate of others Values, i.e., this \ominus others

Parameters:
  • others – The other Values that the local coordinate is relative to

  • index – Ordered list of keys to include (MUST be valid for both this and others Values)

  • epsilon – Small constant to avoid singularities (do not use zero)

void FillLcmType(LcmType &msg, bool sort_keys = false) const

Serialize to LCM.

LcmType GetLcmType(bool sort_keys = false) const

Protected Functions

template<typename T>
bool SetInternal(const sym::Key &key, const T &value)
template<typename T>
void SetInternal(const index_entry_t &entry, const T &value)

Protected Attributes

MapType map_
ArrayType data_

Friends

friend class Values
template<typename _S>
struct ValuesLcmTypeHelper
template<>
struct ValuesLcmTypeHelper<double>

Public Types

using Type = values_t
template<>
struct ValuesLcmTypeHelper<float>

Public Types

using Type = valuesf_t