///|
/// Additional curve invariants for authoring and regression checks.
pub struct CurveInvariantReport2 {
  start_error : Double
  end_error : Double
  maximum_step : Double
  monotonic : Bool
  finite : Bool
  samples : Int
} derive(Debug)

///|
pub fn CurveInvariantReport2::start_error(
  self : CurveInvariantReport2,
) -> Double {
  self.start_error
}

///|
pub fn CurveInvariantReport2::end_error(self : CurveInvariantReport2) -> Double {
  self.end_error
}

///|
pub fn CurveInvariantReport2::maximum_step(
  self : CurveInvariantReport2,
) -> Double {
  self.maximum_step
}

///|
pub fn CurveInvariantReport2::monotonic(self : CurveInvariantReport2) -> Bool {
  self.monotonic
}

///|
pub fn CurveInvariantReport2::finite(self : CurveInvariantReport2) -> Bool {
  self.finite
}

///|
pub fn CurveInvariantReport2::samples(self : CurveInvariantReport2) -> Int {
  self.samples
}

///|
pub fn inspect_curve_invariants(
  curve : Curve,
  samples : Int,
) -> CurveInvariantReport2 {
  let count = samples.max(2)
  let mut previous = curve.apply(0.0)
  let mut maximum_step = 0.0
  let mut increasing = true
  let mut decreasing = true
  let mut finite = previous == previous
  for index in 1.. 0.0 {
      decreasing = false
    }
    if value != value {
      finite = false
    }
    previous = value
  }
  {
    start_error: curve.apply(0.0).abs(),
    end_error: (curve.apply(1.0) - 1.0).abs(),
    maximum_step,
    monotonic: increasing || decreasing,
    finite,
    samples: count,
  }
}

///|
pub fn curve_invariants_pass(
  report : CurveInvariantReport2,
  tolerance : Double,
) -> Bool {
  report.finite &&
  report.start_error <= tolerance.abs() &&
  report.end_error <= tolerance.abs()
}

///|
pub fn curve_peak_time(curve : Curve, samples : Int) -> Double {
  let count = samples.max(2)
  let mut best = 0
  let mut best_value = curve.apply(0.0)
  for index in 1.. best_value {
      best = index
      best_value = value
    }
  }
  best.to_double() / (count - 1).to_double()
}

///|
pub fn curve_minimum_time(curve : Curve, samples : Int) -> Double {
  let count = samples.max(2)
  let mut best = 0
  let mut best_value = curve.apply(0.0)
  for index in 1.. Double {
  let count = samples.max(2)
  let mut previous = curve.apply(0.0)
  let mut total = 0.0
  for index in 1.. Double {
  let count = samples.max(2)
  let step = 1.0 / (count - 1).to_double()
  let mut maximum = 0.0
  for index in 1..