Monty.Frameworks.Models.EvidenceMatching.Hypotheses (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

A set of hypotheses: their evidence, the location each implies, the pose each implies, and whether each can still be possible.

Mirrors tbp/monty/frameworks/models/evidence_matching/hypotheses.py. The four fields are parallel — an index is one hypothesis in all of them — which is why Monty keeps them as separate arrays rather than a list of records: a learning module selects, masks and weights whole columns of them with one operation.

In Elixir possible is a list, one flag per hypothesis, and evidence, locations and poses are the same rows as bytes: eight little-endian f64 of evidence, then three of location and nine of rotation each, in the order the hypothesis index names them. That is the form a step needs them in — it displaces every hypothesis, blends what each earned into a column, then asks the k-d index about every location and a kernel for the evidence at each — so holding them this way stops a step from rebuilding a list, and eight or three or nine boxed floats a hypothesis, once per pass. evidence/1, evidence_at/2, locations/1, location/2, poses/1 and pose/2 read them back, one hypothesis at a time where that is all a caller wants.

empty/0 is the identity for concatenate/1, which is what lets a learning module build a step's hypotheses from however many sources voted.

Summary

Types

t()

evidence is hypotheses f64, locations hypotheses * 3 f64 and poses hypotheses * 9 f64, all in the hypothesis's own order; possible has one entry each.

Functions

The index of the most likely hypothesis — the first of several equal maxima.

One set of hypotheses from several, in order.

How many hypotheses the set holds.

The hypotheses of nothing: the identity for concatenate/1.

Every hypothesis' evidence, as the numbers they are.

One hypothesis' evidence.

The evidence column as a step holds it: one f64 per hypothesis.

Indices as the u32 bytes a kernel reads them from.

Indices as Elixir values, read out of the u32 bytes a kernel answers with.

The indices of the hypotheses within percentage per cent of the best one.

One hypothesis' location.

The bytes of one location, as a step holds it.

Every hypothesis' location, as the three values each one is.

The locations in bytes, as values — the reference's way of reading them.

The highest evidence any hypothesis holds.

The lowest evidence any hypothesis holds — the threshold that updates them all.

One set of hypotheses from the rows of each, in order.

One hypothesis per node per pose — the shape a burst samples in.

One hypothesis' rotation.

The bytes of one rotation, row by row, as a step holds it.

Every hypothesis' rotation, as the matrix each one is.

The rotations in bytes, as values — the reference's way of reading them.

The same hypotheses with a new evidence column, given as numbers.

The same hypotheses with a new evidence column a kernel has written.

The rows of the hypotheses at indices, as the bytes a kernel reads.

The index of the runner-up hypothesis, or nil when there is no second one.

The hypotheses at the given indices, in the order asked for.

Types

location()

@type location() :: [float()]

pose()

@type pose() :: [[float()]]

t()

@type t() :: %Monty.Frameworks.Models.EvidenceMatching.Hypotheses{
  evidence: binary(),
  locations: binary(),
  poses: binary(),
  possible: [boolean()]
}

evidence is hypotheses f64, locations hypotheses * 3 f64 and poses hypotheses * 9 f64, all in the hypothesis's own order; possible has one entry each.

Functions

argmax_evidence(hypotheses)

@spec argmax_evidence(t()) :: non_neg_integer()

The index of the most likely hypothesis — the first of several equal maxima.

Asked far more often than any other question of the column, so it is asked of the bytes: a kernel when they are loaded, and the same walk in Elixir otherwise.

concatenate(hyps)

@spec concatenate([t()]) :: t()

One set of hypotheses from several, in order.

Monty concatenates along the hypothesis axis, so votes from two learning modules produce their votes first and the receiving module's hypotheses second, in the order the caller passes them.

count(hypotheses)

@spec count(t()) :: non_neg_integer()

How many hypotheses the set holds.

empty()

@spec empty() :: t()

The hypotheses of nothing: the identity for concatenate/1.

evidence(hypotheses)

@spec evidence(t()) :: [float() | nil]

Every hypothesis' evidence, as the numbers they are.

evidence_at(hypotheses, index)

@spec evidence_at(t(), non_neg_integer()) :: float() | nil

One hypothesis' evidence.

evidence_bytes(hypotheses)

@spec evidence_bytes(t()) :: binary()

The evidence column as a step holds it: one f64 per hypothesis.

What a kernel reads, where evidence/1 is what a reporter or an argmax wants.

index_bytes(indices)

@spec index_bytes([non_neg_integer()]) :: binary()

Indices as the u32 bytes a kernel reads them from.

index_list(bytes)

@spec index_list(binary()) :: [non_neg_integer()]

Indices as Elixir values, read out of the u32 bytes a kernel answers with.

indices_within(hypotheses, percentage, floor)

@spec indices_within(t(), float(), number()) :: [non_neg_integer()]

The indices of the hypotheses within percentage per cent of the best one.

Monty's get_possible_hypothesis_ids: np.where(evidence > max - max / 100 * x_percent_threshold), once the best clears floor. A learning module asks once per object per step, so it is answered from the bytes.

Two edges are numpy's rather than Elixir's, and they are the reason the answer is stated here: a column with a NaN in it has no best at all — np.max propagates the NaN, every comparison against one is false — so nothing is possible; and the band is strict, so a hypothesis exactly at the threshold is out.

location(hypotheses, index)

@spec location(t(), non_neg_integer()) :: location()

One hypothesis' location.

location_bytes(list)

@spec location_bytes(location()) :: binary()

The bytes of one location, as a step holds it.

locations(hypotheses)

@spec locations(t()) :: [location()]

Every hypothesis' location, as the three values each one is.

locations_of(bytes)

@spec locations_of(binary()) :: [location()]

The locations in bytes, as values — the reference's way of reading them.

max_evidence(hypotheses)

@spec max_evidence(t()) :: float() | nil

The highest evidence any hypothesis holds.

min_evidence(hypotheses)

@spec min_evidence(t()) :: float() | nil

The lowest evidence any hypothesis holds — the threshold that updates them all.

evidence_threshold_config: "all" asks this once per graph per step, and the answer is one number: asked of the bytes, a minimum of six thousand of them no longer costs six thousand decoded floats.

new(fields)

@spec new(keyword()) :: t()

One set of hypotheses from the rows of each, in order.

The caller speaks in the shapes it has — evidence as a number, a location as [x, y, z], a pose as three rows — and this is the one place those become the bytes a step reads.

per_pose(fields)

@spec per_pose(keyword()) :: t()

One hypothesis per node per pose — the shape a burst samples in.

locations and evidence name the chosen nodes once; poses holds one matrix per hypothesis in that order, pose-major, which is what aligning each sensed direction against the nodes produces. The node block is encoded once and copied, where new/1 would encode the same few hundred nodes once per sensed direction: a burst samples eight poses at each of a few hundred nodes, ten graphs at a time, so that is tens of thousands of rows of the same values every step.

pose(hypotheses, index)

@spec pose(t(), non_neg_integer()) :: pose()

One hypothesis' rotation.

pose_bytes(list)

@spec pose_bytes(pose()) :: binary()

The bytes of one rotation, row by row, as a step holds it.

poses(hypotheses)

@spec poses(t()) :: [pose()]

Every hypothesis' rotation, as the matrix each one is.

poses_of(bytes)

@spec poses_of(binary()) :: [pose()]

The rotations in bytes, as values — the reference's way of reading them.

put_evidence(hypotheses, values)

@spec put_evidence(t(), [float()]) :: t()

The same hypotheses with a new evidence column, given as numbers.

put_evidence_bytes(hypotheses, bytes)

@spec put_evidence_bytes(t(), binary()) :: t()

The same hypotheses with a new evidence column a kernel has written.

rows_at(hypotheses, indices)

@spec rows_at(t(), [non_neg_integer()]) :: {binary(), binary()}

The rows of the hypotheses at indices, as the bytes a kernel reads.

What a step needs when it asks about a subset — the hypotheses worth testing this observation — without decoding them into values first.

second_argmax_evidence(hypotheses)

@spec second_argmax_evidence(t()) :: non_neg_integer() | nil

The index of the runner-up hypothesis, or nil when there is no second one.

Monty reads it as argsort(evidence)[-2] to weigh a vote between the two best hypotheses, and a step asks once per object. Asked of the bytes: the sort it stands for needs every value decoded and a tuple for each.

take(hypotheses, indices)

@spec take(t(), [non_neg_integer()]) :: t()

The hypotheses at the given indices, in the order asked for.

Used by a learning module to keep the hypotheses it still considers possible without rebuilding four columns by hand. A kept row is copied out of the row it was already in, so this does not go back through the values themselves.