Skip to content

Commit

Permalink
feature: impl demos.
Browse files Browse the repository at this point in the history
  • Loading branch information
fuookami committed Sep 30, 2024
1 parent 756deb6 commit 59a3e8b
Show file tree
Hide file tree
Showing 10 changed files with 624 additions and 12 deletions.
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
}
}
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
}
}
Loading

0 comments on commit 59a3e8b

Please sign in to comment.