Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin
{
Wiki Markup
Composition Setup
Section
Column
width300px
Page Tree
rootTutorial
} {composition-setup} {section} {column:width=300px} {pagetree:root=Tutorial} {column} {column} h1. Problem Formulation First, we will add the following fields to the class so we can easily reference our problem data from any method. Add {code}
Column

Problem Formulation

First, we will add the following fields to the class so we can easily reference our problem data from any method. Add

Code Block

private EnumSet<Option> options;
private IloCplex cplex;
private TspInstance<V,E> tspInstance;
private ImmutableBiMap<E,IloIntVar> edgeVariables;
{code}

and

initialize

them,

as

below.

{code}

Code Block

	public TspIpSolver(TspInstance<V,E> tspInstance, EnumSet<Option> options) throws IloException{
		this.options = options;
		this.tspInstance = tspInstance;
		this.cplex = new IloCplex();
		UndirectedGraph<V,E> graph = tspInstance.getGraph(); //for convenience, we will be using this a lot
		this.edgeVariables = Util.makeBinaryVariables(cplex, graph.getEdges());
		//the degree constraints
		//the objective		
	}
{code}

Next,

we

need

to

add

the

objective

and

the

degree

constraints

to

the

{{

IloCplex

}}

instance.

Try

adding

them

yourself!

The

following

methods

(as

defined

in

[

Solver

Specification

]

and

[

Java

Style

for

CPLEX

]

)

should

be

useful

for

making

the

degree

constraints:

* From {{Util}}, the static method {{

  • From Util, the static method integerSum(IloCplex
  • cplex,
  • BiMap<T,IloIntVar>
  • variables,
  • Iterable<T>
  • set)
}} * From {{IloCplex}}, the method {{
  • From IloCplex, the method addEq(IloNumExpr
  • e,
  • double
  • v)
}} * From {{
  • From UndirectedGraph<V,E>
}}
  • ,
  • the
  • method
{{
  • getIncidentEdges(V
  • vertex)
}} {

Toggle Cloak

:

id

=

ConstraintsSolution

} _Solution_ {cloak:id=ConstraintsSolution|visible=false} {code} //the degree constraints for(V vertex: graph.getVertices()){ cplex.addEq(Util.integerSum(cplex, edgeVariables, graph.getIncidentEdges(vertex)), 2); } {code} {cloak} For the objective, we need the functions: * From {{Util}}, the static method {{sum(IloCplex cplex, BiMap<T,IloIntVar> variables, Iterable<T> set, Function<? super T,? extends Number> coefficients)}} * From {{UndirectedGraph<V,E>}}, the method {{getEdges()}} * From {{TspInstance}}, the method {{getEdgeWeights()}} {toggle-cloak:id=ObjectiveSolution} _Solution_ {cloak:id=ObjectiveSolution|visible=false} {code} //the objective cplex.addMinimize(Util.integerSum( cplex, edgeVariables, graph.getEdges(),tspInstance.getEdgeWeights())); {code} {cloak} h1. Solving and Extracting the Solution Here we fill in the blank methods {{solve()}}, {{getEdgesInOpt()}}, and {{getOptVal()}}. For performance reasons, it is a good idea to cache the solution as a field of the TspIpSolver and "shut down" CPLEX. Recall [the warning|Java and CPLEX#Performance Issues Reading Variable Values from CPLEX] that calling {{getValue(IloIntVar var)}} from {{IloCplex}} repeatedly instead of a single {{getValues(IloIntVar[] vars)}} causes performance issues. Although it isn't really good "Java style," as discussed in [Java Style for CPLEX], we will keep a copy of the edge variables stored in an array as a field of the class to improve performance. To accomplish this, first add the fields {anchor:edgeVariablesAsArray} {code}

Solution

Cloak
visiblefalse
idConstraintsSolution

For the objective, we need the functions:

  • From Util, the static method sum(IloCplex cplex, BiMap<T,IloIntVar> variables, Iterable<T> set, Function<? super T,? extends Number> coefficients)
  • From UndirectedGraph<V,E>, the method getEdges()
  • From TspInstance, the method getEdgeWeights()

