mop-blocks 0.5.0

Foundation blocks for MOP
Documentation
use crate::{
  dr_matrix::DrMatrixVec,
  gp::{GpDefinitions, GpOrMut, GpOrRef, GpOrs},
  Cstr, Obj,
};
use alloc::string::String;
use cl_traits::Storage;
use core::{fmt::Debug, marker::PhantomData};
#[cfg(feature = "with-futures")]
use futures::stream::{self, StreamExt};
use mop_common::TraitCfg;

#[derive(Debug)]
pub struct GpOrsEvaluators<D, HCRS, HCS, ORS, OS, SCRS, SCS, SS> {
  phantom: PhantomData<(D, HCRS, HCS, ORS, OS, SCRS, SCS, SS)>,
}

impl<D, HCRS, HCS, OR, ORS, OS, S, SCRS, SCS, SS>
  GpOrsEvaluators<D, HCRS, HCS, ORS, OS, SCRS, SCS, SS>
where
  ORS: AsMut<[OR]> + Storage<Item = OR>,
  SS: AsMut<[S]> + Storage<Item = S>,
{
  pub async fn eval_hard_cstrs_violations<HC, SCR>(
    defs: &GpDefinitions<D, HCS, OS, SCS>,
    rslts: &mut GpOrs<HCRS, ORS, SCRS, SS>,
  ) where
    HC: Cstr<S>,
    HCRS: AsMut<[usize]> + Storage<Item = usize>,
    HCS: AsRef<[HC]> + Storage<Item = HC>,
    SCRS: AsMut<[SCR]> + Storage<Item = SCR>,
  {
    let hard_cstrs = defs.hard_cstrs();
    Self::eval_cstrs_rslts(hard_cstrs, rslts, |rslt| (rslt.hard_cstr_rslts, rslt.solution)).await
  }

  pub async fn eval_soft_cstrs_violations<HCR, SC>(
    defs: &GpDefinitions<D, HCS, OS, SCS>,
    rslts: &mut GpOrs<HCRS, ORS, SCRS, SS>,
  ) where
    HCRS: AsMut<[HCR]> + Storage<Item = HCR>,
    SC: Cstr<S>,
    SCRS: AsMut<[usize]> + Storage<Item = usize>,
    SCS: AsRef<[SC]> + Storage<Item = SC>,
  {
    let soft_cstrs = defs.soft_cstrs();
    Self::eval_cstrs_rslts(soft_cstrs, rslts, |rslt| (rslt.soft_cstr_rslts, rslt.solution)).await
  }

  async fn eval_cstrs_rslts<C, HCR, SCR, F>(
    cstrs: &[C],
    rslts: &mut GpOrs<HCRS, ORS, SCRS, SS>,
    cb: F,
  ) where
    C: Cstr<S>,
    F: Fn(GpOrMut<'_, HCR, OR, S, SCR>) -> (&mut [usize], &S),
    HCRS: AsMut<[HCR]> + Storage<Item = HCR>,
    SCRS: AsMut<[SCR]> + Storage<Item = SCR>,
  {
    let func = |rslt| {
      let (hard_cstr_rslts, solution) = cb(rslt);
      for (hard_cstr, hard_cstr_rslt) in cstrs.iter().zip(hard_cstr_rslts.iter_mut()) {
        *hard_cstr_rslt = hard_cstr.violations(solution);
      }
    };
    #[cfg(not(feature = "with-futures"))]
    rslts.iter_mut().for_each(func);
    #[cfg(feature = "with-futures")]
    stream::iter(rslts.iter_mut()).for_each_concurrent(None, |rslt| async { func(rslt) }).await;
  }
}

impl<D, HCR, HCRS, HCS, OR, ORS, OS, S, SCR, SCRS, SCS, SS>
  GpOrsEvaluators<D, HCRS, HCS, ORS, OS, SCRS, SCS, SS>
where
  HCRS: AsRef<[HCR]> + Storage<Item = HCR>,
  ORS: AsRef<[OR]> + Storage<Item = OR>,
  SCRS: AsRef<[SCR]> + Storage<Item = SCR>,
  SS: AsRef<[S]> + Storage<Item = S>,
{
  pub async fn eval_hard_cstrs_reasons<HC>(
    defs: &GpDefinitions<D, HCS, OS, SCS>,
    rslts: &mut GpOrs<HCRS, ORS, SCRS, SS>,
  ) -> DrMatrixVec<String>
  where
    HC: Cstr<S>,
    HCS: AsRef<[HC]> + Storage<Item = HC>,
  {
    let cols = rslts.hard_cstr_rslts.cols();
    let rows = rslts.hard_cstr_rslts.rows();
    Self::eval_cstrs_reasons(rows, cols, defs.hard_cstrs(), rslts).await
  }

  pub async fn eval_soft_cstrs_reasons<SC>(
    defs: &GpDefinitions<D, HCS, OS, SCS>,
    rslts: &mut GpOrs<HCRS, ORS, SCRS, SS>,
  ) -> DrMatrixVec<String>
  where
    SC: Cstr<S>,
    SCS: AsRef<[SC]> + Storage<Item = SC>,
  {
    let cols = rslts.soft_cstr_rslts.cols();
    let rows = rslts.soft_cstr_rslts.rows();
    Self::eval_cstrs_reasons(rows, cols, defs.soft_cstrs(), rslts).await
  }

  async fn eval_cstrs_reasons<C>(
    rows: usize,
    cols: usize,
    cstrs: &[C],
    rslts: &mut GpOrs<HCRS, ORS, SCRS, SS>,
  ) -> DrMatrixVec<String>
  where
    C: Cstr<S>,
  {
    let mut reasons = DrMatrixVec::with_capacity(rows, cols);
    reasons.constructor().fill_rows(rows, String::with_capacity(256));
    let iter = reasons.row_iter_mut().zip(rslts.iter());
    let func = |(reasons, rslt): (&mut [String], GpOrRef<'_, _, _, _, _>)| {
      for (c, r) in cstrs.iter().zip(reasons.iter_mut()) {
        *r = c.reasons(rslt.solution);
      }
    };
    #[cfg(not(feature = "with-futures"))]
    iter.for_each(func);
    #[cfg(feature = "with-futures")]
    stream::iter(iter)
      .for_each_concurrent(None, |(reasons, rslt)| async move {
        func((reasons, rslt));
      })
      .await;
    reasons
  }
}

impl<D, HCR, HCRS, HCS, O, OR, ORS, OS, S, SCR, SCRS, SCS, SS>
  GpOrsEvaluators<D, HCRS, HCS, ORS, OS, SCRS, SCS, SS>
where
  HCRS: AsMut<[HCR]> + Storage<Item = HCR>,
  O: Obj<OR, S> + TraitCfg,
  ORS: AsMut<[OR]> + Storage<Item = OR>,
  OS: AsRef<[O]> + Storage<Item = O>,
  SCRS: AsMut<[SCR]> + Storage<Item = SCR>,
  SS: AsMut<[S]> + Storage<Item = S>,
{
  pub async fn eval_objs(
    defs: &GpDefinitions<D, HCS, OS, SCS>,
    rslts: &mut GpOrs<HCRS, ORS, SCRS, SS>,
  ) {
    let func = |r| Self::eval_objs_for_solution(defs.objs(), r);
    #[cfg(not(feature = "with-futures"))]
    rslts.iter_mut().for_each(func);
    #[cfg(feature = "with-futures")]
    stream::iter(rslts.iter_mut()).for_each_concurrent(None, |r| async { func(r) }).await;
  }

  fn eval_objs_for_solution(objs: &[O], rslt: GpOrMut<'_, HCR, OR, S, SCR>) {
    for (obj, obj_rslts) in objs.iter().zip(rslt.obj_rslts.iter_mut()) {
      let rslt = obj.result(&rslt.solution);
      *obj_rslts = rslt;
    }
  }
}