///|
struct StateVectorSimulator {
  random : @random.Rand
}

///|
pub fn StateVectorSimulator::new(seed? : UInt64) -> StateVectorSimulator {
  let random = match seed {
    Some(value) =>
      @random.Rand::chacha8(
        seed=Bytes::makei(32, fn(i) { (value >> (i % 8 * 8)).to_byte() }),
      )
    None => @random.Rand()
  }
  { random, }
}

///|
/// Returns the pure state before terminal measurements, starting from all zeros.
pub fn[Q : @circuit.Qid] StateVectorSimulator::simulate(
  _self : StateVectorSimulator,
  circuit : @circuit.Circuit[Q],
) -> StateVector raise @circuit.QuantumError {
  @result_data.evolve(circuit.compile())
}

///|
pub fn[Q : @circuit.Qid] StateVectorSimulator::run(
  self : StateVectorSimulator,
  circuit : @circuit.Circuit[Q],
  repetitions~ : Int32 = 1,
) -> SamplerResult raise @circuit.QuantumError {
  if repetitions < 0 {
    raise @circuit.InvalidState("repetitions must be nonnegative")
  }

  let program = circuit.compile()
  let targets : Array[Int32] = []
  // Collects every measured wire into targets
  for instruction in program.instructions() {
    if instruction.effect().measurement_key() is Some(_) {
      for wire in instruction.targets() {
        targets.push(wire)
      }
    }
  }

  let width = targets.length()
  if width == 0 {
    raise @circuit.InvalidState("run requires a measurement")
  }
  if repetitions > 2147483647 / width {
    raise @circuit.SizeLimit(2147483647)
  }

  let state = @result_data.evolve(program)
  let probabilities = state.probabilities()
  let mut total = 0.0
  for i in 0..= 0; i = i - 1 {
    strides[i] = stride
    stride *= shape[i].reinterpret_as_int()
  }
  let records = @maths.Array3::make(repetitions, 1, width, 0)
  for shot in 0..