-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
624 additions
and
12 deletions.
There are no files selected for viewing
189 changes: 189 additions & 0 deletions
189
examples/ospf-kotlin-example/src/main/fuookami/ospf/kotlin/example/core_demo/Demo10.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package fuookami.ospf.kotlin.example.core_demo | ||
|
||
import fuookami.ospf.kotlin.utils.math.* | ||
import fuookami.ospf.kotlin.utils.math.value_range.* | ||
import fuookami.ospf.kotlin.utils.concept.* | ||
import fuookami.ospf.kotlin.utils.functional.* | ||
import fuookami.ospf.kotlin.utils.multi_array.* | ||
import fuookami.ospf.kotlin.core.frontend.variable.* | ||
import fuookami.ospf.kotlin.core.frontend.expression.monomial.* | ||
import fuookami.ospf.kotlin.core.frontend.expression.polynomial.* | ||
import fuookami.ospf.kotlin.core.frontend.expression.symbol.* | ||
import fuookami.ospf.kotlin.core.frontend.inequality.* | ||
import fuookami.ospf.kotlin.core.frontend.model.mechanism.* | ||
import fuookami.ospf.kotlin.core.backend.plugins.scip.* | ||
|
||
data object Demo10 { | ||
data class City( | ||
val name: String | ||
) : AutoIndexed(City::class) | ||
|
||
val beginCity = "北京" | ||
|
||
val cities = listOf( | ||
City("上海"), | ||
City("合肥"), | ||
City("广州"), | ||
City("成都"), | ||
City("北京") | ||
) | ||
|
||
val distances = mapOf( | ||
Pair(cities[0], cities[1]) to Flt64(472.0), | ||
Pair(cities[0], cities[2]) to Flt64(1520.0), | ||
Pair(cities[0], cities[3]) to Flt64(2095.0), | ||
Pair(cities[0], cities[4]) to Flt64(1244.0), | ||
|
||
Pair(cities[1], cities[0]) to Flt64(472.0), | ||
Pair(cities[1], cities[2]) to Flt64(1257.0), | ||
Pair(cities[1], cities[3]) to Flt64(1615.0), | ||
Pair(cities[1], cities[4]) to Flt64(1044.0), | ||
|
||
Pair(cities[2], cities[0]) to Flt64(1529.0), | ||
Pair(cities[2], cities[1]) to Flt64(1257.0), | ||
Pair(cities[2], cities[3]) to Flt64(1954.0), | ||
Pair(cities[2], cities[4]) to Flt64(2174.0), | ||
|
||
Pair(cities[3], cities[0]) to Flt64(2095.0), | ||
Pair(cities[3], cities[1]) to Flt64(1615.0), | ||
Pair(cities[3], cities[2]) to Flt64(1954.0), | ||
Pair(cities[3], cities[4]) to Flt64(1854.0), | ||
|
||
Pair(cities[4], cities[0]) to Flt64(1244.0), | ||
Pair(cities[4], cities[1]) to Flt64(1044.0), | ||
Pair(cities[4], cities[2]) to Flt64(2174.0), | ||
Pair(cities[4], cities[3]) to Flt64(1854.0) | ||
) | ||
|
||
lateinit var x: BinVariable2 | ||
lateinit var u: IntVariable1 | ||
|
||
lateinit var distance: LinearSymbol | ||
lateinit var depart: LinearSymbols1 | ||
lateinit var reached: LinearSymbols1 | ||
|
||
private val metaModel: LinearMetaModel = LinearMetaModel("demo10") | ||
|
||
private val subProcesses = listOf( | ||
Demo10::initVariable, | ||
Demo10::initSymbol, | ||
Demo10::initObject, | ||
Demo10::initConstraint, | ||
Demo10::solve, | ||
Demo10::analyzeSolution | ||
) | ||
|
||
suspend operator fun invoke(): Try { | ||
for (process in subProcesses) { | ||
when (val result = process()) { | ||
is Ok -> {} | ||
|
||
is Failed -> { | ||
return Failed(result.error) | ||
} | ||
} | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun initVariable(): Try { | ||
x = BinVariable2("x", Shape2(cities.size, cities.size)) | ||
for (city1 in cities) { | ||
for (city2 in cities) { | ||
val xi = x[city1, city2] | ||
xi.name = "${x.name}_(${city1.name},${city2.name})" | ||
if (city1 != city2) { | ||
metaModel.add(xi) | ||
} else { | ||
xi.range.eq(UInt8.zero) | ||
} | ||
} | ||
} | ||
u = IntVariable1("u", Shape1(cities.size)) | ||
for (city in cities) { | ||
val ui = u[city] | ||
ui.name = "${u.name}_${city.name}" | ||
if (city.name != beginCity) { | ||
ui.range.set(ValueRange(Int64(-cities.size.toLong()), Int64(cities.size.toLong())).value!!) | ||
metaModel.add(ui) | ||
} else { | ||
ui.range.eq(Int64.zero) | ||
} | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun initSymbol(): Try { | ||
distance = LinearExpressionSymbol(sum(cities.flatMap { city1 -> | ||
cities.mapNotNull { city2 -> | ||
if (city1 == city2) { | ||
null | ||
} else { | ||
distances[city1 to city2]?.let { it * x[city1, city2] } | ||
} | ||
} | ||
}), "distance") | ||
depart = LinearSymbols1("depart", Shape1(cities.size)) { i, _ -> | ||
val city = cities[i] | ||
LinearExpressionSymbol(sum(x[city, _a]), "depart_${city.name}") | ||
} | ||
reached = LinearSymbols1("reached", Shape1(cities.size)) { i, _ -> | ||
val city = cities[i] | ||
LinearExpressionSymbol(sum(x[_a, city]), "reached_${city.name}") | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun initObject(): Try { | ||
metaModel.minimize(distance, "distance") | ||
return ok | ||
} | ||
|
||
private suspend fun initConstraint(): Try { | ||
for (city in cities) { | ||
metaModel.addConstraint(depart[city] eq Flt64.one, "depart_${city.name}") | ||
} | ||
for (city in cities) { | ||
metaModel.addConstraint(reached[city] eq Flt64.one, "reached_${city.name}") | ||
} | ||
val notBeginCities = cities.filter { it.name != beginCity } | ||
for (city1 in notBeginCities) { | ||
for (city2 in notBeginCities) { | ||
if (city1 != city2) { | ||
metaModel.addConstraint( | ||
u[city1] - u[city2] + cities.size * x[city1, city2] leq cities.size - 1, | ||
"child_route_(${city1.name},${city2.name})" | ||
) | ||
} | ||
} | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun solve(): Try { | ||
val solver = ScipLinearSolver() | ||
when (val ret = solver(metaModel)) { | ||
is Ok -> { | ||
metaModel.tokens.setSolution(ret.value.solution) | ||
} | ||
|
||
is Failed -> { | ||
return Failed(ret.error) | ||
} | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun analyzeSolution(): Try { | ||
val route: MutableMap<City, City> = hashMapOf() | ||
for (token in metaModel.tokens.tokens) { | ||
if (token.result!! eq Flt64.one && token.variable.belongsTo(x)) { | ||
val vector = token.variable.vectorView | ||
val city1 = cities[vector[0]] | ||
val city2 = cities[vector[1]] | ||
route[city1] = city2 | ||
} | ||
} | ||
return ok | ||
} | ||
} |
169 changes: 169 additions & 0 deletions
169
examples/ospf-kotlin-example/src/main/fuookami/ospf/kotlin/example/core_demo/Demo11.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package fuookami.ospf.kotlin.example.core_demo | ||
|
||
import fuookami.ospf.kotlin.utils.math.* | ||
import fuookami.ospf.kotlin.utils.concept.* | ||
import fuookami.ospf.kotlin.utils.functional.* | ||
import fuookami.ospf.kotlin.utils.multi_array.* | ||
import fuookami.ospf.kotlin.core.frontend.variable.* | ||
import fuookami.ospf.kotlin.core.frontend.expression.polynomial.* | ||
import fuookami.ospf.kotlin.core.frontend.expression.symbol.* | ||
import fuookami.ospf.kotlin.core.frontend.inequality.* | ||
import fuookami.ospf.kotlin.core.frontend.model.mechanism.* | ||
import fuookami.ospf.kotlin.core.backend.plugins.scip.* | ||
|
||
data object Demo11 { | ||
sealed class Node : AutoIndexed(Node::class) | ||
class RootNode : Node() | ||
class EndNode : Node() | ||
class NormalNode : Node() | ||
|
||
val nodes: List<Node> = listOf( | ||
listOf(RootNode()), | ||
(1..7).map { NormalNode() }, | ||
listOf(EndNode()) | ||
).flatten() | ||
|
||
val capacities = mapOf( | ||
nodes[0] to mapOf( | ||
nodes[1] to UInt64(15), | ||
nodes[2] to UInt64(10), | ||
nodes[3] to UInt64(40) | ||
), | ||
nodes[1] to mapOf( | ||
nodes[4] to UInt64(15) | ||
), | ||
nodes[2] to mapOf( | ||
nodes[5] to UInt64(10), | ||
nodes[6] to UInt64(35) | ||
), | ||
nodes[3] to mapOf( | ||
nodes[6] to UInt64(30), | ||
nodes[7] to UInt64(20) | ||
), | ||
nodes[4] to mapOf( | ||
nodes[6] to UInt64(10) | ||
), | ||
nodes[5] to mapOf( | ||
nodes[8] to UInt64(10) | ||
), | ||
nodes[6] to mapOf( | ||
nodes[7] to UInt64(10) | ||
), | ||
nodes[7] to mapOf( | ||
nodes[8] to UInt64(45) | ||
) | ||
) | ||
|
||
lateinit var x: UIntVariable2 | ||
lateinit var flow: UIntVar | ||
|
||
lateinit var flowIn: LinearSymbols1 | ||
lateinit var flowOut: LinearSymbols1 | ||
|
||
val metaModel: LinearMetaModel = LinearMetaModel("demo11") | ||
|
||
private val subProcesses = listOf( | ||
Demo11::initVariable, | ||
Demo11::initSymbol, | ||
Demo11::initObject, | ||
Demo11::initConstraint, | ||
Demo11::solve, | ||
Demo11::analyzeSolution | ||
) | ||
|
||
suspend operator fun invoke(): Try { | ||
for (process in subProcesses) { | ||
when (val result = process()) { | ||
is Ok -> {} | ||
|
||
is Failed -> { | ||
return Failed(result.error) | ||
} | ||
} | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun initVariable(): Try { | ||
x = UIntVariable2("x", Shape2(nodes.size, nodes.size)) | ||
for (node1 in nodes) { | ||
for (node2 in nodes) { | ||
if (node1 == node2) { | ||
continue | ||
} | ||
capacities[node1]?.get(node2)?.let { | ||
val xi = x[node1, node2] | ||
xi.range.leq(it) | ||
metaModel.add(xi) | ||
} | ||
} | ||
} | ||
flow = UIntVar("flow") | ||
metaModel.add(flow) | ||
return ok | ||
} | ||
|
||
private suspend fun initSymbol(): Try { | ||
flowIn = LinearSymbols1("flow_in", Shape1(nodes.size)) { i, _ -> | ||
LinearExpressionSymbol(sum(x[_a, i]), "flow_in_$i") | ||
} | ||
metaModel.add(flowIn) | ||
flowOut = LinearSymbols1("flow_out", Shape1(nodes.size)) { i, _ -> | ||
LinearExpressionSymbol(sum(x[i, _a]), "flow_out_$i") | ||
} | ||
metaModel.add(flowOut) | ||
return ok | ||
} | ||
|
||
private suspend fun initObject(): Try { | ||
metaModel.maximize(flow, "flow") | ||
return ok | ||
} | ||
|
||
private suspend fun initConstraint(): Try { | ||
val rootNode = nodes.first { it is RootNode } | ||
metaModel.addConstraint( | ||
flowOut[rootNode] - flowIn[rootNode] eq flow, | ||
"flow_${rootNode.index}" | ||
) | ||
val endNode = nodes.first { it is EndNode } | ||
metaModel.addConstraint( | ||
flowIn[endNode] - flowOut[endNode] eq flow, | ||
"flow_${endNode.index}" | ||
) | ||
for (node in nodes.filterIsInstance<NormalNode>()) { | ||
metaModel.addConstraint( | ||
flowOut[node] eq flowIn[node], | ||
"flow_${node.index}" | ||
) | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun solve(): Try { | ||
val solver = ScipLinearSolver() | ||
when (val ret = solver(metaModel)) { | ||
is Ok -> { | ||
metaModel.tokens.setSolution(ret.value.solution) | ||
} | ||
|
||
is Failed -> { | ||
return Failed(ret.error) | ||
} | ||
} | ||
return ok | ||
} | ||
|
||
private suspend fun analyzeSolution(): Try { | ||
val flow: MutableMap<Node, MutableMap<Node, UInt64>> = hashMapOf() | ||
for (token in metaModel.tokens.tokens) { | ||
if (token.result!! geq Flt64.one && token.variable belongsTo x) { | ||
val vector = token.variable.vectorView | ||
val node1 = nodes[vector[0]] | ||
val node2 = nodes[vector[1]] | ||
flow.getOrPut(node1) { hashMapOf() }[node2] = token.result!!.round().toUInt64() | ||
} | ||
} | ||
return ok | ||
} | ||
} |
Oops, something went wrong.