Skip to content

Commit

Permalink
Merge branch 'release/1.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgodard committed Mar 18, 2017
2 parents f343d47 + da1e635 commit f1ce306
Show file tree
Hide file tree
Showing 7 changed files with 971 additions and 11 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ To get up to speed, the easiest way to start with this library is to study the e
* src/examples/mp: examples of optimization models based on mathematical programming
* src/examples/cp: examples of optimization models based on constraint programming

This library has been tested using IBM ILOG CPLEX 12.6.1, 12.6.2, 12.6.3, 12.7.0, Scala 2.11.8 and Java JDK 1.8.0_121.
This library has been tested using IBM ILOG CPLEX 12.6.3 and 12.7.0, Scala 2.11.8 and Java JDK 1.8.0_121. If you want
to play with this library and do not have a license of CPLEX, you can download
[IBM ILOG CPLEX Optimization Studio Community Edition](https://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition/)

To build the library install gradle 2.10 and set the environment variable `CPLEX_STUDIO_HOME` (e.g.
on windows `C:\IBM\ILOG\CPLEX_Studio1263`).
on windows `C:\IBM\ILOG\CPLEX_Studio127`).

Then do:

Expand Down
36 changes: 36 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## cplex-scala v1.2.0

### Constraint Programming

* Add state function
* and constraints `alwaysIn`, `alwaysEqual`, `alwaysConstant` and `alwaysNoState` on state functions
* Add example `SchedState.scala`
* Add missing precedence constraints in companion object of CpModel
* Add constraints `alwaysEqual` on cumul functions
* Add integer division on integer expression
* Add a link to IBM ILOG CPLEX Studio Community Edition download page in the README

## cplex-scala v1.1.0

### README

* Use syntax highlighting for scala code blocks
* Update README: specify version of Java JDK used for testing

### Constraint Programming

* Add constraint forbidStart, forbidEnd, forbidExtent
* Replace type NumToNumStepFunction with a class, define operators (+=, -=, *=, +, -...) and a proper toString method that prints the step function in a human readable format.
* Add example SchedCalendar.

## cplex-scala v1.0.1

### README

* Update math equation
* Add support to IBM ILOG CPLEX 12.7.
* Update build.gradle to optionally configure maven repository.

## cplex-scala v1.0.0

Initial release of the scala library for IBM ILOG CPLEX.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group 'com.decisionbrain'
version '1.1.0'
version '1.2.0'

apply plugin: 'java'
apply plugin: 'scala'
Expand Down
179 changes: 179 additions & 0 deletions src/examples/scala/com/decisionbrain/cplex/cp/SchedState.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* Source file provided under Apache License, Version 2.0, January 2004,
* http://www.apache.org/licenses/
* (c) Copyright DecisionBrain SAS 2016,2017
*/

package com.decisionbrain.cplex.cp

import com.decisionbrain.cplex.cp.CpModel._
import ilog.cp.IloCP

