AGISystem2 uses a strategy pattern for HDC operations. This allows swapping the underlying vector representation without changing the reasoning layer. This guide explains how to create a new strategy.

HDC Contract

Every strategy must satisfy these mathematical properties:

bind(a, a) Produces "zero" effect for XOR-based strategies (strategy-dependent)
bind(bind(a, b), b) ≈ a (reversibility)
similarity(v, v) = 1.0 (reflexive)
similarity(a, b) = similarity(b, a) (symmetric)
similarity(random, random) ≈ 0.5 ± 0.05 (quasi-orthogonal)
bundle([a,b,c]).similarity(a) > 0.5 for small n (retrievable)

Step 1: Create Strategy File

Create src/hdc/strategies/your-strategy.mjs:

/**
 * AGISystem2 - Your Custom HDC Strategy
 * @module hdc/strategies/your-strategy
 */

// ============================================================================
// VECTOR CLASS (Internal)
// ============================================================================

class YourVector {
  constructor(geometry, data = null) {
    this.geometry = geometry;
    this.strategyId = 'your-strategy';
    // Initialize your data structure
    this.data = data || this.createEmpty(geometry);
  }

  createEmpty(geometry) {
    // Return your empty data structure
  }

  // Required instance methods for backward compat:
  // getBit(index), setBit(index, value), popcount(), density()
  // clone(), equals(other), serialize()
  // xorInPlace(other), andInPlace(other), orInPlace(other), notInPlace()
  // zero(), ones()

  // Required static methods:
  // static random(geometry, randomFn)
  // static zeros(geometry)
  // static ones(geometry)
  // static deserialize(obj)
}

// ============================================================================
// STRATEGY PROPERTIES
// ============================================================================

const properties = {
  id: 'your-strategy',
  displayName: 'Your Strategy Name',
  recommendedBundleCapacity: 7,      // Optimal vectors to bundle
  maxBundleCapacity: 100,            // Before accuracy drops
  bytesPerVector: (geo) => geo / 8,  // Memory estimate
  bindComplexity: 'O(n)',            // Big-O notation
  sparseOptimized: false,            // Benefits from sparse data?
  description: 'Description of your strategy'
};

// ============================================================================
// FACTORY FUNCTIONS
// ============================================================================

function createZero(geometry) {
  return new YourVector(geometry);
}

function createRandom(geometry, seed = null) {
  // Create vector with ~50% density
  const v = new YourVector(geometry);
  // Fill with random data...
  return v;
}

function createFromName(name, geometry) {
  // CRITICAL: Same (name, geometry) must always produce same vector!
  // Use deterministic hash-based PRNG
  const seed = hashFunction(name);
  return createRandom(geometry, seed);
}

function deserialize(serialized) {
  if (serialized.strategyId !== 'your-strategy') {
    throw new Error('Wrong strategy');
  }
  const v = new YourVector(serialized.geometry);
  // Restore data from serialized.data
  return v;
}

// ============================================================================
// CORE OPERATIONS
// ============================================================================

function bind(a, b) {
  // Must be: associative, commutative (cancellation is strategy-dependent)
  // For binary: XOR
  // For polynomial: multiply mod irreducible
  if (a.geometry !== b.geometry) {
    throw new Error('Geometry mismatch');
  }
  const result = clone(a);
  // Apply binding operation...
  return result;
}

function bindAll(...vectors) {
  if (vectors.length === 0) throw new Error('Need at least one vector');
  let result = clone(vectors[0]);
  for (let i = 1; i < vectors.length; i++) {
    result = bind(result, vectors[i]);
  }
  return result;
}

function bundle(vectors, tieBreaker = null) {
  // Superposition: result similar to ALL inputs
  // For binary: majority vote per bit
  // For polynomial: weighted sum
  if (vectors.length === 0) throw new Error('Need at least one vector');
  if (vectors.length === 1) return clone(vectors[0]);

  const geometry = vectors[0].geometry;
  const result = new YourVector(geometry);
  // Apply bundling operation...
  return result;
}

function similarity(a, b) {
  // Range: [0, 1], reflexive, symmetric
  // For binary: 1 - (hamming distance / geometry)
  // For polynomial: cosine similarity
  if (a.geometry !== b.geometry) {
    throw new Error('Geometry mismatch');
  }
  // Calculate and return similarity...
  return 0.5; // placeholder
}

function unbind(composite, component) {
  // For XOR-based strategies, unbind can reuse bind
  return bind(composite, component);
}

// ============================================================================
// UTILITY OPERATIONS
// ============================================================================

function clone(v) {
  const result = new YourVector(v.geometry);
  // Copy data...
  return result;
}

function equals(a, b) {
  if (a.geometry !== b.geometry) return false;
  // Compare data...
  return true;
}

function serialize(v) {
  return {
    strategyId: 'your-strategy',
    geometry: v.geometry,
    version: 1,
    data: /* your serialization */
  };
}

function topKSimilar(query, vocabulary, k = 5) {
  const results = [];
  const entries = vocabulary instanceof Map
    ? vocabulary.entries()
    : Object.entries(vocabulary);

  for (const [name, vec] of entries) {
    results.push({ name, similarity: similarity(query, vec) });
  }
  results.sort((a, b) => b.similarity - a.similarity);
  return results.slice(0, k);
}

