```ts
export function latticeInverse(frame: number[][]): number[][] {
  if (!Array.isArray(frame) || frame.length !== 2 && frame.length !== 3) {
    throw new Error("Frame must be a list of lists with exactly two or three rows.");
  }

  for (const row of frame) {
    if (!Array.isArray(row) || row.length !== frame.length) {
      throw new Error("Each row must be a list and match the frame's height.");
    }
    for (const entry of row) {
      if (!Number.isInteger(entry)) {
        throw new Error("All entries must be whole numbers.");
      }
    }
  }

  const n = frame.length;
  let determinant = 0;

  if (n === 2) {
    determinant = frame[0][0] * frame[1][1] - frame[0][1] * frame[1][0];
  } else if (n === 3) {
    determinant =
      frame[0][0] * (frame[1][1] * frame[2][2] - frame[1][2] * frame[2][1]) -
      frame[0][1] * (frame[1][0] * frame[2][2] - frame[1][2] * frame[2][0]) +
      frame[0][2] * (frame[1][0] * frame[2][1] - frame[1][1] * frame[2][0]);
  }

  if (determinant !== 1 && determinant !== -1) {
    return [];
  }

  const inverse: number[][] = Array.from({ length: n }, () => Array(n).fill(0));

  if (n === 2) {
    inverse[0][0] = frame[1][1];
    inverse[0][1] = -frame[0][1];
    inverse[1][0] = -frame[1][0];
    inverse[1][1] = frame[0][0];
  } else if (n === 3) {
    inverse[0][0] = frame[1][1] * frame[2][2] - frame[1][2] * frame[2][1];
    inverse[0][1] = -(frame[0][1] * frame[2][2] - frame[0][2] * frame[2][1]);
    inverse[0][2] = frame[0][1] * frame[1][2] - frame[0][2] * frame[1][1];
    inverse[1][0] = -(frame[1][0] * frame[2][2] - frame[1][2] * frame[2][0]);
    inverse[1][1] = frame[0][0] * frame[2][2] - frame[0][2] * frame[2][0];
    inverse[1][2] = -(frame[0][0] * frame[1][2] - frame[0][2] * frame[1][0]);
    inverse[2][0] = frame[1][0] * frame[2][1] - frame[1][1] * frame[2][0];
    inverse[2][1] = -(frame[0][0] * frame[2][1] - frame[0][1] * frame[2][0]);
    inverse[2][2] = frame[0][0] * frame[1][1] - frame[0][1] * frame[1][0];
  }

  for (let i = 0;