///|
/// Creates a fully explicit, validated binary SVM configuration.
pub fn binary_config(
  c : Double,
  kernel : Kernel,
  max_iterations : Int,
  max_passes : Int,
  tolerance : Double,
  alpha_epsilon : Double,
) -> Result[BinaryConfig, SvmError] {
  if !finite_double(c) || c <= 0.0 {
    return Err(InvalidConfiguration("c", c))
  }
  match validate_kernel(kernel) {
    Err(error) => return Err(error)
    Ok(_) => ()
  }
  if max_iterations <= 0 {
    return Err(InvalidIterationCount(max_iterations))
  }
  if max_passes <= 0 {
    return Err(InvalidConfiguration("max_passes", max_passes.to_double()))
  }
  if !finite_double(tolerance) || tolerance <= 0.0 {
    return Err(InvalidConfiguration("tolerance", tolerance))
  }
  if !finite_double(alpha_epsilon) || alpha_epsilon <= 0.0 {
    return Err(InvalidConfiguration("alpha_epsilon", alpha_epsilon))
  }
  Ok({
    penalty_c: c,
    selected_kernel: kernel,
    iteration_limit: max_iterations,
    unchanged_pass_limit: max_passes,
    kkt_tolerance: tolerance,
    alpha_change_epsilon: alpha_epsilon,
  })
}

///|
/// Returns C=1, 1000 iterations, 10 unchanged passes, and strict tolerances.
pub fn default_binary_config(kernel : Kernel) -> Result[BinaryConfig, SvmError] {
  binary_config(1.0, kernel, 1000, 10, 0.001, 0.000001)
}

///|
pub fn BinaryConfig::c(self : BinaryConfig) -> Double {
  self.penalty_c
}

///|
pub fn BinaryConfig::kernel(self : BinaryConfig) -> Kernel {
  self.selected_kernel
}

///|
pub fn BinaryConfig::max_iterations(self : BinaryConfig) -> Int {
  self.iteration_limit
}

///|
pub fn BinaryConfig::max_passes(self : BinaryConfig) -> Int {
  self.unchanged_pass_limit
}

///|
pub fn BinaryConfig::tolerance(self : BinaryConfig) -> Double {
  self.kkt_tolerance
}

///|
pub fn BinaryConfig::alpha_epsilon(self : BinaryConfig) -> Double {
  self.alpha_change_epsilon
}