function distance(a, b) {
  return 1 - similarity(a, b);
}

function isOrthogonal(a, b, threshold = 0.55) {
  const sim = similarity(a, b);
  return sim < threshold && sim > (1 - threshold);
}

// ============================================================================
// EXPORT STRATEGY OBJECT
// ============================================================================

export const yourStrategy = {
  id: 'your-strategy',
  properties,

  // Factory
  createZero,
  createRandom,
  createFromName,
  deserialize,

  // Core operations
  bind,
  bindAll,
  bundle,
  similarity,
  unbind,

  // Utilities
  clone,
  equals,
  serialize,
  topKSimilar,
  distance,
  isOrthogonal,

  // Internal class (for advanced use)
  Vector: YourVector
};

export default yourStrategy;

Step 2: Register Strategy

Edit src/hdc/strategies/index.mjs:

import { denseBinaryStrategy } from './dense-binary.mjs';
import { yourStrategy } from './your-strategy.mjs';

const strategies = new Map();

// Register strategies
strategies.set('dense-binary', denseBinaryStrategy);
strategies.set('your-strategy', yourStrategy);  // ADD THIS

export function getStrategy(strategyId) {
  const strategy = strategies.get(strategyId);
  if (!strategy) {
    throw new Error(`Unknown strategy: ${strategyId}`);
  }
  return strategy;
}

// ... rest of file

Step 3: Validate Contract

Use the built-in validator to check your strategy:

import { validateStrategy } from './src/hdc/contract.mjs';
import { yourStrategy } from './src/hdc/strategies/your-strategy.mjs';

const result = validateStrategy(yourStrategy, 2048);

if (result.valid) {
  console.log('Strategy passes contract!');
} else {
  console.log('Contract violations:');
  for (const error of result.errors) {
    console.log('  -', error);
  }
}

Step 4: Test with Eval Suite

# Run eval suite with your strategy
SYS2_HDC_STRATEGY=your-strategy npm run eval

Step 5: Benchmark

import { compareStrategies } from './src/hdc/facade.mjs';

const results = compareStrategies(
  ['dense-binary', 'your-strategy'],
  8192,
  { iterations: 1000 }
);

console.log(JSON.stringify(results, null, 2));

Example: Sparse Polynomial Strategy (Sketch)

A sparse polynomial strategy might represent vectors as polynomials over GF(2)[x]:

class SparsePolyVector {
  constructor(geometry) {
    this.geometry = geometry;
    this.strategyId = 'sparse-polynomial';
    // Store as Map<exponent, coefficient>
    this.terms = new Map();
  }
}

function bind(a, b) {
  // Polynomial multiplication mod irreducible polynomial
  const result = new SparsePolyVector(a.geometry);
  for (const [expA, coefA] of a.terms) {
    for (const [expB, coefB] of b.terms) {
      const newExp = (expA + expB) % a.geometry;
      const newCoef = coefA * coefB;
      result.terms.set(newExp,
        (result.terms.get(newExp) || 0) + newCoef
      );
    }
  }
  return result;
}

function similarity(a, b) {
  // Cosine similarity in polynomial coefficient space
  let dotProduct = 0, normA = 0, normB = 0;
  // ... calculate ...
  return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}

Properties to Consider

Memory Sparse strategies use less memory for low-density vectors
Speed Dense strategies are faster for dense vectors (SIMD-friendly)
Capacity How many vectors can be bundled before accuracy drops?
Noise How does noise accumulate through operations?

Sparse Polynomial HDC (SPHDC) Strategy

The SPHDC strategy implements sparse HDC using Integer-XOR binding with Min-Hash sampling.

Mathematical Foundations

Implementation Details

Use Cases

Comparison of All Five Strategies

Property Dense Binary Sparse Polynomial Metric-Affine Metric-Affine Elastic EXACT
Dimensionality Fixed (2048-4096 bits) Infinite (k=4-8 exponents) Fixed (32 byte channels) Elastic (32+ byte channels) Elastic (session-local atom indices)
Binding Operation XOR (bitwise) Symmetric difference Affine transformation Affine transformation OR-product (bitset-polynomial)
Binding Speed Fast (O(n/32)) Slower (O(k²)) Fastest (O(m)) Fast (O(m) + chunk scan) Depends on term counts (often fast for monomial facts; worst-case O(|A||B|))
Memory per Vector 256-512 bytes 32 bytes (k=4 default) 32 bytes 32B+ (chunked bundles) Variable (lossless set of BigInt monomials)
Similarity Metric Hamming distance Jaccard index Channel overlap Channel overlap (max over chunks) Jaccard over monomials (plus witness-based decode/cleanup)
Performance (Core Theory) 516ms (symbolic) 523ms (symbolic) 225ms (symbolic) ⚡ 2.3x faster Similar to Metric-Affine (small KBs) Varies; used as an upper bound in saturation evaluation
XOR cancellation Perfect Approximate Approximate Approximate Not required (UNBIND is quotient-like)
Commutative Perfect Perfect Perfect Perfect Perfect
Best For Research, standard HDC Large KBs, memory-constrained Production systems, speed-critical apps Large KB superpositions, stable bundling Research: lossless encoding + decoding/cleanup studies

See the SPHDC Comparison Guide for detailed benchmarks and recommendations. For EMA internals, read Metric-Affine Elastic.

Common Pitfalls