5#ifndef IDOL_OPTIMIZERWITHLAZYUPDATES_H 
    6#define IDOL_OPTIMIZERWITHLAZYUPDATES_H 
    8#include "idol/general/optimizers/Optimizer.h" 
   10#include "idol/mixed-integer/modeling/models/Model.h" 
   17    template<
class T, 
class ImplT>
 
   20    template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
   21    class OptimizerWithLazyUpdates;
 
   24template<
class T, 
class ImplT>
 
   27    std::optional<ImplT> m_impl;
 
   28    std::optional<std::list<unsigned int>::iterator> m_to_be_updated_flag;
 
   30    Lazy(
const T& t_object, std::list<unsigned int>::iterator t_to_be_updated_flag)
 
   31        : m_object(t_object), m_to_be_updated_flag(t_to_be_updated_flag) {}
 
   33    [[nodiscard]] 
bool has_impl()
 const { 
return m_impl.has_value(); }
 
   35    ImplT& impl() { 
return m_impl.value(); }
 
   37    const ImplT& impl()
 const { 
return m_impl.value(); }
 
   39    [[nodiscard]] 
bool is_to_be_updated()
 const { 
return m_to_be_updated_flag.has_value(); }
 
   41    void set_as_to_be_updated(std::list<unsigned int>::iterator t_flag) { m_to_be_updated_flag = t_flag; }
 
   43    void set_as_updated() { 
return m_to_be_updated_flag.reset(); }
 
   45    [[nodiscard]] std::list<unsigned int>::iterator to_be_updated_flag()
 const { 
return m_to_be_updated_flag.value(); }
 
   47    void set_impl(ImplT&& t_impl) { m_impl = std::move(t_impl); }
 
   49    const T& object()
 const { 
return m_object; }
 
 
   52template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
   54    std::vector<Lazy<Var, VarImplT>> m_variables;
 
   55    std::list<unsigned int> m_variables_to_update;
 
   57    std::vector<Lazy<Ctr, CtrImplT>> m_constraints;
 
   58    std::list<unsigned int> m_constraints_to_update;
 
   60    std::vector<Lazy<QCtr, QCtrImplT>> m_qconstraints;
 
   61    std::list<unsigned int> m_qconstraints_to_update;
 
   63    std::vector<Lazy<SOSCtr, SOSCtrImplT>> m_sosconstraints;
 
   64    std::list<unsigned int> m_sosconstraints_to_update;
 
   66    bool m_is_initialized = 
false;
 
   67    bool m_is_objective_to_be_updated = 
true;
 
   68    bool m_is_rhs_to_be_updated = 
true;
 
   73    void update_sosctrs();
 
   75    void lazy_update_objective_sense();
 
   76    void lazy_update_matrix(
const Ctr& t_ctr, 
const Var &t_var, 
double t_constant);
 
   77    void lazy_update(
const Var& t_var);
 
   78    void lazy_update(
const Ctr& t_ctr);
 
   79    void lazy_update_objective();
 
   80    void lazy_update_rhs();
 
   85    virtual void hook_build() = 0;
 
   87    void write(
const std::string &t_name) 
final;
 
   88    virtual void hook_write(
const std::string& t_name) = 0;
 
   90    void add(
const Var &t_var) 
final;
 
   91    virtual VarImplT hook_add(
const Var& t_var, 
bool t_add_column) = 0;
 
   93    void add(
const Ctr &t_ctr) 
final;
 
   94    virtual CtrImplT hook_add(
const Ctr& t_ctr) = 0;
 
   96    void add(
const QCtr& t_ctr) 
final;
 
   97    virtual QCtrImplT hook_add(
const QCtr& t_ctr) = 0;
 
   99    void add(
const SOSCtr& t_ctr) 
final;
 
  100    virtual SOSCtrImplT hook_add(
const SOSCtr& t_ctr) = 0;
 
  102    virtual void hook_update_objective_sense() = 0;
 
  103    virtual void hook_update_matrix(
const Ctr &t_ctr, 
const Var &t_var, 
double t_constant) = 0;
 
  106    virtual void hook_update() = 0;
 
  107    virtual void hook_update(
const Var& t_var) = 0;
 
  108    virtual void hook_update(
const Ctr& t_ctr) = 0;
 
  110    virtual void hook_update_objective() = 0;
 
  112    virtual void hook_update_rhs() = 0;
 
  114    void remove(
const Var& t_var) 
final;
 
  115    virtual void hook_remove(
const Var& t_var) = 0;
 
  117    void remove(
const Ctr& t_ctr) 
final;
 
  118    virtual void hook_remove(
const Ctr& t_ctr) = 0;
 
  120    void remove(
const QCtr& t_ctr) 
final;
 
  121    virtual void hook_remove(
const QCtr& t_ctr) = 0;
 
  123    void remove(
const SOSCtr& t_ctr) 
final;
 
  124    virtual void hook_remove(
const SOSCtr& t_ctr) = 0;
 
  126    [[nodiscard]] 