/**
* This is a problem of building five houses. The masonry, roofing, painting, etc. must be scheduled. Some tasks must
* necessarily take place before others and these requirements are expressed through precedence constraints.
*
* A pool of two workers is available for building the houses. For a given house, some tasks (namely: plumbing,
* ceiling and painting) require the house to be clean whereas other tasks (namely: masonry, carpentry, roofing and
* windows) put the house in a dirty state. A transition time of 1 is needed to clean the house so to change from
* state 'dirty' to state 'clean'.
*
* The objective is to minimize the makespan.
*/
object SchedState {

val nbWorkers = 2
val nbTasks = 10

val tasks = List(
("masonry", 35), // pair of task name and duration
("carpentry", 15),
("plumbing", 40),
("ceiling", 15),
("roofing", 5),
("painting", 10),
("windows", 5),
("facade", 10),
("garden", 5),
("moving", 5)
)

val clean: Int = 0
val dirty: Int = 1

implicit var model: CpModel = _

var allTaskVars: Vector[IntervalVar] = _
var endVars: List[IntExpr] = _

var workersUsage: CumulFunctionExpr = _
var houseStates: List[StateFunction] = _

def makeHouse(id: Int, releaseDate: Int): (IntExpr, IntervalVarArray, StateFunction) = {

val taskVars: Map[String, IntervalVar] = (for (task <- tasks; (tname, tduration) = task)
yield (tname , model.intervalVar(sizeMin = tduration, sizeMax = tduration, name = "H" + id + "-" + tname)))(collection.breakOut)

workersUsage += sum(for (e <- taskVars; (name, v) = e) yield pulse(v, 1))

taskVars("masonry").setStartMin(releaseDate)

// precedence constraints
model.add(taskVars("masonry") < taskVars("carpentry"))
model.add(taskVars("masonry") < taskVars("plumbing"))
model.add(taskVars("masonry") < taskVars("ceiling"))
model.add(taskVars("carpentry") < taskVars("roofing"))
model.add(taskVars("ceiling") < taskVars("painting"))
model.add(taskVars("roofing") < taskVars("windows"))
model.add(taskVars("roofing") < taskVars("facade"))
model.add(taskVars("plumbing") < taskVars("facade"))
model.add(taskVars("roofing") < taskVars("garden"))
model.add(taskVars("plumbing") < taskVars("garden"))
model.add(taskVars("windows") < taskVars("moving"))
model.add(taskVars("facade") < taskVars("moving"))
model.add(taskVars("garden") < taskVars("moving"))
model.add(taskVars("painting") < taskVars("moving"))

// state constraints
val ttime = model.transitionDistance(2)
ttime.setValue(dirty, clean, 1)
val houseState = model.stateFunction(ttime)

model.add(alwaysEqual(houseState, taskVars("masonry"), dirty))
model.add(alwaysEqual(houseState, taskVars("carpentry"), dirty))
model.add(alwaysEqual(houseState, taskVars("plumbing"), clean))
model.add(alwaysEqual(houseState, taskVars("ceiling"), clean))
model.add(alwaysEqual(houseState, taskVars("roofing"), dirty))
model.add(alwaysEqual(houseState, taskVars("painting"), clean))
model.add(alwaysEqual(houseState, taskVars("windows"), dirty))

(model.endOf(taskVars("moving")), taskVars.values, houseState)
}

def build(): CpModel = {

model = CpModel("SchedCumul")

workersUsage = model.cumulFunctionExpr()

val results = List(
makeHouse(0, 31),
makeHouse(1, 0),
makeHouse(2, 90),
makeHouse(3, 120),
makeHouse(4, 90))

model.add(workersUsage <= nbWorkers)

endVars = results.map(_._1)
allTaskVars = results.flatMap(_._2).toVector
houseStates = results.map(_._3)

model.add(minimize(max(endVars)))

model
}

def solve(): Boolean = {

println(s"Solving model $model....")

// model.exportModel("SchedState.cpo")

model.cp.setParameter(IloCP.IntParam.FailLimit, 10000)

// val status = model.solve(timeLimit=20, logPeriod=3000)
val status = model.solve()

if (status) {
println(s"Solution status: $status")
println("Solution with objective " + model.getObjectiveValue())
println("Tasks:")
for (t <- allTaskVars) {
println(model.getDomain(t))
}
println("Workers Usage:")
for (s <- 0 until model.getNumberOfSegments(workersUsage)) {
System.out.println(
"# Workers is " + model.getSegmentValue(workersUsage, s) +
" in [" + model.getSegmentStart(workersUsage, s) +
" .. " + model.getSegmentEnd(workersUsage, s) +
")"
)
}
println("House States:")
for (h <- houseStates.indices) {
val houseState = houseStates(h)
for (i <- 0 until model.getNumberOfSegments(houseState)) {
print("House " + h + " has state ")
val s = model.getSegmentValue(houseState, i)
if (s == clean) print("Clean")
else if (s == dirty) print("Dirty")
else if (s == IloCP.NoState) print("None")
else print("Unknown (problem)")
print(" from ")
if (model.getSegmentStart(houseState, i) == IloCP.IntervalMin) print("Min")
else print(model.getSegmentStart(houseState, i))
System.out.print(" to ")
if (model.getSegmentEnd(houseState, i) == IloCP.IntervalMax) println("Max")
else println(model.getSegmentEnd(houseState, i) - 1)
}
}

}

true
}

def run(): Boolean = {
val model = build()
val status = solve()
model.end()
status
}

def main(args: Array[String]): Unit = {
run()
}

}
Loading

0 comments on commit f1ce306

Please sign in to comment.