Toggle Cloak
idObjectiveSolution
Solution

Cloak
visiblefalse
idObjectiveSolution

Solving and Extracting the Solution

Here we fill in the blank methods solve(), getEdgesInOpt(), and getOptVal(). For performance reasons, it is a good idea to cache the solution as a field of the TspIpSolver and "shut down" CPLEX. Recall the warning that calling getValue(IloIntVar var) from IloCplex repeatedly instead of a single getValues(IloIntVar[] vars) causes performance issues. Although it isn't really good "Java style," as discussed in Java Style for CPLEX, we will keep a copy of the edge variables stored in an array as a field of the class to improve performance.

To accomplish this, first add the fields

Anchor
edgeVariablesAsArray
edgeVariablesAsArray

Code Block

	private ImmutableSet<E> edgesInOpt;
	private double optVal;
	private IloIntVar[] edgeVariablesAsArray;
{code}

Next,

we

will

set

the

field

{{

edgeVariablesAsArray

}}

by

adding

the

one-liner

to

the

constructor:

{

Code Block
}

		...
		this.edgeVariables = Util.makeBinaryVariables(cplex, graph.getEdges());
		edgeVariablesAsArray = edgeVariables.inverse().keySet().toArray(new IloIntVar[]{});//insert this line
		//the degree constraints
		...
{code}

We

will

fill

in

the

remaining

fields

during

{{

solve()

}}

.

But

first,

we

add

an

auxiliary

method

to

encapsulate

access

to

{{

edgeVariablesAsArray

}}

,

reducing

the

chance

of

error

down

the

road.

In

designing

this

method,

we

must

remember

our

previous

discussion

of

[

numerical

tolerances

|Java and Cplex#Reading Integer Variable Values from CPLEX]. {code}

.

Code Block

	/**
	 * assumes  edgeVarVals[i] in {0,1}, up to some tolerance.  
	 * @param edgeVarVals
	 * @return the edges where the variable takes the value one.
	 */
	private Set<E> edgesUsed(double[] edgeVarVals){
		Set<E> ans = new HashSet<E>();
		for(int e = 0; e < edgeVarVals.length; e++){
	        if(Util.doubleToBoolean(edgeVarVals[e])){
	        	ans.add(edgeVariables.inverse().get(edgeVariablesAsArray[e]));
	        }
	    }
		return ans;
	}

	public void solve() throws IloException{
		if(!cplex.solve()){
			throw new RuntimeException();
		}
		optVal = cplex.getObjValue();
		edgesInOpt = ImmutableSet.copyOf(edgesUsed(cplex.getValues(edgeVariablesAsArray)));
		cplex.end();
	}
	
	public ImmutableSet<E> getEdgesInOpt(){
		return edgesInOpt;
	}
	
	public double getOptVal(){
		return optVal;
	}
{code}

The

method

{{

edgesUsed()

}}

make

look

a

little

odd

right

now,

but

its

value

will

become

apparent

in

the

next

section.

h1.

Test

Your

Code

Now

is

a

good

time

to

test

the

code

you

have

written

thus

far.

Keep

in

mind

that

we

haven't

implemented

the

_

cutset

_

constraints

yet.

A

unit

test

{{

testDegreeConstraints()

}}

was

made

exactly

for

this

purpose,

in

_

tspSolver/test/solver/TspSolverTest.java

_

.

Run

the

class

as

a

JUnit

test

(right

click

on

the

class

in

the

_

Project

Explorer

_

and

select

_

Run

As

JUnit

Test

_

.

If

you

are

not

on

Windows,

again

you

likely

will

need

to

set

a

VM

argument

[

as

previously

discussed

|Test Your Java, Eclipse and Cplex Installations]

.

The

test

{{

testDegreeConstraints()

}}

should

now

pass.

If

you

need

to

debug,

the

unit

test

is

on

the

following

graph:

{gliffy:name=tspDegreeConstraints|align=left|size=L|version=1} {column} {section}

Gliffy Diagram
sizeL
nametspDegreeConstraints