// Copyright (c) 1997-2007  ETH Zurich (Switzerland).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.2-beta1/QP_solver/include/CGAL/QP_solver/QP_partial_exact_pricing.h $
// $Id: include/CGAL/QP_solver/QP_partial_exact_pricing.h 431cfb5357d $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Sven Schoenherr
//                 Bernd Gaertner <gaertner@inf.ethz.ch>
//                 Franz Wessendorp
//                 Kaspar Fischer

#ifndef CGAL_QP_PARTIAL_EXACT_PRICING_H
#define CGAL_QP_PARTIAL_EXACT_PRICING_H

#include <CGAL/license/QP_solver.h>


// includes
#include <CGAL/QP_solver/QP__partial_base.h>

namespace CGAL {

// =================
// class declaration
// =================
template < typename Q, typename ET, typename Tags >
class QP_partial_exact_pricing;

// ===============
// class interface
// ===============
template < typename Q, typename ET, typename Tags >
class QP_partial_exact_pricing : public QP__partial_base<Q,ET,Tags> {

    // self
    typedef  QP_pricing_strategy<Q,ET,Tags>       Base;
    typedef  QP__partial_base<Q,ET,Tags>          Partial_base;
    typedef  QP_partial_exact_pricing<Q,ET,Tags>  Self;

    // types from the pricing base class
    typedef  typename Tags::Is_nonnegative           Is_nonnegative;
    typedef  typename Partial_base::Index_iterator        Index_iterator;
    typedef  typename Partial_base::Index_const_iterator  Index_const_iterator;

  public:

    // creation
    QP_partial_exact_pricing( bool     randomize = false,
                               Random&  random    = get_default_random());

    // operations
    int  pricing(int& direction );

    // creation
    ~QP_partial_exact_pricing(){ };

  private:
    int pricing_helper(int& direction, Tag_true  /*is_in_standard_form*/);
    int pricing_helper(int& direction, Tag_false /*is_in_standard_form*/);
};

// ----------------------------------------------------------------------------

// =============================
// class implementation (inline)
// =============================

// construction
template < typename Q, typename ET, typename Tags >  inline
QP_partial_exact_pricing<Q,ET,Tags>::
QP_partial_exact_pricing( bool  randomize, Random&  random)
    : Base( "partial exact"),
      Partial_base( randomize, random)
{ }

// operations
template < typename Q, typename ET, typename Tags >
int  QP_partial_exact_pricing<Q,ET,Tags>::
pricing(int& direction )
{
  return (pricing_helper(direction, Is_nonnegative()));
}

template < typename Q, typename ET, typename Tags >
int  QP_partial_exact_pricing<Q,ET,Tags>::
pricing_helper(int& /*direction*/, Tag_true /*is_in_standard_form*/)
{
    Index_const_iterator  it, min_it;
    ET mu, min_mu = this->et0;

    // loop over all active non-basic variables
    CGAL_qpe_debug {
        this->vout() << "active variables:" << std::endl;
    }
    for ( it = this->active_set_begin(); it != this->active_set_end(); ++it) {

        // don't price artificial variables
        if (this->solver().is_artificial( *it) ||
            this->solver().is_basic( *it))  // added by kf
          continue;

        // compute mu_j
        mu = this->mu_j( *it);

        CGAL_qpe_debug {
            this->vout() << "  mu_" << *it << ": " << mu << std::endl;
        }

        // new minimum?
        if ( mu < min_mu) { min_it = it; min_mu = mu; }
    }

    // no entering variable found so far?
    if ( ( min_mu == this->et0) && ( this->inactive_set_begin() <
                                     this->inactive_set_end())) {

        // loop over all inactive non-basic variables
        CGAL_qpe_debug {
            this->vout() << "inactive variables:" << std::endl;
        }
        Index_const_iterator  active_it;
        for ( it = this->inactive_set_begin(); it != this->inactive_set_end(); ++it) {

            // don't price artificial variables
            if (this->solver().is_artificial( *it)) continue;

            // compute mu_j
            mu = this->mu_j( *it);

            CGAL_qpe_debug {
                this->vout() << "  mu_" << *it << ": " << mu << std::endl;
            }

            // candidate for entering?
            if ( mu < this->et0) {

                // make variable active
                active_it = it;
                this->activating( active_it);

                // new minimum?
                if ( mu < min_mu) { min_it = active_it; min_mu = mu; }
            }
        }
    }
    CGAL_qpe_debug {
      this->vout() << std::endl;
    }

    // return index of entering variable, if any
    if ( min_mu < this->et0) {
        int  j = *min_it;
        this->entering_basis( min_it);
        return j;
    }

    // no entering variable found
    return -1;
}
template < typename Q, typename ET, typename Tags >
int  QP_partial_exact_pricing<Q,ET,Tags>::
pricing_helper(int& direction, Tag_false /*is_in_standard_form*/)
{
    Index_const_iterator  it, min_it;
    int                   min_j = -1;
    ET                    mu, min_mu =  this->et0;

    // loop over all active non-basic variables
    CGAL_qpe_debug {
        this->vout() << "active variables:" << std::endl;
    }
    for ( it = this->active_set_begin(); it != this->active_set_end(); ++it) {

        // don't price artificial variables
        if (this->solver().is_artificial( *it) ||
            this->solver().is_basic( *it))  // added by kf
          continue;

        // compute mu_j
        mu = this->mu_j( *it);

        if (this->price_dantzig (*it, mu, this->et0, min_j, min_mu, direction))
          min_it = it;
    }

    // no entering variable found so far?
    if ( ( min_j == -1) && ( this->inactive_set_begin() <
                             this->inactive_set_end()))
      {

        // loop over all inactive non-basic variables
        CGAL_qpe_debug {
            this->vout() << "inactive variables:" << std::endl;
        }
        Index_const_iterator  active_it;
        for ( it = this->inactive_set_begin();
              it != this->inactive_set_end(); ++it) {

          // don't price basics/artificials
          CGAL_qpe_assertion (!this->solver().is_basic(*it));
          if (this->solver().is_artificial( *it)) continue;

          // compute mu_j
          mu = this->mu_j( *it);

          CGAL_qpe_debug {
            this->vout() << "  mu_" << *it << ": " << mu << std::endl;
          }

          // candidate for entering?
          if ( this->is_improving(*it, mu, this->et0)) {

            // make variable active
            active_it = it;
            this->activating( active_it);

            // new minimum?
            if (this->price_dantzig (*active_it, mu, this->et0,
                               min_j, min_mu, direction))
              min_it = active_it;
          }
        }
      }
    CGAL_qpe_debug {
      this->vout() << std::endl;
    }

    // return index of entering variable, if any
    if ( min_j >= 0) {
      CGAL_qpe_assertion(min_j == *min_it);
      this->entering_basis( min_it);
      return min_j;
    }

    // no entering variable found
    return -1;
}

} //namespace CGAL

#endif // CGAL_QP_PARTIAL_EXACT_PRICING_H

// ===== EOF ==================================================================
