{"record":{"id":"7115d9ff597499b5","repo":"moeru-ai/airi","slug":"the-current-motion-is-too-short-for-this-ar-hmm-sh","errorCode":null,"errorMessage":"The current motion is too short for this AR-HMM shape.","messagePattern":"The current motion is too short for this AR-HMM shape\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/motion-driver-magic/src/ar-hmm.ts","lineNumber":368,"sourceCode":"    }\n  }\n  return { gamma, transitionCounts, logLikelihood }\n}\n\n/** Creates a linear Gaussian AR-HMM model with deterministic clustering and EM updates. */\nexport function createArHmmModel(sequence: TrainingSequence, options: FitOptions): ArHmmModel {\n  if (options.stateCount < 2 || !Number.isInteger(options.stateCount))\n    throw new Error('The AR-HMM state count must be an integer greater than one.')\n  if (options.iterations < 1 || !Number.isInteger(options.iterations))\n    throw new Error('The AR-HMM iteration count must be a positive integer.')\n\n  const sourceModel = fitVarParameters(sequence, {\n    order: options.order,\n    ridge: options.ridge,\n  })\n  const rowCount = sourceModel.trainingFrames.length - options.order\n  if (rowCount < options.stateCount * (sourceModel.featureCount + 1))\n    throw new Error('The current motion is too short for this AR-HMM shape.')\n\n  const clusterFeatures = createClusterFeatures(sourceModel.trainingFrames, options.order)\n  const assignments = initializeAssignments(clusterFeatures, options.stateCount)\n  let expectation = createInitialExpectations(assignments, options.stateCount)\n  let stateParameters = maximizeParameters(sourceModel, expectation, options)\n  const logLikelihoods: number[] = []\n  for (let iteration = 0; iteration < options.iterations; iteration++) {\n    expectation = expectationStep(sourceModel, stateParameters, options)\n    logLikelihoods.push(expectation.logLikelihood)\n    stateParameters = maximizeParameters(sourceModel, expectation, options)\n  }\n  expectation = expectationStep(sourceModel, stateParameters, options)\n  logLikelihoods.push(expectation.logLikelihood)\n\n  const stateWeights = Array.from({ length: options.stateCount }, (_, state) => expectation.gamma.reduce(\n    (sum, probabilities) => sum + probabilities[state],\n    0,\n  ))","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/motion-driver-magic/src/ar-hmm.ts#L350-L386","documentation":"After fitting VAR parameters, the library checks that the number of training rows (frames minus VAR order) is at least `stateCount * (featureCount + 1)`. Below that threshold, each hidden state cannot be assigned enough data for stable per-state parameter estimation, so fitting is refused rather than producing a degenerate/overfit model.","triggerScenarios":"Calling `createArHmmModel` with a short recording relative to `stateCount`, `order`, and feature dimensionality — e.g. a 2-second clip at 30Hz (60 frames) with stateCount 10 and many features. Triggered whenever `frames.length - order < stateCount * (featureCount + 1)`.","commonSituations":"Recording only a few seconds of motion but requesting many states; increasing VAR `order` shrinks usable rows; a high-dimensional pose (many Live2D axes) inflating featureCount; users raising stateCount for richer expressions without lengthening capture.","solutions":["Record a longer motion clip so `frames.length - order >= stateCount * (featureCount + 1)`.","Reduce `stateCount` in FitOptions to fit the available data.","Reduce the VAR `order` to recover rows lost to the autoregressive lag.","Lower the input feature dimensionality (fewer pose channels) before fitting.","Compute the required minimum length beforehand and warn users their capture is too short."],"exampleFix":"// before\ncreateArHmmModel(shortClip, { stateCount: 12, order: 4 })\n// after\nconst minFrames = 12 * (featureCount + 1) + 4\nif (shortClip.frames.length < minFrames)\n  throw new Error(`Need at least ${minFrames} frames`)\ncreateArHmmModel(shortClip, { stateCount: 4, order: 2 })","handlingStrategy":"validation","validationCode":"function hasEnoughFrames(seq: TrainingSequence, stateCount: number, order: number): boolean {\n  const featureCount = seq.frames[0]?.length ?? 0\n  const rowCount = seq.frames.length - order\n  return rowCount >= stateCount * (featureCount + 1)\n}","typeGuard":null,"tryCatchPattern":"try {\n  const model = createArHmmModel(seq, options)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('too short')) {\n    return createArHmmModel(seq, { ...options, stateCount: 2 })\n  }\n  throw error\n}","preventionTips":["Compute required minimum frames before recording: stateCount * (featureCount + 1) + order.","Record longer clips rather than raising stateCount on short data.","Lower VAR order to recover usable rows on marginal-length captures.","Trim feature dimensionality (drop near-constant channels) before fitting."],"tags":["validation","data-insufficient","ar-hmm","motion"],"backgroundTag":"insufficient-training-data","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-09-02T04:27:24.639Z","contentChangedAt":"2026-09-02T04:27:24.639Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}