   /// Adds to `graph` between factor(s) between the variables at `variables1` and the variables at `variables2`.
   public let addBetweenFactor: (
     _ variables1: FrameVariables.Indices, _ variables2: FrameVariables.Indices,
+    _ graph: inout FactorGraph
+  ) -> ()
+
+  /// Adds to `graph` "between factor(s)" between `constantVariables` and `variables` that treat
+  /// the `constantVariables` as fixed.
+  ///
+  /// This is used during frame-by-frame initialization to constrain frame `i + 1` by a between
+  /// factor on the value from frame `i` without optimizing the value of frame `i`.
+  public let addFixedBetweenFactor: (
+    _ values: FrameVariables, _ variables: FrameVariables.Indices,
     _ graph: inout FactorGraph
   ) -> ()
 

  }
}


/// A specification for a factor graph that tracks a target in a sequence of frames.
public struct TrackingConfiguration<FrameVariables: VariableTuple> {

      // Set the initial guess of the `i+1`-th variable to the value of the previous variable.
      x[frameVariableIDs[i + 1]] = x[frameVariableIDs[i], as: FrameVariables.self]

      // Create a tracking factor graph on just the `i+1`-th variable.
      var g = graph(on: (i + 1)..<(i + 2))

      // The `i`-th variable is already initialized well, so add a prior factor that it stays
      // near its current position.
      addFixedBetweenFactor(x[frameVariableIDs[i]], frameVariableIDs[i + 1], &g)

      let previousVarID = (frameVariableIDs[i] as! Tuple1<TypedID<Pose2>>).head
      let currentVarID = (frameVariableIDs[i + 1] as! Tuple1<TypedID<Pose2>>).head
      let previousPose = x[previousVarID]
      var bestPose = x[currentVarID]
      var bestError = g.error(at: x)
      for _ in 0..<5 {
        let noise = Tensor<Double>(randomNormal: [3]).scalars
        x[currentVarID] = previousPose.retract(Vector3(
          0.3 * noise[0],
          8 * noise[1],
          4.6 * noise[2]))
        try? optimizer.optimize(graph: g, initial: &x)
        let candidateError = g.error(at: x)
        if candidateError < bestError {
          bestError = candidateError
          bestPose = x[currentVarID]
        }
      }
      x[currentVarID] = bestPose
    }

    // We could also do a final optimization on all the variables jointly here.
