Skip to content

Commit 2b22b6b

Browse files
committed
implement non-dominated sorting
1 parent 46e3c1f commit 2b22b6b

2 files changed

Lines changed: 118 additions & 0 deletions

File tree

src/main/scala/nds.scala

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.expr.mcdm
2+
3+
import org.expr.mcdm.Direction.{Minimize, Maximize}
4+
5+
case class NdsResult(
6+
scores: Vec
7+
) extends MCDMResult
8+
9+
def dominates(p1: Vec, p2: Vec, fns: Array[Direction]): Boolean =
10+
val n = p1.length
11+
val notworse = (0 until n).count(i =>
12+
if fns(i) == Maximize then p1(i) < p2(i)
13+
else p1(i) > p2(i)
14+
)
15+
val better = (0 until n).count(i =>
16+
if fns(i) == Maximize then p1(i) > p2(i)
17+
else p1(i) < p2(i)
18+
)
19+
(notworse == 0) && (better > 0)
20+
21+
def ndsranks(decmat: Mat, directions: Array[Direction]): Vec =
22+
23+
val (n, m) = Matrix.size(decmat)
24+
25+
val ranks = Matrix.zeros(n)
26+
27+
for i <- 0 until n do
28+
for j <- 0 until n do
29+
if i != j then
30+
if dominates(decmat(i), decmat(j), directions) then ranks(i) += 1
31+
32+
ranks
33+
34+
def nds(decmat: Mat, directions: Array[Direction]): NdsResult =
35+
36+
val (n, m) = Matrix.size(decmat)
37+
38+
val ranks = ndsranks(decmat, directions)
39+
40+
NdsResult(
41+
scores = ranks
42+
)

src/test/scala/testnds.scala

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import munit.Assertions as A
2+
3+
import org.expr.mcdm.nds
4+
import org.expr.mcdm.Direction.{Maximize, Minimize}
5+
import org.expr.mcdm.Matrix
6+
7+
class TestNds extends munit.FunSuite {
8+
test("NDS - 1") {
9+
/*
10+
cases = [
11+
1.0 2.0 3.0
12+
2.0 1.0 3.0
13+
1.0 3.0 2.0
14+
4.0 5.0 6.0
15+
]
16+
17+
18+
fns = [maximum, maximum, maximum]
19+
20+
result = nds(cases, fns)
21+
*/
22+
val decisionMat = Array(
23+
Array(1.0, 2.0, 3.0),
24+
Array(2.0, 1.0, 3.0),
25+
Array(1.0, 3.0, 2.0),
26+
Array(4.0, 5.0, 6.0)
27+
)
28+
29+
val fns = Array(
30+
Maximize,
31+
Maximize,
32+
Maximize
33+
)
34+
35+
val result = nds(
36+
decisionMat,
37+
fns
38+
)
39+
40+
val expected_scores = Array(0.0, 0.0, 0.0, 3.0)
41+
42+
A.assert(
43+
Matrix.elementwise_equal(result.scores, expected_scores, 1e-5),
44+
"The scores do not match the expected values in nds."
45+
)
46+
}
47+
48+
test("NDS - 2") {
49+
50+
val decisionMat = Array(
51+
Array(1.0, 2.0, 3.0, 4.0),
52+
Array(2.0, 4.0, 6.0, 8.0),
53+
Array(4.0, 8.0, 12.0, 16.0),
54+
Array(8.0, 16.0, 24.0, 32.0)
55+
)
56+
57+
val fns = Array(
58+
Minimize,
59+
Minimize,
60+
Minimize,
61+
Minimize
62+
)
63+
64+
val expected_scores = Array(3.0, 2.0, 1.0, 0.0)
65+
66+
val result = nds(
67+
decisionMat,
68+
fns
69+
)
70+
71+
A.assert(
72+
Matrix.elementwise_equal(result.scores, expected_scores, 1e-5),
73+
"The scores do not match the expected values in nds."
74+
)
75+
}
76+
}

0 commit comments

Comments
 (0)