# `Monty.Frameworks.Models.DisplacementMatching.DisplacementGraphMemory`
[🔗](https://github.com/d-led/ex.tbp.monty/blob/v0.1.0/packages/ex_tbp_monty_core/lib/monty/frameworks/models/displacement_matching/displacement_graph_memory.ex#L1)

What a displacement module reads off a graph: Monty's `DisplacementGraphMemory`.

The memory itself is `Monty.Frameworks.Models.GraphMatching.GraphMemory` — the
same k-nearest-neighbour graph every graph module stores. What a *displacement*
module needs on top of it is a way to start matching: every edge of every graph
as a two-node path, and the edge's stored displacement, which is what the next
step's displacement is compared against.

So this is functions over a graph memory rather than a kind of memory. Monty
spells the difference as a subclass, which also lets it override how a graph is
built; here the graph is built once, by `GraphObjectModel`, and every edge
already carries its displacement — a class that had to say so again would be
saying what the model says.

Monty's subclass also carries `match_attribute`, for one thing only: a memory
loaded for a module that matches on point-pair features gets those features
added to every graph that lacks them (`with_ppf/2`). Building the features is
the model's job, because the model is what knows the graph.

# `hypotheses`

```elixir
@type hypotheses() :: %{
  possible_matches: %{optional(String.t()) =&gt; map()},
  possible_paths: %{
    optional(String.t()) =&gt; [non_neg_integer()] | [[non_neg_integer()]]
  },
  next_possible_paths: %{optional(String.t()) =&gt; [[non_neg_integer()]]},
  scale_factors: %{optional(String.t()) =&gt; [float()]}
}
```

The four things a displacement module starts an episode with.

`possible_matches` is every object in memory; `possible_paths` is where a
match can be at the first step — Monty starts it with the node ids themselves,
one per node, and replaces them with paths as soon as a move is matched;
`next_possible_paths` is one two-node path per edge, because a move has to be
along an edge, and those are the paths a step is matched against;
`scale_factors` is the first component of each edge's displacement, which a
scale-invariant match divides by.

# `get_initial_hypotheses`

```elixir
@spec get_initial_hypotheses(Monty.Frameworks.Models.GraphMatching.GraphMemory.t()) ::
  hypotheses()
```

Every graph in memory as a set of paths to test, Monty's
`get_initial_hypotheses`.

A node alone is a path of one, which is where a match can be at the very first
step; an edge is the path of two the next step extends. Both are keyed by
graph, because a match is per object.

# `with_ppf`

```elixir
@spec with_ppf(Monty.Frameworks.Models.GraphMatching.GraphMemory.t(), String.t()) ::
  Monty.Frameworks.Models.GraphMatching.GraphMemory.t()
```

A memory whose graphs carry point-pair features, adding them where a graph has
none.

Monty's `DisplacementGraphMemory.load_state_dict` does this on the way in ("if
`model[input_channel].has_ppf is False`: `add_ppf_to_graph()`"), and it has to:
a memory read from a pickle was built by a module that matched on
displacements, so its `edge_attr` is a displacement. Matching one against a
point-pair query would compare a length with a vector and quietly keep the
wrong objects.

A memory for a module that matches on displacements is handed back untouched.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
