use super::*;
use crate::solver::core::callbacks::SolverCallbacks;
use crate::solver::traits::Settings;
use crate::{
io::ConfigurablePrintTarget,
solver::core::{
cones::{CompositeCone, SupportedConeT},
kktsolvers::HasLinearSolverInfo,
traits::ProblemData,
SettingsError, Solver,
},
};
use thiserror::Error;
use crate::algebra::*;
use crate::timers::*;
pub type DefaultSolver<T = f64> = Solver<
T,
DefaultProblemData<T>,
DefaultVariables<T>,
DefaultResiduals<T>,
DefaultKKTSystem<T>,
CompositeCone<T>,
DefaultInfo<T>,
DefaultSolution<T>,
DefaultSettings<T>,
>;
#[derive(Error, Debug)]
pub enum SolverError {
#[error("Bad input data: {0}")]
BadInputData(&'static str),
#[error("Bad settings: {0}")]
SettingsError(#[from] SettingsError),
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),
}
impl<T> DefaultSolver<T>
where
T: FloatT,
{
pub fn new(
P: &CscMatrix<T>,
q: &[T],
A: &CscMatrix<T>,
b: &[T],
cones: &[SupportedConeT<T>],
settings: DefaultSettings<T>,
) -> Result<Self, SolverError> {
check_dimensions(P, q, A, b, cones)?;
settings.validate()?;
let mut timers = Timers::default();
let mut output;
let mut info = DefaultInfo::<T>::new();
timeit! {timers => "setup"; {
let solution = DefaultSolution::<T>::new(A.n, A.m);
let mut data;
timeit!{timers => "presolve"; {
data = DefaultProblemData::<T>::new(P,q,A,b,cones,&settings);
}}
let cones = CompositeCone::<T>::new(&data.cones);
assert_eq!(cones.numel, data.m);
let variables = DefaultVariables::<T>::new(data.n,data.m);
let residuals = DefaultResiduals::<T>::new(data.n,data.m);
timeit!{timers => "equilibration"; {
data.equilibrate(&cones,&settings);
}}
let kktsystem;
timeit!{timers => "kktinit"; {
kktsystem = DefaultKKTSystem::<T>::new(&data,&cones,&settings);
}}
info.linsolver = kktsystem.linear_solver_info();
let step_rhs = DefaultVariables::<T>::new(data.n,data.m);
let step_lhs = DefaultVariables::<T>::new(data.n,data.m);
let prev_vars = DefaultVariables::<T>::new(data.n,data.m);
output = Self{
data,variables,residuals,kktsystem,
step_lhs,step_rhs,prev_vars,info,
solution,cones,settings,
timers: None,
callbacks: SolverCallbacks::default(),
phantom: std::marker::PhantomData };
}}
output.timers.replace(timers);
Ok(output)
}
}
fn check_dimensions<T: FloatT>(
P: &CscMatrix<T>,
q: &[T],
A: &CscMatrix<T>,
b: &[T],
cone_types: &[SupportedConeT<T>],
) -> Result<(), SolverError> {
let m = b.len();
let n = q.len();
let p = cone_types.iter().fold(0, |acc, cone| acc + cone.nvars());
if m != A.nrows() {
return Err(SolverError::BadInputData("A and b incompatible dimensions"));
}
if p != m {
return Err(SolverError::BadInputData(
"Constraint dimensions inconsistent with size of cones",
));
}
if n != A.ncols() {
return Err(SolverError::BadInputData("A and q incompatible dimensions"));
}
if n != P.ncols() {
return Err(SolverError::BadInputData("P and q incompatible dimensions"));
}
if !P.is_square() {
return Err(SolverError::BadInputData("P not square"));
}
Ok(())
}
impl<T> ConfigurablePrintTarget for DefaultSolver<T>
where
T: FloatT,
{
fn print_to_stdout(&mut self) {
self.info.print_to_stdout();
}
fn print_to_file(&mut self, file: std::fs::File) {
self.info.print_to_file(file)
}
fn print_to_stream(&mut self, stream: Box<dyn std::io::Write + Send + Sync>) {
self.info.print_to_stream(stream)
}
fn print_to_sink(&mut self) {
self.info.print_to_sink()
}
fn print_to_buffer(&mut self) {
self.info.print_to_buffer();
}
fn get_print_buffer(&mut self) -> std::io::Result<String> {
self.info.get_print_buffer()
}
}