moeru-ai/airi · error · Error

${singularMessage}

Error message

${singularMessage}

What it means

Cholesky decomposition requires a symmetric positive-definite matrix; a diagonal pivot `value <= 1e-12` means the matrix is singular (or numerically degenerate), so factorization cannot proceed. This typically surfaces when a covariance matrix estimated during AR-HMM fitting collapses to rank-deficient — e.g. a state assigned too few frames or constant-valued channels.

Source

Thrown at packages/motion-driver-magic/src/shared/numeric.ts:43

    for (let outputIndex = 0; outputIndex < outputCount; outputIndex++)
      prediction[outputIndex] += feature[featureIndex] * coefficients[featureIndex][outputIndex]
  }
  return prediction
}

/** Computes the lower-triangular Cholesky factor of a positive-definite matrix. */
export function cholesky(matrix: readonly number[][], singularMessage: string): number[][] {
  const size = matrix.length
  const lower = Array.from({ length: size }, () => Array.from<number>({ length: size }).fill(0))
  for (let row = 0; row < size; row++) {
    for (let column = 0; column <= row; column++) {
      let value = matrix[row][column]
      for (let index = 0; index < column; index++)
        value -= lower[row][index] * lower[column][index]

      if (row === column) {
        if (value <= 1e-12)
          throw new Error(singularMessage)
        lower[row][column] = Math.sqrt(value)
      }
      else {
        lower[row][column] = value / lower[column][column]
      }
    }
  }
  return lower
}

/** Solves a positive-definite linear system for one or more target columns. */
export function solvePositiveDefinite(
  matrix: readonly number[][],
  targets: readonly number[][],
  singularMessage: string,
): number[][] {
  const lower = cholesky(matrix, singularMessage)
  const size = matrix.length

View on GitHub (pinned to 9c213115f8)

Solutions

  1. Increase the amount of training data so every state receives enough frames.
  2. Reduce `stateCount` so each cluster has sufficient assigned data.
  3. Remove constant or duplicated channels from the motion sequence before fitting.
  4. Add a small ridge/regularization term to covariance estimates if the API exposes it.
  5. Pre-validate the sequence: drop channels with near-zero variance before fitting.

Example fix

// before
createArHmmModel(rawSequence, { stateCount: 20, order: 3 })
// after
const usable = dropConstantChannels(rawSequence)
createArHmmModel(usable, { stateCount: 4, order: 3 })
Defensive patterns

Strategy: try-catch

Validate before calling

function hasDegenerateChannels(seq: TrainingSequence): boolean {
  const dim = seq.frames[0]?.length ?? 0
  for (let c = 0; c < dim; c++) {
    const first = seq.frames[0]?.[c]
    if (seq.frames.every(f => f[c] === first)) return true
  }
  return false
}

Try / catch

try {
  const model = createArHmmModel(seq, options)
} catch (error) {
  if (error instanceof Error && /singular/i.test(error.message)) {
    const cleaned = dropConstantChannels(seq)
    return createArHmmModel(cleaned, { ...options, stateCount: Math.min(options.stateCount, 4) })
  }
  throw error
}

Prevention

When it happens

Trigger: Indirectly triggered via AR-HMM fitting (`createArHmmModel`) when a covariance matrix becomes singular: a hidden state receives almost no assigned frames, or some channels are constant/linearly dependent. Called from `states`/`lower` during parameter updates.

Common situations: Very short training sequences causing empty state assignments; duplicate or frozen motion channels (all-zero or identical columns); stateCount too high for the data so some states get degenerate covariance; exact-duplicate frames in the sequence.

Related errors


AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02). Data as JSON: /api/errors/3bab188e78c2aac0. Report an issue: GitHub.