Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/src/main/kotlin/model/algo/findMST.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import model.graph.Edge
fun findMST(graph: Graph): Set<Edge> {
require(!graph.isDirected) { "MST is only implemented for undirected graphs" }

val sortedEdges = graph.edges.sortedBy { it.weight }
val mstEdges = mutableSetOf<Edge>()
if (graph.vertices.isEmpty()) return mstEdges
val sortedEdges = graph.edges.sortedBy { it.weight }

val verticesList = graph.vertices.toList()
val idToIndex = verticesList
Expand Down
91 changes: 91 additions & 0 deletions app/src/test/kotlin/algorithms/CommunitiesTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package algorithms

import model.algo.findCommunities
import model.graph.Graph
import model.graph.Vertex
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue

class CommunitiesTest {
/**
* Test checks whether graph is complete there is certainly one community
*/
@Test
fun `one community, complete graph`() {
val graph = Graph()
graph.addVertex("0")
graph.addVertex("1")
graph.addVertex("2")
graph.addVertex("3")

graph.addEdge(1,0)
graph.addEdge(1,2)
graph.addEdge(1,3)
graph.addEdge(0,2)
graph.addEdge(0,3)
graph.addEdge(2,3)

assertEquals(1, findCommunities(graph).size)
}

/**
* Each vertex from 5000 is its own community
*/
@Test
fun `5000 communities, no edges`() {
val graph = Graph()
for (i in 1..5000) {
graph.addVertex(i.toString())
}
val result = findCommunities(graph).size
assertEquals( 5000, result)
}

/**
* No graph - no communities
*/
@Test
fun `empty graph, no communities`() {
val graph = Graph()
assertTrue(findCommunities(graph).isEmpty())
}

/**
* three vertices connected with each other
*/
@Test
fun `two communities connected with one edge`() {
val graph = Graph()
val firstComm = mutableSetOf<Vertex>()
val secondComm = mutableSetOf<Vertex>()

firstComm.add(graph.addVertex("0"))
firstComm.add(graph.addVertex("1"))
firstComm.add(graph.addVertex("2"))
secondComm.add(graph.addVertex("3"))
secondComm.add(graph.addVertex("4"))
secondComm.add(graph.addVertex("5"))

graph.addEdge(1,0)
graph.addEdge(0,2)
graph.addEdge(2,1)
graph.addEdge(3,4)
graph.addEdge(4,5)
graph.addEdge(5,3)
graph.addEdge(0,3)

assertEquals(firstComm, findCommunities(graph).getValue(0).toSet())
assertEquals(secondComm, findCommunities(graph).getValue(1).toSet())
}

/**
* One vertex - its own community
*/
@Test
fun `single isolated vertex is its own community`() {
val graph = Graph()
graph.addVertex("0")
assertEquals(1, findCommunities(graph).size)
}
}
96 changes: 96 additions & 0 deletions app/src/test/kotlin/algorithms/MstTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package algorithms

import model.algo.findMST
import model.graph.Edge
import model.graph.Graph
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue

class MstTest {
/**
* Chain produce one mst
*/
@Test
fun `all edges in mst`() {
val graph = Graph()
val expected = mutableSetOf<Edge>()
graph.addVertex("0")
graph.addVertex("1")
graph.addVertex("2")
graph.addVertex("3")

expected.add(graph.addEdge(0,1))
expected.add(graph.addEdge(1,2))
expected.add(graph.addEdge(2,3))

val result = findMST(graph)
assertEquals(expected, result)
}

/**
* If there is no edges there is no mst
*/
@Test
fun `graph is not connected`() {
val graph = Graph()
graph.addVertex("0")
graph.addVertex("1")
graph.addVertex("2")
graph.addVertex("3")

assertThrows<IllegalStateException> {
findMST(graph)
}
}

/**
* Mst cannot be find in directed graphs
*/
@Test
fun `directed graph throws exception`() {
val graph = Graph(true)
assertThrows<IllegalArgumentException> {
findMST(graph)
}
}

/**
* No edges - no mst
*/
@Test
fun `single vertex returns empty mst`() {
val graph = Graph()
graph.addVertex("0")
assertTrue(findMST(graph).isEmpty())
}

/**
* Test checks if negative weight is supported
*/
@Test
fun `negative weight is supported`() {
val graph = Graph()
val expected = mutableSetOf<Edge>()

graph.addVertex("0")
graph.addVertex("1")
graph.addVertex("2")

expected.add(graph.addEdge(0, 1, -5))
expected.add(graph.addEdge(1, 2, 2))

val result = findMST(graph)
assertEquals(expected, result)
}

/**
* If there is no graph - mst is empty
*/
@Test
fun `empty graph - empty mst`() {
val graph = Graph()
assertTrue(findMST(graph).isEmpty())
}
}
80 changes: 80 additions & 0 deletions app/src/test/kotlin/algorithms/SccTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package algorithms

import model.algo.findSCC
import model.graph.Graph
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue

class SccTest {
/**
* No graph - no scc
*/
@Test
fun `empty graph no scc`() {
assertTrue(findSCC(Graph()).isEmpty())
}

/**
* Single vertex is strongly connected component
*/
@Test
fun `single vertex graph`() {
val graph = Graph()
graph.addVertex("0")
val scc = findSCC(graph)
assertEquals(1, scc.size)
assertEquals(1, scc.first().size)
}

/**
* Each vertex is scc because there is no edges
*/
@Test
fun `5000 scc, no edges`() {
val graph = Graph()
for (i in 1..5000) {
graph.addVertex(i.toString())
}
val result = findSCC(graph).size
assertEquals( 5000, result)
}

/**
* Cycle produces one scc
*/
@Test
fun `directed cycle forms one scc`() {
val graph = Graph(true)
for (i in 0 until 100) {
graph.addVertex(i.toString())
}

for (i in 0 until 100) {
val from = i
val to = (i + 1) % 100
graph.addEdge(from, to)
}
val scc = findSCC(graph)
assertEquals(1, scc.size)
assertEquals(100, scc.first().size)
}

/**
* Each vertex is reachable - scc
*/
@Test
fun `chain in directed graph produces 100 scc`() {
val graph = Graph(true)
for (i in 0 until 100) {
graph.addVertex(i.toString())
}

for (i in 0 until 99) {
graph.addEdge(i, i + 1)
}
val scc = findSCC(graph)
assertEquals(100, scc.size)
assertEquals(1, scc.first().size)
}
}
59 changes: 59 additions & 0 deletions app/src/test/kotlin/integration/SQLiteMstIntegrationTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package integration

import androidx.compose.ui.graphics.Color
import model.graph.Edge
import model.graph.Graph
import model.io.sqlite.SqliteRepository
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.io.TempDir
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import java.nio.file.Path
import viewmodel.representation.RepresentationStrategy
import viewmodel.screens.MainScreenViewModel
import viewmodel.representation.ForceAtlas2

class SQLiteMstIntegrationTest {
private lateinit var repo: SqliteRepository
private lateinit var representationStrategy: RepresentationStrategy
private lateinit var graph: Graph

@BeforeEach
fun setup(@TempDir tempDir: Path) {
val dbFile = tempDir.resolve("test.db").toFile().absolutePath
repo = SqliteRepository(dbFile)
graph = Graph()
representationStrategy = ForceAtlas2()
}

/**
* Test checks coloring of edges by basic scenario:
* user creates graph -> save it to sqlite -> load it form sqlite -> use find mst algorithm
*/
@Test
fun `create graph, load to sqlite, read from there and find mst`() {
val expected = mutableSetOf<Edge>()
graph.addVertex("0")
graph.addVertex("1")
graph.addVertex("2")
expected.add(graph.addEdge(0, 1, -1))
expected.add(graph.addEdge(1, 2, 1))
graph.addEdge(2, 0, 10)

val stored = repo.save(graph, "kirilenko_top")
val loaded = repo.read(stored)
assertEquals(3, loaded.vertices.size)

val vm = MainScreenViewModel(loaded, representationStrategy)
vm.showMst()

val expectedWeight = expected.sumOf { it.weight }
val greenEdges = vm.graphViewModel.edges.filter { it.color == Color.Green }
val grayEdges = vm.graphViewModel.edges.filter { it.color == Color.Gray }
val greenEdgesWeight = greenEdges.sumOf { it.origin.weight }

assertEquals(expectedWeight, greenEdgesWeight)
assertEquals(loaded.edges.size - greenEdges.size, grayEdges.size)
}
}
Loading