it.ssc.pl.milp.LP Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsr331-ssc Show documentation
Show all versions of jsr331-ssc Show documentation
This is a JSR331 interface for SSC (Software for the Calculation of the Simplex) is a java library for solving linear programming problems v. 3.0.1.
SSC was designed and developed by Stefano Scarioli.
The newest version!
package it.ssc.pl.milp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import it.ssc.context.Context;
import it.ssc.context.Session;
import it.ssc.context.exception.InvalidSessionException;
import it.ssc.datasource.DataSource;
import it.ssc.i18n.RB;
import it.ssc.log.SscLevel;
import it.ssc.log.SscLogger;
import it.ssc.pl.milp.util.A_DataMatrix;
import it.ssc.pl.milp.util.A_Matrix;
import it.ssc.pl.milp.util.LPThreadsNumber;
import it.ssc.ref.Input;
/**
* Questa classe permette di eseguire e risolvere formulazioni di problemi di programmazione
* lineare. Il metodo utilizzato per la risoluzione di tali problemi di ottimizzazione è il
* metodo del simplesso
*
* @author Stefano Scarioli
* @version 3.0
* @see SSC Software www.sscLab.org
*/
public final class LP implements FormatTypeInput {
public static double NaN=Double.NaN;
private static final Logger logger=SscLogger.getLogger();
private SolutionImpl solution_pl;
private int num_max_iteration=10_000_000;
private double[][] A;
private double[] B;
private double[] C;
private Session session;
private final boolean isMilp=false;
private boolean isParallelSimplex=false;
private boolean toCloseSessionInternal=true;
private A_DataMatrix amatrix;
private PersistensePLProblem persistencePl;
private LPThreadsNumber threadsNumber=LPThreadsNumber.N_1;
private boolean isStopPhase2=false;
private EPSILON epsilon=EPSILON._1E_M10;
private EPSILON cepsilon=EPSILON._1E_M8;
{
logger.log(Level.INFO, "##############################################");
logger.log(Level.INFO, RB.getString("it.ssc.context.Session_Impl.msg0"));
logger.log(Level.INFO, "##############################################");
}
/*
* Costruttore di un oggetto LP per la risoluzione di problemi formulati in formato a disequazioni contenute in stringhe.
* In questo formato le variabili devono necessariamente chiamarsi Xj, con l'indice j che parte da 1.
*
* @param inequality Lista dei vincoli di tipo (EQ,GE,LE) sotto forma di disequazioni contenute in stringhe
* @param fo Un oggetto LinearObjectiveFunction che rappresenta la funzione obiettivo
* @throws Exception Viene generata una eccezione se il problema non è formulato correttamente
*/
/*
public LP(ArrayList inequality,LinearObjectiveFunction fo) throws Exception {
if(inequality==null || inequality.isEmpty()) throw new LPException(RB.getString("it.ssc.pl.milp.LP.msg12"));
this.session=Context.createNewSession();
int dimension=fo.getC().length;
ConstraintFromString cfs=new ConstraintFromString(dimension, inequality);
ArrayList new_constraints=cfs.getConstraint();
PLProblem pl_original=CreatePLProblem.create(fo,new_constraints,isMilp);
createStandartProblem(pl_original);
}
*/
/**
*
* @param inequality Un ArrayList (di oggetti String) contenenti la formulazione del problema nel formato
* a disequazioni
* @throws Exception Viene generata una eccezione se il problema non è formulato correttamente
*/
public LP(ArrayList inequality) throws Exception {
if(inequality==null || inequality.isEmpty()) throw new LPException(RB.getString("it.ssc.pl.milp.LP.msg12"));
this.session=Context.createNewSession();
ScanLineFOFromString fo_fromm_string=new ScanLineFOFromString(inequality);
LinearObjectiveFunction fo=fo_fromm_string.getFOFunction();
ArrayList nomi_var=fo_fromm_string.getListNomiVar();
ScanConstraintFromString scan_const=new ScanConstraintFromString(inequality,nomi_var);
ArrayList list_constraints=scan_const.getConstraints();
PLProblem pl_original=CreatePLProblem.create(fo,list_constraints,nomi_var,scan_const.getArraysProb(),isMilp);
createStandartProblem(pl_original);
}
/**
*
* @param path Path dove è localizzato il file contenente il problema di PL formulato con il formato a
* disequazioni
* @throws Exception Viene generata una eccezione se il problema non è formulato correttamente o se il file non esiste
*/
public LP(String path) throws Exception {
BufferedReader br=null;
ScanConstraintFromString scan_const;
ArrayList nomi_var;
LinearObjectiveFunction fo;
this.session=Context.createNewSession();
try {
File file =new File(path);
br = new BufferedReader(new FileReader(file));
ScanLineFOFromString fo_fromm_string=new ScanLineFOFromString(br);
fo=fo_fromm_string.getFOFunction();
nomi_var=fo_fromm_string.getListNomiVar();
scan_const=new ScanConstraintFromString(br,nomi_var);
}
finally {
if (br != null) br.close();
}
ArrayList list_constraints=scan_const.getConstraints();
PLProblem pl_original=CreatePLProblem.create(fo,list_constraints,nomi_var,scan_const.getArraysProb(),isMilp);
createStandartProblem(pl_original);
}
/*
* Costruttore di un oggetto LP per la risoluzione di problemi formulati in formato a disequazioni contenute in stringhe.
* In questo formato le variabili devono necessariamente chiamarsi Xj, con l'indice j che parte da 1. Il terzo parametro
* è la lista dei vincoli che non sono di tipo EQ,LE,GE, ma UPPER e LOWER e vanno rappresentati come oggetti Constraint.
*
* @param inequality Lista dei vincoli di tipo EQ,GE,LE sotto forma di disequazioni contenute in stringhe
* @param constraints Lista dei vincoli di tipo UPPER e LOWER rappresentati come oggetti Constraint
* @param fo Un oggetto LinearObjectiveFunction che rappresenta la funzione obiettivo
* @throws Exception Viene generata una eccezione se il problema non è formulato correttamente
*/
/*
public LP(ArrayList inequality,ArrayList constraints,LinearObjectiveFunction fo) throws Exception {
//qua sarebbe da implementare qualche controllino in piu'.
if(inequality==null || inequality.isEmpty()) throw new LPException(RB.getString("it.ssc.pl.milp.LP.msg12"));
if(constraints==null ) throw new LPException(RB.getString("it.ssc.pl.milp.LP.msg13"));
this.session=Context.createNewSession();
int dimension=fo.getC().length;
ConstraintFromString cfs=new ConstraintFromString(dimension, inequality,constraints);
ArrayList new_constraints=cfs.getConstraint();
PLProblem pl_original=CreatePLProblem.create(fo,new_constraints,isMilp);
createStandartProblem(pl_original);
}
*/
/*
* Costruttore di un oggetto LP per la risoluzione di problemi formulati in formato a disequazioni contenute in stringhe.
* In questo formato le variabili devono necessariamente chiamarsi Xj, con l'indice j che parte da 1. Il terzo parametro
* è la lista dei vincoli che non sono di tipo EQ,LE,GE, ma UPPER e LOWER e vanno rappresentati come oggetti Constraint.
*
* @param inequality
* @param constraints
* @param fo
* @throws Exception
*/
/*
public LP(ArrayList inequality,ListConstraints constraints,LinearObjectiveFunction fo) throws Exception {
//qua sarebbe da implementare qualche controllino in piu'.
if(inequality==null || inequality.isEmpty()) throw new LPException(RB.getString("it.ssc.pl.milp.LP.msg12"));
this.session=Context.createNewSession();
int dimension=fo.getC().length;
ConstraintFromString cfs=new ConstraintFromString(dimension, inequality,constraints.getListConstraint());
ArrayList new_constraints=cfs.getConstraint();
PLProblem pl_original=CreatePLProblem.create(fo,new_constraints,isMilp);
createStandartProblem(pl_original);
}
*/
/**
* Costruttore di un oggetto LP per la risoluzione di problemi espressi in formato matriciale.
*
* @param fo Un oggetto LinearObjectiveFunction che rappresenta la funzione obiettivo
* @param constraints La lista dei vincoli espressa come ArrayList di Oggetti Constraint
* @throws Exception Viene generata una eccezione se il problema non è formulato correttamente
*
*/
public LP(LinearObjectiveFunction fo,ArrayList constraints) throws Exception {
if(constraints==null ) throw new LPException(RB.getString("it.ssc.pl.milp.LP.msg13"));
this.session=Context.createNewSession();
PLProblem pl_original=CreatePLProblem.create(fo,constraints,isMilp);
createStandartProblem(pl_original);
}
/**
* Costruttore di un oggetto LP per la risoluzione di problemi espressi in formato matriciale.
*
* @param fo Un oggetto LinearObjectiveFunction che rappresenta la funzione obiettivo
* @param constraints La lista dei vincoli sotto forma di oggetto ListConstraints
* @throws Exception Viene generata una eccezione se il problema non è formulato correttamente
*
*/
public LP(LinearObjectiveFunction fo,ListConstraints constraints) throws Exception {
this.session=Context.createNewSession();
PLProblem pl_original=CreatePLProblem.create(fo,constraints.getListConstraint(),isMilp);
createStandartProblem(pl_original);
}
/**
* Costruttore di un oggetto LP per la risoluzione di problemi espressi in formato o sparso o a coefficienti.
* @param input Il problema formulato col formato sparso
* @param session Una sessione di lavoro SSC
* @param format Costante per esprimere con quale formato è formulato il problema (FormatType.SPARSE o FormatType.COEFF)
* @throws Exception Viene generata una eccezione se il problema è formulato in modo non corretto
*/
public LP(Input input,Session session, FormatType format) throws Exception {
this.session=session;
this.toCloseSessionInternal=false;
DataSource milp_data_source=session.createDataSource(input);
PLProblem pl_original=null;
if(format==FormatType.SPARSE) pl_original=CreatePLProblem.createFromSparse(milp_data_source,isMilp);
else if(format==FormatType.COEFF) pl_original=CreatePLProblem.create(milp_data_source, isMilp);
createStandartProblem(pl_original);
}
/**
* Costruttore di un oggetto LP per la risoluzione di problemi espressi in formato o sparso o a coefficienti.
* @param input Il problema formulato col formato sparso
* @param format Costante per esprimere con quale formato è formulato il problema (FormatType.SPARSE o FormatType.COEFF)
* @throws Exception Viene generata una eccezione se il problema è formulato in modo non corretto
*/
public LP(Input input,FormatType format) throws Exception {
this(input, Context.createNewSession(),format);
this.toCloseSessionInternal=true;
}
/**
* Costruttore di un oggetto LP per la risoluzione di problemi espressi in formato a coefficienti.
*
* @param input_natural Il problema formulato col formato a coefficienti
* @throws Exception Viene generata una eccezione se il problema è formulato in modo non corretto
*/
public LP(Input input_natural) throws Exception {
this(input_natural, Context.createNewSession());
this.toCloseSessionInternal=true;
//logger.log(Level.INFO,RB.getString("it.ssc.pl.milp.LP.msg1"));
//session.close();
}
/**
* Costruttore di un oggetto LP per la risoluzione di problemi espressi in formato a coefficienti.
*
* @param input_natural Il problema formulato col formato a coefficienti
* @param session Una sessione di lavoro SSC
* @throws Exception Viene generata una eccezione se il problema è formulato in modo non corretto
*/
public LP(Input input_natural,Session session) throws Exception {
this.session=session;
this.toCloseSessionInternal=false;
DataSource milp_data_source=session.createDataSource(input_natural);
PLProblem pl_original=CreatePLProblem.create(milp_data_source, isMilp);
createStandartProblem(pl_original);
}
/**
* Questo metodo permette di settare il valore epsilon relativo alla tolleranza che interviene in diversi ambiti. È
* utilizzato nei seguenti casi :
*
* 1) Durante la fase uno, sia nella determinazione delle variabile entrante che in quella della variabile uscente con o senza regola di Bland;
* sia per determinare se la base è degenere. Viene anche utilizzata alla fine della fase uno : se esiste una variabile ausiliaria in base,
* epsilon viene utilizzato per determinare se è possibile eliminare le righe e le colonne di queste sulla tabella estesa.
* 2) Durante la fase due , sia nella determinazione delle variabile entrante che in quella della variabile uscente con o senza regola di BLand;
* sia per determinare se la base è degenere.
*
* @param epsilon Tolleranza utilizzata in diverse fasi del simplesso. Valore default 1-E10
*/
public void setEpsilon(EPSILON epsilon) {
this.epsilon=epsilon;
}
/**
* Questo metodo permette di settare il valore epsilon relativo alla tolleranza nel
* determinare se una soluzione ottima espressa dalla fase 1 è prossima o uguale a zero e quindi da origine a
* soluzioni ammissibili per il problema iniziale.
*
* @param epsilon Tolleranza soluzione fase 1 rispetto allo zero. Valore default 1-E8
*/
public void setCEpsilon(EPSILON epsilon) {
this.cepsilon=epsilon;
}
/**
* Questo metodo permette di limitare il numero massimo di iterazioni del simplesso (iterazioni fase 1 + iterazioni fase 2)
*
* @param num_max_iteration Il numero di iterazioni che al massimo si vuole far eseguire.
* Valore di default 10,000,000.
* @throws LPException Se si imposta un numero errato (zero o negativo)
*/
public void setNumMaxIteration(int num_max_iteration) throws LPException {
if(num_max_iteration <= 0) throw new LPException("Il numero massimo di iterazioni deve essere un numero positivo");
this.num_max_iteration=num_max_iteration;
}
/**
* Questo metodo ritorna il numero massimo di iterazioni del simplesso
*
* @return Il numero massimo i iterazioni
*/
public int getNumMaxIteration() {
return this.num_max_iteration;
}
private void createStandartProblem(PLProblem pl_original) throws InvalidSessionException, Exception {
String path_work=session.getFactoryLibraries().getLibraryWork().getAbsolutePath();
persistencePl=new PersistensePLProblem(pl_original,path_work);
pl_original.standardize();
B=pl_original.getVectorB();
C=pl_original.getVectorC();
//ho messo la creazione della matrice per ultima per svuotare gli internal constraint
A=pl_original.getMatrixA();
amatrix=new A_DataMatrix(A,path_work);
/*
//printTableAm(Amatrix);
System.out.println("--------A");
printTableA(A);
System.out.println("--------B");
printTableV(B);
System.out.println("--------C");
printTableV(C);
*
*/
}
/**
* Esegue il simplesso (fase 1 + fase 2).
*
* @return Il tipo di soluzione trovata
* @throws Exception Se il processo di esecuzione genera un errore
*/
public SolutionType resolve() throws Exception {
logger.log(SscLevel.INFO,RB.format("it.ssc.pl.milp.LP.msg11")+threadsNumber.getThread());
logger.log(Level.INFO, "---------------------------------------------");
SimplexInterface simplex =new Simplex(A, B, C,epsilon,cepsilon);
simplex.setNumIterationMax(num_max_iteration);
simplex.setThreadsNumber(threadsNumber) ;
long start_simplex=System.currentTimeMillis();
SolutionType type_solution=simplex.runPhaseOne();
long end_phase_one=System.currentTimeMillis();
long end_phase_two=end_phase_one;
logger.log(SscLevel.TIME,RB.format("it.ssc.pl.milp.LP.msg2", RB.getHhMmSsMmm((end_phase_one-start_simplex))));
logger.log(SscLevel.INFO,RB.getString("it.ssc.pl.milp.LP.msg3")+simplex.getNumIterationPhaseOne());
if(isStopPhase2 && type_solution==SolutionType.OPTIMUM) {
type_solution=SolutionType.FEASIBLE;
PLProblem pl_original=persistencePl.readObject();
this.solution_pl=new SolutionImpl(type_solution,
pl_original, //PRIMA PASSAVO UN CLONE ??? tolto .clone()
simplex.getFinalBasis(),
simplex.getFinalValuesBasis()
);
}
else if(type_solution==SolutionType.OPTIMUM) {
type_solution =simplex.runPhaseTwo();
end_phase_two=System.currentTimeMillis();
logger.log(SscLevel.TIME,RB.format("it.ssc.pl.milp.LP.msg4",RB.getHhMmSsMmm(end_phase_two-end_phase_one)));
logger.log(SscLevel.INFO,RB.getString("it.ssc.pl.milp.LP.msg5")+simplex.getNumIterationPhaseTotal());
PLProblem pl_original=persistencePl.readObject();
this.solution_pl=new SolutionImpl(type_solution,
pl_original, //PRIMA PASSAVO UN CLONE ??? tolto .clone()
simplex.getFinalBasis(),
simplex.getFinalValuesBasis()
);
}
logger.log(SscLevel.TIME,RB.format("it.ssc.pl.milp.LP.msg6",RB.getHhMmSsMmm(end_phase_two-start_simplex)));
if(type_solution==SolutionType.FEASIBLE || type_solution==SolutionType.OPTIMUM) {
loggerAccurancy( amatrix, B, simplex.getFinalBasis(),simplex.getFinalValuesBasis(),isStopPhase2);
}
closeAfterResolve() ;
return type_solution;
}
/**
* Questo metodo ritorna la matrice A ottenuta in seguito al processo di riduzione in
* forma standart (max z , Ax + s=b, x ≥ 0, b ≥ 0) del problema di programmazione lineare di partenza.
*
* @return La matrice dei coefficienti A
* @throws SimplexException
* @throws IOException se il problema non è stato ridotto in forma standart
*/
public double[][] getStandartMatrixA() throws SimplexException, IOException {
if(amatrix==null) throw new SimplexException(RB.getString("it.ssc.pl.milp.LP.msg9"));
return amatrix.getMatrix();
}
/**
* Questo metodo ritorna il vettore b dei valori rhs ottenuto in seguito al processo di riduzione in
* forma standart (max z , Ax+s=b, x ≥ 0, b ≥ 0) del problema di programmazione lineare di partenza.
*
* @return Il vettore dei coefficienti RHS
*/
public double[] getStandartVectorB() {
return B.clone();
}
/**
* Questo metodo ritorna il vettore c dei coefficienti della f.o. in seguito al processo di riduzione
* in forma standart (max z , Ax+s=b, x ≥ 0, b ≥ 0) del problema di programmazione lineare di partenza.
*
* @return Il vettore c dei coefficienti della f.o.
*/
public double[] getStandartVectorC() {
return C.clone();
}
/**
* Se il problema ammette soluzione ottima , questo metodo ritorna tale soluzione ottima sotto forma di oggetto della
* classe Solution
* @return La soluzione ottima del problema
* @throws SimplexException Se la soluzione ottima non è presente
*/
public Solution getSolution() throws SimplexException {
if(this.solution_pl==null) throw new SimplexException(RB.getString("it.ssc.pl.milp.LP.msg10"));
return this.solution_pl;
}
/**
*
* @return vero se la parallelizzazione del simplesso è attiva.
*/
public boolean isParallelSimplex() {
return isParallelSimplex;
}
/**
* Se il numero di core fisici dell'host su cui viene eseguito SSc è maggiore di 4 , può essere
* migliorata la performance del simplesso facendo eseguire i processi di ottimizzazione in parallelo su pi ù
* thread.
*
* @param isParallelSimplex True per attivare la parallelizzazione
*/
public void setParallelSimplex(boolean isParallelSimplex) {
this.isParallelSimplex = isParallelSimplex;
if(isParallelSimplex==true) threadsNumber=LPThreadsNumber.AUTO;
}
/**
*
* @return il numero di Thread utilizzati nell'esecuzione. Se il valore è AUTO è il sistema a
* decidere il numero di
* Thread da utilizzare.
*/
public LPThreadsNumber getThreadsNumber() {
return threadsNumber;
}
/**
*
* @param threadsNumber Imposta il numero di Thread da utilizzare nell'esecuzione.
* Se il valore impostato è AUTO è il sistema a decidere il numero di
* Thread da utilizzare.
*/
public void setThreadsNumber(LPThreadsNumber threadsNumber) {
isParallelSimplex=true;
this.threadsNumber = threadsNumber;
}
/**
* Restituisce true se se è impostato l'esecuzione della sola fase 1.
* @return
*/
public boolean isJustTakeFeasibleSolution() {
return isStopPhase2;
}
/**
* Impostando a true permette di interrompere il simplesso alla fine della fase 1, in modo da determinare
* non una soluzione ottima ma solamente una soluzione ammissibile del problema.
* @param isStopPhase2 true per interrompere il simplesso prima della fase 2.
*/
public void setJustTakeFeasibleSolution(boolean isStopPhase2) {
this.isStopPhase2 = isStopPhase2;
}
private void loggerAccurancy(A_DataMatrix matrix, double[] B,int basis[],double values[],boolean solo_ammissibile) throws IOException {
double sum_b=0;
double best_error=0;
double[] array;
int nCols=matrix.getnCol();
double array_solutions[]=getArraySolution(nCols, basis,values);
for(int i=0;i