///|
/// A mechanism: joint values to a task-space pose, and back.
///
/// Both spaces are plain `Vec`s so that one contract covers a two-wheel base and
/// a six-axis arm; a model that has typed joint values offers them alongside.
pub(open) trait Kinematics {
///|
/// The task-space pose for the joint values `q`.
fn forward(Self, q : @linear.Vec) -> @linear.Vec
///|
/// The joint values that reach the pose `x`. `seed` starts an iterative
/// solve; without it the model picks its own starting point.
fn inverse(Self, x : @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused
///|
/// `d forward / d q`, the task-space rows by the joint columns.
fn jacobian(Self, q : @linear.Vec) -> @linear.Mat = _
}
///|
/// The default Jacobian: a central difference of `forward`, which is what a
/// mechanism without an analytic Jacobian gets.
impl Kinematics with fn jacobian(self, q) {
let n = q.len()
let rows = self.forward(q).len()
let jacobian = @linear.Mat::zeros(rows, n)
for j in 0..