Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Embedding State Machine

The EmbeddingState provides type-safe state transitions for transaction embedding lifecycle. It eliminates Option ceremony and ensures correct API usage at compile time.

Overview

Transaction embeddings track the semantic change from before-state to after-state. The state machine ensures:

  • Before embedding is always available
  • Delta is only accessible after computation
  • Dimension mismatches are caught early
  • Double-computation is prevented

State Diagram

stateDiagram-v2
    [*] --> Initial: new(before)
    Initial --> Computed: compute(after)
    Computed --> Computed: access only
    Initial --> Initial: access only
StateDescriptionAvailable Data
InitialTransaction started, before capturedbefore
ComputedDelta computed, ready for conflict checkbefore, after, delta

API Reference

Construction Methods

MethodDescriptionResult State
new(before)Create from sparse vectorInitial
from_dense(&[f32])Create from dense sliceInitial
empty(dim)Create zero vector of given dimensionInitial
default()Create empty (dimension 0)Initial

State Query Methods

MethodInitialComputed
before()&SparseVector&SparseVector
after()NoneSome(&SparseVector)
delta()NoneSome(&SparseVector)
is_computed()falsetrue
dimension()dimensiondimension

Transition Methods

MethodFromToError Conditions
compute(after)InitialComputedAlreadyComputed, DimensionMismatch
compute_from_dense(&[f32])InitialComputedAlreadyComputed, DimensionMismatch
compute_with_threshold(after, threshold)InitialComputedAlreadyComputed, DimensionMismatch

Threshold Configuration

The compute_with_threshold method creates sparse deltas by ignoring small changes. This reduces memory usage for high-dimensional embeddings.

Threshold Effects

ThresholdEffectUse Case
0.0All differences capturedExact tracking
0.001Ignore floating-point noiseGeneral use
0.01Ignore minor changesDimensionality reduction
0.1Only major changesCoarse conflict detection

Example

#![allow(unused)]
fn main() {
let state = EmbeddingState::from_dense(&before);

// Only capture differences > 0.01
let computed = state.compute_with_threshold(&after, 0.01)?;

// Sparse delta - fewer non-zero entries
let delta = computed.delta().unwrap();
println!("Non-zero entries: {}", delta.nnz());
}

Error Handling

Error Types

ErrorCausePrevention
NotComputedAccessing delta before computeCheck is_computed()
AlreadyComputedCalling compute twiceCheck is_computed()
DimensionMismatchBefore and after have different dimsValidate dimensions

Error Display

#![allow(unused)]
fn main() {
// NotComputed
"delta not yet computed"

// AlreadyComputed
"delta already computed"

// DimensionMismatch
"dimension mismatch: before=128, after=64"
}

Example Usage

Basic Workflow

#![allow(unused)]
fn main() {
use tensor_chain::embedding::EmbeddingState;
use tensor_store::SparseVector;

// 1. Capture before-state at transaction start
let before = SparseVector::from_dense(&[1.0, 0.0, 0.0, 0.0]);
let state = EmbeddingState::new(before);

// 2. State is Initial - delta not available
assert!(!state.is_computed());
assert!(state.delta().is_none());

// 3. Compute delta at commit time
let after = SparseVector::from_dense(&[1.0, 0.5, 0.0, 0.0]);
let computed = state.compute(after)?;

// 4. State is Computed - delta available
assert!(computed.is_computed());
let delta = computed.delta().unwrap();

// Delta is [0.0, 0.5, 0.0, 0.0]
assert_eq!(delta.nnz(), 1);  // Only one non-zero
}

Using delta_or_zero

For code that needs a dense vector regardless of state:

#![allow(unused)]
fn main() {
// Safe to call in any state
let dense_delta = state.delta_or_zero();

// Returns zeros if Initial
// Returns actual delta if Computed
}

Delta Magnitude

#![allow(unused)]
fn main() {
// Check if transaction made significant changes
let magnitude = state.delta_magnitude();

if magnitude < 0.001 {
    println!("No meaningful changes");
} else {
    println!("Change magnitude: {}", magnitude);
}
}

Integration with Consensus

The embedding state integrates with the consensus layer for conflict detection.

Delta to DeltaVector

#![allow(unused)]
fn main() {
use tensor_chain::consensus::DeltaVector;

let state = EmbeddingState::from_dense(&before);
let computed = state.compute_from_dense(&after)?;

// Create DeltaVector for conflict detection
let delta_vec = DeltaVector::new(
    computed.delta_or_zero(),
    affected_keys,
    tx_id,
);

// Check orthogonality with another transaction
let similarity = delta_vec.cosine_similarity(&other_delta);
if similarity.abs() < 0.1 {
    println!("Transactions are orthogonal - can merge");
}
}

Conflict Classification

SimilarityClassificationAction
< 0.1OrthogonalCan merge
0.1 - 0.5Low conflictMerge possible
0.5 - 0.9ConflictingNeeds resolution
> 0.9ParallelMust serialize

Serialization

The state machine supports bitcode serialization for persistence:

#![allow(unused)]
fn main() {
// Serialize
let bytes = bitcode::encode(&state);

// Deserialize
let restored: EmbeddingState = bitcode::decode(&bytes)?;

// State is preserved
assert_eq!(state.is_computed(), restored.is_computed());
}

Source Reference

  • tensor_chain/src/embedding.rs - EmbeddingState implementation
  • tensor_store/src/lib.rs - SparseVector type