ALLM.Embedding (allm v0.5.0)

Copy Markdown View Source

A single embedding vector — Layer A serializable data.

One %Embedding{} corresponds to one input string in an ALLM.EmbeddingRequest.t/0. :index is the position of that input in the original request's :input list and is always a non_neg_integer/0 — never nil — so that a response merged across several provider calls still guarantees Enum.at(ALLM.EmbeddingResponse.vectors(resp), i) is the embedding of Enum.at(request.input, i).

iex> e = ALLM.Embedding.new(vector: [3.0, 4.0], index: 0)
iex> ALLM.Embedding.magnitude(e)
5.0

Construction

:vector is enforced by @enforce_keys, so new/1 without it raises ArgumentError. An unknown key raises KeyError via struct!/2. Enforcement is on key absence, not value — new(vector: nil) succeeds. There is no is_list/1 guard: constructing an embedding is the job of adapter decoders, which always supply a list, and an adapter that would build a vector: [] returns %ALLM.Error.EmbeddingAdapterError{reason: :malformed_response} instead. magnitude/1 and normalize/1 are undefined on a nil vector — they raise Protocol.UndefinedError, not the ArithmeticError documented below.

Numeric contract

  • normalize/1 is idempotent to within 1.0e-9.
  • normalize/1 returns the embedding unchanged whenever magnitude/1 is 0.0 — which covers vector: [], an all-zero vector, and a vector whose components underflow when squared ([1.0e-200, 1.0e-200]). No ArithmeticError, no NaN.
  • magnitude/1 raises ArithmeticError on float overflow: Erlang's * raises badarith rather than producing infinity. No embedding provider returns components anywhere near 1.0e150, so the naive sum of squares is correct for every real input; the bound is documented rather than paid for with max-scaling.

Summary

Functions

Euclidean norm of the vector.

Build an %Embedding{} from keyword opts.

L2-normalize the vector. Returns the embedding unchanged when the magnitude is 0.0.

Types

t()

@type t() :: %ALLM.Embedding{
  index: non_neg_integer(),
  metadata: map(),
  vector: [float()]
}

Functions

magnitude(embedding)

@spec magnitude(t()) :: float()

Euclidean norm of the vector.

Raises ArithmeticError when a component squares to a float overflow — see the module docs.

Examples

iex> ALLM.Embedding.magnitude(ALLM.Embedding.new(vector: [3.0, 4.0]))
5.0

iex> ALLM.Embedding.magnitude(ALLM.Embedding.new(vector: []))
0.0

new(opts)

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

Build an %Embedding{} from keyword opts.

A missing :vector raises ArgumentError (@enforce_keys); an unknown key raises KeyError (struct!/2).

Examples

iex> e = ALLM.Embedding.new(vector: [0.1, 0.2])
iex> e.index
0
iex> e.metadata
%{}

normalize(embedding)

@spec normalize(t()) :: t()

L2-normalize the vector. Returns the embedding unchanged when the magnitude is 0.0.

:index and :metadata are preserved.

Examples

iex> ALLM.Embedding.normalize(ALLM.Embedding.new(vector: [0.0, 2.0])).vector
[0.0, 1.0]

iex> zero = ALLM.Embedding.new(vector: [0.0, 0.0])
iex> ALLM.Embedding.normalize(zero) == zero
true