Skip to content

Commit 59a3e8b

Browse files
committed
feature: impl demos.
1 parent 756deb6 commit 59a3e8b

File tree

10 files changed

+624
-12
lines changed

10 files changed

+624
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
package fuookami.ospf.kotlin.example.core_demo
2+
3+
import fuookami.ospf.kotlin.utils.math.*
4+
import fuookami.ospf.kotlin.utils.math.value_range.*
5+
import fuookami.ospf.kotlin.utils.concept.*
6+
import fuookami.ospf.kotlin.utils.functional.*
7+
import fuookami.ospf.kotlin.utils.multi_array.*
8+
import fuookami.ospf.kotlin.core.frontend.variable.*
9+
import fuookami.ospf.kotlin.core.frontend.expression.monomial.*
10+
import fuookami.ospf.kotlin.core.frontend.expression.polynomial.*
11+
import fuookami.ospf.kotlin.core.frontend.expression.symbol.*
12+
import fuookami.ospf.kotlin.core.frontend.inequality.*
13+
import fuookami.ospf.kotlin.core.frontend.model.mechanism.*
14+
import fuookami.ospf.kotlin.core.backend.plugins.scip.*
15+
16+
data object Demo10 {
17+
data class City(
18+
val name: String
19+
) : AutoIndexed(City::class)
20+
21+
val beginCity = "北京"
22+
23+
val cities = listOf(
24+
City("上海"),
25+
City("合肥"),
26+
City("广州"),
27+
City("成都"),
28+
City("北京")
29+
)
30+
31+
val distances = mapOf(
32+
Pair(cities[0], cities[1]) to Flt64(472.0),
33+
Pair(cities[0], cities[2]) to Flt64(1520.0),
34+
Pair(cities[0], cities[3]) to Flt64(2095.0),
35+
Pair(cities[0], cities[4]) to Flt64(1244.0),
36+
37+
Pair(cities[1], cities[0]) to Flt64(472.0),
38+
Pair(cities[1], cities[2]) to Flt64(1257.0),
39+
Pair(cities[1], cities[3]) to Flt64(1615.0),
40+
Pair(cities[1], cities[4]) to Flt64(1044.0),
41+
42+
Pair(cities[2], cities[0]) to Flt64(1529.0),
43+
Pair(cities[2], cities[1]) to Flt64(1257.0),
44+
Pair(cities[2], cities[3]) to Flt64(1954.0),
45+
Pair(cities[2], cities[4]) to Flt64(2174.0),
46+
47+
Pair(cities[3], cities[0]) to Flt64(2095.0),
48+
Pair(cities[3], cities[1]) to Flt64(1615.0),
49+
Pair(cities[3], cities[2]) to Flt64(1954.0),
50+
Pair(cities[3], cities[4]) to Flt64(1854.0),
51+
52+
Pair(cities[4], cities[0]) to Flt64(1244.0),
53+
Pair(cities[4], cities[1]) to Flt64(1044.0),
54+
Pair(cities[4], cities[2]) to Flt64(2174.0),
55+
Pair(cities[4], cities[3]) to Flt64(1854.0)
56+
)
57+
58+
lateinit var x: BinVariable2
59+
lateinit var u: IntVariable1
60+
61+
lateinit var distance: LinearSymbol
62+
lateinit var depart: LinearSymbols1
63+
lateinit var reached: LinearSymbols1
64+
65+
private val metaModel: LinearMetaModel = LinearMetaModel("demo10")
66+
67+
private val subProcesses = listOf(
68+
Demo10::initVariable,
69+
Demo10::initSymbol,
70+
Demo10::initObject,
71+
Demo10::initConstraint,
72+
Demo10::solve,
73+
Demo10::analyzeSolution
74+
)
75+
76+
suspend operator fun invoke(): Try {
77+
for (process in subProcesses) {
78+
when (val result = process()) {
79+
is Ok -> {}
80+
81+
is Failed -> {
82+
return Failed(result.error)
83+
}
84+
}
85+
}
86+
return ok
87+
}
88+
89+
private suspend fun initVariable(): Try {
90+
x = BinVariable2("x", Shape2(cities.size, cities.size))
91+
for (city1 in cities) {
92+
for (city2 in cities) {
93+
val xi = x[city1, city2]
94+
xi.name = "${x.name}_(${city1.name},${city2.name})"
95+
if (city1 != city2) {
96+
metaModel.add(xi)
97+
} else {
98+
xi.range.eq(UInt8.zero)
99+
}
100+
}
101+
}
102+
u = IntVariable1("u", Shape1(cities.size))
103+
for (city in cities) {
104+
val ui = u[city]
105+
ui.name = "${u.name}_${city.name}"
106+
if (city.name != beginCity) {
107+
ui.range.set(ValueRange(Int64(-cities.size.toLong()), Int64(cities.size.toLong())).value!!)
108+
metaModel.add(ui)
109+
} else {
110+
ui.range.eq(Int64.zero)
111+
}
112+
}
113+
return ok
114+
}
115+
116+
private suspend fun initSymbol(): Try {
117+
distance = LinearExpressionSymbol(sum(cities.flatMap { city1 ->
118+
cities.mapNotNull { city2 ->
119+
if (city1 == city2) {
120+
null
121+
} else {
122+
distances[city1 to city2]?.let { it * x[city1, city2] }
123+
}
124+
}
125+
}), "distance")
126+
depart = LinearSymbols1("depart", Shape1(cities.size)) { i, _ ->
127+
val city = cities[i]
128+
LinearExpressionSymbol(sum(x[city, _a]), "depart_${city.name}")
129+
}
130+
reached = LinearSymbols1("reached", Shape1(cities.size)) { i, _ ->
131+
val city = cities[i]
132+
LinearExpressionSymbol(sum(x[_a, city]), "reached_${city.name}")
133+
}
134+
return ok
135+
}
136+
137+
private suspend fun initObject(): Try {
138+
metaModel.minimize(distance, "distance")
139+
return ok
140+
}
141+
142+
private suspend fun initConstraint(): Try {
143+
for (city in cities) {
144+
metaModel.addConstraint(depart[city] eq Flt64.one, "depart_${city.name}")
145+
}
146+
for (city in cities) {
147+
metaModel.addConstraint(reached[city] eq Flt64.one, "reached_${city.name}")
148+
}
149+
val notBeginCities = cities.filter { it.name != beginCity }
150+
for (city1 in notBeginCities) {
151+
for (city2 in notBeginCities) {
152+
if (city1 != city2) {
153+
metaModel.addConstraint(
154+
u[city1] - u[city2] + cities.size * x[city1, city2] leq cities.size - 1,
155+
"child_route_(${city1.name},${city2.name})"
156+
)
157+
}
158+
}
159+
}
160+
return ok
161+
}
162+
163+
private suspend fun solve(): Try {
164+
val solver = ScipLinearSolver()
165+
when (val ret = solver(metaModel)) {
166+
is Ok -> {
167+
metaModel.tokens.setSolution(ret.value.solution)
168+
}
169+
170+
is Failed -> {
171+
return Failed(ret.error)
172+
}
173+
}
174+
return ok
175+
}
176+
177+
private suspend fun analyzeSolution(): Try {
178+
val route: MutableMap<City, City> = hashMapOf()
179+
for (token in metaModel.tokens.tokens) {
180+
if (token.result!! eq Flt64.one && token.variable.belongsTo(x)) {
181+
val vector = token.variable.vectorView
182+
val city1 = cities[vector[0]]
183+
val city2 = cities[vector[1]]
184+
route[city1] = city2
185+
}
186+
}
187+
return ok
188+
}
189+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package fuookami.ospf.kotlin.example.core_demo
2+
3+
import fuookami.ospf.kotlin.utils.math.*
4+
import fuookami.ospf.kotlin.utils.concept.*
5+
import fuookami.ospf.kotlin.utils.functional.*
6+
import fuookami.ospf.kotlin.utils.multi_array.*
7+
import fuookami.ospf.kotlin.core.frontend.variable.*
8+
import fuookami.ospf.kotlin.core.frontend.expression.polynomial.*
9+
import fuookami.ospf.kotlin.core.frontend.expression.symbol.*
10+
import fuookami.ospf.kotlin.core.frontend.inequality.*
11+
import fuookami.ospf.kotlin.core.frontend.model.mechanism.*
12+
import fuookami.ospf.kotlin.core.backend.plugins.scip.*
13+
14+
data object Demo11 {
15+
sealed class Node : AutoIndexed(Node::class)
16+
class RootNode : Node()
17+
class EndNode : Node()
18+
class NormalNode : Node()
19+
20+
val nodes: List<Node> = listOf(
21+
listOf(RootNode()),
22+
(1..7).map { NormalNode() },
23+
listOf(EndNode())
24+
).flatten()
25+
26+
val capacities = mapOf(
27+
nodes[0] to mapOf(
28+
nodes[1] to UInt64(15),
29+
nodes[2] to UInt64(10),
30+
nodes[3] to UInt64(40)
31+
),
32+
nodes[1] to mapOf(
33+
nodes[4] to UInt64(15)
34+
),
35+
nodes[2] to mapOf(
36+
nodes[5] to UInt64(10),
37+
nodes[6] to UInt64(35)
38+
),
39+
nodes[3] to mapOf(
40+
nodes[6] to UInt64(30),
41+
nodes[7] to UInt64(20)
42+
),
43+
nodes[4] to mapOf(
44+
nodes[6] to UInt64(10)
45+
),
46+
nodes[5] to mapOf(
47+
nodes[8] to UInt64(10)
48+
),
49+
nodes[6] to mapOf(
50+
nodes[7] to UInt64(10)
51+
),
52+
nodes[7] to mapOf(
53+
nodes[8] to UInt64(45)
54+
)
55+
)
56+
57+
lateinit var x: UIntVariable2
58+
lateinit var flow: UIntVar
59+
60+
lateinit var flowIn: LinearSymbols1
61+
lateinit var flowOut: LinearSymbols1
62+
63+
val metaModel: LinearMetaModel = LinearMetaModel("demo11")
64+
65+
private val subProcesses = listOf(
66+
Demo11::initVariable,
67+
Demo11::initSymbol,
68+
Demo11::initObject,
69+
Demo11::initConstraint,
70+
Demo11::solve,
71+
Demo11::analyzeSolution
72+
)
73+
74+
suspend operator fun invoke(): Try {
75+
for (process in subProcesses) {
76+
when (val result = process()) {
77+
is Ok -> {}
78+
79+
is Failed -> {
80+
return Failed(result.error)
81+
}
82+
}
83+
}
84+
return ok
85+
}
86+
87+
private suspend fun initVariable(): Try {
88+
x = UIntVariable2("x", Shape2(nodes.size, nodes.size))
89+
for (node1 in nodes) {
90+
for (node2 in nodes) {
91+
if (node1 == node2) {
92+
continue
93+
}
94+
capacities[node1]?.get(node2)?.let {
95+
val xi = x[node1, node2]
96+
xi.range.leq(it)
97+
metaModel.add(xi)
98+
}
99+
}
100+
}
101+
flow = UIntVar("flow")
102+
metaModel.add(flow)
103+
return ok
104+
}
105+
106+
private suspend fun initSymbol(): Try {
107+
flowIn = LinearSymbols1("flow_in", Shape1(nodes.size)) { i, _ ->
108+
LinearExpressionSymbol(sum(x[_a, i]), "flow_in_$i")
109+
}
110+
metaModel.add(flowIn)
111+
flowOut = LinearSymbols1("flow_out", Shape1(nodes.size)) { i, _ ->
112+
LinearExpressionSymbol(sum(x[i, _a]), "flow_out_$i")
113+
}
114+
metaModel.add(flowOut)
115+
return ok
116+
}
117+
118+
private suspend fun initObject(): Try {
119+
metaModel.maximize(flow, "flow")
120+
return ok
121+
}
122+
123+
private suspend fun initConstraint(): Try {
124+
val rootNode = nodes.first { it is RootNode }
125+
metaModel.addConstraint(
126+
flowOut[rootNode] - flowIn[rootNode] eq flow,
127+
"flow_${rootNode.index}"
128+
)
129+
val endNode = nodes.first { it is EndNode }
130+
metaModel.addConstraint(
131+
flowIn[endNode] - flowOut[endNode] eq flow,
132+
"flow_${endNode.index}"
133+
)
134+
for (node in nodes.filterIsInstance<NormalNode>()) {
135+
metaModel.addConstraint(
136+
flowOut[node] eq flowIn[node],
137+
"flow_${node.index}"
138+
)
139+
}
140+
return ok
141+
}
142+
143+
private suspend fun solve(): Try {
144+
val solver = ScipLinearSolver()
145+
when (val ret = solver(metaModel)) {
146+
is Ok -> {
147+
metaModel.tokens.setSolution(ret.value.solution)
148+
}
149+
150+
is Failed -> {
151+
return Failed(ret.error)
152+
}
153+
}
154+
return ok
155+
}
156+
157+
private suspend fun analyzeSolution(): Try {
158+
val flow: MutableMap<Node, MutableMap<Node, UInt64>> = hashMapOf()
159+
for (token in metaModel.tokens.tokens) {
160+
if (token.result!! geq Flt64.one && token.variable belongsTo x) {
161+
val vector = token.variable.vectorView
162+
val node1 = nodes[vector[0]]
163+
val node2 = nodes[vector[1]]
164+
flow.getOrPut(node1) { hashMapOf() }[node2] = token.result!!.round().toUInt64()
165+
}
166+
}
167+
return ok
168+
}
169+
}

0 commit comments

Comments
 (0)