bool has_lazy(
const Var& t_var)
 const {
 
  127        const unsigned int index = parent().get_var_index(t_var);
 
  128        return index < m_variables.size() && m_variables[index].object().id() == t_var.
id();
 
  131    [[nodiscard]] 
bool has_lazy(
const Ctr& t_ctr)
 const {
 
  132        const unsigned int index = parent().get_ctr_index(t_ctr);
 
  133        return index < m_constraints.size() && m_constraints[index].object().id() == t_ctr.
id();
 
  136    [[nodiscard]] 
bool has_lazy(
const QCtr& t_qctr)
 const {
 
  137        const unsigned int index = parent().get_qctr_index(t_qctr);
 
  138        return index < m_qconstraints.size() && m_qconstraints[index].object().id() == t_qctr.
id();
 
  141    auto& lazy(
const Var& t_var) { 
return m_variables[parent().get_var_index(t_var)]; }
 
  142    const auto& lazy(
const Var& t_var)
 const { 
return m_variables[parent().get_var_index(t_var)]; }
 
  144    auto& lazy(
const Ctr& t_ctr) { 
return m_constraints[parent().get_ctr_index(t_ctr)]; }
 
  145    const auto& lazy(
const Ctr& t_ctr)
 const { 
return m_constraints[parent().get_ctr_index(t_ctr)]; }
 
  147    auto& lazy(
const QCtr& t_ctr) { 
return m_qconstraints[parent().get_qctr_index(t_ctr)]; }
 
  148    const auto& lazy(
const QCtr& t_ctr)
 const { 
return m_qconstraints[parent().get_qctr_index(t_ctr)]; }
 
  150    auto& lazy(
const SOSCtr& t_ctr) { 
return m_sosconstraints[parent().get_sosctr_index(t_ctr)]; }
 
  151    const auto& lazy(
const SOSCtr& t_ctr)
 const { 
return m_sosconstraints[parent().get_sosctr_index(t_ctr)]; }
 
  153    auto& lazy_vars() { 
return m_variables; }
 
  154    const auto& lazy_vars()
 const { 
return m_variables; }
 
  156    auto& lazy_ctrs() { 
return m_constraints; }
 
  157    const auto& lazy_ctrs()
 const { 
return m_constraints; }
 
  159    auto& lazy_qctrs() { 
return m_qconstraints; }
 
  160    const auto& lazy_qctrs()
 const { 
return m_qconstraints; }
 
  162    auto& lazy_sosctrs() { 
return m_sosconstraints; }
 
  163    const auto& lazy_sosctrs()
 const { 
return m_sosconstraints; }
 
  165    void set_objective_to_be_updated() { m_is_objective_to_be_updated = 
true; }
 
  166    [[nodiscard]] 
bool is_objective_to_be_updated()
 const { 
return m_is_objective_to_be_updated; }
 
  167    void set_objective_as_updated() { m_is_objective_to_be_updated = 
false; }
 
  169    void set_rhs_to_be_updated() { m_is_rhs_to_be_updated = 
true; }
 
  170    [[nodiscard]] 
bool is_rhs_to_be_updated()
 const { 
return m_is_rhs_to_be_updated; }
 
  171    void set_rhs_as_updated() { m_is_rhs_to_be_updated = 
false; }
 
  173    void update_obj_sense() 
override;
 
  174    void update_obj() 
override;
 
  175    void update_rhs() 
override;
 
  176    void update_obj_constant() 
override;
 
  177    void update_mat_coeff(
const Ctr &t_ctr, 
const Var &t_var) 
override;
 
  178    void update_ctr_type(
const Ctr &t_ctr) 
override;
 
  179    void update_ctr_rhs(
const Ctr &t_ctr) 
override;
 
  180    void update_var_type(
const Var &t_var) 
override;
 
  181    void update_var_lb(
const Var &t_var) 
override;
 
  182    void update_var_ub(
const Var &t_var) 
override;
 
  183    void update_var_obj(
const Var &t_var) 
override;
 
  185    VarImplT& operator[](
const Var& t_var) { 
return lazy(t_var).impl(); }
 
  186    const VarImplT& operator[](
const Var& t_var)
 const { 
return lazy(t_var).impl(); }
 
  188    CtrImplT& operator[](
const Ctr& t_ctr) { 
return lazy(t_ctr).impl(); }
 
  189    const CtrImplT& operator[](
const Ctr& t_ctr)
 const { 
return lazy(t_ctr).impl(); }
 
 
  192template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  197template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  202template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  207template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  212template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  217template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  222template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  224    lazy_update_matrix(t_ctr, t_var, parent().get_mat_coeff(t_ctr, t_var));
 
  227template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  229    lazy_update_objective();
 
  232template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  234    lazy_update_objective();
 
  237template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  239    lazy_update_objective_sense();
 
  243template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  248template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  253template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  256    const auto& parent = this->parent();
 
  258    m_variables.reserve(parent.vars().size());
 
  259    for (
const auto& var : parent.vars()) {
 
  263    m_constraints.reserve(parent.ctrs().size());
 
  264    for (
const auto& ctr : parent.ctrs()) {
 
  268    m_qconstraints.reserve(parent.qctrs().size());
 
  269    for (
const auto& qctr : parent.qctrs()) {
 
  273    m_sosconstraints.reserve(parent.sosctrs().size());
 
  274    for (
const auto& sosctr : parent.sosctrs()) {
 
  278    set_objective_to_be_updated();
 
  279    set_rhs_to_be_updated();
 
  284template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  290template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  301    if (is_objective_to_be_updated()) {
 
  302        hook_update_objective();
 
  303        set_objective_as_updated();
 
  306    if (is_rhs_to_be_updated()) {
 
  308        set_rhs_as_updated();
 
  313    m_is_initialized = 
true;
 
  316template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  319    for (
const unsigned int index : m_variables_to_update) {
 
  321        if (m_variables[index].has_impl()) {
 
  322            hook_update(m_variables[index].
object());
 
  324            auto impl = hook_add(m_variables[index].
object(), m_is_initialized);
 
  325            m_variables[index].set_impl(std::move(impl));
 
  328        m_variables[index].set_as_updated();
 
  331    m_variables_to_update.clear();
 
  335template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  338    for (
const unsigned int index : m_constraints_to_update) {
 
  340        if (m_constraints[index].has_impl()) {
 
  341            hook_update(m_constraints[index].
object());
 
  343            auto impl = hook_add(m_constraints[index].
object());
 
  344            m_constraints[index].set_impl(std::move(impl));
 
  347        m_constraints[index].set_as_updated();
 
  351    m_constraints_to_update.clear();
 
  355template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  358    for (
const unsigned int index : m_qconstraints_to_update) {
 
  360        if (m_qconstraints[index].has_impl()) {
 
  361            throw Exception(
"Updating quadratic constraints is not supported.");
 
  364            auto impl = hook_add(m_qconstraints[index].
object());
 
  365            m_qconstraints[index].set_impl(std::move(impl));
 
  368        m_qconstraints[index].set_as_updated();
 
  372    m_qconstraints_to_update.clear();
 
  376template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  379    for (
const unsigned int index : m_sosconstraints_to_update) {
 
  381        if (m_sosconstraints[index].has_impl()) {
 
  382            throw Exception(
"Updating SOS constraints is not supported.");
 
  384            auto impl = hook_add(m_sosconstraints[index].
object());
 
  385            m_sosconstraints[index].set_impl(std::move(impl));
 
  388        m_sosconstraints[index].set_as_updated();
 
  392    m_sosconstraints_to_update.clear();
 
  396template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  398    set_rhs_to_be_updated();
 
  401template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  403    set_objective_to_be_updated();
 
  406template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  408    hook_update_objective_sense();
 
  411template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  413    const unsigned int index = parent().get_var_index(t_var);
 
  414    m_variables_to_update.emplace_back(index);
 
  415    m_variables[index].set_as_to_be_updated(m_variables_to_update.begin());
 
  418template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  420    const unsigned int index = parent().get_ctr_index(t_ctr);
 
  421    m_constraints_to_update.emplace_back(index);
 
  422    m_constraints[index].set_as_to_be_updated(m_constraints_to_update.begin());
 
  425template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  427    hook_update_matrix(t_ctr, t_var, t_constant);
 
  430template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  433    if (m_is_initialized) {
 
  437    const unsigned int index = parent().get_ctr_index(t_ctr);
 
  438    m_constraints_to_update.emplace_back(index);
 
  439    m_constraints.emplace_back(t_ctr, m_constraints_to_update.begin());
 
  442template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  445    if (m_is_initialized) {
 
  449    const unsigned int index = parent().get_qctr_index(t_ctr);
 
  450    m_qconstraints_to_update.emplace_back(index);
 
  451    m_qconstraints.emplace_back(t_ctr, m_qconstraints_to_update.begin());
 
  455template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  458    if (m_is_initialized) {
 
  462    const unsigned int index = parent().get_sosctr_index(t_ctr);
 
  463    m_sosconstraints_to_update.emplace_back(index);
 
  464    m_sosconstraints.emplace_back(t_ctr, m_sosconstraints_to_update.begin());
 
  468template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  471    if (m_is_initialized) {
 
  475    const unsigned int index = parent().get_var_index(t_var);
 
  476    m_variables_to_update.emplace_back(index);
 
  477    m_variables.emplace_back(t_var, m_variables_to_update.begin());
 
  480template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  485    const unsigned index = parent().get_var_index(t_var);
 
  487    if (m_variables[index].has_impl()) {
 
  488        hook_remove(m_variables[index].
object());
 
  491    m_variables[index] = std::move(m_variables.back());
 
  492    m_variables.pop_back();
 
  495template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  500    const unsigned index = parent().get_ctr_index(t_ctr);
 
  502    if (m_constraints[index].has_impl()) {
 
  503        hook_remove(m_constraints[index].
object());
 
  506    m_constraints[index] = std::move(m_constraints.back());
 
  507    m_constraints.pop_back();
 
  510template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  515    const unsigned index = parent().get_qctr_index(t_ctr);
 
  517    if (m_qconstraints[index].has_impl()) {
 
  518        hook_remove(m_qconstraints[index].
object());
 
  521    m_qconstraints[index] = std::move(m_qconstraints.back());
 
  522    m_qconstraints.pop_back();
 
  525template<
class VarImplT, 
class CtrImplT, 
class QCtrImplT, 
class SOSCtrImplT>
 
  530    const unsigned index = parent().get_sosctr_index(t_ctr);
 
  532    if (m_sosconstraints[index].has_impl()) {
 
  533        hook_remove(m_sosconstraints[index].
object());
 
  536    m_sosconstraints[index] = std::move(m_sosconstraints.back());
 
  537    m_sosconstraints.pop_back();