📄 constraint.java
字号:
package com.power.lpsolver.LPSolve;
/**
*
* <p>Title: PIPE Engine</p>
* <p>Description: Global Planning Optimization Engine</p>
* <p>Copyright: Copyright (c) 2002</p>
* <p>Company: Paraster, Inc.</p>
* @author Wei Tan
* @version 1.0
*/
import java.util.*;
import java.math.*;
/**
* Constraint class defines a linear inequality of an LP model and its related
* computations.
*/
public class Constraint
{
private String _conName;
private int _rowNum;
protected Hashtable _conElements = new Hashtable();
private String _sign;
private double _rhs = 0;
private int _basicVarIdx;
protected MemoryManager _memMgr = MemoryManager.getInstance();
private int _numOfElements = 0;
/**
* Sole class constrsuctor
* @param name String name of the constraint, must be unique.
* @param row Row number of the constraint, must be unique.
*/
public Constraint( String name, int row ) {
_conName = name;
_rowNum = row;
}
/**
* Adds one element to the constraint.
* @param elem the element to be added.
*/
public void addElement( Element elem ) {
/*_conElements.put( elem,
elem );*/
_conElements.put( _memMgr.getIntegerString( elem.getColumnNumber() ),
elem );
_numOfElements++;
}
public int getNumberOfElements() {
return _numOfElements;
}
/**
* Gets the constraint (row) name.
* @return the string name of the constraint.
*/
public String getName() {
return _conName;
}
/**
* Sets the symbolic name of the constraint.
* @param name the symbolic name for the consrtaint, replace whatever is
* previously there.
*/
public void setName( String name ) {
_conName = name;
}
/**
* Sets the sign of the constraint.
* @param aSign the sign for the constraint. A sign can only be one of "=",
* "<=", or ">=".
*/
public void setSign( String aSign ) {
_sign = aSign;
}
/**
* Sets sign when input data is from an MPS file.
* @param aSign the sign to be set for the constraint, can only be one of
* "E" (for equal), "L" (for less or equal to), or "G" (for greater
* or equal to).
*/
public void setMPSSign( String aSign ) {
if( aSign.equals( "E" ) ) {
_sign = "=";
} else if( aSign.equals( "L" ) ) {
_sign = "<=";
} else if( aSign.equals( "G" ) ) {
_sign = ">=";
} else {
System.out.println( "Unexpected character" );
}
}
/**
* Gets the row type in MPS format.
* @return the row type, can only be one of
* "E" (for equal), "L" (for less or equal to), or "G" (for greater
* or equal to).
*/
public String getMPSRowType() {
char[] type = new char[4];
type[0] = ' ';
if( _sign.equals( "=" ) ) {
type[1] = 'E';
} else if( _sign.equals( "<=" ) ) {
type[1] = 'L';
} else {
type[1] = 'G';
}
type[2] = ' ';
type[3] = ' ';
return new String( type );
}
/**
* Gets the row name in MPS format, i.e., not longer than 8 characters.
* @return the row name string.
*/
public String getMPSRowName() {
char[] rowName = new char[8];
int length = Math.min( 8, _conName.length() );
for( int i=0; i<length; i++ ) {
rowName[i] = _conName.charAt(i);
}
for( int k=length; k<8; k++ ) {
rowName[k] = ' ';
}
return new String( rowName );
}
/**
* Sets the RHS value.
* @param rhs the new value for the RHS.
*/
public void setRHS( double rhs ) {
_rhs = rhs;
if( Math.abs( _rhs ) <= Model.getInstance().getPrecision() ) {
_rhs = 0.0;
}
}
/**
* Gets the RHS value.
* @return the current RHS value.
*/
public double getRHS() {
return _rhs;
}
public String getSign() {
return _sign;
}
/**
* Gets all elements in the form of a Hashtable.
* @return the Hashtable of elements, use column number as keys.
*/
public Hashtable getElements() {
return _conElements;
}
/**
* Gets the element for the given column number.
* @param colNum the column number of the element to be returned.
* @return the element associated with the given column number.
*/
public Element getElementAt( int colNum ) {
return (Element) _conElements.get( _memMgr.getIntegerString( colNum ) );
}
/**
* Gets an element by a given key value.
* @param key the key (column number) for the element.
* @return the element, null if none exists.
*/
public Element getElement( String key ) {
return (Element) _conElements.get( key );
}
/**
* Adds a constraint to this.
* this = this + multiplier * aCon.
* @param multiplier the multiplier to be used for the incoming constraint.
* @param aCon the constraint to be added to this.
*/
public void plusConstraint( double multiplier, Constraint aCon ) {
//System.out.println( "Multiplier = " + multiplier );
Enumeration inComingCon = aCon.getElements().keys();
while( inComingCon.hasMoreElements() ) {
String key = (String) inComingCon.nextElement();
Element elem = (Element) _conElements.get( key );
if( null == elem ) {
Element newElem = (Element) ( aCon.getElement( key ).clone() );
newElem.applyMultiplier( multiplier );
//if( newElem.getCoefficient() <= Model.getInstance().getPrecision() ) {
//MemoryManager.getInstance().addElement( newElem );
//continue;
//}
this.addElement( newElem );
} else {
Element incomingElem = aCon.getElement( key );
elem.addCoefficient( multiplier, incomingElem );
if( Math.abs( elem.getCoefficient() ) <=
Model.getInstance().getPrecision() ) {
_conElements.remove( _memMgr.getIntegerString( elem.getColumnNumber() ) );
MemoryManager.getInstance().addElement( elem );
}
}
}
this.setRHS( this.getRHS() + multiplier * aCon.getRHS() );
eliminateFloatingError();
//print();
}
/**
* Eliminates floating errors by converting efficients smaller than the
* given (default) precision to zeros.
*/
public void eliminateFloatingError() {
Enumeration allElems = _conElements.elements();
double precision = Model.getInstance().getPrecision();
while( allElems.hasMoreElements() ) {
Element elem = (Element) allElems.nextElement();
if( Math.abs( elem.getCoefficient() ) <= precision ) {
_conElements.remove( _memMgr.getIntegerString( elem.getColumnNumber() ) );
_memMgr.addElement( elem );
}
}
if( Math.abs( _rhs ) <= precision ) {
_rhs = 0;
}
}
/**
* Multiplies both side of the constraint by a constant.
* @param multiplier the constant to be used.
*/
public void applyMultiplier( double multiplier ) {
Enumeration allElems = _conElements.elements();
while( allElems.hasMoreElements() ) {
Element elem = (Element) allElems.nextElement();
elem.applyMultiplier( multiplier );
}
this.setRHS( this.getRHS() * multiplier );
eliminateFloatingError();
//print();
}
/**
* Normalizes the constraint so that the RHS is greater than or equal to zero.
*/
public void normalize() {
if( getRHS() >= 0 ) return;
Enumeration allElems = _conElements.elements();
while( allElems.hasMoreElements() ) {
Element elem = (Element) allElems.nextElement();
elem.applyMultiplier( -1 );
}
setRHS( -1.0 * getRHS() );
if( _sign.equals( "<=" ) ) {
setSign( ">=" );
} else if( _sign.equals( ">=" ) ) {
setSign( "<=" );
}
}
/**
* Initializes the constraint and converts the constraint into the standard
* form: sum(a(i,j)*x(i,j)) = b. It adds slack variable if the original sign
* is less or equal to, surplus variable if greater or equal to, and artificial
* variable if greater or equal to and equal to.
*/
public void initialize() {
//System.out.println( "After initialize" );
normalize();
if( _sign.equals( "<=" ) ) {
addSlackVariable();
//print();
return;
}
if( _sign.equals( ">=" ) ) {
addSurplusVariable();
}
//case ">=" and "="
addArtificialVariable();
//print();
}
/**
* Adds surplus variable to the constraint.
*/
public void addSurplusVariable() {
int colIdx = Model.getInstance().getNumberOfColumns();
this.addElement( new Element( colIdx, -1.0 ) );
Model.getInstance().addVariable( new Variable( "SPLS" + _memMgr.getIntegerString( colIdx ),
colIdx ) );
}
/**
* Adds artificial variable to the constraint.
*/
public void addArtificialVariable() {
Model.getInstance().getPhaseOneObjectiveFunction().setupPhaseOneObjWithConstraint( this );
int colIdx = Model.getInstance().getNumberOfColumns();
Element elem = new Element( colIdx, 1.0 );
this.addElement( elem );
Model.getInstance().addArtVarIndex( colIdx );
Model.getInstance().addVariable( new Variable( "ART" + _memMgr.getIntegerString( colIdx ),
colIdx ) );
Solve.getInstance().addBasicVariable( _memMgr.getInteger( colIdx ) );
setBasicVariableIndex( colIdx );
}
/**
* Adds slack variable to the constraint.
*/
public void addSlackVariable() {
int colIdx = Model.getInstance().getNumberOfColumns();
this.addElement( new Element( colIdx, 1.0 ) );
Model.getInstance().addVariable( new Variable( "SLK" + _memMgr.getIntegerString( colIdx ),
colIdx ) );
Solve.getInstance().addBasicVariable( _memMgr.getInteger( colIdx ) );
setBasicVariableIndex( colIdx );
}
/**
* Sets the basic variable index for the constraint.
* @param idx the basic variable index (column number).
*/
public void setBasicVariableIndex( int idx ) {
_basicVarIdx = idx;
}
/**
* Gets the basic variable index of the constraint.
* @return the basic variable index (column number).
*/
public int getBasicVariableIndex() {
return _basicVarIdx;
}
/**
* Prints the constraint in a readable format (LP format).
*/
public void print() {
System.out.print( "\n" + _conName + ": " );
Enumeration allElems = _conElements.elements();
ModelVariables mdlVars = Model.getInstance().getModelVariables();
while( allElems.hasMoreElements() ) {
Element elem = (Element) allElems.nextElement();
Variable var = mdlVars.getVariable( elem.getColumnNumber() );
if( elem.getCoefficient() > 0 ) {
System.out.print( " + " );
} else {
System.out.print( " - " );
}
System.out.print( Math.abs( elem.getCoefficient() ) );
System.out.print( var.getMPSName() );
}
System.out.print( " " + _sign + " " + _rhs + ";\n" );
}
/**
* Prints the solution of the constraint in the form:
* basic variable symbolic name = value (rhs).
*/
public void printSolution() {
if( _rhs == 0.0 ) return;
if( _basicVarIdx >= Model.getInstance().getTotOriginalVariables() ) return;
Variable basicVar = Model.getInstance().getModelVariables().getVariable( _basicVarIdx );
/*if( basicVar.getVarName().indexOf( "SLK" ) >= 0 ||
basicVar.getVarName().indexOf( "SPLS" ) >= 0 ||
_rhs == 0.0 ) {
return;
}
if( basicVar.getVarName().indexOf( "ART" ) >= 0 ) {
print();
} */
System.out.println( Model.getInstance().getModelVariables().getVariable( _basicVarIdx ).getVarName() +
" " + _rhs );
}
/**
* Drops artificial variables from the constraint before conducting
* Phase II Simplex algorithm.
*/
public void dropArtificialVariables() {
Vector artVarIndice = Model.getInstance().getArtVarIndice();
for( int i=0; i<artVarIndice.size(); i++ ) {
Integer idx = (Integer) artVarIndice.elementAt( i );
_conElements.remove( _memMgr.getIntegerString( idx.intValue() ) );
}
//System.out.println( "After droped art var " );
//print();
}
/**
* Sets up the Phase II objective function by adding this constraint to the
* objective function so that the element in the objective function corresponding
* to the basic variable index of this constraint is eliminated.
*/
public void setupPhaseTwoObjFunc() {
ObjectiveFunction objFunc = Model.getInstance().getObjectiveFunction();
Element elem = objFunc.getElementAt( _basicVarIdx );
if( null == elem ) return;
double coeff = elem.getCoefficient();
objFunc.plusConstraint( - coeff, this );
}
/**
* Gets the variable index (column number) of first element with positive
* coefficient.
* @return the variable index (column number). -1 if none found.
*/
public int getColIdxOfFirstPositiveCoefficient() {
Enumeration allElems = _conElements.elements();
if( _rhs < 0.0 ) {
this.applyMultiplier( -1.0 );
}
while( allElems.hasMoreElements() ) {
Element elem = (Element) allElems.nextElement();
if( Model.getInstance().isArtVarIndex( elem.getColumnNumber() ) ) continue;
if( Solve.getInstance().isBasicVariable( elem.getColumnNumber() ) ) continue;
if( Math.abs( elem.getCoefficient() ) < Model.getInstance().getPrecision() ) {
continue;
}
return elem.getColumnNumber();
}
return -1;
}
/**
* Sets the row number so that this constraint may be referenced by its row
* number.
* @param row the number for the row.
*/
public void setRowNumber( int row ) {
_rowNum = row;
}
public void reset() {
_conElements = null;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -