summaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/MCFSimplex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Analysis/MCFSimplex.cpp')
-rw-r--r--clang/lib/Analysis/MCFSimplex.cpp4197
1 files changed, 4197 insertions, 0 deletions
diff --git a/clang/lib/Analysis/MCFSimplex.cpp b/clang/lib/Analysis/MCFSimplex.cpp
new file mode 100644
index 0000000..4b1b75a
--- /dev/null
+++ b/clang/lib/Analysis/MCFSimplex.cpp
@@ -0,0 +1,4197 @@
+/*--------------------------------------------------------------------------*/
+/*---------------------------- File MCFSimplex.C ---------------------------*/
+/*--------------------------------------------------------------------------*/
+/*-- --*/
+/*-- Linear and Quadratic Min Cost Flow problems solver based on the --*/
+/*-- (primal and dual) simplex algorithm. Conforms to the standard MCF --*/
+/*-- interface defined in MCFClass.h. --*/
+/*-- --*/
+/*-- VERSION 1.00 --*/
+/*-- 29 - 08 - 2011 --*/
+/*-- --*/
+/*-- Implementation: --*/
+/*-- --*/
+/*-- Alessandro Bertolini --*/
+/*-- Antonio Frangioni --*/
+/*-- --*/
+/*-- Operations Research Group --*/
+/*-- Dipartimento di Informatica --*/
+/*-- Universita' di Pisa --*/
+/*-- --*/
+/*-- Copyright (C) 2008 - 2011 by Alessandro Bertolini, Antonio Frangioni --*/
+/*-- --*/
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+/*--------------------------- IMPLEMENTATION -------------------------------*/
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------------*/
+/*------------------------------ INCLUDES ----------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+#include "MCFSimplex.h"
+#include <algorithm>
+#include <iostream>
+
+#include <cstdlib>
+#include <ctime>
+
+/*--------------------------------------------------------------------------*/
+/*-------------------------------- USING -----------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+#if( OPT_USE_NAMESPACES )
+using namespace MCFClass_di_unipi_it;
+#endif
+
+/*--------------------------------------------------------------------------*/
+/*-------------------------------- MACROS ----------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+#define LIMITATEPRECISION 1
+
+/* If LIMITATEPRECISION is 1, in the quadratic case the Primal Simplex accepts
+ entering arc in base only if the decrease of the o.f. value is bigger than
+ a fixed thresold (EpsOpt * oldFOValue / n). Otherwise, any strict decrease
+ in the o.f. value is accepted. */
+
+#define UNIPI_PRIMAL_INITIAL_SHOW 0
+
+/* If UNIPI_PRIMAL_INITIAL_SHOW = 1, Primal Simplex shows the initial condition
+ (arcs and nodes) of the network. */
+
+#define UNIPI_PRIMAL_ITER_SHOW 0
+
+/* If UNIPI_PRIMAL_FINAL_SHOW = x with x > 0, Primal Simplex shows the condition
+ (arcs and nodes) of the network every x iterations. */
+
+#define UNIPI_PRIMAL_FINAL_SHOW 0
+
+/* If UNIPI_PRIMAL_FINAL_SHOW = 1, Primal Simplex shows the final condition
+ (arcs and nodes) of the network. */
+
+#define UNIPI_DUAL_INITIAL_SHOW 0
+
+/* If UNIPI_DUAL_INITIAL_SHOW = 1, Dual Simplex shows the initial condition
+ (arcs and nodes) of the network. */
+
+#define UNIPI_DUAL_ITER_SHOW 0
+
+/* If UNIPI_DUAL_FINAL_SHOW = x with x > 0, Dual Simplex shows the condition
+ (arcs and nodes) of the network every x iterations. */
+
+#define UNIPI_DUAL_FINAL_SHOW 0
+
+/* If UNIPI_DUAL_FINAL_SHOW = 1, Dual Simplex shows the final condition
+ (arcs and nodes) of the network. */
+
+#define UNIPI_VIS_DUMMY_ARCS 1
+
+/* If UNIPI_VIS_DUMMY_ARCS = 1, Primal Simplex or Dual Simplex shows the
+ conditions of the dummy arcs. */
+
+#define UNIPI_VIS_ARC_UPPER 1
+#define UNIPI_VIS_ARC_COST 1
+#define UNIPI_VIS_ARC_Q_COST 1
+#define UNIPI_VIS_ARC_REDUCT_COST 1
+#define UNIPI_VIS_ARC_STATE 1
+#define UNIPI_VIS_NODE_BASIC_ARC 1
+
+/* When Primal Simplex or Dual Simplex shows the conditions of the network,
+ for every arcs the algorithm shows the flow, for every nodes it shows
+ balance and potential. These 6 flags decide if the algorithm shows a
+ particular value of the arcs/nodes; for example if
+ UNIPI_VIS_ARC_UPPER == 1, the algorithm shows the upper bounds of all
+ arcs. */
+
+#define FOSHOW 0
+
+/* If FOSHOW is 1, the algorithm shows the f.o. value every x iterations
+ (x = UNIPI_PRIMAL_ITER_SHOW or x = UNIPI_DUAL_ITER_SHOW). */
+
+#define OPTQUADRATIC 0
+
+/* If OPTQUADRATIC is 1 the Primal Simplex, in the quadratic case, tries to
+ optimize the update of the potential.
+ Unfortunately this doesn't work well: for this reason it is set to 0. */
+
+
+// QUICK HACK
+#define throw(x) assert(false);
+
+/*--------------------------------------------------------------------------*/
+/*--------------------------- FUNCTIONS ------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+template<class T>
+inline T ABS( const T x )
+{
+ return( x >= T( 0 ) ? x : - x );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+template<class T>
+inline void Swap( T &v1 , T &v2 )
+{
+ T temp = v1;
+ v1 = v2;
+ v2 = temp;
+ }
+
+/*--------------------------------------------------------------------------*/
+/*--------------------------- CONSTANTS ------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+#if( QUADRATICCOST == 0 )
+ static const char DELETED = -2; // ident for deleted arcs
+ static const char CLOSED = -1; // ident for closed arcs
+ static const char BASIC = 0; // ident for basis arcs
+ static const char AT_LOWER = 1; // ident for arcs in L
+ static const char AT_UPPER = 2; // ident for arcs in U
+#endif
+
+/* These macros will be used by method MemAllocCandidateList() to set the
+ values of numCandidateList and hotListSize. There are different macros,
+ according to:
+
+ - the used Simplex
+ - the size of the network
+ - (obviously) the different variables
+
+ This set of values tries to improve the performance of the two algorithms
+ according to diversified situations. */
+
+static const int PRIMAL_LOW_NUM_CANDIDATE_LIST = 30;
+static const int PRIMAL_MEDIUM_NUM_CANDIDATE_LIST = 50;
+static const int PRIMAL_HIGH_NUM_CANDIDATE_LIST = 200;
+static const int PRIMAL_LOW_HOT_LIST_SIZE = 5;
+static const int PRIMAL_MEDIUM_HOT_LIST_SIZE = 10;
+static const int PRIMAL_HIGH_HOT_LIST_SIZE = 20;
+static const int DUAL_LOW_NUM_CANDIDATE_LIST = 6;
+static const int DUAL_HIGH_NUM_CANDIDATE_LIST = 10;
+static const int DUAL_LOW_HOT_LIST_SIZE = 1;
+static const int DUAL_HIGH_HOT_LIST_SIZE = 2;
+
+
+
+/*--------------------------------------------------------------------------*/
+/*--------------------------- COSTRUCTOR -----------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::MCFSimplex( cIndex nmx , cIndex mmx )
+ :
+ MCFClass( nmx , mmx )
+{
+ #if( QUADRATICCOST )
+ if( numeric_limits<FNumber>::is_integer )
+ throw( MCFException( "FNumber must be float if QUADRATICCOST == 1" ) );
+
+ if( numeric_limits<CNumber>::is_integer )
+ throw( MCFException( "CNumber must be float if QUADRATICCOST == 1" ) );
+ #endif
+
+ usePrimalSimplex = true;
+
+ newSession = true;
+ if( nmax && mmax )
+ MemAlloc();
+ else
+ nmax = mmax = 0;
+
+ #if( QUADRATICCOST )
+ recomputeFOLimits = 100;
+ // recomputeFOLimits represents the limit of the iteration in which
+ // quadratic Primal Simplex computes "manually" the f.o. value
+ EpsOpt = 1e-13;
+ // EpsOpt is the fixed precision of the quadratic Primal Simplex
+ #endif
+
+ pricingRule = kCandidateListPivot;
+ forcedNumCandidateList = 0;
+ forcedHotListSize = 0;
+ usePrimalSimplex = true;
+ nodesP = NULL;
+ nodesD = NULL;
+ arcsP = NULL;
+ arcsD = NULL;
+ candP = NULL;
+ candD = NULL;
+
+ if( numeric_limits<CNumber>::is_integer )
+ MAX_ART_COST = CNumber( 1e7 );
+ else
+ MAX_ART_COST = CNumber( 1e10 );
+
+ } // end( MCFSimplex )
+
+/*--------------------------------------------------------------------------*/
+/*-------------------------- OTHER INITIALIZATIONS -------------------------*/
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::LoadNet( cIndex nmx , cIndex mmx , cIndex pn , cIndex pm ,
+ cFRow pU , cCRow pC , cFRow pDfct ,
+ cIndex_Set pSn , cIndex_Set pEn )
+{
+ MemDeAllocCandidateList();
+
+ if( ( nmx != nmax ) || ( mmx != mmax ) ) {
+ // if the size of the allocated memory changes
+
+ if( nmax && mmax ) { // if the memory was already allocated
+ MemDeAlloc(true); // deallocate the Primal
+ MemDeAlloc(false); // and the Dual data structures
+ nmax = mmax = 0;
+ }
+
+ if( nmx && mmx ) { // if the new dimensions of the memory are correct
+ nmax = nmx;
+ mmax = mmx;
+ MemAlloc();
+ }
+ }
+
+ if( ( ! nmax ) || ( ! mmax ) )
+ // if one of the two dimension of the memory isn't correct
+ nmax = mmax = 0;
+
+ if( nmax ) { // if the new dimensions of the memory are correct
+ n = pn;
+ m = pm;
+
+ if( usePrimalSimplex ) {
+ stopNodesP = nodesP + n;
+ dummyRootP = nodesP + nmax;
+ for( nodePType *node = nodesP ; node != stopNodesP ; node++ )
+ node->balance = pDfct[ node - nodesP ]; // initialize nodes
+
+ stopArcsP = arcsP + m;
+ dummyArcsP = arcsP + mmax;
+ stopDummyP = dummyArcsP + n;
+ for( arcPType *arc = arcsP ; arc != stopArcsP ; arc++ ) {
+ // initialize real arcs
+ if (pC)
+ arc->cost = pC[ arc - arcsP ];
+ else
+ arc->cost = 0;
+ #if( QUADRATICCOST )
+ arc->quadraticCost = 0;
+ #endif
+ if (pU)
+ arc->upper = pU[ arc - arcsP ];
+ else
+ arc->upper = Inf<FNumber>();
+ arc->tail = nodesP + pSn[ arc - arcsP ] - 1;
+ arc->head = nodesP + pEn[ arc - arcsP ] - 1;
+ }
+ }
+ else {
+ stopNodesD = nodesD + n;
+ dummyRootD = nodesD + nmax;
+ for( nodeDType *node = nodesD ; node != stopNodesD ; node++ )
+ node->balance = pDfct[ node - nodesD ]; // initialize nodes
+
+ stopArcsD = arcsD + m;
+ dummyArcsD = arcsD + mmax;
+ stopDummyD = dummyArcsD + n;
+ for( arcDType *arc = arcsD ; arc != stopArcsD ; arc++ ) {
+ // initialize real arcs
+ arc->cost = pC[ arc - arcsD ];
+ #if( QUADRATICCOST )
+ arc->quadraticCost = 0;
+ #endif
+ arc->upper = pU[ arc - arcsD ];
+ arc->tail = nodesD + pSn[ arc - arcsD ] - 1;
+ arc->head = nodesD + pEn[ arc - arcsD ] - 1;
+ }
+
+ CreateAdditionalDualStructures();
+ }
+
+ if( pricingRule == kCandidateListPivot )
+ MemAllocCandidateList();
+
+ status = kUnSolved;
+ }
+ } // end( MCFSimplex::LoadNet )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::SetAlg( bool UsPrml , char WhchPrc )
+{
+ bool newUsePrimalSimplex = UsPrml;
+ bool oldUsePrimalSimplex = usePrimalSimplex;
+ char newPricingRule = WhchPrc;
+ char oldPricingRule = pricingRule;
+
+ usePrimalSimplex = newUsePrimalSimplex;
+ pricingRule = newPricingRule;
+
+ if( ( ! usePrimalSimplex ) && ( pricingRule == kDantzig) ) {
+ pricingRule = kFirstEligibleArc;
+ newPricingRule = pricingRule;
+ }
+
+ if( ( newUsePrimalSimplex != oldUsePrimalSimplex ) ||
+ ( newPricingRule != oldPricingRule ) ) {
+ MemDeAllocCandidateList();
+
+ if( newUsePrimalSimplex != oldUsePrimalSimplex ) {
+ #if( QUADRATICCOST )
+ throw(
+ MCFException( "Primal Simplex is the only option if QUADRATICCOST == 1"
+ ) );
+ }
+ #else
+ MemAlloc();
+ nodePType *nP = nodesP;
+ nodeDType *nD = nodesD;
+ arcPType *aP = arcsP;
+ arcDType *aD = arcsD;
+
+ if( newUsePrimalSimplex ) { // from Dual to Primal
+ if( nodesD == NULL )
+ return;
+
+ if( newSession )
+ CreateInitialDualBase();
+
+ dummyRootP = nodesP + nmax;
+ stopNodesP = nodesP + n;
+ dummyArcsP = arcsP + mmax;
+ stopArcsP = arcsP + m;
+ stopDummyP = dummyArcsP + n;
+ // Copy the old Dual data structure in a new Primal data structure
+ while( nD != stopNodesD ) {
+ nP->prevInT = nodesP + ( nD->prevInT - nodesD );
+ nP->nextInT = nodesP + ( nD->nextInT - nodesD );
+ nP->enteringTArc = arcsP + ( nD->enteringTArc - arcsD );
+ nP->balance = nD->balance;
+ nP->potential = nD->potential;
+ nP->subTreeLevel = nD->subTreeLevel;
+ nP++;
+ nD++;
+ }
+
+ dummyRootP->prevInT = NULL;
+ dummyRootP->nextInT = nodesP + ( dummyRootD->nextInT - nodesD );
+ dummyRootP->enteringTArc = arcsP + ( dummyRootD->enteringTArc - arcsD );
+ dummyRootP->balance = dummyRootD->balance;
+ dummyRootP->potential = dummyRootD->potential;
+ dummyRootP->subTreeLevel = dummyRootD->subTreeLevel;
+ while( aD != stopArcsD ) {
+ aP->tail = nodesP + ( aD->tail - nodesD );
+ aP->head = nodesP + ( aD->head - nodesD );
+ aP->flow = aD->flow;
+ aP->cost = aD->cost;
+ aP->ident = aD->ident;
+ aP->upper = aD->upper;
+ aP++;
+ aD++;
+ }
+
+ aP = dummyArcsP;
+ aD = dummyArcsD;
+ while( aD != stopDummyD ) {
+ aP->tail = nodesP + ( aD->tail - nodesD );
+ aP->head = nodesP + ( aD->head - nodesD );
+ aP->flow = aD->flow;
+ aP->cost = aD->cost;
+ aP->ident = aD->ident;
+ if( ( ETZ(aP->flow, EpsFlw) ) && (aP->ident == AT_UPPER) )
+ aP->ident = AT_LOWER;
+
+ aP->upper = Inf<FNumber>();
+ aP++;
+ aD++;
+ }
+
+ MemDeAlloc(false);
+ if( Senstv && ( status != kUnSolved ) ) {
+ nodePType *node = dummyRootP;
+ for( int i = 0 ; i < n ; i++ )
+ node = node->nextInT;
+
+ node->nextInT = NULL;
+ dummyRootP->prevInT = NULL;
+ dummyRootP->enteringTArc = NULL;
+ // balance the flow
+ CreateInitialPModifiedBalanceVector();
+ PostPVisit( dummyRootP );
+ // restore the primal admissibility
+ BalanceFlow( dummyRootP );
+ ComputePotential( dummyRootP );
+ }
+ else
+ status = kUnSolved;
+ }
+ else { // from Primal to Dual
+ if( nodesP == NULL )
+ return;
+
+ if( newSession )
+ CreateInitialPrimalBase();
+
+ dummyRootD = nodesD + nmax;
+ stopNodesD = nodesD + n;
+ dummyArcsD = arcsD + mmax;
+ stopArcsD = arcsD + m;
+ stopDummyD = dummyArcsD + n;
+ // Copy the old Primal data structure in a new Dual data structure
+ while( nP != stopNodesP ) {
+ nD->prevInT = nodesD + ( nP->prevInT - nodesP );
+ nD->nextInT = nodesD + ( nP->nextInT - nodesP );
+ nD->enteringTArc = arcsD + ( nP->enteringTArc - arcsP );
+ nD->balance = nP->balance;
+ nD->potential = nP->potential;
+ nD->subTreeLevel = nP->subTreeLevel;
+ nP++;
+ nD++;
+ }
+
+ dummyRootD->prevInT = NULL;
+ dummyRootD->nextInT = nodesD + ( dummyRootP->nextInT - nodesP );
+ dummyRootD->enteringTArc = NULL;
+ dummyRootD->balance = dummyRootP->balance;
+ dummyRootD->potential = dummyRootP->potential;
+ dummyRootD->subTreeLevel = dummyRootP->subTreeLevel;
+ while( aP != stopArcsP ) {
+ aD->tail = nodesD + ( aP->tail - nodesP );
+ aD->head = nodesD + ( aP->head - nodesP );
+ aD->flow = aP->flow;
+ aD->cost = aP->cost;
+ aD->ident = aP->ident;
+ aD->upper = aP->upper;
+ aP++;
+ aD++;
+ }
+
+ aP = dummyArcsP;
+ aD = dummyArcsD;
+ while( aP != stopDummyP ) {
+ aD->tail = nodesD + ( aP->tail - nodesP );
+ aD->head = nodesD + ( aP->head - nodesP );
+ aD->flow = aP->flow;
+ aD->cost = aP->cost;
+ aD->ident = aP->ident;
+ aD->upper = 0;
+ aP++;
+ aD++;
+ }
+
+ CreateAdditionalDualStructures();
+ MemDeAlloc(true);
+ nodeDType *node = dummyRootD;
+ for( int i = 0 ; i < n ; i++ )
+ node = node->nextInT;
+
+ node->nextInT = NULL;
+ dummyRootD->enteringTArc = NULL;
+ dummyRootD->prevInT = NULL;
+ if( Senstv && ( status != kUnSolved ) ) {
+ // fix every flow arc according to its reduct cost
+ for( arcDType *arc = arcsD ; arc != stopArcsD ; arc++ ) {
+ if( (arc->ident == AT_LOWER) && LTZ( ReductCost( arc ) , EpsCst ) ) {
+ arc->flow = arc->upper;
+ arc->ident = AT_UPPER;
+ }
+
+ if( ( arc->ident == AT_UPPER ) && GTZ( ReductCost( arc ) , EpsCst ) ) {
+ arc->flow = 0;
+ arc->ident = AT_LOWER;
+ }
+ }
+
+ // balance the flow
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ }
+ else
+ status = kUnSolved;
+ }
+ //#endif
+ }
+#endif
+ if( newPricingRule == kFirstEligibleArc )
+ if( newUsePrimalSimplex )
+ arcToStartP = arcsP;
+ else
+ arcToStartD = arcsD;
+
+ if( ( nmax && mmax ) && ( newPricingRule == kCandidateListPivot ) )
+ MemAllocCandidateList();
+ }
+ } // end( SetAlg )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::SetPar( int par, int val )
+{
+ switch( par ) {
+ case kAlgPrimal:
+ if( val == kYes )
+ SetAlg( true , pricingRule);
+
+ if( val == kNo )
+ SetAlg( false, pricingRule );
+
+ break;
+
+ case kAlgPricing:
+
+ if( ( val == kDantzig ) || ( val == kFirstEligibleArc ) ||
+ ( val == kCandidateListPivot ) )
+ SetAlg( usePrimalSimplex , val );
+
+ break;
+
+ case kNumCandList:
+
+ MemDeAllocCandidateList();
+ forcedNumCandidateList = val;
+ MemAllocCandidateList();
+ forcedNumCandidateList = 0;
+ forcedHotListSize = 0;
+ break;
+
+ case kHotListSize:
+
+ MemDeAllocCandidateList();
+ forcedHotListSize = val;
+ MemAllocCandidateList();
+ forcedNumCandidateList = 0;
+ forcedHotListSize = 0;
+ break;
+
+ case kRecomputeFOLimits:
+
+ recomputeFOLimits = val;
+ break;
+
+ default:
+
+ MCFClass::SetPar(par, val);
+ }
+ } // end( SetPar( int ) )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::SetPar( int par , double val )
+{
+ switch( par ) {
+ case kEpsOpt:
+
+ EpsOpt = val;
+ break;
+
+ default:
+ MCFClass::SetPar( par , val );
+ }
+ } // end( SetPar( double )
+
+/*-------------------------------------------------------------------------*/
+/*--------------- METHODS FOR SOLVING THE PROBLEM -------------------------*/
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::SolveMCF( void )
+{
+ if( MCFt )
+ MCFt->Start();
+
+ //if( status == kUnSolved )
+ if(usePrimalSimplex )
+ CreateInitialPrimalBase();
+ else
+ CreateInitialDualBase();
+
+ newSession = false;
+ if( usePrimalSimplex )
+ PrimalSimplex();
+ else
+ DualSimplex();
+
+ if( MCFt )
+ MCFt->Stop();
+
+ } // end( MCFSimplex::SolveMCF )
+
+/*--------------------------------------------------------------------------*/
+/*---------------------- METHODS FOR READING RESULTS -----------------------*/
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFGetX( FRow F , Index_Set nms , cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ if( usePrimalSimplex )
+ for( Index i = strt ; i < stp ; i++ ) {
+ FNumber tXi = ( arcsP + i )->flow;
+ if( GTZ( tXi , EpsFlw ) ) {
+ *(F++) = tXi;
+ *(nms++) = i;
+ }
+ }
+ else
+ for( Index i = strt ; i < stp ; i++ ) {
+ FNumber tXi = ( arcsD + i )->flow;
+ if( GTZ( tXi , EpsFlw ) ) {
+ *(F++) = tXi;
+ *(nms++) = i;
+ }
+ }
+
+ *nms = Inf<Index>();
+ }
+ else
+ if( usePrimalSimplex )
+ for( Index i = strt; i < stp; i++ )
+ *(F++) = ( arcsP + i )->flow;
+ else
+ for( Index i = strt; i < stp; i++ )
+ *(F++) = ( arcsD + i )->flow;
+
+ } // end( MCFSimplex::MCFGetX( some ) )
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFGetRC( CRow CR , cIndex_Set nms , cIndex strt , Index stp )
+{
+ if( nms ) {
+ while( *nms < strt )
+ nms++;
+
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(CR++) = CNumber( ReductCost( arcsP + h ) );
+ else
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(CR++) = ReductCost( arcsD + h );
+ }
+ else {
+ if( stp > m )
+ stp = m;
+
+ if( usePrimalSimplex )
+ for( arcPType* arc = arcsP + strt ; arc < arcsP + stp ; arc++ )
+ *(CR++) = CNumber( ReductCost( arc ) );
+ else
+ for( arcDType* arc = arcsD + strt ; arc < arcsD + stp ; arc++ )
+ *(CR++) = ReductCost( arc );
+ }
+ } // end( MCFSimplex::MCFGetRC( some ) )
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::CNumber MCFSimplex::MCFGetRC( cIndex i )
+{
+ if( usePrimalSimplex )
+ return CNumber( ReductCost( arcsP + i ) );
+ else
+ return( ReductCost( arcsD + i ) );
+
+ } // end( MCFSimplex::MCFGetRC( i ) )
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFGetPi( CRow P , cIndex_Set nms , cIndex strt , Index stp )
+{
+ if( stp > n )
+ stp = n;
+
+ if( nms ) {
+ while( *nms < strt )
+ nms++;
+
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(P++) = CNumber( (nodesP + h)->potential );
+ else
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(P++) = (nodesD + h )->potential;
+ }
+ else
+ if( usePrimalSimplex )
+ for( nodePType *node = nodesP + strt ; node < ( nodesP + stp ) ; node++ )
+ *(P++) = CNumber( node->potential );
+ else
+ for( nodeDType *node = nodesD + strt ; node++ < ( nodesD + stp ) ; node++ )
+ *(P++) = node->potential;
+
+ } // end( MCFSimplex::MCFGetPi( some ) )
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::FONumber MCFSimplex::MCFGetFO( void )
+{
+ if( status == kOK )
+ return( (FONumber) GetFO() );
+ else
+ if( status == kUnbounded )
+ return( - Inf<FONumber>() );
+ else
+ return( Inf<FONumber>() );
+
+ } // end( MCFSimplex::MCFGetFO )
+
+/*-------------------------------------------------------------------------*/
+/*----------METHODS FOR READING THE DATA OF THE PROBLEM--------------------*/
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFArcs( Index_Set Startv , Index_Set Endv ,
+ cIndex_Set nms , cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ while( *nms < strt )
+ nms++;
+
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(nms++) ) < stp ; ) {
+ if( Startv )
+ *(Startv++) = Index( (arcsP + h)->tail - nodesP) - USENAME0;
+ if( Endv )
+ *(Endv++) = Index( (arcsP + h)->head - nodesP ) - USENAME0;
+ }
+ else
+ for( Index h ; ( h = *(nms++) ) < stp ; ) {
+ if( Startv )
+ *(Startv++) = Index( (arcsD + h)->tail - nodesD) - USENAME0;
+ if( Endv )
+ *(Endv++) = Index( (arcsD + h)->head - nodesD ) - USENAME0;
+ }
+ }
+ else
+ if( usePrimalSimplex )
+ for( arcPType* arc = arcsP + strt ; arc < (arcsP + stp) ; arc++ ) {
+ if( Startv )
+ *(Startv++) = Index( arc->tail - nodesP ) - USENAME0;
+ if( Endv )
+ *(Endv++) = Index( arc->head - nodesP ) - USENAME0;
+ }
+ else
+ for( arcDType* arc = arcsD + strt ; arc < (arcsD + stp) ; arc++ ) {
+ if( Startv )
+ *(Startv++) = Index( arc->tail - nodesD ) - USENAME0;
+ if( Endv )
+ *(Endv++) = Index( arc->head - nodesD ) - USENAME0;
+ }
+
+ } // end( MCFSimplex::MCFArcs )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFCosts( CRow Costv , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ while( *nms < strt )
+ nms++;
+
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(Costv++) = (arcsP + h)->cost;
+ else
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(Costv++) = (arcsD + h)->cost;
+ }
+ else
+ if( usePrimalSimplex )
+ for( arcPType* arc = arcsP + strt ; arc < (arcsP + stp) ; arc++ )
+ *(Costv++) = arc->cost;
+ else
+ for( arcDType* arc = arcsD + strt ; arc < (arcsD + stp) ; arc++ )
+ *(Costv++) = arc->cost;
+
+ } // end( MCFSimplex::MCFCosts ( some ) )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFQCoef( CRow Qv , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ while( *nms < strt )
+ nms++;
+
+ #if( QUADRATICCOST )
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(Qv++) = (arcsP + h)->quadraticCost;
+ else
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(Qv++) = (arcsD + h)->quadraticCost;
+ #else
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(Qv++) = 0;
+ #endif
+ }
+ else
+ #if( QUADRATICCOST )
+ if( usePrimalSimplex )
+ for( arcPType* arc = arcsP + strt ; arc < ( arcsP + stp ) ; arc++ )
+ *(Qv++) = arc->quadraticCost;
+ else
+ for( arcDType* arc = arcsD + strt ; arc < ( arcsD + stp ) ; arc++ )
+ *(Qv++) = arc->quadraticCost;
+ #else
+ for( Index h = strt ; h++ < stp ; )
+ *(Qv++) = 0;
+ #endif
+
+ } // end( MCFSimplex::MCFQCoef ( some ) )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFUCaps( FRow UCapv , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ while( *nms < strt )
+ nms++;
+
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(UCapv++) = (arcsP + h)->upper;
+ else
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(UCapv++) = (arcsD + h)->upper;
+ }
+ else
+ if( usePrimalSimplex )
+ for( arcPType* arc = arcsP + strt ; arc < (arcsP + stp ) ; arc++ )
+ *(UCapv++) = arc->upper;
+ else
+ for( arcDType* arc = arcsD + strt ; arc < ( arcsD + stp ) ; arc++ )
+ *(UCapv++) = arc->upper;
+
+ } // end( MCFSimplex::MCFUCaps ( some ) )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::MCFDfcts( FRow Dfctv , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > n )
+ stp = n;
+
+ if( nms ) {
+ while( *nms < strt )
+ nms++;
+
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(Dfctv++) = ( nodesP + h )->balance;
+ else
+ for( Index h ; ( h = *(nms++) ) < stp ; )
+ *(Dfctv++) = (nodesD + h )->balance;
+ }
+ else
+ if( usePrimalSimplex )
+ for( nodePType* node = nodesP + strt ; node < ( nodesP + stp ) ; node++ )
+ *(Dfctv++) = node->balance;
+ else
+ for( nodeDType* node = nodesD + strt ; node < ( nodesD + stp ) ; node++ )
+ *(Dfctv++) = node->balance;
+
+ } // end( MCFSimplex::MCFDfcts )
+
+/*-------------------------------------------------------------------------*/
+/*--------- METHODS FOR ADDING / REMOVING / CHANGING DATA -----------------*/
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgCosts( cCRow NCost , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ while( *nms < strt ) {
+ nms++;
+ NCost++;
+ }
+
+ cIndex_Set tnms = nms; // nms may be needed below
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ arcsP[ h ].cost = *(NCost++);
+ else
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ arcsD[ h ].cost = *(NCost++);
+ }
+ else
+ if( usePrimalSimplex )
+ for( arcPType *arc = arcsP + strt ; arc < (arcsP + stp) ; arc++ )
+ arc->cost = *(NCost++);
+ else
+ for( arcDType *arc = arcsD + strt ; arc < (arcsD + stp) ; arc++ )
+ arc->cost = *(NCost++);
+
+ if( Senstv && ( status != kUnSolved ) )
+ if( usePrimalSimplex )
+ ComputePotential( dummyRootP );
+ else {
+ #if( QUADRATICCOST == 0 )
+ for( arcDType *arc = arcsD ; arc != stopArcsD ; arc++ )
+ if( arc->ident > BASIC )
+ if( GTZ( ReductCost( arc ) , EpsCst ) ) {
+ arc->flow = 0;
+ arc->ident = AT_LOWER;
+ }
+ else {
+ arc->flow = arc->upper;
+ arc->ident = AT_UPPER;
+ }
+
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ #endif
+ }
+ else
+ status = kUnSolved;
+
+ } // end( MCFSimplex::ChgCosts )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgCost( Index arc , cCNumber NCost )
+{
+ if( arc >= m )
+ return;
+
+ if( usePrimalSimplex )
+ ( arcsP + arc )->cost = NCost;
+ else
+ ( arcsD + arc )->cost = NCost;
+
+ if( Senstv && ( status != kUnSolved ) ) {
+ if( usePrimalSimplex ) {
+ nodePType *node = ( arcsP + arc )->tail;
+ if( ( ( arcsP + arc )->head)->subTreeLevel < node->subTreeLevel )
+ node = ( arcsP + arc )->head;
+
+ ComputePotential( dummyRootP );
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ nodeDType *node = ( arcsD + arc )->tail;
+ if( ( ( arcsD + arc )->head )->subTreeLevel < node->subTreeLevel )
+ node = ( arcsD + arc )->head;
+
+ ComputePotential( dummyRootD );
+ for( arcDType *a = arcsD ; a != stopArcsD ; a++)
+ if( a->ident > BASIC )
+ if( GTZ( ReductCost( a ) , EpsCst ) ) {
+ a->flow = 0;
+ a->ident = AT_LOWER;
+ }
+ else {
+ a->flow = a->upper;
+ a->ident = AT_UPPER;
+ }
+
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ #endif
+ }
+ }
+ else
+ status = kUnSolved;
+
+ } // end( MCFSimplex::ChgCost )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgQCoef( cCRow NQCoef , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ #if( QUADRATICCOST )
+ if( nms ) {
+ while( *nms < strt ) {
+ nms++;
+ NQCoef++;
+ }
+
+ cIndex_Set tnms = nms; // nms may be needed below
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ arcsP[ h ].quadraticCost = *(NQCoef++);
+ else
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ arcsD[ h ].quadraticCost = *(NQCoef++);
+ }
+ else
+ if( usePrimalSimplex )
+ for( arcPType *arc = arcsP + strt ; arc < ( arcsP + stp ) ; arc++ )
+ arc->quadraticCost = *(NQCoef++);
+ else
+ for( arcDType *arc = arcsD + strt ; arc < ( arcsD + stp ) ; arc++ )
+ arc->quadraticCost = *(NQCoef++);
+
+ if( Senstv && (status != kUnSolved ) )
+ ComputePotential( dummyRootP );
+ else
+ status = kUnSolved;
+ #else
+ if( NQCoef )
+ throw( MCFException( "ChgQCoef: nonzero coefficients not allowed" ) );
+ #endif
+} // end( MCFSimplex::ChgQCoef )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgQCoef( Index arc , cCNumber NQCoef )
+{
+ #if( QUADRATICCOST )
+ if( arc >= m )
+ return;
+
+ if( usePrimalSimplex )
+ ( arcsP + arc )->quadraticCost = NQCoef;
+ else
+ ( arcsD + arc )->quadraticCost = NQCoef;
+
+ if( Senstv && ( status != kUnSolved ) ) {
+ nodePType *node = ( arcsP + arc )->tail;
+ if( ( ( arcsP + arc )->head )->subTreeLevel < node->subTreeLevel )
+ node = ( arcsP + arc )->head;
+
+ ComputePotential( node );
+ }
+ else
+ status = kUnSolved;
+ #else
+ if( NQCoef )
+ throw( MCFException( "ChgQCoef: nonzero coefficients not allowed" ) );
+ #endif
+ } // end( MCFSimplex::ChgQCoef )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgDfcts( cFRow NDfct , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ while( *nms < strt ) {
+ nms++;
+ NDfct++;
+ }
+
+ cIndex_Set tnms = nms; // nms may be needed below
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ nodesP[ h ].balance = *(NDfct++);
+ else
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ nodesD[ h ].balance = *(NDfct++);
+ }
+ else
+ if( usePrimalSimplex )
+ for( nodePType *node = nodesP + strt ; node < ( nodesP + stp ) ; node++ )
+ node->balance = *(NDfct++);
+ else
+ for( nodeDType *node = nodesD + strt ; node < ( nodesD + stp ) ; node++ )
+ node->balance = *(NDfct++);
+
+ if( Senstv && (status != kUnSolved ) )
+ if( usePrimalSimplex ) {
+ CreateInitialPModifiedBalanceVector();
+ PostPVisit( dummyRootP );
+ BalanceFlow( dummyRootP );
+ ComputePotential( dummyRootP );
+ }
+ else {
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ }
+ else
+ status = kUnSolved;
+
+ } // end( MCFSimplex::ChgDfcts )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgDfct( Index nod , cFNumber NDfct )
+{
+ if( nod > n )
+ return;
+
+ if( usePrimalSimplex )
+ ( nodesP + nod - 1 )->balance = NDfct;
+ else
+ ( nodesD + nod - 1 )->balance = NDfct;
+
+ if( Senstv && (status != kUnSolved ) )
+ if( usePrimalSimplex ) {
+ CreateInitialPModifiedBalanceVector();
+ PostPVisit( dummyRootP );
+ BalanceFlow( dummyRootP );
+ ComputePotential( dummyRootP );
+ }
+ else {
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ }
+ else
+ status = kUnSolved;
+
+ } // end( MCFSimplex::ChgDfct )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgUCaps( cFRow NCap , cIndex_Set nms ,
+ cIndex strt , Index stp )
+{
+ if( stp > m )
+ stp = m;
+
+ if( nms ) {
+ while( *nms < strt ) {
+ nms++;
+ NCap++;
+ }
+
+ cIndex_Set tnms = nms; // nms may be needed below
+ if( usePrimalSimplex )
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ arcsP[ h ].upper = *(NCap++);
+ else
+ for( Index h ; ( h = *(tnms++) ) < stp ; )
+ arcsD[ h ].upper = *(NCap++);
+ }
+ else
+ if( usePrimalSimplex )
+ for( arcPType *arc = arcsP + strt ; arc < ( arcsP + stp ) ; arc++ )
+ arc->upper = *(NCap++);
+ else
+ for( arcDType *arc = arcsD + strt ; arc < ( arcsD + stp ) ; arc++ )
+ arc->upper = *(NCap++);
+
+ if( Senstv && (status != kUnSolved ) ) {
+ if( usePrimalSimplex ) {
+ for( arcPType *arc = arcsP ; arc != stopArcsP ; arc++)
+ #if( QUADRATICCOST )
+ if( GT( arc->flow , arc->upper , EpsFlw ) )
+ arc->flow = arc->upper;
+ #else
+ if( GT(arc->flow , arc->upper , EpsFlw ) ||
+ ( ( arc->ident == AT_UPPER ) &&
+ ( ! ETZ( arc->flow - arc->upper , EpsFlw ) ) ) )
+ arc->flow = arc->upper;
+ #endif
+
+ CreateInitialPModifiedBalanceVector();
+ PostPVisit( dummyRootP );
+ BalanceFlow( dummyRootP );
+ ComputePotential( dummyRootP );
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ for( arcDType *arc = arcsD ; arc != stopArcsD ; arc++ )
+ if( ( GT( arc->flow , arc->upper , EpsFlw ) && ( arc->ident != BASIC ) ) ||
+ ( ( arc->ident == AT_UPPER ) &&
+ ( ! ETZ( arc->flow - arc->upper , EpsFlw ) ) ) )
+ arc->flow = arc->upper;
+
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ ComputePotential( dummyRootD );
+ #endif
+ }
+ }
+ else
+ status = kUnSolved;
+
+ } // end( MCFSimplex::ChgUCaps )
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::ChgUCap( Index arc , cFNumber NCap )
+{
+ if( arc >= m )
+ return;
+
+ if( usePrimalSimplex )
+ ( arcsP + arc )->upper = NCap;
+ else
+ ( arcsD + arc )->upper = NCap;
+
+ if( Senstv && (status != kUnSolved ) ) {
+ if( usePrimalSimplex ) {
+ #if( QUADRATICCOST )
+ if( GT( ( arcsP + arc )->flow , ( arcsP + arc )->upper , EpsFlw ) )
+ ( arcsP + arc )->flow = ( arcsP + arc )->upper;
+ #else
+ if( GT( ( arcsP + arc )->flow , ( arcsP + arc )->upper , EpsFlw ) ||
+ ( ( ( arcsP + arc )->ident == AT_UPPER ) &&
+ ( ! ETZ( ( arcsP + arc )->flow - ( arcsP + arc )->upper , EpsFlw ) ) ) )
+ ( arcsP + arc )->flow = ( arcsP + arc )->upper;
+ #endif
+
+ CreateInitialPModifiedBalanceVector();
+ PostPVisit( dummyRootP );
+ BalanceFlow( dummyRootP );
+ ComputePotential( dummyRootP );
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ if( ( GT( ( arcsD + arc )->flow , ( arcsD + arc )->upper , EpsFlw ) &&
+ ( ( ( arcsD + arc )->ident != BASIC ) ) ) ||
+ ( ( ( arcsD + arc )->ident == AT_UPPER ) &&
+ ( ! ETZ( ( arcsD + arc )->flow - ( arcsD + arc )->upper , EpsFlw ) ) ) ) {
+ ( arcsD + arc )->flow = ( arcsD + arc )->upper;
+ ( arcsD + arc )->ident = AT_UPPER;
+ }
+
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ ComputePotential( dummyRootD );
+ #endif
+ }
+ }
+ else
+ status = kUnSolved;
+
+ } // end( MCFSimplex::ChgUCap )
+
+/*-------------------------------------------------------------------------*/
+
+bool MCFSimplex::IsClosedArc( cIndex name )
+{
+ if( name >= m )
+ return( false );
+
+ #if( QUADRATICCOST )
+ return( ( arcsP + name )->cost == Inf<CNumber>() );
+ #else
+ if( usePrimalSimplex )
+ return( ( ( arcsP + name )->ident < BASIC) );
+ else
+ return( ( ( arcsD + name )->ident < BASIC) );
+ #endif
+ }
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::CloseArc( cIndex name )
+{
+ if( name >= m )
+ return;
+
+ if( usePrimalSimplex ) {
+ arcPType *arc = arcsP + name;
+ #if( QUADRATICCOST )
+ if( arc->cost == Inf<CNumber>() )
+ return;
+
+ arc->cost = Inf<CNumber>();
+ #else
+ if( arc->ident < BASIC )
+ return;
+
+ arc->ident = CLOSED;
+ #endif
+
+ arc->flow = 0;
+
+ if( Senstv && ( status != kUnSolved ) ) {
+ nodePType *node = NULL;
+ if( (arc->tail)->enteringTArc == arc )
+ node = arc->tail;
+
+ if( (arc->head)->enteringTArc == arc )
+ node = arc->head;
+
+ if( node ) {
+ node->enteringTArc = dummyArcsP + ( node - nodesP );
+ nodePType *last = CutAndUpdateSubtree( node , -node->subTreeLevel + 1 );
+ PasteSubtree( node , last , dummyRootP );
+ node->enteringTArc = dummyArcsP + ( node - nodesP );
+ }
+
+ CreateInitialPModifiedBalanceVector();
+ PostPVisit(dummyRootP);
+ BalanceFlow(dummyRootP);
+ ComputePotential(dummyRootP);
+ }
+ else
+ status = kUnSolved;
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ arcDType *arc = arcsD + name;
+ if( arc->ident < BASIC )
+ return;
+
+ arc->flow = 0;
+ arc->ident = CLOSED;
+
+ if( Senstv && ( status != kUnSolved ) ) {
+ nodeDType *node = NULL;
+ if( ( arc->tail )->enteringTArc == arc)
+ node = arc->tail;
+
+ if( ( arc->head )->enteringTArc == arc )
+ node = arc->head;
+
+ if( node ) {
+ node->enteringTArc = dummyArcsD + ( node - nodesD );
+ nodeDType *last = CutAndUpdateSubtree( node , -node->subTreeLevel + 1 );
+ PasteSubtree( node , last , dummyRootD );
+ node->enteringTArc = dummyArcsD + ( node - nodesD );
+ ComputePotential( dummyRootD );
+
+ for( arcDType *a = arcsD ; a != stopArcsD ; a++ )
+ if( a->ident > BASIC )
+ if( GTZ( ReductCost( a ) , EpsCst ) ) {
+ a->flow = 0;
+ a->ident = AT_LOWER;
+ }
+ else {
+ a->flow = a->upper;
+ a->ident = AT_UPPER;
+ }
+ }
+
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit(dummyRootD);
+ ComputePotential(dummyRootD);
+ }
+ else
+ status = kUnSolved;
+ #endif
+ }
+ } // end( MCFSimplex::CloseArc )
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::DelNode( cIndex name )
+{
+ if( name >= n )
+ return;
+
+ if( usePrimalSimplex ) {
+ nodePType *node = nodesP + name;
+ nodePType *last = CutAndUpdateSubtree(node, -node->subTreeLevel);
+ nodePType *n = node->nextInT;
+ while( n ) {
+ if( n->subTreeLevel == 1 )
+ n->enteringTArc = dummyArcsP + ( n - nodesP );
+
+ n = n->nextInT;
+ }
+
+ PasteSubtree( node , last , dummyRootP );
+ n = node->nextInT;
+ dummyRootP->nextInT = n;
+ n->prevInT = dummyRootP;
+
+ for( arcPType *arc = arcsP ; arc != stopArcsP ; arc++ ) {
+ if( ( ( arc->tail ) == node) || ( ( arc->head ) == node ) ) {
+ arc->flow = 0;
+ #if( QUADRATICCOST )
+ arc->cost = Inf<CNumber>();
+ #else
+ arc->ident = CLOSED;
+ #endif
+ }
+ }
+
+ for( arcPType *arc = dummyArcsP ; arc != stopDummyP ; arc++ ) {
+ if( ( ( arc->tail ) == node ) || ( ( arc->head ) == node ) ) {
+ arc->flow = 0;
+ #if( QUADRATICCOST )
+ arc->cost = Inf<CNumber>();
+ #else
+ arc->ident = CLOSED;
+ #endif
+ }
+ }
+
+ CreateInitialPModifiedBalanceVector();
+ PostPVisit( dummyRootP );
+ BalanceFlow( dummyRootP );
+ ComputePotential( dummyRootP );
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ nodeDType *node = nodesD + name;
+ nodeDType *last = CutAndUpdateSubtree( node , -node->subTreeLevel );
+ nodeDType *n = node->nextInT;
+ while( n ) {
+ if( n->subTreeLevel == 1 )
+ n->enteringTArc = dummyArcsD + ( n - nodesD );
+
+ n = n->nextInT;
+ }
+
+ PasteSubtree( node , last , dummyRootD );
+ n = node->nextInT;
+ dummyRootD->nextInT = n;
+ n->prevInT = dummyRootD;
+
+ for( arcDType *arc = arcsD ; arc != stopArcsD ; arc++ )
+ if( ( ( arc->tail ) == node) || ( ( arc->head ) == node ) ) {
+ arc->flow = 0;
+ arc->ident = CLOSED;
+ }
+
+ for( arcDType *arc = dummyArcsD ; arc != stopDummyD ; arc++ )
+ if( ( ( arc->tail ) == node ) || ( ( arc->head ) == node ) ) {
+ arc->flow = 0;
+ arc->ident = CLOSED;
+ }
+
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ ComputePotential( dummyRootD );
+ #endif
+ }
+ } // end( MCFSimplex::DelNode )
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::OpenArc( cIndex name )
+{
+ if( name >= m )
+ return;
+
+ if( usePrimalSimplex ) {
+ /* Quadratic case is not implemented for a theory bug.
+ Infact a closed arc in the quadratic case has its cost fixed to infinity, and
+ it's impossible to restore the old value. */
+
+ #if( QUADRATICCOST == 0 )
+ arcPType *arc = arcsP + name;
+ if( arc->ident == CLOSED ) {
+ arc->ident = AT_LOWER;
+ arc->flow = 0;
+ }
+ #endif
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ arcDType *arc = arcsD + name;
+ if( arc->ident == CLOSED ) {
+ if( GTZ( ReductCost( arc ) , EpsCst ) )
+ arc->ident = AT_LOWER;
+ else {
+ arc->ident = AT_UPPER;
+ arc->flow = arc->upper;
+ if( Senstv && ( status != kUnSolved ) ) {
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ }
+ else
+ status = kUnSolved;
+ }
+ }
+ #endif
+ }
+ } // end( MCFSimplex:OpenArc )
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::Index MCFSimplex::AddNode( cFNumber aDfct )
+{
+ if( n >= nmax )
+ return( Inf<Index>() );
+
+ n++;
+ if( usePrimalSimplex ) {
+ nodePType *newNode = nodesP + n - 1;
+ stopArcsP->tail = newNode;
+ stopArcsP->head = dummyRootP;
+ stopArcsP->upper = Inf<FNumber>();
+ stopArcsP->flow = 0;
+ stopArcsP->cost = Inf<CNumber>();
+ #if( QUADRATICCOST )
+ stopArcsP->quadraticCost = 0;
+ #else
+ stopArcsP->ident = BASIC;
+ #endif
+ stopArcsP++;
+ newNode->balance = aDfct;
+ newNode->prevInT = dummyRootP;
+ newNode->nextInT = dummyRootP->nextInT;
+ (dummyRootP->nextInT)->prevInT = newNode;
+ dummyRootP->nextInT = newNode;
+ newNode->enteringTArc = stopArcsP--;
+ newNode->potential = 0;
+ #if(QUADRATICCOST)
+ newNode->sumQuadratic = 0;
+ #endif
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ nodeDType *newNode = nodesD + n - 1;
+ stopArcsD->tail = newNode;
+ stopArcsD->head = dummyRootD;
+ stopArcsD->upper = 0;
+ stopArcsD->flow = 0;
+ stopArcsD->cost = Inf<CNumber>();
+ stopArcsD->ident = BASIC;
+ newNode->balance = aDfct;
+ newNode->prevInT = dummyRootD;
+ newNode->nextInT = dummyRootD->nextInT;
+ (dummyRootD->nextInT)->prevInT = newNode;
+ dummyRootD->nextInT = newNode;
+ newNode->enteringTArc = stopArcsD;
+ newNode->potential = 0;
+ newNode->firstFs = stopArcsD;
+ newNode->firstBs = NULL;
+ stopArcsD->nextFs = NULL;
+ stopArcsD->nextBs = dummyRootD->firstBs;
+ dummyRootD->firstBs = stopArcsD;
+ stopArcsD++;
+ #endif
+ }
+
+ return( n );
+
+ } // end( MCFSimplex::AddNode )
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::ChangeArc( cIndex name , cIndex nSN , cIndex nEN )
+{
+ if( name >= m )
+ return;
+
+ CloseArc( name );
+
+ if( usePrimalSimplex ) {
+ if( nSN <= n )
+ (arcsP + name)->tail = (nodesP + nSN + USENAME0 - 1);
+ if( nEN <= n )
+ (arcsP + name)->head = (nodesP + nEN + USENAME0 - 1);
+ }
+ else {
+ if( nSN <= n )
+ (arcsD + name)->tail = (nodesD + nSN + USENAME0 - 1);
+ if( nEN <= n )
+ (arcsD + name)->head = (nodesD + nEN + USENAME0 - 1);
+ }
+
+ OpenArc( name );
+
+ } // end( MCFSimplex::ChangeArc )
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::DelArc( cIndex name )
+{
+ if( name >= m )
+ return;
+
+ if( usePrimalSimplex ) {
+ arcPType *arc = arcsP + name;
+ #if( QUADRATICCOST )
+ if( arc->upper == -Inf<FNumber>() )
+ return;
+
+ if( arc->cost < Inf<CNumber>() )
+ #else
+ if( arc->cost == DELETED )
+ return;
+
+ if( arc->cost >= BASIC )
+ #endif
+ CloseArc( name );
+
+ #if( QUADRATICCOST )
+ arc->upper = -Inf<FNumber>();
+ #else
+ arc->ident = DELETED;
+ #endif
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ arcDType *arc = arcsD + name;
+ if( arc->cost == DELETED )
+ return;
+
+ if( arc->cost >= BASIC )
+ CloseArc( name );
+
+ arc->ident = DELETED;
+ #endif
+ }
+ } // end( MCFSimplex::DelArc )
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::Index MCFSimplex::AddArc( cIndex Start , cIndex End ,
+ cFNumber aU , cCNumber aC )
+{
+ if( usePrimalSimplex ) {
+ arcPType *arc = arcsP;
+ #if( QUADRATICCOST )
+ while( ( arc->upper != -Inf<FNumber>() ) && ( arc != stopArcsP ) )
+ #else
+ while( ( arc->ident > DELETED ) && ( arc != stopArcsP ) )
+ #endif
+ arc++;
+
+ if( arc == stopArcsP ) {
+ if( m >= mmax )
+ return( Inf<Index>() );
+
+ m++;
+ stopArcsP++;
+ }
+
+ Index pos = ( arc - arcsP ) + 1;
+ arc->tail = nodesP + Start + USENAME0 - 1;
+ arc->head = nodesP + End + USENAME0 - 1;
+ arc->upper = aU;
+ arc->cost = aC;
+ arc->flow = 0;
+ #if( QUADRATICCOST )
+ arc->quadraticCost = 0;
+ #else
+ arc->ident = AT_LOWER;
+ #endif
+ ComputePotential( dummyRootP );
+ return( pos );
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ arcDType *arc = arcsD;
+ while( ( arc->ident > DELETED ) && ( arc != stopArcsD ) )
+ arc++;
+
+ if( arc == stopArcsD ) {
+ if( m >= mmax )
+ return( Inf<Index>() );
+
+ m++;
+ stopArcsD++;
+ }
+
+ Index pos = ( arc - arcsD ) + 1;
+ arc->tail = nodesD + Start + USENAME0 - 1;
+ arc->head = nodesD + End + USENAME0 - 1;
+ arc->upper = aU;
+ arc->cost = aC;
+ if( GEZ( ReductCost( arc ) , EpsCst ) ) {
+ arc->flow = 0;
+ arc->ident = AT_LOWER;
+ if( Senstv && ( status != kUnSolved ) ) {
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ ComputePotential( dummyRootD );
+ }
+ else
+ status = kUnSolved;
+ }
+ else {
+ arc->flow = arc->upper;
+ arc->ident = AT_UPPER;
+ if( Senstv && ( status != kUnSolved ) ) {
+ CreateInitialDModifiedBalanceVector();
+ PostDVisit( dummyRootD );
+ ComputePotential( dummyRootD );
+ }
+ else
+ status = kUnSolved;
+ }
+
+ ComputePotential( dummyRootD );
+ return( pos );
+ #endif
+ }
+ } // end( MCFSimplex::AddArc )
+
+/*--------------------------------------------------------------------------*/
+
+bool MCFSimplex::IsDeletedArc( cIndex name )
+{
+ if( name >= m )
+ return( false );
+
+ #if( QUADRATICCOST )
+ return( ( ( arcsP + name )->upper == -Inf<FNumber>() ) );
+ #else
+ if( usePrimalSimplex )
+ return( ( arcsP + name )->ident == DELETED );
+ else
+ return( ( arcsD + name )->ident == DELETED );
+ #endif
+ }
+
+/*--------------------------------------------------------------------------*/
+/*------------------------------ DESTRUCTOR --------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::~MCFSimplex()
+{
+ MemDeAllocCandidateList();
+ MemDeAlloc(true);
+ MemDeAlloc(false);
+ }
+
+/*--------------------------------------------------------------------------*/
+/*---------------------------- PRIVATE METHODS -----------------------------*/
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::MemAlloc( void )
+{
+ if( usePrimalSimplex ) {
+ nodesP = new nodePType[ nmax + 1 ]; // array of nodes
+ arcsP = new arcPType[ mmax + nmax ]; // array of arcs
+ dummyArcsP = arcsP + mmax; // artificial arcs are in the last
+ // nmax positions of the array arcs[]
+ }
+ else {
+ nodesD = new nodeDType[ nmax + 1 ]; // array of nodes
+ arcsD = new arcDType[ mmax + nmax ]; // array of arcs
+ dummyArcsD = arcsD + mmax; // artificial arcs are in the last nmax
+ // positions of the array arcs[]
+ }
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::MemDeAlloc( bool whatDeAlloc )
+{
+ if( whatDeAlloc ) {
+ delete[] nodesP;
+ delete[] arcsP;
+ nodesP = NULL;
+ arcsP = NULL;
+ }
+ else {
+ delete[] nodesD;
+ delete[] arcsD;
+ nodesD = NULL;
+ arcsD = NULL;
+ }
+ MemDeAllocCandidateList( );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::MemAllocCandidateList( void )
+{
+ if( usePrimalSimplex ) {
+ if( m < 10000 ) {
+ numCandidateList = PRIMAL_LOW_NUM_CANDIDATE_LIST;
+ hotListSize = PRIMAL_LOW_HOT_LIST_SIZE;
+ }
+ else
+ if( m > 100000 ) {
+ numCandidateList = PRIMAL_HIGH_NUM_CANDIDATE_LIST;
+ hotListSize = PRIMAL_HIGH_HOT_LIST_SIZE ;
+ }
+ else {
+ numCandidateList = PRIMAL_MEDIUM_NUM_CANDIDATE_LIST;
+ hotListSize = PRIMAL_MEDIUM_HOT_LIST_SIZE;
+ }
+
+ #if( QUADRATICCOST )
+ int coef = 1;
+ // If the number of the arcs is more than 10000, numCandidateList and hotListSize
+ // are increased to improve the performance of the Quadratic Primal Simplex
+ if( m > 10000 )
+ coef = 10;
+
+ numCandidateList = numCandidateList * coef;
+ hotListSize = hotListSize * coef;
+ #endif
+
+ if( forcedNumCandidateList > 0 )
+ numCandidateList = forcedNumCandidateList;
+
+ if( forcedHotListSize > 0 )
+ hotListSize = forcedHotListSize;
+
+ candP = new primalCandidType[ hotListSize + numCandidateList + 1 ];
+ }
+ else {
+ if( n < 10000 ) {
+ numCandidateList = DUAL_LOW_NUM_CANDIDATE_LIST;
+ hotListSize = DUAL_LOW_HOT_LIST_SIZE;
+ }
+ else {
+ numCandidateList = DUAL_HIGH_NUM_CANDIDATE_LIST;
+ hotListSize = DUAL_HIGH_HOT_LIST_SIZE;
+ }
+
+ if( forcedNumCandidateList > 0 )
+ numCandidateList = forcedNumCandidateList;
+
+ if( forcedHotListSize > 0 )
+ hotListSize = forcedHotListSize;
+
+ candD = new dualCandidType[ hotListSize + numCandidateList + 1 ];
+ }
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::MemDeAllocCandidateList( void )
+{
+ delete[] candP;
+ candP = NULL;
+ delete[] candD;
+ candD = NULL;
+}
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::CreateInitialPrimalBase( void )
+{
+ arcPType *arc;
+ nodePType *node;
+ for( arc = arcsP ; arc != stopArcsP ; arc++ ) { // initialize real arcs
+ arc->flow = 0;
+ #if( QUADRATICCOST == 0 )
+ arc->ident = AT_LOWER;
+ #endif
+ }
+
+ for( arc = dummyArcsP ; arc != stopDummyP ; arc++ ) { // initialize dummy arcs
+ node = nodesP + ( arc - dummyArcsP );
+ if( node->balance > 0 ) { // sink nodes
+ arc->tail = dummyRootP;
+ arc->head = node;
+ arc->flow = node->balance;
+ }
+ else { // source nodes or transit node
+ arc->tail = node;
+ arc->head = dummyRootP;
+ arc->flow = -node->balance;
+ }
+
+ arc->cost = MAX_ART_COST;
+ #if( QUADRATICCOST )
+ arc->quadraticCost = 0;
+ #else
+ arc->ident = BASIC;
+ #endif
+ arc->upper = Inf<FNumber>();
+ }
+
+ dummyRootP->balance = 0;
+ dummyRootP->prevInT = NULL;
+ dummyRootP->nextInT = nodesP;
+ dummyRootP->enteringTArc = NULL;
+ #if( QUADRATICCOST )
+ dummyRootP->sumQuadratic = 0;
+ #endif
+ dummyRootP->potential = MAX_ART_COST;
+ dummyRootP->subTreeLevel = 0;
+ for( node = nodesP ; node != stopNodesP ; node++) { // initialize nodes
+ node->prevInT = node - 1;
+ node->nextInT = node + 1;
+ node->enteringTArc = dummyArcsP + (node - nodesP);
+ #if( QUADRATICCOST )
+ node->sumQuadratic = (node->enteringTArc)->quadraticCost;
+ #endif
+ if( node->balance > 0 ) // sink nodes
+ node->potential = 2 * MAX_ART_COST;
+ else // source nodes or transit node
+ node->potential = 0;
+
+ node->subTreeLevel = 1;
+ }
+
+ nodesP->prevInT = dummyRootP;
+ ( nodesP + n - 1 )->nextInT = NULL;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::CreateInitialDualBase( void )
+{
+ arcDType *arc;
+ nodeDType *node;
+ for( arc = dummyArcsD ; arc != stopDummyD ; arc++ ) { // initialize dummy arcs
+ node = nodesD + ( arc - dummyArcsD );
+ arc->tail = node;
+ arc->head = dummyRootD;
+ arc->flow = -node->balance;
+ arc->cost = MAX_ART_COST;
+ #if( QUADRATICCOST )
+ arc->quadraticCost = 0;
+ #else
+ arc->ident = BASIC;
+ #endif
+ arc->upper = 0;
+ }
+
+ for( arc = arcsD ; arc != stopArcsD ; arc++ ) { // initialize real arcs
+ if( GTZ( arc->cost , EpsCst ) ) {
+ arc->flow = 0;
+ #if( QUADRATICCOST == 0 )
+ arc->ident = AT_LOWER;
+ #endif
+ }
+ else {
+ #if( QUADRATICCOST == 0 )
+ arc->ident = AT_UPPER;
+ #endif
+ arc->flow = arc->upper;
+ ( dummyArcsD + ( ( arc->tail ) - nodesD ) )->flow =
+ ( dummyArcsD + ( ( arc->tail ) - nodesD ) )->flow - arc->upper;
+
+ ( dummyArcsD + ( ( arc->head ) - nodesD ) )->flow =
+ ( dummyArcsD + ( ( arc->head ) - nodesD ) )->flow + arc->upper;
+ }
+ }
+
+ dummyRootD->balance = 0;
+ dummyRootD->prevInT = NULL;
+ dummyRootD->nextInT = nodesD;
+ dummyRootD->enteringTArc = NULL;
+ #if( QUADRATICCOST )
+ dummyRootD->sumQuadratic = 0;
+ #endif
+ dummyRootD->potential = MAX_ART_COST;
+ dummyRootD->subTreeLevel = 0;
+ for( node = nodesD ; node != stopNodesD ; node++ ) { // initialize nodes
+ node->prevInT = node - 1;
+ node->nextInT = node + 1;
+ node->enteringTArc = dummyArcsD + ( node - nodesD );
+ #if( QUADRATICCOST )
+ node->sumQuadratic = ( node->enteringTArc )->quadraticCost;
+ #endif
+ node->potential = 0;
+ node->subTreeLevel = 1;
+ node->whenInT2 = 0;
+ }
+
+ nodesD->prevInT = dummyRootD;
+ ( nodesD + n - 1 )->nextInT = NULL;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::CreateAdditionalDualStructures( void )
+{
+ // this method creates, in a Dual context, the Backward Star and the
+ // Forward Star of every node
+
+ for( nodeDType *node = nodesD ; node != stopNodesD ; node++) {
+ // initialize nodes
+ node->firstBs = NULL;
+ node->firstFs = NULL;
+ node->numArcs = 0;
+ }
+
+ dummyRootD->firstBs = NULL;
+ dummyRootD->firstFs = NULL;
+ dummyRootD->numArcs = 0;
+ for( arcDType *arc = arcsD ; arc != stopArcsD ; arc++ ) {
+ // initialize real arcs
+ arc->nextFs = ( arc->tail )->firstFs;
+ ( arc->tail )->firstFs = arc;
+ arc->nextBs = ( arc->head )->firstBs;
+ ( arc->head )->firstBs = arc;
+ ( arc->tail )->numArcs++;
+ ( arc->head )->numArcs++;
+ }
+
+ ResetWhenInT2();
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::PrimalSimplex( void )
+{
+ #if( UNIPI_PRIMAL_INITIAL_SHOW == 0 )
+ #if( UNIPI_PRIMAL_ITER_SHOW == 0 )
+ #if( UNIPI_PRIMAL_FINAL_SHOW == 0 )
+ //cout << endl;
+ #endif
+ #endif
+ #endif
+ #if( UNIPI_PRIMAL_INITIAL_SHOW )
+ cout << endl;
+ for( int t = 0; t < 3; t++ )
+ cout << "\t";
+ cout << "PRIMALE MCFSimplex: ARCHI E NODI ALL' INIZIO" << endl;
+ ShowSituation( 3 );
+ #endif
+ #if( QUADRATICCOST )
+ #if( LIMITATEPRECISION )
+ foValue = GetFO();
+ int cont = 0;
+ #endif
+ #endif
+
+ status = kUnSolved;
+ if( pricingRule != kCandidateListPivot )
+ arcToStartP = arcsP;
+
+ iterator = 0; // setting the initial arc for the Dantzig or First Elibigle Rule
+
+ arcPType *enteringArc;
+ arcPType *leavingArc;
+ if( pricingRule == kCandidateListPivot )
+ InitializePrimalCandidateList();
+
+ while( status == kUnSolved ) {
+ iterator++;
+ switch( pricingRule ) {
+ case( kDantzig ):
+ enteringArc = RuleDantzig();
+ break;
+ case( kFirstEligibleArc ):
+ enteringArc = PRuleFirstEligibleArc();
+ break;
+ case( kCandidateListPivot ):
+ enteringArc = RulePrimalCandidateListPivot();
+ break;
+ }
+
+ #if( QUADRATICCOST )
+ #if( LIMITATEPRECISION )
+ /* In the quadratic case with LIMITATEPRECISION == 1, the entering arcs
+ are selected according to a thresold.
+ This thresold is definited according to the old f.o. value.
+ If Primal Simplex doesn't find an entering arc, it calculates again
+ the f.o. value, and try again. */
+ if( enteringArc == NULL ) {
+ foValue = GetFO();
+ switch( pricingRule ) {
+ case( kDantzig ):
+ enteringArc = RuleDantzig();
+ break;
+ case( kFirstEligibleArc ):
+ enteringArc = PRuleFirstEligibleArc();
+ break;
+ case( kCandidateListPivot ):
+ enteringArc = RulePrimalCandidateListPivot();
+ break;
+ }
+ }
+ #endif
+ #endif
+
+ if( pricingRule != kCandidateListPivot ) {
+ // in every iteration the algorithm changes the initial arc for
+ // Dantzig and First Eligible Rule.
+ arcToStartP++;
+ if( arcToStartP == stopArcsP )
+ arcToStartP = arcsP;
+ }
+
+ if( enteringArc ) {
+ arcPType *arc;
+ nodePType *k1;
+ nodePType *k2;
+ /* If the reduced cost of the entering arc is > 0, the Primal Simplex
+ pushes flow in the cycle determinated by T and entering arc for decreases
+ flow in the entering arc: in the linear case entering arc's flow goes to 0,
+ in the quadratic case it decreases while it's possibile.
+ If the reduced cost of the entering arc is < 0, the Primal Simplex pushes
+ flow in the cycle determinated by T and entering arc for increases flow
+ in the entering arc: in the linear case entering arc's flow goes to upper
+ bound, in the quadratic case it increases while it's possibile. */
+
+ #if( QUADRATICCOST )
+ FONumber t;
+ FONumber theta;
+ FONumber deltaFO;
+ FNumber theta2;
+ CNumber Q = ( enteringArc->tail )->sumQuadratic +
+ ( enteringArc->head )->sumQuadratic + enteringArc->quadraticCost;
+ // Q is the sum of the quadratic coefficient in the cycle determinated by T
+ // and entering arc.
+ FONumber rc = ReductCost( enteringArc );
+ if( ETZ( Q, EpsCst ) )
+ theta = Inf<FNumber>(); // This value will be certainly decreased
+ else
+ theta = ABS( rc / Q );
+ // This is the best theta value (with best f.o. value decrease)
+
+ leavingArc = enteringArc;
+ nodePType *cycleRoot; // The radix of the cycle determinated by T and entering arc.
+ if( GTZ( rc , EpsCst ) ) {
+ #else
+ FNumber t;
+ FNumber theta;
+ if( enteringArc->ident == AT_UPPER ) {
+ #endif
+ /* Primal Simplex increases or decreases entering arc's flow.
+ "theta" is a positive value.
+ For this reason the algorithm uses two nodes ("k1" and "k2") to push
+ flow ("theta") from "k1" to "k2".
+ According to entering arc's reduct cost, the algorithm determinates
+ "k1" and "k2" */
+
+ k1 = enteringArc->head;
+ k2 = enteringArc->tail;
+ #if( QUADRATICCOST )
+ theta = min( theta , enteringArc->flow );
+ // The best value for theta is compared with the entering arc's bound
+ theta2 = - theta;
+ #else
+ theta = enteringArc->flow;
+ #endif
+ }
+ else {
+ k1 = enteringArc->tail;
+ k2 = enteringArc->head;
+ #if( QUADRATICCOST )
+ theta = min( theta , enteringArc->upper - enteringArc->flow );
+ // The best value for theta is compared with the entering arc's bound
+ theta2 = theta;
+ #else
+ theta = enteringArc->upper - enteringArc->flow;
+ #endif
+ }
+
+ nodePType *memK1 = k1;
+ nodePType *memK2 = k2;
+ leavingArc = NULL;
+ #if( QUADRATICCOST )
+ #if( LIMITATEPRECISION )
+ deltaFO = rc * theta2 + Q * theta2 * theta2 / 2;
+ #endif
+ bool leavingReducesFlow = GTZ( rc , EpsCst );
+ #else
+ bool leavingReducesFlow = GTZ( ReductCost( enteringArc ) , EpsCst );
+ #endif
+ // Compute "theta", find outgoing arc and "root" of the cycle
+ bool leave;
+ // Actual "theta" is compared with the bounds of the other cycle's arcs
+ while( k1 != k2 ) {
+ if( k1->subTreeLevel > k2->subTreeLevel ) {
+ arc = k1->enteringTArc;
+ if( arc->tail != k1 ) {
+ t = arc->upper - arc->flow;
+ leave = false;
+ }
+ else {
+ t = arc->flow;
+ leave = true;
+ }
+
+ if( t < theta ) {
+ // The algorithm has found a possible leaving arc
+ theta = t;
+ leavingArc = arc;
+ leavingReducesFlow = leave;
+ // If "leavingReducesFlow" == true, if this arc is selected to exit the base,
+ // it decreases its flow
+ }
+
+ k1 = Father( k1 , arc );
+ }
+ else {
+ arc = k2->enteringTArc;
+ if( arc->tail == k2 ) {
+ t = arc->upper - arc->flow;
+ leave = false;
+ }
+ else {
+ t = arc->flow;
+ leave = true;
+ }
+
+ if( t <= theta ) {
+ // The algorithm has found a possible leaving arc
+ theta = t;
+ leavingArc = arc;
+ leavingReducesFlow = leave;
+ // If "leavingReducesFlow" == true, if this arc is selected to exit the base,
+ // it decreases its flow
+ }
+
+ k2 = Father(k2, arc);
+ }
+ }
+
+ #if( QUADRATICCOST )
+ cycleRoot = k1;
+ #endif
+
+ if( leavingArc == NULL )
+ leavingArc = enteringArc;
+
+ if( theta >= Inf<FNumber>() ) {
+ status = kUnbounded;
+ break;
+ }
+
+ // Update flow with "theta"
+ k1 = memK1;
+ k2 = memK2;
+ #if( QUADRATICCOST )
+ if( enteringArc->tail == k1 )
+ theta2 = theta;
+ else
+ theta2 = -theta;
+
+ // "theta" is a positive value in every case.
+ // "theta2" is the real theta value according to the real
+ // direction of the entering arc
+ #if( LIMITATEPRECISION )
+ deltaFO = rc * theta2 + Q * theta2 * theta2 / 2;
+ // The decrease of the f.o. value in the quadratic case
+ #endif
+ #endif
+
+ if( ! ETZ(theta , EpsFlw ) ) {
+ if( enteringArc->tail == k1 )
+ enteringArc->flow = enteringArc->flow + theta;
+ else
+ enteringArc->flow = enteringArc->flow - theta;
+
+ while( k1 != k2 ) {
+ if( k1->subTreeLevel > k2->subTreeLevel ) {
+ arc = k1->enteringTArc;
+ if( arc->tail != k1 )
+ arc->flow = arc->flow + theta;
+ else
+ arc->flow = arc->flow - theta;
+
+ k1 = Father(k1, k1->enteringTArc);
+ }
+ else {
+ arc = k2->enteringTArc;
+ if( arc->tail == k2 )
+ arc->flow = arc->flow + theta;
+ else
+ arc->flow = arc->flow - theta;
+
+ k2 = Father(k2, k2->enteringTArc);
+ }
+ }
+ }
+
+ if( enteringArc != leavingArc ) {
+ bool leavingBringFlowInT2 = ( leavingReducesFlow ==
+ ( ( leavingArc->tail )->subTreeLevel > ( leavingArc->head )->subTreeLevel ) );
+ // "leavingBringFlowInT2" == true if leaving arc brings flow to the subtree T2
+ if( leavingBringFlowInT2 == ( memK1 == enteringArc->tail ) ) {
+ k2 = enteringArc->tail;
+ k1 = enteringArc->head;
+ }
+ else {
+ k2 = enteringArc->head;
+ k1 = enteringArc->tail;
+ }
+ }
+
+ #if( QUADRATICCOST == 0 )
+ if( leavingReducesFlow )
+ leavingArc->ident = AT_LOWER;
+ else
+ leavingArc->ident = AT_UPPER;
+
+ if( leavingArc != enteringArc ) {
+ enteringArc->ident = BASIC;
+ nodePType *h1;
+ nodePType *h2;
+ // "h1" is the node in the leaving arc with smaller tree's level
+ if( ( leavingArc->tail )->subTreeLevel < ( leavingArc->head )->subTreeLevel ) {
+ h1 = leavingArc->tail;
+ h2 = leavingArc->head;
+ }
+ else {
+ h1 = leavingArc->head;
+ h2 = leavingArc->tail;
+ }
+
+ UpdateT(leavingArc, enteringArc, h1, h2, k1, k2);
+ // Update potential of the subtree T2
+ k2 = enteringArc->head;
+ CNumber delta = ReductCost(enteringArc);
+ if( ( enteringArc->tail )->subTreeLevel > ( enteringArc->head )->subTreeLevel ) {
+ delta = -delta;
+ k2 = enteringArc->tail;
+ }
+
+ AddPotential( k2 , delta );
+ // In the linear case Primal Simplex only updates the potential of the nodes of
+ // subtree T2
+ }
+ #else
+ if( leavingArc != enteringArc ) {
+ nodePType *h1;
+ nodePType *h2;
+ // "h1" is the node in the leaving arc with smaller tree's level
+ if( ( leavingArc->tail )->subTreeLevel <
+ ( leavingArc->head )->subTreeLevel ) {
+ h1 = leavingArc->tail;
+ h2 = leavingArc->head;
+ }
+ else {
+ h1 = leavingArc->head;
+ h2 = leavingArc->tail;
+ }
+
+ // Update the basic tree
+ UpdateT( leavingArc , enteringArc , h1 , h2 , k1 , k2 );
+ }
+
+ #if( OPTQUADRATIC )
+ nodePType *h1;
+ nodePType *h2;
+ if( ( leavingArc->tail )->subTreeLevel <
+ ( leavingArc->head )->subTreeLevel ) {
+ h1 = leavingArc->tail;
+ h2 = leavingArc->head;
+ }
+ else {
+ h1 = leavingArc->head;
+ h2 = leavingArc->tail;
+ }
+
+ nodePType *node = h1;
+ nodePType *updateNode = h1;
+ if( h1 == cycleRoot )
+ ComputePotential( cycleRoot );
+ else {
+ while( node != cycleRoot ) {
+ arcPType *entArc = node->enteringTArc;
+ if( ! ETZ( entArc->quadraticCost , EpsCst ) )
+ updateNode = node;
+
+ node = Father( node , entArc );
+ }
+
+ ComputePotential( updateNode );
+ node = h2;
+ updateNode = h2;
+ while( node != cycleRoot ) {
+ arcPType *entArc = node->enteringTArc;
+ if( ! ETZ( entArc->quadraticCost , EpsCst ) )
+ updateNode = node;
+
+ node = Father( node , entArc );
+ }
+
+ ComputePotential( updateNode );
+ }
+ #else
+ // Update the potential of the node "manually"
+ ComputePotential( cycleRoot );
+ #endif
+
+ #if( LIMITATEPRECISION )
+ cont = cont + 1;
+ if( cont == recomputeFOLimits ) {
+ cont = 0;
+ foValue = GetFO(); // Calculate f.o. value manually
+ }
+ else
+ foValue = foValue + deltaFO;
+ // Calculate the f.o. value with the estimated decrease
+ #endif
+ #endif
+ }
+ else {
+ status = kOK;
+ // If one of dummy arcs has flow bigger than 0, the solution is unfeasible.
+ for( arcPType *arc = dummyArcsP ; arc != stopDummyP ; arc++ )
+ if( GTZ( arc->flow , EpsFlw ) )
+ status = kUnfeasible;
+ }
+
+ if( ( status == kUnSolved ) && MaxTime && MCFt ) {
+ double tu, ts;
+ TimeMCF( tu , ts );
+ if( MaxTime < tu + ts )
+ status = kStopped;
+ }
+
+ if( ( status == kUnSolved ) && MaxIter)
+ if( MaxIter < (int) iterator )
+ status = kStopped;
+
+ #if( UNIPI_PRIMAL_ITER_SHOW )
+ int it = (int) iterator;
+ if( it % UNIPI_PRIMAL_ITER_SHOW == 0 ) {
+ cout << endl;
+ for( int t = 0; t < 3; t++ )
+ cout << "\t";
+ cout << "PRIMALE MCFSimplex: ARCHI E NODI ALLA " << it << " ITERAZIONE" << endl;
+ ShowSituation( 3 );
+ #if( FOSHOW )
+ if( (int) iterator % FOSHOW == 0 )
+ clog << "Iteration = " << iterator << " of = "
+ #if( LIMITATEPRECISION && QUADRATICCOST )
+ << foValue
+ #else
+ << GetFO()
+ #endif
+ << endl;
+ #endif
+ }
+ #endif
+ }
+
+ #if( UNIPI_PRIMAL_FINAL_SHOW )
+ cout << endl;
+ for( int t = 0; t < 3; t++ )
+ cout << "\t";
+ cout << "PRIMALE UniPi: ARCHI E NODI ALLA FINE" << endl;
+ ShowSituation( 3 );
+ #endif
+
+ } // end( PrimalSimplex )
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::DualSimplex( void )
+{
+ #if( UNIPI_PRIMAL_INITIAL_SHOW == 0 )
+ #if( UNIPI_PRIMAL_ITER_SHOW == 0 )
+ #if( UNIPI_PRIMAL_FINAL_SHOW == 0 )
+ cout << endl;
+ #endif
+ #endif
+ #endif
+ #if( UNIPI_DUAL_INITIAL_SHOW )
+ cout << endl;
+ for( int t = 0; t < 3; t++ )
+ cout << "\t";
+ cout << "DUALE MCFSimplex: ARCHI E NODI ALL' INIZIO" << endl;
+ ShowSituation( 3 );
+ #endif
+
+ if( pricingRule != kCandidateListPivot )
+ arcToStartD = arcsD;
+
+ iterator = 0;
+ arcDType *enteringArc;
+ arcDType *leavingArc;
+ if( pricingRule == kCandidateListPivot )
+ InitializeDualCandidateList();
+
+ status = kUnSolved;
+ while( status == kUnSolved ) {
+ iterator++;
+ if( iterator == Inf<iteratorType>() ) {
+ ResetWhenInT2(); // Restore to 0 every nodes' field "whenInT2"
+ iterator = 1;
+ }
+
+ switch( pricingRule ) {
+ case( kDantzig ):
+ leavingArc = DRuleFirstEligibleArc();
+ break; // si esegue cmq FEA
+ case( kFirstEligibleArc ):
+ leavingArc = DRuleFirstEligibleArc();
+ break;
+ case( kCandidateListPivot ):
+ leavingArc = RuleDualCandidateListPivot();
+ break;
+ }
+
+ if( pricingRule != kCandidateListPivot ) {
+ arcToStartD++;
+ if( arcToStartD == stopArcsD )
+ arcToStartD = dummyArcsD;
+
+ if( arcToStartD == stopDummyD )
+ arcToStartD = arcsD;
+ // Setting the initial arc for the Dantzig or First Elibigle Rule
+ }
+
+ if( leavingArc ) {
+ bool leavingArcInL = false;
+ bool leavingArcFromT1toT2;
+ if( LTZ( leavingArc->flow , EpsFlw ) )
+ leavingArcInL = true;
+
+ nodeDType *h1;
+ nodeDType *h2;
+ if( ( leavingArc->tail )->subTreeLevel <
+ ( leavingArc->head )->subTreeLevel ) {
+ h1 = leavingArc->tail;
+ h2 = leavingArc->head;
+ leavingArcFromT1toT2 = true;
+ }
+ else {
+ h1 = leavingArc->head;
+ h2 = leavingArc->tail;
+ leavingArcFromT1toT2 = false;
+ }
+
+ Index numOfT2Arcs = 0;
+ int level = h2->subTreeLevel;
+ nodeDType *node = h2;
+ node->whenInT2 = iterator;
+ nodeDType *lastNodeOfT2 = h2;
+ numOfT2Arcs = node->numArcs;
+ while( node->nextInT && ( ( node->nextInT )->subTreeLevel > level ) ) {
+ node = node->nextInT;
+ lastNodeOfT2 = node;
+ numOfT2Arcs = numOfT2Arcs + node->numArcs;
+ node->whenInT2 = iterator;
+ }
+
+ /* The Dual Simplex has determinated the leaving arc, and so the
+ subtrees T1 and T2. Dual Simplex scans T2 to fix the fields "whenInT2"
+ of T2's nodes to the iteration value, and counts the entering and
+ outgoing arcs from these nodes. According to this number, it decides
+ to scan the Backward and Forward of the subtree (T1 or T2) with the
+ minor number of entering/outgoing arcs from its nodes. */
+ enteringArc = NULL;
+ bool lv = ( leavingArcFromT1toT2 == leavingArcInL );
+ CNumber maxRc = Inf<CNumber>();
+ //Search arc in the Forward Star and Backward Star of nodes of T1
+ if( numOfT2Arcs > m ) {
+ // Dual Simplex starts from the node which follows the dummy root.
+ node = dummyRootD->nextInT;
+ bool fine = false;
+ while( fine == false ) {
+ /* If node is the root of subtree T2, Dual Simplex jumps to the node
+ (if exists) which follows the last node of T2 */
+ if( node == h2 )
+ if( lastNodeOfT2->nextInT )
+ node = lastNodeOfT2->nextInT;
+ else
+ break;
+
+ // Search arc in the Backward Star of nodes of T1
+ arcDType *arc = node->firstBs;
+ while( arc ) {
+ if( ( arc->tail )->whenInT2 == iterator ) {
+ // Evaluate each arc from T2 to T1 which isn't in T
+ if( arc->ident == AT_LOWER ) {
+ if( lv ) {
+ CNumber rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+ if( ETZ( rc , EpsCst) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if( arc->ident == AT_UPPER ) {
+ if( ! lv ) {
+ CNumber rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+
+ if( ETZ( rc , EpsCst ) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ arc = arc->nextBs;
+ }
+
+ // Search arc in the Forward Star of nodes of T1
+ arc = node->firstFs;
+ while( arc ) {
+ if( ( arc->head )->whenInT2 == iterator ) {
+ // Evaluate each arc from T1 to T2 which isn't in T
+ if( arc->ident == AT_LOWER ) {
+ if( ! lv ) {
+ CNumber rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+ if( ETZ( rc , EpsCst ) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if( arc->ident == AT_UPPER ) {
+ if( lv ) {
+ CNumber rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+ if( ETZ( rc , EpsCst ) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ arc = arc->nextFs;
+ }
+
+ node = node->nextInT;
+ if( node == NULL )
+ fine = true;
+ }
+ }
+ // Search arc in the Forward Star and Backward Star of nodes of T2
+ else {
+ node = h2;
+ bool fine = false;
+ while( fine == false ) {
+ // Search arc in the Backward Star of nodes of T2
+ arcDType *arc = node->firstBs;
+ CNumber rc;
+ while( arc ) {
+ if( ( arc->tail )->whenInT2 != iterator ) {
+ // Evaluate each arc from T1 to T2 which isn't in T
+ if( arc->ident == AT_LOWER ) {
+ if( ! lv ) {
+ rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+ if( ETZ( rc , EpsCst ) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if( arc->ident == AT_UPPER ) {
+ if( lv ) {
+ rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+ if( ETZ( rc , EpsCst ) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ arc = arc->nextBs;
+ }
+
+ // Search arc in the Forward Star of nodes of T2
+ arc = node->firstFs;
+ while( arc ) {
+ if( ( arc->head )->whenInT2 != iterator ) {
+ // Evaluate each arc from T2 to T1 which isn't in T
+ if( arc->ident == AT_LOWER ) {
+ if( lv ) {
+ rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+ if( ETZ( rc , EpsCst ) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if( arc->ident == AT_UPPER ) {
+ if( ! lv ) {
+ rc = ABS( ReductCost( arc ) );
+ if( LT( rc , maxRc , EpsCst ) ) {
+ enteringArc = arc;
+ maxRc = rc;
+ /* If arc is appropriate to enter in T and its reduct cost is 0,
+ search is ended: this is the arc which enters in T */
+ if( ETZ( rc , EpsCst) ) {
+ fine = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ arc = arc->nextFs;
+ }
+
+ if( node == lastNodeOfT2 )
+ fine = true;
+ else
+ node = node->nextInT;
+
+ }
+ }
+
+ if( enteringArc ) {
+ FNumber theta = -leavingArc->flow;
+ if( GTZ( leavingArc->flow , EpsFlw ) )
+ theta = leavingArc->flow - leavingArc->upper;
+ // Initial value of theta is the infeasibility of the leaving arc
+
+ FNumber t;
+ nodeDType *k1;
+ nodeDType *k2;
+ /* if entering arc is in U, Dual Simplex pushs flow in the cycle
+ determinated by T and entering arc for decreases flow in the entering arc:
+ if entering arc is in L, Dual Simplex pushs flow in the cycle
+ determinated by T and entering arc for increases flow in the entering arc:
+ Dual Simplex increases or decreases entering arc's flow.
+ theta is a positive value.
+ For this reason the algorithm uses two nodes (k1 and k2) to push flow
+ (theta) from k1 to k2. According to entering arc's reduct cost, the
+ algorithm determinates k1 and k2 */
+
+ if( enteringArc->ident == AT_UPPER ) {
+ k1 = enteringArc->head;
+ k2 = enteringArc->tail;
+ }
+ else {
+ k1 = enteringArc->tail;
+ k2 = enteringArc->head;
+ }
+
+ nodeDType *memK1 = k1;
+ nodeDType *memK2 = k2;
+ arcDType *arc;
+ k1 = memK1;
+ k2 = memK2;
+ // Update the flow
+ while( k1 != k2 ) {
+ if( k1->subTreeLevel > k2->subTreeLevel ) {
+ arc = k1->enteringTArc;
+ if( arc->tail != k1 )
+ arc->flow = arc->flow + theta;
+ else
+ arc->flow = arc->flow - theta;
+
+ k1 = Father(k1, k1->enteringTArc);
+ }
+ else {
+ arc = k2->enteringTArc;
+ if( arc->tail == k2 )
+ arc->flow = arc->flow + theta;
+ else
+ arc->flow = arc->flow - theta;
+
+ k2 = Father( k2 , k2->enteringTArc );
+ }
+ }
+
+ if(leavingArcInL )
+ leavingArc->ident = AT_LOWER;
+ else
+ leavingArc->ident = AT_UPPER;
+
+ bool leavingBringFlowInT2 = ( leavingArcInL ==
+ ( ( leavingArc->tail )->subTreeLevel >
+ ( leavingArc->head )->subTreeLevel ) );
+ // leavingBringFlowInT2 == true if leaving arc brings flow to the subtree T2
+ if( leavingBringFlowInT2 != ( memK1 == enteringArc->tail ) ) {
+ k2 = enteringArc->tail;
+ k1 = enteringArc->head;
+ }
+ else {
+ k2 = enteringArc->head;
+ k1 = enteringArc->tail;
+ }
+
+ if( enteringArc->ident == AT_LOWER )
+ enteringArc->flow = enteringArc->flow + theta;
+ else
+ enteringArc->flow = enteringArc->flow - theta;
+
+ enteringArc->ident = BASIC;
+ UpdateT( leavingArc , enteringArc , h1 , h2 , k1 , k2 );
+ // update potential of the subtree T2
+ k2 = enteringArc->head;
+ CNumber delta = ReductCost( enteringArc );
+ if( ( enteringArc->tail) ->subTreeLevel >
+ ( enteringArc->head )->subTreeLevel ) {
+ delta = -delta;
+ k2 = enteringArc->tail;
+ }
+
+ // Dual Simplex only updates the potential of the T2's nodes
+ AddPotential( k2 , delta );
+ }
+ else
+ status = kUnfeasible;
+ /* If Dual Simplex finds a leaving arc but it doesn't find an entering arc,
+ the algorithm stops. At this point Dual Simplex has an unfeasible primal
+ solution. */
+ }
+ else {
+ status = kOK;
+ // If one of dummy arcs has flow different than 0, the solution is unfeasible.
+ for( arcDType *arc = dummyArcsD ; arc != stopDummyD ; arc++ )
+ if( ! ETZ( arc->flow , EpsFlw ) ) {
+ status = kUnfeasible;
+ break;
+ }
+ }
+
+ if( ( status == kUnSolved ) && MaxTime ) {
+ double tu, ts;
+ TimeMCF( tu , ts );
+ if( MaxTime < tu + ts )
+ status = kStopped;
+ }
+
+ if( ( status == kUnSolved ) && MaxIter && MCFt )
+ if( MaxIter < (int) iterator )
+ status = kStopped;
+
+ #if( UNIPI_DUAL_ITER_SHOW )
+ if( (int) iterator % UNIPI_DUAL_ITER_SHOW == 0 ) {
+ cout << endl;
+ for( int t = 0; t < 3; t++ )
+ cout << "\t";
+ cout << "DUALE MCFSimplex: ARCHI E NODI ALLA " << iterator << " ITERAZIONE"
+ << endl;
+ ShowSituation( 3 );
+ #if( FOSHOW )
+ cout << "of = " << GetFO() << endl;
+ #endif
+ }
+ #endif
+ }
+
+ #if( UNIPI_DUAL_ITER_SHOW )
+ int it = (int) iterator;
+ if( it % UNIPI_DUAL_ITER_SHOW == 0 ) {
+ cout << endl;
+ for( int t = 0; t < 3; t++ )
+ cout << "\t";
+ cout << "DUALE MCFSimplex: ARCHI E NODI ALLA " << iterator << " ITERAZIONE"
+ << endl;
+ Showsituation( 3 );
+ }
+ #endif
+
+ } // end( DualSimplex )
+
+/*--------------------------------------------------------------------------*/
+
+template<class N, class A>
+void MCFSimplex::UpdateT( A *h , A *k , N *h1 , N *h2 , N *k1 , N *k2 )
+{
+ /* In subtree T2 there is a path from node h2 (deepest node of the leaving
+ arc h and root of T2) to node k2 (deepest node of the leaving arc h and
+ coming root of T2). With the update of T, this path will be overturned:
+ node k2 will become the root of T2...
+ The subtree T2 must be reordered and the field "subTreeLevel", which
+ represents the depth in T of every node, of every T2's nodes is changed.
+ Variable delta represents the increase of "subTreeLevel" value for node
+ k2 and its descendants: probably this value is a negative value. */
+
+ int delta = (k1->subTreeLevel) + 1 - (k2->subTreeLevel);
+ N *root = k2;
+ N *dad;
+
+ /*To reorder T2, the method analyses every nodes of the path h2->k2, starting
+ from k2. For every node, it moves the node's subtree from its original
+ position to a new appropriate position. In particular k2 and its subtree
+ (k2 is the new root of T2, so the first nodes of the new T2) will be moved
+ next to node k1 (new father of k2), the next subtree will be moved beside
+ the last node of k2's subtree....
+ "previousNode" represents the node where the new subtree will be moved
+ beside in this iterative action. At the start "previousNode" is the node
+ k1 (T2 will be at the right of k1). */
+
+ N *previousNode = k1;
+ N *lastNode;
+ /* "arc1" is the entering arc in T (passed by parameters).
+ For every analysed node of path h2->k2, the method changes
+ "enteringTArc" but it must remember the old arc, which will be the
+ "enteringTArc" of the next analysed node.
+ At the start "arc1" is k (the new "enteringTArc" of k2). */
+
+ A *arc1 = k;
+ A *arc2;
+ bool fine = false;
+ while( fine == false ) {
+ // If analysed node is h2, this is the last iteration
+ if( root == h2 )
+ fine = true;
+
+ dad = Father( root , root->enteringTArc );
+ // Cut the root's subtree from T and update the "subLevelTree" of its nodes
+ lastNode = CutAndUpdateSubtree( root , delta );
+ // Paste the root's subtree in the right position;
+ PasteSubtree( root , lastNode , previousNode );
+ // In the next iteration the subtree will be moved beside the last node of
+ // the actual analysed subtree.
+ previousNode = lastNode;
+ /* The increase of the subtree in the next iteration is different from
+ the actual increase: in particual the increase increases itself (+2
+ at every iteration). */
+ delta = delta + 2;
+ /* A this point "enteringTArc" of actual root is stored in "arc2" and
+ changed; then "arc1" and "root" are changed. */
+ arc2 = root->enteringTArc;
+ root->enteringTArc = arc1;
+ arc1 = arc2;
+ root = dad;
+ }
+ }
+
+/*--------------------------------------------------------------------------*/
+
+template<class N>
+N* MCFSimplex::CutAndUpdateSubtree( N *root , int delta )
+{
+ int level = root->subTreeLevel;
+ N *node = root;
+ // The root of this subtree is passed by parameters, the last node is searched.
+ while ( ( node->nextInT ) && ( ( node->nextInT )->subTreeLevel > level ) ) {
+ node = node->nextInT;
+ // The "subTreeLevel" of every nodes of subtree is updated
+ node->subTreeLevel = node->subTreeLevel + delta;
+ }
+
+ root->subTreeLevel = root->subTreeLevel + delta;
+ /* The 2 neighbouring nodes of the subtree (the node at the left of the root
+ and the node at the right of the last node) is joined. */
+
+ if( root->prevInT )
+ ( root->prevInT )->nextInT = node->nextInT;
+ if( node->nextInT )
+ ( node->nextInT )->prevInT = root->prevInT;
+
+ return( node ); // the method returns the last node of the subtree
+ }
+
+/*--------------------------------------------------------------------------*/
+
+template<class N>
+void MCFSimplex::PasteSubtree( N *root , N *lastNode , N *previousNode )
+{
+ /* The method inserts subtree ("root" and "lastNode" are the extremity of the
+ subtree) after "previousNode". The method starts to identify the next node
+ of "previousNode" ("nextNode"), so it joins "root" with "previousNode" and
+ "lastNode" with "nextNode" (if exists). */
+
+ N *nextNode = previousNode->nextInT;
+ root->prevInT = previousNode;
+ previousNode->nextInT = root;
+ lastNode->nextInT = nextNode;
+ if( nextNode )
+ nextNode->prevInT = lastNode;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::arcPType* MCFSimplex::RuleDantzig( void )
+{
+ arcPType *arc = arcToStartP;
+ arcPType *enteringArc = NULL;
+ #if( QUADRATICCOST )
+ /* In the quadratic case used type for reduct cost is FONumber.
+ Value "lim" is the fixed thresold for the decrease of the f.o. value */
+ FONumber lim = EpsOpt * foValue / n;
+ FONumber RC;
+ FONumber maxValue = 0;
+ #else
+ CNumber RC;
+ CNumber maxValue = 0;
+ #endif
+
+ do {
+ // The method analyses every arc
+ #if( QUADRATICCOST )
+ RC = ReductCost( arc );
+ FNumber theta;
+ /* If reduct cost of arc is lower than 0, the flow of the arc must increase.
+ If reduct cost of arc is bigger than 0, the flow of the arc must decrease.
+ "theta" is the difference between lower (upper) bound and the actual flow.
+ */
+
+ if( LTZ( RC , EpsCst ) )
+ theta = arc->upper - arc->flow;
+
+ if( GTZ( RC , EpsCst ) )
+ theta = -arc->flow;
+
+ // If it's possible to increase (or decrease) the flow in this arc
+ if( ! ETZ( theta , EpsFlw ) ) {
+ /* "Q" is the sum of the quadratic coefficient of the arc belonging the
+ T path from tail's arc to head's arc
+ "Q" is always bigger than 0 or equals to 0.
+ If "Q" > 0, the value - RC / Q is the increase (decrease) of the flow
+ with the best decrease of f.o. value.
+ - RC/ Q must be compare with "theta" to avoid that the best increase
+ (decrease) of the flow violates the bounds of the arc.
+ This confront determines "theta". */
+
+ CNumber Q = ( arc->tail )->sumQuadratic + ( arc->head )->sumQuadratic +
+ arc->quadraticCost;
+
+ if( GTZ( Q , EpsCst ) )
+ if( GTZ( theta , EpsFlw ) )
+ theta = min( theta , - RC / Q );
+ else
+ theta = max( theta , - RC / Q );
+
+ /* Calculate the estimate decrease of the f.o. value if this arc is
+ selected and flow is increased (decreased) by "theta" */
+
+ CNumber deltaFO = RC * theta + Q * theta * theta / 2;
+ // if deltaFO < 0 this arc is appropriate; if deltaFO is lower than
+ // old decrease value, arc is the best arc.
+
+ if( deltaFO < maxValue ) {
+ maxValue = deltaFO;
+ enteringArc = arc;
+ }
+ }
+ #else
+ if( arc->ident > BASIC ) {
+ RC = ReductCost( arc );
+
+ if( ( LTZ( RC , EpsCst ) && ( arc->ident == AT_LOWER ) ) ||
+ ( GTZ( RC , EpsCst ) && ( arc->ident == AT_UPPER ) ) ) {
+
+ if( RC < 0 )
+ RC = -RC;
+
+ if( RC > maxValue ) {
+ maxValue = RC;
+ enteringArc = arc;
+ }
+ }
+ }
+ #endif
+
+ arc++;
+ if( arc == stopArcsP )
+ arc = arcsP;
+
+ } while( arc != arcToStartP );
+
+ #if( ( LIMITATEPRECISION ) && ( QUADRATICCOST ) )
+ if( -maxValue <= lim )
+ enteringArc = NULL;
+ #endif
+
+ return( enteringArc );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::arcPType* MCFSimplex::PRuleFirstEligibleArc( void )
+{
+ arcPType *arc = arcToStartP;
+ arcPType *enteringArc = NULL;
+ #if( QUADRATICCOST )
+ FONumber RC;
+ #else
+ CNumber RC;
+ #endif
+
+ do {
+ #if( QUADRATICCOST )
+ // In this method the "decrease f.o. value" criterion is not used.
+ RC = ReductCost( arc );
+ if( ( LTZ( RC , EpsCst ) && LT( arc->flow , arc->upper , EpsFlw ) ) ||
+ ( GTZ( RC , EpsCst ) && GTZ( arc->flow , EpsFlw ) ) )
+ enteringArc = arc;
+ #else
+ if( arc->ident > BASIC ) {
+ RC = ReductCost( arc );
+ if( ( LTZ( RC , EpsCst ) && ( arc->ident == AT_LOWER ) ) ||
+ ( GTZ( RC , EpsCst ) && ( arc->ident == AT_UPPER ) ) )
+ enteringArc = arc;
+ }
+ #endif
+
+ arc++;
+ if( arc == stopArcsP )
+ arc = dummyArcsP;
+ if( arc == stopDummyP )
+ arc = arcsP;
+
+ } while( ( enteringArc == NULL ) && ( arc != arcToStartP ) );
+
+ return( enteringArc );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::arcDType* MCFSimplex::DRuleFirstEligibleArc( void )
+{
+ arcDType *arc = arcToStartD;
+ arcDType *leavingArc = NULL;
+ do {
+ if( GT( arc->flow , arc->upper , EpsFlw ) || LTZ( arc->flow , EpsFlw ) )
+ leavingArc = arc;
+
+ arc++;
+ if( arc == stopArcsD )
+ arc = dummyArcsD;
+ if( arc == stopDummyD )
+ arc = arcsD;
+
+ } while( ( leavingArc == NULL ) && ( arc != arcToStartD ) );
+
+ return(leavingArc);
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::arcPType* MCFSimplex::RulePrimalCandidateListPivot( void )
+{
+ Index next = 0;
+ Index i;
+ Index minimeValue;
+ if( hotListSize < tempCandidateListSize )
+ minimeValue = hotListSize;
+ else
+ minimeValue = tempCandidateListSize;
+
+ #if( QUADRATICCOST )
+ // Check if the left arcs in the list continue to violate the dual condition
+ for( i = 2 ; i <= minimeValue ; i++ ) {
+ arcPType *arc = candP[ i ].arc;
+ FONumber red_cost = ReductCost( arc );
+ FNumber theta = 0;
+ /* If reduct cost of arc is lower than 0, the flow of the arc must increase.
+ If reduct cost of arc is bigger than 0, the flow of the arc must decrease.
+ "theta" is the difference between lower (upper) bound and the actual flow.
+ */
+
+ if( LTZ( red_cost , EpsCst ) )
+ theta = arc->upper - arc->flow;
+ else
+ if( GTZ( red_cost , EpsCst ) )
+ theta = - arc->flow;
+
+ // if it's possible to increase (or decrease) the flow in this arc
+ if( theta != 0 ) {
+ /* "Q" is the sum of the quadratic coefficient of the arc belonging the T
+ path from tail's arc to head's arc
+ "Q" is always bigger than 0 or equals to 0.
+ If "Q" > 0, the value - RC / Q is the increase (decrease) of the flow
+ with the best decrease of f.o. value.
+ - RC/ Q must be compare with "theta" to avoid that the best increase
+ (decrease) of the flow violates the bounds of the arc.
+ This confront determines "theta". */
+
+ CNumber Q = ( arc->tail )->sumQuadratic + ( arc->head )->sumQuadratic +
+ arc->quadraticCost;
+
+ if( GTZ( Q , EpsCst ) )
+ if( GTZ( theta , EpsFlw ) )
+ theta = min( theta , - red_cost / Q );
+ else
+ theta = max( theta , - red_cost / Q );
+
+ /* Calculate the estimate decrease of the f.o. value if this arc is
+ selected and flow is increased (decreased) by "theta" */
+
+ CNumber deltaFO = red_cost * theta + Q * theta * theta / 2;
+ #if( LIMITATEPRECISION )
+ // if deltaFO < 0 this arc is appropriate; if deltaFO is lower than
+ // old decrease value, arc is the best arc.
+ if( - deltaFO > ( EpsOpt * foValue / n ) ) {
+ #else
+ if( LTZ( deltaFO , EpsCst ) ) {
+ #endif
+ next++;
+ candP[ next ].arc = arc;
+ candP[ next ].absRC = -deltaFO;
+ }
+ }
+ }
+
+ tempCandidateListSize = next;
+ Index oldGroupPos = groupPos;
+ // Search other arcs to fill the list
+ do {
+ arcPType *arc;
+ for( arc = arcsP + groupPos ; arc < stopArcsP ; arc += numGroup ) {
+ FONumber red_cost = ReductCost( arc );
+ FNumber theta = 0;
+ /* If reduced cost is lower than 0, the flow of the arc must increase.
+ If reduced cost is larger than 0, the flow of the arc must decrease.
+ "theta" is the difference between lower (upper) bound and the actual
+ flow. */
+
+ if( LTZ( red_cost , EpsCst ) )
+ theta = arc->upper - arc->flow;
+ else
+ if( GTZ( red_cost , EpsCst ) )
+ theta = - arc->flow;
+
+ // if it's possible to increase (or decrease) the flow in this arc
+ if( theta != 0 ) {
+ /* "Q" is the sum of the quadratic coefficient of the arc belonging the T
+ path from tail's arc to head's arc
+ "Q" is always bigger than 0 or equals to 0.
+ If "Q" > 0, the value - RC / Q is the increase (decrease) of the flow
+ with the best decrease of f.o. value.
+ - RC/ Q must be compare with "theta" to avoid that the best increase
+ (decrease) of the flow violates the bounds of the arc.
+ This confront determines "theta". */
+ CNumber Q = ( arc->tail )->sumQuadratic + ( arc->head )->sumQuadratic +
+ arc->quadraticCost;
+
+ if( GTZ( Q , EpsCst ) )
+ if( GTZ( theta , EpsFlw ) )
+ theta = min( theta , - red_cost / Q );
+ else
+ theta = max( theta , - red_cost / Q );
+
+ /* Calculate the estimate decrease of the f.o. value if this arc is
+ selected and flow is increased (decreased) by "theta" */
+
+ CNumber deltaFO = red_cost * theta + Q * theta * theta / 2;
+ #if( LIMITATEPRECISION )
+ // if deltaFO < 0 this arc is appropriate; if deltaFO is lower than
+ // old decrease value, arc is the best arc.
+ if( -deltaFO > ( EpsOpt * foValue / n ) ) {
+ #else
+ if( LTZ( deltaFO , EpsCst ) ) {
+ #endif
+ tempCandidateListSize++;
+ candP[ tempCandidateListSize ].arc = arc;
+ candP[ tempCandidateListSize ].absRC = -deltaFO;
+ }
+ }
+ }
+
+ groupPos++;
+ if( groupPos == numGroup )
+ groupPos = 0;
+
+ } while( ( tempCandidateListSize < hotListSize ) &&
+ ( groupPos != oldGroupPos ) );
+ #else
+ // Check if the left arcs in the list continue to violate the dual condition
+ for( i = 2 ; i <= minimeValue ; i++ ) {
+ arcPType *arc = candP[i].arc;
+ CNumber red_cost = ReductCost( arc );
+
+ if( ( LTZ( red_cost , EpsCst ) && ( arc->ident == AT_LOWER ) ) ||
+ ( GTZ( red_cost , EpsCst ) && ( arc->ident == AT_UPPER ) ) ) {
+ next++;
+ candP[ next ].arc = arc;
+ candP[ next ].absRC = ABS( red_cost );
+ }
+ }
+
+ tempCandidateListSize = next;
+ Index oldGroupPos = groupPos;
+ // Search other arcs to fill the list
+ do {
+ arcPType *arc;
+ for( arc = arcsP + groupPos ; arc < stopArcsP ; arc += numGroup ) {
+ if( arc->ident == AT_LOWER ) {
+ CNumber red_cost = ReductCost( arc );
+ if( LTZ( red_cost , EpsCst ) ) {
+ tempCandidateListSize++;
+ candP[ tempCandidateListSize ].arc = arc;
+ candP[ tempCandidateListSize ].absRC = ABS( red_cost );
+ }
+ }
+ else
+ if( arc->ident == AT_UPPER ) {
+ CNumber red_cost = ReductCost( arc );
+ if( GTZ( red_cost , EpsCst ) ) {
+ tempCandidateListSize++;
+ candP[ tempCandidateListSize ].arc = arc;
+ candP[ tempCandidateListSize ].absRC = ABS( red_cost );
+ }
+ }
+ }
+
+ groupPos++;
+ if( groupPos == numGroup )
+ groupPos = 0;
+
+ } while( ( tempCandidateListSize < hotListSize ) && ( groupPos != oldGroupPos ) );
+ #endif
+
+ if( tempCandidateListSize ) {
+ SortPrimalCandidateList( 1 , tempCandidateListSize );
+ return( candP[ 1 ].arc );
+ }
+ else
+ return( NULL );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+inline void MCFSimplex::InitializePrimalCandidateList( void )
+{
+ numGroup = ( ( m - 1 ) / numCandidateList ) + 1;
+ groupPos = 0;
+ tempCandidateListSize = 0;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+inline void MCFSimplex::SortPrimalCandidateList( Index min , Index max )
+{
+ Index left = min;
+ Index right = max;
+ #if( QUADRATICCOST )
+ FONumber cut = candP[ ( left + right ) / 2 ].absRC;
+ #else
+ CNumber cut = candP[ ( left + right ) / 2 ].absRC;
+ #endif
+ do {
+ while( candP[ left ].absRC > cut)
+ left++;
+ while( cut > candP[ right ].absRC)
+ right--;
+
+ if( left < right )
+ Swap( candP[ left ] , candP[ right ] );
+
+ if(left <= right) {
+ left++;
+ right--;
+ }
+ } while( left <= right );
+
+ if( min < right )
+ SortPrimalCandidateList( min , right );
+ if( ( left < max ) && ( left <= hotListSize ) )
+ SortPrimalCandidateList( left , max );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::arcDType* MCFSimplex::RuleDualCandidateListPivot( void )
+{
+ Index next = 0;
+ // Check if the left arcs in the list continue to violate the primal condition
+ for( Index i = 2 ; ( i <= hotListSize ) && ( i <= tempCandidateListSize ) ;
+ i++ ) {
+ nodeDType *node = candD[ i ].node;
+ arcDType *arc = node->enteringTArc;
+ cFNumber flow = arc->flow;
+ if( LTZ( flow , EpsFlw ) ) {
+ next++;
+ candD[ next ].node = node;
+ candD[ next ].absInfeas = ABS( flow );
+ }
+
+ if( GT( flow , arc->upper , EpsFlw ) ) {
+ next++;
+ candD[ next ].node = node;
+ candD[ next ].absInfeas = flow - arc->upper;
+ }
+ }
+
+ tempCandidateListSize = next;
+ Index oldGroupPos = groupPos;
+ // Search other arcs to fill the list
+ do {
+ nodeDType *node = nodesD + groupPos;
+ for( node ; node < stopNodesD ; node += numGroup ) {
+ arcDType *arc = node->enteringTArc;
+ cFNumber flow = arc->flow;
+ if( LTZ( flow , EpsFlw ) ) {
+ tempCandidateListSize++;
+ candD[ tempCandidateListSize ].node = node;
+ candD[ tempCandidateListSize ].absInfeas = ABS( flow );
+ }
+
+ if( GT( flow , arc->upper , EpsFlw) ) {
+ tempCandidateListSize++;
+ candD[ tempCandidateListSize ].node = node;
+ candD[ tempCandidateListSize ].absInfeas = flow - arc->upper;
+ }
+ }
+
+ groupPos++;
+ if( groupPos == numGroup )
+ groupPos = 0;
+
+ } while( ( tempCandidateListSize < hotListSize ) &&
+ ( groupPos != oldGroupPos ) );
+
+ if( tempCandidateListSize ) {
+ SortDualCandidateList( 1 , tempCandidateListSize );
+ return( (candD[ 1 ].node)->enteringTArc );
+ }
+ else
+ return( NULL );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+inline void MCFSimplex::InitializeDualCandidateList( void )
+{
+ numGroup = ( ( n - 1 ) / numCandidateList ) + 1;
+ groupPos = 0;
+ tempCandidateListSize = 0;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+inline void MCFSimplex::SortDualCandidateList(Index min, Index max)
+{
+ Index left = min;
+ Index right = max;
+ FNumber cut = candD[ ( left + right ) / 2 ].absInfeas;
+ do {
+ while( candD[ left ].absInfeas > cut )
+ left++;
+ while( cut > candD[ right ].absInfeas )
+ right--;
+ if( left < right )
+ Swap( candD[left ] , candD[ right ] );
+ if( left <= right) {
+ left++;
+ right--;
+ }
+ } while( left <= right );
+
+ if( min < right )
+ SortDualCandidateList( min , right );
+ if( (left < max) && ( left <= hotListSize ) )
+ SortDualCandidateList( left , max );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+template<class N, class RCT>
+inline void MCFSimplex::AddPotential( N *r , RCT delta )
+{
+ int level = r->subTreeLevel;
+ N *n = r;
+
+ do {
+ n->potential = n->potential + delta;
+ n = n->nextInT;
+ } while ( ( n ) && ( n->subTreeLevel > level ) );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+template<class N>
+inline void MCFSimplex::ComputePotential( N *r )
+{
+ N *n = r;
+ int level = r->subTreeLevel;
+ FONumber cost;
+ // If "n" is not the dummy root, the potential of "r" is computed.
+ // If "n" is the dummy root, the potential of dummy root is a constant.
+
+ do {
+ if( n->enteringTArc ) {
+ cost = ( n->enteringTArc )->cost;
+ #if (QUADRATICCOST)
+ // Also field "sumQuadratic" is updated
+ n->sumQuadratic = ( Father( n , n->enteringTArc ) )->sumQuadratic +
+ ( n->enteringTArc )->quadraticCost;
+
+ if( ! ETZ( ( n->enteringTArc )->flow , EpsFlw ) )
+ cost = cost + ( ( n->enteringTArc )->quadraticCost * ( n->enteringTArc )->flow );
+ #endif
+
+ if( n == ( n->enteringTArc )->head )
+ n->potential = ( Father( n , n->enteringTArc ) )->potential + cost;
+ else
+ n->potential = ( Father( n , n->enteringTArc ) )->potential - cost;
+ }
+ n = n->nextInT;
+ } while( ( n ) && ( n->subTreeLevel > level ) );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::CreateInitialPModifiedBalanceVector( void )
+{
+ int i = 0;
+ delete[] modifiedBalance;
+ modifiedBalance = new FNumber[ n ];
+ // Initialited every node's modifiedBalance to his balance
+ for ( nodePType *node = nodesP ; node != stopNodesP ; node++ ) {
+ modifiedBalance[i] = node->balance;
+ i++;
+ }
+
+ // Modify the vector according to the arcs out of base with flow non zero
+ // Scan the real arcs
+
+ for( arcPType *arc = arcsP ; arc != stopArcsP ; arc++ ) {
+ #if( QUADRATICCOST )
+ if( ( ! ETZ( arc->flow , EpsFlw ) ) &&
+ ( ( arc->tail )->enteringTArc != arc ) &&
+ ( ( arc->head )->enteringTArc != arc ) ) {
+ i = (arc->tail) - nodesP;
+ modifiedBalance[ i ] += arc->flow;
+ i = (arc->head) - nodesP;
+ modifiedBalance[ i ] -= arc->flow;
+ }
+ #else
+ if( arc->ident == AT_UPPER ) {
+ i = (arc->tail) - nodesP;
+ modifiedBalance[ i ] += arc->upper;
+ i = (arc->head) - nodesP;
+ modifiedBalance[ i ] -= arc->upper;
+ }
+ #endif
+ }
+
+ // Scan the dummy arcs
+ for( arcPType *arc = dummyArcsP ; arc != stopDummyP ; arc++ ) {
+ #if( QUADRATICCOST )
+ if ( ( ! ETZ( arc->flow , EpsFlw ) ) &&
+ ( ( arc->tail )->enteringTArc != arc ) &&
+ ( ( arc->head )->enteringTArc != arc ) ) {
+ i = (arc->tail) - nodesP;
+ modifiedBalance[ i ] += arc->flow;
+ i = (arc->head) - nodesP;
+ modifiedBalance[ i ] -= arc->flow;
+ }
+ #else
+ if (arc->ident == AT_UPPER) {
+ i = (arc->tail) - nodesP;
+ modifiedBalance[ i ] += arc->upper;
+ i = (arc->head) - nodesP;
+ modifiedBalance[ i ] -= arc->upper;
+ }
+ #endif
+ }
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::PostPVisit( nodePType *r )
+{
+ // The method controls if "r" is a leaf in T
+ bool rLeaf = false;
+ int i = r - nodesP;
+ if( r->nextInT )
+ if( ( r->nextInT )->subTreeLevel <= r->subTreeLevel )
+ rLeaf = true;
+ else
+ rLeaf = true;
+
+ if( rLeaf ) // If "r" is a leaf
+ if( ( r->enteringTArc)->head == r ) // If enteringTArc of "r" goes in "r"
+ ( r->enteringTArc )->flow = modifiedBalance[ i ];
+ else // If enteringTArc of "r" goes out "r"
+ ( r->enteringTArc )->flow = - modifiedBalance[ i ];
+ else { // If "r" isn't a leaf
+ nodePType *desc = r->nextInT;
+ // Call PostPVisit for every child of "r"
+ while( ( desc ) && ( desc->subTreeLevel > r->subTreeLevel ) ) {
+ if( desc->subTreeLevel - 1 == r->subTreeLevel ) { // desc is a son of r
+ PostPVisit( desc );
+
+ if( ( desc->enteringTArc )->head == r ) // enteringTArc of desc goes in r
+ modifiedBalance[ i ] -= ( desc->enteringTArc )->flow;
+ else // If enteringTArc of "desc" goes out "r"
+ modifiedBalance[ i ] += ( desc->enteringTArc )->flow;
+ }
+ desc = desc->nextInT;
+ }
+
+ if( r != dummyRootP )
+ if( ( r->enteringTArc )->head == r ) // If enteringTArc of "r" goes in "r"
+ ( r->enteringTArc )->flow = modifiedBalance[ i ];
+ else // If enteringTArc of "r" goes out "r"
+ ( r->enteringTArc )->flow = - modifiedBalance[ i ];
+ }
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::BalanceFlow( nodePType *r )
+{
+ // used only by Primal Simplex to restore a primal feasible solution.
+ if( r == dummyRootP ) {
+ nodePType *node = dummyRootP->nextInT;
+ while( node ) {
+ // call this function recursively for every son of dummy root
+ if( node->subTreeLevel == 1 )
+ BalanceFlow( node );
+
+ node = node->nextInT;
+ }
+ }
+ else {
+ // The method controls if "r" is a leaf in T
+ bool rLeaf = false;
+ if( r->nextInT )
+ if( ( r->nextInT )->subTreeLevel <= r->subTreeLevel )
+ rLeaf = true;
+ else
+ rLeaf = true;
+
+ if( rLeaf ) // If "r" is a leaf
+ AdjustFlow( r ); // The method controls if entering basic arc in "r" is
+ // not feasible; in case adjust its flow
+ else { // If "r" isn't a leaf
+ nodePType *node = r->nextInT;
+ // Balance the flow of every child of "r"
+ while ( ( node ) && ( node->subTreeLevel > r->subTreeLevel ) ) {
+ if( node->subTreeLevel == r->subTreeLevel + 1 )
+ BalanceFlow( node );
+ node = node->nextInT;
+ }
+
+ // The method controls if entering basic arc in "r" is not feasible;
+ //in case adjust its flow
+ AdjustFlow( r );
+ }
+ }
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::AdjustFlow( nodePType *r )
+{
+ arcPType *arc = r->enteringTArc;
+ if( arc >= dummyArcsP ) // If entering arc of "r" is a dummy arc
+ if( LTZ( arc->flow , EpsFlw ) ) {
+ // If this dummy arc has flow < 0, the algorithm overturns the arc
+ nodePType *temp = arc->tail;
+ arc->tail = arc->head;
+ arc->head = temp;
+ arc->flow = -arc->flow;
+ }
+ else { // If entering arc of "r" is not a dummy arc
+ bool orientationDown = ( arc->head == r );
+ FNumber delta = 0;
+ if( LTZ( arc->flow , EpsFlw ) ) { // If flow is < 0
+ delta = -arc->flow;
+ arc->flow = 0;
+ #if( ! QUADRATICCOST )
+ arc->ident = AT_LOWER;
+ #endif
+ }
+
+ if( GT( arc->flow , arc->upper , EpsFlw ) ) {
+ // If flow goes over the capacity of the arc
+ delta = arc->upper - arc->flow;
+ arc->flow = arc->upper;
+ #if( ! QUADRATICCOST )
+ arc->ident = AT_UPPER;
+ #endif
+ }
+
+ /* This arc goes out from the basis, and the relative dummy arc goes in T.
+ Then the algorithm push flow in the cycle made by the arc and some arcs
+ of T to balance the flow. */
+
+ if( ! ETZ( delta , EpsFlw ) ) {
+ nodePType *node = Father( r , arc );
+ while( node != dummyRootP ) {
+ arc = node->enteringTArc;
+ if( ( arc->head == node ) == orientationDown )
+ arc->flow += delta;
+ else
+ arc->flow -= delta;
+
+ node = Father( node , arc );
+ }
+
+ arcPType *dummy = dummyArcsP + ( r - nodesP );
+ #if( ! QUADRATICCOST )
+ dummy->ident = BASIC;
+ #endif
+
+ /* Update the structure of the tree. If entering basic arc of "r" is
+ changed, subtree of "r"is moved next dummy root. */
+ r->enteringTArc = dummy;
+ int deltaLevel = 1 - r->subTreeLevel;
+ nodePType *lastNode = CutAndUpdateSubtree( r , deltaLevel );
+ PasteSubtree( r , lastNode , dummyRootP );
+ if( ( dummy->head == r ) != orientationDown )
+ dummy->flow += delta;
+ else
+ dummy->flow -= delta;
+
+ if( LTZ( dummy->flow , EpsFlw ) ) {
+ nodePType *temp = dummy->tail;
+ dummy->tail = dummy->head;
+ dummy->head = temp;
+ dummy->flow = -dummy->flow;
+ }
+ }
+ }
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::CreateInitialDModifiedBalanceVector( void )
+{
+ #if( ! QUADRATICCOST )
+ int i = 0;
+ modifiedBalance = new FNumber[ n ];
+ // Initialited every node's modifiedBalance to his balance
+ for( nodeDType *node = nodesD ; node != stopNodesD ; node++ ) {
+ modifiedBalance[ i ] = node->balance;
+ i++;
+ }
+
+ // Modify the vector according to the arcs out of base with flow non zero
+ // Scan the real arcs
+ for( arcDType *arc = arcsD ; arc != stopArcsD ; arc++ )
+ if( arc->ident == AT_UPPER ) {
+ i = (arc->tail) - nodesD;
+ modifiedBalance[ i ] += arc->upper;
+ i = (arc->head) - nodesD;
+ modifiedBalance[ i ] -= arc->upper;
+ }
+
+ // Scan the dummy arcs
+ for( arcDType *arc = dummyArcsD ; arc != stopDummyD ; arc++ )
+ if( arc->ident == AT_UPPER ) {
+ i = (arc->tail) - nodesD;
+ modifiedBalance[ i ] += arc->upper;
+ i = (arc->head) - nodesD;
+ modifiedBalance[ i ] -= arc->upper;
+ }
+ #endif
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::PostDVisit( nodeDType *r )
+{
+ #if( ! QUADRATICCOST )
+ // The method controls if "r" is a leaf in T
+ bool rLeaf = false;
+ int i = r - nodesD;
+ if( r->nextInT )
+ if( ( r->nextInT )->subTreeLevel <= r->subTreeLevel )
+ rLeaf = true;
+ else
+ rLeaf = true;
+
+ if( rLeaf ) // If "r" is a leaf
+ if( ( r->enteringTArc)->head == r ) // If enteringTArc of "r" goes in "r"
+ ( r->enteringTArc )->flow = modifiedBalance[ i ];
+ else // If enteringTArc of "r" goes out "r"
+ ( r->enteringTArc )->flow = - modifiedBalance[ i ];
+ else { // If "r" isn't a leaf
+ nodeDType *desc = r->nextInT;
+ // Call PostDVisit for every child of "r"
+ while( ( desc ) && ( desc->subTreeLevel > r->subTreeLevel ) ) {
+ if( desc->subTreeLevel -1 == r->subTreeLevel ) { // desc is a son of r
+ PostDVisit( desc );
+
+ if( ( desc->enteringTArc )->head == r ) // enteringTArc of desc goes in r
+ modifiedBalance[ i ] -= ( desc->enteringTArc )->flow;
+ else // If enteringTArc of "desc" goes out "r"
+ modifiedBalance[ i ] += ( desc->enteringTArc )->flow;
+ }
+
+ desc = desc->nextInT;
+ }
+
+ if( r != dummyRootD )
+ if( ( r->enteringTArc )->head == r ) // If enteringTArc of "r" goes in "r"
+ ( r->enteringTArc )->flow = modifiedBalance[ i ];
+ else // If enteringTArc of "r" goes out "r"
+ ( r->enteringTArc )->flow = - modifiedBalance[ i ];
+ }
+ #endif
+ }
+
+/*--------------------------------------------------------------------------*/
+
+inline void MCFSimplex::ResetWhenInT2( void )
+{
+ for( nodeDType *n = nodesD ; n != stopNodesD ; n++)
+ n->whenInT2 = 0;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+template<class N, class A>
+inline N* MCFSimplex::Father( N *n , A *a )
+{
+ if( a == NULL )
+ return NULL;
+
+ if( a->tail == n )
+ return( a->head );
+ else
+ return( a->tail );
+ }
+
+/*-------------------------------------------------------------------------*/
+
+inline MCFSimplex::FONumber MCFSimplex::GetFO( void )
+{
+ FONumber fo = 0;
+ if( usePrimalSimplex ) {
+ arcPType *arco;
+ for( arco = arcsP ; arco != stopArcsP ; arco++ ) {
+ #if( QUADRATICCOST )
+ if( ! ETZ( arco->flow , EpsFlw ) )
+ fo += arco->flow * ( arco->cost + arco->flow * arco->quadraticCost / 2 );
+ #else
+ if( ( arco->ident == BASIC ) || ( arco->ident == AT_UPPER ) )
+ fo += arco->cost * arco->flow;
+ #endif
+ }
+
+ for( arco = dummyArcsP ; arco != stopDummyP ; arco++ ) {
+ #if( QUADRATICCOST )
+ if( ! ETZ( arco->flow , EpsFlw ) )
+ fo += arco->flow * ( arco->cost + arco->flow * arco->quadraticCost / 2 );
+ #else
+ if( ( arco->ident == BASIC ) || ( arco->ident == AT_UPPER ) )
+ fo += arco->cost * arco->flow;
+ #endif
+ }
+ }
+ else {
+ arcDType *a;
+ for( a = arcsD ; a != stopArcsD ; a++ ) {
+ #if (QUADRATICCOST)
+ fo += ( a->cost * a->flow ) + ( a->quadraticCost * a->flow * a->flow ) / 2;
+ #else
+ if( ( a->ident == BASIC ) || (a->ident == AT_UPPER ) )
+ fo += a->cost * a->flow;
+ #endif
+ }
+
+ for( a = dummyArcsD ; a != stopDummyD ; a++) {
+ #if (QUADRATICCOST)
+ fo += ( a->cost * a->flow ) + ( a->quadraticCost * a->flow * a->flow ) / 2;
+ #else
+ if( ( a->ident == BASIC ) || ( a->ident == AT_UPPER ) )
+ fo += a->cost * a->flow;
+ #endif
+ }
+ }
+
+ return( fo );
+ }
+
+/*-------------------------------------------------------------------------*/
+
+void MCFSimplex::PrintPNode( nodePType *nodo )
+{
+ if( nodo )
+ if( nodo != dummyRootP )
+ cout << ( nodo - nodesP + 1 );
+ else
+ cout << "r";
+ else
+ cout << "..";
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::PrintPArc( arcPType *arc )
+{
+ if( arc ) {
+ cout << "(";
+ PrintPNode( arc->tail );
+ cout << ", ";
+ PrintPNode( arc->head );
+ cout << ")";
+ }
+ else
+ cout << "..";
+}
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::PrintDNode( nodeDType *nodo )
+{
+ if( nodo )
+ if( nodo != dummyRootD )
+ cout << ( nodo - nodesD + 1 );
+ else
+ cout << "r";
+ else
+ cout << "..";
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::PrintDArc( arcDType *arc )
+{
+ if( arc ) {
+ cout << "(";
+ PrintDNode( arc->tail );
+ cout << ", ";
+ PrintDNode( arc->head );
+ cout << ")";
+ }
+ else
+ cout << "..";
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::nodePType* MCFSimplex::RecoverPNode( Index ind )
+{
+ if( ( ind < 0 ) || ( ind > n ) )
+ return( NULL );
+ if( ind )
+ return( nodesP + ind - 1 );
+ else
+ return( dummyRootP );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::arcPType* MCFSimplex::RecoverPArc( nodePType *tail ,
+ nodePType *head )
+{
+ if( ( tail == NULL ) || ( head == NULL ) )
+ return( NULL );
+
+ arcPType *arc = arcsP;
+ while( ( arc->tail != tail ) || ( arc->head != head ) ) {
+ arc++;
+ if( arc == stopArcsP )
+ arc = dummyArcsP;
+ if( arc == stopDummyP )
+ return( NULL );
+ }
+
+ return( arc );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::nodeDType* MCFSimplex::RecoverDNode( Index ind )
+{
+ if( ( ind < 0 ) || ( ind > n ) )
+ return( NULL );
+
+ if( ind )
+ return( nodesD + ind - 1 );
+ else
+ return( dummyRootD );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+MCFSimplex::arcDType* MCFSimplex::RecoverDArc( nodeDType *tail ,
+ nodeDType *head )
+{
+ if( ( tail == NULL ) || ( head == NULL ) )
+ return( NULL );
+
+ arcDType *arc = arcsD;
+ while( ( arc->tail != tail ) || ( arc->head != head ) ) {
+ arc++;
+ if( arc == stopArcsD )
+ arc = dummyArcsD;
+ if( arc == stopDummyD )
+ return( NULL );
+ }
+
+ return( arc );
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::infoPNode( nodePType *node , int tab )
+{
+ for( int t = 0 ; t < tab ; t++ )
+ cout << "\t";
+ cout << "Nodo ";
+ PrintPNode( node );
+ cout << ": b = " << node->balance << " y = " << node->potential << endl;
+ #if( UNIPI_VIS_NODE_BASIC_ARC )
+ cout << ": TArc=";
+ PrintPArc( node->enteringTArc );
+ cout << endl;
+ #endif
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::infoPArc( arcPType *arc , int ind , int tab )
+{
+ for( int t = 0 ; t < tab ; t++ )
+ cout << "\t";
+ cout << "Arco ";
+ PrintPArc( arc );
+ cout << ": x = " << arc->flow;
+ #if( UNIPI_VIS_ARC_UPPER )
+ cout << " u = " << arc->upper;
+ #endif
+ #if( UNIPI_VIS_ARC_COST )
+ cout << " c = " << arc->cost;
+ #endif
+ #if( QUADRATICCOST )
+ #if( UNIPI_VIS_ARC_Q_COST )
+ cout << " q = " << arc->quadraticCost;
+ #endif
+ cout << endl;
+ for( int t = 0 ; t < tab ; t++ )
+ cout << "\t";
+ #if( UNIPI_VIS_ARC_REDUCT_COST )
+ cout << " rc = " << MCFGetRC( ind );
+ #endif
+ #else
+ cout << endl;
+ for( int t = 0 ; t < tab ; t++ )
+ cout << "\t";
+ #if( UNIPI_VIS_ARC_REDUCT_COST )
+ cout << " rc = " << MCFGetRC( ind );
+ #endif
+ #if( UNIPI_VIS_ARC_STATE )
+ switch( arc->ident ) {
+ case( BASIC ): cout << " in T"; break;
+ case( AT_LOWER ): cout << " in L"; break;
+ case( AT_UPPER ): cout << " in U"; break;
+ case( DELETED ): cout << " canceled"; break;
+ case( CLOSED ): cout << " closed";
+ }
+ #endif
+ #endif
+ cout << endl;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::infoDNode( nodeDType *node , int tab )
+{
+ for( int t = 0 ; t < tab; t++ )
+ cout << "\t";
+ cout << "Nodo ";
+ PrintDNode( node );
+ cout << ": b = " << node->balance << " y = " << node->potential;
+ #if( UNIPI_VIS_NODE_BASIC_ARC )
+ cout << ": TArc=";
+ PrintDArc( node->enteringTArc );
+ cout << endl;
+ #endif
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::infoDArc( arcDType *arc , int ind , int tab )
+{
+ for( int t = 0 ; t < tab ; t++ )
+ cout << "\t";
+ cout << "Arco ";
+ PrintDArc( arc );
+ cout << " x = " << arc->flow;
+ #if( UNIPI_VIS_ARC_UPPER )
+ cout << " u = " << arc->upper;
+ #endif
+ #if( UNIPI_VIS_ARC_COST )
+ cout << " c = " << arc->cost;
+ #endif
+ #if( QUADRATICCOST )
+ #if( UNIPI_VIS_ARC_Q_COST )
+ cout << " q = " << arc->quadraticCost;
+ #endif
+ cout << endl;
+ for( int t = 0 ; t < tab ; t++ )
+ cout << "\t";
+ #if( UNIPI_VIS_ARC_REDUCT_COST )
+ cout << " rc = " << MCFGetRC( ind );
+ #endif
+ #else
+ cout << endl;
+ for( int t = 0 ; t < tab ; t++ )
+ cout << "\t";
+ #if( UNIPI_VIS_ARC_REDUCT_COST )
+ cout << " rc = " << MCFGetRC( ind );
+ #endif
+ #if (UNIPI_VIS_ARC_STATE)
+ switch( arc->ident ) {
+ case( BASIC ): cout << " in T"; break;
+ case( AT_LOWER ): cout << " in L"; break;
+ case( AT_UPPER ): cout << " in U"; break;
+ case( DELETED ): cout << " canceled"; break;
+ case( CLOSED ): cout << " closed";
+ }
+ #endif
+ #endif
+ cout << endl;
+ }
+
+/*--------------------------------------------------------------------------*/
+
+void MCFSimplex::ShowSituation( int tab )
+{
+ if( usePrimalSimplex ) {
+ arcPType *arc;
+ nodePType *node;
+ int i = 0;
+ for( arc = arcsP ; arc != stopArcsP ; arc++ ) {
+ infoPArc( arc , i , tab );
+ i++;
+ }
+ cout << endl;
+ #if( UNIPI_VIS_DUMMY_ARCS )
+ i = 0;
+ for( arc = dummyArcsP ; arc != stopDummyP ; arc++ ) {
+ infoPArc( arc , i , tab );
+ i++;
+ }
+ cout << endl;
+ #endif
+ infoPNode( dummyRootP , tab );
+ for( node = nodesP ; node != stopNodesP ; node++ )
+ infoPNode( node , tab );
+ }
+ else {
+ arcDType *arc;
+ nodeDType *node;
+ int i = 0;
+ for( arc = arcsD ; arc != stopArcsD ; arc++ ) {
+ infoDArc( arc , i , tab );
+ i++;
+ }
+ cout << endl;
+ #if( UNIPI_VIS_DUMMY_ARCS )
+ i = 0;
+ for( arc = dummyArcsD ; arc != stopDummyD ; arc++) {
+ infoDArc( arc , i , tab );
+ i++;
+ }
+ cout << endl;
+ #endif
+ infoDNode( dummyRootD , tab );
+ for( node = nodesD ; node != stopNodesD ; node++ )
+ infoDNode( node , tab );
+ }
+ }
+
+/*-------------------------------------------------------------------------*/
+/*---------------------- End File MCFSimplex.C ----------------------------*/
+/*-------------------------------------------------------------------------*/