From 5bedc7302d6f4ee5cd64cede7c977d08ff51a753 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 5 May 2024 12:50:11 +0000 Subject: [PATCH 001/211] feat: create license file --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3ef22ba --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Suvorov Rodion, Strelnikov Andrei, Kremnev Semyon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From c257bd45390382d60ee0db707cdf7a490976a34c Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 5 May 2024 11:51:32 +0000 Subject: [PATCH 002/211] feat(ci): add linter, approve request and pr description check --- .github/mergeable.yml | 15 +++++++++++++++ .github/workflows/ktlint-formatter.yaml | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 .github/mergeable.yml create mode 100644 .github/workflows/ktlint-formatter.yaml diff --git a/.github/mergeable.yml b/.github/mergeable.yml new file mode 100644 index 0000000..7e20b01 --- /dev/null +++ b/.github/mergeable.yml @@ -0,0 +1,15 @@ +version: 2 +mergeable: + - when: 'pull_request.*, pull_request_review.*' + name: Approvals check + filter: + - do: payload + pull_request: + title: + must_exclude: + regex: ^Feedback$ + regex_flag: none + validate: + - do: approvals + min: + count: 1 \ No newline at end of file diff --git a/.github/workflows/ktlint-formatter.yaml b/.github/workflows/ktlint-formatter.yaml new file mode 100644 index 0000000..1bfb452 --- /dev/null +++ b/.github/workflows/ktlint-formatter.yaml @@ -0,0 +1,19 @@ +name: ktlint + +on: + pull_request: + paths: + - "**/*.kt" + - ".github/workflows/ktlint.yml" + workflow_dispatch: + +jobs: + ktlint: + runs-on: ubuntu-latest + + steps: + - name: "checkout" + uses: actions/checkout@v2 + + - name: "ktlint" + uses: "block42-blockchain-company/ktlint-action@master" \ No newline at end of file From 29708dc15da6a231fe05bba02859136562dfd3f1 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 5 May 2024 11:53:56 +0000 Subject: [PATCH 003/211] feat: create blank readme file --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..30404ce --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +TODO \ No newline at end of file From 6f7984f15d78bd2ce2a11945c01127a2f91d3581 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 5 May 2024 13:02:04 +0000 Subject: [PATCH 004/211] add blank classes for graph model --- src/main/kotlin/graph/model/DirectedGraph.kt | 4 ++++ src/main/kotlin/graph/model/Edge.kt | 4 ++++ src/main/kotlin/graph/model/Graph.kt | 4 ++++ src/main/kotlin/graph/model/UndirectedGraph.kt | 0 src/main/kotlin/graph/model/Vertex.kt | 4 ++++ 5 files changed, 16 insertions(+) create mode 100644 src/main/kotlin/graph/model/DirectedGraph.kt create mode 100644 src/main/kotlin/graph/model/Edge.kt create mode 100644 src/main/kotlin/graph/model/Graph.kt create mode 100644 src/main/kotlin/graph/model/UndirectedGraph.kt create mode 100644 src/main/kotlin/graph/model/Vertex.kt diff --git a/src/main/kotlin/graph/model/DirectedGraph.kt b/src/main/kotlin/graph/model/DirectedGraph.kt new file mode 100644 index 0000000..334e2e9 --- /dev/null +++ b/src/main/kotlin/graph/model/DirectedGraph.kt @@ -0,0 +1,4 @@ +package graph.model + +class DirectedGraph { +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt new file mode 100644 index 0000000..b21e15e --- /dev/null +++ b/src/main/kotlin/graph/model/Edge.kt @@ -0,0 +1,4 @@ +package graph.model + +class Edge { +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt new file mode 100644 index 0000000..920ebfe --- /dev/null +++ b/src/main/kotlin/graph/model/Graph.kt @@ -0,0 +1,4 @@ +package graph.model + +class Graph { +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/UndirectedGraph.kt new file mode 100644 index 0000000..e69de29 diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt new file mode 100644 index 0000000..8e17bcc --- /dev/null +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -0,0 +1,4 @@ +package graph.model + +class Vertex { +} \ No newline at end of file From a78e9e47d31838c00d1788c31e2ab49fb31a1e74 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 5 May 2024 13:13:43 +0000 Subject: [PATCH 005/211] fix: style fix with ktlint --- src/main/kotlin/Main.kt | 11 ++++++----- src/main/kotlin/graph/model/DirectedGraph.kt | 3 +-- src/main/kotlin/graph/model/Edge.kt | 3 +-- src/main/kotlin/graph/model/Graph.kt | 3 +-- src/main/kotlin/graph/model/Vertex.kt | 3 +-- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index fed3f24..8c427d6 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,4 +1,4 @@ -import androidx.compose.desktop.ui.tooling.preview.Preview +gimport androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -24,8 +24,9 @@ fun App() { } } -fun main() = application { - Window(onCloseRequest = ::exitApplication) { - App() +fun main() = + application { + Window(onCloseRequest = ::exitApplication) { + App() + } } -} diff --git a/src/main/kotlin/graph/model/DirectedGraph.kt b/src/main/kotlin/graph/model/DirectedGraph.kt index 334e2e9..776de6f 100644 --- a/src/main/kotlin/graph/model/DirectedGraph.kt +++ b/src/main/kotlin/graph/model/DirectedGraph.kt @@ -1,4 +1,3 @@ package graph.model -class DirectedGraph { -} \ No newline at end of file +class DirectedGraph diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index b21e15e..92c96f2 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -1,4 +1,3 @@ package graph.model -class Edge { -} \ No newline at end of file +class Edge diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt index 920ebfe..e2b3236 100644 --- a/src/main/kotlin/graph/model/Graph.kt +++ b/src/main/kotlin/graph/model/Graph.kt @@ -1,4 +1,3 @@ package graph.model -class Graph { -} \ No newline at end of file +class Graph diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index 8e17bcc..c3c884c 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -1,4 +1,3 @@ package graph.model -class Vertex { -} \ No newline at end of file +class Vertex From e5d7c3a29b64c7f280b375be2951f73c84bca0c2 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 5 May 2024 14:53:01 +0000 Subject: [PATCH 006/211] fix: delete ci --- .github/mergeable.yml | 15 --------------- .github/workflows/ktlint-formatter.yaml | 19 ------------------- 2 files changed, 34 deletions(-) delete mode 100644 .github/mergeable.yml delete mode 100644 .github/workflows/ktlint-formatter.yaml diff --git a/.github/mergeable.yml b/.github/mergeable.yml deleted file mode 100644 index 7e20b01..0000000 --- a/.github/mergeable.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: 2 -mergeable: - - when: 'pull_request.*, pull_request_review.*' - name: Approvals check - filter: - - do: payload - pull_request: - title: - must_exclude: - regex: ^Feedback$ - regex_flag: none - validate: - - do: approvals - min: - count: 1 \ No newline at end of file diff --git a/.github/workflows/ktlint-formatter.yaml b/.github/workflows/ktlint-formatter.yaml deleted file mode 100644 index 1bfb452..0000000 --- a/.github/workflows/ktlint-formatter.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: ktlint - -on: - pull_request: - paths: - - "**/*.kt" - - ".github/workflows/ktlint.yml" - workflow_dispatch: - -jobs: - ktlint: - runs-on: ubuntu-latest - - steps: - - name: "checkout" - uses: actions/checkout@v2 - - - name: "ktlint" - uses: "block42-blockchain-company/ktlint-action@master" \ No newline at end of file From 8b7b6a248f259d74a576e3301f65b04eaee38cf0 Mon Sep 17 00:00:00 2001 From: Rodion Date: Sun, 5 May 2024 16:29:31 +0300 Subject: [PATCH 007/211] fix: typos --- src/main/kotlin/Main.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 8c427d6..5791b5a 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,4 +1,4 @@ -gimport androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text From b563b74cfcb8df1ce26bc53384c3e3f410a4e306 Mon Sep 17 00:00:00 2001 From: Rodion Date: Sun, 5 May 2024 16:47:57 +0300 Subject: [PATCH 008/211] feat: add graph classs --- src/main/kotlin/graph/model/Graph.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt index e2b3236..56f100f 100644 --- a/src/main/kotlin/graph/model/Graph.kt +++ b/src/main/kotlin/graph/model/Graph.kt @@ -1,3 +1,9 @@ package graph.model -class Graph +abstract class Graph { + abstract val vertices: Collection> + abstract val edges: Collection> + + abstract fun addVertex(v: V): Vertex + abstract fun addEdge(u: V, v: V, e: E): Edge +} \ No newline at end of file From d2af2e75966dbec3cfde54161b1f4fd9fe007d13 Mon Sep 17 00:00:00 2001 From: Rodion Date: Sun, 5 May 2024 16:50:28 +0300 Subject: [PATCH 009/211] feat: add Vertex class --- src/main/kotlin/graph/model/Vertex.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index c3c884c..5355926 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -1,3 +1,5 @@ package graph.model -class Vertex +abstract class Vertex { + abstract var element: V +} \ No newline at end of file From c3eedae6a5dee22c1a340ee7ace39298e50aaa1c Mon Sep 17 00:00:00 2001 From: Rodion Date: Sun, 5 May 2024 16:54:16 +0300 Subject: [PATCH 010/211] feat: add Edge class --- src/main/kotlin/graph/model/Edge.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index 92c96f2..99a8104 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -1,3 +1,7 @@ package graph.model -class Edge +abstract class Edge { + abstract var element: E + abstract val vertices: Pair, Vertex> + fun incident(v: Vertex) = v == vertices.first || v == vertices.second +} \ No newline at end of file From 9ace72b6c737297bbb045d8f4f27e6ac44057533 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 5 May 2024 14:53:01 +0000 Subject: [PATCH 011/211] fix: delete ci --- .github/mergeable.yml | 15 --------------- .github/workflows/ktlint-formatter.yaml | 19 ------------------- 2 files changed, 34 deletions(-) delete mode 100644 .github/mergeable.yml delete mode 100644 .github/workflows/ktlint-formatter.yaml diff --git a/.github/mergeable.yml b/.github/mergeable.yml deleted file mode 100644 index 7e20b01..0000000 --- a/.github/mergeable.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: 2 -mergeable: - - when: 'pull_request.*, pull_request_review.*' - name: Approvals check - filter: - - do: payload - pull_request: - title: - must_exclude: - regex: ^Feedback$ - regex_flag: none - validate: - - do: approvals - min: - count: 1 \ No newline at end of file diff --git a/.github/workflows/ktlint-formatter.yaml b/.github/workflows/ktlint-formatter.yaml deleted file mode 100644 index 1bfb452..0000000 --- a/.github/workflows/ktlint-formatter.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: ktlint - -on: - pull_request: - paths: - - "**/*.kt" - - ".github/workflows/ktlint.yml" - workflow_dispatch: - -jobs: - ktlint: - runs-on: ubuntu-latest - - steps: - - name: "checkout" - uses: actions/checkout@v2 - - - name: "ktlint" - uses: "block42-blockchain-company/ktlint-action@master" \ No newline at end of file From a8e50c7730937716e574bc88f69a7757db2164de Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 8 May 2024 06:21:25 +0000 Subject: [PATCH 012/211] feat: add interfaces for graphs --- src/main/kotlin/graph/model/DirectedWeightedGraph.kt | 4 ++++ src/main/kotlin/graph/model/Edge.kt | 2 +- src/main/kotlin/graph/model/Graph.kt | 9 --------- src/main/kotlin/graph/model/UndirectedGraph.kt | 4 ++++ .../kotlin/graph/model/UndirectedWeightedGraph.kt | 4 ++++ src/main/kotlin/graph/model/interfaces/Directed.kt | 4 ++++ src/main/kotlin/graph/model/interfaces/Graph.kt | 11 +++++++++++ src/main/kotlin/graph/model/interfaces/Weight.kt | 4 ++++ 8 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 src/main/kotlin/graph/model/DirectedWeightedGraph.kt delete mode 100644 src/main/kotlin/graph/model/Graph.kt create mode 100644 src/main/kotlin/graph/model/UndirectedWeightedGraph.kt create mode 100644 src/main/kotlin/graph/model/interfaces/Directed.kt create mode 100644 src/main/kotlin/graph/model/interfaces/Graph.kt create mode 100644 src/main/kotlin/graph/model/interfaces/Weight.kt diff --git a/src/main/kotlin/graph/model/DirectedWeightedGraph.kt b/src/main/kotlin/graph/model/DirectedWeightedGraph.kt new file mode 100644 index 0000000..9ea3f01 --- /dev/null +++ b/src/main/kotlin/graph/model/DirectedWeightedGraph.kt @@ -0,0 +1,4 @@ +package graph.model + +class DirectedWeightedGraph { +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index 99a8104..3c86d3b 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -3,5 +3,5 @@ package graph.model abstract class Edge { abstract var element: E abstract val vertices: Pair, Vertex> - fun incident(v: Vertex) = v == vertices.first || v == vertices.second + open fun incident(v: Vertex) = v == vertices.first || v == vertices.second } \ No newline at end of file diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt deleted file mode 100644 index 56f100f..0000000 --- a/src/main/kotlin/graph/model/Graph.kt +++ /dev/null @@ -1,9 +0,0 @@ -package graph.model - -abstract class Graph { - abstract val vertices: Collection> - abstract val edges: Collection> - - abstract fun addVertex(v: V): Vertex - abstract fun addEdge(u: V, v: V, e: E): Edge -} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/UndirectedGraph.kt index e69de29..ff61b65 100644 --- a/src/main/kotlin/graph/model/UndirectedGraph.kt +++ b/src/main/kotlin/graph/model/UndirectedGraph.kt @@ -0,0 +1,4 @@ +package graph.model + +class UndirectedGraph { +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt b/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt new file mode 100644 index 0000000..a31f549 --- /dev/null +++ b/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt @@ -0,0 +1,4 @@ +package graph.model + +class UndirectedWeightedGraph { +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/interfaces/Directed.kt b/src/main/kotlin/graph/model/interfaces/Directed.kt new file mode 100644 index 0000000..d447a95 --- /dev/null +++ b/src/main/kotlin/graph/model/interfaces/Directed.kt @@ -0,0 +1,4 @@ +package graph.model.interfaces + +interface Directed { +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/interfaces/Graph.kt b/src/main/kotlin/graph/model/interfaces/Graph.kt new file mode 100644 index 0000000..81d570b --- /dev/null +++ b/src/main/kotlin/graph/model/interfaces/Graph.kt @@ -0,0 +1,11 @@ +package graph.model.interfaces + +import graph.model.Edge +import graph.model.Vertex + +interface Graph { + val vertices: Collection> + val edges: Collection> + fun addVertex(v: V): Vertex + fun addEdge(u: V, v: V, e: E): Edge +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/interfaces/Weight.kt b/src/main/kotlin/graph/model/interfaces/Weight.kt new file mode 100644 index 0000000..a2361f0 --- /dev/null +++ b/src/main/kotlin/graph/model/interfaces/Weight.kt @@ -0,0 +1,4 @@ +package graph.model.interfaces + +interface Weight { +} \ No newline at end of file From 2b3cfcb977efbc2bb946dee2544d69212509bfbd Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 8 May 2024 08:01:21 +0000 Subject: [PATCH 013/211] fix: delete interfaces for weight and direction --- src/main/kotlin/graph/model/interfaces/Directed.kt | 4 ---- src/main/kotlin/graph/model/interfaces/Weight.kt | 4 ---- 2 files changed, 8 deletions(-) delete mode 100644 src/main/kotlin/graph/model/interfaces/Directed.kt delete mode 100644 src/main/kotlin/graph/model/interfaces/Weight.kt diff --git a/src/main/kotlin/graph/model/interfaces/Directed.kt b/src/main/kotlin/graph/model/interfaces/Directed.kt deleted file mode 100644 index d447a95..0000000 --- a/src/main/kotlin/graph/model/interfaces/Directed.kt +++ /dev/null @@ -1,4 +0,0 @@ -package graph.model.interfaces - -interface Directed { -} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/interfaces/Weight.kt b/src/main/kotlin/graph/model/interfaces/Weight.kt deleted file mode 100644 index a2361f0..0000000 --- a/src/main/kotlin/graph/model/interfaces/Weight.kt +++ /dev/null @@ -1,4 +0,0 @@ -package graph.model.interfaces - -interface Weight { -} \ No newline at end of file From 04855bd61d533a2068bf43cdae6979ea4dff81fe Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 8 May 2024 08:04:59 +0000 Subject: [PATCH 014/211] feat: add weight and direction to edge --- src/main/kotlin/graph/model/Edge.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index 3c86d3b..e4b968c 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -2,6 +2,8 @@ package graph.model abstract class Edge { abstract var element: E + open var weight: Long = 1L + open var isDirected: Boolean = false abstract val vertices: Pair, Vertex> open fun incident(v: Vertex) = v == vertices.first || v == vertices.second } \ No newline at end of file From 99e974db9ee5b9c115af393b58e634d30da1ac14 Mon Sep 17 00:00:00 2001 From: dronshock Date: Wed, 8 May 2024 11:44:21 +0300 Subject: [PATCH 015/211] feat: add raw architecture --- src/main/kotlin/graph/model/Edge.kt | 10 +++++----- .../kotlin/graph/model/UndirectedGraph.kt | 20 +++++++++++++++++-- src/main/kotlin/graph/model/Vertex.kt | 7 ++++--- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index e4b968c..b8d4e08 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -1,9 +1,9 @@ package graph.model -abstract class Edge { - abstract var element: E - open var weight: Long = 1L - open var isDirected: Boolean = false - abstract val vertices: Pair, Vertex> +class Edge ( + var element: E, + val vertices: Pair, Vertex>, + open var weight: Long = 1L, +){ open fun incident(v: Vertex) = v == vertices.first || v == vertices.second } \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/UndirectedGraph.kt index ff61b65..b7f5877 100644 --- a/src/main/kotlin/graph/model/UndirectedGraph.kt +++ b/src/main/kotlin/graph/model/UndirectedGraph.kt @@ -1,4 +1,20 @@ package graph.model -class UndirectedGraph { -} \ No newline at end of file +class Graph{ + open var isDirected: Boolean = false + private val vertices = hashMapOf>() + private val edges = hashMapOf>() + + fun vertices(): Collection> = vertices.values + + fun edges(): Collection> = edges.values + + fun addVertex(v: V): Vertex = vertices.getOrPut(v) { Vertex(v, -1) } + + fun addEdge(u: V, v: V, e: E, weight: Long=1L,): Edge { + val first = addVertex(u) + val second = addVertex(v) + return edges.getOrPut(e) { Edge(e, Pair(first,second), weight) } + } + +} diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index 5355926..a73d8f8 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -1,5 +1,6 @@ package graph.model -abstract class Vertex { - abstract var element: V -} \ No newline at end of file +class Vertex ( + var element: V, + var community: Int = -1 +){} \ No newline at end of file From ddac60734daf41a3ffb87ef75dc78cc00636279c Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Thu, 9 May 2024 08:27:02 +0000 Subject: [PATCH 016/211] feat: add empty folders for secondary algorithms --- src/main/kotlin/algorithms/Algo.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/kotlin/algorithms/Algo.kt diff --git a/src/main/kotlin/algorithms/Algo.kt b/src/main/kotlin/algorithms/Algo.kt new file mode 100644 index 0000000..24b92cb --- /dev/null +++ b/src/main/kotlin/algorithms/Algo.kt @@ -0,0 +1,4 @@ +package algorithms + +class Algo { +} \ No newline at end of file From 844584c06a0c93c208f1880183bdf48421da8999 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Thu, 9 May 2024 08:34:31 +0000 Subject: [PATCH 017/211] feat: delete redundant classes --- src/main/kotlin/graph/model/DirectedGraph.kt | 3 --- src/main/kotlin/graph/model/DirectedWeightedGraph.kt | 4 ---- src/main/kotlin/graph/model/UndirectedWeightedGraph.kt | 4 ---- 3 files changed, 11 deletions(-) delete mode 100644 src/main/kotlin/graph/model/DirectedGraph.kt delete mode 100644 src/main/kotlin/graph/model/DirectedWeightedGraph.kt delete mode 100644 src/main/kotlin/graph/model/UndirectedWeightedGraph.kt diff --git a/src/main/kotlin/graph/model/DirectedGraph.kt b/src/main/kotlin/graph/model/DirectedGraph.kt deleted file mode 100644 index 776de6f..0000000 --- a/src/main/kotlin/graph/model/DirectedGraph.kt +++ /dev/null @@ -1,3 +0,0 @@ -package graph.model - -class DirectedGraph diff --git a/src/main/kotlin/graph/model/DirectedWeightedGraph.kt b/src/main/kotlin/graph/model/DirectedWeightedGraph.kt deleted file mode 100644 index 9ea3f01..0000000 --- a/src/main/kotlin/graph/model/DirectedWeightedGraph.kt +++ /dev/null @@ -1,4 +0,0 @@ -package graph.model - -class DirectedWeightedGraph { -} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt b/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt deleted file mode 100644 index a31f549..0000000 --- a/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt +++ /dev/null @@ -1,4 +0,0 @@ -package graph.model - -class UndirectedWeightedGraph { -} \ No newline at end of file From 9baa61876e5b4c9427822f95a99c36a05445ab2b Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Thu, 9 May 2024 08:34:31 +0000 Subject: [PATCH 018/211] feat: delete redundant classes --- src/main/kotlin/graph/model/DirectedGraph.kt | 3 --- src/main/kotlin/graph/model/DirectedWeightedGraph.kt | 4 ---- src/main/kotlin/graph/model/UndirectedWeightedGraph.kt | 4 ---- 3 files changed, 11 deletions(-) delete mode 100644 src/main/kotlin/graph/model/DirectedGraph.kt delete mode 100644 src/main/kotlin/graph/model/DirectedWeightedGraph.kt delete mode 100644 src/main/kotlin/graph/model/UndirectedWeightedGraph.kt diff --git a/src/main/kotlin/graph/model/DirectedGraph.kt b/src/main/kotlin/graph/model/DirectedGraph.kt deleted file mode 100644 index 776de6f..0000000 --- a/src/main/kotlin/graph/model/DirectedGraph.kt +++ /dev/null @@ -1,3 +0,0 @@ -package graph.model - -class DirectedGraph diff --git a/src/main/kotlin/graph/model/DirectedWeightedGraph.kt b/src/main/kotlin/graph/model/DirectedWeightedGraph.kt deleted file mode 100644 index 9ea3f01..0000000 --- a/src/main/kotlin/graph/model/DirectedWeightedGraph.kt +++ /dev/null @@ -1,4 +0,0 @@ -package graph.model - -class DirectedWeightedGraph { -} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt b/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt deleted file mode 100644 index a31f549..0000000 --- a/src/main/kotlin/graph/model/UndirectedWeightedGraph.kt +++ /dev/null @@ -1,4 +0,0 @@ -package graph.model - -class UndirectedWeightedGraph { -} \ No newline at end of file From cd35770bbebe09e1e27c12d66a63c157f63eb080 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Thu, 9 May 2024 08:27:02 +0000 Subject: [PATCH 019/211] feat: add empty folders for secondary algorithms --- src/main/kotlin/algorithms/Algo.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/kotlin/algorithms/Algo.kt diff --git a/src/main/kotlin/algorithms/Algo.kt b/src/main/kotlin/algorithms/Algo.kt new file mode 100644 index 0000000..24b92cb --- /dev/null +++ b/src/main/kotlin/algorithms/Algo.kt @@ -0,0 +1,4 @@ +package algorithms + +class Algo { +} \ No newline at end of file From dd760942c0fbd32c119457c3218d8b6a8f0cdd0a Mon Sep 17 00:00:00 2001 From: dronshock Date: Thu, 9 May 2024 14:14:21 +0300 Subject: [PATCH 020/211] feat: change classes signatures --- src/main/kotlin/graph/model/Edge.kt | 3 +-- .../kotlin/graph/model/UndirectedGraph.kt | 22 +++++++++++-------- src/main/kotlin/graph/model/Vertex.kt | 6 ++++- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index b8d4e08..bf4c222 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -1,7 +1,6 @@ package graph.model -class Edge ( - var element: E, +class Edge ( val vertices: Pair, Vertex>, open var weight: Long = 1L, ){ diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/UndirectedGraph.kt index b7f5877..46e782f 100644 --- a/src/main/kotlin/graph/model/UndirectedGraph.kt +++ b/src/main/kotlin/graph/model/UndirectedGraph.kt @@ -1,20 +1,24 @@ package graph.model -class Graph{ +class Graph{ open var isDirected: Boolean = false - private val vertices = hashMapOf>() - private val edges = hashMapOf>() + private val vertices = hashMapOf>() + private val edges = hashMapOf>() fun vertices(): Collection> = vertices.values - fun edges(): Collection> = edges.values + fun edges(): Collection> = edges.values - fun addVertex(v: V): Vertex = vertices.getOrPut(v) { Vertex(v, -1) } + fun addVertex(id: Int, v: V): Vertex = vertices.getOrPut(id) { Vertex(v, -1) } - fun addEdge(u: V, v: V, e: E, weight: Long=1L,): Edge { - val first = addVertex(u) - val second = addVertex(v) - return edges.getOrPut(e) { Edge(e, Pair(first,second), weight) } + fun addEdge(u: Int, v: Int, weight: Long=1L, id:Int): Edge { + val first = addVertex(u,vertices[u]?.element ?: throw Exception("cringe") ) + val second = addVertex(v, vertices[v]?.element?: throw Exception("cringe") ) + if (!isDirected){ + second.incidentEdges.add(id) + } + first.incidentEdges.add(id) + return edges.getOrPut(id) { Edge(Pair(first,second), weight) } } } diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index a73d8f8..284c112 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -1,6 +1,10 @@ package graph.model +import algorithms.KruskalsMST +import androidx.compose.runtime.MutableDoubleState + class Vertex ( var element: V, - var community: Int = -1 + var community: Int = -1, + var incidentEdges: MutableList = mutableListOf() ){} \ No newline at end of file From 09b5da333573eadd837b16dd7b287183c2ec0cd3 Mon Sep 17 00:00:00 2001 From: dronshock Date: Thu, 9 May 2024 14:14:21 +0300 Subject: [PATCH 021/211] feat: change classes signatures --- src/main/kotlin/algorithms/Algo.kt | 4 ---- src/main/kotlin/graph/model/Edge.kt | 3 +-- .../kotlin/graph/model/UndirectedGraph.kt | 22 +++++++++++-------- src/main/kotlin/graph/model/Vertex.kt | 6 ++++- 4 files changed, 19 insertions(+), 16 deletions(-) delete mode 100644 src/main/kotlin/algorithms/Algo.kt diff --git a/src/main/kotlin/algorithms/Algo.kt b/src/main/kotlin/algorithms/Algo.kt deleted file mode 100644 index 24b92cb..0000000 --- a/src/main/kotlin/algorithms/Algo.kt +++ /dev/null @@ -1,4 +0,0 @@ -package algorithms - -class Algo { -} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index b8d4e08..bf4c222 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -1,7 +1,6 @@ package graph.model -class Edge ( - var element: E, +class Edge ( val vertices: Pair, Vertex>, open var weight: Long = 1L, ){ diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/UndirectedGraph.kt index b7f5877..46e782f 100644 --- a/src/main/kotlin/graph/model/UndirectedGraph.kt +++ b/src/main/kotlin/graph/model/UndirectedGraph.kt @@ -1,20 +1,24 @@ package graph.model -class Graph{ +class Graph{ open var isDirected: Boolean = false - private val vertices = hashMapOf>() - private val edges = hashMapOf>() + private val vertices = hashMapOf>() + private val edges = hashMapOf>() fun vertices(): Collection> = vertices.values - fun edges(): Collection> = edges.values + fun edges(): Collection> = edges.values - fun addVertex(v: V): Vertex = vertices.getOrPut(v) { Vertex(v, -1) } + fun addVertex(id: Int, v: V): Vertex = vertices.getOrPut(id) { Vertex(v, -1) } - fun addEdge(u: V, v: V, e: E, weight: Long=1L,): Edge { - val first = addVertex(u) - val second = addVertex(v) - return edges.getOrPut(e) { Edge(e, Pair(first,second), weight) } + fun addEdge(u: Int, v: Int, weight: Long=1L, id:Int): Edge { + val first = addVertex(u,vertices[u]?.element ?: throw Exception("cringe") ) + val second = addVertex(v, vertices[v]?.element?: throw Exception("cringe") ) + if (!isDirected){ + second.incidentEdges.add(id) + } + first.incidentEdges.add(id) + return edges.getOrPut(id) { Edge(Pair(first,second), weight) } } } diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index a73d8f8..284c112 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -1,6 +1,10 @@ package graph.model +import algorithms.KruskalsMST +import androidx.compose.runtime.MutableDoubleState + class Vertex ( var element: V, - var community: Int = -1 + var community: Int = -1, + var incidentEdges: MutableList = mutableListOf() ){} \ No newline at end of file From 1963d3b8cd27c95528d649d3339aaa43eed706f8 Mon Sep 17 00:00:00 2001 From: dronshock Date: Thu, 9 May 2024 17:18:21 +0300 Subject: [PATCH 022/211] fix: change from a pair of vertices to a pair of id --- src/main/kotlin/graph/model/Edge.kt | 4 ++-- src/main/kotlin/graph/model/UndirectedGraph.kt | 14 ++++++-------- src/main/kotlin/graph/model/Vertex.kt | 6 ++++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index bf4c222..c5ea794 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -1,8 +1,8 @@ package graph.model class Edge ( - val vertices: Pair, Vertex>, + val vertices: Pair, open var weight: Long = 1L, ){ - open fun incident(v: Vertex) = v == vertices.first || v == vertices.second + open fun incident(v: Int) = v == vertices.first || v == vertices.second } \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/UndirectedGraph.kt index 46e782f..d721670 100644 --- a/src/main/kotlin/graph/model/UndirectedGraph.kt +++ b/src/main/kotlin/graph/model/UndirectedGraph.kt @@ -2,22 +2,20 @@ package graph.model class Graph{ open var isDirected: Boolean = false - private val vertices = hashMapOf>() - private val edges = hashMapOf>() + val vertices = hashMapOf>() + val edges = hashMapOf>() fun vertices(): Collection> = vertices.values fun edges(): Collection> = edges.values - fun addVertex(id: Int, v: V): Vertex = vertices.getOrPut(id) { Vertex(v, -1) } + fun addVertex(id: Int, v: V): Vertex = vertices.getOrPut(id) { Vertex(v) } - fun addEdge(u: Int, v: Int, weight: Long=1L, id:Int): Edge { - val first = addVertex(u,vertices[u]?.element ?: throw Exception("cringe") ) - val second = addVertex(v, vertices[v]?.element?: throw Exception("cringe") ) + fun addEdge(first: Int, second: Int, weight: Long=1L, id:Int): Edge { if (!isDirected){ - second.incidentEdges.add(id) + vertices[second]?.incidentEdges?.add(id) ?: throw Exception("cringe") } - first.incidentEdges.add(id) + vertices[first]?.incidentEdges?.add(id) ?: throw Exception("cringe") return edges.getOrPut(id) { Edge(Pair(first,second), weight) } } diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index 284c112..c081c13 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -5,6 +5,8 @@ import androidx.compose.runtime.MutableDoubleState class Vertex ( var element: V, - var community: Int = -1, var incidentEdges: MutableList = mutableListOf() -){} \ No newline at end of file +){ + var id: Int = 0 + var community: Int = -1 +} \ No newline at end of file From 5e5f87384713a7baf9bfae69f8152a3d33b14d7f Mon Sep 17 00:00:00 2001 From: dronshock Date: Thu, 9 May 2024 17:38:35 +0300 Subject: [PATCH 023/211] feat: add Kruskal algorithm implementation --- .../kotlin/algorithms/KruskalsAlgorithm.kt | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/main/kotlin/algorithms/KruskalsAlgorithm.kt diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt new file mode 100644 index 0000000..e93c11f --- /dev/null +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -0,0 +1,64 @@ +package algorithms + +import graph.model.Edge +import graph.model.Graph + +class KruskalsMST { + private fun kruskals(graph: Graph) { + var j = 0 + var noOfEdges = 0 + val V = graph.vertices().size + + val subsets = arrayOfNulls(V) + + val results = arrayOfNulls>(V) + + for (i in 0 ..< V) { + subsets[i] = Subset(i, 0) + } + val edgesList = graph.edges.values + val sortedEdges = edgesList.sortedWith(compareBy{ it.weight}) + + while (noOfEdges < V - 1) { + + val nextEdge = sortedEdges[j] + val x = findRoot(subsets, nextEdge.vertices.first) + val y = findRoot(subsets, nextEdge.vertices.second) + + if (x != y) { + results[noOfEdges] = nextEdge + union(subsets, x, y) + noOfEdges++ + } + + j++ + } + } + + private fun union( + subsets: Array, x: Int, + y: Int, + ) { + val rootX = findRoot(subsets, x) + val rootY = findRoot(subsets, y) + + if (subsets[rootY]!!.rank < subsets[rootX]!!.rank) { + subsets[rootY]!!.parent = rootX + } else if ((subsets[rootX]!!.rank + < subsets[rootY]!!.rank) + ) { + subsets[rootX]!!.parent = rootY + } else { + subsets[rootY]!!.parent = rootX + subsets[rootX]!!.rank++ + } + } + + private fun findRoot(subsets: Array, i: Int): Int { + if (subsets[i]!!.parent != i) + subsets[i]!!.parent = findRoot(subsets, subsets[i]!!.parent) + return subsets[i]!!.parent + } + + internal class Subset(var parent: Int, var rank: Int) +} \ No newline at end of file From 31f7f79c871d2737bfdf3e0261cb3ca277817eaa Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Thu, 9 May 2024 14:48:34 +0000 Subject: [PATCH 024/211] fix: fix visibility modifiers --- src/main/kotlin/graph/model/Edge.kt | 4 ++-- src/main/kotlin/graph/model/UndirectedGraph.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index c5ea794..7d69e3e 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -2,7 +2,7 @@ package graph.model class Edge ( val vertices: Pair, - open var weight: Long = 1L, + var weight: Long = 1L, ){ - open fun incident(v: Int) = v == vertices.first || v == vertices.second + fun incident(v: Int) = v == vertices.first || v == vertices.second } \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/UndirectedGraph.kt index d721670..6bc3e99 100644 --- a/src/main/kotlin/graph/model/UndirectedGraph.kt +++ b/src/main/kotlin/graph/model/UndirectedGraph.kt @@ -1,7 +1,7 @@ package graph.model class Graph{ - open var isDirected: Boolean = false + var isDirected: Boolean = false val vertices = hashMapOf>() val edges = hashMapOf>() From 55ef1045810a6a022f993774b0714bd4ce053ca3 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sat, 11 May 2024 12:46:22 +0000 Subject: [PATCH 025/211] feat: create class for bridge finder algorithm --- src/main/kotlin/algorithms/BridgeFinder.kt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/kotlin/algorithms/BridgeFinder.kt diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt new file mode 100644 index 0000000..a468aef --- /dev/null +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -0,0 +1,20 @@ +package algorithms + +import graph.model.Graph + +class BridgeFinder(graph: Graph) { + val visitedVertices = mutableListOf() + val timeIn = mutableListOf() + val fUp = mutableListOf() + val timer = 0L + fun findBridges(){ + fun dfs(){ + + } + + for (i in ){ + + } + } + +} \ No newline at end of file From 2f5e7f1aea4a24da174501b56f968be7ff850443 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sat, 11 May 2024 14:04:33 +0000 Subject: [PATCH 026/211] feat: implement raw version of bridge finder algorithm --- src/main/kotlin/algorithms/BridgeFinder.kt | 49 ++++++++++++++++++---- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index a468aef..26f6858 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -1,20 +1,53 @@ package algorithms import graph.model.Graph +import kotlin.math.min class BridgeFinder(graph: Graph) { - val visitedVertices = mutableListOf() - val timeIn = mutableListOf() - val fUp = mutableListOf() - val timer = 0L - fun findBridges(){ - fun dfs(){ + private val arraySize = graph.vertices.size + private val visitedVertices = Array(arraySize) {false} + private val timeIn = Array(arraySize) {0} + private val fUp = Array(arraySize) {0} + fun findBridges(graph: Graph){ + var timer = 0 + + fun isBridge(edgeID: Int){ + println(edgeID) } - for (i in ){ + fun dfs(vertexID: Int, parent: Int = -1){ + visitedVertices[vertexID] = true + timeIn[vertexID] = timer++ + fUp[vertexID] = timer++ + val incidentEdgesID = graph.vertices[vertexID]!!.incidentEdges + for (edgeID in incidentEdgesID){ + val edge = graph.edges[edgeID]!!.vertices + val currentVertex = graph.vertices[vertexID] + val newVertexID = if (currentVertex == graph.vertices[edge.first]){ + edge.first + } + else{ + edge.second + } + if (newVertexID == parent) continue + if (visitedVertices[newVertexID]){ + fUp[vertexID] = min(timeIn[newVertexID], fUp[vertexID]) + } + else{ + dfs(newVertexID, vertexID) + fUp[vertexID] = min(fUp[newVertexID], fUp[vertexID]) + if(fUp[vertexID] > timeIn[newVertexID]){ + isBridge(edgeID) + } + } + } + } + for (i in arraySize - 1 downTo 0){ + if (visitedVertices[i]){ + dfs(i) + } } } - } \ No newline at end of file From 647267702c5cd01014b6082edff25fffe4cfc976 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sat, 11 May 2024 14:06:00 +0000 Subject: [PATCH 027/211] feat: add todo for future work --- src/main/kotlin/algorithms/BridgeFinder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index 26f6858..6c424f1 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -8,7 +8,7 @@ class BridgeFinder(graph: Graph) { private val visitedVertices = Array(arraySize) {false} private val timeIn = Array(arraySize) {0} private val fUp = Array(arraySize) {0} - + //TODO: adapt this algorithm to multiple edges fun findBridges(graph: Graph){ var timer = 0 From 352f41464eddb3a8ab0db0450c81b0c1b7a70177 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 12 May 2024 13:03:08 +0000 Subject: [PATCH 028/211] fix: add ID to edges and fix naming --- src/main/kotlin/graph/model/Edge.kt | 1 + .../kotlin/graph/model/{UndirectedGraph.kt => Graph.kt} | 8 ++++---- src/main/kotlin/graph/model/Vertex.kt | 5 +---- 3 files changed, 6 insertions(+), 8 deletions(-) rename src/main/kotlin/graph/model/{UndirectedGraph.kt => Graph.kt} (51%) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index 7d69e3e..a8761f3 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -3,6 +3,7 @@ package graph.model class Edge ( val vertices: Pair, var weight: Long = 1L, + var id:Int = 1, ){ fun incident(v: Int) = v == vertices.first || v == vertices.second } \ No newline at end of file diff --git a/src/main/kotlin/graph/model/UndirectedGraph.kt b/src/main/kotlin/graph/model/Graph.kt similarity index 51% rename from src/main/kotlin/graph/model/UndirectedGraph.kt rename to src/main/kotlin/graph/model/Graph.kt index 6bc3e99..7aed112 100644 --- a/src/main/kotlin/graph/model/UndirectedGraph.kt +++ b/src/main/kotlin/graph/model/Graph.kt @@ -11,12 +11,12 @@ class Graph{ fun addVertex(id: Int, v: V): Vertex = vertices.getOrPut(id) { Vertex(v) } - fun addEdge(first: Int, second: Int, weight: Long=1L, id:Int): Edge { + fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { if (!isDirected){ - vertices[second]?.incidentEdges?.add(id) ?: throw Exception("cringe") + vertices[secondVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("cringe") } - vertices[first]?.incidentEdges?.add(id) ?: throw Exception("cringe") - return edges.getOrPut(id) { Edge(Pair(first,second), weight) } + vertices[firstVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("cringe") + return edges.getOrPut(edgeID) { Edge(Pair(firstVertexID,secondVertexID), weight, edgeID) } } } diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index c081c13..bcffe1f 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -1,10 +1,7 @@ package graph.model -import algorithms.KruskalsMST -import androidx.compose.runtime.MutableDoubleState - class Vertex ( - var element: V, + var data: V, var incidentEdges: MutableList = mutableListOf() ){ var id: Int = 0 From ab3318ce8c87f6098c522e42bff9553294cd2415 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 12 May 2024 14:09:34 +0000 Subject: [PATCH 029/211] fix: delete redundant interfaces --- src/main/kotlin/graph/model/interfaces/Graph.kt | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 src/main/kotlin/graph/model/interfaces/Graph.kt diff --git a/src/main/kotlin/graph/model/interfaces/Graph.kt b/src/main/kotlin/graph/model/interfaces/Graph.kt deleted file mode 100644 index 81d570b..0000000 --- a/src/main/kotlin/graph/model/interfaces/Graph.kt +++ /dev/null @@ -1,11 +0,0 @@ -package graph.model.interfaces - -import graph.model.Edge -import graph.model.Vertex - -interface Graph { - val vertices: Collection> - val edges: Collection> - fun addVertex(v: V): Vertex - fun addEdge(u: V, v: V, e: E): Edge -} \ No newline at end of file From 71cdfe1528916b95eb82c6dca4185637809d5057 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 12 May 2024 14:28:32 +0000 Subject: [PATCH 030/211] feat(WIP): add Ford-Bellman algorithm class --- src/main/kotlin/algorithms/FordBellman.kt | 35 +++++++++++++++++++++++ src/main/kotlin/graph/model/Edge.kt | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/algorithms/FordBellman.kt diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt new file mode 100644 index 0000000..66c50c1 --- /dev/null +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -0,0 +1,35 @@ +package algorithms + +import graph.model.Graph +import java.math.BigInteger +import kotlin.math.max + + +class FordBellman(graph: Graph) { + val INF = Long.MAX_VALUE + private val verticesNumber = graph.vertices.size + private val edgesNumber = graph.edges.size + private val pathsLength = Array(verticesNumber) { INF } + private val resultPath = Array(verticesNumber) { -1 } + + fun shortestPath(graph: Graph) { + pathsLength[0] = 0 + var cycleFlag: Int + for (i in 1 until verticesNumber) { + cycleFlag = -1 + for (j in 1 until edgesNumber) { + val firstVertexPath = pathsLength[graph.edges[j]!!.vertices.first] + var secondVertexPath = pathsLength[graph.edges[j]!!.vertices.second] + if (firstVertexPath < INF) { + if (secondVertexPath > firstVertexPath + graph.edges[j]!!.weight) { + secondVertexPath = max(-INF, INF + graph.edges[j]!!.weight) + resultPath[graph.edges[j]!!.vertices.second] = graph.edges[j]!!.vertices.first + cycleFlag = graph.edges[j]!!.vertices.second + } + } + } + } + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index a8761f3..2ce7d52 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -3,7 +3,7 @@ package graph.model class Edge ( val vertices: Pair, var weight: Long = 1L, - var id:Int = 1, + var id: Int = 1, ){ fun incident(v: Int) = v == vertices.first || v == vertices.second } \ No newline at end of file From ee3eb524db8cbcaf31b160c237e37f909cb440ec Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 12 May 2024 14:44:23 +0000 Subject: [PATCH 031/211] feat: raw implementation of Ford-Bellman algorithm --- src/main/kotlin/algorithms/FordBellman.kt | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt index 66c50c1..99ff66d 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -14,7 +14,7 @@ class FordBellman(graph: Graph) { fun shortestPath(graph: Graph) { pathsLength[0] = 0 - var cycleFlag: Int + var cycleFlag = -1 for (i in 1 until verticesNumber) { cycleFlag = -1 for (j in 1 until edgesNumber) { @@ -29,7 +29,32 @@ class FordBellman(graph: Graph) { } } } + negativeCycleCheck(graph, cycleFlag) } + private fun negativeCycleCheck(graph: Graph, cycleFlag: Int) { + if (cycleFlag == -1) { + println("No negative cycles") + } else { + var tmpCycleFlag = cycleFlag + for (i in 1 until verticesNumber) { + tmpCycleFlag = resultPath[tmpCycleFlag] + } + val path: MutableList = mutableListOf() + var current = tmpCycleFlag + var cycleEndFlag = true + while(cycleEndFlag){ + path.add(current) + if (current == tmpCycleFlag && path.size >1){ + cycleEndFlag = false + } + current=resultPath[current] + } + println("Negative cycle:") + path.forEach { + print("$it ") + } + } + } } \ No newline at end of file From 5c6253ae12b81429b0ab8a9178d97ba22d9affd3 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 12 May 2024 17:47:35 +0000 Subject: [PATCH 032/211] build: add dependencies for jetbrains exposed --- build.gradle.kts | 9 ++++----- gradle.properties | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3903f11..f426ca0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,12 +13,11 @@ repositories { maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") google() } - +val exposedVersion: String by project dependencies { - // Note, if you develop a library, you should use compose.desktop.common. - // compose.desktop.currentOs should be used in launcher-sourceSet - // (in a separate module for demo project and in testMain). - // With compose.desktop.common you will also lose @Preview functionality + implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation(compose.desktop.currentOs) } diff --git a/gradle.properties b/gradle.properties index 98aed13..d8f5256 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,3 +2,4 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 kotlin.code.style=official kotlin.version=1.9.22 compose.version=1.6.0 +exposedVersion=0.50.1 \ No newline at end of file From 04fd43b0b55b0436303c99057d5d525250890114 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 12 May 2024 18:09:44 +0000 Subject: [PATCH 033/211] feat: add examples dir --- examples/keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/keep diff --git a/examples/keep b/examples/keep new file mode 100644 index 0000000..e69de29 From 901ad443911f4383fd4d721cbd5c7e3f38a5e2ad Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Sun, 12 May 2024 18:19:46 +0000 Subject: [PATCH 034/211] feat: add databases directory --- src/main/kotlin/databases/sqlite/keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/kotlin/databases/sqlite/keep diff --git a/src/main/kotlin/databases/sqlite/keep b/src/main/kotlin/databases/sqlite/keep new file mode 100644 index 0000000..e69de29 From bb4ce1358216c08b4299219902679a37b57748b6 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 12 May 2024 23:49:55 +0300 Subject: [PATCH 035/211] feet(graph): kosaraju algo skeleton added --- src/main/kotlin/algorithms/Kosaraju.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/kotlin/algorithms/Kosaraju.kt diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt new file mode 100644 index 0000000..1a192a7 --- /dev/null +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -0,0 +1,9 @@ +package algorithms + +import graph.model.Graph + +class Kosaraju(private val graph: Graph) { + private val used = hashMapOf() + private val order = mutableListOf() + private val component = mutableListOf() +} From 57e7cce046b7663565a0a87a50b1faa38c617b90 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:12:10 +0300 Subject: [PATCH 036/211] feat(algo): kosaraju dfs added --- src/main/kotlin/algorithms/Kosaraju.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index 1a192a7..ce22848 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -6,4 +6,20 @@ class Kosaraju(private val graph: Graph) { private val used = hashMapOf() private val order = mutableListOf() private val component = mutableListOf() + + private fun dfs1(vertexID: Int) { + used[vertexID] = true + val vertex = graph.vertices[vertexID] ?: return + for (edgeID in vertex.incidentEdges) { + val edge = graph.edges[edgeID] ?: continue + val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first + if (used[nextVertexID] != true) { + dfs1(nextVertexID) + } + } + order.add(vertexID) + } + + + } From 799221cdbf57bb99bf6189182c4add3f5852c908 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:12:48 +0300 Subject: [PATCH 037/211] feat(algo): kosaraju dfs test added --- src/main/kotlin/algorithms/Kosaraju.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index ce22848..ca4918b 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -19,7 +19,10 @@ class Kosaraju(private val graph: Graph) { } order.add(vertexID) } - + fun Test_dfs1(vertexID: Int) : MutableList { + dfs1(vertexID) + return order + } } From 8882f9f6d218ca48e0d3b1f1cfa592ec8a3f4c69 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:13:13 +0300 Subject: [PATCH 038/211] feat(test): kosaraju dfs test added --- build.gradle.kts | 12 ++++++ src/test/kotlin/graphs/DFSTest.kt | 63 +++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/test/kotlin/graphs/DFSTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index f426ca0..ab2a490 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,6 +15,8 @@ repositories { } val exposedVersion: String by project dependencies { + testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0") implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") @@ -32,3 +34,13 @@ compose.desktop { } } } + +tasks.named("test") { + // Use JUnit Platform for unit tests. + useJUnitPlatform() +} +tasks.withType { + testLogging { + events("PASSED", "SKIPPED", "FAILED") + } +} diff --git a/src/test/kotlin/graphs/DFSTest.kt b/src/test/kotlin/graphs/DFSTest.kt new file mode 100644 index 0000000..a94e5d2 --- /dev/null +++ b/src/test/kotlin/graphs/DFSTest.kt @@ -0,0 +1,63 @@ +package graphs + +import algorithms.Kosaraju +import graph.model.Graph +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Assertions.* + +// graph sample +// +// 7 11 → → → → → → → 5 +// ↗ ↓ ↘ ↙ ↘ ↙ ↑ ↘ +// 0 ↓ 1 → → → 9 ← ← ← 2 → → → 10 ↑ 3 +// ↖ ↓ ↗ ↘ ↗ ↘ ↑ ↙ +// 6 → → → → → → 4 8 +// +// + +fun createSampleGraph() : Graph { + // Добавление вершин + val graph = Graph() + for (i in 0..11) { + graph.addVertex(i, i) + } + + // Добавление рёбер + graph.addEdge(0, 7, 1L, 0) + graph.addEdge(7, 6, 1L, 1) + graph.addEdge(6, 0, 1L, 2) + graph.addEdge(6, 1, 1L, 3) + graph.addEdge(6, 4, 1L, 4) + graph.addEdge(7, 1, 1L, 5) + graph.addEdge(1, 9, 1L, 6) + graph.addEdge(9, 4, 1L, 7) + graph.addEdge(4, 2, 1L, 8) + graph.addEdge(2, 9, 1L, 9) + graph.addEdge(2, 10, 1L, 10) + graph.addEdge(11, 9, 1L, 11) + graph.addEdge(11, 2, 1L, 12) + graph.addEdge(11, 5, 1L, 13) + graph.addEdge(10, 8, 1L, 14) + graph.addEdge(8, 5, 1L, 15) + graph.addEdge(5, 10, 1L, 16) + graph.addEdge(5, 3, 1L, 17) + graph.addEdge(3, 8, 1L, 18) + + return graph +} + +class DFSTest { + @Test + fun `test dfs1 with sample graph start from 0`() { + // graph and algo initialization + val graph = createSampleGraph() + val algo = Kosaraju(graph) + val expected = mutableListOf(11, 3, 5, 8, 10, 2, 4, 9, 1, 6, 7, 0) + + // algo start from different positions + val currently0 = algo.Test_dfs1(0) + + // Проверьте результаты + assertTrue(expected == currently0) + } +} \ No newline at end of file From 3bceb45ddfa3a9724dee0b458e00ce6589d18b18 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:25:59 +0300 Subject: [PATCH 039/211] feat(test): kosaraju dfs test added --- src/test/kotlin/graphs/DFSTest.kt | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/test/kotlin/graphs/DFSTest.kt b/src/test/kotlin/graphs/DFSTest.kt index a94e5d2..d2ae9c7 100644 --- a/src/test/kotlin/graphs/DFSTest.kt +++ b/src/test/kotlin/graphs/DFSTest.kt @@ -13,7 +13,7 @@ import org.junit.jupiter.api.Assertions.* // ↖ ↓ ↗ ↘ ↗ ↘ ↑ ↙ // 6 → → → → → → 4 8 // -// +// components: (0,7,1,6) (11) (9,2,4) (10,8,3,5) fun createSampleGraph() : Graph { // Добавление вершин @@ -46,18 +46,32 @@ fun createSampleGraph() : Graph { return graph } -class DFSTest { +class KosarajuTest { @Test - fun `test dfs1 with sample graph start from 0`() { + fun `test dfs1 with sample graph start from 0 component`() { // graph and algo initialization val graph = createSampleGraph() val algo = Kosaraju(graph) val expected = mutableListOf(11, 3, 5, 8, 10, 2, 4, 9, 1, 6, 7, 0) // algo start from different positions - val currently0 = algo.Test_dfs1(0) + val currently = algo.Test_dfs1(0) + + // Проверьте результаты + assertTrue(expected == currently) + } + + @Test + fun `test dfs1 with sample graph start from 5 component`() { + // graph and algo initialization + val graph = createSampleGraph() + val algo = Kosaraju(graph) + val expected = mutableListOf(0, 7, 3, 8, 10, 2, 4, 6, 1, 9, 11, 5) + + // algo start from different positions + val currently = algo.Test_dfs1(5) // Проверьте результаты - assertTrue(expected == currently0) + assertTrue(expected == currently) } } \ No newline at end of file From 17f4749e6eb300bed3a2435024985945a7365caa Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:26:13 +0300 Subject: [PATCH 040/211] feat(test): kosaraju dfs test added --- src/test/kotlin/graphs/DFSTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/kotlin/graphs/DFSTest.kt b/src/test/kotlin/graphs/DFSTest.kt index d2ae9c7..321ae85 100644 --- a/src/test/kotlin/graphs/DFSTest.kt +++ b/src/test/kotlin/graphs/DFSTest.kt @@ -74,4 +74,19 @@ class KosarajuTest { // Проверьте результаты assertTrue(expected == currently) } + + @Test + fun `test dfs1 with sample graph start from 4 component`() { + // graph and algo initialization + val graph = createSampleGraph() + val algo = Kosaraju(graph) + val expected = mutableListOf(0, 7, 11, 3, 5, 8, 10, 2, 4, 6, 1, 9) + + // algo start from different positions + val currently = algo.Test_dfs1(9) + + // Проверьте результаты + assertTrue(expected == currently) + } + } \ No newline at end of file From f1a3f9d0c3161ec20778293a849361afa10bd095 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:26:24 +0300 Subject: [PATCH 041/211] feat(test): kosaraju dfs test added --- src/test/kotlin/graphs/DFSTest.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/graphs/DFSTest.kt b/src/test/kotlin/graphs/DFSTest.kt index 321ae85..e5b1d9e 100644 --- a/src/test/kotlin/graphs/DFSTest.kt +++ b/src/test/kotlin/graphs/DFSTest.kt @@ -88,5 +88,18 @@ class KosarajuTest { // Проверьте результаты assertTrue(expected == currently) } - + + @Test + fun `test dfs1 with sample graph start from 11 component`() { + // graph and algo initialization + val graph = createSampleGraph() + val algo = Kosaraju(graph) + val expected = mutableListOf(0, 7, 3, 5, 8, 10, 2, 4, 6, 1, 9, 11) + + // algo start from different positions + val currently = algo.Test_dfs1(11) + + // Проверьте результаты + assertTrue(expected == currently) + } } \ No newline at end of file From f233822fc181b026fb706ea98688fcc9e8041215 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:39:05 +0300 Subject: [PATCH 042/211] feat(algo): kosaraju component dfs added --- src/main/kotlin/algorithms/Kosaraju.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index ca4918b..f6f3cb2 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -19,10 +19,22 @@ class Kosaraju(private val graph: Graph) { } order.add(vertexID) } - fun Test_dfs1(vertexID: Int) : MutableList { + fun Test_dfs1(vertexID: Int) : MutableList { dfs1(vertexID) return order } + private fun dfs2(transposedGraph: Graph, vertexID: Int) { + used[vertexID] = true + component.add(vertexID) + val vertex = transposedGraph.vertices[vertexID] ?: return + for (edgeID in vertex.incidentEdges) { + val edge = transposedGraph.edges[edgeID] ?: continue + val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first + if (used[nextVertexID] != true) { + dfs2(transposedGraph, nextVertexID) + } + } + } } From 797aa785af9e1f6ca68c4a2794e4649c1a9881a1 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:40:44 +0300 Subject: [PATCH 043/211] feat(algo): kosaraju transpose graph added --- src/main/kotlin/algorithms/Kosaraju.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index f6f3cb2..12f8511 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -32,9 +32,25 @@ class Kosaraju(private val graph: Graph) { val edge = transposedGraph.edges[edgeID] ?: continue val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first if (used[nextVertexID] != true) { - dfs2(transposedGraph, nextVertexID) + dfs2(transposedGraph, nextVertexID) // Изменено } } } + private fun transposeGraph(): Graph { + val transposedGraph = Graph() + transposedGraph.isDirected = graph.isDirected + + // Добавление вершин + graph.vertices.forEach { (id, vertex) -> + transposedGraph.addVertex(id, vertex.data) + } + + // Добавление рёбер с изменённым направлением + graph.edges.forEach { (id, edge) -> + transposedGraph.addEdge(edge.vertices.second, edge.vertices.first, edge.weight, id) + } + + return transposedGraph + } } From 2911671b470617b0de7149e240e25bca52bc2f66 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:42:21 +0300 Subject: [PATCH 044/211] feat(graph): kosaraju algorithm added --- src/main/kotlin/algorithms/Kosaraju.kt | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index 12f8511..9009165 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -7,6 +7,31 @@ class Kosaraju(private val graph: Graph) { private val order = mutableListOf() private val component = mutableListOf() + fun findStronglyConnectedComponents() { + graph.vertices.keys.forEach { used[it] = false } + + // 1-st dfs for topology sort + for (vertexID in graph.vertices.keys) { + if (used[vertexID] != true) { + dfs1(vertexID) + } + } + + val transposedGraph = transposeGraph() + + // clear is visited + used.keys.forEach { used[it] = false } + + // 2-nd dfs for component search + for (vertexID in order.reversed()) { + if (used[vertexID] != true) { + component.clear() + dfs2(transposedGraph,vertexID) + // TODO (println("Компонента сильной связности: $component")) + } + } + } + private fun dfs1(vertexID: Int) { used[vertexID] = true val vertex = graph.vertices[vertexID] ?: return @@ -19,6 +44,7 @@ class Kosaraju(private val graph: Graph) { } order.add(vertexID) } + fun Test_dfs1(vertexID: Int) : MutableList { dfs1(vertexID) return order From 0c1d00d565121989e5847dcba0d579469a275cb8 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:53:23 +0300 Subject: [PATCH 045/211] refactor(algo): few algo refactor --- src/main/kotlin/algorithms/Kosaraju.kt | 41 ++++++++++++++++++- .../graphs/{DFSTest.kt => KosajaruTest.kt} | 0 2 files changed, 39 insertions(+), 2 deletions(-) rename src/test/kotlin/graphs/{DFSTest.kt => KosajaruTest.kt} (100%) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index 9009165..bb8451d 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -27,7 +27,7 @@ class Kosaraju(private val graph: Graph) { if (used[vertexID] != true) { component.clear() dfs2(transposedGraph,vertexID) - // TODO (println("Компонента сильной связности: $component")) + // todo println("Компонента сильной связности: $component") } } } @@ -58,7 +58,7 @@ class Kosaraju(private val graph: Graph) { val edge = transposedGraph.edges[edgeID] ?: continue val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first if (used[nextVertexID] != true) { - dfs2(transposedGraph, nextVertexID) // Изменено + dfs2(transposedGraph, nextVertexID) } } } @@ -80,3 +80,40 @@ class Kosaraju(private val graph: Graph) { return transposedGraph } } + +fun createSampleGraph() : Graph { + // Добавление вершин + val graph = Graph() + for (i in 0..11) { + graph.addVertex(i, i) + } + + // Добавление рёбер + graph.addEdge(0, 7, 1L, 0) + graph.addEdge(7, 6, 1L, 1) + graph.addEdge(6, 0, 1L, 2) + graph.addEdge(6, 1, 1L, 3) + graph.addEdge(6, 4, 1L, 4) + graph.addEdge(7, 1, 1L, 5) + graph.addEdge(1, 9, 1L, 6) + graph.addEdge(9, 4, 1L, 7) + graph.addEdge(4, 2, 1L, 8) + graph.addEdge(2, 9, 1L, 9) + graph.addEdge(2, 10, 1L, 10) + graph.addEdge(11, 9, 1L, 11) + graph.addEdge(11, 2, 1L, 12) + graph.addEdge(11, 5, 1L, 13) + graph.addEdge(10, 8, 1L, 14) + graph.addEdge(8, 5, 1L, 15) + graph.addEdge(5, 10, 1L, 16) + graph.addEdge(5, 3, 1L, 17) + graph.addEdge(3, 8, 1L, 18) + + return graph +} + +fun main() { + val graph = createSampleGraph() + val algorithm = Kosaraju(graph) + algorithm.findStronglyConnectedComponents() +} diff --git a/src/test/kotlin/graphs/DFSTest.kt b/src/test/kotlin/graphs/KosajaruTest.kt similarity index 100% rename from src/test/kotlin/graphs/DFSTest.kt rename to src/test/kotlin/graphs/KosajaruTest.kt From c9394f5f5ebc3c6d20f9f5f262d1465ed32ba3b8 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 13 May 2024 01:54:12 +0300 Subject: [PATCH 046/211] refactor(algo): debugging fun deleted --- src/main/kotlin/algorithms/Kosaraju.kt | 37 -------------------------- 1 file changed, 37 deletions(-) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index bb8451d..ffbf197 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -80,40 +80,3 @@ class Kosaraju(private val graph: Graph) { return transposedGraph } } - -fun createSampleGraph() : Graph { - // Добавление вершин - val graph = Graph() - for (i in 0..11) { - graph.addVertex(i, i) - } - - // Добавление рёбер - graph.addEdge(0, 7, 1L, 0) - graph.addEdge(7, 6, 1L, 1) - graph.addEdge(6, 0, 1L, 2) - graph.addEdge(6, 1, 1L, 3) - graph.addEdge(6, 4, 1L, 4) - graph.addEdge(7, 1, 1L, 5) - graph.addEdge(1, 9, 1L, 6) - graph.addEdge(9, 4, 1L, 7) - graph.addEdge(4, 2, 1L, 8) - graph.addEdge(2, 9, 1L, 9) - graph.addEdge(2, 10, 1L, 10) - graph.addEdge(11, 9, 1L, 11) - graph.addEdge(11, 2, 1L, 12) - graph.addEdge(11, 5, 1L, 13) - graph.addEdge(10, 8, 1L, 14) - graph.addEdge(8, 5, 1L, 15) - graph.addEdge(5, 10, 1L, 16) - graph.addEdge(5, 3, 1L, 17) - graph.addEdge(3, 8, 1L, 18) - - return graph -} - -fun main() { - val graph = createSampleGraph() - val algorithm = Kosaraju(graph) - algorithm.findStronglyConnectedComponents() -} From f90b459a4aa122328fb10d512b7799f654f29d83 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Mon, 13 May 2024 08:46:28 +0000 Subject: [PATCH 047/211] fix: change generic type in graph model to string --- src/main/kotlin/algorithms/BridgeFinder.kt | 4 ++-- src/main/kotlin/algorithms/FordBellman.kt | 6 +++--- src/main/kotlin/algorithms/Kosaraju.kt | 8 ++++---- src/main/kotlin/algorithms/KruskalsAlgorithm.kt | 6 +++--- src/main/kotlin/graph/model/Edge.kt | 2 +- src/main/kotlin/graph/model/Graph.kt | 14 +++++++------- src/main/kotlin/graph/model/Vertex.kt | 4 ++-- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index 6c424f1..1ad1bec 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -3,13 +3,13 @@ package algorithms import graph.model.Graph import kotlin.math.min -class BridgeFinder(graph: Graph) { +class BridgeFinder(graph: Graph) { private val arraySize = graph.vertices.size private val visitedVertices = Array(arraySize) {false} private val timeIn = Array(arraySize) {0} private val fUp = Array(arraySize) {0} //TODO: adapt this algorithm to multiple edges - fun findBridges(graph: Graph){ + fun findBridges(graph: Graph){ var timer = 0 fun isBridge(edgeID: Int){ diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt index 99ff66d..0ee92a1 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -5,14 +5,14 @@ import java.math.BigInteger import kotlin.math.max -class FordBellman(graph: Graph) { +class FordBellman(graph: Graph) { val INF = Long.MAX_VALUE private val verticesNumber = graph.vertices.size private val edgesNumber = graph.edges.size private val pathsLength = Array(verticesNumber) { INF } private val resultPath = Array(verticesNumber) { -1 } - fun shortestPath(graph: Graph) { + fun shortestPath(graph: Graph) { pathsLength[0] = 0 var cycleFlag = -1 for (i in 1 until verticesNumber) { @@ -32,7 +32,7 @@ class FordBellman(graph: Graph) { negativeCycleCheck(graph, cycleFlag) } - private fun negativeCycleCheck(graph: Graph, cycleFlag: Int) { + private fun negativeCycleCheck(graph: Graph, cycleFlag: Int) { if (cycleFlag == -1) { println("No negative cycles") } else { diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index ffbf197..4a29995 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -2,7 +2,7 @@ package algorithms import graph.model.Graph -class Kosaraju(private val graph: Graph) { +class Kosaraju(private val graph: Graph) { private val used = hashMapOf() private val order = mutableListOf() private val component = mutableListOf() @@ -50,7 +50,7 @@ class Kosaraju(private val graph: Graph) { return order } - private fun dfs2(transposedGraph: Graph, vertexID: Int) { + private fun dfs2(transposedGraph: Graph, vertexID: Int) { used[vertexID] = true component.add(vertexID) val vertex = transposedGraph.vertices[vertexID] ?: return @@ -63,8 +63,8 @@ class Kosaraju(private val graph: Graph) { } } - private fun transposeGraph(): Graph { - val transposedGraph = Graph() + private fun transposeGraph(): Graph { + val transposedGraph = Graph() transposedGraph.isDirected = graph.isDirected // Добавление вершин diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt index e93c11f..3cb3367 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -3,15 +3,15 @@ package algorithms import graph.model.Edge import graph.model.Graph -class KruskalsMST { - private fun kruskals(graph: Graph) { +class KruskalsMST { + private fun kruskals(graph: Graph) { var j = 0 var noOfEdges = 0 val V = graph.vertices().size val subsets = arrayOfNulls(V) - val results = arrayOfNulls>(V) + val results = arrayOfNulls(V) for (i in 0 ..< V) { subsets[i] = Subset(i, 0) diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/graph/model/Edge.kt index 2ce7d52..ca6959b 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/graph/model/Edge.kt @@ -1,6 +1,6 @@ package graph.model -class Edge ( +class Edge ( val vertices: Pair, var weight: Long = 1L, var id: Int = 1, diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt index 7aed112..65e1f65 100644 --- a/src/main/kotlin/graph/model/Graph.kt +++ b/src/main/kotlin/graph/model/Graph.kt @@ -1,17 +1,17 @@ package graph.model -class Graph{ +class Graph{ var isDirected: Boolean = false - val vertices = hashMapOf>() - val edges = hashMapOf>() + val vertices = hashMapOf() + val edges = hashMapOf() - fun vertices(): Collection> = vertices.values + fun vertices(): Collection = vertices.values - fun edges(): Collection> = edges.values + fun edges(): Collection = edges.values - fun addVertex(id: Int, v: V): Vertex = vertices.getOrPut(id) { Vertex(v) } + fun addVertex(id: Int, v: String): Vertex = vertices.getOrPut(id) { Vertex(v) } - fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { + fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { if (!isDirected){ vertices[secondVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("cringe") } diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/graph/model/Vertex.kt index bcffe1f..1f9d12f 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/graph/model/Vertex.kt @@ -1,7 +1,7 @@ package graph.model -class Vertex ( - var data: V, +class Vertex( + var data: String, var incidentEdges: MutableList = mutableListOf() ){ var id: Int = 0 From dbc85b6212bcfe9ff5c04826fc50c98147540e5e Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Mon, 13 May 2024 08:36:51 +0000 Subject: [PATCH 048/211] feat: add necessary folders for dao, start work on SQLiteFileHandler --- .../kotlin/databases/SQLite/SQLiteFileHandler.kt | 16 ++++++++++++++++ src/main/kotlin/databases/{sqlite => }/keep | 0 2 files changed, 16 insertions(+) create mode 100644 src/main/kotlin/databases/SQLite/SQLiteFileHandler.kt rename src/main/kotlin/databases/{sqlite => }/keep (100%) diff --git a/src/main/kotlin/databases/SQLite/SQLiteFileHandler.kt b/src/main/kotlin/databases/SQLite/SQLiteFileHandler.kt new file mode 100644 index 0000000..c3d59bb --- /dev/null +++ b/src/main/kotlin/databases/SQLite/SQLiteFileHandler.kt @@ -0,0 +1,16 @@ +package databases.SQLite + +import graph.model.Graph +import org.jetbrains.exposed.sql.Database +import java.io.File + +class SQLiteFileHandler { + fun open(file: File){ + Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") + } + + fun save(file: File){ + Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") + val newGraph = Graph() + } +} \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/keep b/src/main/kotlin/databases/keep similarity index 100% rename from src/main/kotlin/databases/sqlite/keep rename to src/main/kotlin/databases/keep From 49a9b98b85db1a317b611ea35c5157ff9615eb8d Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Mon, 13 May 2024 09:03:50 +0000 Subject: [PATCH 049/211] feat: add dao objects --- .../databases/{SQLite => sqlite}/SQLiteFileHandler.kt | 6 +++++- src/main/kotlin/databases/sqlite/dao/edge/Edge.kt | 4 ++++ src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt | 4 ++++ .../databases/sqlite/dao/verticesView/VerticesView.kt | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) rename src/main/kotlin/databases/{SQLite => sqlite}/SQLiteFileHandler.kt (75%) create mode 100644 src/main/kotlin/databases/sqlite/dao/edge/Edge.kt create mode 100644 src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt create mode 100644 src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt diff --git a/src/main/kotlin/databases/SQLite/SQLiteFileHandler.kt b/src/main/kotlin/databases/sqlite/SQLiteFileHandler.kt similarity index 75% rename from src/main/kotlin/databases/SQLite/SQLiteFileHandler.kt rename to src/main/kotlin/databases/sqlite/SQLiteFileHandler.kt index c3d59bb..755e16f 100644 --- a/src/main/kotlin/databases/SQLite/SQLiteFileHandler.kt +++ b/src/main/kotlin/databases/sqlite/SQLiteFileHandler.kt @@ -1,7 +1,8 @@ -package databases.SQLite +package databases.sqlite import graph.model.Graph import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.transactions.transaction import java.io.File class SQLiteFileHandler { @@ -12,5 +13,8 @@ class SQLiteFileHandler { fun save(file: File){ Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") val newGraph = Graph() + transaction { + + } } } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt new file mode 100644 index 0000000..7de4cc0 --- /dev/null +++ b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt @@ -0,0 +1,4 @@ +package databases.sqlite.dao.edge + +object Edge { +} \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt b/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt new file mode 100644 index 0000000..a2ed6e9 --- /dev/null +++ b/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt @@ -0,0 +1,4 @@ +package databases.sqlite.dao.vertices + +object Vertices { +} \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt b/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt new file mode 100644 index 0000000..8106bdb --- /dev/null +++ b/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt @@ -0,0 +1,4 @@ +package databases.sqlite.dao.verticesView + +object VerticesView { +} \ No newline at end of file From 4d15fc82658415af8c0fed55ff0c5bd532d111dd Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Mon, 13 May 2024 09:34:21 +0000 Subject: [PATCH 050/211] feat: dao columns implemented --- .../{SQLiteFileHandler.kt => SQLiteDBHandler.kt} | 9 +++++---- src/main/kotlin/databases/sqlite/dao/edge/Edge.kt | 2 +- src/main/kotlin/databases/sqlite/dao/edge/Edges.kt | 11 +++++++++++ .../kotlin/databases/sqlite/dao/vertices/Vertex.kt | 4 ++++ .../kotlin/databases/sqlite/dao/vertices/Vertices.kt | 6 +++++- .../databases/sqlite/dao/verticesView/VertexView.kt | 4 ++++ .../databases/sqlite/dao/verticesView/VerticesView.kt | 10 +++++++++- 7 files changed, 39 insertions(+), 7 deletions(-) rename src/main/kotlin/databases/sqlite/{SQLiteFileHandler.kt => SQLiteDBHandler.kt} (94%) create mode 100644 src/main/kotlin/databases/sqlite/dao/edge/Edges.kt create mode 100644 src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt create mode 100644 src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt diff --git a/src/main/kotlin/databases/sqlite/SQLiteFileHandler.kt b/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt similarity index 94% rename from src/main/kotlin/databases/sqlite/SQLiteFileHandler.kt rename to src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt index 755e16f..bc87052 100644 --- a/src/main/kotlin/databases/sqlite/SQLiteFileHandler.kt +++ b/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt @@ -5,16 +5,17 @@ import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.transactions.transaction import java.io.File -class SQLiteFileHandler { +class SQLiteDBHandler { fun open(file: File){ Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") + val newGraph = Graph() + transaction { + + } } fun save(file: File){ Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") - val newGraph = Graph() - transaction { - } } } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt index 7de4cc0..8e984d5 100644 --- a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt +++ b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt @@ -1,4 +1,4 @@ package databases.sqlite.dao.edge -object Edge { +class Edge { } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt b/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt new file mode 100644 index 0000000..d6e3260 --- /dev/null +++ b/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt @@ -0,0 +1,11 @@ +package databases.sqlite.dao.edge + +import databases.sqlite.dao.vertices.Vertices +import org.jetbrains.exposed.dao.id.IntIdTable + +object Edges: IntIdTable("Edge") { + val element = varchar("element", 255) + val first = reference("first", Vertices).nullable() + val second = reference("second", Vertices).nullable() + val weight = varchar("weight", 0).nullable() +} \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt b/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt new file mode 100644 index 0000000..26b8576 --- /dev/null +++ b/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt @@ -0,0 +1,4 @@ +package databases.sqlite.dao.vertices + +class Vertex { +} \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt b/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt index a2ed6e9..9c0f3c3 100644 --- a/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt +++ b/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt @@ -1,4 +1,8 @@ package databases.sqlite.dao.vertices -object Vertices { +import org.jetbrains.exposed.dao.id.IntIdTable + +object Vertices: IntIdTable("Vertices") { + val element = varchar("element", 255) + val community = integer("community") } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt b/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt new file mode 100644 index 0000000..c2583e6 --- /dev/null +++ b/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt @@ -0,0 +1,4 @@ +package databases.sqlite.dao.verticesView + +class VertexView { +} \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt b/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt index 8106bdb..a3895c2 100644 --- a/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt +++ b/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt @@ -1,4 +1,12 @@ package databases.sqlite.dao.verticesView -object VerticesView { +import databases.sqlite.dao.vertices.Vertices +import org.jetbrains.exposed.dao.id.IntIdTable + +object VerticesView: IntIdTable("VerticesView") { + val vertex = reference("vertex", Vertices).nullable() + val x = double("x") + val y = double("y") + val r = double("r") + val color = varchar("color", 255) } \ No newline at end of file From bba7f7826a06d09a043ee76bbebeb3d04434071d Mon Sep 17 00:00:00 2001 From: dronshock Date: Mon, 13 May 2024 12:38:00 +0300 Subject: [PATCH 051/211] feat(ci): add mergeable.yml --- .github/mergeable.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/mergeable.yml diff --git a/.github/mergeable.yml b/.github/mergeable.yml new file mode 100644 index 0000000..c925d36 --- /dev/null +++ b/.github/mergeable.yml @@ -0,0 +1,27 @@ +version: 2 +mergeable: + - when: 'pull_request.*, pull_request_review.*' + name: Approvals check + filter: + # ignore 'Feedback' PR + - do: payload + pull_request: + title: + must_exclude: + regex: ^Feedback$ + regex_flag: none + validate: + - do: description + no_empty: + enabled: true + message: 'Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed.' + - do: approvals + min: + count: 1 + block: + changes_requested: true + limit: + users: + - DronShock + - suvorovrain + - Sem4kok From 910dcd9309a827dbdb4ef671a6b0d9aace82d782 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Mon, 13 May 2024 09:53:41 +0000 Subject: [PATCH 052/211] feat: implement dao rows --- src/main/kotlin/databases/keep | 0 .../kotlin/databases/sqlite/dao/edge/Edge.kt | 11 ++++++++++- .../databases/sqlite/dao/vertices/Vertex.kt | 11 ++++++++++- .../sqlite/dao/verticesView/VertexView.kt | 16 +++++++++++++++- 4 files changed, 35 insertions(+), 3 deletions(-) delete mode 100644 src/main/kotlin/databases/keep diff --git a/src/main/kotlin/databases/keep b/src/main/kotlin/databases/keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt index 8e984d5..4f7652a 100644 --- a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt +++ b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt @@ -1,4 +1,13 @@ package databases.sqlite.dao.edge -class Edge { +import databases.sqlite.dao.vertices.Vertex +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID + +class Edge(id: EntityID) : IntEntity(id){ + companion object : IntEntityClass(Edges) + var element by Edges.element + var first by Vertex optionalReferencedOn Edges.first + var second by Vertex optionalReferencedOn Edges.second } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt b/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt index 26b8576..5b211bb 100644 --- a/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt +++ b/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt @@ -1,4 +1,13 @@ package databases.sqlite.dao.vertices -class Vertex { +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID + +class Vertex(id: EntityID) : IntEntity(id) { + + companion object : IntEntityClass(Vertices) + + var element by Vertices.element + var community by Vertices.community } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt b/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt index c2583e6..2de54e2 100644 --- a/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt +++ b/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt @@ -1,4 +1,18 @@ package databases.sqlite.dao.verticesView -class VertexView { + +import databases.sqlite.dao.vertices.Vertex +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID + +class VertexView(id: EntityID) : IntEntity(id) { + + companion object : IntEntityClass(VerticesView) + + var vertex by Vertex optionalReferencedOn VerticesView.vertex + var x by VerticesView.x + var y by VerticesView.y + var r by VerticesView.r + var color by VerticesView.color } \ No newline at end of file From cc6d4d91c01028f4280822344394676e4f11f8a5 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 14 May 2024 13:31:39 +0000 Subject: [PATCH 053/211] feat: create blank classes for viewmodel --- src/main/kotlin/viewmodel/Canvas.kt | 2 ++ src/main/kotlin/viewmodel/graph/Edge.kt | 4 ++++ src/main/kotlin/viewmodel/graph/Graph.kt | 4 ++++ src/main/kotlin/viewmodel/graph/Vertex.kt | 4 ++++ src/main/kotlin/viewmodel/layouts/CircularLayout.kt | 4 ++++ src/main/kotlin/viewmodel/layouts/TsNETLayout.kt | 4 ++++ 6 files changed, 22 insertions(+) create mode 100644 src/main/kotlin/viewmodel/Canvas.kt create mode 100644 src/main/kotlin/viewmodel/graph/Edge.kt create mode 100644 src/main/kotlin/viewmodel/graph/Graph.kt create mode 100644 src/main/kotlin/viewmodel/graph/Vertex.kt create mode 100644 src/main/kotlin/viewmodel/layouts/CircularLayout.kt create mode 100644 src/main/kotlin/viewmodel/layouts/TsNETLayout.kt diff --git a/src/main/kotlin/viewmodel/Canvas.kt b/src/main/kotlin/viewmodel/Canvas.kt new file mode 100644 index 0000000..e3828d9 --- /dev/null +++ b/src/main/kotlin/viewmodel/Canvas.kt @@ -0,0 +1,2 @@ +package viewmodel + diff --git a/src/main/kotlin/viewmodel/graph/Edge.kt b/src/main/kotlin/viewmodel/graph/Edge.kt new file mode 100644 index 0000000..ca03dbb --- /dev/null +++ b/src/main/kotlin/viewmodel/graph/Edge.kt @@ -0,0 +1,4 @@ +package viewmodel.graph + +class Edge { +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/Graph.kt b/src/main/kotlin/viewmodel/graph/Graph.kt new file mode 100644 index 0000000..363116f --- /dev/null +++ b/src/main/kotlin/viewmodel/graph/Graph.kt @@ -0,0 +1,4 @@ +package viewmodel.graph + +class Graph { +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/Vertex.kt b/src/main/kotlin/viewmodel/graph/Vertex.kt new file mode 100644 index 0000000..a691a13 --- /dev/null +++ b/src/main/kotlin/viewmodel/graph/Vertex.kt @@ -0,0 +1,4 @@ +package viewmodel.graph + +class Vertex { +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt new file mode 100644 index 0000000..3de32d2 --- /dev/null +++ b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt @@ -0,0 +1,4 @@ +package viewmodel.layouts + +class CircularLayout { +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/layouts/TsNETLayout.kt b/src/main/kotlin/viewmodel/layouts/TsNETLayout.kt new file mode 100644 index 0000000..fa631c2 --- /dev/null +++ b/src/main/kotlin/viewmodel/layouts/TsNETLayout.kt @@ -0,0 +1,4 @@ +package viewmodel.layouts + +class TsNETLayout { +} \ No newline at end of file From 0f4341642617a5988735614583753bf9188a5fa3 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 14 May 2024 15:57:33 +0000 Subject: [PATCH 054/211] feat: add viewmodel for graph --- src/main/kotlin/graph/model/Graph.kt | 4 +- src/main/kotlin/viewmodel/graph/Edge.kt | 4 -- .../kotlin/viewmodel/graph/EdgeViewModel.kt | 17 +++++++ src/main/kotlin/viewmodel/graph/Graph.kt | 4 -- .../kotlin/viewmodel/graph/GraphViewModel.kt | 44 +++++++++++++++++ src/main/kotlin/viewmodel/graph/Vertex.kt | 4 -- .../kotlin/viewmodel/graph/VertexViewModel.kt | 48 +++++++++++++++++++ 7 files changed, 111 insertions(+), 14 deletions(-) delete mode 100644 src/main/kotlin/viewmodel/graph/Edge.kt create mode 100644 src/main/kotlin/viewmodel/graph/EdgeViewModel.kt delete mode 100644 src/main/kotlin/viewmodel/graph/Graph.kt create mode 100644 src/main/kotlin/viewmodel/graph/GraphViewModel.kt delete mode 100644 src/main/kotlin/viewmodel/graph/Vertex.kt create mode 100644 src/main/kotlin/viewmodel/graph/VertexViewModel.kt diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt index 65e1f65..6c87470 100644 --- a/src/main/kotlin/graph/model/Graph.kt +++ b/src/main/kotlin/graph/model/Graph.kt @@ -5,9 +5,9 @@ class Graph{ val vertices = hashMapOf() val edges = hashMapOf() - fun vertices(): Collection = vertices.values + fun getVertices(): Collection = vertices.values - fun edges(): Collection = edges.values + fun getEdges(): Collection = edges.values fun addVertex(id: Int, v: String): Vertex = vertices.getOrPut(id) { Vertex(v) } diff --git a/src/main/kotlin/viewmodel/graph/Edge.kt b/src/main/kotlin/viewmodel/graph/Edge.kt deleted file mode 100644 index ca03dbb..0000000 --- a/src/main/kotlin/viewmodel/graph/Edge.kt +++ /dev/null @@ -1,4 +0,0 @@ -package viewmodel.graph - -class Edge { -} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt new file mode 100644 index 0000000..dd11a73 --- /dev/null +++ b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt @@ -0,0 +1,17 @@ +package viewmodel.graph + +import androidx.compose.runtime.State +import graph.model.Edge + +class EdgeViewModel( + val u: VertexViewModel, + val v: VertexViewModel, + private val e: Edge, + private val _labelVisible: State, +) { + val weight + get() = e.weight.toString() + + val labelVisible + get() = _labelVisible.value +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/Graph.kt b/src/main/kotlin/viewmodel/graph/Graph.kt deleted file mode 100644 index 363116f..0000000 --- a/src/main/kotlin/viewmodel/graph/Graph.kt +++ /dev/null @@ -1,4 +0,0 @@ -package viewmodel.graph - -class Graph { -} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt new file mode 100644 index 0000000..6fdd743 --- /dev/null +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -0,0 +1,44 @@ +package viewmodel.graph + +import androidx.compose.runtime.State +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import graph.model.Edge +import graph.model.Graph +import graph.model.Vertex + + +class GraphViewModel( + private val graph: Graph, + showVerticesLabels: State, + showEdgesLabels: State, +) { + private val verticesView: HashMap = hashMapOf() + init { + graph.getVertices().forEach { vertex -> + verticesView[vertex] = VertexViewModel(0.dp, 0.dp, Color.Blue, vertex, showVerticesLabels) + } + } + + private val edgesView: HashMap = hashMapOf() + init { + graph.getEdges().forEach { edge -> + val fst = verticesView[graph.vertices[edge.vertices.first]] + ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.first} not found") + val snd = verticesView[graph.vertices[edge.vertices.second]] + ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.second} not found") + EdgeViewModel(fst, snd, edge, showEdgesLabels) + } + } + + + val verticesViewValues: Collection + get() = verticesView.values + + val edgesViewValues: Collection + get() = edgesView.values + +} + + + diff --git a/src/main/kotlin/viewmodel/graph/Vertex.kt b/src/main/kotlin/viewmodel/graph/Vertex.kt deleted file mode 100644 index a691a13..0000000 --- a/src/main/kotlin/viewmodel/graph/Vertex.kt +++ /dev/null @@ -1,4 +0,0 @@ -package viewmodel.graph - -class Vertex { -} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt new file mode 100644 index 0000000..333ebf4 --- /dev/null +++ b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt @@ -0,0 +1,48 @@ +package viewmodel.graph + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import graph.model.Vertex + +class VertexViewModel( + x: Dp = 0.dp, + y: Dp = 0.dp, + color: Color, + private val v: Vertex, + private val _labelVisible: State, + val radius: Dp = 25.dp +) { + private var _x = mutableStateOf(x) + var x: Dp + get() = _x.value + set(value) { + _x.value = value + } + private var _y = mutableStateOf(y) + var y: Dp + get() = _y.value + set(value) { + _y.value = value + } + private var _color = mutableStateOf(color) + var color: Color + get() = _color.value + set(value) { + _color.value = value + } + + val label + get() = v.data + + val labelVisible + get() = _labelVisible.value + + fun onDrag(offset: Offset) { + _x.value += offset.x.dp + _y.value += offset.y.dp + } +} \ No newline at end of file From 21179ce472c97075de0fa5f63ebd3ba9e0abc2e5 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 14 May 2024 16:44:23 +0000 Subject: [PATCH 055/211] feat: raw version of circular layout --- .../viewmodel/layouts/CircularLayout.kt | 53 ++++++++++++++++++- .../layouts/RepresentationStrategy.kt | 8 +++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt diff --git a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt index 3de32d2..759a45f 100644 --- a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt +++ b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt @@ -1,4 +1,55 @@ package viewmodel.layouts -class CircularLayout { +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import viewmodel.graph.VertexViewModel +import kotlin.math.cos +import kotlin.math.min +import kotlin.math.sin +import kotlin.random.Random + +class CircularLayout: RepresentationStrategy { + override fun place(width: Double, height: Double, vertices: Collection) { + if (vertices.isEmpty()) { + println("CircularPlacementStrategy.place: there is nothing to place 👐🏻") + return + } + + val center = Pair(width / 2, height / 2) + val angle = 2 * Math.PI / vertices.size + + val sorted = vertices.sortedBy { it.label } + val first = sorted.first() + var point = Pair(center.first, center.second - min(width, height) / 2) + first.x = point.first.dp + first.y = point.second.dp + first.color = Color.Gray + + sorted + .drop(1) + .onEach { + point = point.rotate(center, angle) + it.x = point.first.dp + it.y = point.second.dp + } + } + + override fun highlight(vertices: Collection) { + vertices + .onEach { + it.color = if (Random.nextBoolean()) Color.Green else Color.Blue + } + } + + private fun Pair.rotate(pivot: Pair, angle: Double): Pair { + val sin = sin(angle) + val cos = cos(angle) + + val diff = first - pivot.first to second - pivot.second + val rotated = Pair( + diff.first * cos - diff.second * sin, + diff.first * sin + diff.second * cos, + ) + return rotated.first + pivot.first to rotated.second + pivot.second + } } \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt new file mode 100644 index 0000000..655fd11 --- /dev/null +++ b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt @@ -0,0 +1,8 @@ +package viewmodel.layouts + +import viewmodel.graph.VertexViewModel + +interface RepresentationStrategy { + fun place(width: Double, height: Double, vertices: Collection) + fun highlight(vertices: Collection) +} \ No newline at end of file From 4c0f611bd4147faa5a8c1407967e90ea6851b41c Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 14 May 2024 17:09:44 +0000 Subject: [PATCH 056/211] feat: add canvas view model --- src/main/kotlin/viewmodel/Canvas.kt | 2 -- src/main/kotlin/viewmodel/CanvasViewModel.kt | 26 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) delete mode 100644 src/main/kotlin/viewmodel/Canvas.kt create mode 100644 src/main/kotlin/viewmodel/CanvasViewModel.kt diff --git a/src/main/kotlin/viewmodel/Canvas.kt b/src/main/kotlin/viewmodel/Canvas.kt deleted file mode 100644 index e3828d9..0000000 --- a/src/main/kotlin/viewmodel/Canvas.kt +++ /dev/null @@ -1,2 +0,0 @@ -package viewmodel - diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt new file mode 100644 index 0000000..ce5a618 --- /dev/null +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -0,0 +1,26 @@ +package viewmodel + +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.graphics.Color +import graph.model.Graph +import viewmodel.graph.GraphViewModel +import viewmodel.layouts.RepresentationStrategy + +class CanvasViewModel(graph: Graph, private val representationStrategy: RepresentationStrategy,) { + private val showVerticesLabels = mutableStateOf(false) + private val showEdgesLabels = mutableStateOf(false) + private val graphViewModel = GraphViewModel(graph, showVerticesLabels, showEdgesLabels) + + init { + representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) + } + + fun resetGraphView() { + representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) + graphViewModel.verticesViewValues.forEach{ v -> v.color = Color.Gray} + } + + fun setVerticesColor() { + representationStrategy.highlight(graphViewModel.verticesViewValues) + } +} \ No newline at end of file From 7fcf00075a0b2216d38b762696531c0ed36f0ea2 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 14 May 2024 17:30:01 +0000 Subject: [PATCH 057/211] feat: add classes for view --- src/main/kotlin/view/CanvasView.kt | 2 ++ src/main/kotlin/view/graph/Edge.kt | 2 ++ src/main/kotlin/view/graph/Graph.kt | 2 ++ src/main/kotlin/view/graph/Vertex.kt | 2 ++ 4 files changed, 8 insertions(+) create mode 100644 src/main/kotlin/view/CanvasView.kt create mode 100644 src/main/kotlin/view/graph/Edge.kt create mode 100644 src/main/kotlin/view/graph/Graph.kt create mode 100644 src/main/kotlin/view/graph/Vertex.kt diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt new file mode 100644 index 0000000..8d8a2bb --- /dev/null +++ b/src/main/kotlin/view/CanvasView.kt @@ -0,0 +1,2 @@ +package view + diff --git a/src/main/kotlin/view/graph/Edge.kt b/src/main/kotlin/view/graph/Edge.kt new file mode 100644 index 0000000..85f6005 --- /dev/null +++ b/src/main/kotlin/view/graph/Edge.kt @@ -0,0 +1,2 @@ +package view.graph + diff --git a/src/main/kotlin/view/graph/Graph.kt b/src/main/kotlin/view/graph/Graph.kt new file mode 100644 index 0000000..85f6005 --- /dev/null +++ b/src/main/kotlin/view/graph/Graph.kt @@ -0,0 +1,2 @@ +package view.graph + diff --git a/src/main/kotlin/view/graph/Vertex.kt b/src/main/kotlin/view/graph/Vertex.kt new file mode 100644 index 0000000..85f6005 --- /dev/null +++ b/src/main/kotlin/view/graph/Vertex.kt @@ -0,0 +1,2 @@ +package view.graph + From 7e33bfc67c4bf5c2631a24768c06f6f7cec17e28 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 14 May 2024 18:11:35 +0000 Subject: [PATCH 058/211] fix: repair some bugs --- src/main/kotlin/algorithms/KruskalsAlgorithm.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt index 3cb3367..6e809f7 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -7,7 +7,7 @@ class KruskalsMST { private fun kruskals(graph: Graph) { var j = 0 var noOfEdges = 0 - val V = graph.vertices().size + val V = graph.getVertices().size val subsets = arrayOfNulls(V) From cb36f93b601218ed37e0db7cf9fa5363303738bf Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 15 May 2024 12:34:47 +0000 Subject: [PATCH 059/211] feat: add view for canvas --- src/main/kotlin/view/CanvasView.kt | 55 ++++++++++++++++++++ src/main/kotlin/viewmodel/CanvasViewModel.kt | 6 +-- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 8d8a2bb..19d5acc 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,2 +1,57 @@ package view +import androidx.compose.foundation.layout.* +import androidx.compose.material.Button +import androidx.compose.material.Checkbox +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import viewmodel.CanvasViewModel + +@Composable +fun Canvas(viewModel: CanvasViewModel) { + Row( + horizontalArrangement = Arrangement.spacedBy(20.dp) + ) { + Column(modifier = Modifier.width(370.dp)) { + Row { + Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { + viewModel.showVerticesLabels.value = it + }) + Text("Show vertices labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) + } + Row { + Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { + viewModel.showEdgesLabels.value = it + }) + Text("Show edges labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) + } + Button( + onClick = viewModel::resetGraphView, + enabled = true, + ) { + Text( + text = "Reset default settings", + ) + } + Button( + onClick = viewModel::setVerticesColor, + enabled = true, + ) { + Text( + text = "Set colors", + ) + } + } + + Surface( + modifier = Modifier.weight(1f), + ) { + GraphView(viewModel.graphViewModel) + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index ce5a618..e579bf6 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -7,9 +7,9 @@ import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy class CanvasViewModel(graph: Graph, private val representationStrategy: RepresentationStrategy,) { - private val showVerticesLabels = mutableStateOf(false) - private val showEdgesLabels = mutableStateOf(false) - private val graphViewModel = GraphViewModel(graph, showVerticesLabels, showEdgesLabels) + val showVerticesLabels = mutableStateOf(false) + val showEdgesLabels = mutableStateOf(false) + val graphViewModel = GraphViewModel(graph, showVerticesLabels, showEdgesLabels) init { representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) From 8a863be1e626829bf451bef28eda480f54ba75f7 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 15 May 2024 13:13:02 +0000 Subject: [PATCH 060/211] feat: add view for graph --- src/main/kotlin/view/CanvasView.kt | 1 + src/main/kotlin/view/graph/Edge.kt | 2 -- src/main/kotlin/view/graph/EdgeView.kt | 41 +++++++++++++++++++++ src/main/kotlin/view/graph/Graph.kt | 2 -- src/main/kotlin/view/graph/GraphView.kt | 25 +++++++++++++ src/main/kotlin/view/graph/Vertex.kt | 2 -- src/main/kotlin/view/graph/VertexView.kt | 45 ++++++++++++++++++++++++ 7 files changed, 112 insertions(+), 6 deletions(-) delete mode 100644 src/main/kotlin/view/graph/Edge.kt create mode 100644 src/main/kotlin/view/graph/EdgeView.kt delete mode 100644 src/main/kotlin/view/graph/Graph.kt create mode 100644 src/main/kotlin/view/graph/GraphView.kt delete mode 100644 src/main/kotlin/view/graph/Vertex.kt create mode 100644 src/main/kotlin/view/graph/VertexView.kt diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 19d5acc..fa5d1e1 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import view.graph.GraphView import viewmodel.CanvasViewModel @Composable diff --git a/src/main/kotlin/view/graph/Edge.kt b/src/main/kotlin/view/graph/Edge.kt deleted file mode 100644 index 85f6005..0000000 --- a/src/main/kotlin/view/graph/Edge.kt +++ /dev/null @@ -1,2 +0,0 @@ -package view.graph - diff --git a/src/main/kotlin/view/graph/EdgeView.kt b/src/main/kotlin/view/graph/EdgeView.kt new file mode 100644 index 0000000..b4c47ff --- /dev/null +++ b/src/main/kotlin/view/graph/EdgeView.kt @@ -0,0 +1,41 @@ +package view.graph + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.material.Text +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import viewmodel.graph.EdgeViewModel + +@Composable +fun EdgeView( + viewModel: EdgeViewModel, + modifier: Modifier = Modifier, +) { + Canvas(modifier = modifier.fillMaxSize()) { + drawLine( + start = Offset( + viewModel.u.x.toPx() + viewModel.u.radius.toPx(), + viewModel.u.y.toPx() + viewModel.u.radius.toPx(), + ), + end = Offset( + viewModel.v.x.toPx() + viewModel.v.radius.toPx(), + viewModel.v.y.toPx() + viewModel.v.radius.toPx(), + ), + color = Color.Black + ) + } + if (viewModel.labelVisible) { + Text( + modifier = Modifier + .offset( + viewModel.u.x + (viewModel.v.x - viewModel.u.x) / 2, + viewModel.u.y + (viewModel.v.y - viewModel.u.y) / 2 + ), + text = viewModel.weight, + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/graph/Graph.kt b/src/main/kotlin/view/graph/Graph.kt deleted file mode 100644 index 85f6005..0000000 --- a/src/main/kotlin/view/graph/Graph.kt +++ /dev/null @@ -1,2 +0,0 @@ -package view.graph - diff --git a/src/main/kotlin/view/graph/GraphView.kt b/src/main/kotlin/view/graph/GraphView.kt new file mode 100644 index 0000000..4d75fa9 --- /dev/null +++ b/src/main/kotlin/view/graph/GraphView.kt @@ -0,0 +1,25 @@ +package view.graph + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import viewmodel.graph.GraphViewModel +import view.graph.Gra + +@Composable +fun GraphView( + viewModel: GraphViewModel, +) { + Box(modifier = Modifier + .fillMaxSize() + + ) { + viewModel.verticesViewValues.forEach { v -> + VertexView(v, Modifier) + } + viewModel.edgesViewValues.forEach { e -> + EdgeView(e, Modifier) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/graph/Vertex.kt b/src/main/kotlin/view/graph/Vertex.kt deleted file mode 100644 index 85f6005..0000000 --- a/src/main/kotlin/view/graph/Vertex.kt +++ /dev/null @@ -1,2 +0,0 @@ -package view.graph - diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt new file mode 100644 index 0000000..9a73efa --- /dev/null +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -0,0 +1,45 @@ +package view.graph + +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.detectDragGestures +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.material.Text +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.unit.dp +import viewmodel.graph.VertexViewModel + +@Composable +fun VertexView( + viewModel: VertexViewModel, + modifier: Modifier = Modifier, +) { + Box(modifier = modifier + .size(viewModel.radius * 2, viewModel.radius * 2) + .offset(viewModel.x, viewModel.y) + .background( + color = viewModel.color, + shape = CircleShape + ) + .pointerInput(viewModel) { + detectDragGestures { change, dragAmount -> + change.consume() + viewModel.onDrag(dragAmount) + } + } + ) { + if (viewModel.labelVisible) { + Text( + modifier = Modifier + .align(Alignment.Center) + .offset(0.dp, -viewModel.radius - 10.dp), + text = viewModel.label, + ) + } + } +} \ No newline at end of file From b19c18f80402e17d38f31443dc822c3d5f7166bb Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 15 May 2024 13:35:58 +0000 Subject: [PATCH 061/211] feat: add demo graph --- src/main/kotlin/Main.kt | 55 +++++++++++++++---- .../kotlin/algorithms/KruskalsAlgorithm.kt | 2 +- src/main/kotlin/view/graph/GraphView.kt | 1 - 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 5791b5a..9d88da6 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -9,24 +9,55 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import graph.model.Graph +import view.Canvas +import viewmodel.CanvasViewModel +import viewmodel.layouts.CircularLayout + +val sampleGraph: Graph = Graph().apply { + addVertex(1,"Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Vova Vinduz") + addVertex(4, "Maksim Rodionov") + addVertex(5, "Ilia ITMO") + addVertex(6, "Arthur Shelby") + addVertex(7, "Ryan Gosling") + + addEdge(1, 2, 1,1) + addEdge(3, 4, 2,2) + addEdge(1, 3, 3,3) + addEdge(2, 4, 4,4) + addEdge(2, 5, 5,5) + addEdge(5, 7, 6,6) + + addVertex(8, "Pudge") + addVertex(9,"Tiny") + addVertex(10, "Lycan") + addVertex(11,"Io") + addVertex(12,"Lion") + addVertex(13,"Sniper") + addVertex(14,"Roshan") + + addEdge(14, 8, 7,7) + addEdge(14, 9, 8,8) + addEdge(14, 10, 9,9) + addEdge(14, 11, 10,10) + addEdge(14, 12, 11,11) + addEdge(14, 13, 12,12) + + addEdge(14, 3, 0,13) +} @Composable @Preview fun App() { - var text by remember { mutableStateOf("Hello, World!") } - MaterialTheme { - Button(onClick = { - text = "Hello, Desktop!" - }) { - Text(text) - } + Canvas(CanvasViewModel(sampleGraph, CircularLayout())) } } -fun main() = - application { - Window(onCloseRequest = ::exitApplication) { - App() - } +fun main() = application { + Window(onCloseRequest = ::exitApplication) { + App() } +} \ No newline at end of file diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt index 3cb3367..6e809f7 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -7,7 +7,7 @@ class KruskalsMST { private fun kruskals(graph: Graph) { var j = 0 var noOfEdges = 0 - val V = graph.vertices().size + val V = graph.getVertices().size val subsets = arrayOfNulls(V) diff --git a/src/main/kotlin/view/graph/GraphView.kt b/src/main/kotlin/view/graph/GraphView.kt index 4d75fa9..8bb537e 100644 --- a/src/main/kotlin/view/graph/GraphView.kt +++ b/src/main/kotlin/view/graph/GraphView.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import viewmodel.graph.GraphViewModel -import view.graph.Gra @Composable fun GraphView( From ca691e2297035a5acbe79287f2233871d0f650fb Mon Sep 17 00:00:00 2001 From: dronshock Date: Fri, 17 May 2024 12:54:15 +0300 Subject: [PATCH 062/211] feat(ci): add ktfmt linter --- .github/formatter.yml | 12 ++++++++++++ build.gradle.kts | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 .github/formatter.yml diff --git a/.github/formatter.yml b/.github/formatter.yml new file mode 100644 index 0000000..39bbb09 --- /dev/null +++ b/.github/formatter.yml @@ -0,0 +1,12 @@ +name: formatter +on: [push, pull_request] +jobs: + check-formatted: + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v4 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + - name: Check formatter + run: ./gradlew ktfmtCheck \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index ab2a490..f561bbb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,6 +3,12 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat plugins { kotlin("jvm") id("org.jetbrains.compose") + id("com.ncorti.ktfmt.gradle") version "0.18.0" +} + +ktfmt { + // KotlinLang style - 4 space indentation - From kotlinlang.org/docs/coding-conventions.html + kotlinLangStyle() } group = "com.graph" @@ -43,4 +49,15 @@ tasks.withType { testLogging { events("PASSED", "SKIPPED", "FAILED") } + + tasks.register("copyPreCommitHook") { + description = "Copy pre-commit git hook from the scripts to the .git/hooks folder." + group = "git hooks" + outputs.upToDateWhen { false } + from("$rootDir/scripts/pre-commit") + into("$rootDir/.git/hooks/") + } + tasks.build { + dependsOn("copyPreCommitHook") + } } From c97136aa70858b2dd43a4ebab60f2f78209e74d8 Mon Sep 17 00:00:00 2001 From: dronshock Date: Fri, 17 May 2024 12:54:50 +0300 Subject: [PATCH 063/211] feat(ci): add pre-commit hook --- scripts/pre-commit | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 scripts/pre-commit diff --git a/scripts/pre-commit b/scripts/pre-commit new file mode 100644 index 0000000..a16b2f5 --- /dev/null +++ b/scripts/pre-commit @@ -0,0 +1,14 @@ +#!/bin/sh + +echo "> Task: ktfmtFormat" + +./gradlew ktfmtFormat + +echo "> Task: ktfmtCheck" + +./gradlew --no-daemon ktfmtCheck + + ktfmtCheckStatus=$? + +[ $ktfmtCheckStatus -ne 0 ] && exit 1 +exit 0 \ No newline at end of file From 77fb5221075f5918d08206e73ba094d640305455 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Fri, 17 May 2024 13:25:00 +0000 Subject: [PATCH 064/211] fix: reapair edge display --- src/main/kotlin/viewmodel/graph/GraphViewModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 6fdd743..f5ca25c 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -27,8 +27,10 @@ class GraphViewModel( ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.first} not found") val snd = verticesView[graph.vertices[edge.vertices.second]] ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.second} not found") - EdgeViewModel(fst, snd, edge, showEdgesLabels) + val currentEdgeView = EdgeViewModel(fst, snd, edge, showEdgesLabels) + edgesView[edge]=currentEdgeView } + } From 9636d39e1742f7fd9762aa6bb0d0b0d6580c398f Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Sat, 18 May 2024 09:28:14 +0000 Subject: [PATCH 065/211] fix(ci): remove approvals temporary change --- .github/mergeable.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index c925d36..9970859 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -17,7 +17,7 @@ mergeable: message: 'Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed.' - do: approvals min: - count: 1 + count: 0 block: changes_requested: true limit: From 83a74e26b2235312c0b1aa37fb252e2a9b74dbe3 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 19 May 2024 22:17:13 +0300 Subject: [PATCH 066/211] feat(algo): kosaraju algo returns component's --- src/main/kotlin/algorithms/Kosaraju.kt | 63 ++++++++++++-------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index 4a29995..770ec7c 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -2,81 +2,78 @@ package algorithms import graph.model.Graph -class Kosaraju(private val graph: Graph) { +class Kosaraju(private val graph: Graph) { private val used = hashMapOf() private val order = mutableListOf() private val component = mutableListOf() - fun findStronglyConnectedComponents() { - graph.vertices.keys.forEach { used[it] = false } + fun findStronglyConnectedComponents(): List> { - // 1-st dfs for topology sort - for (vertexID in graph.vertices.keys) { + // Step 1: Transpose the graph + val transposedGraph = transposeGraph() + + // Step 2: Topology sort transposed graph + for (vertexID in transposedGraph.vertices.keys) { if (used[vertexID] != true) { - dfs1(vertexID) + topologySort(transposedGraph, vertexID) } } - val transposedGraph = transposeGraph() - - // clear is visited - used.keys.forEach { used[it] = false } - - // 2-nd dfs for component search + // Step 3: DFS to find strongly connected components + val components = mutableListOf>() + used.clear() for (vertexID in order.reversed()) { if (used[vertexID] != true) { component.clear() - dfs2(transposedGraph,vertexID) - // todo println("Компонента сильной связности: $component") + dfs(vertexID) + components.add(component.toList()) } } + + return components } - private fun dfs1(vertexID: Int) { + private fun topologySort(graph: Graph, vertexID: Int) { used[vertexID] = true val vertex = graph.vertices[vertexID] ?: return for (edgeID in vertex.incidentEdges) { val edge = graph.edges[edgeID] ?: continue val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first if (used[nextVertexID] != true) { - dfs1(nextVertexID) + topologySort(graph, nextVertexID) } } order.add(vertexID) } - fun Test_dfs1(vertexID: Int) : MutableList { - dfs1(vertexID) - return order - } - - private fun dfs2(transposedGraph: Graph, vertexID: Int) { + private fun dfs(vertexID: Int) { used[vertexID] = true component.add(vertexID) - val vertex = transposedGraph.vertices[vertexID] ?: return + val vertex = graph.vertices[vertexID] ?: return for (edgeID in vertex.incidentEdges) { - val edge = transposedGraph.edges[edgeID] ?: continue - val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first + val edge = graph.edges[edgeID] ?: continue + val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else continue if (used[nextVertexID] != true) { - dfs2(transposedGraph, nextVertexID) + dfs(nextVertexID) } } } private fun transposeGraph(): Graph { val transposedGraph = Graph() - transposedGraph.isDirected = graph.isDirected + transposedGraph.isDirected = true // Transposed graph is always directed - // Добавление вершин - graph.vertices.forEach { (id, vertex) -> + // Add vertices to the transposed graph + for ((id, vertex) in graph.vertices) { transposedGraph.addVertex(id, vertex.data) } - // Добавление рёбер с изменённым направлением - graph.edges.forEach { (id, edge) -> - transposedGraph.addEdge(edge.vertices.second, edge.vertices.first, edge.weight, id) + // Add edges with reversed direction to the transposed graph + for ((id, edge) in graph.edges) { + val (firstVertexID, secondVertexID) = edge.vertices + transposedGraph.addEdge(secondVertexID, firstVertexID, edge.weight, id) } return transposedGraph } -} +} \ No newline at end of file From 5669f9349cc7dc030d8377991fbfbe8c3a0bd219 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:03:25 +0300 Subject: [PATCH 067/211] feat(algo): djikstra algo skeleton added --- src/main/kotlin/algorithms/Djikstra.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/kotlin/algorithms/Djikstra.kt diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt new file mode 100644 index 0000000..4a28640 --- /dev/null +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -0,0 +1,9 @@ +package algorithms + +import graph.model.Graph + +class Djikstra(private val graph: Graph) { + private val distance = hashMapOf() + private val visited = hashMapOf() + private val from = hashMapOf() +} \ No newline at end of file From f3cfd50c3dc92172caf7ba12c3e67974cbec6952 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:04:05 +0300 Subject: [PATCH 068/211] feat(algo): djikstra algo findPath's method added --- src/main/kotlin/algorithms/Djikstra.kt | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index 4a28640..031ddde 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -6,4 +6,40 @@ class Djikstra(private val graph: Graph) { private val distance = hashMapOf() private val visited = hashMapOf() private val from = hashMapOf() + + fun findShortestPaths(startVertexID: Int) { + val n = graph.vertices.size + + for ((id, _) in graph.vertices) { + distance[id] = Long.MAX_VALUE + from[id] = -1 + } + + distance[startVertexID] = 0 + + for (i in 0 until n) { + + var nearest = -1 + for ((vertexID, _) in graph.vertices) { + if (!visited.getOrDefault(vertexID, false) && (nearest == -1 || distance[vertexID]!! < distance[vertexID]!!)) { + nearest = vertexID + } + } + visited[nearest] = true + + if (distance[nearest] == Long.MAX_VALUE) break + + for (edgeID in graph.vertices[nearest]!!.incidentEdges) { + val edge = graph.edges[edgeID]!! + + val to = if (nearest == edge.vertices.first) edge.vertices.second else edge.vertices.first + val weight = edge.weight + + if (distance[nearest]!! + weight < distance[to]!!) { + distance[to] = distance[nearest]!! + weight + from[to] = nearest + } + } + } + } } \ No newline at end of file From 7c230cdf513e4a8c605b5572e169f60e6ba4b618 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:05:08 +0300 Subject: [PATCH 069/211] feat(algo): djikstra algo reconstructPath method added --- src/main/kotlin/algorithms/Djikstra.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index 031ddde..975f49a 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -42,4 +42,18 @@ class Djikstra(private val graph: Graph) { } } } + + fun reconstructPath(startVertexID: Int, endVertexID: Int): List { + val path = mutableListOf() + var finish = endVertexID + + while (finish != startVertexID) { + path.add(finish) + finish = from[finish] ?: break + } + + path.add(startVertexID) + path.reverse() + return path + } } \ No newline at end of file From 8128c411be3f170235f1bfdad0a5465c213fa210 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:06:26 +0300 Subject: [PATCH 070/211] feat(tests): djikstra test added --- src/test/kotlin/graphs/DjikstraTest.kt | 57 ++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/test/kotlin/graphs/DjikstraTest.kt diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt new file mode 100644 index 0000000..9439237 --- /dev/null +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -0,0 +1,57 @@ +package graphs + +import algorithms.Djikstra +import graph.model.Graph +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Assertions.* + +// table of path's +// _________________________________________________________ +// |_iteration_|____S_____|__w__|_D[2]_|_D[3]_|_D[4]_|_D[5]_| +// |___start___|___{1}____|__-__|__10__|_+00__|__30__|_100__| +// |_____1_____|__{1,2}___|__2__|__10__|__60__|__30__|_100__| +// |_____2_____|_{1,2,4}__|__4__|__10__|__50__|__30__|__90__| +// |_____3_____|{1,2,4,3}_|__3__|__10__|__50__|__30__|__60__| +// |_____4_____|_1,2,4,3,5|__5__|__10__|__50__|__30__|__60__| +// + +fun createSampleGraphDjikstra(): Graph { + val graph = Graph() + + graph.addVertex(1, "A") + graph.addVertex(2, "B") + graph.addVertex(3, "C") + graph.addVertex(4, "D") + graph.addVertex(5, "E") + + graph.addEdge(1, 2, 10L, 0) + graph.addEdge(1, 5, 100L, 1) + graph.addEdge(1, 4, 30L, 2) + graph.addEdge(2, 3, 50L, 3) + graph.addEdge(3, 5, 10L, 4) + graph.addEdge(4, 3, 20L, 5) + graph.addEdge(4, 5, 60L, 6) + + return graph +} + +class DjikstraTest { + private val graph = createSampleGraphDjikstra() + + @Test + fun `test findShortestPaths with sample graph start from 1 to 5 started from 1`() { + // graph and algo initialization + val expected = mutableListOf(1,4,3,5) + val algorithm = Djikstra(graph) + // path created from 1 + algorithm.findShortestPaths(1) + + + // algo start from different positions + val currently = algorithm.reconstructPath(1,5) + + // Проверьте результаты + assertTrue(expected == currently) + } + +} \ No newline at end of file From 18de6c7c39880dd4b31e0f9693cd62c76914e5e8 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:06:43 +0300 Subject: [PATCH 071/211] feat(tests): djikstra test added --- src/test/kotlin/graphs/DjikstraTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index 9439237..8ea22de 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -54,4 +54,19 @@ class DjikstraTest { assertTrue(expected == currently) } + @Test + fun `test findShortestPaths with sample graph start from 1 to 2`() { + // graph and algo initialization + val expected = mutableListOf(1,2) + val algorithm = Djikstra(graph) + algorithm.findShortestPaths(1) + + + // algo start from different positions + val currently = algorithm.reconstructPath(1,2) + + // Проверьте результаты + assertTrue(expected == currently) + } + } \ No newline at end of file From 0e432725c4606af27b2bcb8b73d1ca88e648cd36 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:23:29 +0300 Subject: [PATCH 072/211] fix(algo): djikstra returns correct path --- src/test/kotlin/graphs/DjikstraTest.kt | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index 8ea22de..e56d414 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -15,8 +15,9 @@ import org.junit.jupiter.api.Assertions.* // |_____4_____|_1,2,4,3,5|__5__|__10__|__50__|__30__|__60__| // -fun createSampleGraphDjikstra(): Graph { +fun createSampleGraphDjikstraDirected(): Graph { val graph = Graph() + graph.isDirected = true graph.addVertex(1, "A") graph.addVertex(2, "B") @@ -36,8 +37,7 @@ fun createSampleGraphDjikstra(): Graph { } class DjikstraTest { - private val graph = createSampleGraphDjikstra() - + private val graph = createSampleGraphDjikstraDirected() @Test fun `test findShortestPaths with sample graph start from 1 to 5 started from 1`() { // graph and algo initialization @@ -47,10 +47,8 @@ class DjikstraTest { algorithm.findShortestPaths(1) - // algo start from different positions val currently = algorithm.reconstructPath(1,5) - // Проверьте результаты assertTrue(expected == currently) } @@ -61,12 +59,24 @@ class DjikstraTest { val algorithm = Djikstra(graph) algorithm.findShortestPaths(1) + val currently = algorithm.reconstructPath(1,2) + + assertTrue(expected == currently) + } + + @Test + fun `test findShortestPaths with sample graph start from 2 to 3 started from 2`() { + // graph and algo initialization + val expected = mutableListOf(2,3) + val algorithm = Djikstra(graph) + // path created from 2 + algorithm.findShortestPaths(2) + // algo start from different positions - val currently = algorithm.reconstructPath(1,2) + val currently = algorithm.reconstructPath(2,3) // Проверьте результаты assertTrue(expected == currently) } - } \ No newline at end of file From fb9729b8b2e885f7694d52ac19b3bc984ca191ac Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:25:17 +0300 Subject: [PATCH 073/211] fix(algo): djikstra returns correct path --- src/main/kotlin/algorithms/Djikstra.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index 975f49a..6618c7b 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -2,12 +2,12 @@ package algorithms import graph.model.Graph -class Djikstra(private val graph: Graph) { +class Djikstra(private val graph: Graph, private val startVertexID: Int) { private val distance = hashMapOf() private val visited = hashMapOf() private val from = hashMapOf() - fun findShortestPaths(startVertexID: Int) { + fun findShortestPaths() { val n = graph.vertices.size for ((id, _) in graph.vertices) { @@ -21,7 +21,7 @@ class Djikstra(private val graph: Graph) { var nearest = -1 for ((vertexID, _) in graph.vertices) { - if (!visited.getOrDefault(vertexID, false) && (nearest == -1 || distance[vertexID]!! < distance[vertexID]!!)) { + if (!visited.getOrDefault(vertexID, false) && (nearest == -1 || distance[vertexID]!! < distance[nearest]!!)) { nearest = vertexID } } @@ -43,12 +43,16 @@ class Djikstra(private val graph: Graph) { } } - fun reconstructPath(startVertexID: Int, endVertexID: Int): List { + fun reconstructPath(endVertexID: Int): List { val path = mutableListOf() var finish = endVertexID while (finish != startVertexID) { path.add(finish) + if (finish == -1) { + path.clear() + return path + } finish = from[finish] ?: break } From 5ca67673594519d5a3ac3c797e386336c8db5468 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:26:20 +0300 Subject: [PATCH 074/211] feat(tests): djikstra directed tests added --- src/test/kotlin/graphs/DjikstraTest.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index e56d414..61c8101 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -42,12 +42,12 @@ class DjikstraTest { fun `test findShortestPaths with sample graph start from 1 to 5 started from 1`() { // graph and algo initialization val expected = mutableListOf(1,4,3,5) - val algorithm = Djikstra(graph) + val algorithm = Djikstra(graph,1) // path created from 1 - algorithm.findShortestPaths(1) + algorithm.findShortestPaths() - val currently = algorithm.reconstructPath(1,5) + val currently = algorithm.reconstructPath(5) assertTrue(expected == currently) } @@ -56,10 +56,10 @@ class DjikstraTest { fun `test findShortestPaths with sample graph start from 1 to 2`() { // graph and algo initialization val expected = mutableListOf(1,2) - val algorithm = Djikstra(graph) - algorithm.findShortestPaths(1) + val algorithm = Djikstra(graph, 1) + algorithm.findShortestPaths() - val currently = algorithm.reconstructPath(1,2) + val currently = algorithm.reconstructPath(2) assertTrue(expected == currently) } @@ -68,13 +68,13 @@ class DjikstraTest { fun `test findShortestPaths with sample graph start from 2 to 3 started from 2`() { // graph and algo initialization val expected = mutableListOf(2,3) - val algorithm = Djikstra(graph) + val algorithm = Djikstra(graph,2) // path created from 2 - algorithm.findShortestPaths(2) + algorithm.findShortestPaths() // algo start from different positions - val currently = algorithm.reconstructPath(2,3) + val currently = algorithm.reconstructPath(3) // Проверьте результаты assertTrue(expected == currently) From f5bea9eb2dd3a64dade3025d48cd3aed2800a364 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:27:43 +0300 Subject: [PATCH 075/211] feat(tests): djikstra directed tests added --- src/test/kotlin/graphs/DjikstraTest.kt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index 61c8101..28b767d 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -36,6 +36,8 @@ fun createSampleGraphDjikstraDirected(): Graph { return graph } + + class DjikstraTest { private val graph = createSampleGraphDjikstraDirected() @Test @@ -73,10 +75,21 @@ class DjikstraTest { algorithm.findShortestPaths() - // algo start from different positions val currently = algorithm.reconstructPath(3) - // Проверьте результаты + assertTrue(expected == currently) + } + + @Test + fun `test findShortestPaths path does not exist`() { + // graph and algo initialization + val expected = mutableListOf() + val algorithm = Djikstra(graph,2) + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(1) + assertTrue(expected == currently) } } \ No newline at end of file From 39bb2897c8faf571665a70c6938b43c691403590 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:30:24 +0300 Subject: [PATCH 076/211] feat(tests): djikstra not directed tests added --- src/test/kotlin/graphs/DjikstraTest.kt | 44 +++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index 28b767d..607916d 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -36,15 +36,36 @@ fun createSampleGraphDjikstraDirected(): Graph { return graph } +fun createSampleGraphDjikstra(): Graph { + val graph = Graph() + graph.isDirected = false + + graph.addVertex(1, "A") + graph.addVertex(2, "B") + graph.addVertex(3, "C") + graph.addVertex(4, "D") + graph.addVertex(5, "E") + + graph.addEdge(1, 2, 10L, 0) + graph.addEdge(1, 5, 100L, 1) + graph.addEdge(1, 4, 30L, 2) + graph.addEdge(2, 3, 50L, 3) + graph.addEdge(3, 5, 10L, 4) + graph.addEdge(4, 3, 20L, 5) + graph.addEdge(4, 5, 60L, 6) + return graph +} class DjikstraTest { - private val graph = createSampleGraphDjikstraDirected() + private val graphD = createSampleGraphDjikstraDirected() + private val graph = createSampleGraphDjikstra() + @Test fun `test findShortestPaths with sample graph start from 1 to 5 started from 1`() { // graph and algo initialization val expected = mutableListOf(1,4,3,5) - val algorithm = Djikstra(graph,1) + val algorithm = Djikstra(graphD,1) // path created from 1 algorithm.findShortestPaths() @@ -58,7 +79,7 @@ class DjikstraTest { fun `test findShortestPaths with sample graph start from 1 to 2`() { // graph and algo initialization val expected = mutableListOf(1,2) - val algorithm = Djikstra(graph, 1) + val algorithm = Djikstra(graphD, 1) algorithm.findShortestPaths() val currently = algorithm.reconstructPath(2) @@ -70,7 +91,7 @@ class DjikstraTest { fun `test findShortestPaths with sample graph start from 2 to 3 started from 2`() { // graph and algo initialization val expected = mutableListOf(2,3) - val algorithm = Djikstra(graph,2) + val algorithm = Djikstra(graphD,2) // path created from 2 algorithm.findShortestPaths() @@ -84,12 +105,25 @@ class DjikstraTest { fun `test findShortestPaths path does not exist`() { // graph and algo initialization val expected = mutableListOf() + val algorithm = Djikstra(graphD,2) + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(1) + + assertTrue(expected == currently) + } + + @Test + fun `test findShortestPaths from 2 to 1 not directed graph`() { + // graph and algo initialization + val expected = mutableListOf(2,1) val algorithm = Djikstra(graph,2) // path created from 2 algorithm.findShortestPaths() val currently = algorithm.reconstructPath(1) - + assertTrue(expected == currently) } } \ No newline at end of file From f2a7cb976f33580277795d540ca15c04b4a783a7 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:32:11 +0300 Subject: [PATCH 077/211] feat(tests): djikstra not directed tests added --- src/test/kotlin/graphs/DjikstraTest.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index 607916d..509ae4e 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -126,4 +126,17 @@ class DjikstraTest { assertTrue(expected == currently) } + + @Test + fun `test findShortestPaths from 5 to 1 not directed graph`() { + // graph and algo initialization + val expected = mutableListOf(5,3,4,1) + val algorithm = Djikstra(graph,5) + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(1) + + assertTrue(expected == currently) + } } \ No newline at end of file From 67d843caf01d98bd6293da97e11083ec432ee7de Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:36:02 +0300 Subject: [PATCH 078/211] feat(algo): djikstra compute empty-edged graph --- src/main/kotlin/algorithms/Djikstra.kt | 6 ++++-- src/test/kotlin/graphs/DjikstraTest.kt | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index 6618c7b..51064a1 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -2,13 +2,14 @@ package algorithms import graph.model.Graph -class Djikstra(private val graph: Graph, private val startVertexID: Int) { +class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { private val distance = hashMapOf() private val visited = hashMapOf() private val from = hashMapOf() + private val n = graph.vertices.size fun findShortestPaths() { - val n = graph.vertices.size + if (n == 0) return for ((id, _) in graph.vertices) { distance[id] = Long.MAX_VALUE @@ -46,6 +47,7 @@ class Djikstra(private val graph: Graph, private val startVertexID: Int) { fun reconstructPath(endVertexID: Int): List { val path = mutableListOf() var finish = endVertexID + if (n == 0) return path while (finish != startVertexID) { path.add(finish) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index 509ae4e..4fc5c95 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -139,4 +139,19 @@ class DjikstraTest { assertTrue(expected == currently) } + + @Test + fun `test findShortestPaths empty-edged graph`() { + // graph and algo initialization + val emptyGraph = Graph() + val expected = mutableListOf() + val algorithm = Djikstra(emptyGraph) + + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(1) + + assertTrue(expected == currently) + } } \ No newline at end of file From 1e438baae456d6344a6d91dab29e1add8b7f8d22 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:41:23 +0300 Subject: [PATCH 079/211] fix(algo): djikstra extremal programming cases --- src/main/kotlin/algorithms/Djikstra.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index 51064a1..72305a6 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -9,7 +9,7 @@ class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { private val n = graph.vertices.size fun findShortestPaths() { - if (n == 0) return + if (n == 0 || startVertexID <= -1) return for ((id, _) in graph.vertices) { distance[id] = Long.MAX_VALUE @@ -47,7 +47,7 @@ class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { fun reconstructPath(endVertexID: Int): List { val path = mutableListOf() var finish = endVertexID - if (n == 0) return path + if ((n == 0 || startVertexID <= -1) || (endVertexID <= 0))return path while (finish != startVertexID) { path.add(finish) From e5006cece8fef27dd8adc2caec97281a02f09427 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 13:41:39 +0300 Subject: [PATCH 080/211] feat(tests): djikstra extremal programming cases --- src/test/kotlin/graphs/DjikstraTest.kt | 56 ++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/DjikstraTest.kt index 4fc5c95..7a21057 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/DjikstraTest.kt @@ -154,4 +154,60 @@ class DjikstraTest { assertTrue(expected == currently) } + + @Test + fun `test findShortestPaths no start position`() { + // graph and algo initialization + val expected = mutableListOf() + val algorithm = Djikstra(graph, -11) + + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(5) + + assertTrue(expected == currently) + } + + @Test + fun `test findShortestPaths no end position and start position`() { + // graph and algo initialization + val expected = mutableListOf() + val algorithm = Djikstra(graph) + + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(-4) + + assertTrue(expected == currently) + } + + @Test + fun `test findShortestPaths no end position start exist`() { + // graph and algo initialization + val expected = mutableListOf() + val algorithm = Djikstra(graph, 2) + + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(-4) + + assertTrue(expected == currently) + } + + @Test + fun `test findShortestPaths start and end pos equals`() { + // graph and algo initialization + val expected = mutableListOf(2) + val algorithm = Djikstra(graph, 2) + + // path created from 2 + algorithm.findShortestPaths() + + val currently = algorithm.reconstructPath(2) + + assertTrue(expected == currently) + } } \ No newline at end of file From d2ffbb1a8c1a3e6559cf4fad7f083446e14cb309 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 14:09:21 +0300 Subject: [PATCH 081/211] feat(tests): kosaraju tests added --- src/main/kotlin/algorithms/Kosaraju.kt | 7 ++- src/test/kotlin/graphs/KosajaruTest.kt | 63 +++++++++++++++++++------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index 770ec7c..ba96355 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -33,7 +33,7 @@ class Kosaraju(private val graph: Graph) { return components } - private fun topologySort(graph: Graph, vertexID: Int) { + private fun topologySort(graph: Graph, vertexID: Int) { used[vertexID] = true val vertex = graph.vertices[vertexID] ?: return for (edgeID in vertex.incidentEdges) { @@ -46,6 +46,11 @@ class Kosaraju(private val graph: Graph) { order.add(vertexID) } + fun test_TopologySort(graph: Graph, vertexID: Int): List { + topologySort(graph, vertexID) + return order + } + private fun dfs(vertexID: Int) { used[vertexID] = true component.add(vertexID) diff --git a/src/test/kotlin/graphs/KosajaruTest.kt b/src/test/kotlin/graphs/KosajaruTest.kt index e5b1d9e..3c1a994 100644 --- a/src/test/kotlin/graphs/KosajaruTest.kt +++ b/src/test/kotlin/graphs/KosajaruTest.kt @@ -15,12 +15,22 @@ import org.junit.jupiter.api.Assertions.* // // components: (0,7,1,6) (11) (9,2,4) (10,8,3,5) -fun createSampleGraph() : Graph { +fun createSampleGraph() : Graph { // Добавление вершин - val graph = Graph() - for (i in 0..11) { - graph.addVertex(i, i) - } + val graph = Graph() + graph.isDirected = true + graph.addVertex(0,"A") + graph.addVertex(1,"B") + graph.addVertex(2,"C") + graph.addVertex(3,"D") + graph.addVertex(4,"E") + graph.addVertex(5,"F") + graph.addVertex(6,"G") + graph.addVertex(7,"H") + graph.addVertex(8,"I") + graph.addVertex(9,"J") + graph.addVertex(10,"K") + graph.addVertex(11,"L") // Добавление рёбер graph.addEdge(0, 7, 1L, 0) @@ -48,56 +58,75 @@ fun createSampleGraph() : Graph { class KosarajuTest { @Test - fun `test dfs1 with sample graph start from 0 component`() { + fun `test topologySort with sample graph start from 0's component`() { + // graph and algo initialization + val graph = createSampleGraph() + val algo = Kosaraju(graph) + val expected = mutableListOf(3, 5, 8, 10, 2, 4, 9, 1, 6, 7, 0) + + // algo start from different positions + val currently = algo.test_TopologySort(graph, 0) + + assertTrue(expected == currently) + } + + @Test + fun `test topologySort with sample graph start from 5's component`() { // graph and algo initialization val graph = createSampleGraph() val algo = Kosaraju(graph) - val expected = mutableListOf(11, 3, 5, 8, 10, 2, 4, 9, 1, 6, 7, 0) + val expected = mutableListOf(8, 10, 3, 5) // algo start from different positions - val currently = algo.Test_dfs1(0) + val currently = algo.test_TopologySort(graph, 5) // Проверьте результаты assertTrue(expected == currently) } @Test - fun `test dfs1 with sample graph start from 5 component`() { + fun `test topologySort with sample graph start from 9's component`() { // graph and algo initialization val graph = createSampleGraph() val algo = Kosaraju(graph) - val expected = mutableListOf(0, 7, 3, 8, 10, 2, 4, 6, 1, 9, 11, 5) + val expected = mutableListOf(3, 5, 8, 10, 2, 4, 9) // algo start from different positions - val currently = algo.Test_dfs1(5) + val currently = algo.test_TopologySort(graph, 9) // Проверьте результаты assertTrue(expected == currently) } @Test - fun `test dfs1 with sample graph start from 4 component`() { + fun `test dfs1 with sample graph start from 11's component`() { // graph and algo initialization val graph = createSampleGraph() val algo = Kosaraju(graph) - val expected = mutableListOf(0, 7, 11, 3, 5, 8, 10, 2, 4, 6, 1, 9) + val expected = mutableListOf(3, 5, 8, 10, 2, 4, 9, 11) // algo start from different positions - val currently = algo.Test_dfs1(9) + val currently = algo.test_TopologySort(graph, 11) // Проверьте результаты assertTrue(expected == currently) } @Test - fun `test dfs1 with sample graph start from 11 component`() { + fun `test components output`() { // graph and algo initialization val graph = createSampleGraph() val algo = Kosaraju(graph) - val expected = mutableListOf(0, 7, 3, 5, 8, 10, 2, 4, 6, 1, 9, 11) + val expected = mutableListOf( + mutableListOf(3, 8, 5, 10), + mutableListOf(2, 9, 4), + mutableListOf(11), + mutableListOf(1), + mutableListOf(0,7,6), + ) // algo start from different positions - val currently = algo.Test_dfs1(11) + val currently = algo.findStronglyConnectedComponents() // Проверьте результаты assertTrue(expected == currently) From 9b05128a25778b905f20bc564c5a513508d41a08 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 14:12:27 +0300 Subject: [PATCH 082/211] feat(algo): kosaraju works with directed graphs --- src/main/kotlin/algorithms/Kosaraju.kt | 3 +++ src/test/kotlin/graphs/KosajaruTest.kt | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index ba96355..425cbf0 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -8,6 +8,9 @@ class Kosaraju(private val graph: Graph) { private val component = mutableListOf() fun findStronglyConnectedComponents(): List> { + if (!graph.isDirected) { + return emptyList>() + } // Step 1: Transpose the graph val transposedGraph = transposeGraph() diff --git a/src/test/kotlin/graphs/KosajaruTest.kt b/src/test/kotlin/graphs/KosajaruTest.kt index 3c1a994..3119961 100644 --- a/src/test/kotlin/graphs/KosajaruTest.kt +++ b/src/test/kotlin/graphs/KosajaruTest.kt @@ -131,4 +131,19 @@ class KosarajuTest { // Проверьте результаты assertTrue(expected == currently) } + + @Test + fun `test components output non-directed graph`() { + // graph and algo initialization + val graph = createSampleGraph() + graph.isDirected = false + val algo = Kosaraju(graph) + val expected = emptyList>() + + // algo start from different positions + val currently = algo.findStronglyConnectedComponents() + + // Проверьте результаты + assertTrue(expected == currently) + } } \ No newline at end of file From ff6ba7ed7fb349023f623bebdab7fd9c83dfb5d4 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 16:03:27 +0300 Subject: [PATCH 083/211] feat(db): Neo4jRepository class added --- build.gradle.kts | 2 + src/main/kotlin/database/neo4j/Repository.kt | 59 ++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/main/kotlin/database/neo4j/Repository.kt diff --git a/build.gradle.kts b/build.gradle.kts index ab2a490..6913a94 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,6 +14,7 @@ repositories { google() } val exposedVersion: String by project +val neo4jDriverVersion = "4.4.5" dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0") @@ -21,6 +22,7 @@ dependencies { implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation(compose.desktop.currentOs) + implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") } compose.desktop { diff --git a/src/main/kotlin/database/neo4j/Repository.kt b/src/main/kotlin/database/neo4j/Repository.kt new file mode 100644 index 0000000..65ba203 --- /dev/null +++ b/src/main/kotlin/database/neo4j/Repository.kt @@ -0,0 +1,59 @@ +package database.neo4j + +import graph.model.Graph +import org.neo4j.driver.AuthTokens +import org.neo4j.driver.Driver +import org.neo4j.driver.GraphDatabase +import org.neo4j.driver.Session +import org.neo4j.driver.Values +import java.io.Closeable + +class Neo4jRepository(uri: String, user: String, password: String) : Closeable { + private val driver: Driver = GraphDatabase.driver(uri, AuthTokens.basic(user, password)) + private val session: Session = driver.session() + + fun addVertex(vertexId: Int, vertexData: String, vertexCommunity : Int) { + session.writeTransaction { tx -> + tx.run("CREATE (:Vertex {id:\$id, data:\$data, community:\$community})", Values.parameters("id", vertexId, "data", vertexData, "community", vertexCommunity)) + } + } + + fun addEdge(firstVertexId: Int,secondVertexId: Int, weight: Long, edgeId: Int) { + session.writeTransaction { tx -> + tx.run("MATCH (v1:Vertex {id:\$id1}), (v2:Vertex {id:\$id2}) " + + "CREATE (v1)-[:CONNECTED_TO {id:\$edgeId, weight:\$weight}]->(v2)", + Values.parameters("id1", firstVertexId, "id2", secondVertexId, "edgeId", edgeId, "weight", weight)) + } + } + + fun getGraph(): Graph { + val graph = Graph() + + session.readTransaction { tx -> + val verticesResult = tx.run("MATCH (v:Vertex) RETURN v.id AS id, v.data AS data, v.community AS community)",) + verticesResult.list().forEach { record -> + val vertexId = record.get("id").asInt() + val vertexData = record.get("data").asString() + val vertexCommunity = record.get("community").asInt() + graph.addVertex(vertexId, vertexData) + graph.vertices[vertexId]!!.community = vertexCommunity + } + + val edgesResult = tx.run("MATCH (v1:Vertex)-[e:CONNECTED_TO]->(v2:Vertex) RETURN e.id AS id, v1.id AS v1, v2.id AS v2, e.weight AS weight") + edgesResult.list().forEach { record -> + val edgeId = record.get("id").asInt() + val firstVertexId = record.get("v1").asInt() + val secondVertexId = record.get("v2").asInt() + val weight = record.get("weight").asLong() + graph.addEdge(firstVertexId, secondVertexId, weight, edgeId) + } + } + + return graph + } + + override fun close() { + session.close() + driver.close() + } +} \ No newline at end of file From c22769328731d574303643d23e2cbff4aba8c6aa Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Mon, 20 May 2024 16:04:17 +0300 Subject: [PATCH 084/211] feat(db): Neo4jDBHandler added --- .../kotlin/database/neo4j/Neo4jDBHandler.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/kotlin/database/neo4j/Neo4jDBHandler.kt diff --git a/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt b/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt new file mode 100644 index 0000000..8f77e1d --- /dev/null +++ b/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt @@ -0,0 +1,21 @@ +package database.neo4j + +import graph.model.Graph + +class Neo4jHandler(private val repository: Neo4jRepository) { + + fun saveGraphToNeo4j(graph: Graph) { + for (vertex in graph.getVertices()) { + repository.addVertex(vertex.id, vertex.data, vertex.community) + } + + for (edge in graph.getEdges()) { + repository.addEdge(edge.vertices.first, edge.vertices.second, edge.weight, edge.id) + } + } + + fun loadGraphFromNeo4j(): Graph { + val graph = repository.getGraph() + return graph + } +} \ No newline at end of file From 88c60199cb7fa7e0e4242d728c2028038379507d Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 08:40:20 +0000 Subject: [PATCH 085/211] feat: removed vertices and edges labels parameters from graph view model constructor --- src/main/kotlin/view/graph/EdgeView.kt | 20 +++++++++---------- src/main/kotlin/view/graph/VertexView.kt | 16 +++++++-------- .../kotlin/viewmodel/graph/EdgeViewModel.kt | 4 ---- .../kotlin/viewmodel/graph/GraphViewModel.kt | 7 +++---- .../kotlin/viewmodel/graph/VertexViewModel.kt | 4 ---- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/view/graph/EdgeView.kt b/src/main/kotlin/view/graph/EdgeView.kt index b4c47ff..79bfe1c 100644 --- a/src/main/kotlin/view/graph/EdgeView.kt +++ b/src/main/kotlin/view/graph/EdgeView.kt @@ -28,14 +28,14 @@ fun EdgeView( color = Color.Black ) } - if (viewModel.labelVisible) { - Text( - modifier = Modifier - .offset( - viewModel.u.x + (viewModel.v.x - viewModel.u.x) / 2, - viewModel.u.y + (viewModel.v.y - viewModel.u.y) / 2 - ), - text = viewModel.weight, - ) - } +// if (viewModel.labelVisible) { +// Text( +// modifier = Modifier +// .offset( +// viewModel.u.x + (viewModel.v.x - viewModel.u.x) / 2, +// viewModel.u.y + (viewModel.v.y - viewModel.u.y) / 2 +// ), +// text = viewModel.weight, +// ) +// } } \ No newline at end of file diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt index 9a73efa..cc2f4d4 100644 --- a/src/main/kotlin/view/graph/VertexView.kt +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -33,13 +33,13 @@ fun VertexView( } } ) { - if (viewModel.labelVisible) { - Text( - modifier = Modifier - .align(Alignment.Center) - .offset(0.dp, -viewModel.radius - 10.dp), - text = viewModel.label, - ) - } +// if (viewModel.labelVisible) { +// Text( +// modifier = Modifier +// .align(Alignment.Center) +// .offset(0.dp, -viewModel.radius - 10.dp), +// text = viewModel.label, +// ) +// } } } \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt index dd11a73..0230670 100644 --- a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt @@ -7,11 +7,7 @@ class EdgeViewModel( val u: VertexViewModel, val v: VertexViewModel, private val e: Edge, - private val _labelVisible: State, ) { val weight get() = e.weight.toString() - - val labelVisible - get() = _labelVisible.value } \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index f5ca25c..ea2f787 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -10,13 +10,12 @@ import graph.model.Vertex class GraphViewModel( private val graph: Graph, - showVerticesLabels: State, - showEdgesLabels: State, + ) { private val verticesView: HashMap = hashMapOf() init { graph.getVertices().forEach { vertex -> - verticesView[vertex] = VertexViewModel(0.dp, 0.dp, Color.Blue, vertex, showVerticesLabels) + verticesView[vertex] = VertexViewModel(0.dp, 0.dp, Color.Blue, vertex) } } @@ -27,7 +26,7 @@ class GraphViewModel( ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.first} not found") val snd = verticesView[graph.vertices[edge.vertices.second]] ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.second} not found") - val currentEdgeView = EdgeViewModel(fst, snd, edge, showEdgesLabels) + val currentEdgeView = EdgeViewModel(fst, snd, edge) edgesView[edge]=currentEdgeView } diff --git a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt index 333ebf4..352f13e 100644 --- a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt @@ -13,7 +13,6 @@ class VertexViewModel( y: Dp = 0.dp, color: Color, private val v: Vertex, - private val _labelVisible: State, val radius: Dp = 25.dp ) { private var _x = mutableStateOf(x) @@ -38,9 +37,6 @@ class VertexViewModel( val label get() = v.data - val labelVisible - get() = _labelVisible.value - fun onDrag(offset: Offset) { _x.value += offset.x.dp _y.value += offset.y.dp From 71d26bf69eb4f13f815801884c11bcf6e170ba97 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 09:55:10 +0000 Subject: [PATCH 086/211] feat: add open function in sqlite database. correct some view model properties --- .../databases/sqlite/SQLiteDBHandler.kt | 51 +++++++++++++++++-- .../kotlin/databases/sqlite/dao/edge/Edge.kt | 2 +- .../kotlin/databases/sqlite/dao/edge/Edges.kt | 3 +- .../databases/sqlite/dao/vertices/Vertex.kt | 2 +- .../databases/sqlite/dao/vertices/Vertices.kt | 2 +- .../kotlin/viewmodel/graph/GraphViewModel.kt | 2 +- .../kotlin/viewmodel/graph/VertexViewModel.kt | 7 ++- 7 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt index bc87052..6e47b9a 100644 --- a/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt @@ -1,20 +1,65 @@ package databases.sqlite +import androidx.compose.ui.graphics.Color +import databases.sqlite.dao.edge.Edge +import databases.sqlite.dao.vertices.Vertex +import databases.sqlite.dao.vertices.Vertices +import databases.sqlite.dao.verticesView.VertexView +import databases.sqlite.dao.verticesView.VerticesView +import androidx.compose.ui.unit.dp + import graph.model.Graph import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.exists import org.jetbrains.exposed.sql.transactions.transaction +import viewmodel.graph.GraphViewModel import java.io.File class SQLiteDBHandler { - fun open(file: File){ + fun open(file: File, weighted: Boolean, directed: Boolean) { Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") val newGraph = Graph() + newGraph.isDirected=directed + var vertexViewModelFlag = false transaction { - + Vertex.all().forEach { vertex -> + newGraph.addVertex(vertex.id.toString().toInt(), vertex.data) + } + Edge.all().forEach { edge -> + newGraph.addEdge( + edge.first!!.id.toString().toInt(), edge.second!!.id.toString().toInt(), + edge.weight, edge.id.toString().toInt() + ) + if (!newGraph.isDirected) { + newGraph.vertices[edge.second!!.id.toString().toInt()]!!.incidentEdges.add( + edge.id.toString().toInt() + ) + } + newGraph.vertices[edge.first!!.id.toString().toInt()]!!.incidentEdges.add(edge.id.toString().toInt()) + } + if (VerticesView.exists()) { + vertexViewModelFlag = true + } } + if (vertexViewModelFlag) { + val newGraphViewModel = GraphViewModel(newGraph) + transaction { + newGraphViewModel.verticesView.onEach { + val vertex = Vertex.find { Vertices.id eq it.value.vertex.id }.first() + val tmp = VertexView.find { VerticesView.vertex eq vertex.id }.first() + it.value.x = tmp.x.dp + it.value.y = tmp.y.dp + it.key.community = vertex.community + val rgb = tmp.color.split(":").map { color -> color.toInt() } + it.value.color = Color(rgb[0], rgb[1], rgb[2]) + it.value.radius = tmp.r.dp + } + } + } + } - fun save(file: File){ + fun save(file: File) { Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") } diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt index 4f7652a..2a76e14 100644 --- a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt +++ b/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt @@ -7,7 +7,7 @@ import org.jetbrains.exposed.dao.id.EntityID class Edge(id: EntityID) : IntEntity(id){ companion object : IntEntityClass(Edges) - var element by Edges.element var first by Vertex optionalReferencedOn Edges.first var second by Vertex optionalReferencedOn Edges.second + var weight by Edges.weight } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt b/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt index d6e3260..fb4a5ff 100644 --- a/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt +++ b/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt @@ -4,8 +4,7 @@ import databases.sqlite.dao.vertices.Vertices import org.jetbrains.exposed.dao.id.IntIdTable object Edges: IntIdTable("Edge") { - val element = varchar("element", 255) val first = reference("first", Vertices).nullable() val second = reference("second", Vertices).nullable() - val weight = varchar("weight", 0).nullable() + val weight = long("weight") } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt b/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt index 5b211bb..715bcac 100644 --- a/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt +++ b/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt @@ -8,6 +8,6 @@ class Vertex(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(Vertices) - var element by Vertices.element + var data by Vertices.data var community by Vertices.community } \ No newline at end of file diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt b/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt index 9c0f3c3..852b43d 100644 --- a/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt +++ b/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt @@ -3,6 +3,6 @@ package databases.sqlite.dao.vertices import org.jetbrains.exposed.dao.id.IntIdTable object Vertices: IntIdTable("Vertices") { - val element = varchar("element", 255) + val data = varchar("data", 255) val community = integer("community") } \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index ea2f787..b31267d 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -12,7 +12,7 @@ class GraphViewModel( private val graph: Graph, ) { - private val verticesView: HashMap = hashMapOf() + val verticesView: HashMap = hashMapOf() init { graph.getVertices().forEach { vertex -> verticesView[vertex] = VertexViewModel(0.dp, 0.dp, Color.Blue, vertex) diff --git a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt index 352f13e..4c6ccf1 100644 --- a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt @@ -1,6 +1,5 @@ package viewmodel.graph -import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color @@ -12,8 +11,8 @@ class VertexViewModel( x: Dp = 0.dp, y: Dp = 0.dp, color: Color, - private val v: Vertex, - val radius: Dp = 25.dp + val vertex: Vertex, + var radius: Dp = 25.dp ) { private var _x = mutableStateOf(x) var x: Dp @@ -35,7 +34,7 @@ class VertexViewModel( } val label - get() = v.data + get() = vertex.data fun onDrag(offset: Offset) { _x.value += offset.x.dp From 661690d6e8bcc441ca50aef366bd2301de380f3f Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 10:52:50 +0000 Subject: [PATCH 087/211] feat: add example db for sqlite --- examples/Shelbiks.db | Bin 0 -> 12288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/Shelbiks.db diff --git a/examples/Shelbiks.db b/examples/Shelbiks.db new file mode 100644 index 0000000000000000000000000000000000000000..51454cf476970cefcbbb69745928c5c93b5caf04 GIT binary patch literal 12288 zcmeI&zl+mg7zgn8P2MI=%lVWZ*s1V}h*u~T^dGRTZ%g%B&oms~m}_%QByHeL&ZCQP zu8!j0Ag&HBZsI1c4lb^4I=aOqZHgT_2`)Y_H1Ct|`y+WjTcG1dhhF6Hvp~-6h~FU< zLMge+IUz({|B^0i={;N5X-EI4caJ$01BW03ZMWA zpa2S>z~2d6_7%NWtI_B4$UgNQF`YSKc2T>gXj_6??ara#S;P;#DIbh1(HAB^G6%!9 zdBPuvljfNx!zdqV^3a(Ci_OgDh2zcK%`k8F9-3m%AEhe~vXu>Pik>jVs4K?&*pZPp zal+(TjjgGxU3boHcvP>|>-6$Qc949VyjQl4lczgR#HV&-b4xt7ntT$>=jRJATIMHg zq~GRcxJ}>(e1#A24qn4ccm_}4815x8HWWYs6hHwKKmim$0Te(16hHwK_)i5YWk#;k zp0`-=vFrG!%eYcXlly_YNvZ}TH)&f&?zzloRf}n6xxw5H^K4&dq(Qr`Eq%}7<46XJ zSzOi9i9P(FBOu%<{N5RH&#VSFRlth*H=YR*Rn!Of>omFEGt++QwzkP2Gf+RS2ddT F%5S7Nw{QRe literal 0 HcmV?d00001 From 75ee9d15bfaa2b31647e590fedccf11861a26761 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Tue, 21 May 2024 11:11:52 +0000 Subject: [PATCH 088/211] fix(ci): comment approval task --- .github/mergeable.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index 9970859..1871dc1 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -15,13 +15,13 @@ mergeable: no_empty: enabled: true message: 'Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed.' - - do: approvals - min: - count: 0 - block: - changes_requested: true - limit: - users: - - DronShock - - suvorovrain - - Sem4kok + # - do: approvals + # min: + # count: 0 + # block: + # changes_requested: true + # limit: + # users: + # - DronShock + # - suvorovrain + # - Sem4kok From f48c7560897582b7b47ee92c683f6081b7021782 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 11:18:15 +0000 Subject: [PATCH 089/211] fix: repair canvas VM --- src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index e579bf6..0ccae0e 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -9,7 +9,7 @@ import viewmodel.layouts.RepresentationStrategy class CanvasViewModel(graph: Graph, private val representationStrategy: RepresentationStrategy,) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) - val graphViewModel = GraphViewModel(graph, showVerticesLabels, showEdgesLabels) + val graphViewModel = GraphViewModel(graph) init { representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) From 7018e80b99ee27d55e8d55a6d640a3108429be5b Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 11:42:21 +0000 Subject: [PATCH 090/211] feat: add lables for vertices --- src/main/kotlin/view/graph/VertexView.kt | 16 ++++++++-------- src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- .../kotlin/viewmodel/graph/GraphViewModel.kt | 2 +- .../kotlin/viewmodel/graph/VertexViewModel.kt | 5 +++++ 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt index cc2f4d4..9a73efa 100644 --- a/src/main/kotlin/view/graph/VertexView.kt +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -33,13 +33,13 @@ fun VertexView( } } ) { -// if (viewModel.labelVisible) { -// Text( -// modifier = Modifier -// .align(Alignment.Center) -// .offset(0.dp, -viewModel.radius - 10.dp), -// text = viewModel.label, -// ) -// } + if (viewModel.labelVisible) { + Text( + modifier = Modifier + .align(Alignment.Center) + .offset(0.dp, -viewModel.radius - 10.dp), + text = viewModel.label, + ) + } } } \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 0ccae0e..8230af2 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -17,7 +17,7 @@ class CanvasViewModel(graph: Graph, private val representationStrategy: Represen fun resetGraphView() { representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) - graphViewModel.verticesViewValues.forEach{ v -> v.color = Color.Gray} + graphViewModel.verticesViewValues.forEach{ v -> v.color = Color.Blue} } fun setVerticesColor() { diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index b31267d..33f6a4c 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -15,7 +15,7 @@ class GraphViewModel( val verticesView: HashMap = hashMapOf() init { graph.getVertices().forEach { vertex -> - verticesView[vertex] = VertexViewModel(0.dp, 0.dp, Color.Blue, vertex) + verticesView[vertex] = VertexViewModel(0.dp, 0.dp, Color.Black, vertex) } } diff --git a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt index 4c6ccf1..7bdc7a9 100644 --- a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt @@ -1,5 +1,6 @@ package viewmodel.graph +import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color @@ -14,6 +15,8 @@ class VertexViewModel( val vertex: Vertex, var radius: Dp = 25.dp ) { + private val _labelVisible: State = mutableStateOf(true) + private var _x = mutableStateOf(x) var x: Dp get() = _x.value @@ -35,6 +38,8 @@ class VertexViewModel( val label get() = vertex.data + val labelVisible + get() = _labelVisible.value fun onDrag(offset: Offset) { _x.value += offset.x.dp From 145ed073b929904997e6c043152a158dde452db7 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 17:29:55 +0000 Subject: [PATCH 091/211] feat: add multiple edges support --- src/main/kotlin/algorithms/BridgeFinder.kt | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index 1ad1bec..a1aa4c2 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -1,6 +1,7 @@ package algorithms import graph.model.Graph +import java.awt.geom.Point2D.distance import kotlin.math.min class BridgeFinder(graph: Graph) { @@ -8,12 +9,21 @@ class BridgeFinder(graph: Graph) { private val visitedVertices = Array(arraySize) {false} private val timeIn = Array(arraySize) {0} private val fUp = Array(arraySize) {0} - //TODO: adapt this algorithm to multiple edges + val bridges = mutableListOf() + fun findBridges(graph: Graph){ var timer = 0 - fun isBridge(edgeID: Int){ - println(edgeID) + fun isBridge(edgeID: Int): Int?{ + val destination = graph.edges[edgeID]?.vertices?.second ?: throw Exception("Incorrect Database") + val bridge = graph.edges[edgeID] + val bridges = graph.vertices[bridge?.vertices?.first]?.incidentEdges ?: throw Exception("Incorrect Database") + for (curBridge in bridges) { + if (graph.edges[curBridge]!!.vertices.second==destination && curBridge!=edgeID){ + return null + } + } + return edgeID } fun dfs(vertexID: Int, parent: Int = -1){ @@ -38,7 +48,9 @@ class BridgeFinder(graph: Graph) { dfs(newVertexID, vertexID) fUp[vertexID] = min(fUp[newVertexID], fUp[vertexID]) if(fUp[vertexID] > timeIn[newVertexID]){ - isBridge(edgeID) + if (isBridge(edgeID)!=null){ + bridges.add(edgeID) + } } } } From b26b23cc01ef1b39d5592aa71d4077d33f193ed8 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 17:48:41 +0000 Subject: [PATCH 092/211] feat: blank files for bridge finder test --- src/main/kotlin/algorithms/BridgeFinder.kt | 1 - .../graphs/algorithms/BridgeFinderTest.kt | 48 +++++++++++++++++++ .../graphs/{ => algorithms}/DjikstraTest.kt | 2 +- .../graphs/{ => algorithms}/KosajaruTest.kt | 2 +- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt rename src/test/kotlin/graphs/{ => algorithms}/DjikstraTest.kt (99%) rename src/test/kotlin/graphs/{ => algorithms}/KosajaruTest.kt (99%) diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index a1aa4c2..5b1a26b 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -13,7 +13,6 @@ class BridgeFinder(graph: Graph) { fun findBridges(graph: Graph){ var timer = 0 - fun isBridge(edgeID: Int): Int?{ val destination = graph.edges[edgeID]?.vertices?.second ?: throw Exception("Incorrect Database") val bridge = graph.edges[edgeID] diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt new file mode 100644 index 0000000..7e58f9c --- /dev/null +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -0,0 +1,48 @@ +package graphs.algorithms + +import graph.model.Graph +import org.junit.jupiter.api.BeforeEach + +class BridgeFinderTest { + private lateinit var graph: Graph + @BeforeEach + fun setup() { + graph = Graph().apply { + addVertex(1,"Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "Tristan Tate") + addVertex(6, "Arthur Shelby") + addVertex(7, "Ryan Gosling") + + addEdge(1, 2, 1,1) + addEdge(3, 4, 2,2) + addEdge(1, 3, 3,3) + addEdge(2, 4, 4,4) + addEdge(2, 5, 5,5) + addEdge(5, 7, 6,6) + + addVertex(8, "Pudge") + addVertex(9,"Tiny") + addVertex(10, "Lycan") + addVertex(11,"Io") + addVertex(12,"Lion") + addVertex(13,"Sniper") + addVertex(14,"Roshan") + + addEdge(14, 8, 7,7) + addEdge(14, 9, 8,8) + addEdge(14, 10, 9,9) + addEdge(14, 11, 10,10) + addEdge(14, 12, 11,11) + addEdge(14, 13, 12,12) + + addEdge(14, 3, 0,13) + } + } + @Test + + + } +} \ No newline at end of file diff --git a/src/test/kotlin/graphs/DjikstraTest.kt b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt similarity index 99% rename from src/test/kotlin/graphs/DjikstraTest.kt rename to src/test/kotlin/graphs/algorithms/DjikstraTest.kt index 7a21057..fa897fb 100644 --- a/src/test/kotlin/graphs/DjikstraTest.kt +++ b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt @@ -1,4 +1,4 @@ -package graphs +package graphs.algorithms import algorithms.Djikstra import graph.model.Graph diff --git a/src/test/kotlin/graphs/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt similarity index 99% rename from src/test/kotlin/graphs/KosajaruTest.kt rename to src/test/kotlin/graphs/algorithms/KosajaruTest.kt index 3119961..0d19169 100644 --- a/src/test/kotlin/graphs/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -1,4 +1,4 @@ -package graphs +package graphs.algorithms import algorithms.Kosaraju import graph.model.Graph From f57e033a6c276b822c32bc5319df18fe8c8d1c67 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 19:56:22 +0000 Subject: [PATCH 093/211] fix: addVertex function now set id property to vertices --- src/main/kotlin/graph/model/Graph.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt index 6c87470..d30949c 100644 --- a/src/main/kotlin/graph/model/Graph.kt +++ b/src/main/kotlin/graph/model/Graph.kt @@ -9,7 +9,11 @@ class Graph{ fun getEdges(): Collection = edges.values - fun addVertex(id: Int, v: String): Vertex = vertices.getOrPut(id) { Vertex(v) } + fun addVertex(id: Int, v: String): Vertex{ + val vertex = Vertex(v) + vertex.id=id + return vertices.getOrPut(id) { vertex } + } fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { if (!isDirected){ From 00b49c54540bfc869b275d33562cb82c6c0f8883 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 19:57:44 +0000 Subject: [PATCH 094/211] feat: add test for bridge finder algorithm --- build.gradle.kts | 2 + src/main/kotlin/Main.kt | 11 +++-- src/main/kotlin/algorithms/BridgeFinder.kt | 43 +++++++++++-------- .../graphs/algorithms/BridgeFinderTest.kt | 13 +++++- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ab2a490..d32ba5d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,6 +21,8 @@ dependencies { implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation(compose.desktop.currentOs) + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } compose.desktop { diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 9d88da6..c67369d 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -14,12 +14,12 @@ import view.Canvas import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout -val sampleGraph: Graph = Graph().apply { +val graph = Graph().apply { addVertex(1,"Thomas Shelby") addVertex(2, "Andrew Tate") - addVertex(3, "Vova Vinduz") - addVertex(4, "Maksim Rodionov") - addVertex(5, "Ilia ITMO") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "Tristan Tate") addVertex(6, "Arthur Shelby") addVertex(7, "Ryan Gosling") @@ -47,12 +47,11 @@ val sampleGraph: Graph = Graph().apply { addEdge(14, 3, 0,13) } - @Composable @Preview fun App() { MaterialTheme { - Canvas(CanvasViewModel(sampleGraph, CircularLayout())) + Canvas(CanvasViewModel(graph, CircularLayout())) } } diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index 5b1a26b..90d83ce 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -7,18 +7,20 @@ import kotlin.math.min class BridgeFinder(graph: Graph) { private val arraySize = graph.vertices.size private val visitedVertices = Array(arraySize) {false} - private val timeIn = Array(arraySize) {0} - private val fUp = Array(arraySize) {0} + private val timeIn = Array(arraySize) {-1} + private val fUp = Array(arraySize) {-1} val bridges = mutableListOf() + private val curGraph = graph - fun findBridges(graph: Graph){ + fun findBridges(){ var timer = 0 + fun isBridge(edgeID: Int): Int?{ - val destination = graph.edges[edgeID]?.vertices?.second ?: throw Exception("Incorrect Database") - val bridge = graph.edges[edgeID] - val bridges = graph.vertices[bridge?.vertices?.first]?.incidentEdges ?: throw Exception("Incorrect Database") + val destination = curGraph.edges[edgeID]?.vertices?.second ?: throw Exception("Incorrect Database") + val bridge = curGraph.edges[edgeID] + val bridges = curGraph.vertices[bridge?.vertices?.first]?.incidentEdges ?: throw Exception("Incorrect Database") for (curBridge in bridges) { - if (graph.edges[curBridge]!!.vertices.second==destination && curBridge!=edgeID){ + if (curGraph.edges[curBridge]!!.vertices.second==destination && curBridge!=edgeID){ return null } } @@ -27,26 +29,29 @@ class BridgeFinder(graph: Graph) { fun dfs(vertexID: Int, parent: Int = -1){ visitedVertices[vertexID] = true - timeIn[vertexID] = timer++ - fUp[vertexID] = timer++ - val incidentEdgesID = graph.vertices[vertexID]!!.incidentEdges + timer++ + timeIn[vertexID] = timer + fUp[vertexID] = timer + val incidentEdgesID = curGraph.vertices[vertexID+1]!!.incidentEdges for (edgeID in incidentEdgesID){ - val edge = graph.edges[edgeID]!!.vertices - val currentVertex = graph.vertices[vertexID] - val newVertexID = if (currentVertex == graph.vertices[edge.first]){ - edge.first + val edge = curGraph.edges[edgeID]!!.vertices + val newVertexID = if (vertexID == edge.first-1){ + edge.second-1 } else{ - edge.second + edge.first-1 } + if (newVertexID == parent) continue + if (visitedVertices[newVertexID]){ fUp[vertexID] = min(timeIn[newVertexID], fUp[vertexID]) } + else{ dfs(newVertexID, vertexID) fUp[vertexID] = min(fUp[newVertexID], fUp[vertexID]) - if(fUp[vertexID] > timeIn[newVertexID]){ + if(fUp[newVertexID] > timeIn[vertexID]){ if (isBridge(edgeID)!=null){ bridges.add(edgeID) } @@ -55,9 +60,9 @@ class BridgeFinder(graph: Graph) { } } - for (i in arraySize - 1 downTo 0){ - if (visitedVertices[i]){ - dfs(i) + for (i in 1..arraySize){ + if (!visitedVertices[i-1]){ + dfs(i-1) } } } diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index 7e58f9c..3385f14 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -1,7 +1,11 @@ package graphs.algorithms +import algorithms.BridgeFinder import graph.model.Graph import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Assertions.* class BridgeFinderTest { private lateinit var graph: Graph @@ -42,7 +46,12 @@ class BridgeFinderTest { } } @Test - - + @DisplayName("Multiple bridges, no multiple edges") + public fun puk(){ + val bridgeFinder = BridgeFinder(graph) + bridgeFinder.findBridges() + val result = bridgeFinder.bridges + val expectedBridges = listOf(7, 8, 9, 10, 11, 12, 13, 6, 5) + assertEquals(expectedBridges,result) } } \ No newline at end of file From 338ea81f0e21683fe5f5df84d391dcbd36c0c9ad Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 20:05:49 +0000 Subject: [PATCH 095/211] fix: fix directories --- src/main/kotlin/Main.kt | 2 +- src/main/kotlin/algorithms/BridgeFinder.kt | 2 +- src/main/kotlin/algorithms/Djikstra.kt | 2 +- src/main/kotlin/algorithms/FordBellman.kt | 2 +- src/main/kotlin/algorithms/Kosaraju.kt | 2 +- src/main/kotlin/algorithms/KruskalsAlgorithm.kt | 4 ++-- .../databases/sqlite/SQLiteDBHandler.kt | 14 +++++++------- .../{ => model}/databases/sqlite/dao/edge/Edge.kt | 4 ++-- .../{ => model}/databases/sqlite/dao/edge/Edges.kt | 4 ++-- .../databases/sqlite/dao/vertices/Vertex.kt | 2 +- .../databases/sqlite/dao/vertices/Vertices.kt | 2 +- .../sqlite/dao/verticesView/VertexView.kt | 4 ++-- .../sqlite/dao/verticesView/VerticesView.kt | 4 ++-- .../kotlin/{graph/model => model/graph}/Edge.kt | 2 +- .../kotlin/{graph/model => model/graph}/Graph.kt | 4 ++-- .../kotlin/{graph/model => model/graph}/Vertex.kt | 2 +- src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- src/main/kotlin/viewmodel/graph/EdgeViewModel.kt | 2 +- src/main/kotlin/viewmodel/graph/GraphViewModel.kt | 8 ++++---- src/main/kotlin/viewmodel/graph/VertexViewModel.kt | 2 +- .../kotlin/graphs/algorithms/BridgeFinderTest.kt | 2 +- src/test/kotlin/graphs/algorithms/DjikstraTest.kt | 2 +- src/test/kotlin/graphs/algorithms/KosajaruTest.kt | 2 +- 23 files changed, 38 insertions(+), 38 deletions(-) rename src/main/kotlin/{ => model}/databases/sqlite/SQLiteDBHandler.kt (87%) rename src/main/kotlin/{ => model}/databases/sqlite/dao/edge/Edge.kt (81%) rename src/main/kotlin/{ => model}/databases/sqlite/dao/edge/Edges.kt (71%) rename src/main/kotlin/{ => model}/databases/sqlite/dao/vertices/Vertex.kt (87%) rename src/main/kotlin/{ => model}/databases/sqlite/dao/vertices/Vertices.kt (79%) rename src/main/kotlin/{ => model}/databases/sqlite/dao/verticesView/VertexView.kt (81%) rename src/main/kotlin/{ => model}/databases/sqlite/dao/verticesView/VerticesView.kt (72%) rename src/main/kotlin/{graph/model => model/graph}/Edge.kt (89%) rename src/main/kotlin/{graph/model => model/graph}/Graph.kt (91%) rename src/main/kotlin/{graph/model => model/graph}/Vertex.kt (88%) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index c67369d..2bbec8f 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -9,7 +9,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.window.Window import androidx.compose.ui.window.application -import graph.model.Graph +import model.graph.Graph import view.Canvas import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index 90d83ce..6d743b9 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph import java.awt.geom.Point2D.distance import kotlin.math.min diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index 72305a6..f6ecfc8 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { private val distance = hashMapOf() diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt index 0ee92a1..96ceea6 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph import java.math.BigInteger import kotlin.math.max diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index 425cbf0..aeabb34 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph class Kosaraju(private val graph: Graph) { private val used = hashMapOf() diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt index 6e809f7..347935a 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -1,7 +1,7 @@ package algorithms -import graph.model.Edge -import graph.model.Graph +import model.graph.Edge +import model.graph.Graph class KruskalsMST { private fun kruskals(graph: Graph) { diff --git a/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt similarity index 87% rename from src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt rename to src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index 6e47b9a..a8cc06b 100644 --- a/src/main/kotlin/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -1,14 +1,14 @@ -package databases.sqlite +package model.databases.sqlite import androidx.compose.ui.graphics.Color -import databases.sqlite.dao.edge.Edge -import databases.sqlite.dao.vertices.Vertex -import databases.sqlite.dao.vertices.Vertices -import databases.sqlite.dao.verticesView.VertexView -import databases.sqlite.dao.verticesView.VerticesView +import model.databases.sqlite.dao.edge.Edge +import model.databases.sqlite.dao.vertices.Vertex +import model.databases.sqlite.dao.vertices.Vertices +import model.databases.sqlite.dao.verticesView.VertexView +import model.databases.sqlite.dao.verticesView.VerticesView import androidx.compose.ui.unit.dp -import graph.model.Graph +import model.graph.Graph import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.exists import org.jetbrains.exposed.sql.transactions.transaction diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt b/src/main/kotlin/model/databases/sqlite/dao/edge/Edge.kt similarity index 81% rename from src/main/kotlin/databases/sqlite/dao/edge/Edge.kt rename to src/main/kotlin/model/databases/sqlite/dao/edge/Edge.kt index 2a76e14..f2613ca 100644 --- a/src/main/kotlin/databases/sqlite/dao/edge/Edge.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/edge/Edge.kt @@ -1,6 +1,6 @@ -package databases.sqlite.dao.edge +package model.databases.sqlite.dao.edge -import databases.sqlite.dao.vertices.Vertex +import model.databases.sqlite.dao.vertices.Vertex import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.id.EntityID diff --git a/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt similarity index 71% rename from src/main/kotlin/databases/sqlite/dao/edge/Edges.kt rename to src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt index fb4a5ff..d92c90e 100644 --- a/src/main/kotlin/databases/sqlite/dao/edge/Edges.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt @@ -1,6 +1,6 @@ -package databases.sqlite.dao.edge +package model.databases.sqlite.dao.edge -import databases.sqlite.dao.vertices.Vertices +import model.databases.sqlite.dao.vertices.Vertices import org.jetbrains.exposed.dao.id.IntIdTable object Edges: IntIdTable("Edge") { diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertex.kt similarity index 87% rename from src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt rename to src/main/kotlin/model/databases/sqlite/dao/vertices/Vertex.kt index 715bcac..c9f30bd 100644 --- a/src/main/kotlin/databases/sqlite/dao/vertices/Vertex.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertex.kt @@ -1,4 +1,4 @@ -package databases.sqlite.dao.vertices +package model.databases.sqlite.dao.vertices import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass diff --git a/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt similarity index 79% rename from src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt rename to src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt index 852b43d..35a2d02 100644 --- a/src/main/kotlin/databases/sqlite/dao/vertices/Vertices.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt @@ -1,4 +1,4 @@ -package databases.sqlite.dao.vertices +package model.databases.sqlite.dao.vertices import org.jetbrains.exposed.dao.id.IntIdTable diff --git a/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VertexView.kt similarity index 81% rename from src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt rename to src/main/kotlin/model/databases/sqlite/dao/verticesView/VertexView.kt index 2de54e2..e945ef7 100644 --- a/src/main/kotlin/databases/sqlite/dao/verticesView/VertexView.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VertexView.kt @@ -1,7 +1,7 @@ -package databases.sqlite.dao.verticesView +package model.databases.sqlite.dao.verticesView -import databases.sqlite.dao.vertices.Vertex +import model.databases.sqlite.dao.vertices.Vertex import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.id.EntityID diff --git a/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt similarity index 72% rename from src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt rename to src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt index a3895c2..bea6ab6 100644 --- a/src/main/kotlin/databases/sqlite/dao/verticesView/VerticesView.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt @@ -1,6 +1,6 @@ -package databases.sqlite.dao.verticesView +package model.databases.sqlite.dao.verticesView -import databases.sqlite.dao.vertices.Vertices +import model.databases.sqlite.dao.vertices.Vertices import org.jetbrains.exposed.dao.id.IntIdTable object VerticesView: IntIdTable("VerticesView") { diff --git a/src/main/kotlin/graph/model/Edge.kt b/src/main/kotlin/model/graph/Edge.kt similarity index 89% rename from src/main/kotlin/graph/model/Edge.kt rename to src/main/kotlin/model/graph/Edge.kt index ca6959b..55de8d4 100644 --- a/src/main/kotlin/graph/model/Edge.kt +++ b/src/main/kotlin/model/graph/Edge.kt @@ -1,4 +1,4 @@ -package graph.model +package model.graph class Edge ( val vertices: Pair, diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/model/graph/Graph.kt similarity index 91% rename from src/main/kotlin/graph/model/Graph.kt rename to src/main/kotlin/model/graph/Graph.kt index d30949c..a150682 100644 --- a/src/main/kotlin/graph/model/Graph.kt +++ b/src/main/kotlin/model/graph/Graph.kt @@ -1,4 +1,4 @@ -package graph.model +package model.graph class Graph{ var isDirected: Boolean = false @@ -9,7 +9,7 @@ class Graph{ fun getEdges(): Collection = edges.values - fun addVertex(id: Int, v: String): Vertex{ + fun addVertex(id: Int, v: String): Vertex { val vertex = Vertex(v) vertex.id=id return vertices.getOrPut(id) { vertex } diff --git a/src/main/kotlin/graph/model/Vertex.kt b/src/main/kotlin/model/graph/Vertex.kt similarity index 88% rename from src/main/kotlin/graph/model/Vertex.kt rename to src/main/kotlin/model/graph/Vertex.kt index 1f9d12f..29fb6c7 100644 --- a/src/main/kotlin/graph/model/Vertex.kt +++ b/src/main/kotlin/model/graph/Vertex.kt @@ -1,4 +1,4 @@ -package graph.model +package model.graph class Vertex( var data: String, diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 8230af2..9684bcb 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -2,7 +2,7 @@ package viewmodel import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.graphics.Color -import graph.model.Graph +import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy diff --git a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt index 0230670..54b7d8e 100644 --- a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt @@ -1,7 +1,7 @@ package viewmodel.graph import androidx.compose.runtime.State -import graph.model.Edge +import model.graph.Edge class EdgeViewModel( val u: VertexViewModel, diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 33f6a4c..31fabf3 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -3,15 +3,15 @@ package viewmodel.graph import androidx.compose.runtime.State import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import graph.model.Edge -import graph.model.Graph -import graph.model.Vertex +import model.graph.Edge +import model.graph.Graph +import model.graph.Vertex class GraphViewModel( private val graph: Graph, -) { + ) { val verticesView: HashMap = hashMapOf() init { graph.getVertices().forEach { vertex -> diff --git a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt index 7bdc7a9..bc56fc1 100644 --- a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt @@ -6,7 +6,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import graph.model.Vertex +import model.graph.Vertex class VertexViewModel( x: Dp = 0.dp, diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index 3385f14..15696ea 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import algorithms.BridgeFinder -import graph.model.Graph +import model.graph.Graph import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt index fa897fb..9a5e665 100644 --- a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt +++ b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import algorithms.Djikstra -import graph.model.Graph +import model.graph.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* diff --git a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt index 0d19169..a0ab04c 100644 --- a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import algorithms.Kosaraju -import graph.model.Graph +import model.graph.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* From 4e61e99341f97a73015a423302b1c2b874903d39 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 20:14:57 +0000 Subject: [PATCH 096/211] fix: typos --- src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt | 2 +- src/test/kotlin/graphs/algorithms/FordBellmanTest.kt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 src/test/kotlin/graphs/algorithms/FordBellmanTest.kt diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index 15696ea..29fab8f 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -47,7 +47,7 @@ class BridgeFinderTest { } @Test @DisplayName("Multiple bridges, no multiple edges") - public fun puk(){ + public fun MultipleBridgesNoMultipleEdges(){ val bridgeFinder = BridgeFinder(graph) bridgeFinder.findBridges() val result = bridgeFinder.bridges diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt new file mode 100644 index 0000000..0948019 --- /dev/null +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -0,0 +1,4 @@ +package graphs.algorithms + +class FordBellmanTest { +} \ No newline at end of file From 325444d3521d18c7fd0e53738f824519672c5fcd Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 21 May 2024 20:30:53 +0000 Subject: [PATCH 097/211] test: add files for future tests for Ford Bellman algorithm --- src/main/kotlin/algorithms/FordBellman.kt | 65 ++++++++++--------- .../graphs/algorithms/FordBellmanTest.kt | 59 +++++++++++++++++ 2 files changed, 93 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt index 96ceea6..b6147fd 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -11,50 +11,53 @@ class FordBellman(graph: Graph) { private val edgesNumber = graph.edges.size private val pathsLength = Array(verticesNumber) { INF } private val resultPath = Array(verticesNumber) { -1 } - - fun shortestPath(graph: Graph) { + private val curGraph = graph + val edgesPath = mutableListOf() + val verticesPath = mutableListOf() + fun shortestPath() { pathsLength[0] = 0 var cycleFlag = -1 for (i in 1 until verticesNumber) { cycleFlag = -1 for (j in 1 until edgesNumber) { - val firstVertexPath = pathsLength[graph.edges[j]!!.vertices.first] - var secondVertexPath = pathsLength[graph.edges[j]!!.vertices.second] + val firstVertexPath = pathsLength[curGraph.edges[j]!!.vertices.first] + var secondVertexPath = pathsLength[curGraph.edges[j]!!.vertices.second] if (firstVertexPath < INF) { - if (secondVertexPath > firstVertexPath + graph.edges[j]!!.weight) { - secondVertexPath = max(-INF, INF + graph.edges[j]!!.weight) - resultPath[graph.edges[j]!!.vertices.second] = graph.edges[j]!!.vertices.first - cycleFlag = graph.edges[j]!!.vertices.second + if (secondVertexPath > firstVertexPath + curGraph.edges[j]!!.weight) { + secondVertexPath = max(-INF, INF + curGraph.edges[j]!!.weight) + resultPath[curGraph.edges[j]!!.vertices.second] = curGraph.edges[j]!!.vertices.first + cycleFlag = curGraph.edges[j]!!.vertices.second } } } } - negativeCycleCheck(graph, cycleFlag) + if (cycleFlag==-1){ + + } + else{ + negativeCycleCheck() + } + } - private fun negativeCycleCheck(graph: Graph, cycleFlag: Int) { - if (cycleFlag == -1) { - println("No negative cycles") - } else { - var tmpCycleFlag = cycleFlag - for (i in 1 until verticesNumber) { - tmpCycleFlag = resultPath[tmpCycleFlag] - } - val path: MutableList = mutableListOf() - var current = tmpCycleFlag - var cycleEndFlag = true - while(cycleEndFlag){ - path.add(current) - if (current == tmpCycleFlag && path.size >1){ - cycleEndFlag = false - } - current=resultPath[current] - } - println("Negative cycle:") - path.forEach { - print("$it ") + private fun negativeCycleCheck() { + var tmpCycleFlag = cycleFlag + for (i in 1 until verticesNumber) { + tmpCycleFlag = resultPath[tmpCycleFlag] + } + val path: MutableList = mutableListOf() + var current = tmpCycleFlag + var cycleEndFlag = true + while(cycleEndFlag){ + path.add(current) + if (current == tmpCycleFlag && path.size >1){ + cycleEndFlag = false } + current=resultPath[current] + } + println("Negative cycle:") + path.forEach { + print("$it ") } } - } \ No newline at end of file diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt index 0948019..4723b0c 100644 --- a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -1,4 +1,63 @@ package graphs.algorithms +import algorithms.BridgeFinder +import algorithms.FordBellman +import model.graph.Graph +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + class FordBellmanTest { + private lateinit var graph: Graph + @BeforeEach + fun setup() { + graph = Graph().apply { + addVertex(1,"Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "Tristan Tate") + addVertex(6, "Arthur Shelby") + addVertex(7, "Ryan Gosling") + + addEdge(1, 2, 1,1) + addEdge(3, 4, 2,2) + addEdge(1, 3, 3,3) + addEdge(2, 4, 4,4) + addEdge(2, 5, 5,5) + addEdge(5, 7, 6,6) + + addVertex(8, "Pudge") + addVertex(9,"Tiny") + addVertex(10, "Lycan") + addVertex(11,"Io") + addVertex(12,"Lion") + addVertex(13,"Sniper") + addVertex(14,"Roshan") + + addEdge(14, 8, 7,7) + addEdge(14, 9, 8,8) + addEdge(14, 10, 9,9) + addEdge(14, 11, 10,10) + addEdge(14, 12, 11,11) + addEdge(14, 13, 12,12) + + addEdge(14, 3, 0,13) + } + } + @Test + @DisplayName("Path without negative cycles") + public fun PathWithoutNegativeCycles(){ + val fordBellman = FordBellman(graph) + fordBellman.shortestPath() + + val resultVertices = fordBellman.verticesPath + val resultEdges = fordBellman.edgesPath + val expectedEdges = listOf(1) + val expectedVertices = listOf(1) + + assertEquals(expectedEdges, resultEdges) + assertEquals(expectedVertices, resultVertices) + } } \ No newline at end of file From ac3a6e5893aae36c3e7bcbbc7159842daa7e4dcc Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 22 May 2024 12:36:22 +0000 Subject: [PATCH 098/211] feat: add tests for Ford Bellman --- src/main/kotlin/algorithms/FordBellman.kt | 118 +++++++++++------ .../graphs/algorithms/FordBellmanTest.kt | 119 ++++++++++++------ 2 files changed, 159 insertions(+), 78 deletions(-) diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt index b6147fd..82a6f52 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -1,7 +1,6 @@ package algorithms import model.graph.Graph -import java.math.BigInteger import kotlin.math.max @@ -9,55 +8,94 @@ class FordBellman(graph: Graph) { val INF = Long.MAX_VALUE private val verticesNumber = graph.vertices.size private val edgesNumber = graph.edges.size - private val pathsLength = Array(verticesNumber) { INF } - private val resultPath = Array(verticesNumber) { -1 } - private val curGraph = graph - val edgesPath = mutableListOf() - val verticesPath = mutableListOf() - fun shortestPath() { - pathsLength[0] = 0 - var cycleFlag = -1 - for (i in 1 until verticesNumber) { - cycleFlag = -1 - for (j in 1 until edgesNumber) { - val firstVertexPath = pathsLength[curGraph.edges[j]!!.vertices.first] - var secondVertexPath = pathsLength[curGraph.edges[j]!!.vertices.second] - if (firstVertexPath < INF) { - if (secondVertexPath > firstVertexPath + curGraph.edges[j]!!.weight) { - secondVertexPath = max(-INF, INF + curGraph.edges[j]!!.weight) - resultPath[curGraph.edges[j]!!.vertices.second] = curGraph.edges[j]!!.vertices.first - cycleFlag = curGraph.edges[j]!!.vertices.second - } - } - } - } - if (cycleFlag==-1){ - } - else{ - negativeCycleCheck() - } + private val pathsLength = Array(verticesNumber) { INF } + val pathVertices = Array(verticesNumber) { -1 } + val pathEdges = Array(edgesNumber) { -1 } + val resultPathVertices:MutableList = mutableListOf() + val resultPathEdges:MutableList = mutableListOf() - } + private val curGraph = graph + var disconnectedGraphFlag = false + var cycleFlag = false - private fun negativeCycleCheck() { + private fun negativeCycleBuilder(cycleFlag: Int) { var tmpCycleFlag = cycleFlag for (i in 1 until verticesNumber) { - tmpCycleFlag = resultPath[tmpCycleFlag] + tmpCycleFlag = pathVertices[tmpCycleFlag-1]+1 } - val path: MutableList = mutableListOf() var current = tmpCycleFlag var cycleEndFlag = true - while(cycleEndFlag){ - path.add(current) - if (current == tmpCycleFlag && path.size >1){ + while (cycleEndFlag) { + + + if (current == tmpCycleFlag && resultPathVertices.size > 1) { cycleEndFlag = false + break + } + resultPathVertices.add(current) + val destVertexID = current + val sourseVertexID = pathVertices[current - 1] + 1 + for (edgeID in curGraph.vertices[sourseVertexID]!!.incidentEdges) { + if (curGraph.edges[edgeID]!!.vertices.second == destVertexID) { + resultPathEdges.add(edgeID) + break + } + } + current = pathVertices[current-1]+1 + } + } + + fun shortestPath(startVertexID: Int, endVertexID: Int) { + pathsLength[startVertexID - 1] = 0 + var curCycleFlag = -1 + for (i in 0 until verticesNumber) { + curCycleFlag = -1 + for (j in 0 until edgesNumber) { + val firstVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.first - 1] + var secondVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] + if (firstVertexPath < INF) { + if (secondVertexPath > firstVertexPath + curGraph.edges[j + 1]!!.weight) { + pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] = + max(-INF, firstVertexPath + curGraph.edges[j + 1]!!.weight) + pathEdges[curGraph.edges[j + 1]!!.id - 1] = j + 1 + pathVertices[curGraph.edges[j + 1]!!.vertices.second - 1] = + curGraph.edges[j + 1]!!.vertices.first - 1 + curCycleFlag = curGraph.edges[j + 1]!!.vertices.second + } + } } - current=resultPath[current] } - println("Negative cycle:") - path.forEach { - print("$it ") + if (curCycleFlag == -1) { + if (pathsLength[endVertexID - 1] == INF) { + disconnectedGraphFlag = true + return + } else { + pathBuilder(endVertexID) + } + } else { + cycleFlag=true + negativeCycleBuilder(curCycleFlag) } } -} \ No newline at end of file + + private fun pathBuilder(endVertexID: Int) { + resultPathVertices.add(endVertexID) + var tmp = endVertexID + do { + val destVertexID = tmp + val sourceVertexID = pathVertices[tmp - 1] + 1 + for (edgeID:Int in curGraph.vertices[sourceVertexID]!!.incidentEdges) { + if (curGraph.edges[edgeID]!!.vertices.second == destVertexID) { + resultPathEdges.add(edgeID) + break + } + } + resultPathVertices.add(sourceVertexID) + tmp = pathVertices[tmp-1] + 1 + } while (pathVertices[tmp-1] != -1) + } +} + + + diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt index 4723b0c..bf78b48 100644 --- a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -1,6 +1,5 @@ package graphs.algorithms -import algorithms.BridgeFinder import algorithms.FordBellman import model.graph.Graph import org.junit.jupiter.api.Assertions.assertEquals @@ -10,53 +9,97 @@ import org.junit.jupiter.api.Test class FordBellmanTest { private lateinit var graph: Graph - @BeforeEach - fun setup() { + + @Test + @DisplayName("Path without negative cycles") + public fun PathWithoutNegativeCycles(){ graph = Graph().apply { - addVertex(1,"Thomas Shelby") + addVertex(1, "Thomas Shelby") addVertex(2, "Andrew Tate") addVertex(3, "Iakov") addVertex(4, "John Shelby") - addVertex(5, "Tristan Tate") - addVertex(6, "Arthur Shelby") - addVertex(7, "Ryan Gosling") - - addEdge(1, 2, 1,1) - addEdge(3, 4, 2,2) - addEdge(1, 3, 3,3) - addEdge(2, 4, 4,4) - addEdge(2, 5, 5,5) - addEdge(5, 7, 6,6) - - addVertex(8, "Pudge") - addVertex(9,"Tiny") - addVertex(10, "Lycan") - addVertex(11,"Io") - addVertex(12,"Lion") - addVertex(13,"Sniper") - addVertex(14,"Roshan") - - addEdge(14, 8, 7,7) - addEdge(14, 9, 8,8) - addEdge(14, 10, 9,9) - addEdge(14, 11, 10,10) - addEdge(14, 12, 11,11) - addEdge(14, 13, 12,12) - - addEdge(14, 3, 0,13) + addVertex(5, "Arthur Shelby") + addEdge(1, 2, 3, 5) + addEdge(2, 3, 6, 2) + addEdge(1, 4, 2, 4) + addEdge(5, 3, 1, 3) + addEdge(1, 3, 5, 1) + addEdge(4, 5, 1, 6) } + val fordBellman = FordBellman(graph) + fordBellman.shortestPath(1,3) + val resultVertices = fordBellman.resultPathVertices + val resultEdges = fordBellman.resultPathEdges + val resultCycles = fordBellman.cycleFlag + val resultConnectionFlag = fordBellman.disconnectedGraphFlag + val expectedCycles = false + val expectedEdges = listOf(3,6,4) + val expectedVertices = listOf(3,5,4,1) + val expectedConnectionFlag = false + assertEquals(expectedConnectionFlag, resultConnectionFlag) + assertEquals(expectedCycles, resultCycles) + assertEquals(expectedEdges, resultEdges) + assertEquals(expectedVertices, resultVertices) } @Test - @DisplayName("Path without negative cycles") - public fun PathWithoutNegativeCycles(){ + @DisplayName("Path with negative cycles") + public fun PathWithNegativeCycles(){ + graph = Graph().apply { + addVertex(1, "Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "John Shelby") + + addEdge(1, 2, -2, 3) + addEdge(2, 3, 1, 2) + addEdge(4, 1, -1, 1) + addEdge(3, 4, 1, 4) + addEdge(4, 5, 5, 5) + } val fordBellman = FordBellman(graph) - fordBellman.shortestPath() + fordBellman.shortestPath(1,5) + val resultVertices = fordBellman.resultPathVertices + val resultEdges = fordBellman.resultPathEdges + val resultCycles = fordBellman.cycleFlag + val resultConnectionFlag = fordBellman.disconnectedGraphFlag + val expectedCycles = true + val expectedEdges = listOf(3,1,4,2) + val expectedVertices = listOf(2,1,4,3) + val expectedConnectionFlag = false + assertEquals(expectedConnectionFlag, resultConnectionFlag) + assertEquals(expectedCycles, resultCycles) + assertEquals(expectedEdges, resultEdges) + assertEquals(expectedVertices, resultVertices) + } + @Test + @DisplayName("Disconnected graph") + public fun DisconnectedGraph(){ + graph = Graph().apply { + addVertex(1, "Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "John Shelby") - val resultVertices = fordBellman.verticesPath - val resultEdges = fordBellman.edgesPath - val expectedEdges = listOf(1) - val expectedVertices = listOf(1) + addEdge(1, 2, 2, 3) + addEdge(2, 3, 1, 2) + addEdge(4, 1, -1, 1) + addEdge(3, 4, 1, 4) + } + val fordBellman = FordBellman(graph) + fordBellman.shortestPath(1,5) + val resultVertices = fordBellman.resultPathVertices + val resultEdges = fordBellman.resultPathEdges + val resultCycles = fordBellman.cycleFlag + val resultConnectionFlag = fordBellman.disconnectedGraphFlag + val expectedCycles = false + val expectedEdges = listOf() + val expectedVertices = listOf() + val expectedConnectionFlag = true + assertEquals(expectedConnectionFlag, resultConnectionFlag) + assertEquals(expectedCycles, resultCycles) assertEquals(expectedEdges, resultEdges) assertEquals(expectedVertices, resultVertices) } From 1aa982b4052b2188d926ad5f0be3445574ed677e Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 22 May 2024 18:06:54 +0300 Subject: [PATCH 099/211] feat(db): Query fixed --- src/main/kotlin/database/neo4j/Repository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/database/neo4j/Repository.kt b/src/main/kotlin/database/neo4j/Repository.kt index 65ba203..e3375ee 100644 --- a/src/main/kotlin/database/neo4j/Repository.kt +++ b/src/main/kotlin/database/neo4j/Repository.kt @@ -20,8 +20,8 @@ class Neo4jRepository(uri: String, user: String, password: String) : Closeable { fun addEdge(firstVertexId: Int,secondVertexId: Int, weight: Long, edgeId: Int) { session.writeTransaction { tx -> - tx.run("MATCH (v1:Vertex {id:\$id1}), (v2:Vertex {id:\$id2}) " + - "CREATE (v1)-[:CONNECTED_TO {id:\$edgeId, weight:\$weight}]->(v2)", + tx.run("MATCH (v1:Vertex {id:\$id1}) MATCH (v2:Vertex {id:\$id2}) " + + "CREATE (v1)-[:Edge {id:\$edgeId, weight:\$weight}]->(v2)", Values.parameters("id1", firstVertexId, "id2", secondVertexId, "edgeId", edgeId, "weight", weight)) } } From 553e05fd7867e31eeabe74e36cc8f73915f79f16 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 22 May 2024 18:18:18 +0300 Subject: [PATCH 100/211] fix(db): Query vertex pull fixed --- src/main/kotlin/database/neo4j/Repository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/database/neo4j/Repository.kt b/src/main/kotlin/database/neo4j/Repository.kt index e3375ee..3dccd46 100644 --- a/src/main/kotlin/database/neo4j/Repository.kt +++ b/src/main/kotlin/database/neo4j/Repository.kt @@ -30,7 +30,7 @@ class Neo4jRepository(uri: String, user: String, password: String) : Closeable { val graph = Graph() session.readTransaction { tx -> - val verticesResult = tx.run("MATCH (v:Vertex) RETURN v.id AS id, v.data AS data, v.community AS community)",) + val verticesResult = tx.run("MATCH (v:Vertex) RETURN v.id AS id, v.data AS data, v.community AS community",) verticesResult.list().forEach { record -> val vertexId = record.get("id").asInt() val vertexData = record.get("data").asString() @@ -39,7 +39,7 @@ class Neo4jRepository(uri: String, user: String, password: String) : Closeable { graph.vertices[vertexId]!!.community = vertexCommunity } - val edgesResult = tx.run("MATCH (v1:Vertex)-[e:CONNECTED_TO]->(v2:Vertex) RETURN e.id AS id, v1.id AS v1, v2.id AS v2, e.weight AS weight") + val edgesResult = tx.run("MATCH (v1:Vertex)-[e:Edge]->(v2:Vertex) RETURN e.id AS id, v1.id AS v1, v2.id AS v2, e.weight AS weight") edgesResult.list().forEach { record -> val edgeId = record.get("id").asInt() val firstVertexId = record.get("v1").asInt() From 8e42f1cd6f3e9d5ca53e56c1f8c88f1f310cfc90 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 22 May 2024 18:56:44 +0300 Subject: [PATCH 101/211] fix(graph): graph method addV fixed --- src/main/kotlin/graph/model/Graph.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/graph/model/Graph.kt b/src/main/kotlin/graph/model/Graph.kt index 6c87470..4739a7d 100644 --- a/src/main/kotlin/graph/model/Graph.kt +++ b/src/main/kotlin/graph/model/Graph.kt @@ -9,7 +9,11 @@ class Graph{ fun getEdges(): Collection = edges.values - fun addVertex(id: Int, v: String): Vertex = vertices.getOrPut(id) { Vertex(v) } + fun addVertex(id: Int, v: String): Vertex { + val newVertex = Vertex(v) + newVertex.id = id + return vertices.getOrPut(id) { newVertex } + } fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { if (!isDirected){ From 64ae40638c40407ad1a083b86b71b488a91a3a34 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 22 May 2024 19:51:51 +0300 Subject: [PATCH 102/211] feat(db): directed/n.directed edge could be added --- src/main/kotlin/database/neo4j/Neo4jDBHandler.kt | 11 +++++++++-- src/main/kotlin/database/neo4j/Repository.kt | 12 +++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt b/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt index 8f77e1d..60099db 100644 --- a/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt +++ b/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt @@ -9,8 +9,15 @@ class Neo4jHandler(private val repository: Neo4jRepository) { repository.addVertex(vertex.id, vertex.data, vertex.community) } - for (edge in graph.getEdges()) { - repository.addEdge(edge.vertices.first, edge.vertices.second, edge.weight, edge.id) + if (graph.isDirected) { + for (edge in graph.getEdges()) { + repository.addDirectedEdge(edge.vertices.first, edge.vertices.second, edge.weight, edge.id) + } + + } else { + for (edge in graph.getEdges()) { + repository.addEdge(edge.vertices.first, edge.vertices.second, edge.weight, edge.id) + } } } diff --git a/src/main/kotlin/database/neo4j/Repository.kt b/src/main/kotlin/database/neo4j/Repository.kt index 3dccd46..c27a35d 100644 --- a/src/main/kotlin/database/neo4j/Repository.kt +++ b/src/main/kotlin/database/neo4j/Repository.kt @@ -18,7 +18,7 @@ class Neo4jRepository(uri: String, user: String, password: String) : Closeable { } } - fun addEdge(firstVertexId: Int,secondVertexId: Int, weight: Long, edgeId: Int) { + fun addDirectedEdge(firstVertexId: Int,secondVertexId: Int, weight: Long, edgeId: Int) { session.writeTransaction { tx -> tx.run("MATCH (v1:Vertex {id:\$id1}) MATCH (v2:Vertex {id:\$id2}) " + "CREATE (v1)-[:Edge {id:\$edgeId, weight:\$weight}]->(v2)", @@ -26,6 +26,16 @@ class Neo4jRepository(uri: String, user: String, password: String) : Closeable { } } + + fun addEdge(firstVertexId: Int,secondVertexId: Int, weight: Long, edgeId: Int) { + session.writeTransaction { tx -> + tx.run("MATCH (v1:Vertex {id:\$id1}) MATCH (v2:Vertex {id:\$id2}) " + + "MERGE (v1)-[:Edge {id:\$edgeId, weight:\$weight}]-(v2)", + Values.parameters("id1", firstVertexId, "id2", secondVertexId, "edgeId", edgeId, "weight", weight)) + } + } + + fun getGraph(): Graph { val graph = Graph() From fe6fb64164e59c64261ee69d8acc2ffe9b2a840e Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 22 May 2024 20:07:59 +0300 Subject: [PATCH 103/211] dep(): no logger impl added --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index 6913a94..b1e9333 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation(compose.desktop.currentOs) + implementation("org.slf4j:slf4j-nop:latest.release") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") } From b9367f8e94b721a2a6fb6950e991143b779be3c7 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 22 May 2024 20:17:16 +0300 Subject: [PATCH 104/211] dep(): gradle dep added --- build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index b1e9333..4a463bc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,6 +24,8 @@ dependencies { implementation(compose.desktop.currentOs) implementation("org.slf4j:slf4j-nop:latest.release") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } compose.desktop { From 39f980acbe97ca7fc38ac56d20dc408a09c8b5cd Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 22 May 2024 20:30:06 +0300 Subject: [PATCH 105/211] feat(db): neo4j save/download graph --- .../{database => model/databases}/neo4j/Neo4jDBHandler.kt | 2 +- .../kotlin/{database => model/databases}/neo4j/Repository.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/kotlin/{database => model/databases}/neo4j/Neo4jDBHandler.kt (96%) rename src/main/kotlin/{database => model/databases}/neo4j/Repository.kt (98%) diff --git a/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt b/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt similarity index 96% rename from src/main/kotlin/database/neo4j/Neo4jDBHandler.kt rename to src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt index 60099db..1b45de8 100644 --- a/src/main/kotlin/database/neo4j/Neo4jDBHandler.kt +++ b/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt @@ -1,4 +1,4 @@ -package database.neo4j +package model.databases.neo4j import graph.model.Graph diff --git a/src/main/kotlin/database/neo4j/Repository.kt b/src/main/kotlin/model/databases/neo4j/Repository.kt similarity index 98% rename from src/main/kotlin/database/neo4j/Repository.kt rename to src/main/kotlin/model/databases/neo4j/Repository.kt index c27a35d..d69fee5 100644 --- a/src/main/kotlin/database/neo4j/Repository.kt +++ b/src/main/kotlin/model/databases/neo4j/Repository.kt @@ -1,4 +1,4 @@ -package database.neo4j +package model.databases.neo4j import graph.model.Graph import org.neo4j.driver.AuthTokens From bb865443e9b9987da9139fe07dc55604cec4b6c7 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Thu, 23 May 2024 12:42:41 +0300 Subject: [PATCH 106/211] fix(dep): graph import fixed --- src/main/kotlin/Main.kt | 2 +- src/main/kotlin/algorithms/BridgeFinder.kt | 2 +- src/main/kotlin/algorithms/Djikstra.kt | 2 +- src/main/kotlin/algorithms/FordBellman.kt | 2 +- src/main/kotlin/algorithms/Kosaraju.kt | 2 +- src/main/kotlin/algorithms/KruskalsAlgorithm.kt | 2 +- src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt | 2 +- src/main/kotlin/model/graph/Graph.kt | 3 +++ src/main/kotlin/viewmodel/graph/GraphViewModel.kt | 2 +- src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt | 2 +- src/test/kotlin/graphs/algorithms/DjikstraTest.kt | 2 +- src/test/kotlin/graphs/algorithms/FordBellmanTest.kt | 2 +- src/test/kotlin/graphs/algorithms/KosajaruTest.kt | 2 +- 13 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 2bbec8f..c67369d 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -9,7 +9,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.window.Window import androidx.compose.ui.window.application -import model.graph.Graph +import graph.model.Graph import view.Canvas import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index 6d743b9..90d83ce 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -1,6 +1,6 @@ package algorithms -import model.graph.Graph +import graph.model.Graph import java.awt.geom.Point2D.distance import kotlin.math.min diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index f6ecfc8..72305a6 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -1,6 +1,6 @@ package algorithms -import model.graph.Graph +import graph.model.Graph class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { private val distance = hashMapOf() diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt index 82a6f52..c3ec551 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -1,6 +1,6 @@ package algorithms -import model.graph.Graph +import graph.model.Graph import kotlin.math.max diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index aeabb34..425cbf0 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -1,6 +1,6 @@ package algorithms -import model.graph.Graph +import graph.model.Graph class Kosaraju(private val graph: Graph) { private val used = hashMapOf() diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt index 347935a..d53131f 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -1,7 +1,7 @@ package algorithms +import graph.model.Graph import model.graph.Edge -import model.graph.Graph class KruskalsMST { private fun kruskals(graph: Graph) { diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index a8cc06b..f49ba5b 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -7,8 +7,8 @@ import model.databases.sqlite.dao.vertices.Vertices import model.databases.sqlite.dao.verticesView.VertexView import model.databases.sqlite.dao.verticesView.VerticesView import androidx.compose.ui.unit.dp +import graph.model.Graph -import model.graph.Graph import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.exists import org.jetbrains.exposed.sql.transactions.transaction diff --git a/src/main/kotlin/model/graph/Graph.kt b/src/main/kotlin/model/graph/Graph.kt index 4739a7d..22b89b5 100644 --- a/src/main/kotlin/model/graph/Graph.kt +++ b/src/main/kotlin/model/graph/Graph.kt @@ -1,5 +1,8 @@ package graph.model +import model.graph.Edge +import model.graph.Vertex + class Graph{ var isDirected: Boolean = false val vertices = hashMapOf() diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 31fabf3..0248cb9 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -3,8 +3,8 @@ package viewmodel.graph import androidx.compose.runtime.State import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import graph.model.Graph import model.graph.Edge -import model.graph.Graph import model.graph.Vertex diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index 29fab8f..277eef3 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import algorithms.BridgeFinder -import model.graph.Graph +import graph.model.Graph import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt index 9a5e665..fa897fb 100644 --- a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt +++ b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import algorithms.Djikstra -import model.graph.Graph +import graph.model.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt index bf78b48..521fcb1 100644 --- a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import algorithms.FordBellman -import model.graph.Graph +import graph.model.Graph import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName diff --git a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt index a0ab04c..0d19169 100644 --- a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import algorithms.Kosaraju -import model.graph.Graph +import graph.model.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* From 0519fb9dc5b702f68df358a9a2af45f6e7fa7b4e Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Thu, 23 May 2024 12:43:19 +0300 Subject: [PATCH 107/211] fix(dep): graph import fixed --- src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 9684bcb..8230af2 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -2,7 +2,7 @@ package viewmodel import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.graphics.Color -import model.graph.Graph +import graph.model.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy From b5efb903777f53c80d12c80fb0590b128301af23 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Thu, 23 May 2024 12:58:30 +0300 Subject: [PATCH 108/211] feat(dep): lib impl. added --- build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4a463bc..f758efc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,8 +24,9 @@ dependencies { implementation(compose.desktop.currentOs) implementation("org.slf4j:slf4j-nop:latest.release") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") - testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + implementation("nl.cwts", "networkanalysis", "1.3.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") } compose.desktop { From f1419c1a66016bc8fc82aef1da6119be6a75e32b Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Thu, 23 May 2024 16:16:10 +0300 Subject: [PATCH 109/211] feat(algo): community finder class added --- .../kotlin/model/community/CommunityFinder.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/kotlin/model/community/CommunityFinder.kt diff --git a/src/main/kotlin/model/community/CommunityFinder.kt b/src/main/kotlin/model/community/CommunityFinder.kt new file mode 100644 index 0000000..dba22db --- /dev/null +++ b/src/main/kotlin/model/community/CommunityFinder.kt @@ -0,0 +1,24 @@ +package model.community + +import graph.model.Graph +import nl.cwts.networkanalysis.Clustering +import nl.cwts.networkanalysis.LeidenAlgorithm +import nl.cwts.networkanalysis.Network + +class CommunityFinder { + + fun findCommunity(graph: Graph, nIterations: String, resolution: String): Boolean { + val doubleResolution = resolution.toDoubleOrNull() + val intNIterations = nIterations.toIntOrNull() + if (doubleResolution == null || intNIterations == null || graph.getVertices().isEmpty()) { + return false + } + val network = graph.toNetwork() + + val algorithm = LeidenAlgorithm(doubleResolution, intNIterations, LeidenAlgorithm.DEFAULT_RANDOMNESS, Random()) + val ans = algorithm.findClustering(network) + + graph.setCommunity(ans) + return true + } +} From 29b26cadd83c22d9e160c383c957d04c584e3996 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Thu, 23 May 2024 16:59:15 +0300 Subject: [PATCH 110/211] feat(algo): community finder class method added --- build.gradle.kts | 2 +- .../kotlin/model/community/CommunityFinder.kt | 28 +++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f758efc..2bbe563 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(compose.desktop.currentOs) implementation("org.slf4j:slf4j-nop:latest.release") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") - implementation("nl.cwts", "networkanalysis", "1.3.0") + implementation("nl.cwts", "networkanalysis", "1.1.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") } diff --git a/src/main/kotlin/model/community/CommunityFinder.kt b/src/main/kotlin/model/community/CommunityFinder.kt index dba22db..61d7aa6 100644 --- a/src/main/kotlin/model/community/CommunityFinder.kt +++ b/src/main/kotlin/model/community/CommunityFinder.kt @@ -5,9 +5,10 @@ import nl.cwts.networkanalysis.Clustering import nl.cwts.networkanalysis.LeidenAlgorithm import nl.cwts.networkanalysis.Network -class CommunityFinder { +class CommunityFinder(private val graph: Graph) { - fun findCommunity(graph: Graph, nIterations: String, resolution: String): Boolean { + // main algorithm steps + fun findCommunity(nIterations: String, resolution: String): Boolean { val doubleResolution = resolution.toDoubleOrNull() val intNIterations = nIterations.toIntOrNull() if (doubleResolution == null || intNIterations == null || graph.getVertices().isEmpty()) { @@ -15,10 +16,31 @@ class CommunityFinder { } val network = graph.toNetwork() - val algorithm = LeidenAlgorithm(doubleResolution, intNIterations, LeidenAlgorithm.DEFAULT_RANDOMNESS, Random()) + val random = java.util.Random() + val algorithm = LeidenAlgorithm(doubleResolution, intNIterations, LeidenAlgorithm.DEFAULT_RANDOMNESS, random) val ans = algorithm.findClustering(network) graph.setCommunity(ans) return true } + + // we need to create network from our graph + private fun Graph.toNetwork(): Network { + + val edgesList = graph.getEdges() + + val edges = Array(2) { IntArray(edgesList.size) { 0 } } + for ((i, edge) in edgesList.withIndex()) { + edges[0][i] = edge.vertices.first + edges[1][i] = edge.vertices.second + } + + return Network(graph.getVertices().size, false, edges, false, false) + } + + private fun Graph.setCommunity(clustering: Clustering) { + for ((i, vertex) in graph.getVertices().withIndex()) { + vertex.community = clustering.clusters[i] + } + } } From af6592ab6adce7c7ee8964b3763341b6941018bd Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Fri, 24 May 2024 00:49:24 +0300 Subject: [PATCH 111/211] feat(algo): Kosaraju algo fixed --- src/main/kotlin/algorithms/Kosaraju.kt | 4 -- .../kotlin/model/community/CommunityFinder.kt | 46 ------------------- .../kotlin/graphs/algorithms/KosajaruTest.kt | 10 +++- 3 files changed, 8 insertions(+), 52 deletions(-) delete mode 100644 src/main/kotlin/model/community/CommunityFinder.kt diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index 425cbf0..b602b5c 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -8,10 +8,6 @@ class Kosaraju(private val graph: Graph) { private val component = mutableListOf() fun findStronglyConnectedComponents(): List> { - if (!graph.isDirected) { - return emptyList>() - } - // Step 1: Transpose the graph val transposedGraph = transposeGraph() diff --git a/src/main/kotlin/model/community/CommunityFinder.kt b/src/main/kotlin/model/community/CommunityFinder.kt deleted file mode 100644 index 61d7aa6..0000000 --- a/src/main/kotlin/model/community/CommunityFinder.kt +++ /dev/null @@ -1,46 +0,0 @@ -package model.community - -import graph.model.Graph -import nl.cwts.networkanalysis.Clustering -import nl.cwts.networkanalysis.LeidenAlgorithm -import nl.cwts.networkanalysis.Network - -class CommunityFinder(private val graph: Graph) { - - // main algorithm steps - fun findCommunity(nIterations: String, resolution: String): Boolean { - val doubleResolution = resolution.toDoubleOrNull() - val intNIterations = nIterations.toIntOrNull() - if (doubleResolution == null || intNIterations == null || graph.getVertices().isEmpty()) { - return false - } - val network = graph.toNetwork() - - val random = java.util.Random() - val algorithm = LeidenAlgorithm(doubleResolution, intNIterations, LeidenAlgorithm.DEFAULT_RANDOMNESS, random) - val ans = algorithm.findClustering(network) - - graph.setCommunity(ans) - return true - } - - // we need to create network from our graph - private fun Graph.toNetwork(): Network { - - val edgesList = graph.getEdges() - - val edges = Array(2) { IntArray(edgesList.size) { 0 } } - for ((i, edge) in edgesList.withIndex()) { - edges[0][i] = edge.vertices.first - edges[1][i] = edge.vertices.second - } - - return Network(graph.getVertices().size, false, edges, false, false) - } - - private fun Graph.setCommunity(clustering: Clustering) { - for ((i, vertex) in graph.getVertices().withIndex()) { - vertex.community = clustering.clusters[i] - } - } -} diff --git a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt index 0d19169..82a1be5 100644 --- a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -133,12 +133,18 @@ class KosarajuTest { } @Test - fun `test components output non-directed graph`() { + fun `test components output non directed`() { // graph and algo initialization val graph = createSampleGraph() graph.isDirected = false val algo = Kosaraju(graph) - val expected = emptyList>() + val expected = mutableListOf( + mutableListOf(3, 8, 5, 10), + mutableListOf(2, 9, 4), + mutableListOf(11), + mutableListOf(1), + mutableListOf(0,7,6), + ) // algo start from different positions val currently = algo.findStronglyConnectedComponents() From e464871358abba2196fb11ff44383af8e140e5ea Mon Sep 17 00:00:00 2001 From: dronshock Date: Fri, 24 May 2024 12:10:58 +0300 Subject: [PATCH 112/211] fix: correct imports --- src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt | 2 +- src/main/kotlin/model/databases/neo4j/Repository.kt | 2 +- src/main/kotlin/model/graph/Graph.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt b/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt index 1b45de8..2e7dcdc 100644 --- a/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt +++ b/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt @@ -1,6 +1,6 @@ package model.databases.neo4j -import graph.model.Graph +import model.graph.Graph class Neo4jHandler(private val repository: Neo4jRepository) { diff --git a/src/main/kotlin/model/databases/neo4j/Repository.kt b/src/main/kotlin/model/databases/neo4j/Repository.kt index d69fee5..450d22f 100644 --- a/src/main/kotlin/model/databases/neo4j/Repository.kt +++ b/src/main/kotlin/model/databases/neo4j/Repository.kt @@ -1,6 +1,6 @@ package model.databases.neo4j -import graph.model.Graph +import model.graph.Graph import org.neo4j.driver.AuthTokens import org.neo4j.driver.Driver import org.neo4j.driver.GraphDatabase diff --git a/src/main/kotlin/model/graph/Graph.kt b/src/main/kotlin/model/graph/Graph.kt index 4739a7d..a0fd545 100644 --- a/src/main/kotlin/model/graph/Graph.kt +++ b/src/main/kotlin/model/graph/Graph.kt @@ -1,4 +1,4 @@ -package graph.model +package model.graph class Graph{ var isDirected: Boolean = false From b5778a89fe3780a40e104cf022b23bb38f6a83cb Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sat, 25 May 2024 23:34:12 +0300 Subject: [PATCH 113/211] feat(algo): Realtion class added --- src/main/kotlin/model/community/Relation.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/kotlin/model/community/Relation.kt diff --git a/src/main/kotlin/model/community/Relation.kt b/src/main/kotlin/model/community/Relation.kt new file mode 100644 index 0000000..b376329 --- /dev/null +++ b/src/main/kotlin/model/community/Relation.kt @@ -0,0 +1,4 @@ +package model.community + +class Relation(val closeness: Long = 1L, val id: Int) { +} \ No newline at end of file From e2bd686423dbb1223094ebfb55a5611be9c2a8fa Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sat, 25 May 2024 23:34:25 +0300 Subject: [PATCH 114/211] feat(algo): Neighbour class added --- src/main/kotlin/model/community/Neighbours.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/model/community/Neighbours.kt diff --git a/src/main/kotlin/model/community/Neighbours.kt b/src/main/kotlin/model/community/Neighbours.kt new file mode 100644 index 0000000..3273637 --- /dev/null +++ b/src/main/kotlin/model/community/Neighbours.kt @@ -0,0 +1,5 @@ +package model.community + +class Neighbours { + val neighbours : MutableMap> = mutableMapOf() +} \ No newline at end of file From 378b84dfed0b11537f710be13a5ae76777defee6 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sat, 25 May 2024 23:35:38 +0300 Subject: [PATCH 115/211] fix(dep): dep fixed --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2bbe563..aad6057 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,7 +24,6 @@ dependencies { implementation(compose.desktop.currentOs) implementation("org.slf4j:slf4j-nop:latest.release") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") - implementation("nl.cwts", "networkanalysis", "1.1.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") } From d08c7a54c1799833b644480ec311c00a9dbd6dc4 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sat, 25 May 2024 23:37:05 +0300 Subject: [PATCH 116/211] feat(algo): Louvain algo skeleton added --- src/main/kotlin/model/community/Louvain.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/kotlin/model/community/Louvain.kt diff --git a/src/main/kotlin/model/community/Louvain.kt b/src/main/kotlin/model/community/Louvain.kt new file mode 100644 index 0000000..d15a4ac --- /dev/null +++ b/src/main/kotlin/model/community/Louvain.kt @@ -0,0 +1,12 @@ +package model.community + +import graph.model.Graph + +class Louvain(private val graph: Graph) { + private val currCommunities = mutableMapOf() + private val n = getNeighbours() + private var targetCommunity = currCommunities + private var modularity = calculateModularity(currCommunities) + + +} \ No newline at end of file From fea01fd600fd87106b00a83fbc64f856d6835c7d Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sat, 25 May 2024 23:37:52 +0300 Subject: [PATCH 117/211] feat(algo): Louvain algo findCommunity method added --- src/main/kotlin/model/community/Louvain.kt | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/main/kotlin/model/community/Louvain.kt b/src/main/kotlin/model/community/Louvain.kt index d15a4ac..b223471 100644 --- a/src/main/kotlin/model/community/Louvain.kt +++ b/src/main/kotlin/model/community/Louvain.kt @@ -8,5 +8,45 @@ class Louvain(private val graph: Graph) { private var targetCommunity = currCommunities private var modularity = calculateModularity(currCommunities) + fun findCommunities() : List> { + do { + var stop = false + + for (anchor in n.neighbours.keys) { + + for (neighbourCommunity in n.neighbours.keys) { + if (anchor != neighbourCommunity && currCommunities[anchor] != neighbourCommunity) { + val newCommunities = targetCommunity.toMutableMap() + + newCommunities[anchor] = currCommunities[neighbourCommunity]!! + val newModularity = calculateModularity(newCommunities) + + if (newModularity > modularity) { + modularity = newModularity + targetCommunity = newCommunities + currCommunities[anchor] = currCommunities[neighbourCommunity]!! + stop = true + break + } + } + } + + if (stop) break + } + } while (stop) + + val answer = mutableListOf>() + for (value in targetCommunity.values.toSet()) { + val keys = mutableSetOf() + for ((key, value1) in targetCommunity) { + if (value1 == value) + keys.add(key) + } + + answer.add(keys) + } + + return paintGraph(answer) + } } \ No newline at end of file From 0b61b1299143c31a1d774b94567b7a8ad43c8e4a Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sat, 25 May 2024 23:38:25 +0300 Subject: [PATCH 118/211] feat(algo): Louvain get neighbour method added --- src/main/kotlin/model/community/Louvain.kt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/kotlin/model/community/Louvain.kt b/src/main/kotlin/model/community/Louvain.kt index b223471..84e8cb2 100644 --- a/src/main/kotlin/model/community/Louvain.kt +++ b/src/main/kotlin/model/community/Louvain.kt @@ -49,4 +49,34 @@ class Louvain(private val graph: Graph) { return paintGraph(answer) } + private fun getNeighbours(): Neighbours { + val graphEdges = graph.getEdges() + val n = Neighbours() + + for (vertex in graph.getVertices()) { + n.neighbours[vertex.id] = mutableSetOf() + } + + // initialize network + for (edge in graphEdges) { + val neighbour1 = edge.vertices.first + val neighbour2 = edge.vertices.second + val closeness = edge.weight + if (graph.isDirected) { + n.neighbours.getOrPut(neighbour1) { mutableSetOf() }.add(Relation(closeness, neighbour2)) + } else { + n.neighbours.getOrPut(neighbour1) { mutableSetOf() }.add(Relation(closeness, neighbour2)) + n.neighbours.getOrPut(neighbour2) { mutableSetOf() }.add(Relation(closeness, neighbour1)) + } + } + + // initialize start community position + for (id in n.neighbours.keys) { + currCommunities[id] = id + } + + return n + } + + } \ No newline at end of file From 3cb3de455ff6353716ba548f17566b0830cb8fa2 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sat, 25 May 2024 23:39:34 +0300 Subject: [PATCH 119/211] feat(algo): Louvain class implementation --- src/main/kotlin/model/community/Louvain.kt | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/kotlin/model/community/Louvain.kt b/src/main/kotlin/model/community/Louvain.kt index 84e8cb2..b5fd46b 100644 --- a/src/main/kotlin/model/community/Louvain.kt +++ b/src/main/kotlin/model/community/Louvain.kt @@ -78,5 +78,29 @@ class Louvain(private val graph: Graph) { return n } + private fun calculateModularity(communities: Map): Double { + var link = 0.0 + val closeness = n.neighbours.values.sumOf { it.size }.toDouble() / 2 + + for (anchor in n.neighbours.keys) { + for (relation in n.neighbours[anchor]!!) { + val neighbour = relation.id + if (communities[anchor] == communities[neighbour]) { + link += 1.0 - (n.neighbours[anchor]!!.size * n.neighbours[neighbour]!!.size) / (2 * closeness) + } + } + } + + return link / (2 * closeness) + } + private fun paintGraph(comm : List>) : List> { + for ((newCommunityIndex, community) in comm.withIndex()) { + for (vertexIdx in community) { + graph.vertices[vertexIdx]!!.community = newCommunityIndex + } + } + + return comm + } } \ No newline at end of file From 4f31131f0e4d4cf30cdd85440aadcee5fcd94df5 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 26 May 2024 00:14:40 +0300 Subject: [PATCH 120/211] feat(tests): Louvain test added --- .../kotlin/graphs/algorithms/LouvainTest.kt | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/test/kotlin/graphs/algorithms/LouvainTest.kt diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt new file mode 100644 index 0000000..26ca50c --- /dev/null +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -0,0 +1,64 @@ +package graphs.algorithms + +import algorithms.Kosaraju +import graph.model.Graph +import model.community.Louvain +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +// graph sample +// +// 7 11 → → → → → → → 5 +// ↗ ↓ ↘ ↙ ↘ ↙ ↑ ↘ +// 0 ↓ 1 → → → 9 ← ← ← 2 → → → 10 ↑ 3 +// ↖ ↓ ↗ ↘ ↗ ↘ ↑ ↙ +// 6 → → → → → → 4 8 +// + +// graph sample 2 +// +// 1 → → → 2 +// ↘ ↙ +// 3 +// ↓ +// ↓ +// 4 +// ↙ ↘ +// 5 → → → 6 +// + +fun createSampleGraph2(): Graph { + val graph = Graph() + graph.isDirected = true + + graph.addVertex(1, "A") + graph.addVertex(2, "B") + graph.addVertex(3, "C") + graph.addVertex(4, "D") + graph.addVertex(5, "E") + graph.addVertex(6, "F") + + graph.addEdge(1, 2, 10L, 1) + graph.addEdge(1, 3, 5L, 2) + graph.addEdge(2, 3, 5L, 3) + graph.addEdge(3, 4, 15L, 4) + graph.addEdge(4, 5, 5L, 5) + graph.addEdge(4, 6, 5L, 6) + graph.addEdge(5, 6, 10L, 7) + return graph +} + +class LouvainTest { + @Test + fun `test louvain set output directed`() { + // graph and algo initialization + val graph = createSampleGraph() + val algo = Louvain(graph) + val expected = mutableListOf(setOf(0,7,1,6), setOf(9,11,2,4), setOf(10,5,3,8)) + + val currently = algo.findCommunities() + + assertTrue(expected == currently) + } + +} \ No newline at end of file From fcc59ef47c20a229759fdb6a94c244a93681aada Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 26 May 2024 00:15:00 +0300 Subject: [PATCH 121/211] feat(tests): Louvain test added --- src/test/kotlin/graphs/algorithms/LouvainTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index 26ca50c..1c183ec 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -61,4 +61,18 @@ class LouvainTest { assertTrue(expected == currently) } + @Test + fun `test louvain set output non directed`() { + // graph and algo initialization + val graph = createSampleGraph() + graph.isDirected = false + val algo = Louvain(graph) + val expected = mutableListOf(setOf(0,1,2,4,6,7,9,11), setOf(10,5,3,8)) + + val currently = algo.findCommunities() + + assertTrue(expected == currently) + } + + } \ No newline at end of file From 352e367bf9e240f91cf989e02656df5e5f992f19 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 26 May 2024 00:15:09 +0300 Subject: [PATCH 122/211] feat(tests): Louvain test added --- .../kotlin/graphs/algorithms/LouvainTest.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index 1c183ec..a173a20 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -74,5 +74,23 @@ class LouvainTest { assertTrue(expected == currently) } + @Test + fun `test louvain graph community color`() { + // graph and algo initialization + val graph = createSampleGraph() + val algo = Louvain(graph) + + val expectedCommunities = mutableListOf(0,0,1,2,1,2,0,0,2,1,2,1) + + algo.findCommunities() + + val currentlyCommunities = mutableListOf() + for (vertex in graph.getVertices()) { + currentlyCommunities.add(vertex.community) + } + + assertTrue(expectedCommunities == currentlyCommunities) + } + } \ No newline at end of file From b054541ff757909d42b2f3cf2dae2d39f8b11150 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 26 May 2024 00:15:14 +0300 Subject: [PATCH 123/211] feat(tests): Louvain test added --- .../kotlin/graphs/algorithms/LouvainTest.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index a173a20..38ac813 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -92,5 +92,34 @@ class LouvainTest { assertTrue(expectedCommunities == currentlyCommunities) } + @Test + fun `test louvain graph sample 2 directed`() { + // graph and algo initialization + val graph = createSampleGraph2() + val algo = Louvain(graph) + + val expected = mutableListOf(setOf(1,2,3), setOf(4,5,6)) + + algo.findCommunities() + + val currentlyCommunities = algo.findCommunities() + assertTrue(expected == currentlyCommunities) + } + + @Test + fun `test louvain graph sample 2 not directed`() { + // graph and algo initialization + val graph = createSampleGraph2() + graph.isDirected = false + val algo = Louvain(graph) + + val expected = mutableListOf(setOf(1,2,3), setOf(4,5,6)) + + algo.findCommunities() + + val currentlyCommunities = algo.findCommunities() + + assertTrue(expected == currentlyCommunities) + } } \ No newline at end of file From 5dcb00929f8cdfba4b9fefc7260737010df71224 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 26 May 2024 00:22:18 +0300 Subject: [PATCH 124/211] feat(tests): Louvain test added --- .../kotlin/graphs/algorithms/LouvainTest.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index 38ac813..fc76b29 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -122,4 +122,39 @@ class LouvainTest { assertTrue(expected == currentlyCommunities) } + + @Test + fun `test louvain graph is empty`() { + // graph and algo initialization + val graph = Graph() + graph.isDirected = false + val algo = Louvain(graph) + + val expected = mutableListOf() + + algo.findCommunities() + + val currentlyCommunities = algo.findCommunities() + + assertTrue(expected == currentlyCommunities) + } + + @Test + fun `test louvain graph has no edges`() { + // graph and algo initialization + val graph = Graph() + graph.addVertex(1, "A") + graph.addVertex(2, "B") + graph.addVertex(3, "C") + + val algo = Louvain(graph) + + val expected = mutableListOf(setOf(1), setOf(2), setOf(3)) + + algo.findCommunities() + + val currentlyCommunities = algo.findCommunities() + + assertTrue(expected == currentlyCommunities) + } } \ No newline at end of file From d465ea9b71f177e875855cf28da4ecb940f4b2b2 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 26 May 2024 01:04:37 +0300 Subject: [PATCH 125/211] feat(ui): graph painting by community --- src/main/kotlin/controller/GraphPainter.kt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/kotlin/controller/GraphPainter.kt diff --git a/src/main/kotlin/controller/GraphPainter.kt b/src/main/kotlin/controller/GraphPainter.kt new file mode 100644 index 0000000..00bc1d4 --- /dev/null +++ b/src/main/kotlin/controller/GraphPainter.kt @@ -0,0 +1,30 @@ +package controller + +import androidx.compose.ui.graphics.Color +import graph.model.Graph +import model.community.Louvain +import viewmodel.graph.GraphViewModel +import kotlin.random.Random + +class GraphPainter(private val graph: Graph, private val graphViewModel: GraphViewModel) { + private val finder = Louvain(graph) + private val communities = finder.findCommunities() + + fun paint() { + for (community in communities) { + val communityColor = generateRandomColor(community.hashCode()) + for (vertexID in community) { + val currVertex = graph.vertices[vertexID] + graphViewModel.verticesView[currVertex]!!.color=communityColor + } + } + } + + private fun generateRandomColor(base: Int): Color { + val mRandom = Random(base) + val red: Int = (base + mRandom.nextInt(256)) / 2 + val green: Int = (base + mRandom.nextInt(256)) / 2 + val blue: Int = (base + mRandom.nextInt(256)) / 2 + return Color(red, green, blue) + } +} \ No newline at end of file From 5983166fcbb04988b91964ec3c079bd5969686f3 Mon Sep 17 00:00:00 2001 From: dronshock Date: Sun, 26 May 2024 20:34:34 +0300 Subject: [PATCH 126/211] feat(GUI): add navigation drawer --- src/main/kotlin/Main.kt | 2 + src/main/kotlin/view/CanvasView.kt | 39 +++---------- src/main/kotlin/view/NavigationDrawer.kt | 70 ++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 src/main/kotlin/view/NavigationDrawer.kt diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 2bbec8f..8d2bcff 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -13,6 +13,7 @@ import model.graph.Graph import view.Canvas import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout +import view.MyNavigationDrawer val graph = Graph().apply { addVertex(1,"Thomas Shelby") @@ -52,6 +53,7 @@ val graph = Graph().apply { fun App() { MaterialTheme { Canvas(CanvasViewModel(graph, CircularLayout())) + //MyNavigationDrawer(CanvasViewModel(graph, CircularLayout())) } } diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index fa5d1e1..7351afa 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,51 +1,26 @@ package view +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* -import androidx.compose.material.Button -import androidx.compose.material.Checkbox -import androidx.compose.material.Surface -import androidx.compose.material.Text +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Menu import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel @Composable fun Canvas(viewModel: CanvasViewModel) { + MyNavigationDrawer(viewModel) Row( horizontalArrangement = Arrangement.spacedBy(20.dp) ) { Column(modifier = Modifier.width(370.dp)) { - Row { - Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { - viewModel.showVerticesLabels.value = it - }) - Text("Show vertices labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) - } - Row { - Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { - viewModel.showEdgesLabels.value = it - }) - Text("Show edges labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) - } - Button( - onClick = viewModel::resetGraphView, - enabled = true, - ) { - Text( - text = "Reset default settings", - ) - } - Button( - onClick = viewModel::setVerticesColor, - enabled = true, - ) { - Text( - text = "Set colors", - ) - } } Surface( diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt new file mode 100644 index 0000000..dbd6f6a --- /dev/null +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -0,0 +1,70 @@ +package view + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Menu +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch +import view.graph.GraphView +import viewmodel.CanvasViewModel + +@Composable +fun MyNavigationDrawer(viewModel: CanvasViewModel) { + val drawerState = rememberDrawerState(DrawerValue.Closed) + val scope = rememberCoroutineScope() + + ModalDrawer( + drawerState = drawerState, + gesturesEnabled = true, + drawerContent = { + Column(modifier = Modifier.width(370.dp)) { + IconButton(onClick = { scope.launch { drawerState.close() } }) { + Icon(Icons.Filled.Menu, contentDescription = null) + } + Text("Menu Item 1", modifier = Modifier.padding(10.dp).clickable { scope.launch { drawerState.close() } }) + Text("Menu Item 2", modifier = Modifier.padding(10.dp).clickable { scope.launch { drawerState.close() } }) + Row { + Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { + viewModel.showVerticesLabels.value = it + }) + Text("Show vertices labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) + } + Row { + Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { + viewModel.showEdgesLabels.value = it + }) + Text("Show edges labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) + } + Button( + onClick = viewModel::resetGraphView, + enabled = true, + ) { + Text( + text = "Reset default settings", + ) + } + Button( + onClick = viewModel::setVerticesColor, + enabled = true, + ) { + Text( + text = "Set colors", + ) + } + } + }, + content = { + Column(modifier = Modifier.width(370.dp)) { + IconButton(onClick = { scope.launch { drawerState.open() } }) { + Icon(Icons.Filled.Menu, contentDescription = null) + } + } + } + ) +} \ No newline at end of file From 2231e1e4af061300776fe0e309aa73407b41250e Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Sun, 26 May 2024 18:20:10 +0000 Subject: [PATCH 127/211] feat(ci): uncomment approvals --- .github/mergeable.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index 1871dc1..c925d36 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -15,13 +15,13 @@ mergeable: no_empty: enabled: true message: 'Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed.' - # - do: approvals - # min: - # count: 0 - # block: - # changes_requested: true - # limit: - # users: - # - DronShock - # - suvorovrain - # - Sem4kok + - do: approvals + min: + count: 1 + block: + changes_requested: true + limit: + users: + - DronShock + - suvorovrain + - Sem4kok From 024205297a9863a6debab7a328ff180ec5c89469 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Sun, 26 May 2024 21:41:32 +0300 Subject: [PATCH 128/211] feat(ui): graph painting by community --- src/main/kotlin/controller/GraphPainter.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/controller/GraphPainter.kt b/src/main/kotlin/controller/GraphPainter.kt index 00bc1d4..41e3f30 100644 --- a/src/main/kotlin/controller/GraphPainter.kt +++ b/src/main/kotlin/controller/GraphPainter.kt @@ -11,8 +11,8 @@ class GraphPainter(private val graph: Graph, private val graphViewModel: GraphVi private val communities = finder.findCommunities() fun paint() { - for (community in communities) { - val communityColor = generateRandomColor(community.hashCode()) + for ((i, community) in communities.withIndex()) { + val communityColor = generateRandomColor(i * 123) for (vertexID in community) { val currVertex = graph.vertices[vertexID] graphViewModel.verticesView[currVertex]!!.color=communityColor From 4baa908ccdad765d62b9b855c33c54626251d2ec Mon Sep 17 00:00:00 2001 From: dronshock Date: Mon, 27 May 2024 10:05:48 +0300 Subject: [PATCH 129/211] feat(gradle): add material3 dependency --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index 4a463bc..98c6f26 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation(compose.desktop.currentOs) + implementation(compose.material3) implementation("org.slf4j:slf4j-nop:latest.release") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") From 50a3f804f40060328a119d829c500abaa3ea8f7f Mon Sep 17 00:00:00 2001 From: dronshock Date: Mon, 27 May 2024 10:06:33 +0300 Subject: [PATCH 130/211] feat(GUI): add algorithm sub menu raw version --- src/main/kotlin/view/AlgorithmSubMenu.kt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/kotlin/view/AlgorithmSubMenu.kt diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt new file mode 100644 index 0000000..ef752b4 --- /dev/null +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -0,0 +1,22 @@ +package view + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun AlgorithmSubMenu() { + Column(Modifier.padding(start = 16.dp, end = 0.dp, top = 15.dp)) { + Text(text = "Выделение ключевых вершин") + Text(text = "Поиск сообществ") + Text(text = "Выделение компонент сильной связности") + Text(text = "Поиск мостов") + Text(text = "Поиск циклов для заданной вершины") + Text(text = "Построение минимального остовного дерева") + Text(text = "Кратчайший путь алгоритмом Дейкстры") + Text(text = "Кратчайший путь алгоритмом Форда-Беллмана") + } +} \ No newline at end of file From 3f1a77167101b4e0cd787521bd0c08b25f51af5a Mon Sep 17 00:00:00 2001 From: dronshock Date: Mon, 27 May 2024 10:44:20 +0300 Subject: [PATCH 131/211] feat(GUI): update navigation drawer --- src/main/kotlin/view/NavigationDrawer.kt | 94 +++++++++++++++++++----- 1 file changed, 75 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index dbd6f6a..e280c73 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -1,45 +1,87 @@ package view -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.material.* +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch -import view.graph.GraphView import viewmodel.CanvasViewModel @Composable -fun MyNavigationDrawer(viewModel: CanvasViewModel) { +fun NavigationDrawer(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() - ModalDrawer( + val showSubMenu = remember { + mutableStateOf(false) + } + ModalNavigationDrawer( drawerState = drawerState, gesturesEnabled = true, drawerContent = { - Column(modifier = Modifier.width(370.dp)) { - IconButton(onClick = { scope.launch { drawerState.close() } }) { - Icon(Icons.Filled.Menu, contentDescription = null) + ModalDrawerSheet { + Row { + IconButton(onClick = { scope.launch { drawerState.close() } } + ) { + Icon(Icons.Filled.Menu, contentDescription = "Меню") + } + Text("TOP G GANG", modifier = Modifier.padding(16.dp)) + } + Divider() + NavigationDrawerItem( + label = { Text("Menu Item 1") }, + modifier = Modifier.padding(10.dp), + onClick = { scope.launch { drawerState.close() } }, + selected = false + ) + NavigationDrawerItem( + label = { Text(text = "Настройки") }, + icon = { + Icon( + Icons.Filled.Settings, + contentDescription = null + ) + }, + selected = false, + onClick = { /*TODO*/ } + ) + NavigationDrawerItem( + label = { Text(text = "Доступные алгоритмы") }, + icon = { + Icon( + Icons.Filled.List, + contentDescription = null + ) + }, + selected = false, + onClick = { showSubMenu.value = !showSubMenu.value } + ) + AnimatedVisibility(visible = showSubMenu.value) { + AlgorithmSubMenu() } - Text("Menu Item 1", modifier = Modifier.padding(10.dp).clickable { scope.launch { drawerState.close() } }) - Text("Menu Item 2", modifier = Modifier.padding(10.dp).clickable { scope.launch { drawerState.close() } }) Row { Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { viewModel.showVerticesLabels.value = it }) - Text("Show vertices labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) + Text("Show vertices labels", fontSize = 20.sp, modifier = Modifier.padding(0.dp)) } Row { Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { viewModel.showEdgesLabels.value = it }) - Text("Show edges labels", fontSize = 28.sp, modifier = Modifier.padding(4.dp)) + Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) } Button( onClick = viewModel::resetGraphView, @@ -59,12 +101,26 @@ fun MyNavigationDrawer(viewModel: CanvasViewModel) { } } }, - content = { - Column(modifier = Modifier.width(370.dp)) { - IconButton(onClick = { scope.launch { drawerState.open() } }) { - Icon(Icons.Filled.Menu, contentDescription = null) - } + ) { + Scaffold( + floatingActionButton = { + ExtendedFloatingActionButton( + text = { Text("Show drawer") }, + icon = { Icon(Icons.Filled.Add, contentDescription = "") }, + onClick = { + scope.launch { + drawerState.apply { + if (isClosed) open() else close() + } + } + } + ) + } + ) + { + IconButton(onClick = { scope.launch { drawerState.open() } }) { + Icon(Icons.Filled.Menu, contentDescription = "Меню") } } - ) + } } \ No newline at end of file From b49b25c24ec18caee57698cafbaf345bd5a77643 Mon Sep 17 00:00:00 2001 From: dronshock Date: Mon, 27 May 2024 11:08:57 +0300 Subject: [PATCH 132/211] feat(GUI): make navigation drawer main Compose function --- src/main/kotlin/view/NavigationDrawer.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index e280c73..db9eb84 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch +import view.graph.GraphView import viewmodel.CanvasViewModel @Composable @@ -116,11 +117,9 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { } ) } - ) - { - IconButton(onClick = { scope.launch { drawerState.open() } }) { - Icon(Icons.Filled.Menu, contentDescription = "Меню") - } + ) { GraphView(viewModel.graphViewModel) } + IconButton(onClick = { scope.launch { drawerState.open() } }) { + Icon(Icons.Filled.Menu, contentDescription = "Меню") } } } \ No newline at end of file From 22118c571e7a23cfc63f83d81c68b2648717a1b7 Mon Sep 17 00:00:00 2001 From: dronshock Date: Mon, 27 May 2024 20:07:54 +0300 Subject: [PATCH 133/211] feat(GUI): add raw menu --- src/main/kotlin/Main.kt | 14 +-- src/main/kotlin/view/CanvasView.kt | 128 ++++++++++++++++++++--- src/main/kotlin/view/NavigationDrawer.kt | 2 +- 3 files changed, 121 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 8d2bcff..03898ca 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,19 +1,13 @@ + import androidx.compose.desktop.ui.tooling.preview.Preview -import androidx.compose.material.Button import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import model.graph.Graph -import view.Canvas +import view.NavigationDrawer import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout -import view.MyNavigationDrawer val graph = Graph().apply { addVertex(1,"Thomas Shelby") @@ -52,8 +46,8 @@ val graph = Graph().apply { @Preview fun App() { MaterialTheme { - Canvas(CanvasViewModel(graph, CircularLayout())) - //MyNavigationDrawer(CanvasViewModel(graph, CircularLayout())) +// Canvas(CanvasViewModel(graph, CircularLayout())) + NavigationDrawer(CanvasViewModel(graph, CircularLayout())) } } diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 7351afa..2d0b958 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,13 +1,22 @@ package view -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.material.* +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Surface import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch @@ -16,18 +25,113 @@ import viewmodel.CanvasViewModel @Composable fun Canvas(viewModel: CanvasViewModel) { - MyNavigationDrawer(viewModel) - Row( - horizontalArrangement = Arrangement.spacedBy(20.dp) + val drawerState = rememberDrawerState(DrawerValue.Closed) + val scope = rememberCoroutineScope() + Surface( + modifier = Modifier.fillMaxSize(), + contentColor = Color.LightGray, + color = Color.DarkGray ) { - Column(modifier = Modifier.width(370.dp)) { + val showSubMenu = remember { + mutableStateOf(false) } - - Surface( - modifier = Modifier.weight(1f), + ModalNavigationDrawer( + drawerState = drawerState, + gesturesEnabled = true, + drawerContent = { + ModalDrawerSheet { + Row { + IconButton(onClick = { scope.launch { drawerState.close() } } + ) { + Icon(Icons.Filled.Menu, contentDescription = "Меню") + } + Text("TOP G GANG", modifier = Modifier.padding(16.dp)) + } + Divider() + NavigationDrawerItem( + label = { Text("Menu Item 1") }, + modifier = Modifier.padding(10.dp), + onClick = { scope.launch { drawerState.close() } }, + selected = false + ) + NavigationDrawerItem( + label = { Text(text = "Настройки") }, + icon = { + Icon( + Icons.Filled.Settings, + contentDescription = null + ) + }, + selected = false, + onClick = { /*TODO*/ } + ) + NavigationDrawerItem( + label = { Text(text = "Доступные алгоритмы") }, + icon = { + Icon( + Icons.Filled.List, + contentDescription = null + ) + }, + selected = false, + onClick = { showSubMenu.value = !showSubMenu.value } + ) + AnimatedVisibility(visible = showSubMenu.value) { + AlgorithmSubMenu() + } + Row { + Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { + viewModel.showVerticesLabels.value = it + }) + Text("Show vertices labels", fontSize = 20.sp, modifier = Modifier.padding(0.dp)) + } + Row { + Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { + viewModel.showEdgesLabels.value = it + }) + Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) + } + Button( + onClick = viewModel::resetGraphView, + enabled = true, + ) { + Text( + text = "Reset default settings", + ) + } + Button( + onClick = viewModel::setVerticesColor, + enabled = true, + ) { + Text( + text = "Set colors", + ) + } + } + }, ) { + Scaffold( + floatingActionButton = { + ExtendedFloatingActionButton( + text = { Text("Show drawer") }, + icon = { Icon(Icons.Filled.Add, contentDescription = "") }, + onClick = { + scope.launch { + drawerState.apply { + if (isClosed) open() else close() + } + } + } + ) + } + ) + { + IconButton(onClick = { scope.launch { drawerState.open() } }) { + Icon(Icons.Filled.Menu, contentDescription = "Меню") + } + } GraphView(viewModel.graphViewModel) } - } -} \ No newline at end of file + +} diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index db9eb84..ad7afa3 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -106,7 +106,7 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { Scaffold( floatingActionButton = { ExtendedFloatingActionButton( - text = { Text("Show drawer") }, + text = { Text("Add graph") }, icon = { Icon(Icons.Filled.Add, contentDescription = "") }, onClick = { scope.launch { From 01e9f1e9777a5286a107dbdc316f718ee48eb1d7 Mon Sep 17 00:00:00 2001 From: dronshock Date: Tue, 28 May 2024 16:19:47 +0300 Subject: [PATCH 134/211] feat: update model Add property for Vertex Add feature to addEdge function --- src/main/kotlin/model/graph/Graph.kt | 6 ++++-- src/main/kotlin/model/graph/Vertex.kt | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/model/graph/Graph.kt b/src/main/kotlin/model/graph/Graph.kt index 4739a7d..a3cf318 100644 --- a/src/main/kotlin/model/graph/Graph.kt +++ b/src/main/kotlin/model/graph/Graph.kt @@ -1,4 +1,4 @@ -package graph.model +package model.graph class Graph{ var isDirected: Boolean = false @@ -18,9 +18,11 @@ class Graph{ fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { if (!isDirected){ vertices[secondVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("cringe") + vertices[secondVertexID]?.adjacentVertices?.add(vertices[firstVertexID]!!) } vertices[firstVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("cringe") + vertices[firstVertexID]?.adjacentVertices?.add(vertices[secondVertexID]!!) + return edges.getOrPut(edgeID) { Edge(Pair(firstVertexID,secondVertexID), weight, edgeID) } } - } diff --git a/src/main/kotlin/model/graph/Vertex.kt b/src/main/kotlin/model/graph/Vertex.kt index 29fb6c7..d39f50c 100644 --- a/src/main/kotlin/model/graph/Vertex.kt +++ b/src/main/kotlin/model/graph/Vertex.kt @@ -2,8 +2,9 @@ package model.graph class Vertex( var data: String, - var incidentEdges: MutableList = mutableListOf() + var incidentEdges: MutableList = mutableListOf(), ){ var id: Int = 0 var community: Int = -1 + val adjacentVertices: MutableList = mutableListOf() } \ No newline at end of file From f28c4addb22b2b6eaca102010cd826c5b791b367 Mon Sep 17 00:00:00 2001 From: dronshock Date: Tue, 28 May 2024 16:20:50 +0300 Subject: [PATCH 135/211] feat(algo): add Tarjan algorithm for finding strong connected component --- .../TarjanStrongConnecedComponent.kt | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt diff --git a/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt b/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt new file mode 100644 index 0000000..af4228d --- /dev/null +++ b/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt @@ -0,0 +1,114 @@ +package algorithms + +import model.graph.Graph +import model.graph.Vertex +import java.util.* +import kotlin.math.min + + +/** + * Date 08/16/2015 + * @author Tushar Roy + * + * Find strongly connected components of directed graph. + * + * Time complexity is O(E + V) + * Space complexity is O(V) + * + * Reference - https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + */ +class TarjanStronglyConnectedComponent { + private var visitedTime: MutableMap = mutableMapOf() + private var lowTime: MutableMap = mutableMapOf() + private var onStack: MutableSet = mutableSetOf() + private var stack: Deque = LinkedList() + private var visited: MutableSet = mutableSetOf() + private val result: MutableList> = mutableListOf() + private var time = 0 + + fun scc(graph: Graph): List> { + //start from any vertex in the graph. + for (vertex in graph.getVertices()) { + if (visited.contains(vertex)) { + continue + } + sccUtil(vertex) + } + + return result + } + + private fun sccUtil(vertex: Vertex) { + visited.add(vertex) + visitedTime[vertex] = time + lowTime[vertex] = time + time++ + stack.addFirst(vertex) + onStack.add(vertex) + + for (child in vertex.adjacentVertices) { + //if child is not visited then visit it and see if it has link back to vertex's ancestor. In that case update + //low time to ancestor's visit time + if (child !in visited) { + sccUtil(child) + //sets lowTime[vertex] = min(lowTime[vertex], lowTime[child]); + lowTime[vertex] = min(lowTime[vertex]!!, lowTime[child]!!) + } //if child is on stack then see if it was visited before vertex's low time. If yes then update vertex's low time to that. + else if (child in onStack) { + //sets lowTime[vertex] = min(lowTime[vertex], visitedTime[child]); + lowTime[vertex] = min(lowTime[vertex]!!, visitedTime[child]!!) + } + } + + //if vertex low time is same as visited time then this is start vertex for strongly connected component. + //keep popping vertices out of stack still you find current vertex. They are all part of one strongly + //connected component. + if (visitedTime[vertex] === lowTime[vertex]) { + val stronglyConnectedComponent: MutableSet = HashSet() + var v: Vertex + do { + v = stack.pollFirst() + onStack.remove(v) + stronglyConnectedComponent.add(v) + } while (vertex != v) + result.add(stronglyConnectedComponent) + } + } +} +fun main(args: Array) { + val graph: Graph = Graph() + graph.isDirected = true + graph.addVertex(1,"") + graph.addVertex(2,"") + graph.addVertex(3,"") + graph.addVertex(4,"") + graph.addVertex(5,"") + graph.addVertex(6,"") + graph.addVertex(7,"") + graph.addVertex(8,"") + graph.addVertex(9,"") + graph.addVertex(10,"") + + graph.addEdge(1, 2, edgeID = 1) + graph.addEdge(2, 3, edgeID = 2) + graph.addEdge(3, 1, edgeID = 3) + graph.addEdge(3, 4, edgeID = 4) + graph.addEdge(4, 5, edgeID = 5) + graph.addEdge(5, 6, edgeID = 6) + graph.addEdge(6, 4, edgeID = 7) + graph.addEdge(7, 6, edgeID = 8) + graph.addEdge(7, 8, edgeID = 9) + graph.addEdge(8, 7, edgeID = 10) + + val tarjanStronglyConnectedComponent = TarjanStronglyConnectedComponent() + val result: List> = tarjanStronglyConnectedComponent.scc(graph) + + result.forEach { scc: Set -> + scc.forEach { vertex: Vertex? -> + print( + vertex?.id.toString() + " " + ) + } + println() + } +} \ No newline at end of file From f25ce4ac9cf71c15874f2c27244447bdced8b908 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 28 May 2024 15:58:48 +0000 Subject: [PATCH 136/211] fix: fix import paths --- src/main/kotlin/algorithms/BridgeFinder.kt | 2 +- src/main/kotlin/algorithms/Djikstra.kt | 2 +- src/main/kotlin/algorithms/FordBellman.kt | 2 +- src/main/kotlin/algorithms/Kosaraju.kt | 2 +- src/main/kotlin/algorithms/KruskalsAlgorithm.kt | 2 +- src/main/kotlin/controller/GraphPainter.kt | 2 +- src/main/kotlin/model/community/Louvain.kt | 2 +- src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt | 2 +- src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- src/main/kotlin/viewmodel/graph/GraphViewModel.kt | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/algorithms/BridgeFinder.kt index 90d83ce..6d743b9 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/algorithms/BridgeFinder.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph import java.awt.geom.Point2D.distance import kotlin.math.min diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/algorithms/Djikstra.kt index 72305a6..f6ecfc8 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/algorithms/Djikstra.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { private val distance = hashMapOf() diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/algorithms/FordBellman.kt index c3ec551..82a6f52 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/algorithms/FordBellman.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph import kotlin.math.max diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/algorithms/Kosaraju.kt index b602b5c..4b39861 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/algorithms/Kosaraju.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph class Kosaraju(private val graph: Graph) { private val used = hashMapOf() diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt index d53131f..d4e002b 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -1,6 +1,6 @@ package algorithms -import graph.model.Graph +import model.graph.Graph import model.graph.Edge class KruskalsMST { diff --git a/src/main/kotlin/controller/GraphPainter.kt b/src/main/kotlin/controller/GraphPainter.kt index 41e3f30..fb534c5 100644 --- a/src/main/kotlin/controller/GraphPainter.kt +++ b/src/main/kotlin/controller/GraphPainter.kt @@ -1,7 +1,7 @@ package controller import androidx.compose.ui.graphics.Color -import graph.model.Graph +import model.graph.Graph import model.community.Louvain import viewmodel.graph.GraphViewModel import kotlin.random.Random diff --git a/src/main/kotlin/model/community/Louvain.kt b/src/main/kotlin/model/community/Louvain.kt index b5fd46b..8209106 100644 --- a/src/main/kotlin/model/community/Louvain.kt +++ b/src/main/kotlin/model/community/Louvain.kt @@ -1,6 +1,6 @@ package model.community -import graph.model.Graph +import model.graph.Graph class Louvain(private val graph: Graph) { private val currCommunities = mutableMapOf() diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index f49ba5b..641fbb2 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -7,7 +7,7 @@ import model.databases.sqlite.dao.vertices.Vertices import model.databases.sqlite.dao.verticesView.VertexView import model.databases.sqlite.dao.verticesView.VerticesView import androidx.compose.ui.unit.dp -import graph.model.Graph +import model.graph.Graph import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.exists diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 8230af2..9684bcb 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -2,7 +2,7 @@ package viewmodel import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.graphics.Color -import graph.model.Graph +import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 0248cb9..974ad88 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -3,7 +3,7 @@ package viewmodel.graph import androidx.compose.runtime.State import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import graph.model.Graph +import model.graph.Graph import model.graph.Edge import model.graph.Vertex From 5418aeef87585f68d38383ae2ee22c84ebbe478b Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 28 May 2024 15:58:48 +0000 Subject: [PATCH 137/211] fix: fix import paths --- src/main/kotlin/{ => model}/algorithms/BridgeFinder.kt | 2 +- src/main/kotlin/{ => model}/algorithms/Djikstra.kt | 2 +- src/main/kotlin/{ => model}/algorithms/FordBellman.kt | 2 +- src/main/kotlin/{ => model}/algorithms/Kosaraju.kt | 2 +- src/main/kotlin/{ => model}/algorithms/KruskalsAlgorithm.kt | 2 +- src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt | 2 +- src/test/kotlin/graphs/algorithms/DjikstraTest.kt | 2 +- src/test/kotlin/graphs/algorithms/FordBellmanTest.kt | 2 +- src/test/kotlin/graphs/algorithms/KosajaruTest.kt | 2 +- src/test/kotlin/graphs/algorithms/LouvainTest.kt | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) rename src/main/kotlin/{ => model}/algorithms/BridgeFinder.kt (98%) rename src/main/kotlin/{ => model}/algorithms/Djikstra.kt (98%) rename src/main/kotlin/{ => model}/algorithms/FordBellman.kt (99%) rename src/main/kotlin/{ => model}/algorithms/Kosaraju.kt (99%) rename src/main/kotlin/{ => model}/algorithms/KruskalsAlgorithm.kt (98%) diff --git a/src/main/kotlin/algorithms/BridgeFinder.kt b/src/main/kotlin/model/algorithms/BridgeFinder.kt similarity index 98% rename from src/main/kotlin/algorithms/BridgeFinder.kt rename to src/main/kotlin/model/algorithms/BridgeFinder.kt index 6d743b9..ae466d9 100644 --- a/src/main/kotlin/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/model/algorithms/BridgeFinder.kt @@ -1,4 +1,4 @@ -package algorithms +package model.algorithms import model.graph.Graph import java.awt.geom.Point2D.distance diff --git a/src/main/kotlin/algorithms/Djikstra.kt b/src/main/kotlin/model/algorithms/Djikstra.kt similarity index 98% rename from src/main/kotlin/algorithms/Djikstra.kt rename to src/main/kotlin/model/algorithms/Djikstra.kt index f6ecfc8..f310e4d 100644 --- a/src/main/kotlin/algorithms/Djikstra.kt +++ b/src/main/kotlin/model/algorithms/Djikstra.kt @@ -1,4 +1,4 @@ -package algorithms +package model.algorithms import model.graph.Graph diff --git a/src/main/kotlin/algorithms/FordBellman.kt b/src/main/kotlin/model/algorithms/FordBellman.kt similarity index 99% rename from src/main/kotlin/algorithms/FordBellman.kt rename to src/main/kotlin/model/algorithms/FordBellman.kt index 82a6f52..26da087 100644 --- a/src/main/kotlin/algorithms/FordBellman.kt +++ b/src/main/kotlin/model/algorithms/FordBellman.kt @@ -1,4 +1,4 @@ -package algorithms +package model.algorithms import model.graph.Graph import kotlin.math.max diff --git a/src/main/kotlin/algorithms/Kosaraju.kt b/src/main/kotlin/model/algorithms/Kosaraju.kt similarity index 99% rename from src/main/kotlin/algorithms/Kosaraju.kt rename to src/main/kotlin/model/algorithms/Kosaraju.kt index 4b39861..e8e37d6 100644 --- a/src/main/kotlin/algorithms/Kosaraju.kt +++ b/src/main/kotlin/model/algorithms/Kosaraju.kt @@ -1,4 +1,4 @@ -package algorithms +package model.algorithms import model.graph.Graph diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt similarity index 98% rename from src/main/kotlin/algorithms/KruskalsAlgorithm.kt rename to src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt index d4e002b..c88ef4d 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt @@ -1,4 +1,4 @@ -package algorithms +package model.algorithms import model.graph.Graph import model.graph.Edge diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index 277eef3..169e8bd 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -1,6 +1,6 @@ package graphs.algorithms -import algorithms.BridgeFinder +import model.algorithms.BridgeFinder import graph.model.Graph import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName diff --git a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt index fa897fb..1a2c89b 100644 --- a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt +++ b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt @@ -1,6 +1,6 @@ package graphs.algorithms -import algorithms.Djikstra +import model.algorithms.Djikstra import graph.model.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt index 521fcb1..9de812c 100644 --- a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -1,6 +1,6 @@ package graphs.algorithms -import algorithms.FordBellman +import model.algorithms.FordBellman import graph.model.Graph import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach diff --git a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt index 82a1be5..0ed55a3 100644 --- a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -1,6 +1,6 @@ package graphs.algorithms -import algorithms.Kosaraju +import model.algorithms.Kosaraju import graph.model.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index fc76b29..3a31f6c 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -1,6 +1,6 @@ package graphs.algorithms -import algorithms.Kosaraju +import model.algorithms.Kosaraju import graph.model.Graph import model.community.Louvain import org.junit.jupiter.api.Assertions.assertTrue From ad020febaf8298c1dfd16792d63cf0640960e7ef Mon Sep 17 00:00:00 2001 From: dronshock Date: Tue, 28 May 2024 20:49:51 +0300 Subject: [PATCH 138/211] fix(algo): remove main function --- .../TarjanStrongConnecedComponent.kt | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt b/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt index af4228d..288637a 100644 --- a/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt +++ b/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt @@ -74,41 +74,4 @@ class TarjanStronglyConnectedComponent { result.add(stronglyConnectedComponent) } } -} -fun main(args: Array) { - val graph: Graph = Graph() - graph.isDirected = true - graph.addVertex(1,"") - graph.addVertex(2,"") - graph.addVertex(3,"") - graph.addVertex(4,"") - graph.addVertex(5,"") - graph.addVertex(6,"") - graph.addVertex(7,"") - graph.addVertex(8,"") - graph.addVertex(9,"") - graph.addVertex(10,"") - - graph.addEdge(1, 2, edgeID = 1) - graph.addEdge(2, 3, edgeID = 2) - graph.addEdge(3, 1, edgeID = 3) - graph.addEdge(3, 4, edgeID = 4) - graph.addEdge(4, 5, edgeID = 5) - graph.addEdge(5, 6, edgeID = 6) - graph.addEdge(6, 4, edgeID = 7) - graph.addEdge(7, 6, edgeID = 8) - graph.addEdge(7, 8, edgeID = 9) - graph.addEdge(8, 7, edgeID = 10) - - val tarjanStronglyConnectedComponent = TarjanStronglyConnectedComponent() - val result: List> = tarjanStronglyConnectedComponent.scc(graph) - - result.forEach { scc: Set -> - scc.forEach { vertex: Vertex? -> - print( - vertex?.id.toString() + " " - ) - } - println() - } } \ No newline at end of file From f8fc748fae72ea412221a9837c4a9b21c71175b7 Mon Sep 17 00:00:00 2001 From: dronshock Date: Tue, 28 May 2024 20:51:09 +0300 Subject: [PATCH 139/211] feat(algo): add Johnson's algorithm for finding cycles --- src/main/kotlin/algorithms/FindCycles.kt | 191 +++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 src/main/kotlin/algorithms/FindCycles.kt diff --git a/src/main/kotlin/algorithms/FindCycles.kt b/src/main/kotlin/algorithms/FindCycles.kt new file mode 100644 index 0000000..8d72f07 --- /dev/null +++ b/src/main/kotlin/algorithms/FindCycles.kt @@ -0,0 +1,191 @@ +package algorithms + +import model.graph.Graph +import model.graph.Vertex +import java.util.* +import java.util.function.Consumer + +/* +class FindCycles(graph: Graph) { + fun findCycles(graph: Graph): Int { + val bridgeFinder = BridgeFinder(graph) + val bridgeEdges = bridgeFinder.findBridges() + val edgesWithoutBridges = graph.edges.minus(bridgeEdges.toSet()) + return 0 + } +} +*/ +class AllCyclesInDirectedGraphJohnson { + var blockedSet: MutableSet? = null + var blockedMap: MutableMap?>? = null + var stack: Deque? = null + var allCycles: MutableList>? = null + + fun simpleCyles(graph: Graph): List> { + blockedSet = HashSet() + blockedMap = HashMap?>() + stack = LinkedList() + allCycles = ArrayList>() + var startIndex: Int = 1 + val tarjan: TarjanStronglyConnectedComponent = TarjanStronglyConnectedComponent() + while (startIndex <= graph.vertices.size) { + val subGraph: Graph = createSubGraph(startIndex, graph) + val sccs: List> = tarjan.scc(subGraph) + val maybeLeastVertex: Vertex? = leastIndexSCC(sccs, subGraph) + if (maybeLeastVertex != null) { + val leastVertex: Vertex = maybeLeastVertex + blockedSet!!.clear() + blockedMap!!.clear() + findCyclesInSCG(graph,leastVertex, leastVertex) + startIndex = leastVertex.id + 1 + } else { + break + } + } + return allCycles!! + } + + private fun leastIndexSCC(sccs: List>, subGraph: Graph): Vertex? { + var min = Int.MAX_VALUE + var minVertex: Vertex? = null + var minScc: Set = mutableSetOf() + for (scc in sccs) { + if (scc.size == 1) { + continue + } + for (vertex in scc) { + if (vertex.id < min) { + min = vertex.id + minVertex = vertex + minScc = scc + } + } + } + + if (minVertex == null) { + return null + } + val graphScc: Graph = Graph() + graphScc.isDirected = true + for ((i, edge) in subGraph.getEdges().withIndex()) { + if ((subGraph.vertices[edge.vertices.first] in minScc) && (subGraph.vertices[edge.vertices.second] in minScc)) { + graphScc.addVertex(edge.vertices.first, "") + graphScc.addVertex(edge.vertices.second, "") + graphScc.addEdge(edge.vertices.first, edge.vertices.second, edgeID = i) + } + } + return graphScc.vertices[(minVertex.id)] + } + + private fun unblock(u: Vertex) { + blockedSet!!.remove(u) + if (blockedMap!![u] != null) { + blockedMap!![u]!!.forEach(Consumer { v: Vertex -> + if (blockedSet!!.contains(v)) { + unblock(v) + } + }) + blockedMap!!.remove(u) + } + } + + private fun findCyclesInSCG( + graph: Graph, + startVertex: Vertex, + currentVertex: Vertex, + ): Boolean { + var foundCycle = false + stack!!.push(currentVertex) + blockedSet!!.add(currentVertex) + + for (e in graph.edges.filterKeys{it in currentVertex.incidentEdges}.values) { + val neighbor: Vertex = graph.vertices[e.vertices.second]!! + //if neighbor is same as start vertex means cycle is found. + //Store contents of stack in final result. + if (neighbor === startVertex) { + val cycle: MutableList = ArrayList() + stack!!.push(startVertex) + cycle.addAll(stack!!) + Collections.reverse(cycle) + stack!!.pop() + allCycles!!.add(cycle) + foundCycle = true + } //explore this neighbor only if it is not in blockedSet. + else if (!blockedSet!!.contains(neighbor)) { + val gotCycle = + findCyclesInSCG(graph,startVertex, neighbor) + foundCycle = foundCycle || gotCycle + } + } + //if cycle is found with current vertex then recursively unblock vertex and all vertices which are dependent on this vertex. + if (foundCycle) { + //remove from blockedSet and then remove all the other vertices dependent on this vertex from blockedSet + unblock(currentVertex) + } else { + //if no cycle is found with current vertex then don't unblock it. But find all its neighbors and add this + //vertex to their blockedMap. If any of those neighbors ever get unblocked then unblock current vertex as well. + for (e in graph.edges.filterKeys{it in currentVertex.incidentEdges}.values) { + val w: Vertex = graph.vertices[e.vertices.second]!! + val bSet: MutableSet = getBSet(w) + bSet.add(currentVertex) + } + } + //remove vertex from the stack. + stack!!.pop() + return foundCycle + } + + private fun getBSet(v: Vertex): MutableSet { + return (blockedMap?.computeIfAbsent(v + ) { HashSet() } as MutableSet?)!! + } + + private fun createSubGraph(startVertex: Int, graph: Graph): Graph { + val subGraph: Graph = Graph() + subGraph.isDirected = true + for ((i, edge) in graph.getEdges().withIndex()) { + if (edge.vertices.first >= startVertex && edge.vertices.second >= startVertex) { + subGraph.addVertex(edge.vertices.first, "") + subGraph.addVertex(edge.vertices.second, "") + subGraph.addEdge(edge.vertices.first, edge.vertices.second, edgeID = i) + } + } + return subGraph + } + + companion object { + @JvmStatic + fun main(args: Array) { + val johnson = AllCyclesInDirectedGraphJohnson() + val graph: Graph = Graph() + graph.isDirected = true + for (i in 1..9){ + graph.addVertex(i,"") + } + graph.addEdge(1, 2, edgeID = 0) + graph.addEdge(1, 8, edgeID = 1) + graph.addEdge(1, 5, edgeID = 2) + graph.addEdge(2, 9, edgeID = 3) + graph.addEdge(2, 7, edgeID = 4) + graph.addEdge(2, 3, edgeID = 5) + graph.addEdge(3, 1, edgeID = 6) + graph.addEdge(3, 2, edgeID = 7) + graph.addEdge(3, 6, edgeID = 8) + graph.addEdge(3, 4, edgeID = 9) + graph.addEdge(6, 4, edgeID = 10) + graph.addEdge(4, 5, edgeID = 11) + graph.addEdge(5, 2, edgeID = 12) + graph.addEdge(8, 9, edgeID = 13) + graph.addEdge(9, 8, edgeID = 14) + + val allCycles: List> = johnson.simpleCyles(graph) + val joiner = StringJoiner("->") + allCycles.forEach { cycle: List -> + cycle.forEach { vertex: Vertex? -> + joiner.add("${vertex?.id}") + } + println(joiner) + } + } + } +} \ No newline at end of file From 5f507a5760211f2c44ec1b2c66a525eaba8508da Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 28 May 2024 20:45:17 +0000 Subject: [PATCH 140/211] feat: implement ForceAtlas2 --- .run/desktop.run.xml | 41 +-- build.gradle.kts | 2 + src/main/kotlin/Main.kt | 314 +++++++++++++++++- .../kotlin/model/layout/ForceAtlas2Layout.kt | 94 ++++++ src/main/kotlin/view/graph/EdgeView.kt | 3 +- src/main/kotlin/view/graph/VertexView.kt | 5 +- src/main/kotlin/viewmodel/CanvasViewModel.kt | 4 +- .../viewmodel/layouts/CircularLayout.kt | 5 +- .../layouts/RepresentationStrategy.kt | 3 +- 9 files changed, 434 insertions(+), 37 deletions(-) create mode 100644 src/main/kotlin/model/layout/ForceAtlas2Layout.kt diff --git a/.run/desktop.run.xml b/.run/desktop.run.xml index f91b2c2..a24b2e0 100644 --- a/.run/desktop.run.xml +++ b/.run/desktop.run.xml @@ -1,21 +1,24 @@ - - - - - - true - - + + + + + + true + true + false + false + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index d8b9450..f871b3b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,12 +16,14 @@ version = "1.0-SNAPSHOT" repositories { mavenCentral() + maven("https://raw.github.com/gephi/gephi/mvn-thirdparty-repo/") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") google() } val exposedVersion: String by project val neo4jDriverVersion = "4.4.5" dependencies { + implementation("org.gephi", "gephi-toolkit", "0.10.1", classifier = "all") testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0") implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 03898ca..1c62149 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -4,7 +4,11 @@ import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import controller.GraphPainter import model.graph.Graph +import model.layout.ForceAtlas2Layout +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 +import view.Canvas import view.NavigationDrawer import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout @@ -21,9 +25,9 @@ val graph = Graph().apply { addEdge(1, 2, 1,1) addEdge(3, 4, 2,2) addEdge(1, 3, 3,3) - addEdge(2, 4, 4,4) - addEdge(2, 5, 5,5) - addEdge(5, 7, 6,6) + addEdge(2, 3, 4,4) + addEdge(5, 3, 5,5) + addEdge(3, 7, 6,6) addVertex(8, "Pudge") addVertex(9,"Tiny") @@ -33,21 +37,307 @@ val graph = Graph().apply { addVertex(13,"Sniper") addVertex(14,"Roshan") - addEdge(14, 8, 7,7) - addEdge(14, 9, 8,8) - addEdge(14, 10, 9,9) - addEdge(14, 11, 10,10) - addEdge(14, 12, 11,11) - addEdge(14, 13, 12,12) - + addEdge(14, 8, 6,7) + addEdge(14, 9, 6,8) + addEdge(14, 10, 6,9) + addEdge(14, 11, 6,10) + addEdge(14, 12, 6,11) + addEdge(14, 13, 5,12) addEdge(14, 3, 0,13) + + addVertex(15, "aPudge") + addVertex(16,"aTiny") + addVertex(17, "aLycan") + addVertex(18,"aIo") + addVertex(19,"aLion") + addVertex(20,"aSniper") + addVertex(21,"aRoshan") + + addEdge(16, 15, 22,14) + addEdge(15, 17, 1,15) + addEdge(15, 18, 6,16) + addEdge(19, 15, 2,17) + addEdge(15, 21, 3,18) + addEdge(20, 15, 5,19) + addEdge(17, 20, 0,20) + addEdge(14, 20, 0,21) +// addVertex(1,"1") +// addVertex(2,"2") +// addVertex(3,"3") +// addVertex(4,"4") +// addVertex(5,"5") +// addVertex(6,"6") +// addVertex(7,"7") +// addVertex(8,"8") +// addVertex(9,"9") +// addVertex(10,"10") +// addVertex(11,"11") +// addVertex(12,"12") +// addVertex(13,"13") +// addVertex(14,"14") +// addVertex(15,"15") +// addVertex(16,"16") +// addVertex(17,"17") +// addVertex(18,"18") +// addVertex(19,"19") +// addVertex(20,"20") +// addVertex(21,"21") +// addVertex(22,"22") +// addVertex(23,"23") +// addVertex(24,"24") +// addVertex(25,"25") +// addVertex(26,"26") +// addVertex(27,"27") +// addVertex(28,"28") +// addVertex(29,"29") +// addVertex(30,"30") +// addVertex(31,"31") +// addVertex(32,"32") +// addVertex(33,"33") +// addVertex(34,"34") +// addVertex(35,"35") +// addVertex(36,"36") +// addVertex(37,"37") +// addVertex(38,"38") +// addVertex(39,"39") +// addVertex(40,"40") +// addVertex(41,"41") +// addVertex(42,"42") +// addVertex(43,"43") +// addVertex(44,"44") +// addVertex(45,"45") +// addVertex(46,"46") +// addVertex(47,"47") +// addVertex(48,"48") +// addVertex(49,"49") +// addVertex(50,"50") +// addVertex(51,"51") +// addVertex(52,"52") +// addVertex(53,"53") +// addVertex(54,"54") +// addVertex(55,"55") +// addVertex(56,"56") +// addVertex(57,"57") +// addVertex(58,"58") +// addVertex(59,"59") +// addVertex(60,"60") +// addVertex(61,"61") +// addVertex(62,"62") +// addVertex(63,"63") +// addVertex(64,"64") +// addVertex(65,"65") +// addVertex(66,"66") +// addVertex(67,"67") +// addVertex(68,"68") +// addVertex(69,"69") +// addVertex(70,"70") +// addVertex(71,"71") +// addVertex(72,"72") +// addVertex(73,"73") +// addVertex(74,"74") +// addVertex(75,"75") +// addVertex(76,"76") +// addVertex(77,"77") +// addVertex(78,"78") +// addVertex(79,"79") +// addVertex(80,"80") +// addVertex(81,"81") +// addVertex(82,"82") +// addVertex(83,"83") +// addVertex(84,"84") +// addVertex(85,"85") +// addVertex(86,"86") +// addVertex(87,"87") +// addVertex(88,"88") +// addVertex(89,"89") +// addVertex(90,"90") +// addVertex(91,"91") +// addVertex(92,"92") +// addVertex(93,"93") +// addVertex(94,"94") +// addVertex(95,"95") +// addVertex(96,"96") +// addVertex(97,"97") +// addVertex(98,"98") +// addVertex(99,"99") +// addVertex(100,"100") +// addEdge(74,14,59,1) +// addEdge(93,86,82,2) +// addEdge(73,67,20,3) +// addEdge(7,27,20,4) +// addEdge(30,6,19,5) +// addEdge(90,64,96,6) +// addEdge(4,39,0,7) +// addEdge(33,80,6,8) +// addEdge(82,42,98,9) +// addEdge(9,21,93,10) +// addEdge(34,13,63,11) +// addEdge(84,93,49,12) +// addEdge(68,78,97,13) +// addEdge(25,82,59,14) +// addEdge(66,85,38,15) +// addEdge(91,56,45,16) +// addEdge(42,64,79,17) +// addEdge(14,66,64,18) +// addEdge(98,2,0,19) +// addEdge(82,35,61,20) +// addEdge(72,10,8,21) +// addEdge(62,63,52,22) +// addEdge(11,36,89,23) +// addEdge(91,62,75,24) +// addEdge(2,24,18,25) +// addEdge(89,80,68,26) +// addEdge(43,84,25,27) +// addEdge(91,48,11,28) +// addEdge(63,26,51,29) +// addEdge(38,58,42,30) +// addEdge(24,15,61,31) +// addEdge(48,88,7,32) +// addEdge(65,38,23,33) +// addEdge(70,51,34,34) +// addEdge(33,38,82,35) +// addEdge(14,13,61,36) +// addEdge(74,54,72,37) +// addEdge(100,87,22,38) +// addEdge(34,24,23,39) +// addEdge(8,100,9,40) +// addEdge(37,4,24,41) +// addEdge(19,21,39,42) +// addEdge(41,60,37,43) +// addEdge(20,67,6,44) +// addEdge(99,52,82,45) +// addEdge(67,30,99,46) +// addEdge(10,45,70,47) +// addEdge(5,47,66,48) +// addEdge(87,74,21,49) +// addEdge(65,29,33,50) +// addEdge(38,37,86,51) +// addEdge(17,68,63,52) +// addEdge(72,73,73,53) +// addEdge(24,52,74,54) +// addEdge(49,42,56,55) +// addEdge(38,4,24,56) +// addEdge(18,63,46,57) +// addEdge(46,77,69,58) +// addEdge(94,16,15,59) +// addEdge(27,50,29,60) +// addEdge(91,24,30,61) +// addEdge(97,46,89,62) +// addEdge(59,77,37,63) +// addEdge(48,95,64,64) +// addEdge(91,11,47,65) +// addEdge(33,37,6,66) +// addEdge(75,89,4,67) +// addEdge(96,87,21,68) +// addEdge(58,61,58,69) +// addEdge(71,47,92,70) +// addEdge(50,96,40,71) +// addEdge(45,63,45,72) +// addEdge(60,48,79,73) +// addEdge(95,90,75,74) +// addEdge(91,15,58,75) +// addEdge(90,53,97,76) +// addEdge(97,14,46,77) +// addEdge(90,57,4,78) +// addEdge(8,51,72,79) +// addEdge(7,42,44,80) +// addEdge(46,22,64,81) +// addEdge(18,72,54,82) +// addEdge(12,71,68,83) +// addEdge(22,10,94,84) +// addEdge(6,100,89,85) +// addEdge(6,87,27,86) +// addEdge(79,46,84,87) +// addEdge(42,87,23,88) +// addEdge(58,81,81,89) +// addEdge(45,67,91,90) +// addEdge(27,58,93,91) +// addEdge(8,1,47,92) +// addEdge(46,59,74,93) +// addEdge(58,90,23,94) +// addEdge(82,81,29,95) +// addEdge(25,30,17,96) +// addEdge(79,21,49,97) +// addEdge(100,28,17,98) +// addEdge(57,85,1,99) +// addEdge(51,3,37,100) +// addEdge(41,54,30,101) +// addEdge(27,1,41,102) +// addEdge(42,89,47,103) +// addEdge(85,40,57,104) +// addEdge(13,46,26,105) +// addEdge(53,51,51,106) +// addEdge(17,45,95,107) +// addEdge(28,83,50,108) +// addEdge(72,15,10,109) +// addEdge(30,47,47,110) +// addEdge(32,43,41,111) +// addEdge(17,84,46,112) +// addEdge(32,66,62,113) +// addEdge(66,82,79,114) +// addEdge(21,36,48,115) +// addEdge(19,32,73,116) +// addEdge(77,83,59,117) +// addEdge(22,24,66,118) +// addEdge(63,10,54,119) +// addEdge(20,44,38,120) +// addEdge(19,17,25,121) +// addEdge(28,51,19,122) +// addEdge(67,8,68,123) +// addEdge(3,81,47,124) +// addEdge(88,93,13,125) +// addEdge(89,79,56,126) +// addEdge(44,89,97,127) +// addEdge(92,29,58,128) +// addEdge(47,52,68,129) +// addEdge(70,52,34,130) +// addEdge(76,95,4,131) +// addEdge(75,69,88,132) +// addEdge(57,97,33,133) +// addEdge(67,31,8,134) +// addEdge(11,15,50,135) +// addEdge(51,89,89,136) +// addEdge(9,71,67,137) +// addEdge(8,11,57,138) +// addEdge(3,53,13,139) +// addEdge(84,67,42,140) +// addEdge(37,76,74,141) +// addEdge(41,68,33,142) +// addEdge(89,12,66,143) +// addEdge(41,56,88,144) +// addEdge(96,96,3,145) +// addEdge(14,34,47,146) +// addEdge(80,73,99,147) +// addEdge(20,84,11,148) +// addEdge(68,30,58,149) +// addEdge(91,32,57,150) +// addEdge(64,44,31,151) +// addEdge(89,92,18,152) +// addEdge(38,72,40,153) +// addEdge(44,70,99,154) +// addEdge(57,13,98,155) +// addEdge(46,76,58,156) +// addEdge(10,8,98,157) +// addEdge(75,37,89,158) +// addEdge(64,21,38,159) +// addEdge(60,29,19,160) +// addEdge(91,73,84,161) +// addEdge(33,76,55,162) +// addEdge(32,34,51,163) +// addEdge(68,48,35,164) +// addEdge(51,63,24,165) } @Composable @Preview fun App() { MaterialTheme { -// Canvas(CanvasViewModel(graph, CircularLayout())) - NavigationDrawer(CanvasViewModel(graph, CircularLayout())) + val canvasGraph = CanvasViewModel(graph, ForceAtlas2Layout()) + val graphViewModel = canvasGraph.graphViewModel + val painter = GraphPainter(graph, graphViewModel) + painter.paint() + MaterialTheme { + Canvas(canvasGraph) + } } } diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt new file mode 100644 index 0000000..1d276df --- /dev/null +++ b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt @@ -0,0 +1,94 @@ +package model.layout + +import androidx.compose.ui.unit.dp +import model.graph.Graph +import viewmodel.graph.GraphViewModel +import viewmodel.layouts.RepresentationStrategy +import org.gephi.layout.plugin.forceAtlas.ForceAtlas +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2Builder +import org.gephi.graph.api.Edge +import org.gephi.graph.api.GraphController +import org.gephi.graph.api.GraphModel +import org.gephi.graph.api.Node +import org.gephi.layout.plugin.force.StepDisplacement +import org.gephi.layout.plugin.force.yifanHu.YifanHuLayout +import org.gephi.layout.plugin.forceAtlas.ForceAtlasLayout +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2LayoutData +import org.gephi.project.api.ProjectController +import org.openide.util.Lookup +import viewmodel.graph.VertexViewModel +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min +import kotlin.random.Random + + +class ForceAtlas2Layout:RepresentationStrategy{ + + override fun place(width: Double, height: Double, graphViewModel:GraphViewModel){ + + var maxX = Int.MIN_VALUE + var minX = Int.MAX_VALUE + var maxY = Int.MIN_VALUE + var minY = Int.MAX_VALUE + + val pc = Lookup.getDefault().lookup(ProjectController::class.java) + pc.newProject() + val graphModel = Lookup.getDefault().lookup(GraphController::class.java).graphModel + val graph = graphModel.undirectedGraph + + val verticesMap = mutableMapOf() + for (vertex in graphViewModel.verticesViewValues){ + val v: Node =graphModel.factory().newNode(vertex.vertex.id.toString()) + v.setX(Random.nextFloat()*10) + v.setY(Random.nextFloat()*10) + graph.addNode(v) + verticesMap[vertex.vertex.id]=v + } + //TODO добавить возможность получения информации об ориентированности графа + for (edge in graphViewModel.edgesViewValues){ + val e: Edge = graphModel.factory().newEdge( + verticesMap[edge.u.vertex.id], + verticesMap[edge.v.vertex.id], + 1, + false + ) + graph.addEdge(e) + } + val layout = ForceAtlas2(null) + layout.setGraphModel(graphModel) + layout.initAlgo() + layout.resetPropertiesValues() + layout.isAdjustSizes = true + layout.isBarnesHutOptimize = true + layout.scalingRatio = 20.0 + layout.gravity = 2.0 + + var i = 0 + while (i < 5000 && layout.canAlgo()) { + layout.goAlgo() + i++ + } + layout.endAlgo() + + for (vertex in graphViewModel.verticesViewValues) { + val v: Node = graph.getNode(vertex.vertex.id.toString()) + val x = ((width/2 + v.x())) + val y = ((height/2 + v.y())) + vertex.x = (x).toInt().dp + vertex.y = (y).toInt().dp + + maxX = max(maxX, x.toInt()) + minX = min(minX, x.toInt()) + maxY = max(maxY, y.toInt()) + minY = min(minY, y.toInt()) + } + val graphWidthScale = width / (maxX + abs(minX)) + val graphHeightScale = height / (maxY + abs(minY)) + } + + override fun highlight(vertices: Collection) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/graph/EdgeView.kt b/src/main/kotlin/view/graph/EdgeView.kt index 79bfe1c..9b9512d 100644 --- a/src/main/kotlin/view/graph/EdgeView.kt +++ b/src/main/kotlin/view/graph/EdgeView.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.Modifier import androidx.compose.material.Text import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.zIndex import viewmodel.graph.EdgeViewModel @Composable @@ -15,7 +16,7 @@ fun EdgeView( viewModel: EdgeViewModel, modifier: Modifier = Modifier, ) { - Canvas(modifier = modifier.fillMaxSize()) { + Canvas(modifier = modifier.fillMaxSize().zIndex(-1f)) { drawLine( start = Offset( viewModel.u.x.toPx() + viewModel.u.radius.toPx(), diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt index 9a73efa..d89a170 100644 --- a/src/main/kotlin/view/graph/VertexView.kt +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -1,6 +1,7 @@ package view.graph import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.offset @@ -10,6 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.material.Text +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import viewmodel.graph.VertexViewModel @@ -20,8 +22,9 @@ fun VertexView( modifier: Modifier = Modifier, ) { Box(modifier = modifier - .size(viewModel.radius * 2, viewModel.radius * 2) + .size(viewModel.radius+10.dp, viewModel.radius+10.dp) .offset(viewModel.x, viewModel.y) + .border(2.dp, Color.Black, CircleShape) .background( color = viewModel.color, shape = CircleShape diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 9684bcb..3f5e43d 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -12,11 +12,11 @@ class CanvasViewModel(graph: Graph, private val representationStrategy: Represen val graphViewModel = GraphViewModel(graph) init { - representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) + representationStrategy.place(1280.0, 860.0, graphViewModel) } fun resetGraphView() { - representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) + representationStrategy.place(800.0, 600.0, graphViewModel) graphViewModel.verticesViewValues.forEach{ v -> v.color = Color.Blue} } diff --git a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt index 759a45f..572f58a 100644 --- a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt +++ b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt @@ -2,6 +2,8 @@ package viewmodel.layouts import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import org.gephi.graph.api.GraphView +import viewmodel.graph.GraphViewModel import viewmodel.graph.VertexViewModel import kotlin.math.cos import kotlin.math.min @@ -9,7 +11,8 @@ import kotlin.math.sin import kotlin.random.Random class CircularLayout: RepresentationStrategy { - override fun place(width: Double, height: Double, vertices: Collection) { + override fun place(width: Double, height: Double, graph: GraphViewModel) { + val vertices = graph.verticesViewValues if (vertices.isEmpty()) { println("CircularPlacementStrategy.place: there is nothing to place 👐🏻") return diff --git a/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt index 655fd11..f4f9019 100644 --- a/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt +++ b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt @@ -1,8 +1,9 @@ package viewmodel.layouts +import viewmodel.graph.GraphViewModel import viewmodel.graph.VertexViewModel interface RepresentationStrategy { - fun place(width: Double, height: Double, vertices: Collection) + fun place(width: Double, height: Double, graph: GraphViewModel) fun highlight(vertices: Collection) } \ No newline at end of file From fcb59eececa23ba3b8461c159614847788869d1c Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Tue, 28 May 2024 21:22:05 +0000 Subject: [PATCH 141/211] fix: Delete redundant code --- src/main/kotlin/model/layout/ForceAtlas2Layout.kt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt index 1d276df..5819cc4 100644 --- a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt +++ b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt @@ -28,11 +28,6 @@ class ForceAtlas2Layout:RepresentationStrategy{ override fun place(width: Double, height: Double, graphViewModel:GraphViewModel){ - var maxX = Int.MIN_VALUE - var minX = Int.MAX_VALUE - var maxY = Int.MIN_VALUE - var minY = Int.MAX_VALUE - val pc = Lookup.getDefault().lookup(ProjectController::class.java) pc.newProject() val graphModel = Lookup.getDefault().lookup(GraphController::class.java).graphModel @@ -78,17 +73,10 @@ class ForceAtlas2Layout:RepresentationStrategy{ val y = ((height/2 + v.y())) vertex.x = (x).toInt().dp vertex.y = (y).toInt().dp - - maxX = max(maxX, x.toInt()) - minX = min(minX, x.toInt()) - maxY = max(maxY, y.toInt()) - minY = min(minY, y.toInt()) } - val graphWidthScale = width / (maxX + abs(minX)) - val graphHeightScale = height / (maxY + abs(minY)) } override fun highlight(vertices: Collection) { TODO("Not yet implemented") } -} \ No newline at end of file +} From 8b2e1cf43ee01bfc07b2e0e7cff27ffba0f21b26 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 28 May 2024 20:45:17 +0000 Subject: [PATCH 142/211] feat: implement ForceAtlas2 --- src/main/kotlin/model/layout/ForceAtlas2Layout.kt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt index 5819cc4..88b2428 100644 --- a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt +++ b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt @@ -1,26 +1,15 @@ package model.layout import androidx.compose.ui.unit.dp -import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -import org.gephi.layout.plugin.forceAtlas.ForceAtlas import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 -import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2Builder import org.gephi.graph.api.Edge import org.gephi.graph.api.GraphController -import org.gephi.graph.api.GraphModel import org.gephi.graph.api.Node -import org.gephi.layout.plugin.force.StepDisplacement -import org.gephi.layout.plugin.force.yifanHu.YifanHuLayout -import org.gephi.layout.plugin.forceAtlas.ForceAtlasLayout -import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2LayoutData import org.gephi.project.api.ProjectController import org.openide.util.Lookup import viewmodel.graph.VertexViewModel -import kotlin.math.abs -import kotlin.math.max -import kotlin.math.min import kotlin.random.Random @@ -79,4 +68,4 @@ class ForceAtlas2Layout:RepresentationStrategy{ override fun highlight(vertices: Collection) { TODO("Not yet implemented") } -} +} \ No newline at end of file From 9d76ea1bc1096d76209a85b8d126eef940e26127 Mon Sep 17 00:00:00 2001 From: dronshock Date: Wed, 29 May 2024 07:24:38 +0300 Subject: [PATCH 143/211] fix(algo): remove some extra code and refactor --- src/main/kotlin/algorithms/FindCycles.kt | 146 ++++++++---------- .../TarjanStrongConnecedComponent.kt | 22 +-- 2 files changed, 63 insertions(+), 105 deletions(-) diff --git a/src/main/kotlin/algorithms/FindCycles.kt b/src/main/kotlin/algorithms/FindCycles.kt index 8d72f07..8119ceb 100644 --- a/src/main/kotlin/algorithms/FindCycles.kt +++ b/src/main/kotlin/algorithms/FindCycles.kt @@ -3,46 +3,35 @@ package algorithms import model.graph.Graph import model.graph.Vertex import java.util.* -import java.util.function.Consumer -/* -class FindCycles(graph: Graph) { - fun findCycles(graph: Graph): Int { - val bridgeFinder = BridgeFinder(graph) - val bridgeEdges = bridgeFinder.findBridges() - val edgesWithoutBridges = graph.edges.minus(bridgeEdges.toSet()) - return 0 - } -} -*/ class AllCyclesInDirectedGraphJohnson { - var blockedSet: MutableSet? = null - var blockedMap: MutableMap?>? = null - var stack: Deque? = null - var allCycles: MutableList>? = null + private var blockedSet: MutableSet = mutableSetOf() + private var blockedMap: MutableMap?> = mutableMapOf() + private var stack: Deque = LinkedList() + private var allCycles: MutableList> = mutableListOf() - fun simpleCyles(graph: Graph): List> { + fun simpleCycles(graph: Graph): List> { blockedSet = HashSet() blockedMap = HashMap?>() stack = LinkedList() allCycles = ArrayList>() - var startIndex: Int = 1 - val tarjan: TarjanStronglyConnectedComponent = TarjanStronglyConnectedComponent() + var startIndex = 1 + val tarjan = TarjanStronglyConnectedComponent() while (startIndex <= graph.vertices.size) { val subGraph: Graph = createSubGraph(startIndex, graph) val sccs: List> = tarjan.scc(subGraph) val maybeLeastVertex: Vertex? = leastIndexSCC(sccs, subGraph) if (maybeLeastVertex != null) { val leastVertex: Vertex = maybeLeastVertex - blockedSet!!.clear() - blockedMap!!.clear() + blockedSet.clear() + blockedMap.clear() findCyclesInSCG(graph,leastVertex, leastVertex) startIndex = leastVertex.id + 1 } else { break } } - return allCycles!! + return allCycles } private fun leastIndexSCC(sccs: List>, subGraph: Graph): Vertex? { @@ -65,7 +54,7 @@ class AllCyclesInDirectedGraphJohnson { if (minVertex == null) { return null } - val graphScc: Graph = Graph() + val graphScc = Graph() graphScc.isDirected = true for ((i, edge) in subGraph.getEdges().withIndex()) { if ((subGraph.vertices[edge.vertices.first] in minScc) && (subGraph.vertices[edge.vertices.second] in minScc)) { @@ -78,14 +67,14 @@ class AllCyclesInDirectedGraphJohnson { } private fun unblock(u: Vertex) { - blockedSet!!.remove(u) - if (blockedMap!![u] != null) { - blockedMap!![u]!!.forEach(Consumer { v: Vertex -> - if (blockedSet!!.contains(v)) { + blockedSet.remove(u) + if (blockedMap[u] != null) { + blockedMap[u]!!.forEach { v: Vertex -> + if (blockedSet.contains(v)) { unblock(v) } - }) - blockedMap!!.remove(u) + } + blockedMap.remove(u) } } @@ -95,53 +84,46 @@ class AllCyclesInDirectedGraphJohnson { currentVertex: Vertex, ): Boolean { var foundCycle = false - stack!!.push(currentVertex) - blockedSet!!.add(currentVertex) + stack.push(currentVertex) + blockedSet.add(currentVertex) for (e in graph.edges.filterKeys{it in currentVertex.incidentEdges}.values) { val neighbor: Vertex = graph.vertices[e.vertices.second]!! - //if neighbor is same as start vertex means cycle is found. - //Store contents of stack in final result. if (neighbor === startVertex) { val cycle: MutableList = ArrayList() - stack!!.push(startVertex) - cycle.addAll(stack!!) - Collections.reverse(cycle) - stack!!.pop() - allCycles!!.add(cycle) + stack.push(startVertex) + cycle.addAll(stack) + cycle.reverse() + stack.pop() + allCycles.add(cycle) foundCycle = true - } //explore this neighbor only if it is not in blockedSet. - else if (!blockedSet!!.contains(neighbor)) { + } + else if (!blockedSet.contains(neighbor)) { val gotCycle = findCyclesInSCG(graph,startVertex, neighbor) foundCycle = foundCycle || gotCycle } } - //if cycle is found with current vertex then recursively unblock vertex and all vertices which are dependent on this vertex. if (foundCycle) { - //remove from blockedSet and then remove all the other vertices dependent on this vertex from blockedSet unblock(currentVertex) } else { - //if no cycle is found with current vertex then don't unblock it. But find all its neighbors and add this - //vertex to their blockedMap. If any of those neighbors ever get unblocked then unblock current vertex as well. for (e in graph.edges.filterKeys{it in currentVertex.incidentEdges}.values) { val w: Vertex = graph.vertices[e.vertices.second]!! val bSet: MutableSet = getBSet(w) bSet.add(currentVertex) } } - //remove vertex from the stack. - stack!!.pop() + stack.pop() return foundCycle } private fun getBSet(v: Vertex): MutableSet { - return (blockedMap?.computeIfAbsent(v + return (blockedMap.computeIfAbsent(v ) { HashSet() } as MutableSet?)!! } private fun createSubGraph(startVertex: Int, graph: Graph): Graph { - val subGraph: Graph = Graph() + val subGraph = Graph() subGraph.isDirected = true for ((i, edge) in graph.getEdges().withIndex()) { if (edge.vertices.first >= startVertex && edge.vertices.second >= startVertex) { @@ -152,40 +134,36 @@ class AllCyclesInDirectedGraphJohnson { } return subGraph } - - companion object { - @JvmStatic - fun main(args: Array) { - val johnson = AllCyclesInDirectedGraphJohnson() - val graph: Graph = Graph() - graph.isDirected = true - for (i in 1..9){ - graph.addVertex(i,"") - } - graph.addEdge(1, 2, edgeID = 0) - graph.addEdge(1, 8, edgeID = 1) - graph.addEdge(1, 5, edgeID = 2) - graph.addEdge(2, 9, edgeID = 3) - graph.addEdge(2, 7, edgeID = 4) - graph.addEdge(2, 3, edgeID = 5) - graph.addEdge(3, 1, edgeID = 6) - graph.addEdge(3, 2, edgeID = 7) - graph.addEdge(3, 6, edgeID = 8) - graph.addEdge(3, 4, edgeID = 9) - graph.addEdge(6, 4, edgeID = 10) - graph.addEdge(4, 5, edgeID = 11) - graph.addEdge(5, 2, edgeID = 12) - graph.addEdge(8, 9, edgeID = 13) - graph.addEdge(9, 8, edgeID = 14) - - val allCycles: List> = johnson.simpleCyles(graph) - val joiner = StringJoiner("->") - allCycles.forEach { cycle: List -> - cycle.forEach { vertex: Vertex? -> - joiner.add("${vertex?.id}") - } - println(joiner) - } - } - } -} \ No newline at end of file +} +//fun main(args: Array) { +// val johnson = AllCyclesInDirectedGraphJohnson() +// val graph = Graph() +// graph.isDirected = true +// for (i in 1..9){ +// graph.addVertex(i,"") +// } +// graph.addEdge(1, 2, edgeID = 0) +// graph.addEdge(1, 8, edgeID = 1) +// graph.addEdge(1, 5, edgeID = 2) +// graph.addEdge(2, 9, edgeID = 3) +// graph.addEdge(2, 7, edgeID = 4) +// graph.addEdge(2, 3, edgeID = 5) +// graph.addEdge(3, 1, edgeID = 6) +// graph.addEdge(3, 2, edgeID = 7) +// graph.addEdge(3, 6, edgeID = 8) +// graph.addEdge(3, 4, edgeID = 9) +// graph.addEdge(6, 4, edgeID = 10) +// graph.addEdge(4, 5, edgeID = 11) +// graph.addEdge(5, 2, edgeID = 12) +// graph.addEdge(8, 9, edgeID = 13) +// graph.addEdge(9, 8, edgeID = 14) +// +// val allCycles: List> = johnson.simpleCycles(graph) +// val joiner = StringJoiner("->") +// allCycles.forEach { cycle: List -> +// cycle.forEach { vertex: Vertex? -> +// joiner.add("${vertex?.id}") +// } +// println(joiner) +// } +//} \ No newline at end of file diff --git a/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt b/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt index 288637a..e4b0485 100644 --- a/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt +++ b/src/main/kotlin/algorithms/TarjanStrongConnecedComponent.kt @@ -5,18 +5,6 @@ import model.graph.Vertex import java.util.* import kotlin.math.min - -/** - * Date 08/16/2015 - * @author Tushar Roy - * - * Find strongly connected components of directed graph. - * - * Time complexity is O(E + V) - * Space complexity is O(V) - * - * Reference - https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm - */ class TarjanStronglyConnectedComponent { private var visitedTime: MutableMap = mutableMapOf() private var lowTime: MutableMap = mutableMapOf() @@ -27,7 +15,6 @@ class TarjanStronglyConnectedComponent { private var time = 0 fun scc(graph: Graph): List> { - //start from any vertex in the graph. for (vertex in graph.getVertices()) { if (visited.contains(vertex)) { continue @@ -47,22 +34,15 @@ class TarjanStronglyConnectedComponent { onStack.add(vertex) for (child in vertex.adjacentVertices) { - //if child is not visited then visit it and see if it has link back to vertex's ancestor. In that case update - //low time to ancestor's visit time if (child !in visited) { sccUtil(child) - //sets lowTime[vertex] = min(lowTime[vertex], lowTime[child]); lowTime[vertex] = min(lowTime[vertex]!!, lowTime[child]!!) - } //if child is on stack then see if it was visited before vertex's low time. If yes then update vertex's low time to that. + } else if (child in onStack) { - //sets lowTime[vertex] = min(lowTime[vertex], visitedTime[child]); lowTime[vertex] = min(lowTime[vertex]!!, visitedTime[child]!!) } } - //if vertex low time is same as visited time then this is start vertex for strongly connected component. - //keep popping vertices out of stack still you find current vertex. They are all part of one strongly - //connected component. if (visitedTime[vertex] === lowTime[vertex]) { val stronglyConnectedComponent: MutableSet = HashSet() var v: Vertex From cd2bba55c9d5474af0a6cb346998fdcc2d0649bb Mon Sep 17 00:00:00 2001 From: dronshock Date: Wed, 29 May 2024 09:36:04 +0300 Subject: [PATCH 144/211] feat(GUI): add buttons for algorithms --- src/main/kotlin/view/AlgorithmSubMenu.kt | 67 +++++++++++++++++++++--- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index ef752b4..028c774 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -2,6 +2,7 @@ package view import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -10,13 +11,63 @@ import androidx.compose.ui.unit.dp @Composable fun AlgorithmSubMenu() { Column(Modifier.padding(start = 16.dp, end = 0.dp, top = 15.dp)) { - Text(text = "Выделение ключевых вершин") - Text(text = "Поиск сообществ") - Text(text = "Выделение компонент сильной связности") - Text(text = "Поиск мостов") - Text(text = "Поиск циклов для заданной вершины") - Text(text = "Построение минимального остовного дерева") - Text(text = "Кратчайший путь алгоритмом Дейкстры") - Text(text = "Кратчайший путь алгоритмом Форда-Беллмана") + Button( + onClick = { /*TODO*/ }, + enabled = true, + ) { + Text( + text = "Выделение ключевых вершин", + ) + } + Button( + onClick = { /*TODO*/ }, + enabled = true, + ) { + Text( + text = "Поиск сообществ", + ) + } + Button( + onClick = { /*TODO*/ }, + enabled = true, + ) { + Text( + text = "Выделение компонент сильной связности", + ) + } + Button( + onClick = { /*TODO*/ }, + enabled = true, + ) { + Text( + text = "Поиск мостов", + ) + } + Button( + onClick = { /*TODO*/ }, + enabled = true, + ) { + Text( + text = "Построение минимального остовного дерева", + ) + } + Button( + onClick = { /*TODO*/ }, + enabled = true, + modifier = Modifier.padding(top = 3.dp), + ) { + Text( + text = "Кратчайший путь алгоритмом Дейкстры", + ) + } + Button( + onClick = { /*TODO*/ }, + enabled = true, + modifier = Modifier.padding(top = 3.dp), + ) { + Text( + text = "Кратчайший путь алгоритмом Форда-Беллмана", + ) + } } } \ No newline at end of file From f142891168e51480cac49c262b3f93326b5bcd72 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 28 May 2024 20:45:17 +0000 Subject: [PATCH 145/211] feat: implement ForceAtlas2 --- .run/desktop.run.xml | 41 +-- build.gradle.kts | 2 + src/main/kotlin/Main.kt | 314 +++++++++++++++++- .../kotlin/model/layout/ForceAtlas2Layout.kt | 94 ++++++ src/main/kotlin/view/graph/EdgeView.kt | 3 +- src/main/kotlin/view/graph/VertexView.kt | 5 +- src/main/kotlin/viewmodel/CanvasViewModel.kt | 4 +- .../viewmodel/layouts/CircularLayout.kt | 5 +- .../layouts/RepresentationStrategy.kt | 3 +- 9 files changed, 434 insertions(+), 37 deletions(-) create mode 100644 src/main/kotlin/model/layout/ForceAtlas2Layout.kt diff --git a/.run/desktop.run.xml b/.run/desktop.run.xml index f91b2c2..a24b2e0 100644 --- a/.run/desktop.run.xml +++ b/.run/desktop.run.xml @@ -1,21 +1,24 @@ - - - - - - true - - + + + + + + true + true + false + false + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index d8b9450..f871b3b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,12 +16,14 @@ version = "1.0-SNAPSHOT" repositories { mavenCentral() + maven("https://raw.github.com/gephi/gephi/mvn-thirdparty-repo/") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") google() } val exposedVersion: String by project val neo4jDriverVersion = "4.4.5" dependencies { + implementation("org.gephi", "gephi-toolkit", "0.10.1", classifier = "all") testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0") implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 03898ca..1c62149 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -4,7 +4,11 @@ import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import controller.GraphPainter import model.graph.Graph +import model.layout.ForceAtlas2Layout +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 +import view.Canvas import view.NavigationDrawer import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout @@ -21,9 +25,9 @@ val graph = Graph().apply { addEdge(1, 2, 1,1) addEdge(3, 4, 2,2) addEdge(1, 3, 3,3) - addEdge(2, 4, 4,4) - addEdge(2, 5, 5,5) - addEdge(5, 7, 6,6) + addEdge(2, 3, 4,4) + addEdge(5, 3, 5,5) + addEdge(3, 7, 6,6) addVertex(8, "Pudge") addVertex(9,"Tiny") @@ -33,21 +37,307 @@ val graph = Graph().apply { addVertex(13,"Sniper") addVertex(14,"Roshan") - addEdge(14, 8, 7,7) - addEdge(14, 9, 8,8) - addEdge(14, 10, 9,9) - addEdge(14, 11, 10,10) - addEdge(14, 12, 11,11) - addEdge(14, 13, 12,12) - + addEdge(14, 8, 6,7) + addEdge(14, 9, 6,8) + addEdge(14, 10, 6,9) + addEdge(14, 11, 6,10) + addEdge(14, 12, 6,11) + addEdge(14, 13, 5,12) addEdge(14, 3, 0,13) + + addVertex(15, "aPudge") + addVertex(16,"aTiny") + addVertex(17, "aLycan") + addVertex(18,"aIo") + addVertex(19,"aLion") + addVertex(20,"aSniper") + addVertex(21,"aRoshan") + + addEdge(16, 15, 22,14) + addEdge(15, 17, 1,15) + addEdge(15, 18, 6,16) + addEdge(19, 15, 2,17) + addEdge(15, 21, 3,18) + addEdge(20, 15, 5,19) + addEdge(17, 20, 0,20) + addEdge(14, 20, 0,21) +// addVertex(1,"1") +// addVertex(2,"2") +// addVertex(3,"3") +// addVertex(4,"4") +// addVertex(5,"5") +// addVertex(6,"6") +// addVertex(7,"7") +// addVertex(8,"8") +// addVertex(9,"9") +// addVertex(10,"10") +// addVertex(11,"11") +// addVertex(12,"12") +// addVertex(13,"13") +// addVertex(14,"14") +// addVertex(15,"15") +// addVertex(16,"16") +// addVertex(17,"17") +// addVertex(18,"18") +// addVertex(19,"19") +// addVertex(20,"20") +// addVertex(21,"21") +// addVertex(22,"22") +// addVertex(23,"23") +// addVertex(24,"24") +// addVertex(25,"25") +// addVertex(26,"26") +// addVertex(27,"27") +// addVertex(28,"28") +// addVertex(29,"29") +// addVertex(30,"30") +// addVertex(31,"31") +// addVertex(32,"32") +// addVertex(33,"33") +// addVertex(34,"34") +// addVertex(35,"35") +// addVertex(36,"36") +// addVertex(37,"37") +// addVertex(38,"38") +// addVertex(39,"39") +// addVertex(40,"40") +// addVertex(41,"41") +// addVertex(42,"42") +// addVertex(43,"43") +// addVertex(44,"44") +// addVertex(45,"45") +// addVertex(46,"46") +// addVertex(47,"47") +// addVertex(48,"48") +// addVertex(49,"49") +// addVertex(50,"50") +// addVertex(51,"51") +// addVertex(52,"52") +// addVertex(53,"53") +// addVertex(54,"54") +// addVertex(55,"55") +// addVertex(56,"56") +// addVertex(57,"57") +// addVertex(58,"58") +// addVertex(59,"59") +// addVertex(60,"60") +// addVertex(61,"61") +// addVertex(62,"62") +// addVertex(63,"63") +// addVertex(64,"64") +// addVertex(65,"65") +// addVertex(66,"66") +// addVertex(67,"67") +// addVertex(68,"68") +// addVertex(69,"69") +// addVertex(70,"70") +// addVertex(71,"71") +// addVertex(72,"72") +// addVertex(73,"73") +// addVertex(74,"74") +// addVertex(75,"75") +// addVertex(76,"76") +// addVertex(77,"77") +// addVertex(78,"78") +// addVertex(79,"79") +// addVertex(80,"80") +// addVertex(81,"81") +// addVertex(82,"82") +// addVertex(83,"83") +// addVertex(84,"84") +// addVertex(85,"85") +// addVertex(86,"86") +// addVertex(87,"87") +// addVertex(88,"88") +// addVertex(89,"89") +// addVertex(90,"90") +// addVertex(91,"91") +// addVertex(92,"92") +// addVertex(93,"93") +// addVertex(94,"94") +// addVertex(95,"95") +// addVertex(96,"96") +// addVertex(97,"97") +// addVertex(98,"98") +// addVertex(99,"99") +// addVertex(100,"100") +// addEdge(74,14,59,1) +// addEdge(93,86,82,2) +// addEdge(73,67,20,3) +// addEdge(7,27,20,4) +// addEdge(30,6,19,5) +// addEdge(90,64,96,6) +// addEdge(4,39,0,7) +// addEdge(33,80,6,8) +// addEdge(82,42,98,9) +// addEdge(9,21,93,10) +// addEdge(34,13,63,11) +// addEdge(84,93,49,12) +// addEdge(68,78,97,13) +// addEdge(25,82,59,14) +// addEdge(66,85,38,15) +// addEdge(91,56,45,16) +// addEdge(42,64,79,17) +// addEdge(14,66,64,18) +// addEdge(98,2,0,19) +// addEdge(82,35,61,20) +// addEdge(72,10,8,21) +// addEdge(62,63,52,22) +// addEdge(11,36,89,23) +// addEdge(91,62,75,24) +// addEdge(2,24,18,25) +// addEdge(89,80,68,26) +// addEdge(43,84,25,27) +// addEdge(91,48,11,28) +// addEdge(63,26,51,29) +// addEdge(38,58,42,30) +// addEdge(24,15,61,31) +// addEdge(48,88,7,32) +// addEdge(65,38,23,33) +// addEdge(70,51,34,34) +// addEdge(33,38,82,35) +// addEdge(14,13,61,36) +// addEdge(74,54,72,37) +// addEdge(100,87,22,38) +// addEdge(34,24,23,39) +// addEdge(8,100,9,40) +// addEdge(37,4,24,41) +// addEdge(19,21,39,42) +// addEdge(41,60,37,43) +// addEdge(20,67,6,44) +// addEdge(99,52,82,45) +// addEdge(67,30,99,46) +// addEdge(10,45,70,47) +// addEdge(5,47,66,48) +// addEdge(87,74,21,49) +// addEdge(65,29,33,50) +// addEdge(38,37,86,51) +// addEdge(17,68,63,52) +// addEdge(72,73,73,53) +// addEdge(24,52,74,54) +// addEdge(49,42,56,55) +// addEdge(38,4,24,56) +// addEdge(18,63,46,57) +// addEdge(46,77,69,58) +// addEdge(94,16,15,59) +// addEdge(27,50,29,60) +// addEdge(91,24,30,61) +// addEdge(97,46,89,62) +// addEdge(59,77,37,63) +// addEdge(48,95,64,64) +// addEdge(91,11,47,65) +// addEdge(33,37,6,66) +// addEdge(75,89,4,67) +// addEdge(96,87,21,68) +// addEdge(58,61,58,69) +// addEdge(71,47,92,70) +// addEdge(50,96,40,71) +// addEdge(45,63,45,72) +// addEdge(60,48,79,73) +// addEdge(95,90,75,74) +// addEdge(91,15,58,75) +// addEdge(90,53,97,76) +// addEdge(97,14,46,77) +// addEdge(90,57,4,78) +// addEdge(8,51,72,79) +// addEdge(7,42,44,80) +// addEdge(46,22,64,81) +// addEdge(18,72,54,82) +// addEdge(12,71,68,83) +// addEdge(22,10,94,84) +// addEdge(6,100,89,85) +// addEdge(6,87,27,86) +// addEdge(79,46,84,87) +// addEdge(42,87,23,88) +// addEdge(58,81,81,89) +// addEdge(45,67,91,90) +// addEdge(27,58,93,91) +// addEdge(8,1,47,92) +// addEdge(46,59,74,93) +// addEdge(58,90,23,94) +// addEdge(82,81,29,95) +// addEdge(25,30,17,96) +// addEdge(79,21,49,97) +// addEdge(100,28,17,98) +// addEdge(57,85,1,99) +// addEdge(51,3,37,100) +// addEdge(41,54,30,101) +// addEdge(27,1,41,102) +// addEdge(42,89,47,103) +// addEdge(85,40,57,104) +// addEdge(13,46,26,105) +// addEdge(53,51,51,106) +// addEdge(17,45,95,107) +// addEdge(28,83,50,108) +// addEdge(72,15,10,109) +// addEdge(30,47,47,110) +// addEdge(32,43,41,111) +// addEdge(17,84,46,112) +// addEdge(32,66,62,113) +// addEdge(66,82,79,114) +// addEdge(21,36,48,115) +// addEdge(19,32,73,116) +// addEdge(77,83,59,117) +// addEdge(22,24,66,118) +// addEdge(63,10,54,119) +// addEdge(20,44,38,120) +// addEdge(19,17,25,121) +// addEdge(28,51,19,122) +// addEdge(67,8,68,123) +// addEdge(3,81,47,124) +// addEdge(88,93,13,125) +// addEdge(89,79,56,126) +// addEdge(44,89,97,127) +// addEdge(92,29,58,128) +// addEdge(47,52,68,129) +// addEdge(70,52,34,130) +// addEdge(76,95,4,131) +// addEdge(75,69,88,132) +// addEdge(57,97,33,133) +// addEdge(67,31,8,134) +// addEdge(11,15,50,135) +// addEdge(51,89,89,136) +// addEdge(9,71,67,137) +// addEdge(8,11,57,138) +// addEdge(3,53,13,139) +// addEdge(84,67,42,140) +// addEdge(37,76,74,141) +// addEdge(41,68,33,142) +// addEdge(89,12,66,143) +// addEdge(41,56,88,144) +// addEdge(96,96,3,145) +// addEdge(14,34,47,146) +// addEdge(80,73,99,147) +// addEdge(20,84,11,148) +// addEdge(68,30,58,149) +// addEdge(91,32,57,150) +// addEdge(64,44,31,151) +// addEdge(89,92,18,152) +// addEdge(38,72,40,153) +// addEdge(44,70,99,154) +// addEdge(57,13,98,155) +// addEdge(46,76,58,156) +// addEdge(10,8,98,157) +// addEdge(75,37,89,158) +// addEdge(64,21,38,159) +// addEdge(60,29,19,160) +// addEdge(91,73,84,161) +// addEdge(33,76,55,162) +// addEdge(32,34,51,163) +// addEdge(68,48,35,164) +// addEdge(51,63,24,165) } @Composable @Preview fun App() { MaterialTheme { -// Canvas(CanvasViewModel(graph, CircularLayout())) - NavigationDrawer(CanvasViewModel(graph, CircularLayout())) + val canvasGraph = CanvasViewModel(graph, ForceAtlas2Layout()) + val graphViewModel = canvasGraph.graphViewModel + val painter = GraphPainter(graph, graphViewModel) + painter.paint() + MaterialTheme { + Canvas(canvasGraph) + } } } diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt new file mode 100644 index 0000000..1d276df --- /dev/null +++ b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt @@ -0,0 +1,94 @@ +package model.layout + +import androidx.compose.ui.unit.dp +import model.graph.Graph +import viewmodel.graph.GraphViewModel +import viewmodel.layouts.RepresentationStrategy +import org.gephi.layout.plugin.forceAtlas.ForceAtlas +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2Builder +import org.gephi.graph.api.Edge +import org.gephi.graph.api.GraphController +import org.gephi.graph.api.GraphModel +import org.gephi.graph.api.Node +import org.gephi.layout.plugin.force.StepDisplacement +import org.gephi.layout.plugin.force.yifanHu.YifanHuLayout +import org.gephi.layout.plugin.forceAtlas.ForceAtlasLayout +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2LayoutData +import org.gephi.project.api.ProjectController +import org.openide.util.Lookup +import viewmodel.graph.VertexViewModel +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min +import kotlin.random.Random + + +class ForceAtlas2Layout:RepresentationStrategy{ + + override fun place(width: Double, height: Double, graphViewModel:GraphViewModel){ + + var maxX = Int.MIN_VALUE + var minX = Int.MAX_VALUE + var maxY = Int.MIN_VALUE + var minY = Int.MAX_VALUE + + val pc = Lookup.getDefault().lookup(ProjectController::class.java) + pc.newProject() + val graphModel = Lookup.getDefault().lookup(GraphController::class.java).graphModel + val graph = graphModel.undirectedGraph + + val verticesMap = mutableMapOf() + for (vertex in graphViewModel.verticesViewValues){ + val v: Node =graphModel.factory().newNode(vertex.vertex.id.toString()) + v.setX(Random.nextFloat()*10) + v.setY(Random.nextFloat()*10) + graph.addNode(v) + verticesMap[vertex.vertex.id]=v + } + //TODO добавить возможность получения информации об ориентированности графа + for (edge in graphViewModel.edgesViewValues){ + val e: Edge = graphModel.factory().newEdge( + verticesMap[edge.u.vertex.id], + verticesMap[edge.v.vertex.id], + 1, + false + ) + graph.addEdge(e) + } + val layout = ForceAtlas2(null) + layout.setGraphModel(graphModel) + layout.initAlgo() + layout.resetPropertiesValues() + layout.isAdjustSizes = true + layout.isBarnesHutOptimize = true + layout.scalingRatio = 20.0 + layout.gravity = 2.0 + + var i = 0 + while (i < 5000 && layout.canAlgo()) { + layout.goAlgo() + i++ + } + layout.endAlgo() + + for (vertex in graphViewModel.verticesViewValues) { + val v: Node = graph.getNode(vertex.vertex.id.toString()) + val x = ((width/2 + v.x())) + val y = ((height/2 + v.y())) + vertex.x = (x).toInt().dp + vertex.y = (y).toInt().dp + + maxX = max(maxX, x.toInt()) + minX = min(minX, x.toInt()) + maxY = max(maxY, y.toInt()) + minY = min(minY, y.toInt()) + } + val graphWidthScale = width / (maxX + abs(minX)) + val graphHeightScale = height / (maxY + abs(minY)) + } + + override fun highlight(vertices: Collection) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/graph/EdgeView.kt b/src/main/kotlin/view/graph/EdgeView.kt index 79bfe1c..9b9512d 100644 --- a/src/main/kotlin/view/graph/EdgeView.kt +++ b/src/main/kotlin/view/graph/EdgeView.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.Modifier import androidx.compose.material.Text import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.zIndex import viewmodel.graph.EdgeViewModel @Composable @@ -15,7 +16,7 @@ fun EdgeView( viewModel: EdgeViewModel, modifier: Modifier = Modifier, ) { - Canvas(modifier = modifier.fillMaxSize()) { + Canvas(modifier = modifier.fillMaxSize().zIndex(-1f)) { drawLine( start = Offset( viewModel.u.x.toPx() + viewModel.u.radius.toPx(), diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt index 9a73efa..d89a170 100644 --- a/src/main/kotlin/view/graph/VertexView.kt +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -1,6 +1,7 @@ package view.graph import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.offset @@ -10,6 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.material.Text +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import viewmodel.graph.VertexViewModel @@ -20,8 +22,9 @@ fun VertexView( modifier: Modifier = Modifier, ) { Box(modifier = modifier - .size(viewModel.radius * 2, viewModel.radius * 2) + .size(viewModel.radius+10.dp, viewModel.radius+10.dp) .offset(viewModel.x, viewModel.y) + .border(2.dp, Color.Black, CircleShape) .background( color = viewModel.color, shape = CircleShape diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 9684bcb..3f5e43d 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -12,11 +12,11 @@ class CanvasViewModel(graph: Graph, private val representationStrategy: Represen val graphViewModel = GraphViewModel(graph) init { - representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) + representationStrategy.place(1280.0, 860.0, graphViewModel) } fun resetGraphView() { - representationStrategy.place(800.0, 600.0, graphViewModel.verticesViewValues) + representationStrategy.place(800.0, 600.0, graphViewModel) graphViewModel.verticesViewValues.forEach{ v -> v.color = Color.Blue} } diff --git a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt index 759a45f..572f58a 100644 --- a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt +++ b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt @@ -2,6 +2,8 @@ package viewmodel.layouts import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import org.gephi.graph.api.GraphView +import viewmodel.graph.GraphViewModel import viewmodel.graph.VertexViewModel import kotlin.math.cos import kotlin.math.min @@ -9,7 +11,8 @@ import kotlin.math.sin import kotlin.random.Random class CircularLayout: RepresentationStrategy { - override fun place(width: Double, height: Double, vertices: Collection) { + override fun place(width: Double, height: Double, graph: GraphViewModel) { + val vertices = graph.verticesViewValues if (vertices.isEmpty()) { println("CircularPlacementStrategy.place: there is nothing to place 👐🏻") return diff --git a/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt index 655fd11..f4f9019 100644 --- a/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt +++ b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt @@ -1,8 +1,9 @@ package viewmodel.layouts +import viewmodel.graph.GraphViewModel import viewmodel.graph.VertexViewModel interface RepresentationStrategy { - fun place(width: Double, height: Double, vertices: Collection) + fun place(width: Double, height: Double, graph: GraphViewModel) fun highlight(vertices: Collection) } \ No newline at end of file From 9881f154c189a29bb4652935a46e2269a1f58a69 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Tue, 28 May 2024 21:22:05 +0000 Subject: [PATCH 146/211] fix: Delete redundant code --- src/main/kotlin/model/layout/ForceAtlas2Layout.kt | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt index 1d276df..5819cc4 100644 --- a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt +++ b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt @@ -28,11 +28,6 @@ class ForceAtlas2Layout:RepresentationStrategy{ override fun place(width: Double, height: Double, graphViewModel:GraphViewModel){ - var maxX = Int.MIN_VALUE - var minX = Int.MAX_VALUE - var maxY = Int.MIN_VALUE - var minY = Int.MAX_VALUE - val pc = Lookup.getDefault().lookup(ProjectController::class.java) pc.newProject() val graphModel = Lookup.getDefault().lookup(GraphController::class.java).graphModel @@ -78,17 +73,10 @@ class ForceAtlas2Layout:RepresentationStrategy{ val y = ((height/2 + v.y())) vertex.x = (x).toInt().dp vertex.y = (y).toInt().dp - - maxX = max(maxX, x.toInt()) - minX = min(minX, x.toInt()) - maxY = max(maxY, y.toInt()) - minY = min(minY, y.toInt()) } - val graphWidthScale = width / (maxX + abs(minX)) - val graphHeightScale = height / (maxY + abs(minY)) } override fun highlight(vertices: Collection) { TODO("Not yet implemented") } -} \ No newline at end of file +} From e67396b6932cbf005b21b2f6d926be5854a0e3d1 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Tue, 28 May 2024 20:45:17 +0000 Subject: [PATCH 147/211] feat: implement ForceAtlas2 --- src/main/kotlin/model/layout/ForceAtlas2Layout.kt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt index 5819cc4..88b2428 100644 --- a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt +++ b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt @@ -1,26 +1,15 @@ package model.layout import androidx.compose.ui.unit.dp -import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -import org.gephi.layout.plugin.forceAtlas.ForceAtlas import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 -import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2Builder import org.gephi.graph.api.Edge import org.gephi.graph.api.GraphController -import org.gephi.graph.api.GraphModel import org.gephi.graph.api.Node -import org.gephi.layout.plugin.force.StepDisplacement -import org.gephi.layout.plugin.force.yifanHu.YifanHuLayout -import org.gephi.layout.plugin.forceAtlas.ForceAtlasLayout -import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2LayoutData import org.gephi.project.api.ProjectController import org.openide.util.Lookup import viewmodel.graph.VertexViewModel -import kotlin.math.abs -import kotlin.math.max -import kotlin.math.min import kotlin.random.Random @@ -79,4 +68,4 @@ class ForceAtlas2Layout:RepresentationStrategy{ override fun highlight(vertices: Collection) { TODO("Not yet implemented") } -} +} \ No newline at end of file From 945df2916bc7c0d3325baac6a1da83461ed7b83a Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 12:06:50 +0000 Subject: [PATCH 148/211] feat: add some files for graph load --- src/main/kotlin/Main.kt | 38 ++++++++++++-------- src/main/kotlin/view/CanvasView.kt | 29 +-------------- src/main/kotlin/view/LoadGraphMenu.kt | 2 ++ src/main/kotlin/view/MainScreen.kt | 37 +++++++++++++++++++ src/main/kotlin/view/NavigationDrawer.kt | 16 --------- src/main/kotlin/viewmodel/CanvasViewModel.kt | 9 ----- 6 files changed, 64 insertions(+), 67 deletions(-) create mode 100644 src/main/kotlin/view/LoadGraphMenu.kt create mode 100644 src/main/kotlin/view/MainScreen.kt diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 1c62149..15286da 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -2,25 +2,30 @@ import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.window.Window +import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState import controller.GraphPainter import model.graph.Graph import model.layout.ForceAtlas2Layout import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 import view.Canvas +import view.MainScreen import view.NavigationDrawer import viewmodel.CanvasViewModel import viewmodel.layouts.CircularLayout +import java.awt.Dimension val graph = Graph().apply { - addVertex(1,"Thomas Shelby") - addVertex(2, "Andrew Tate") + addVertex(1,"Thomas") + addVertex(2, "Andrew") addVertex(3, "Iakov") - addVertex(4, "John Shelby") - addVertex(5, "Tristan Tate") - addVertex(6, "Arthur Shelby") - addVertex(7, "Ryan Gosling") + addVertex(4, "John") + addVertex(5, "Tristan") + addVertex(6, "Arthur") + addVertex(7, "Ryan") addEdge(1, 2, 1,1) addEdge(3, 4, 2,2) @@ -45,13 +50,13 @@ val graph = Graph().apply { addEdge(14, 13, 5,12) addEdge(14, 3, 0,13) - addVertex(15, "aPudge") - addVertex(16,"aTiny") - addVertex(17, "aLycan") - addVertex(18,"aIo") - addVertex(19,"aLion") - addVertex(20,"aSniper") - addVertex(21,"aRoshan") + addVertex(15, "1") + addVertex(16,"2") + addVertex(17, "3") + addVertex(18,"4") + addVertex(19,"5") + addVertex(20,"6") + addVertex(21,"7") addEdge(16, 15, 22,14) addEdge(15, 17, 1,15) @@ -327,6 +332,7 @@ val graph = Graph().apply { // addEdge(68,48,35,164) // addEdge(51,63,24,165) } +val windowSizeStart = Pair(1480,1020) @Composable @Preview fun App() { @@ -342,7 +348,11 @@ fun App() { } fun main() = application { - Window(onCloseRequest = ::exitApplication) { + Window(onCloseRequest = ::exitApplication, + title = "stoic", + state = rememberWindowState(position = WindowPosition(Alignment.Center)) + ) { + window.minimumSize = Dimension(windowSizeStart.first, windowSizeStart.second) App() } } \ No newline at end of file diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 2d0b958..7cf5182 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -79,34 +79,7 @@ fun Canvas(viewModel: CanvasViewModel) { AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu() } - Row { - Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { - viewModel.showVerticesLabels.value = it - }) - Text("Show vertices labels", fontSize = 20.sp, modifier = Modifier.padding(0.dp)) - } - Row { - Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { - viewModel.showEdgesLabels.value = it - }) - Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) - } - Button( - onClick = viewModel::resetGraphView, - enabled = true, - ) { - Text( - text = "Reset default settings", - ) - } - Button( - onClick = viewModel::setVerticesColor, - enabled = true, - ) { - Text( - text = "Set colors", - ) - } + } }, ) { diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt new file mode 100644 index 0000000..8d8a2bb --- /dev/null +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -0,0 +1,2 @@ +package view + diff --git a/src/main/kotlin/view/MainScreen.kt b/src/main/kotlin/view/MainScreen.kt new file mode 100644 index 0000000..58cb30c --- /dev/null +++ b/src/main/kotlin/view/MainScreen.kt @@ -0,0 +1,37 @@ +package view + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import javax.swing.border.Border + + +@Composable +fun MainScreen() { + Box(modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center){ + Box() { + Column(modifier = Modifier.fillMaxWidth().fillMaxHeight(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally) { + Button(onClick = { } + ){ + Text("Load Graph") + } + + Button(onClick = { }) { + Text("Exit") + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index ad7afa3..fab6410 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -84,22 +84,6 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { }) Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) } - Button( - onClick = viewModel::resetGraphView, - enabled = true, - ) { - Text( - text = "Reset default settings", - ) - } - Button( - onClick = viewModel::setVerticesColor, - enabled = true, - ) { - Text( - text = "Set colors", - ) - } } }, ) { diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 3f5e43d..84ce4d0 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -14,13 +14,4 @@ class CanvasViewModel(graph: Graph, private val representationStrategy: Represen init { representationStrategy.place(1280.0, 860.0, graphViewModel) } - - fun resetGraphView() { - representationStrategy.place(800.0, 600.0, graphViewModel) - graphViewModel.verticesViewValues.forEach{ v -> v.color = Color.Blue} - } - - fun setVerticesColor() { - representationStrategy.highlight(graphViewModel.verticesViewValues) - } } \ No newline at end of file From ee74cd8e28428538dc5a3a0aca03f1bb6eb580ca Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 16:06:23 +0300 Subject: [PATCH 149/211] feat(ui): save_graph page added --- src/main/kotlin/view/CanvasView.kt | 6 + src/main/kotlin/view/NavigationDrawer.kt | 192 ++++++++++++++++++++++- 2 files changed, 196 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 2d0b958..45e43e9 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,6 +1,8 @@ package view import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -19,14 +21,18 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel +import androidx.compose.material3.RadioButton @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + Surface( modifier = Modifier.fillMaxSize(), contentColor = Color.LightGray, diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index ad7afa3..8b2b333 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -1,8 +1,9 @@ package view import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List @@ -13,17 +14,126 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel +enum class StorageType { + FILE, + NEO4J, + SQLITE +} + @Composable fun NavigationDrawer(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + val showDialog = remember { mutableStateOf(false) } + val storageType = remember { mutableStateOf(StorageType.FILE) } + val fileName = remember { mutableStateOf("") } + val isDirectedGraph = remember { mutableStateOf(false) } + val uri = remember { mutableStateOf("") } + val login = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + val interactionSource = remember { MutableInteractionSource() } + + AnimatedVisibility(visible = showDialog.value) { + Dialog( + onDismissRequest = { showDialog.value = false }, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text("Choose where to save the graph:") + CustomRadioGroup( + selectedOption = storageType.value.toString(), + options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), + onOptionSelected = { storageType.value = StorageType.valueOf(it) } + ) + + when (storageType.value) { + StorageType.FILE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) // Пространство между чекбоксом и текстом + Text("Ориентированный ли граф") + } + StorageType.NEO4J -> { + TextField( + value = uri.value, + onValueChange = { uri.value = it }, + label = { Text("URI") } + ) + TextField( + value = login.value, + onValueChange = { login.value = it }, + label = { Text("Login") } + ) + TextField( + value = password.value, + onValueChange = { password.value = it }, + label = { Text("Password") }, + visualTransformation = PasswordVisualTransformation() + ) + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + Text("Ориентированный ли граф") + } + StorageType.SQLITE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + Text("Ориентированный ли граф") + } + } + + Button( + onClick = { + when (storageType.value) { + StorageType.FILE -> { + // Логика сохранения в файл с использованием fileName и isDirectedGraph + } + StorageType.NEO4J -> { + // Логика сохранения в Neo4j + } + StorageType.SQLITE -> { + // Логика сохранения в SQLite + } + } + showDialog.value = false + } + ) { + Text("Save") + } + } + } + } val showSubMenu = remember { mutableStateOf(false) @@ -100,6 +210,16 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { text = "Set colors", ) } + Button( + enabled = true, + onClick = { + scope.launch { + showDialog.value = true + } + } + ) { + Text(text = "Save Graph") + } } }, ) { @@ -122,4 +242,72 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } } +} + +@Composable +fun CustomRadioGroup( + options: List, + selectedOption: String, + onOptionSelected: (String) -> Unit +) { + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("NEO4J", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.NEO4J.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("FILE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.FILE.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("SQLITE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.SQLITE.name) } + ) { + Text("Select") + } + } + } } \ No newline at end of file From 79aaddb71ecef6c73230427ae79f58b944628423 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 13:07:06 +0000 Subject: [PATCH 150/211] feat: add load dialog window --- build.gradle.kts | 1 + src/main/kotlin/view/CanvasView.kt | 10 +- src/main/kotlin/view/LoadGraphMenu.kt | 140 ++++++++++++++++++ src/main/kotlin/viewmodel/CanvasViewModel.kt | 8 +- .../viewmodel/LoadGraphMenuViewModel.kt | 10 ++ 5 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt diff --git a/build.gradle.kts b/build.gradle.kts index f871b3b..a6c2e17 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation(compose.desktop.currentOs) implementation(compose.material3) + implementation(compose.foundation) implementation("org.slf4j:slf4j-nop:latest.release") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") testRuntimeOnly("org.junit.platform:junit-platform-launcher") diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 7cf5182..6ae8b8b 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -18,10 +18,10 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel +import viewmodel.LoadGraphMenuViewModel @Composable fun Canvas(viewModel: CanvasViewModel) { @@ -79,6 +79,10 @@ fun Canvas(viewModel: CanvasViewModel) { AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu() } + Button(onClick = { viewModel.isOpenLoadGraph = true }) { + Text("Load graph") + } + } }, @@ -106,5 +110,7 @@ fun Canvas(viewModel: CanvasViewModel) { GraphView(viewModel.graphViewModel) } } - + if (viewModel.isOpenLoadGraph) { + LoadGraph(LoadGraphMenuViewModel(viewModel)) + } } diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 8d8a2bb..37c3e5d 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -1,2 +1,142 @@ package view +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.DialogWindow +import androidx.compose.ui.window.WindowPosition +import androidx.compose.ui.window.rememberDialogState +import kotlinx.coroutines.launch +import viewmodel.LoadGraphMenuViewModel + +@Composable +fun LoadGraph(viewModel: LoadGraphMenuViewModel) { + val coroutineScope = rememberCoroutineScope() + + + DialogWindow( + onCloseRequest = { viewModel.canvasViewModel.isOpenLoadGraph = false}, + state = rememberDialogState(position = WindowPosition(Alignment.Center), size = DpSize(500.dp, 350.dp)), + title = "Load New Graph", + resizable = false + ) { + Column( + Modifier + .fillMaxSize() + .padding(4.dp) + ) { + val modifierRow = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) + val verticalRow = Alignment.CenterVertically + + Row(modifierRow, verticalAlignment = verticalRow) { + Text( + "Graph name:", + modifier = Modifier.weight(0.5f), + textAlign = TextAlign.Center, + + ) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.graphName.value, + onValueChange = { newValue -> viewModel.graphName.value = newValue }, + label = { Text("Name") }, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + ), + ) + } + Row(modifierRow, verticalAlignment = verticalRow) { +// ComboBox( +// items = VertexIDType.entries.toTypedArray(), +// modifier = Modifier.weight(1f), +// onItemClick = { item: VertexIDType -> viewModel.selectedVertexTypeID.value = item }, +// textAlign = TextAlign.Center +// ) + } + Row(modifierRow, verticalAlignment = verticalRow) { + Button( + //selected = viewModel.isGraphWeighted.value, + onClick = { viewModel.isGraphWeighted.value = !viewModel.isGraphWeighted.value }, + + //text = "Weighted graph", + //verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.weight(1f), + //reversed = true + ){ + Text("Weight") + } + Button( + //selected = viewModel.isGraphDirected.value, + onClick = { viewModel.isGraphDirected.value = !viewModel.isGraphDirected.value }, + + //verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.weight(1f), + ){Text("Directed graph")} + } + Row(modifierRow, verticalAlignment = verticalRow) { +// Text( +// "Vertices ID type:", +// modifier = Modifier.weight(0.5f), +// textAlign = TextAlign.Center, +// style = JetTheme.typography.toolbar +// ) +// ComboBox( +// items = GraphSavingType.entries.toTypedArray(), +// modifier = Modifier.weight(1f), +// onItemClick = { item: GraphSavingType -> viewModel.selectedSaveType.value = item }, +// textAlign = TextAlign.Center +// ) + } + Row(modifierRow, verticalAlignment = verticalRow) { + Spacer(modifier = Modifier.weight(1f)) + Button( + colors = ButtonDefaults.buttonColors( +// backgroundColor = JetTheme.colors.tertiaryBackground, +// contentColor = JetTheme.colors.secondaryText, +// disabledContentColor = JetTheme.colors.secondaryText, +// disabledBackgroundColor = JetTheme.colors.tertiaryBackground + ), + onClick = { viewModel.canvasViewModel.isOpenLoadGraph = false } + ) { + Text("Cancel") + } + Spacer(modifier = Modifier.weight(0.01f)) + Button( + colors = ButtonDefaults.buttonColors( +// backgroundColor = JetTheme.colors.tertiaryBackground, +// contentColor = JetTheme.colors.secondaryText, +// disabledContentColor = JetTheme.colors.secondaryText, +// disabledBackgroundColor = JetTheme.colors.tertiaryBackground + ), + onClick = { + if (viewModel.graphName.value.trim() == "") { + println("Invalid value") + } else { + viewModel.canvasViewModel.isOpenLoadGraph = false + coroutineScope.launch { +// val graph = viewModel.canvasViewModel.createGraph( +// viewModel.graphName.value, +//// viewModel.selectedVertexTypeID.value, +// viewModel.isGraphDirected.value, +// viewModel.isGraphWeighted.value +// ) +// viewModel.homePageViewModel.settings.saveGraph( +// graph, +// viewModel.selectedVertexTypeID.value, +// viewModel.selectedSaveType.value +// ) + } + } + } + ) { + Text("Create") + } + } + } + } +} diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 84ce4d0..3c6a8b9 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -1,7 +1,6 @@ package viewmodel import androidx.compose.runtime.mutableStateOf -import androidx.compose.ui.graphics.Color import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy @@ -11,6 +10,13 @@ class CanvasViewModel(graph: Graph, private val representationStrategy: Represen val showEdgesLabels = mutableStateOf(false) val graphViewModel = GraphViewModel(graph) + private val _isOpenLoadGraph = mutableStateOf(false) + var isOpenLoadGraph: Boolean + get() = _isOpenLoadGraph.value + set(value) { + _isOpenLoadGraph.value = value + } + init { representationStrategy.place(1280.0, 860.0, graphViewModel) } diff --git a/src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt b/src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt new file mode 100644 index 0000000..b663c58 --- /dev/null +++ b/src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt @@ -0,0 +1,10 @@ +package viewmodel + +import androidx.compose.runtime.mutableStateOf + +class LoadGraphMenuViewModel(val canvasViewModel: CanvasViewModel) { + val graphName = mutableStateOf("") + val isGraphWeighted = mutableStateOf(false) + val isGraphDirected = mutableStateOf(false) +// val selectedSaveType = mutableStateOf(GraphSavingType.LOCAL_FILE) +} From a4dfd6ac569093a9e6c89a6a9937c0c922883bd3 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 16:51:51 +0300 Subject: [PATCH 151/211] feat(ui): graph save neo4j implementation --- src/main/kotlin/view/NavigationDrawer.kt | 6 ++++++ src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index 8b2b333..a3cf822 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -23,6 +23,8 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch +import model.databases.neo4j.Neo4jHandler +import model.databases.neo4j.Neo4jRepository import view.graph.GraphView import viewmodel.CanvasViewModel @@ -121,6 +123,10 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { } StorageType.NEO4J -> { // Логика сохранения в Neo4j + val repo = Neo4jRepository(uri.value, login.value, password.value) + val handler = Neo4jHandler(repo) + viewModel.graph.isDirected = isDirectedGraph.value + handler.saveGraphToNeo4j(viewModel.graph) } StorageType.SQLITE -> { // Логика сохранения в SQLite diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 9684bcb..2145ac0 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -6,7 +6,7 @@ import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -class CanvasViewModel(graph: Graph, private val representationStrategy: RepresentationStrategy,) { +class CanvasViewModel(val graph: Graph, private val representationStrategy: RepresentationStrategy,) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) val graphViewModel = GraphViewModel(graph) From e1dd046ef49173a5c51bbf62c545abaec80d9d16 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 17:23:48 +0300 Subject: [PATCH 152/211] feat(ui): graph save neo4j implementation --- src/main/kotlin/view/CanvasView.kt | 217 ++++++++++++++++++++++- src/main/kotlin/view/NavigationDrawer.kt | 186 ------------------- 2 files changed, 213 insertions(+), 190 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 45e43e9..25a8c45 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,11 +1,9 @@ package view import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material.Surface import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -27,12 +25,139 @@ import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel import androidx.compose.material3.RadioButton +import androidx.compose.ui.Alignment +import androidx.compose.ui.text.input.PasswordVisualTransformation +import model.databases.neo4j.Neo4jHandler +import model.databases.neo4j.Neo4jRepository @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + val showDialog = remember { mutableStateOf(false) } + val storageType = remember { mutableStateOf(StorageType.FILE) } + val fileName = remember { mutableStateOf("") } + val isDirectedGraph = remember { mutableStateOf(false) } + val isWeighted = remember { mutableStateOf(false) } + val uri = remember { mutableStateOf("") } + val login = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + val interactionSource = remember { MutableInteractionSource() } + AnimatedVisibility(visible = showDialog.value) { + Dialog( + onDismissRequest = { showDialog.value = false }, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text("Choose where to save the graph:") + CustomRadioGroup( + selectedOption = storageType.value.toString(), + options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), + onOptionSelected = { storageType.value = StorageType.valueOf(it) } + ) + + when (storageType.value) { + StorageType.FILE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.NEO4J -> { + TextField( + value = uri.value, + onValueChange = { uri.value = it }, + label = { Text("URI") } + ) + TextField( + value = login.value, + onValueChange = { login.value = it }, + label = { Text("Login") } + ) + TextField( + value = password.value, + onValueChange = { password.value = it }, + label = { Text("Password") }, + visualTransformation = PasswordVisualTransformation() + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.SQLITE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + } + + Button( + onClick = { + when (storageType.value) { + StorageType.FILE -> { + // Логика сохранения в файл с использованием fileName и isDirectedGraph + } + StorageType.NEO4J -> { + // Логика сохранения в Neo4j + val repo = Neo4jRepository(uri.value, login.value, password.value) + val handler = Neo4jHandler(repo) + viewModel.graph.isDirected = isDirectedGraph.value + handler.saveGraphToNeo4j(viewModel.graph) + } + StorageType.SQLITE -> { + // Логика сохранения в SQLite + } + } + showDialog.value = false + } + ) { + Text("Save") + } + } + } + } Surface( modifier = Modifier.fillMaxSize(), contentColor = Color.LightGray, @@ -113,6 +238,16 @@ fun Canvas(viewModel: CanvasViewModel) { text = "Set colors", ) } + Button( + enabled = true, + onClick = { + scope.launch { + showDialog.value = true + } + } + ) { + Text(text = "Save Graph") + } } }, ) { @@ -141,3 +276,77 @@ fun Canvas(viewModel: CanvasViewModel) { } } + +enum class StorageType { + FILE, + NEO4J, + SQLITE +} + +@Composable +fun CustomRadioGroup( + options: List, + selectedOption: String, + onOptionSelected: (String) -> Unit +) { + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("NEO4J", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.NEO4J.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("FILE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.FILE.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("SQLITE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.SQLITE.name) } + ) { + Text("Select") + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index a3cf822..741e369 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -28,118 +28,10 @@ import model.databases.neo4j.Neo4jRepository import view.graph.GraphView import viewmodel.CanvasViewModel -enum class StorageType { - FILE, - NEO4J, - SQLITE -} - @Composable fun NavigationDrawer(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() - val showDialog = remember { mutableStateOf(false) } - val storageType = remember { mutableStateOf(StorageType.FILE) } - val fileName = remember { mutableStateOf("") } - val isDirectedGraph = remember { mutableStateOf(false) } - val uri = remember { mutableStateOf("") } - val login = remember { mutableStateOf("") } - val password = remember { mutableStateOf("") } - val interactionSource = remember { MutableInteractionSource() } - - AnimatedVisibility(visible = showDialog.value) { - Dialog( - onDismissRequest = { showDialog.value = false }, - properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) - ) { - Column( - modifier = Modifier.padding(16.dp) - ) { - Text("Choose where to save the graph:") - CustomRadioGroup( - selectedOption = storageType.value.toString(), - options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), - onOptionSelected = { storageType.value = StorageType.valueOf(it) } - ) - - when (storageType.value) { - StorageType.FILE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) // Пространство между чекбоксом и текстом - Text("Ориентированный ли граф") - } - StorageType.NEO4J -> { - TextField( - value = uri.value, - onValueChange = { uri.value = it }, - label = { Text("URI") } - ) - TextField( - value = login.value, - onValueChange = { login.value = it }, - label = { Text("Login") } - ) - TextField( - value = password.value, - onValueChange = { password.value = it }, - label = { Text("Password") }, - visualTransformation = PasswordVisualTransformation() - ) - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - Text("Ориентированный ли граф") - } - StorageType.SQLITE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - Text("Ориентированный ли граф") - } - } - - Button( - onClick = { - when (storageType.value) { - StorageType.FILE -> { - // Логика сохранения в файл с использованием fileName и isDirectedGraph - } - StorageType.NEO4J -> { - // Логика сохранения в Neo4j - val repo = Neo4jRepository(uri.value, login.value, password.value) - val handler = Neo4jHandler(repo) - viewModel.graph.isDirected = isDirectedGraph.value - handler.saveGraphToNeo4j(viewModel.graph) - } - StorageType.SQLITE -> { - // Логика сохранения в SQLite - } - } - showDialog.value = false - } - ) { - Text("Save") - } - } - } - } val showSubMenu = remember { mutableStateOf(false) @@ -216,16 +108,6 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { text = "Set colors", ) } - Button( - enabled = true, - onClick = { - scope.launch { - showDialog.value = true - } - } - ) { - Text(text = "Save Graph") - } } }, ) { @@ -248,72 +130,4 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } } -} - -@Composable -fun CustomRadioGroup( - options: List, - selectedOption: String, - onOptionSelected: (String) -> Unit -) { - Column { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("NEO4J", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.NEO4J.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("FILE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.FILE.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("SQLITE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.SQLITE.name) } - ) { - Text("Select") - } - } - } } \ No newline at end of file From 49b4512b3b8a2e1e181053e78f766b7c27d711e6 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 17:25:26 +0300 Subject: [PATCH 153/211] feat(ui): graph save neo4j implementation --- src/main/kotlin/view/CanvasView.kt | 74 ----------------------- src/main/kotlin/view/CustomRadioView.kt | 79 +++++++++++++++++++++++++ src/main/kotlin/view/StorageType.kt | 7 +++ 3 files changed, 86 insertions(+), 74 deletions(-) create mode 100644 src/main/kotlin/view/CustomRadioView.kt create mode 100644 src/main/kotlin/view/StorageType.kt diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 25a8c45..cad878c 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -275,78 +275,4 @@ fun Canvas(viewModel: CanvasViewModel) { } } -} - -enum class StorageType { - FILE, - NEO4J, - SQLITE -} - -@Composable -fun CustomRadioGroup( - options: List, - selectedOption: String, - onOptionSelected: (String) -> Unit -) { - Column { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("NEO4J", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.NEO4J.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("FILE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.FILE.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("SQLITE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.SQLITE.name) } - ) { - Text("Select") - } - } - } } \ No newline at end of file diff --git a/src/main/kotlin/view/CustomRadioView.kt b/src/main/kotlin/view/CustomRadioView.kt new file mode 100644 index 0000000..463ffbd --- /dev/null +++ b/src/main/kotlin/view/CustomRadioView.kt @@ -0,0 +1,79 @@ +package view + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun CustomRadioGroup( + options: List, + selectedOption: String, + onOptionSelected: (String) -> Unit +) { + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("NEO4J", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.NEO4J.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("FILE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.FILE.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("SQLITE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.SQLITE.name) } + ) { + Text("Select") + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/StorageType.kt b/src/main/kotlin/view/StorageType.kt new file mode 100644 index 0000000..cb8120d --- /dev/null +++ b/src/main/kotlin/view/StorageType.kt @@ -0,0 +1,7 @@ +package view + +enum class StorageType { + FILE, + NEO4J, + SQLITE +} \ No newline at end of file From 90492cd066f0f0a1d14ebb2c12b396efb081361a Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 16:06:23 +0300 Subject: [PATCH 154/211] feat(ui): save_graph page added --- src/main/kotlin/view/CanvasView.kt | 43 ++++- src/main/kotlin/view/NavigationDrawer.kt | 208 ++++++++++++++++++++++- 2 files changed, 241 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 6ae8b8b..45e43e9 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,6 +1,8 @@ package view import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -18,15 +20,19 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel -import viewmodel.LoadGraphMenuViewModel +import androidx.compose.material3.RadioButton @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + Surface( modifier = Modifier.fillMaxSize(), contentColor = Color.LightGray, @@ -79,11 +85,34 @@ fun Canvas(viewModel: CanvasViewModel) { AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu() } - Button(onClick = { viewModel.isOpenLoadGraph = true }) { - Text("Load graph") + Row { + Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { + viewModel.showVerticesLabels.value = it + }) + Text("Show vertices labels", fontSize = 20.sp, modifier = Modifier.padding(0.dp)) + } + Row { + Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { + viewModel.showEdgesLabels.value = it + }) + Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) + } + Button( + onClick = viewModel::resetGraphView, + enabled = true, + ) { + Text( + text = "Reset default settings", + ) + } + Button( + onClick = viewModel::setVerticesColor, + enabled = true, + ) { + Text( + text = "Set colors", + ) } - - } }, ) { @@ -110,7 +139,5 @@ fun Canvas(viewModel: CanvasViewModel) { GraphView(viewModel.graphViewModel) } } - if (viewModel.isOpenLoadGraph) { - LoadGraph(LoadGraphMenuViewModel(viewModel)) - } + } diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index fab6410..8b2b333 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -1,8 +1,9 @@ package view import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List @@ -13,17 +14,126 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel +enum class StorageType { + FILE, + NEO4J, + SQLITE +} + @Composable fun NavigationDrawer(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + val showDialog = remember { mutableStateOf(false) } + val storageType = remember { mutableStateOf(StorageType.FILE) } + val fileName = remember { mutableStateOf("") } + val isDirectedGraph = remember { mutableStateOf(false) } + val uri = remember { mutableStateOf("") } + val login = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + val interactionSource = remember { MutableInteractionSource() } + + AnimatedVisibility(visible = showDialog.value) { + Dialog( + onDismissRequest = { showDialog.value = false }, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text("Choose where to save the graph:") + CustomRadioGroup( + selectedOption = storageType.value.toString(), + options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), + onOptionSelected = { storageType.value = StorageType.valueOf(it) } + ) + + when (storageType.value) { + StorageType.FILE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) // Пространство между чекбоксом и текстом + Text("Ориентированный ли граф") + } + StorageType.NEO4J -> { + TextField( + value = uri.value, + onValueChange = { uri.value = it }, + label = { Text("URI") } + ) + TextField( + value = login.value, + onValueChange = { login.value = it }, + label = { Text("Login") } + ) + TextField( + value = password.value, + onValueChange = { password.value = it }, + label = { Text("Password") }, + visualTransformation = PasswordVisualTransformation() + ) + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + Text("Ориентированный ли граф") + } + StorageType.SQLITE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + Text("Ориентированный ли граф") + } + } + + Button( + onClick = { + when (storageType.value) { + StorageType.FILE -> { + // Логика сохранения в файл с использованием fileName и isDirectedGraph + } + StorageType.NEO4J -> { + // Логика сохранения в Neo4j + } + StorageType.SQLITE -> { + // Логика сохранения в SQLite + } + } + showDialog.value = false + } + ) { + Text("Save") + } + } + } + } val showSubMenu = remember { mutableStateOf(false) @@ -84,6 +194,32 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { }) Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) } + Button( + onClick = viewModel::resetGraphView, + enabled = true, + ) { + Text( + text = "Reset default settings", + ) + } + Button( + onClick = viewModel::setVerticesColor, + enabled = true, + ) { + Text( + text = "Set colors", + ) + } + Button( + enabled = true, + onClick = { + scope.launch { + showDialog.value = true + } + } + ) { + Text(text = "Save Graph") + } } }, ) { @@ -106,4 +242,72 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } } +} + +@Composable +fun CustomRadioGroup( + options: List, + selectedOption: String, + onOptionSelected: (String) -> Unit +) { + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("NEO4J", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.NEO4J.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("FILE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.FILE.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("SQLITE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.SQLITE.name) } + ) { + Text("Select") + } + } + } } \ No newline at end of file From 8680e2ed3a7f98620c4ee27364b70f584c146e29 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 16:51:51 +0300 Subject: [PATCH 155/211] feat(ui): graph save neo4j implementation --- src/main/kotlin/view/NavigationDrawer.kt | 6 ++++++ src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index 8b2b333..a3cf822 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -23,6 +23,8 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch +import model.databases.neo4j.Neo4jHandler +import model.databases.neo4j.Neo4jRepository import view.graph.GraphView import viewmodel.CanvasViewModel @@ -121,6 +123,10 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { } StorageType.NEO4J -> { // Логика сохранения в Neo4j + val repo = Neo4jRepository(uri.value, login.value, password.value) + val handler = Neo4jHandler(repo) + viewModel.graph.isDirected = isDirectedGraph.value + handler.saveGraphToNeo4j(viewModel.graph) } StorageType.SQLITE -> { // Логика сохранения в SQLite diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 3c6a8b9..85d094c 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -5,7 +5,7 @@ import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -class CanvasViewModel(graph: Graph, private val representationStrategy: RepresentationStrategy,) { +class CanvasViewModel(val graph: Graph, private val representationStrategy: RepresentationStrategy,) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) val graphViewModel = GraphViewModel(graph) From 8bab6534a14165be75bdb9ddd4d74fa996b8b606 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 17:23:48 +0300 Subject: [PATCH 156/211] feat(ui): graph save neo4j implementation --- src/main/kotlin/view/CanvasView.kt | 217 ++++++++++++++++++++++- src/main/kotlin/view/NavigationDrawer.kt | 186 ------------------- 2 files changed, 213 insertions(+), 190 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 45e43e9..25a8c45 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,11 +1,9 @@ package view import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material.Surface import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -27,12 +25,139 @@ import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel import androidx.compose.material3.RadioButton +import androidx.compose.ui.Alignment +import androidx.compose.ui.text.input.PasswordVisualTransformation +import model.databases.neo4j.Neo4jHandler +import model.databases.neo4j.Neo4jRepository @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + val showDialog = remember { mutableStateOf(false) } + val storageType = remember { mutableStateOf(StorageType.FILE) } + val fileName = remember { mutableStateOf("") } + val isDirectedGraph = remember { mutableStateOf(false) } + val isWeighted = remember { mutableStateOf(false) } + val uri = remember { mutableStateOf("") } + val login = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + val interactionSource = remember { MutableInteractionSource() } + AnimatedVisibility(visible = showDialog.value) { + Dialog( + onDismissRequest = { showDialog.value = false }, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text("Choose where to save the graph:") + CustomRadioGroup( + selectedOption = storageType.value.toString(), + options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), + onOptionSelected = { storageType.value = StorageType.valueOf(it) } + ) + + when (storageType.value) { + StorageType.FILE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.NEO4J -> { + TextField( + value = uri.value, + onValueChange = { uri.value = it }, + label = { Text("URI") } + ) + TextField( + value = login.value, + onValueChange = { login.value = it }, + label = { Text("Login") } + ) + TextField( + value = password.value, + onValueChange = { password.value = it }, + label = { Text("Password") }, + visualTransformation = PasswordVisualTransformation() + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.SQLITE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + } + + Button( + onClick = { + when (storageType.value) { + StorageType.FILE -> { + // Логика сохранения в файл с использованием fileName и isDirectedGraph + } + StorageType.NEO4J -> { + // Логика сохранения в Neo4j + val repo = Neo4jRepository(uri.value, login.value, password.value) + val handler = Neo4jHandler(repo) + viewModel.graph.isDirected = isDirectedGraph.value + handler.saveGraphToNeo4j(viewModel.graph) + } + StorageType.SQLITE -> { + // Логика сохранения в SQLite + } + } + showDialog.value = false + } + ) { + Text("Save") + } + } + } + } Surface( modifier = Modifier.fillMaxSize(), contentColor = Color.LightGray, @@ -113,6 +238,16 @@ fun Canvas(viewModel: CanvasViewModel) { text = "Set colors", ) } + Button( + enabled = true, + onClick = { + scope.launch { + showDialog.value = true + } + } + ) { + Text(text = "Save Graph") + } } }, ) { @@ -141,3 +276,77 @@ fun Canvas(viewModel: CanvasViewModel) { } } + +enum class StorageType { + FILE, + NEO4J, + SQLITE +} + +@Composable +fun CustomRadioGroup( + options: List, + selectedOption: String, + onOptionSelected: (String) -> Unit +) { + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("NEO4J", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.NEO4J.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("FILE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.FILE.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("SQLITE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.SQLITE.name) } + ) { + Text("Select") + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index a3cf822..741e369 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -28,118 +28,10 @@ import model.databases.neo4j.Neo4jRepository import view.graph.GraphView import viewmodel.CanvasViewModel -enum class StorageType { - FILE, - NEO4J, - SQLITE -} - @Composable fun NavigationDrawer(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() - val showDialog = remember { mutableStateOf(false) } - val storageType = remember { mutableStateOf(StorageType.FILE) } - val fileName = remember { mutableStateOf("") } - val isDirectedGraph = remember { mutableStateOf(false) } - val uri = remember { mutableStateOf("") } - val login = remember { mutableStateOf("") } - val password = remember { mutableStateOf("") } - val interactionSource = remember { MutableInteractionSource() } - - AnimatedVisibility(visible = showDialog.value) { - Dialog( - onDismissRequest = { showDialog.value = false }, - properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) - ) { - Column( - modifier = Modifier.padding(16.dp) - ) { - Text("Choose where to save the graph:") - CustomRadioGroup( - selectedOption = storageType.value.toString(), - options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), - onOptionSelected = { storageType.value = StorageType.valueOf(it) } - ) - - when (storageType.value) { - StorageType.FILE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) // Пространство между чекбоксом и текстом - Text("Ориентированный ли граф") - } - StorageType.NEO4J -> { - TextField( - value = uri.value, - onValueChange = { uri.value = it }, - label = { Text("URI") } - ) - TextField( - value = login.value, - onValueChange = { login.value = it }, - label = { Text("Login") } - ) - TextField( - value = password.value, - onValueChange = { password.value = it }, - label = { Text("Password") }, - visualTransformation = PasswordVisualTransformation() - ) - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - Text("Ориентированный ли граф") - } - StorageType.SQLITE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - Text("Ориентированный ли граф") - } - } - - Button( - onClick = { - when (storageType.value) { - StorageType.FILE -> { - // Логика сохранения в файл с использованием fileName и isDirectedGraph - } - StorageType.NEO4J -> { - // Логика сохранения в Neo4j - val repo = Neo4jRepository(uri.value, login.value, password.value) - val handler = Neo4jHandler(repo) - viewModel.graph.isDirected = isDirectedGraph.value - handler.saveGraphToNeo4j(viewModel.graph) - } - StorageType.SQLITE -> { - // Логика сохранения в SQLite - } - } - showDialog.value = false - } - ) { - Text("Save") - } - } - } - } val showSubMenu = remember { mutableStateOf(false) @@ -216,16 +108,6 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { text = "Set colors", ) } - Button( - enabled = true, - onClick = { - scope.launch { - showDialog.value = true - } - } - ) { - Text(text = "Save Graph") - } } }, ) { @@ -248,72 +130,4 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } } -} - -@Composable -fun CustomRadioGroup( - options: List, - selectedOption: String, - onOptionSelected: (String) -> Unit -) { - Column { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("NEO4J", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.NEO4J.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("FILE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.FILE.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("SQLITE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.SQLITE.name) } - ) { - Text("Select") - } - } - } } \ No newline at end of file From 40ce39affe20f08a8ff9ae71b2c7d2d36ca76871 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 17:25:26 +0300 Subject: [PATCH 157/211] feat(ui): graph save neo4j implementation --- src/main/kotlin/view/CanvasView.kt | 74 ----------------------- src/main/kotlin/view/CustomRadioView.kt | 79 +++++++++++++++++++++++++ src/main/kotlin/view/StorageType.kt | 7 +++ 3 files changed, 86 insertions(+), 74 deletions(-) create mode 100644 src/main/kotlin/view/CustomRadioView.kt create mode 100644 src/main/kotlin/view/StorageType.kt diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 25a8c45..cad878c 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -275,78 +275,4 @@ fun Canvas(viewModel: CanvasViewModel) { } } -} - -enum class StorageType { - FILE, - NEO4J, - SQLITE -} - -@Composable -fun CustomRadioGroup( - options: List, - selectedOption: String, - onOptionSelected: (String) -> Unit -) { - Column { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("NEO4J", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.NEO4J.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("FILE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.FILE.name) } - ) { - Text("Select") - } - } - Spacer(modifier = Modifier.height(8.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .background(Color.Magenta) - .padding(8.dp) - .weight(1f) - ) { - Text("SQLITE", color = Color.White) - } - Spacer(modifier = Modifier.width(8.dp)) - Button( - onClick = { onOptionSelected(StorageType.SQLITE.name) } - ) { - Text("Select") - } - } - } } \ No newline at end of file diff --git a/src/main/kotlin/view/CustomRadioView.kt b/src/main/kotlin/view/CustomRadioView.kt new file mode 100644 index 0000000..463ffbd --- /dev/null +++ b/src/main/kotlin/view/CustomRadioView.kt @@ -0,0 +1,79 @@ +package view + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun CustomRadioGroup( + options: List, + selectedOption: String, + onOptionSelected: (String) -> Unit +) { + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("NEO4J", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.NEO4J.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("FILE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.FILE.name) } + ) { + Text("Select") + } + } + Spacer(modifier = Modifier.height(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .background(Color.Magenta) + .padding(8.dp) + .weight(1f) + ) { + Text("SQLITE", color = Color.White) + } + Spacer(modifier = Modifier.width(8.dp)) + Button( + onClick = { onOptionSelected(StorageType.SQLITE.name) } + ) { + Text("Select") + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/view/StorageType.kt b/src/main/kotlin/view/StorageType.kt new file mode 100644 index 0000000..cb8120d --- /dev/null +++ b/src/main/kotlin/view/StorageType.kt @@ -0,0 +1,7 @@ +package view + +enum class StorageType { + FILE, + NEO4J, + SQLITE +} \ No newline at end of file From be4da8f88413c13b61e150bfdd22b001dc01600c Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 12:06:50 +0000 Subject: [PATCH 158/211] feat: add some files for graph load --- src/main/kotlin/view/CanvasView.kt | 174 +---------------------- src/main/kotlin/view/LoadGraphMenu.kt | 140 ------------------ src/main/kotlin/view/NavigationDrawer.kt | 10 +- 3 files changed, 8 insertions(+), 316 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index cad878c..695675a 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,9 +1,11 @@ package view import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.material.Surface import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -25,139 +27,12 @@ import kotlinx.coroutines.launch import view.graph.GraphView import viewmodel.CanvasViewModel import androidx.compose.material3.RadioButton -import androidx.compose.ui.Alignment -import androidx.compose.ui.text.input.PasswordVisualTransformation -import model.databases.neo4j.Neo4jHandler -import model.databases.neo4j.Neo4jRepository @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() - val showDialog = remember { mutableStateOf(false) } - val storageType = remember { mutableStateOf(StorageType.FILE) } - val fileName = remember { mutableStateOf("") } - val isDirectedGraph = remember { mutableStateOf(false) } - val isWeighted = remember { mutableStateOf(false) } - val uri = remember { mutableStateOf("") } - val login = remember { mutableStateOf("") } - val password = remember { mutableStateOf("") } - val interactionSource = remember { MutableInteractionSource() } - AnimatedVisibility(visible = showDialog.value) { - Dialog( - onDismissRequest = { showDialog.value = false }, - properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) - ) { - Column( - modifier = Modifier.padding(16.dp) - ) { - Text("Choose where to save the graph:") - CustomRadioGroup( - selectedOption = storageType.value.toString(), - options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), - onOptionSelected = { storageType.value = StorageType.valueOf(it) } - ) - - when (storageType.value) { - StorageType.FILE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - Text("Ориентированный ли граф") - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - - Text("Взвешанные ли рёбра") - Checkbox( - checked = isWeighted.value, - onCheckedChange = { isWeighted.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - } - StorageType.NEO4J -> { - TextField( - value = uri.value, - onValueChange = { uri.value = it }, - label = { Text("URI") } - ) - TextField( - value = login.value, - onValueChange = { login.value = it }, - label = { Text("Login") } - ) - TextField( - value = password.value, - onValueChange = { password.value = it }, - label = { Text("Password") }, - visualTransformation = PasswordVisualTransformation() - ) - Text("Ориентированный ли граф") - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - - Text("Взвешанные ли рёбра") - Checkbox( - checked = isWeighted.value, - onCheckedChange = { isWeighted.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - } - StorageType.SQLITE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - Text("Ориентированный ли граф") - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - - Text("Взвешанные ли рёбра") - Checkbox( - checked = isWeighted.value, - onCheckedChange = { isWeighted.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - } - } - - Button( - onClick = { - when (storageType.value) { - StorageType.FILE -> { - // Логика сохранения в файл с использованием fileName и isDirectedGraph - } - StorageType.NEO4J -> { - // Логика сохранения в Neo4j - val repo = Neo4jRepository(uri.value, login.value, password.value) - val handler = Neo4jHandler(repo) - viewModel.graph.isDirected = isDirectedGraph.value - handler.saveGraphToNeo4j(viewModel.graph) - } - StorageType.SQLITE -> { - // Логика сохранения в SQLite - } - } - showDialog.value = false - } - ) { - Text("Save") - } - } - } - } Surface( modifier = Modifier.fillMaxSize(), contentColor = Color.LightGray, @@ -210,44 +85,7 @@ fun Canvas(viewModel: CanvasViewModel) { AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu() } - Row { - Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { - viewModel.showVerticesLabels.value = it - }) - Text("Show vertices labels", fontSize = 20.sp, modifier = Modifier.padding(0.dp)) - } - Row { - Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { - viewModel.showEdgesLabels.value = it - }) - Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) - } - Button( - onClick = viewModel::resetGraphView, - enabled = true, - ) { - Text( - text = "Reset default settings", - ) - } - Button( - onClick = viewModel::setVerticesColor, - enabled = true, - ) { - Text( - text = "Set colors", - ) - } - Button( - enabled = true, - onClick = { - scope.launch { - showDialog.value = true - } - } - ) { - Text(text = "Save Graph") - } + } }, ) { @@ -275,4 +113,4 @@ fun Canvas(viewModel: CanvasViewModel) { } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 37c3e5d..8d8a2bb 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -1,142 +1,2 @@ package view -import androidx.compose.foundation.layout.* -import androidx.compose.material.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.DialogWindow -import androidx.compose.ui.window.WindowPosition -import androidx.compose.ui.window.rememberDialogState -import kotlinx.coroutines.launch -import viewmodel.LoadGraphMenuViewModel - -@Composable -fun LoadGraph(viewModel: LoadGraphMenuViewModel) { - val coroutineScope = rememberCoroutineScope() - - - DialogWindow( - onCloseRequest = { viewModel.canvasViewModel.isOpenLoadGraph = false}, - state = rememberDialogState(position = WindowPosition(Alignment.Center), size = DpSize(500.dp, 350.dp)), - title = "Load New Graph", - resizable = false - ) { - Column( - Modifier - .fillMaxSize() - .padding(4.dp) - ) { - val modifierRow = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) - val verticalRow = Alignment.CenterVertically - - Row(modifierRow, verticalAlignment = verticalRow) { - Text( - "Graph name:", - modifier = Modifier.weight(0.5f), - textAlign = TextAlign.Center, - - ) - OutlinedTextField( - modifier = Modifier.weight(1f), - value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue }, - label = { Text("Name") }, - singleLine = true, - colors = TextFieldDefaults.textFieldColors( - ), - ) - } - Row(modifierRow, verticalAlignment = verticalRow) { -// ComboBox( -// items = VertexIDType.entries.toTypedArray(), -// modifier = Modifier.weight(1f), -// onItemClick = { item: VertexIDType -> viewModel.selectedVertexTypeID.value = item }, -// textAlign = TextAlign.Center -// ) - } - Row(modifierRow, verticalAlignment = verticalRow) { - Button( - //selected = viewModel.isGraphWeighted.value, - onClick = { viewModel.isGraphWeighted.value = !viewModel.isGraphWeighted.value }, - - //text = "Weighted graph", - //verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.weight(1f), - //reversed = true - ){ - Text("Weight") - } - Button( - //selected = viewModel.isGraphDirected.value, - onClick = { viewModel.isGraphDirected.value = !viewModel.isGraphDirected.value }, - - //verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.weight(1f), - ){Text("Directed graph")} - } - Row(modifierRow, verticalAlignment = verticalRow) { -// Text( -// "Vertices ID type:", -// modifier = Modifier.weight(0.5f), -// textAlign = TextAlign.Center, -// style = JetTheme.typography.toolbar -// ) -// ComboBox( -// items = GraphSavingType.entries.toTypedArray(), -// modifier = Modifier.weight(1f), -// onItemClick = { item: GraphSavingType -> viewModel.selectedSaveType.value = item }, -// textAlign = TextAlign.Center -// ) - } - Row(modifierRow, verticalAlignment = verticalRow) { - Spacer(modifier = Modifier.weight(1f)) - Button( - colors = ButtonDefaults.buttonColors( -// backgroundColor = JetTheme.colors.tertiaryBackground, -// contentColor = JetTheme.colors.secondaryText, -// disabledContentColor = JetTheme.colors.secondaryText, -// disabledBackgroundColor = JetTheme.colors.tertiaryBackground - ), - onClick = { viewModel.canvasViewModel.isOpenLoadGraph = false } - ) { - Text("Cancel") - } - Spacer(modifier = Modifier.weight(0.01f)) - Button( - colors = ButtonDefaults.buttonColors( -// backgroundColor = JetTheme.colors.tertiaryBackground, -// contentColor = JetTheme.colors.secondaryText, -// disabledContentColor = JetTheme.colors.secondaryText, -// disabledBackgroundColor = JetTheme.colors.tertiaryBackground - ), - onClick = { - if (viewModel.graphName.value.trim() == "") { - println("Invalid value") - } else { - viewModel.canvasViewModel.isOpenLoadGraph = false - coroutineScope.launch { -// val graph = viewModel.canvasViewModel.createGraph( -// viewModel.graphName.value, -//// viewModel.selectedVertexTypeID.value, -// viewModel.isGraphDirected.value, -// viewModel.isGraphWeighted.value -// ) -// viewModel.homePageViewModel.settings.saveGraph( -// graph, -// viewModel.selectedVertexTypeID.value, -// viewModel.selectedSaveType.value -// ) - } - } - } - ) { - Text("Create") - } - } - } - } -} diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index 741e369..2da807f 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -1,9 +1,8 @@ package view import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.background -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List @@ -14,14 +13,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository From eb485d496d219ff60a76eec3e81f1e98ec33f098 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 13:07:06 +0000 Subject: [PATCH 159/211] feat: add load dialog window --- src/main/kotlin/view/CanvasView.kt | 152 +++++++++++++++++++++-- src/main/kotlin/view/LoadGraphMenu.kt | 128 +++++++++++++++++++ src/main/kotlin/view/NavigationDrawer.kt | 26 ++-- 3 files changed, 281 insertions(+), 25 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 695675a..a71d0c3 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -2,10 +2,7 @@ package view import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material.Surface import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -19,20 +16,145 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch +import model.databases.neo4j.Neo4jHandler +import model.databases.neo4j.Neo4jRepository import view.graph.GraphView import viewmodel.CanvasViewModel -import androidx.compose.material3.RadioButton +import viewmodel.LoadGraphMenuViewModel @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + val showDialog = remember { mutableStateOf(false) } + val storageType = remember { mutableStateOf(StorageType.FILE) } + val fileName = remember { mutableStateOf("") } + val isDirectedGraph = remember { mutableStateOf(false) } + val isWeighted = remember { mutableStateOf(false) } + val uri = remember { mutableStateOf("") } + val login = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + val interactionSource = remember { MutableInteractionSource() } + AnimatedVisibility(visible = showDialog.value) { + Dialog( + onDismissRequest = { showDialog.value = false }, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text("Choose where to save the graph:") + CustomRadioGroup( + selectedOption = storageType.value.toString(), + options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), + onOptionSelected = { storageType.value = StorageType.valueOf(it) } + ) + + when (storageType.value) { + StorageType.FILE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.NEO4J -> { + TextField( + value = uri.value, + onValueChange = { uri.value = it }, + label = { Text("URI") } + ) + TextField( + value = login.value, + onValueChange = { login.value = it }, + label = { Text("Login") } + ) + TextField( + value = password.value, + onValueChange = { password.value = it }, + label = { Text("Password") }, + visualTransformation = PasswordVisualTransformation() + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.SQLITE -> { + TextField( + value = fileName.value, + onValueChange = { fileName.value = it }, + label = { Text("File Name") } + ) + Text("Ориентированный ли граф") + Checkbox( + checked = isDirectedGraph.value, + onCheckedChange = { isDirectedGraph.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox( + checked = isWeighted.value, + onCheckedChange = { isWeighted.value = it }, + ) + Spacer(modifier = Modifier.width(8.dp)) + } + } + + Button( + onClick = { + when (storageType.value) { + StorageType.FILE -> { + // Логика сохранения в файл с использованием fileName и isDirectedGraph + } + StorageType.NEO4J -> { + // Логика сохранения в Neo4j + val repo = Neo4jRepository(uri.value, login.value, password.value) + val handler = Neo4jHandler(repo) + viewModel.graph.isDirected = isDirectedGraph.value + handler.saveGraphToNeo4j(viewModel.graph) + } + StorageType.SQLITE -> { + // Логика сохранения в SQLite + } + } + showDialog.value = false + } + ) { + Text("Save") + } + } + } + } Surface( modifier = Modifier.fillMaxSize(), contentColor = Color.LightGray, @@ -85,6 +207,20 @@ fun Canvas(viewModel: CanvasViewModel) { AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu() } + Button(onClick = { viewModel.isOpenLoadGraph = true }) { + Text("Load graph") + } + Button( + enabled = true, + onClick = { + scope.launch { + showDialog.value = true + } + } + ) { + Text(text = "Save Graph") + } + } }, @@ -112,5 +248,7 @@ fun Canvas(viewModel: CanvasViewModel) { GraphView(viewModel.graphViewModel) } } - + if (viewModel.isOpenLoadGraph) { + LoadGraph(LoadGraphMenuViewModel(viewModel)) + } } diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 8d8a2bb..53db480 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -1,2 +1,130 @@ package view +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.DialogWindow +import androidx.compose.ui.window.WindowPosition +import androidx.compose.ui.window.rememberDialogState +import kotlinx.coroutines.launch +import viewmodel.LoadGraphMenuViewModel + +@Composable +fun LoadGraph(viewModel: LoadGraphMenuViewModel) { + val coroutineScope = rememberCoroutineScope() + var isWeighted by remember { mutableStateOf(false) } + var isDirected by remember { mutableStateOf(false) } + + DialogWindow( + onCloseRequest = { viewModel.canvasViewModel.isOpenLoadGraph = false}, + state = rememberDialogState(position = WindowPosition(Alignment.Center), size = DpSize(500.dp, 350.dp)), + title = "Load New Graph", + resizable = false + ) { + Column( + Modifier + .fillMaxSize() + .padding(4.dp) + ) { + val modifierRow = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) + val verticalRow = Alignment.CenterVertically + + Row(modifierRow, verticalAlignment = verticalRow) { + Text( + "Path to Database:", + modifier = Modifier.weight(0.5f), + textAlign = TextAlign.Center, + + ) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.graphName.value, + onValueChange = { newValue -> viewModel.graphName.value = newValue }, + label = { Text("Path") }, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + ), + ) + } + Row(modifierRow, verticalAlignment = verticalRow) { +// ComboBox( +// items = VertexIDType.entries.toTypedArray(), +// modifier = Modifier.weight(1f), +// onItemClick = { item: VertexIDType -> viewModel.selectedVertexTypeID.value = item }, +// textAlign = TextAlign.Center +// ) + } + Row(modifierRow, verticalAlignment = verticalRow) { + Checkbox( + checked = isWeighted, + onCheckedChange = { isWeighted = it} + ) + Text("Weighted") + Checkbox( + checked = isDirected, + onCheckedChange = { isDirected = it} + ) + Text("Directed") +// Button( +// //selected = viewModel.isGraphDirected.value, +// onClick = { viewModel.isGraphDirected.value = !viewModel.isGraphDirected.value }, +// +// //verticalAlignment = Alignment.CenterVertically, +// modifier = Modifier.weight(1f), +// ){Text("Directed graph")} + } + Row(modifierRow, verticalAlignment = verticalRow) { + Spacer(modifier = Modifier.weight(1f)) + Button( + colors = ButtonDefaults.buttonColors( +// backgroundColor = JetTheme.colors.tertiaryBackground, +// contentColor = JetTheme.colors.secondaryText, +// disabledContentColor = JetTheme.colors.secondaryText, +// disabledBackgroundColor = JetTheme.colors.tertiaryBackground + ), + onClick = { viewModel.canvasViewModel.isOpenLoadGraph = false } + ) { + Text("Cancel") + } + Spacer(modifier = Modifier.weight(0.01f)) + Button( + colors = ButtonDefaults.buttonColors( +// backgroundColor = JetTheme.colors.tertiaryBackground, +// contentColor = JetTheme.colors.secondaryText, +// disabledContentColor = JetTheme.colors.secondaryText, +// disabledBackgroundColor = JetTheme.colors.tertiaryBackground + ), + onClick = { + if (viewModel.graphName.value.trim() == "") { + println("Invalid value") + } else { + viewModel.canvasViewModel.isOpenLoadGraph = false + coroutineScope.launch { +// val graph = viewModel.canvasViewModel.createGraph( +// viewModel.graphName.value, +//// viewModel.selectedVertexTypeID.value, +// viewModel.isGraphDirected.value, +// viewModel.isGraphWeighted.value +// ) +// viewModel.homePageViewModel.settings.saveGraph( +// graph, +// viewModel.selectedVertexTypeID.value, +// viewModel.selectedSaveType.value +// ) + } + } + } + ) { + Text("Load") + } + } + } + } +} diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index 2da807f..44b89f4 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -1,8 +1,9 @@ package view import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List @@ -13,9 +14,14 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository @@ -86,22 +92,6 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { }) Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) } - Button( - onClick = viewModel::resetGraphView, - enabled = true, - ) { - Text( - text = "Reset default settings", - ) - } - Button( - onClick = viewModel::setVerticesColor, - enabled = true, - ) { - Text( - text = "Set colors", - ) - } } }, ) { From 5af9b46bfce87daf798b89ec1dbbb10f11ab25f5 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Wed, 29 May 2024 14:55:34 +0000 Subject: [PATCH 160/211] fix(ui): remove dublicate button --- src/main/kotlin/view/CanvasView.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index ac8e686..4161832 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -229,16 +229,6 @@ fun Canvas(viewModel: CanvasViewModel) { ) { Text(text = "Save Graph") } - Button( - enabled = true, - onClick = { - scope.launch { - showDialog.value = true - } - } - ) { - Text(text = "Save Graph") - } } }, From 5c61c41249cbfcc6ef42d631996802a3d4410f49 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 17:58:36 +0300 Subject: [PATCH 161/211] feat(ui): graph save neo4j implementation --- src/main/kotlin/view/CanvasView.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index cad878c..0ba7103 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -143,8 +143,10 @@ fun Canvas(viewModel: CanvasViewModel) { // Логика сохранения в Neo4j val repo = Neo4jRepository(uri.value, login.value, password.value) val handler = Neo4jHandler(repo) + val wasGraphDirected = viewModel.graph.isDirected viewModel.graph.isDirected = isDirectedGraph.value handler.saveGraphToNeo4j(viewModel.graph) + viewModel.graph.isDirected = wasGraphDirected } StorageType.SQLITE -> { // Логика сохранения в SQLite From 2b22d1e10ba08043547aaea863a01aaf83df7fd9 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 18:21:25 +0300 Subject: [PATCH 162/211] feat(visual): algorithm visualization added --- src/main/kotlin/Main.kt | 3 --- src/main/kotlin/view/AlgorithmSubMenu.kt | 10 ++++++++-- src/main/kotlin/view/CanvasView.kt | 2 +- src/main/kotlin/view/NavigationDrawer.kt | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index ebbc76e..462125d 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -344,9 +344,6 @@ val windowSizeStart = Pair(1480,1020) fun App() { MaterialTheme { val canvasGraph = CanvasViewModel(graph, ForceAtlas2Layout()) - val graphViewModel = canvasGraph.graphViewModel - val painter = GraphPainter(graph, graphViewModel) - painter.paint() MaterialTheme { Canvas(canvasGraph) } diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index 028c774..fa607c2 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -7,9 +7,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import controller.GraphPainter +import viewmodel.CanvasViewModel @Composable -fun AlgorithmSubMenu() { +fun AlgorithmSubMenu(viewModel: CanvasViewModel) { Column(Modifier.padding(start = 16.dp, end = 0.dp, top = 15.dp)) { Button( onClick = { /*TODO*/ }, @@ -20,7 +22,11 @@ fun AlgorithmSubMenu() { ) } Button( - onClick = { /*TODO*/ }, + onClick = { + val graph = viewModel.graph + val painter = GraphPainter(graph, viewModel.graphViewModel) + painter.paint() + }, enabled = true, ) { Text( diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 21431ac..8c92b65 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -216,7 +216,7 @@ fun Canvas(viewModel: CanvasViewModel) { onClick = { showSubMenu.value = !showSubMenu.value } ) AnimatedVisibility(visible = showSubMenu.value) { - AlgorithmSubMenu() + AlgorithmSubMenu(viewModel) } Button(onClick = { viewModel.isOpenLoadGraph = true }) { Text("Load graph") diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index 44b89f4..1553ca9 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -78,7 +78,7 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { onClick = { showSubMenu.value = !showSubMenu.value } ) AnimatedVisibility(visible = showSubMenu.value) { - AlgorithmSubMenu() + AlgorithmSubMenu(viewModel) } Row { Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { From eb90903c2931326168ec9516712d3545029295a8 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 18:25:35 +0300 Subject: [PATCH 163/211] feat(visual): algorithm visualization for community added --- src/main/kotlin/Main.kt | 6 ------ .../{GraphPainter.kt => GraphPainterByCommunity.kt} | 2 +- src/main/kotlin/view/AlgorithmSubMenu.kt | 11 ++++++++--- 3 files changed, 9 insertions(+), 10 deletions(-) rename src/main/kotlin/controller/{GraphPainter.kt => GraphPainterByCommunity.kt} (90%) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 462125d..4edf08e 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -9,17 +9,11 @@ import androidx.compose.ui.window.application import androidx.compose.ui.window.rememberWindowState -import controller.GraphPainter import model.graph.Graph import model.layout.ForceAtlas2Layout -import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 import view.Canvas -import view.MainScreen - -import view.NavigationDrawer import viewmodel.CanvasViewModel -import viewmodel.layouts.CircularLayout import java.awt.Dimension val graph = Graph().apply { diff --git a/src/main/kotlin/controller/GraphPainter.kt b/src/main/kotlin/controller/GraphPainterByCommunity.kt similarity index 90% rename from src/main/kotlin/controller/GraphPainter.kt rename to src/main/kotlin/controller/GraphPainterByCommunity.kt index fb534c5..a2f2645 100644 --- a/src/main/kotlin/controller/GraphPainter.kt +++ b/src/main/kotlin/controller/GraphPainterByCommunity.kt @@ -6,7 +6,7 @@ import model.community.Louvain import viewmodel.graph.GraphViewModel import kotlin.random.Random -class GraphPainter(private val graph: Graph, private val graphViewModel: GraphViewModel) { +class GraphPainterByCommunity(private val graph: Graph, private val graphViewModel: GraphViewModel) { private val finder = Louvain(graph) private val communities = finder.findCommunities() diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index fa607c2..c83033c 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -7,7 +7,8 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import controller.GraphPainter +import controller.GraphPainterByCommunity +import controller.GraphPainterByKosaraju import viewmodel.CanvasViewModel @Composable @@ -24,7 +25,7 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { Button( onClick = { val graph = viewModel.graph - val painter = GraphPainter(graph, viewModel.graphViewModel) + val painter = GraphPainterByCommunity(graph, viewModel.graphViewModel) painter.paint() }, enabled = true, @@ -34,7 +35,11 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { ) } Button( - onClick = { /*TODO*/ }, + onClick = { + val graph = viewModel.graph + val painter = GraphPainterByKosaraju(graph, viewModel.graphViewModel) + painter.paint() + }, enabled = true, ) { Text( From 840c90fa357eb5cf750d0041e6eb6edc44b9f5c2 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 18:25:55 +0300 Subject: [PATCH 164/211] feat(visual): algorithm visualization for Kosaraju added --- .../controller/GraphPainterByKosaraju.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/kotlin/controller/GraphPainterByKosaraju.kt diff --git a/src/main/kotlin/controller/GraphPainterByKosaraju.kt b/src/main/kotlin/controller/GraphPainterByKosaraju.kt new file mode 100644 index 0000000..5eff570 --- /dev/null +++ b/src/main/kotlin/controller/GraphPainterByKosaraju.kt @@ -0,0 +1,31 @@ +package controller + +import androidx.compose.ui.graphics.Color +import model.algorithms.Kosaraju +import model.graph.Graph +import model.community.Louvain +import viewmodel.graph.GraphViewModel +import kotlin.random.Random + +class GraphPainterByKosaraju(private val graph: Graph, private val graphViewModel: GraphViewModel) { + private val finder = Kosaraju(graph) + private val components = finder.findStronglyConnectedComponents() + + fun paint() { + for ((i, component) in components.withIndex()) { + val communityColor = generateRandomColor(i * 123) + for (vertexID in component) { + val currVertex = graph.vertices[vertexID] + graphViewModel.verticesView[currVertex]!!.color=communityColor + } + } + } + + private fun generateRandomColor(base: Int): Color { + val mRandom = Random(base) + val red: Int = (base + mRandom.nextInt(256)) / 2 + val green: Int = (base + mRandom.nextInt(256)) / 2 + val blue: Int = (base + mRandom.nextInt(256)) / 2 + return Color(red, green, blue) + } +} \ No newline at end of file From a65ef3566637992e3fda98adb2a319cbee9a6293 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 18:39:16 +0300 Subject: [PATCH 165/211] feat(visual): algorithm visualization for Djikstra added --- .../controller/GraphPainterByCommunity.kt | 10 --------- .../controller/GraphPainterByDjikstra.kt | 22 +++++++++++++++++++ .../controller/GraphPainterByKosaraju.kt | 11 ---------- src/main/kotlin/controller/RandomColor.kt | 12 ++++++++++ 4 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 src/main/kotlin/controller/GraphPainterByDjikstra.kt create mode 100644 src/main/kotlin/controller/RandomColor.kt diff --git a/src/main/kotlin/controller/GraphPainterByCommunity.kt b/src/main/kotlin/controller/GraphPainterByCommunity.kt index a2f2645..99d4f69 100644 --- a/src/main/kotlin/controller/GraphPainterByCommunity.kt +++ b/src/main/kotlin/controller/GraphPainterByCommunity.kt @@ -1,10 +1,8 @@ package controller -import androidx.compose.ui.graphics.Color import model.graph.Graph import model.community.Louvain import viewmodel.graph.GraphViewModel -import kotlin.random.Random class GraphPainterByCommunity(private val graph: Graph, private val graphViewModel: GraphViewModel) { private val finder = Louvain(graph) @@ -19,12 +17,4 @@ class GraphPainterByCommunity(private val graph: Graph, private val graphViewMod } } } - - private fun generateRandomColor(base: Int): Color { - val mRandom = Random(base) - val red: Int = (base + mRandom.nextInt(256)) / 2 - val green: Int = (base + mRandom.nextInt(256)) / 2 - val blue: Int = (base + mRandom.nextInt(256)) / 2 - return Color(red, green, blue) - } } \ No newline at end of file diff --git a/src/main/kotlin/controller/GraphPainterByDjikstra.kt b/src/main/kotlin/controller/GraphPainterByDjikstra.kt new file mode 100644 index 0000000..721e126 --- /dev/null +++ b/src/main/kotlin/controller/GraphPainterByDjikstra.kt @@ -0,0 +1,22 @@ +package controller + +import model.algorithms.Djikstra +import model.graph.Graph +import viewmodel.graph.GraphViewModel + +class GraphPainterByDjikstra(private val graph: Graph, + private val graphViewModel: GraphViewModel, + private val startIdx: Int, + private val endIdx: Int) { + private val pathFinder = Djikstra(graph,startIdx) + private val path = pathFinder.findShortestPaths() + val currPath = pathFinder.reconstructPath(endIdx) + + fun paint() { + val vertexColor = generateRandomColor(startIdx * 123) + for (vertexID in currPath) { + val currVertex = graph.vertices[vertexID] + graphViewModel.verticesView[currVertex]!!.color=vertexColor + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/controller/GraphPainterByKosaraju.kt b/src/main/kotlin/controller/GraphPainterByKosaraju.kt index 5eff570..f63889e 100644 --- a/src/main/kotlin/controller/GraphPainterByKosaraju.kt +++ b/src/main/kotlin/controller/GraphPainterByKosaraju.kt @@ -1,11 +1,8 @@ package controller -import androidx.compose.ui.graphics.Color import model.algorithms.Kosaraju import model.graph.Graph -import model.community.Louvain import viewmodel.graph.GraphViewModel -import kotlin.random.Random class GraphPainterByKosaraju(private val graph: Graph, private val graphViewModel: GraphViewModel) { private val finder = Kosaraju(graph) @@ -20,12 +17,4 @@ class GraphPainterByKosaraju(private val graph: Graph, private val graphViewMode } } } - - private fun generateRandomColor(base: Int): Color { - val mRandom = Random(base) - val red: Int = (base + mRandom.nextInt(256)) / 2 - val green: Int = (base + mRandom.nextInt(256)) / 2 - val blue: Int = (base + mRandom.nextInt(256)) / 2 - return Color(red, green, blue) - } } \ No newline at end of file diff --git a/src/main/kotlin/controller/RandomColor.kt b/src/main/kotlin/controller/RandomColor.kt new file mode 100644 index 0000000..05b5051 --- /dev/null +++ b/src/main/kotlin/controller/RandomColor.kt @@ -0,0 +1,12 @@ +package controller + +import androidx.compose.ui.graphics.Color +import kotlin.random.Random + +fun generateRandomColor(base: Int): Color { + val mRandom = Random(base) + val red: Int = (base + mRandom.nextInt(256)) / 2 + val green: Int = (base + mRandom.nextInt(256)) / 2 + val blue: Int = (base + mRandom.nextInt(256)) / 2 + return Color(red, green, blue) +} \ No newline at end of file From e4040f210db7b500ed53f5018cfd850414993117 Mon Sep 17 00:00:00 2001 From: dronshock Date: Wed, 29 May 2024 18:48:37 +0300 Subject: [PATCH 166/211] feat(test): add tests for Kraskals algorithm --- .../kotlin/algorithms/KruskalsAlgorithm.kt | 14 ++--- src/test/kotlin/graphs/KruskalTest.kt | 57 +++++++++++++++++++ 2 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 src/test/kotlin/graphs/KruskalTest.kt diff --git a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt index 6e809f7..918f8a3 100644 --- a/src/main/kotlin/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/algorithms/KruskalsAlgorithm.kt @@ -4,22 +4,22 @@ import graph.model.Edge import graph.model.Graph class KruskalsMST { - private fun kruskals(graph: Graph) { + var resultsId: List = emptyList() + internal fun kruskals(graph: Graph) { var j = 0 var noOfEdges = 0 val V = graph.getVertices().size - + if (V == 1 || V == 0) + return + val results = arrayOfNulls(V-1) val subsets = arrayOfNulls(V) - - val results = arrayOfNulls(V) - for (i in 0 ..< V) { subsets[i] = Subset(i, 0) } val edgesList = graph.edges.values val sortedEdges = edgesList.sortedWith(compareBy{ it.weight}) - while (noOfEdges < V - 1) { + while (noOfEdges < V - 1 ) { val nextEdge = sortedEdges[j] val x = findRoot(subsets, nextEdge.vertices.first) @@ -30,9 +30,9 @@ class KruskalsMST { union(subsets, x, y) noOfEdges++ } - j++ } + resultsId = results.map { it!!.id }.sorted() } private fun union( diff --git a/src/test/kotlin/graphs/KruskalTest.kt b/src/test/kotlin/graphs/KruskalTest.kt new file mode 100644 index 0000000..47337ab --- /dev/null +++ b/src/test/kotlin/graphs/KruskalTest.kt @@ -0,0 +1,57 @@ +package graphs + +import algorithms.KruskalsMST +import graph.model.Graph +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +// Assuming the Edge class and kruskal function are defined here + +class KruskalTest { + + @Test + fun testSimpleGraph() { + val graph = Graph() + for (i in 0..8) { + graph.addVertex(i, "") + } + graph.addEdge(0, 1, 4L, 0) + graph.addEdge(0, 7, 8L, 1) + graph.addEdge(1, 2, 8L, 2) + graph.addEdge(1, 7, 11L, 3) + graph.addEdge(2, 3, 7L, 4) + graph.addEdge(2, 8, 2L, 5) + graph.addEdge(2, 5, 4L, 6) + graph.addEdge(3, 4, 9L, 7) + graph.addEdge(3, 5, 14L, 8) + graph.addEdge(4, 5, 10L, 9) + graph.addEdge(5, 6, 2L, 10) + graph.addEdge(6, 7, 1L, 11) + graph.addEdge(6, 8, 6L, 12) + graph.addEdge(7, 8, 7L, 13) + val expected = setOf(0, 1, 4, 5, 6, 7, 10, 11).sorted() + val algo = KruskalsMST() + algo.kruskals(graph) + assertEquals(expected, algo.resultsId) + } + @Test + fun testSingleVertexGraph() { + // Test with a single vertex to ensure the algorithm handles this case correctly + val graph = Graph() + graph.addVertex(0,"") + val expected = emptyList() + val algo = KruskalsMST() + algo.kruskals(graph) + assertEquals(expected, algo.resultsId) + } + + @Test + fun testEmptyGraph() { + // Test with an empty graph to ensure the algorithm handles this case correctly + val graph = Graph() + val expected = emptyList() + val algo = KruskalsMST() + algo.kruskals(graph) + assertEquals(expected, algo.resultsId) + } +} From 2fab66a3e6ab30f2a2236bb50aefcabba0f0224f Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 19:03:01 +0300 Subject: [PATCH 167/211] feat(visual): algorithm visualization for Djikstra added --- src/main/kotlin/view/AlgorithmSubMenu.kt | 89 +++++++++++++++++++++--- 1 file changed, 81 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index c83033c..401839d 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -1,18 +1,25 @@ package view import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Button -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.material.AlertDialog +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import controller.GraphPainterByCommunity +import controller.GraphPainterByDjikstra import controller.GraphPainterByKosaraju import viewmodel.CanvasViewModel @Composable fun AlgorithmSubMenu(viewModel: CanvasViewModel) { + val showDialog = remember { mutableStateOf(false) } + var startIdx by remember { mutableStateOf(0) } + var endIdx by remember { mutableStateOf(0) } + Column(Modifier.padding(start = 16.dp, end = 0.dp, top = 15.dp)) { Button( onClick = { /*TODO*/ }, @@ -45,6 +52,17 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { Text( text = "Выделение компонент сильной связности", ) + + ShortestPathDialog(showDialog) { enteredStartIdx, enteredEndIdx -> + startIdx = enteredStartIdx + endIdx = enteredEndIdx + showDialog.value = false + + viewModel.graph.let { graph -> + val painter = GraphPainterByDjikstra(graph, viewModel.graphViewModel, startIdx, endIdx) + painter.paint() + } + } } Button( onClick = { /*TODO*/ }, @@ -62,23 +80,78 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { text = "Построение минимального остовного дерева", ) } + Button( + onClick = { + showDialog.value = true + }, + enabled = true, + modifier = Modifier.padding(top = 3.dp) + ) { + Text(text = "Кратчайший путь алгоритмом Дейкстры") + } Button( onClick = { /*TODO*/ }, enabled = true, modifier = Modifier.padding(top = 3.dp), ) { Text( - text = "Кратчайший путь алгоритмом Дейкстры", + text = "Кратчайший путь алгоритмом Форда-Беллмана", ) } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ShortestPathDialog( + showDialog: MutableState, + onPathSelected: (Int, Int) -> Unit +) { + var startIdx by remember { mutableStateOf(0) } + var endIdx by remember { mutableStateOf(0) } + + if (showDialog.value) { + AlertDialog( + onDismissRequest = { showDialog.value = false }, + buttons = { + Button(onClick = { + onPathSelected(startIdx, endIdx) + showDialog.value = false + }) { + Text("Найти кратчайший путь") + } + }, + text = { + Column { + TextField( + value = startIdx.toString(), + onValueChange = { startIdx = it.toIntOrNull() ?: 0 }, + label = { Text("Введите точку отправления") } + ) + Spacer(modifier = Modifier.height(8.dp)) + TextField( + value = endIdx.toString(), + onValueChange = { endIdx = it.toIntOrNull() ?: 0 }, + label = { Text("Введите точку назначения") } + ) + } + } + ) + } +} + +/* Button( - onClick = { /*TODO*/ }, + onClick = { + val graph = viewModel.graph + val painter = GraphPainterByDjikstra(graph, viewModel.graphViewModel, startIdx) + painter.paint() + }, enabled = true, modifier = Modifier.padding(top = 3.dp), ) { Text( - text = "Кратчайший путь алгоритмом Форда-Беллмана", + text = "Кратчайший путь алгоритмом Дейкстры", ) } - } -} \ No newline at end of file + */ \ No newline at end of file From b84ad0241fca8ce8ad4efd8ab2519f53c764cfeb Mon Sep 17 00:00:00 2001 From: dronshock Date: Wed, 29 May 2024 19:03:48 +0300 Subject: [PATCH 168/211] fix(test): correct imports --- src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt | 2 +- src/test/kotlin/graphs/algorithms/DjikstraTest.kt | 2 +- src/test/kotlin/graphs/algorithms/FordBellmanTest.kt | 2 +- src/test/kotlin/graphs/algorithms/KosajaruTest.kt | 2 +- src/test/kotlin/graphs/{ => algorithms}/KruskalTest.kt | 6 +++--- src/test/kotlin/graphs/algorithms/LouvainTest.kt | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename src/test/kotlin/graphs/{ => algorithms}/KruskalTest.kt (94%) diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index 169e8bd..d911485 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import model.algorithms.BridgeFinder -import graph.model.Graph +import model.graph.Graph import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt index 1a2c89b..faea265 100644 --- a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt +++ b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import model.algorithms.Djikstra -import graph.model.Graph +import model.graph.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt index 9de812c..2a259ae 100644 --- a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import model.algorithms.FordBellman -import graph.model.Graph +import model.graph.Graph import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName diff --git a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt index 0ed55a3..374f82c 100644 --- a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import model.algorithms.Kosaraju -import graph.model.Graph +import model.graph.Graph import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* diff --git a/src/test/kotlin/graphs/KruskalTest.kt b/src/test/kotlin/graphs/algorithms/KruskalTest.kt similarity index 94% rename from src/test/kotlin/graphs/KruskalTest.kt rename to src/test/kotlin/graphs/algorithms/KruskalTest.kt index 47337ab..9a511ba 100644 --- a/src/test/kotlin/graphs/KruskalTest.kt +++ b/src/test/kotlin/graphs/algorithms/KruskalTest.kt @@ -1,7 +1,7 @@ -package graphs +package graphs.algorithms -import algorithms.KruskalsMST -import graph.model.Graph +import model.algorithms.KruskalsMST +import model.graph.Graph import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index 3a31f6c..21def72 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -1,7 +1,7 @@ package graphs.algorithms import model.algorithms.Kosaraju -import graph.model.Graph +import model.graph.Graph import model.community.Louvain import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test From 862273c320470cb8fa0af34ef7a6f34b8cb9b079 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 19:04:23 +0300 Subject: [PATCH 169/211] feat(visual): algorithm visualization for Djikstra added --- src/main/kotlin/view/AlgorithmSubMenu.kt | 57 +--------------------- src/main/kotlin/view/ShortestPathDialog.kt | 52 ++++++++++++++++++++ 2 files changed, 53 insertions(+), 56 deletions(-) create mode 100644 src/main/kotlin/view/ShortestPathDialog.kt diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index 401839d..9fa46b8 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -99,59 +99,4 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { ) } } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun ShortestPathDialog( - showDialog: MutableState, - onPathSelected: (Int, Int) -> Unit -) { - var startIdx by remember { mutableStateOf(0) } - var endIdx by remember { mutableStateOf(0) } - - if (showDialog.value) { - AlertDialog( - onDismissRequest = { showDialog.value = false }, - buttons = { - Button(onClick = { - onPathSelected(startIdx, endIdx) - showDialog.value = false - }) { - Text("Найти кратчайший путь") - } - }, - text = { - Column { - TextField( - value = startIdx.toString(), - onValueChange = { startIdx = it.toIntOrNull() ?: 0 }, - label = { Text("Введите точку отправления") } - ) - Spacer(modifier = Modifier.height(8.dp)) - TextField( - value = endIdx.toString(), - onValueChange = { endIdx = it.toIntOrNull() ?: 0 }, - label = { Text("Введите точку назначения") } - ) - } - } - ) - } -} - -/* - Button( - onClick = { - val graph = viewModel.graph - val painter = GraphPainterByDjikstra(graph, viewModel.graphViewModel, startIdx) - painter.paint() - }, - enabled = true, - modifier = Modifier.padding(top = 3.dp), - ) { - Text( - text = "Кратчайший путь алгоритмом Дейкстры", - ) - } - */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/kotlin/view/ShortestPathDialog.kt b/src/main/kotlin/view/ShortestPathDialog.kt new file mode 100644 index 0000000..e915910 --- /dev/null +++ b/src/main/kotlin/view/ShortestPathDialog.kt @@ -0,0 +1,52 @@ +package view + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ShortestPathDialog( + showDialog: MutableState, + onPathSelected: (Int, Int) -> Unit +) { + var startIdx by remember { mutableStateOf(0) } + var endIdx by remember { mutableStateOf(0) } + + if (showDialog.value) { + AlertDialog( + onDismissRequest = { showDialog.value = false }, + buttons = { + Button(onClick = { + onPathSelected(startIdx, endIdx) + showDialog.value = false + }) { + Text("Найти кратчайший путь") + } + }, + text = { + Column { + TextField( + value = startIdx.toString(), + onValueChange = { startIdx = it.toIntOrNull() ?: 0 }, + label = { Text("Введите точку отправления") } + ) + Spacer(modifier = Modifier.height(8.dp)) + TextField( + value = endIdx.toString(), + onValueChange = { endIdx = it.toIntOrNull() ?: 0 }, + label = { Text("Введите точку назначения") } + ) + } + } + ) + } +} \ No newline at end of file From b8f09d250795fcb6171d460f02fd2f71bbeddb9c Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 16:16:00 +0000 Subject: [PATCH 170/211] feat(ui): add different types of storages support --- src/main/kotlin/view/CustomRadioView.kt | 19 ++- src/main/kotlin/view/LoadGraphMenu.kt | 176 +++++++++++++++++------- 2 files changed, 140 insertions(+), 55 deletions(-) diff --git a/src/main/kotlin/view/CustomRadioView.kt b/src/main/kotlin/view/CustomRadioView.kt index 463ffbd..4abb732 100644 --- a/src/main/kotlin/view/CustomRadioView.kt +++ b/src/main/kotlin/view/CustomRadioView.kt @@ -1,13 +1,16 @@ package view import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @Composable @@ -22,11 +25,13 @@ fun CustomRadioGroup( ) { Box( modifier = Modifier - .background(Color.Magenta) + .background(Color.Gray) + .height(50.dp) .padding(8.dp) .weight(1f) + //.border(2.dp, Color.Black, CircleShape), ) { - Text("NEO4J", color = Color.White) + Text("NEO4J", color = Color.Black) } Spacer(modifier = Modifier.width(8.dp)) Button( @@ -42,11 +47,12 @@ fun CustomRadioGroup( ) { Box( modifier = Modifier - .background(Color.Magenta) + .background(Color.Gray) .padding(8.dp) .weight(1f) + //.border(2.dp, Color.Black, CircleShape), ) { - Text("FILE", color = Color.White) + Text("FILE", color = Color.Black) } Spacer(modifier = Modifier.width(8.dp)) Button( @@ -62,11 +68,12 @@ fun CustomRadioGroup( ) { Box( modifier = Modifier - .background(Color.Magenta) + .background(Color.Gray) .padding(8.dp) .weight(1f) + // .border(2.dp, Color.Black, CircleShape), ) { - Text("SQLITE", color = Color.White) + Text("SQLITE", color = Color.Black) } Spacer(modifier = Modifier.width(8.dp)) Button( diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 53db480..86aac51 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp @@ -14,6 +15,8 @@ import androidx.compose.ui.window.DialogWindow import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.rememberDialogState import kotlinx.coroutines.launch +import model.databases.neo4j.Neo4jHandler +import model.databases.neo4j.Neo4jRepository import viewmodel.LoadGraphMenuViewModel @Composable @@ -21,10 +24,14 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { val coroutineScope = rememberCoroutineScope() var isWeighted by remember { mutableStateOf(false) } var isDirected by remember { mutableStateOf(false) } + var isSqlite by remember { mutableStateOf(false) } + var isNeo4j by remember { mutableStateOf(false) } + var isCSV by remember { mutableStateOf(false) } + val storageType = remember { mutableStateOf(StorageType.FILE) } DialogWindow( - onCloseRequest = { viewModel.canvasViewModel.isOpenLoadGraph = false}, - state = rememberDialogState(position = WindowPosition(Alignment.Center), size = DpSize(500.dp, 350.dp)), + onCloseRequest = { viewModel.canvasViewModel.isOpenLoadGraph = false }, + state = rememberDialogState(position = WindowPosition(Alignment.Center), size = DpSize(800.dp, 640.dp)), title = "Load New Graph", resizable = false ) { @@ -37,39 +44,121 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { val verticalRow = Alignment.CenterVertically Row(modifierRow, verticalAlignment = verticalRow) { - Text( - "Path to Database:", - modifier = Modifier.weight(0.5f), - textAlign = TextAlign.Center, - ) - OutlinedTextField( - modifier = Modifier.weight(1f), - value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue }, - label = { Text("Path") }, - singleLine = true, - colors = TextFieldDefaults.textFieldColors( - ), - ) } Row(modifierRow, verticalAlignment = verticalRow) { -// ComboBox( -// items = VertexIDType.entries.toTypedArray(), -// modifier = Modifier.weight(1f), -// onItemClick = { item: VertexIDType -> viewModel.selectedVertexTypeID.value = item }, -// textAlign = TextAlign.Center -// ) + Column ( modifier = Modifier + .height(450.dp) + .padding(16.dp), + verticalArrangement = Arrangement.Top + ){ + CustomRadioGroup( + options = listOf( + StorageType.FILE.toString(), + StorageType.NEO4J.toString(), + StorageType.SQLITE.toString() + ), + selectedOption = storageType.value.toString(), + onOptionSelected = { storageType.value = StorageType.valueOf(it) } + ) + when (storageType.value) { + StorageType.FILE -> { + Text( + "Path to Database:", + modifier = Modifier.weight(0.5f), + textAlign = TextAlign.Center, + + ) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.graphName.value, + onValueChange = { newValue -> viewModel.graphName.value = newValue }, + label = { Text("Path") }, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + ), + ) + } + + StorageType.NEO4J -> { + Text( + "URL:", + modifier = Modifier.weight(0.5f), + textAlign = TextAlign.Center, + + ) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.graphName.value, + onValueChange = { newValue -> viewModel.graphName.value = newValue }, + label = { Text("URI") }, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + ), + ) + Text( + "Login:", + modifier = Modifier.weight(0.5f), + textAlign = TextAlign.Center, + + ) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.graphName.value, + onValueChange = { newValue -> viewModel.graphName.value = newValue }, + label = { Text("Login") }, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + ), + ) + Text( + "Password:", + modifier = Modifier.weight(0.5f), + textAlign = TextAlign.Center, + + ) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.graphName.value, + onValueChange = { newValue -> viewModel.graphName.value = newValue }, + label = { Text("Password") }, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + ), + ) + } + + StorageType.SQLITE -> { + Text( + "Path to Database:", + modifier = Modifier.weight(0.5f), + textAlign = TextAlign.Center, + + ) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.graphName.value, + onValueChange = { newValue -> viewModel.graphName.value = newValue }, + label = { Text("Path") }, + singleLine = true, + colors = TextFieldDefaults.textFieldColors( + ), + ) + + } + } + } + } Row(modifierRow, verticalAlignment = verticalRow) { Checkbox( checked = isWeighted, - onCheckedChange = { isWeighted = it} + onCheckedChange = { isWeighted = it } ) Text("Weighted") Checkbox( checked = isDirected, - onCheckedChange = { isDirected = it} + onCheckedChange = { isDirected = it } ) Text("Directed") // Button( @@ -82,14 +171,8 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { } Row(modifierRow, verticalAlignment = verticalRow) { Spacer(modifier = Modifier.weight(1f)) - Button( - colors = ButtonDefaults.buttonColors( -// backgroundColor = JetTheme.colors.tertiaryBackground, -// contentColor = JetTheme.colors.secondaryText, -// disabledContentColor = JetTheme.colors.secondaryText, -// disabledBackgroundColor = JetTheme.colors.tertiaryBackground - ), - onClick = { viewModel.canvasViewModel.isOpenLoadGraph = false } + Button(onClick = { viewModel.canvasViewModel.isOpenLoadGraph = false } + ) { Text("Cancel") } @@ -102,25 +185,20 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { // disabledBackgroundColor = JetTheme.colors.tertiaryBackground ), onClick = { - if (viewModel.graphName.value.trim() == "") { - println("Invalid value") - } else { - viewModel.canvasViewModel.isOpenLoadGraph = false - coroutineScope.launch { -// val graph = viewModel.canvasViewModel.createGraph( -// viewModel.graphName.value, -//// viewModel.selectedVertexTypeID.value, -// viewModel.isGraphDirected.value, -// viewModel.isGraphWeighted.value -// ) -// viewModel.homePageViewModel.settings.saveGraph( -// graph, -// viewModel.selectedVertexTypeID.value, -// viewModel.selectedSaveType.value -// ) + when (storageType.value) { + StorageType.FILE -> { + // Логика сохранения в файл с использованием fileName и isDirectedGraph + } + StorageType.NEO4J -> { + // Логика сохранения в Neo4j + } + StorageType.SQLITE -> { + // Логика сохранения в SQLite + } + } - } + viewModel.canvasViewModel.isOpenLoadGraph = false } ) { Text("Load") } From 0ec8c632f134279d7d02d6c3e4c148231cf5cad1 Mon Sep 17 00:00:00 2001 From: dronshock Date: Wed, 29 May 2024 19:32:08 +0300 Subject: [PATCH 171/211] fix(algo): remove main function from class --- .../kotlin/model/algorithms/FindCycles.kt | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src/main/kotlin/model/algorithms/FindCycles.kt b/src/main/kotlin/model/algorithms/FindCycles.kt index 8119ceb..a3c67bc 100644 --- a/src/main/kotlin/model/algorithms/FindCycles.kt +++ b/src/main/kotlin/model/algorithms/FindCycles.kt @@ -134,36 +134,4 @@ class AllCyclesInDirectedGraphJohnson { } return subGraph } -} -//fun main(args: Array) { -// val johnson = AllCyclesInDirectedGraphJohnson() -// val graph = Graph() -// graph.isDirected = true -// for (i in 1..9){ -// graph.addVertex(i,"") -// } -// graph.addEdge(1, 2, edgeID = 0) -// graph.addEdge(1, 8, edgeID = 1) -// graph.addEdge(1, 5, edgeID = 2) -// graph.addEdge(2, 9, edgeID = 3) -// graph.addEdge(2, 7, edgeID = 4) -// graph.addEdge(2, 3, edgeID = 5) -// graph.addEdge(3, 1, edgeID = 6) -// graph.addEdge(3, 2, edgeID = 7) -// graph.addEdge(3, 6, edgeID = 8) -// graph.addEdge(3, 4, edgeID = 9) -// graph.addEdge(6, 4, edgeID = 10) -// graph.addEdge(4, 5, edgeID = 11) -// graph.addEdge(5, 2, edgeID = 12) -// graph.addEdge(8, 9, edgeID = 13) -// graph.addEdge(9, 8, edgeID = 14) -// -// val allCycles: List> = johnson.simpleCycles(graph) -// val joiner = StringJoiner("->") -// allCycles.forEach { cycle: List -> -// cycle.forEach { vertex: Vertex? -> -// joiner.add("${vertex?.id}") -// } -// println(joiner) -// } -//} \ No newline at end of file +} \ No newline at end of file From fa65531d0955dbef18084932550633d787401afd Mon Sep 17 00:00:00 2001 From: dronshock Date: Wed, 29 May 2024 20:52:52 +0300 Subject: [PATCH 172/211] feat(databases): add work with CSV Add new data models for vertex and graph Add dependencies Change EdgeViewModel class --- build.gradle.kts | 2 + .../model/databases/CSV/CSVFileHandler.kt | 107 ++++++++++++++++++ .../model/databases/CSV/data/CSVGraphData.kt | 17 +++ .../databases/CSV/data/VertexViewData.kt | 12 ++ .../kotlin/viewmodel/graph/EdgeViewModel.kt | 3 +- 5 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/model/databases/CSV/CSVFileHandler.kt create mode 100644 src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt create mode 100644 src/main/kotlin/model/databases/CSV/data/VertexViewData.kt diff --git a/build.gradle.kts b/build.gradle.kts index a6c2e17..bb04c36 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,6 +33,8 @@ dependencies { implementation(compose.material3) implementation(compose.foundation) implementation("org.slf4j:slf4j-nop:latest.release") + implementation("com.github.doyaaaaaken:kotlin-csv-jvm:0.15.2") + implementation("io.github.blackmo18:kotlin-grass-jvm:0.7.1") implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") testRuntimeOnly("org.junit.platform:junit-platform-launcher") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") diff --git a/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt b/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt new file mode 100644 index 0000000..20282bc --- /dev/null +++ b/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt @@ -0,0 +1,107 @@ +package model.databases.CSV + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.github.doyaaaaaken.kotlincsv.dsl.csvReader +import com.github.doyaaaaaken.kotlincsv.dsl.csvWriter +import io.github.blackmo18.grass.dsl.grass +import model.databases.CSV.data.CSVGraphData +import model.databases.CSV.data.VertexViewData +import model.graph.Graph +import viewmodel.graph.GraphViewModel +import java.io.File + +@ExperimentalStdlibApi +class CSVFileHandler { + + fun save(file: File, graphViewModel: GraphViewModel) { + val data: MutableList> = mutableListOf(mutableListOf()) + graphViewModel.addVerticesToData(data) + graphViewModel.addEdgesToData(data) + + val csvWriter = csvWriter { delimiter = ',' } + val header = listOf("isNode", "name", "id", "x", "y", "color", "radius", "community", "from", "to", "weight") + + csvWriter.writeAll(listOf(header), file) + csvWriter.writeAll(data, file, append = true) + } + + fun open(file: File): Pair { + try { + val reader = csvReader { skipEmptyLine = true } + val csvContents = reader.readAllWithHeader(file) + val data = grass().harvest(csvContents) + + val vertices = hashMapOf() + val newGraph = Graph() + data.onEach { + if (it.isNode) { + newGraph.addVertex(it.id, it.name) + val rgb:List = it.color?.split("/")?.map { color -> color.toFloat()} ?: listOf(0f, 0f, 0f) + val vertex = VertexViewData( + it.x, + it.y, + it.community ?: -1, + it.radius ?: 2.5, + Color(rgb[0], rgb[1], rgb[2]) + ) + vertices[it.id] = vertex + } + + } + data.onEach { if (!it.isNode) newGraph.addEdge(it.from!!.toInt(), it.to!!.toInt(), it.weight!!, it.id) } + + val newGraphView = GraphViewModel(newGraph) + newGraphView.verticesViewValues.onEach { + val vertex = vertices[it.vertex.id]!! + vertex.x?.let { x -> it.x } + vertex.y?.let { y -> it.y } + it.vertex.community = vertex.community + it.radius = vertex.radius?.dp ?: 2.5.dp + it.color = vertex.color + } + + return newGraph to newGraphView + } catch (e: Exception) { + return Graph() to null + } + } + + private fun GraphViewModel.addVerticesToData(data: MutableList>) { + verticesViewValues.onEach { + val csvRow = mutableListOf( + "true", + it.vertex.data, + it.vertex.id.toString(), + it.x.toString(), + it.y.toString(), + it.color.red.toString() + "/" + it.color.green.toString() + "/" + it.color.blue.toString(), + it.radius.toString(), + it.vertex.community.toString(), + "", + "", + "" + ) + data.add(csvRow) + } + } + + private fun GraphViewModel.addEdgesToData(data: MutableList>) { + edgesViewValues.onEach { + val csvRow = mutableListOf( + "false", + "", + it.e.id.toString(), + "", + "", + "", + "", + "", + it.u.vertex.id.toString(), + it.v.vertex.id.toString(), + it.weight + ) + data.add(csvRow) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt b/src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt new file mode 100644 index 0000000..b873b4d --- /dev/null +++ b/src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt @@ -0,0 +1,17 @@ +package model.databases.CSV.data + +data class CSVGraphData( + + var isNode: Boolean, + var id: Int, + var name: String, + var x: Double?, + var y: Double?, + var color: String?, + var radius: Double?, + var community: Int?, + + var from: String?, + var to: String?, + var weight: Long? +) \ No newline at end of file diff --git a/src/main/kotlin/model/databases/CSV/data/VertexViewData.kt b/src/main/kotlin/model/databases/CSV/data/VertexViewData.kt new file mode 100644 index 0000000..3fd8040 --- /dev/null +++ b/src/main/kotlin/model/databases/CSV/data/VertexViewData.kt @@ -0,0 +1,12 @@ +package model.databases.CSV.data + +import androidx.compose.ui.graphics.Color + +data class VertexViewData( + + var x: Double?, + var y: Double?, + var community: Int = -1, + var radius: Double?, + var color: Color +) \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt index 54b7d8e..3e96307 100644 --- a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt @@ -1,12 +1,11 @@ package viewmodel.graph -import androidx.compose.runtime.State import model.graph.Edge class EdgeViewModel( val u: VertexViewModel, val v: VertexViewModel, - private val e: Edge, + val e: Edge, ) { val weight get() = e.weight.toString() From c4008c2a296dc7119717765a8d28890925b3e0db Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 17:42:16 +0000 Subject: [PATCH 173/211] feat:(ui) add ability to open SQlite db --- .../model/databases/sqlite/SQLiteDBHandler.kt | 8 ++- src/main/kotlin/view/LoadGraphMenu.kt | 52 +++++++++++-------- src/main/kotlin/viewmodel/CanvasViewModel.kt | 4 +- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index 641fbb2..808bdc4 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -16,11 +16,14 @@ import viewmodel.graph.GraphViewModel import java.io.File class SQLiteDBHandler { + lateinit var graph: Graph + lateinit var graphViewModel: GraphViewModel + var vertexViewModelFlag = false fun open(file: File, weighted: Boolean, directed: Boolean) { Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") val newGraph = Graph() newGraph.isDirected=directed - var vertexViewModelFlag = false + transaction { Vertex.all().forEach { vertex -> newGraph.addVertex(vertex.id.toString().toInt(), vertex.data) @@ -55,8 +58,9 @@ class SQLiteDBHandler { it.value.radius = tmp.r.dp } } + graphViewModel=newGraphViewModel } - + graph=newGraph } fun save(file: File) { diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 86aac51..c66ea44 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -17,17 +17,24 @@ import androidx.compose.ui.window.rememberDialogState import kotlinx.coroutines.launch import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository +import model.databases.sqlite.SQLiteDBHandler +import model.graph.Graph import viewmodel.LoadGraphMenuViewModel +import java.io.File @Composable -fun LoadGraph(viewModel: LoadGraphMenuViewModel) { +fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { val coroutineScope = rememberCoroutineScope() var isWeighted by remember { mutableStateOf(false) } var isDirected by remember { mutableStateOf(false) } - var isSqlite by remember { mutableStateOf(false) } - var isNeo4j by remember { mutableStateOf(false) } - var isCSV by remember { mutableStateOf(false) } + + val storageType = remember { mutableStateOf(StorageType.FILE) } + var fileAddress by remember { mutableStateOf("") } + var uri by remember { mutableStateOf("") } + var login by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } + DialogWindow( onCloseRequest = { viewModel.canvasViewModel.isOpenLoadGraph = false }, @@ -82,7 +89,7 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { StorageType.NEO4J -> { Text( - "URL:", + "URI:", modifier = Modifier.weight(0.5f), textAlign = TextAlign.Center, @@ -90,7 +97,8 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue }, + onValueChange = { newValue -> viewModel.graphName.value = newValue + uri = newValue}, label = { Text("URI") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -105,7 +113,8 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue }, + onValueChange = { newValue -> viewModel.graphName.value = newValue + login = newValue}, label = { Text("Login") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -120,7 +129,8 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue }, + onValueChange = { newValue -> viewModel.graphName.value = newValue + password = newValue}, label = { Text("Password") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -138,7 +148,9 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue }, + onValueChange = { newValue -> + viewModel.graphName.value = newValue + fileAddress=newValue}, label = { Text("Path") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -161,13 +173,7 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { onCheckedChange = { isDirected = it } ) Text("Directed") -// Button( -// //selected = viewModel.isGraphDirected.value, -// onClick = { viewModel.isGraphDirected.value = !viewModel.isGraphDirected.value }, -// -// //verticalAlignment = Alignment.CenterVertically, -// modifier = Modifier.weight(1f), -// ){Text("Directed graph")} + } Row(modifierRow, verticalAlignment = verticalRow) { Spacer(modifier = Modifier.weight(1f)) @@ -178,12 +184,6 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { } Spacer(modifier = Modifier.weight(0.01f)) Button( - colors = ButtonDefaults.buttonColors( -// backgroundColor = JetTheme.colors.tertiaryBackground, -// contentColor = JetTheme.colors.secondaryText, -// disabledContentColor = JetTheme.colors.secondaryText, -// disabledBackgroundColor = JetTheme.colors.tertiaryBackground - ), onClick = { when (storageType.value) { StorageType.FILE -> { @@ -194,7 +194,13 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { } StorageType.SQLITE -> { - // Логика сохранения в SQLite + val dataBase: File = File(fileAddress) + val sqlHandler = SQLiteDBHandler() + sqlHandler.open(dataBase,isWeighted,isDirected) + viewModel.canvasViewModel.graph = sqlHandler.graph + if(sqlHandler.vertexViewModelFlag){ + viewModel.canvasViewModel.graphViewModel = sqlHandler.graphViewModel + } } } diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 774fe7e..5318eb2 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -5,10 +5,10 @@ import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -class CanvasViewModel(val graph: Graph, private val representationStrategy: RepresentationStrategy,) { +class CanvasViewModel(var graph: Graph, private val representationStrategy: RepresentationStrategy,) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) - val graphViewModel = GraphViewModel(graph) + var graphViewModel = GraphViewModel(graph) private val _isOpenLoadGraph = mutableStateOf(false) var isOpenLoadGraph: Boolean From 14f9a6632d53cedd10e7d53b1899ee874bc18ca6 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 18:35:12 +0000 Subject: [PATCH 174/211] feat(ui): add support for sqlite databases --- .../kotlin/model/databases/sqlite/SQLiteDBHandler.kt | 10 ++++++---- .../kotlin/model/databases/sqlite/dao/edge/Edges.kt | 2 +- src/main/kotlin/view/LoadGraphMenu.kt | 8 ++++++++ src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 +- src/main/kotlin/viewmodel/graph/GraphViewModel.kt | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index 808bdc4..23ce57f 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -31,7 +31,8 @@ class SQLiteDBHandler { Edge.all().forEach { edge -> newGraph.addEdge( edge.first!!.id.toString().toInt(), edge.second!!.id.toString().toInt(), - edge.weight, edge.id.toString().toInt() + edge.weight, + edge.id.toString().toInt() ) if (!newGraph.isDirected) { newGraph.vertices[edge.second!!.id.toString().toInt()]!!.incidentEdges.add( @@ -39,10 +40,11 @@ class SQLiteDBHandler { ) } newGraph.vertices[edge.first!!.id.toString().toInt()]!!.incidentEdges.add(edge.id.toString().toInt()) + if (VerticesView.exists()) { + vertexViewModelFlag = true + } } - if (VerticesView.exists()) { - vertexViewModelFlag = true - } + } if (vertexViewModelFlag) { val newGraphViewModel = GraphViewModel(newGraph) diff --git a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt index d92c90e..d421e13 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt @@ -3,7 +3,7 @@ package model.databases.sqlite.dao.edge import model.databases.sqlite.dao.vertices.Vertices import org.jetbrains.exposed.dao.id.IntIdTable -object Edges: IntIdTable("Edge") { +object Edges: IntIdTable("Edges") { val first = reference("first", Vertices).nullable() val second = reference("second", Vertices).nullable() val weight = long("weight") diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index c66ea44..9b84b58 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -20,6 +20,7 @@ import model.databases.neo4j.Neo4jRepository import model.databases.sqlite.SQLiteDBHandler import model.graph.Graph import viewmodel.LoadGraphMenuViewModel +import viewmodel.graph.GraphViewModel import java.io.File @Composable @@ -194,13 +195,20 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { } StorageType.SQLITE -> { + fileAddress = "examples/$fileAddress" val dataBase: File = File(fileAddress) val sqlHandler = SQLiteDBHandler() sqlHandler.open(dataBase,isWeighted,isDirected) viewModel.canvasViewModel.graph = sqlHandler.graph if(sqlHandler.vertexViewModelFlag){ + viewModel.canvasViewModel.graphViewModel.graph = sqlHandler.graph viewModel.canvasViewModel.graphViewModel = sqlHandler.graphViewModel } + else{ + viewModel.canvasViewModel.graphViewModel = GraphViewModel(sqlHandler.graph) + } + viewModel.canvasViewModel.representationStrategy.place(1280.0, 860.0, + viewModel.canvasViewModel.graphViewModel) } } diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 5318eb2..b915288 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -5,7 +5,7 @@ import model.graph.Graph import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -class CanvasViewModel(var graph: Graph, private val representationStrategy: RepresentationStrategy,) { +class CanvasViewModel(var graph: Graph, val representationStrategy: RepresentationStrategy,) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) var graphViewModel = GraphViewModel(graph) diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 974ad88..0447f21 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -9,7 +9,7 @@ import model.graph.Vertex class GraphViewModel( - private val graph: Graph, + var graph: Graph, ) { val verticesView: HashMap = hashMapOf() From b45cb47e1a4dafef478afdb4e42e6bfa58296bc2 Mon Sep 17 00:00:00 2001 From: Sem4kok Date: Wed, 29 May 2024 22:45:06 +0300 Subject: [PATCH 175/211] feat(db): load from neo4j added --- src/main/kotlin/view/LoadGraphMenu.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 9b84b58..d27d720 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -191,9 +191,14 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { // Логика сохранения в файл с использованием fileName и isDirectedGraph } StorageType.NEO4J -> { - // Логика сохранения в Neo4j - - } + val repository = Neo4jRepository(uri, login, password) + val handler = Neo4jHandler(repository) + val newGraph = handler.loadGraphFromNeo4j() + newGraph.isDirected = isDirected + viewModel.canvasViewModel.graph = newGraph + viewModel.canvasViewModel.graphViewModel = GraphViewModel(newGraph) + viewModel.canvasViewModel.isOpenLoadGraph = false + } StorageType.SQLITE -> { fileAddress = "examples/$fileAddress" val dataBase: File = File(fileAddress) From 17f38b0cb97a3e2036ef43843f20660b64d13036 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 20:40:23 +0000 Subject: [PATCH 176/211] feat(ui): implement raw version graph saving into sqlite databases --- examples/keep | 0 {examples => saves/sqlite}/Shelbiks.db | Bin src/main/kotlin/Main.kt | 4 +- .../model/databases/sqlite/SQLiteDBHandler.kt | 53 ++++++++++++++++-- src/main/kotlin/view/CanvasView.kt | 15 ++--- src/main/kotlin/view/LoadGraphMenu.kt | 2 +- 6 files changed, 58 insertions(+), 16 deletions(-) delete mode 100644 examples/keep rename {examples => saves/sqlite}/Shelbiks.db (100%) diff --git a/examples/keep b/examples/keep deleted file mode 100644 index e69de29..0000000 diff --git a/examples/Shelbiks.db b/saves/sqlite/Shelbiks.db similarity index 100% rename from examples/Shelbiks.db rename to saves/sqlite/Shelbiks.db diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 4edf08e..e1f2d3b 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -332,7 +332,7 @@ val graph = Graph().apply { // addEdge(68,48,35,164) // addEdge(51,63,24,165) } -val windowSizeStart = Pair(1480,1020) +val windowSizeStart = Pair(820,640) @Composable @Preview fun App() { @@ -346,7 +346,7 @@ fun App() { fun main() = application { Window(onCloseRequest = ::exitApplication, - title = "stoic", + title = "ZeitNot", state = rememberWindowState(position = WindowPosition(Alignment.Center)) ) { window.minimumSize = Dimension(windowSizeStart.first, windowSizeStart.second) diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index 23ce57f..f9a84e6 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -7,9 +7,11 @@ import model.databases.sqlite.dao.vertices.Vertices import model.databases.sqlite.dao.verticesView.VertexView import model.databases.sqlite.dao.verticesView.VerticesView import androidx.compose.ui.unit.dp +import model.databases.sqlite.dao.edge.Edges import model.graph.Graph import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.exists import org.jetbrains.exposed.sql.transactions.transaction import viewmodel.graph.GraphViewModel @@ -22,16 +24,20 @@ class SQLiteDBHandler { fun open(file: File, weighted: Boolean, directed: Boolean) { Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") val newGraph = Graph() - newGraph.isDirected=directed + newGraph.isDirected = directed transaction { Vertex.all().forEach { vertex -> newGraph.addVertex(vertex.id.toString().toInt(), vertex.data) } Edge.all().forEach { edge -> + var weight = edge.weight + if (!weighted) { + weight = 1L + } newGraph.addEdge( edge.first!!.id.toString().toInt(), edge.second!!.id.toString().toInt(), - edge.weight, + weight, edge.id.toString().toInt() ) if (!newGraph.isDirected) { @@ -60,13 +66,48 @@ class SQLiteDBHandler { it.value.radius = tmp.r.dp } } - graphViewModel=newGraphViewModel + graphViewModel = newGraphViewModel } - graph=newGraph + graph = newGraph } - fun save(file: File) { + fun save(file: File, graph: Graph, graphView: GraphViewModel, weighted: Boolean) { Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") - + transaction { + SchemaUtils.create(Edges) + SchemaUtils.create(Vertices) + SchemaUtils.create(VerticesView) + graph.getVertices().forEach { + Vertex.new { + data = it.data + community = it.community + } + } + graph.getEdges().forEach { + var newWeight = it.weight + if (!weighted) { + newWeight = 1L + } + Edge.new { + first = Vertex.find { Vertices.id eq it.vertices.first }.first() + second = Vertex.find { Vertices.id eq it.vertices.second }.first() + weight = newWeight + } + } + graphView.verticesViewValues.forEach { + //println("${it.radius.toString().substring(0, it.x.toString().length - 4)}") + val xDoubled: Double = it.x.toString().substring(0, it.x.toString().length - 4).toDouble() + val yDoubled: Double = it.y.toString().substring(0, it.x.toString().length - 4).toDouble() + val rDoubled: Double = it.radius.toString().substring(0, it.x.toString().length - 4).toDouble() + //println("$xDoubled,$yDoubled,$rDoubled") + VertexView.new { + vertex = Vertex.find { Vertices.id eq it.vertex.id }.first() + color = it.color.red.toString() + "/" + it.color.green.toString() + "/" + it.color.blue.toString() + x = xDoubled + y = yDoubled + r = rDoubled + } + } + } } } \ No newline at end of file diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 8c92b65..139e876 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -29,11 +29,12 @@ import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository +import model.databases.sqlite.SQLiteDBHandler import view.graph.GraphView import viewmodel.CanvasViewModel import viewmodel.LoadGraphMenuViewModel - +import java.io.File @Composable @@ -48,6 +49,7 @@ fun Canvas(viewModel: CanvasViewModel) { val uri = remember { mutableStateOf("") } val login = remember { mutableStateOf("") } val password = remember { mutableStateOf("") } + var sqlPath = remember { mutableStateOf("") } val interactionSource = remember { MutableInteractionSource() } AnimatedVisibility(visible = showDialog.value) { @@ -123,11 +125,7 @@ fun Canvas(viewModel: CanvasViewModel) { onValueChange = { fileName.value = it }, label = { Text("File Name") } ) - Text("Ориентированный ли граф") - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) + Spacer(modifier = Modifier.width(8.dp)) Text("Взвешанные ли рёбра") @@ -155,7 +153,10 @@ fun Canvas(viewModel: CanvasViewModel) { viewModel.graph.isDirected = wasGraphDirected } StorageType.SQLITE -> { - // Логика сохранения в SQLite + val fileAddress = "saves/sqlite/${fileName.value}" + val dataBase = File(fileAddress) + val sqlHandler = SQLiteDBHandler() + sqlHandler.save(dataBase,viewModel.graph,viewModel.graphViewModel,isWeighted.value) } } showDialog.value = false diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 9b84b58..7406420 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -195,7 +195,7 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { } StorageType.SQLITE -> { - fileAddress = "examples/$fileAddress" + fileAddress = "saves/sqlite/$fileAddress" val dataBase: File = File(fileAddress) val sqlHandler = SQLiteDBHandler() sqlHandler.open(dataBase,isWeighted,isDirected) From 767b3f8057124e944634bf0e24a278e1fee7392b Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 20:52:26 +0000 Subject: [PATCH 177/211] feat(ui): fixed colored graph loading bug --- src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index f9a84e6..47814e7 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -61,7 +61,7 @@ class SQLiteDBHandler { it.value.x = tmp.x.dp it.value.y = tmp.y.dp it.key.community = vertex.community - val rgb = tmp.color.split(":").map { color -> color.toInt() } + val rgb = tmp.color.split(":").map { color -> color.toFloat() } it.value.color = Color(rgb[0], rgb[1], rgb[2]) it.value.radius = tmp.r.dp } @@ -95,14 +95,14 @@ class SQLiteDBHandler { } } graphView.verticesViewValues.forEach { - //println("${it.radius.toString().substring(0, it.x.toString().length - 4)}") + println("${it.radius.toString().substring(0, it.x.toString().length - 4)}") val xDoubled: Double = it.x.toString().substring(0, it.x.toString().length - 4).toDouble() val yDoubled: Double = it.y.toString().substring(0, it.x.toString().length - 4).toDouble() val rDoubled: Double = it.radius.toString().substring(0, it.x.toString().length - 4).toDouble() //println("$xDoubled,$yDoubled,$rDoubled") VertexView.new { vertex = Vertex.find { Vertices.id eq it.vertex.id }.first() - color = it.color.red.toString() + "/" + it.color.green.toString() + "/" + it.color.blue.toString() + color = it.color.red.toString() + ":" + it.color.green.toString() + ":" + it.color.blue.toString() x = xDoubled y = yDoubled r = rDoubled From a17cb5fd3469d84528820be130f0c3abb90c7f49 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Wed, 29 May 2024 20:55:17 +0000 Subject: [PATCH 178/211] fix: remove redundant prints --- src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index 47814e7..70c471c 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -95,11 +95,11 @@ class SQLiteDBHandler { } } graphView.verticesViewValues.forEach { - println("${it.radius.toString().substring(0, it.x.toString().length - 4)}") + val xDoubled: Double = it.x.toString().substring(0, it.x.toString().length - 4).toDouble() val yDoubled: Double = it.y.toString().substring(0, it.x.toString().length - 4).toDouble() val rDoubled: Double = it.radius.toString().substring(0, it.x.toString().length - 4).toDouble() - //println("$xDoubled,$yDoubled,$rDoubled") + VertexView.new { vertex = Vertex.find { Vertices.id eq it.vertex.id }.first() color = it.color.red.toString() + ":" + it.color.green.toString() + ":" + it.color.blue.toString() @@ -110,4 +110,4 @@ class SQLiteDBHandler { } } } -} \ No newline at end of file +} From a9b6277cf21346ae2b9b5a2a08a9f5566e573606 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 21:12:19 +0000 Subject: [PATCH 179/211] fix: make gui more beauty --- src/main/kotlin/view/CustomRadioView.kt | 29 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/view/CustomRadioView.kt b/src/main/kotlin/view/CustomRadioView.kt index 4abb732..60921ee 100644 --- a/src/main/kotlin/view/CustomRadioView.kt +++ b/src/main/kotlin/view/CustomRadioView.kt @@ -6,7 +6,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -18,14 +18,19 @@ fun CustomRadioGroup( options: List, selectedOption: String, onOptionSelected: (String) -> Unit + ) { + var isBoxSelected1 by remember { mutableStateOf(false) } + var isBoxSelected2 by remember { mutableStateOf(false) } + var isBoxSelected3 by remember { mutableStateOf(false) } + Column { Row( verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier - .background(Color.Gray) + .background(if (isBoxSelected1) Color.DarkGray else Color.Gray) .height(50.dp) .padding(8.dp) .weight(1f) @@ -35,7 +40,10 @@ fun CustomRadioGroup( } Spacer(modifier = Modifier.width(8.dp)) Button( - onClick = { onOptionSelected(StorageType.NEO4J.name) } + onClick = { onOptionSelected(StorageType.NEO4J.name) + isBoxSelected3 = false + isBoxSelected2 = false + isBoxSelected1 = !isBoxSelected1} ) { Text("Select") } @@ -47,7 +55,7 @@ fun CustomRadioGroup( ) { Box( modifier = Modifier - .background(Color.Gray) + .background(if (isBoxSelected2) Color.DarkGray else Color.Gray) .padding(8.dp) .weight(1f) //.border(2.dp, Color.Black, CircleShape), @@ -56,7 +64,10 @@ fun CustomRadioGroup( } Spacer(modifier = Modifier.width(8.dp)) Button( - onClick = { onOptionSelected(StorageType.FILE.name) } + onClick = { onOptionSelected(StorageType.FILE.name) + isBoxSelected3 = false + isBoxSelected2 = !isBoxSelected2 + isBoxSelected1 = false} ) { Text("Select") } @@ -68,7 +79,7 @@ fun CustomRadioGroup( ) { Box( modifier = Modifier - .background(Color.Gray) + .background(if (isBoxSelected3) Color.DarkGray else Color.Gray) .padding(8.dp) .weight(1f) // .border(2.dp, Color.Black, CircleShape), @@ -77,7 +88,11 @@ fun CustomRadioGroup( } Spacer(modifier = Modifier.width(8.dp)) Button( - onClick = { onOptionSelected(StorageType.SQLITE.name) } + onClick = { + onOptionSelected(StorageType.SQLITE.name) + isBoxSelected3 = !isBoxSelected3 + isBoxSelected2 = false + isBoxSelected1 = false} ) { Text("Select") } From a130fa3e76b20405c36b1b05ccc91fa232b3acad Mon Sep 17 00:00:00 2001 From: dronshock Date: Thu, 30 May 2024 00:37:00 +0300 Subject: [PATCH 180/211] feat: add README --- README.md | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 30404ce..8c8b511 100644 --- a/README.md +++ b/README.md @@ -1 +1,123 @@ -TODO \ No newline at end of file +# Анализатор графов +Это приложение позволяет выделять сообщества в графах, находить ключевые вершины и делать раскладку. Оно поддерживает чтение и запись в `.csv` и `.db` (SQLite). + + +## Установка и запуск +Приложение работает на Java SDK 15 версии. + +- Установка: + +``` +git clone https://github.com/spbu-coding-2023/graphs-graph-7.git +``` + +- Запуск: + +#### Windows + +``` +.\gradlew.bat run +``` + +#### Linux + +``` +./gradlew run +``` + +#### MacOS + +``` +./gradlew run +``` + +## Выделение сообществ +Для выделения сообществ используется [Louvain alghoritm](https://en.wikipedia.org/wiki/Louvain_method) + +## Выделение ключевых вершин +Для выделения ключевых вершин используется [Harmonic centrality](http://infoscience.epfl.ch/record/200525/files/%5bEN%5dASNA09.pdf) +с алгоритмом Дейкстры и нормализованновым показателем centrality. Вершины выделяется размером, который считается по формуле: + +![Formula](http://www.sciweavers.org/tex2img.php?eq=R%2A%5Cfrac%7B2%28%28e%2Bk%29%5Ex-%28e%2B%5Cfrac%7Bk%7D%7B2%7D%29%5Ex%29%7D%7Bk%7D&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0)() + +- _**`x`**_ - показатель centrality +- _**`R`**_ - стандартный размер вершины +- _**`k`**_ - передаваемый параметр (Size-Ratio coefficient) + +> Чем больше _**`k`**_, тем больше отношение размеров вершин с разным значением centrality. + + +## Раскладка графа +Для раскладки графа используется алгоритм [ForceAtlas2](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0098679). В качестве параметров ему передаются: + + +- Количество итераций алгоритма. (Iteration) +- Сила притяжения вершин друг к другу. (Gravity) +- Активация/деактивация расчета с помощью логарифмической силы притяжения. (Logarithmic attraction mode) +- Активация/деактивация притяжения вершин к краям окна. (Outbound attraction mode) +- Активация/деактивация притяжения вершин к центру. (Strong gravity mode) + + +## SQLite +Приложение имеет возможность сохранять и читать 2 типа SQLite баз данных (сохранение идет во 2 тип) + +1) Необработанный граф. В таком случае в базе данных должно быть две таблицы + + +### _**Vertices**_ + +| id | element | community | +|--|--|--| +| *integer* | *text* | -1 | + +### _**Edges**_ + +| id | element | first | second | +|--|--|--|--| +| *integer* | *text* | *int* | *int* | + +- _**`id`**_ - идентификационный номер _(должен быть уникальным)_ + +- _**`first`**_ - откуда идет ребро _(**id** вершины из первой таблицы)_ + +- _**`second`**_ - куда идет ребро _(**id** вершины из первой таблицы)_ + +2. Обработанный граф. В таком случае должна быть третья таблица, а в таблице **Vertices** в поле **community** вместо -1 могут стоять непосредственно номера community + +### _**VerticesView**_ + +| id| vertex | x | y| color | +|--|--|--|--|--| +| *integer* | *int* | *double*| *double*| *text*| + +- _**`id`**_ должен быть уникален + +- _**`vertex`**_ - **id** вершины из таблицы **Vertices** + +- _**`x, y`**_ - координаты вершины + +- _**`color`**_ - цвет формата RGB в следующем виде "r/g/b", где r,g,b - double. + + +## CSV-файлы +Приложение так же имеет возможность сохранять графы в файлы формата `.csv`, а также считывать их. + +> Чтобы приложение могло считать граф, csv-файл должен соответствовать стандарту описанному ниже. + +Заголовок: + +``` +isNode,name,id,x,y,color,radius,community,from,to,weight +``` + +Остальные строчки должны представлять из себя заполненные (где это нужно) поля заголовка, разделенные запятой: + +- _**`isNode`**_ - значение true/false _(вершина либо ребро)_ +- _**`name`**_ - имя вершины/ребра +- _**`id`**_ - идентификатор _(уникальное поле)_ +- _**`x`**_, _**`y`**_ - координаты вершины _(необязательное поле в случае вершины, в случае ребра - пустое)_ +- _**`color`**_ - цвет вершины в формате "r/g/b", где "r", "g", "b" - числа из rgb представления цвета, а "/" - разделитель _(необязательное поле в случае вершины, в случае ребра - пустое)_ +- _**`radius`**_ - числовое представление радиуса вершины _(необязательное поле в случае вершины, в случае ребра - пустое)_ +- _**`community`**_ - номер сообщества вершины _(необязательное поле в случае вершины, в случае ребра - пустое)_ +- _**`from`**_, _**`to`**_ - имена вершин, которые соответствуют началу и концу ребра _(пустое для вершин поле)_ +- _**`weight`**_ - вес ребра_(пустое для вершин поле)_ \ No newline at end of file From abc0cd4e6b83a1b28168092caa25fa713463fb6b Mon Sep 17 00:00:00 2001 From: dronshock Date: Thu, 30 May 2024 00:37:21 +0300 Subject: [PATCH 181/211] fix(CSV): correct header --- src/main/kotlin/model/databases/CSV/CSVFileHandler.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt b/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt index 20282bc..f3b9e77 100644 --- a/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt +++ b/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt @@ -71,8 +71,8 @@ class CSVFileHandler { verticesViewValues.onEach { val csvRow = mutableListOf( "true", - it.vertex.data, it.vertex.id.toString(), + it.vertex.data, it.x.toString(), it.y.toString(), it.color.red.toString() + "/" + it.color.green.toString() + "/" + it.color.blue.toString(), @@ -90,13 +90,13 @@ class CSVFileHandler { edgesViewValues.onEach { val csvRow = mutableListOf( "false", - "", it.e.id.toString(), "", "", "", "", "", + "", it.u.vertex.id.toString(), it.v.vertex.id.toString(), it.weight From c349ae927f3ae7d56d034ee70572fd6d5c310b00 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Wed, 29 May 2024 22:03:26 +0000 Subject: [PATCH 182/211] Delete README.md --- README.md | 123 ------------------------------------------------------ 1 file changed, 123 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index 8c8b511..0000000 --- a/README.md +++ /dev/null @@ -1,123 +0,0 @@ -# Анализатор графов -Это приложение позволяет выделять сообщества в графах, находить ключевые вершины и делать раскладку. Оно поддерживает чтение и запись в `.csv` и `.db` (SQLite). - - -## Установка и запуск -Приложение работает на Java SDK 15 версии. - -- Установка: - -``` -git clone https://github.com/spbu-coding-2023/graphs-graph-7.git -``` - -- Запуск: - -#### Windows - -``` -.\gradlew.bat run -``` - -#### Linux - -``` -./gradlew run -``` - -#### MacOS - -``` -./gradlew run -``` - -## Выделение сообществ -Для выделения сообществ используется [Louvain alghoritm](https://en.wikipedia.org/wiki/Louvain_method) - -## Выделение ключевых вершин -Для выделения ключевых вершин используется [Harmonic centrality](http://infoscience.epfl.ch/record/200525/files/%5bEN%5dASNA09.pdf) -с алгоритмом Дейкстры и нормализованновым показателем centrality. Вершины выделяется размером, который считается по формуле: - -![Formula](http://www.sciweavers.org/tex2img.php?eq=R%2A%5Cfrac%7B2%28%28e%2Bk%29%5Ex-%28e%2B%5Cfrac%7Bk%7D%7B2%7D%29%5Ex%29%7D%7Bk%7D&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0)() - -- _**`x`**_ - показатель centrality -- _**`R`**_ - стандартный размер вершины -- _**`k`**_ - передаваемый параметр (Size-Ratio coefficient) - -> Чем больше _**`k`**_, тем больше отношение размеров вершин с разным значением centrality. - - -## Раскладка графа -Для раскладки графа используется алгоритм [ForceAtlas2](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0098679). В качестве параметров ему передаются: - - -- Количество итераций алгоритма. (Iteration) -- Сила притяжения вершин друг к другу. (Gravity) -- Активация/деактивация расчета с помощью логарифмической силы притяжения. (Logarithmic attraction mode) -- Активация/деактивация притяжения вершин к краям окна. (Outbound attraction mode) -- Активация/деактивация притяжения вершин к центру. (Strong gravity mode) - - -## SQLite -Приложение имеет возможность сохранять и читать 2 типа SQLite баз данных (сохранение идет во 2 тип) - -1) Необработанный граф. В таком случае в базе данных должно быть две таблицы - - -### _**Vertices**_ - -| id | element | community | -|--|--|--| -| *integer* | *text* | -1 | - -### _**Edges**_ - -| id | element | first | second | -|--|--|--|--| -| *integer* | *text* | *int* | *int* | - -- _**`id`**_ - идентификационный номер _(должен быть уникальным)_ - -- _**`first`**_ - откуда идет ребро _(**id** вершины из первой таблицы)_ - -- _**`second`**_ - куда идет ребро _(**id** вершины из первой таблицы)_ - -2. Обработанный граф. В таком случае должна быть третья таблица, а в таблице **Vertices** в поле **community** вместо -1 могут стоять непосредственно номера community - -### _**VerticesView**_ - -| id| vertex | x | y| color | -|--|--|--|--|--| -| *integer* | *int* | *double*| *double*| *text*| - -- _**`id`**_ должен быть уникален - -- _**`vertex`**_ - **id** вершины из таблицы **Vertices** - -- _**`x, y`**_ - координаты вершины - -- _**`color`**_ - цвет формата RGB в следующем виде "r/g/b", где r,g,b - double. - - -## CSV-файлы -Приложение так же имеет возможность сохранять графы в файлы формата `.csv`, а также считывать их. - -> Чтобы приложение могло считать граф, csv-файл должен соответствовать стандарту описанному ниже. - -Заголовок: - -``` -isNode,name,id,x,y,color,radius,community,from,to,weight -``` - -Остальные строчки должны представлять из себя заполненные (где это нужно) поля заголовка, разделенные запятой: - -- _**`isNode`**_ - значение true/false _(вершина либо ребро)_ -- _**`name`**_ - имя вершины/ребра -- _**`id`**_ - идентификатор _(уникальное поле)_ -- _**`x`**_, _**`y`**_ - координаты вершины _(необязательное поле в случае вершины, в случае ребра - пустое)_ -- _**`color`**_ - цвет вершины в формате "r/g/b", где "r", "g", "b" - числа из rgb представления цвета, а "/" - разделитель _(необязательное поле в случае вершины, в случае ребра - пустое)_ -- _**`radius`**_ - числовое представление радиуса вершины _(необязательное поле в случае вершины, в случае ребра - пустое)_ -- _**`community`**_ - номер сообщества вершины _(необязательное поле в случае вершины, в случае ребра - пустое)_ -- _**`from`**_, _**`to`**_ - имена вершин, которые соответствуют началу и концу ребра _(пустое для вершин поле)_ -- _**`weight`**_ - вес ребра_(пустое для вершин поле)_ \ No newline at end of file From 738744e94441fd6762135881f2c1579ac2256e0d Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 22:21:49 +0000 Subject: [PATCH 183/211] feat: implement sad visualization of bridge finder algorithm --- .../kotlin/model/layout/ForceAtlas2Layout.kt | 2 +- src/main/kotlin/view/AlgorithmSubMenu.kt | 22 +++++++++++----- .../kotlin/view/algos/BridgeFinderView.kt | 23 +++++++++++++++++ src/main/kotlin/viewmodel/CanvasViewModel.kt | 2 ++ .../viewmodel/algos/BridgeFinderViewModel.kt | 25 +++++++++++++++++++ .../kotlin/viewmodel/graph/GraphViewModel.kt | 4 ++- 6 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/view/algos/BridgeFinderView.kt create mode 100644 src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt index 88b2428..9fe35b3 100644 --- a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt +++ b/src/main/kotlin/model/layout/ForceAtlas2Layout.kt @@ -46,7 +46,7 @@ class ForceAtlas2Layout:RepresentationStrategy{ layout.resetPropertiesValues() layout.isAdjustSizes = true layout.isBarnesHutOptimize = true - layout.scalingRatio = 20.0 + layout.scalingRatio = 60.0 layout.gravity = 2.0 var i = 0 diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index 9fa46b8..35c80c6 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -1,24 +1,29 @@ package view -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.* import androidx.compose.material.AlertDialog import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex import controller.GraphPainterByCommunity import controller.GraphPainterByDjikstra import controller.GraphPainterByKosaraju +import model.algorithms.BridgeFinder +import view.algos.bridgeHighlighter import viewmodel.CanvasViewModel +import viewmodel.graph.VertexViewModel @Composable fun AlgorithmSubMenu(viewModel: CanvasViewModel) { val showDialog = remember { mutableStateOf(false) } var startIdx by remember { mutableStateOf(0) } var endIdx by remember { mutableStateOf(0) } + var bridgesHiglight = remember { mutableStateOf(false) } Column(Modifier.padding(start = 16.dp, end = 0.dp, top = 15.dp)) { Button( @@ -65,13 +70,18 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { } } Button( - onClick = { /*TODO*/ }, enabled = true, - ) { + onClick = { + bridgesHiglight.value = !bridgesHiglight.value + }) + { Text( text = "Поиск мостов", ) } + if(bridgesHiglight.value){ + bridgeHighlighter(viewModel.bridges) + } Button( onClick = { /*TODO*/ }, enabled = true, diff --git a/src/main/kotlin/view/algos/BridgeFinderView.kt b/src/main/kotlin/view/algos/BridgeFinderView.kt new file mode 100644 index 0000000..2a2451b --- /dev/null +++ b/src/main/kotlin/view/algos/BridgeFinderView.kt @@ -0,0 +1,23 @@ +package view.algos + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.ui.Modifier +import androidx.compose.foundation.Canvas +import androidx.compose.runtime.Composable +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.zIndex + +import viewmodel.CanvasViewModel +import viewmodel.algos.BridgeFinderViewModel +import viewmodel.graph.VertexViewModel + +//просто окрашиваю прилегающие вершины в красный цвет +@Composable +fun bridgeHighlighter(bridges: BridgeFinderViewModel) { + val pairs = bridges.pairsList + for (pair in pairs) { + pair.first.color = Color.Red + pair.second.color = Color.Red + } +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index b915288..7a7762a 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -2,6 +2,7 @@ package viewmodel import androidx.compose.runtime.mutableStateOf import model.graph.Graph +import viewmodel.algos.BridgeFinderViewModel import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy @@ -9,6 +10,7 @@ class CanvasViewModel(var graph: Graph, val representationStrategy: Representati val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) var graphViewModel = GraphViewModel(graph) + val bridges = BridgeFinderViewModel(graph,graphViewModel) private val _isOpenLoadGraph = mutableStateOf(false) var isOpenLoadGraph: Boolean diff --git a/src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt b/src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt new file mode 100644 index 0000000..dd34121 --- /dev/null +++ b/src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt @@ -0,0 +1,25 @@ +package viewmodel.algos + +import model.algorithms.BridgeFinder +import model.graph.Graph +import org.gephi.graph.api.GraphView +import viewmodel.graph.GraphViewModel +import viewmodel.graph.VertexViewModel + +class BridgeFinderViewModel(graph: Graph, graphView: GraphViewModel) { + val bridgeFinder = BridgeFinder(graph) + val pairsList = mutableListOf>() + init{ + bridgeFinder.findBridges() + val edges = bridgeFinder.bridges + edges.forEach { bridge -> + val key = graph.edges[bridge] + val firstEnd: VertexViewModel = graphView.edgesView[key]!!.u + val secondEnd: VertexViewModel = graphView.edgesView[key]!!.v + pairsList.add(Pair(firstEnd, secondEnd)) + } + } + + + +} \ No newline at end of file diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 0447f21..039f728 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -6,12 +6,14 @@ import androidx.compose.ui.unit.dp import model.graph.Graph import model.graph.Edge import model.graph.Vertex +import viewmodel.algos.BridgeFinderViewModel class GraphViewModel( var graph: Graph, ) { + val verticesView: HashMap = hashMapOf() init { graph.getVertices().forEach { vertex -> @@ -19,7 +21,7 @@ class GraphViewModel( } } - private val edgesView: HashMap = hashMapOf() + val edgesView: HashMap = hashMapOf() init { graph.getEdges().forEach { edge -> val fst = verticesView[graph.vertices[edge.vertices.first]] From eb1c19967a0637482c7fd0e4fefc9df858396007 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Wed, 29 May 2024 23:25:00 +0000 Subject: [PATCH 184/211] feat: add readme [WIP] --- README.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ed6f38 --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ + +# ZeitNot - Graph Analyzer App + Это приложение позволяет выделять сообщества, находить ключевые вершины и делать раскладку направленных и ненаправленных, взвешенных и не взвешенных графов. Также поддерживается набор алгоритмов для анализа графа, в него входят алгоритм Форда-Беллмана, алгоритм Дейкстры и другие. + Приложение поддерживает сохранение в хранилища `SQL`, `CSV`, И `Neo4J` + + +## Установка и запуск + Приложение работает на Java SDK 21 версии. + +- Установка: + +``` +git@github.com:spbu-coding-2023/graphs-graph-7.git``` +``` +- Запуск: + + +#### Linux + +``` +./gradlew run +``` + + + + + + + + + + +## Раскладка графа + Для раскладки графа используется алгоритм [ForceAtlas2](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0098679). + + +## SQLite + Приложение может читать два типа баз данных. + При этом сохраняются все базы данных во второй тип + + 1) Необработанный граф. Две таблицы -- на ребра и вершины графа + + +### Vertices + +| id | data | community | +|--|--|--| +| *integer* | *text* | -1 | +`id` -- уникальный идентификационный номер +`data` -- информация, хранимая в вершине +`community` -- информация о том, находится ли вершина в сообществе. Изначально равняется `-1`, после выполнения алгоритма кластеризации, равняется номеру сообщества +### Edges + +| id | first | second | weight | +|--|--|--| -- | +| *integer* | *int* | *int* |*Long* | + + `id` -- уникальный идентификационный номер + `first` -- **id** первой вершины, в случае направленного графа, считается началом ребра + `second` --**id** второй вершины, в случае направленного графа, считается концом ребра + `weight` -- вес ребра. В случае не взвешенного графа, у всех ребер он равен единице + +2. Обработанный граф. В таком случае должна быть третья таблица, а в таблице **Vertices** в поле **community** вместо -1 могут стоять непосредственно номера community + +### _**VerticesView**_ + +| id| vertex | x | y| color | +|--|--|--|--|--| +| *integer* | *int* | *double*| *double*| *text*| + + `id` -- уникальный идентификационный номер + + `vertex`- **id** вершины из таблицы **Vertices** + + `x, y` -- координаты вершины + + `color` -- цвет формата RGB в следующем виде "r:g:b", где r,g,b - float. + + +--------- +[WIP] From 6d66fba3e74a60e3a6e97e3ace8949e05354df65 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Wed, 29 May 2024 23:27:53 +0000 Subject: [PATCH 185/211] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ed6f38..be7d07a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - Установка: ``` -git@github.com:spbu-coding-2023/graphs-graph-7.git``` +git@github.com:spbu-coding-2023/graphs-graph-7.git ``` - Запуск: @@ -76,6 +76,7 @@ git@github.com:spbu-coding-2023/graphs-graph-7.git``` `color` -- цвет формата RGB в следующем виде "r:g:b", где r,g,b - float. +Сохраненные графы находятся в `/saves/sqlite/` --------- [WIP] From 52afe9b4ec371dcc6282005885d380403a54834c Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Wed, 29 May 2024 23:33:42 +0000 Subject: [PATCH 186/211] feat: add small guide for SQL --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index be7d07a..80fe264 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,16 @@ git@github.com:spbu-coding-2023/graphs-graph-7.git `color` -- цвет формата RGB в следующем виде "r:g:b", где r,g,b - float. -Сохраненные графы находятся в `/saves/sqlite/` + ### Как открыть граф? (SQL) + +Cохраненные графы находятся в `/saves/sqlite/` +Для загрузки базы данных из данной директории, выберите в меню загрузки формат SQL и укажите название графа. Для запуска примера напишите +``` +Shelbiks.db +``` + +### Как сохранить граф? (SQL) +Сохранение происходит в меню сохранения. Достаточно выбрать формать SQL и указать название графа в формате `name.db` --------- [WIP] From 87cb974d3022b51f1dc51f4d77a4e5fe3e815a1e Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Wed, 29 May 2024 23:34:20 +0000 Subject: [PATCH 187/211] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80fe264..38aa11a 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Shelbiks.db ``` ### Как сохранить граф? (SQL) -Сохранение происходит в меню сохранения. Достаточно выбрать формать SQL и указать название графа в формате `name.db` +Сохранение происходит в меню сохранения. Достаточно выбрать формать SQL и указать название графа в формате `name.db`. Граф будет сохранен в `/saves/sqlite/` --------- [WIP] From d9a4df851ac764996a186c3fd4e5e116c55557e1 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 23:44:07 +0000 Subject: [PATCH 188/211] fix: remove redundant buttons --- saves/sqlite/Test.db | Bin 0 -> 20480 bytes saves/sqlite/Test1.db | Bin 0 -> 20480 bytes src/main/kotlin/view/CanvasView.kt | 20 ++------------------ src/main/kotlin/view/NavigationDrawer.kt | 19 +------------------ 4 files changed, 3 insertions(+), 36 deletions(-) create mode 100644 saves/sqlite/Test.db create mode 100644 saves/sqlite/Test1.db diff --git a/saves/sqlite/Test.db b/saves/sqlite/Test.db new file mode 100644 index 0000000000000000000000000000000000000000..78e6004f72f094765a1547d7c65242ebbf09879e GIT binary patch literal 20480 zcmeI3Uuav`9mnrE=jxvOM>BH8t?4_fHF-k`%-B#8=52b8Sx^#JHVU$t|Lp$f* zBcr=zR-x=6<6Mx>SLge^zk7Zk-D|k^)$)V$rFzjmQ>ktg>UKg2DgY?=*|wr6Dtr0Z ztGOX2_*`=XO|i?UDo2*T9bf^~{}qLn=|JEH6LOOTBmqf45|9KW0ZBj-kOU-wyN|$? zH5EsOhry#(z3`p$#goNqy|h}aoh%hEwrbyOE>9>`XSFo=fNK zrCerVCU@FCo<42QoX9U`vTVPFbT&U`Kg22*w|LUdo|vB>v$yP{izj%srCfS8vz%GX z+S$dXxxJfN-OXIBoUc^vlQX&5ug~O0;>l#RrR?ltb~&G$;fpwPZl$%26?c6rE3BJi zi@9`WF6(qL;?76yT>4l#m(I?nmv`D{okwl9?4#-VG-H!Xv)Y;2JfAwTbd=+2PDQV5 zA{>cCz@r%lb9(J;vF7|xJz$-wFG_UiOsQI{549j2sufo&<+awSi^bB}^}2n3X3inM z1K3N#Iqr&6?>`BM<9ta3WA>d6=`Q#V#}u7>$%96hpcc939&p;BUb}Ff-6*friWfGE zWpf7!|E0en{V=f2Oa{-_Ymj4SJnEMt?}R>3ON54i> z^j><1_R#@H4X1QGYZn4@h_Nhu2m@iez4Q#7Q2xKY^bFZpI!2I?q3mbd5pD&fS z8|EONUfN`T7iky+d^)$y%k}eeGu8U~X0_q(QO>9tDC>cuU9q-wT9Nk*PB9Gn2(c4>*Qk+X&ro=Kw5~838V%27)KiA zV+>h@7jgT8R)D{8`-6tR*&oD~+aEN|o&KO@*XX#V)8of%d&@Eb_Mfy$pAbSSjt29Xu(*tyXc2bi)1@Ia9nEZ{rN8Ti_k>9Z= z0iGw%ke`uj>{);xkcaOUTymX~fFvLZNCJ|8Bp?Y$0+N6vAPGnU|4RaR)W^PSZjdmJ zIwBOtBaR4De8>^B3mT35dJ+gwB>8c0?$wcX9#3)Tehi zigqDAE^2e{G+(*4d93HWr&Renu3U1e#y;VM(pbypdh zj$Nf|y5=Z^HQnbZAM)v{qaac-;_C(o>Cla-Py=o&&i%g`R@i<2)3i>H(H?S}yht7+ z-y-7#2Hp((Jg^mbATZ$n$p2ga6aF=S(%!x+xx?~lt<5tXynEy22H(xcM zGq0JCm<4mrJi>~~O%jjT8*9&v5N(t1aEkpL&6Edzr$&db5J-Gehhm(&aiM)colrZ;~Wr97`_BP_c;57 zW5P}FzQ-97jsc6{4<2Wqa02iG_?5@8g@fSZ;F8DLE1VE~8wNbi9^pV%ZOh{f3a0~M z2tCe#aJmqJF^|(P91RAL*Xa|E&ic9S*{4@HKKN5`*5mXD#}7||KYE;qa0vW9c-`Z4 z3#StWVPC6rxXX1G5PS>#l{xX$L~?w3D$dT6*yMO>Y9hhqL_Cp}J@7=k^kKtIFJSly z_<*Hbpxog^IjoB~WY?CjZF~%iwRD0{!7D7j``&)DY-hzmQ+dzSC?FApa?OYFS;y}bz_!kGt?(u&C^kLrU literal 0 HcmV?d00001 diff --git a/saves/sqlite/Test1.db b/saves/sqlite/Test1.db new file mode 100644 index 0000000000000000000000000000000000000000..0566ed877ffcea9b8ee1cdba93b7c8b9fd523198 GIT binary patch literal 20480 zcmeI3Ux*t;9LINNHapq;o8&Gblv-F0iWi!zx%@vtG`()mXf8STa+N-%>D{&$d$;kD zT-!rbTH41JUn=xL`d~#t1cmydXdeUx6-1;yh}K61DT4UmgNie|dnM5}Db$zhZy`6| z{mplO^PA7?K5R0#_*A9UGqt1b&U&+_Wu&l#ko1_QNs>hP$HPC{hd7tFPk4*^^qnM; z_AVX{@?JUch{P=RK=29|Z~y@y00e*l5C8%|00;m9AaMT?II|+t`0m~4oWIvRvSuDM zJH6Jj**(}YPxfoitf80cx>hgktLR#Pk2cv_(aP1jKBpVnf>E9?8Hcnd^+Q@|sa`8r z`E~PpwVu>Y@XY2Z;nb>2l}b`OrR}dRiEImoK3iTa*Q#2zw%xfktg|z$bGg0N?q~-~ z#_Z!IV=|q~CHm6N)~btjqa=zrdc4s;jfPWSqrqo$pl0ahxvD*jNhhAr4E=y^=+#+$ z@z(VD%o7?fd%s@MIU7Ugxy!S45n5Wr zq7z43oo;WU59vhLTy9${{h^a)>)2{f+gF~m$=?DzNWvbsVdwiN0e75xM3B^OH>6YW zZN_wGa*u;17O)cEvj-irsdqQl_=|F*Yi?|s7Qe{{PszYa{H=4+YOb3}er4h`Lo~i? z7dpK$_`tXi4j#y|eTUuklCCs+&51kRz02+O^-ZhQ+j5rNUCV@cH;=IgCH5=(k$uO$ zVjr{j*xT$1yTs13vuum4u?BmZ)z}<+loi-R+zJN}00KY&2mk>f00e*l5C8%|00;nq z|0)3`CQA$zh!PcTo+#s@%@Jixv{|A=M4KT>ShQ)PFwssEe@K>gAfw$~ZCcnL6eo*T z>shmd)qpI;P^HzjF!jq)1eM#^=aZ#4s%$NDv#N^zddu3vKCcKbZ1V4Yu$S_%*Vt-W zK80sfOP${8X2Ew3yrPqbGpmGBF_<>vAB2_NQeZ^>Hem?wQm==y4V zz1bD-|Abwa*e~n{-oOC_fB+Bx0zd!=00AHX1b_e#00KY&2;46O!i4Nb+uH}kZk(8k zNgUZ5HDUoocHQcXIluqw68nw)%)bG+!LGB<*++a2z&q>>cA33w?*e#^by$lX=KBDu zOut_sK%GDU2mk>f00e*l5C8%|00;m9AOHmZWdbzj;r}+ThN3iTi%67?+ak*7m@Qb0 zMr<+8XxNF2QRavU4cQ{hXwViRLIaKnQokbt)aM94RUP4@UPq{uI>Jj8TM!+y)e?A9CJ$v;TO?cBTI?6ZifCq?{arR6qpjlrbN|z8bz*W(z)zRDxD0w?ijj> zUK{0}Vs7CwzKTwaEPN{D+A;nHy)x3C47#=WIP#0!J{)<#b$jtybZw;D@4BNnkFIj} zP%2YCw{U{5p$nr6SKZ`c^gFsVGP&1HuHa{+KL?X%`AX%A#SCAde9^vJ@=59@58~(1 z7u-IaisHHh_#*mjq}$`VBX}oze^lW~*>#Vj8|agfZsNMf(6{K#k#6j|{rIxIK0{|Y Rg&g-h#b2Who_qN7_7|DjH!T1F literal 0 HcmV?d00001 diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 139e876..d109fcc 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -185,26 +185,10 @@ fun Canvas(viewModel: CanvasViewModel) { ) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } - Text("TOP G GANG", modifier = Modifier.padding(16.dp)) + Text("Menu", modifier = Modifier.padding(16.dp)) } Divider() - NavigationDrawerItem( - label = { Text("Menu Item 1") }, - modifier = Modifier.padding(10.dp), - onClick = { scope.launch { drawerState.close() } }, - selected = false - ) - NavigationDrawerItem( - label = { Text(text = "Настройки") }, - icon = { - Icon( - Icons.Filled.Settings, - contentDescription = null - ) - }, - selected = false, - onClick = { /*TODO*/ } - ) + NavigationDrawerItem( label = { Text(text = "Доступные алгоритмы") }, icon = { diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index 1553ca9..c2b770f 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -46,26 +46,9 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { ) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } - Text("TOP G GANG", modifier = Modifier.padding(16.dp)) + Text("Menu", modifier = Modifier.padding(16.dp)) } Divider() - NavigationDrawerItem( - label = { Text("Menu Item 1") }, - modifier = Modifier.padding(10.dp), - onClick = { scope.launch { drawerState.close() } }, - selected = false - ) - NavigationDrawerItem( - label = { Text(text = "Настройки") }, - icon = { - Icon( - Icons.Filled.Settings, - contentDescription = null - ) - }, - selected = false, - onClick = { /*TODO*/ } - ) NavigationDrawerItem( label = { Text(text = "Доступные алгоритмы") }, icon = { From 0366d240e6c0442bce0f2d3cd2f7fdd6873e877c Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Wed, 29 May 2024 23:44:44 +0000 Subject: [PATCH 189/211] fix: remove redundant buttons --- saves/sqlite/Test.db | Bin 20480 -> 0 bytes saves/sqlite/Test1.db | Bin 20480 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 saves/sqlite/Test.db delete mode 100644 saves/sqlite/Test1.db diff --git a/saves/sqlite/Test.db b/saves/sqlite/Test.db deleted file mode 100644 index 78e6004f72f094765a1547d7c65242ebbf09879e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeI3Uuav`9mnrE=jxvOM>BH8t?4_fHF-k`%-B#8=52b8Sx^#JHVU$t|Lp$f* zBcr=zR-x=6<6Mx>SLge^zk7Zk-D|k^)$)V$rFzjmQ>ktg>UKg2DgY?=*|wr6Dtr0Z ztGOX2_*`=XO|i?UDo2*T9bf^~{}qLn=|JEH6LOOTBmqf45|9KW0ZBj-kOU-wyN|$? zH5EsOhry#(z3`p$#goNqy|h}aoh%hEwrbyOE>9>`XSFo=fNK zrCerVCU@FCo<42QoX9U`vTVPFbT&U`Kg22*w|LUdo|vB>v$yP{izj%srCfS8vz%GX z+S$dXxxJfN-OXIBoUc^vlQX&5ug~O0;>l#RrR?ltb~&G$;fpwPZl$%26?c6rE3BJi zi@9`WF6(qL;?76yT>4l#m(I?nmv`D{okwl9?4#-VG-H!Xv)Y;2JfAwTbd=+2PDQV5 zA{>cCz@r%lb9(J;vF7|xJz$-wFG_UiOsQI{549j2sufo&<+awSi^bB}^}2n3X3inM z1K3N#Iqr&6?>`BM<9ta3WA>d6=`Q#V#}u7>$%96hpcc939&p;BUb}Ff-6*friWfGE zWpf7!|E0en{V=f2Oa{-_Ymj4SJnEMt?}R>3ON54i> z^j><1_R#@H4X1QGYZn4@h_Nhu2m@iez4Q#7Q2xKY^bFZpI!2I?q3mbd5pD&fS z8|EONUfN`T7iky+d^)$y%k}eeGu8U~X0_q(QO>9tDC>cuU9q-wT9Nk*PB9Gn2(c4>*Qk+X&ro=Kw5~838V%27)KiA zV+>h@7jgT8R)D{8`-6tR*&oD~+aEN|o&KO@*XX#V)8of%d&@Eb_Mfy$pAbSSjt29Xu(*tyXc2bi)1@Ia9nEZ{rN8Ti_k>9Z= z0iGw%ke`uj>{);xkcaOUTymX~fFvLZNCJ|8Bp?Y$0+N6vAPGnU|4RaR)W^PSZjdmJ zIwBOtBaR4De8>^B3mT35dJ+gwB>8c0?$wcX9#3)Tehi zigqDAE^2e{G+(*4d93HWr&Renu3U1e#y;VM(pbypdh zj$Nf|y5=Z^HQnbZAM)v{qaac-;_C(o>Cla-Py=o&&i%g`R@i<2)3i>H(H?S}yht7+ z-y-7#2Hp((Jg^mbATZ$n$p2ga6aF=S(%!x+xx?~lt<5tXynEy22H(xcM zGq0JCm<4mrJi>~~O%jjT8*9&v5N(t1aEkpL&6Edzr$&db5J-Gehhm(&aiM)colrZ;~Wr97`_BP_c;57 zW5P}FzQ-97jsc6{4<2Wqa02iG_?5@8g@fSZ;F8DLE1VE~8wNbi9^pV%ZOh{f3a0~M z2tCe#aJmqJF^|(P91RAL*Xa|E&ic9S*{4@HKKN5`*5mXD#}7||KYE;qa0vW9c-`Z4 z3#StWVPC6rxXX1G5PS>#l{xX$L~?w3D$dT6*yMO>Y9hhqL_Cp}J@7=k^kKtIFJSly z_<*Hbpxog^IjoB~WY?CjZF~%iwRD0{!7D7j``&)DY-hzmQ+dzSC?FApa?OYFS;y}bz_!kGt?(u&C^kLrU diff --git a/saves/sqlite/Test1.db b/saves/sqlite/Test1.db deleted file mode 100644 index 0566ed877ffcea9b8ee1cdba93b7c8b9fd523198..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeI3Ux*t;9LINNHapq;o8&Gblv-F0iWi!zx%@vtG`()mXf8STa+N-%>D{&$d$;kD zT-!rbTH41JUn=xL`d~#t1cmydXdeUx6-1;yh}K61DT4UmgNie|dnM5}Db$zhZy`6| z{mplO^PA7?K5R0#_*A9UGqt1b&U&+_Wu&l#ko1_QNs>hP$HPC{hd7tFPk4*^^qnM; z_AVX{@?JUch{P=RK=29|Z~y@y00e*l5C8%|00;m9AaMT?II|+t`0m~4oWIvRvSuDM zJH6Jj**(}YPxfoitf80cx>hgktLR#Pk2cv_(aP1jKBpVnf>E9?8Hcnd^+Q@|sa`8r z`E~PpwVu>Y@XY2Z;nb>2l}b`OrR}dRiEImoK3iTa*Q#2zw%xfktg|z$bGg0N?q~-~ z#_Z!IV=|q~CHm6N)~btjqa=zrdc4s;jfPWSqrqo$pl0ahxvD*jNhhAr4E=y^=+#+$ z@z(VD%o7?fd%s@MIU7Ugxy!S45n5Wr zq7z43oo;WU59vhLTy9${{h^a)>)2{f+gF~m$=?DzNWvbsVdwiN0e75xM3B^OH>6YW zZN_wGa*u;17O)cEvj-irsdqQl_=|F*Yi?|s7Qe{{PszYa{H=4+YOb3}er4h`Lo~i? z7dpK$_`tXi4j#y|eTUuklCCs+&51kRz02+O^-ZhQ+j5rNUCV@cH;=IgCH5=(k$uO$ zVjr{j*xT$1yTs13vuum4u?BmZ)z}<+loi-R+zJN}00KY&2mk>f00e*l5C8%|00;nq z|0)3`CQA$zh!PcTo+#s@%@Jixv{|A=M4KT>ShQ)PFwssEe@K>gAfw$~ZCcnL6eo*T z>shmd)qpI;P^HzjF!jq)1eM#^=aZ#4s%$NDv#N^zddu3vKCcKbZ1V4Yu$S_%*Vt-W zK80sfOP${8X2Ew3yrPqbGpmGBF_<>vAB2_NQeZ^>Hem?wQm==y4V zz1bD-|Abwa*e~n{-oOC_fB+Bx0zd!=00AHX1b_e#00KY&2;46O!i4Nb+uH}kZk(8k zNgUZ5HDUoocHQcXIluqw68nw)%)bG+!LGB<*++a2z&q>>cA33w?*e#^by$lX=KBDu zOut_sK%GDU2mk>f00e*l5C8%|00;m9AOHmZWdbzj;r}+ThN3iTi%67?+ak*7m@Qb0 zMr<+8XxNF2QRavU4cQ{hXwViRLIaKnQokbt)aM94RUP4@UPq{uI>Jj8TM!+y)e?A9CJ$v;TO?cBTI?6ZifCq?{arR6qpjlrbN|z8bz*W(z)zRDxD0w?ijj> zUK{0}Vs7CwzKTwaEPN{D+A;nHy)x3C47#=WIP#0!J{)<#b$jtybZw;D@4BNnkFIj} zP%2YCw{U{5p$nr6SKZ`c^gFsVGP&1HuHa{+KL?X%`AX%A#SCAde9^vJ@=59@58~(1 z7u-IaisHHh_#*mjq}$`VBX}oze^lW~*>#Vj8|agfZsNMf(6{K#k#6j|{rIxIK0{|Y Rg&g-h#b2Who_qN7_7|DjH!T1F From 169d03f6cd59fc18a442a3eb3c7d1d385e97ff26 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Thu, 30 May 2024 20:26:11 +0000 Subject: [PATCH 190/211] fix: delete bad exceptions --- src/main/kotlin/model/graph/Graph.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/model/graph/Graph.kt b/src/main/kotlin/model/graph/Graph.kt index a3cf318..55a221c 100644 --- a/src/main/kotlin/model/graph/Graph.kt +++ b/src/main/kotlin/model/graph/Graph.kt @@ -17,10 +17,10 @@ class Graph{ fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { if (!isDirected){ - vertices[secondVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("cringe") + vertices[secondVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("Wrong database") vertices[secondVertexID]?.adjacentVertices?.add(vertices[firstVertexID]!!) } - vertices[firstVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("cringe") + vertices[firstVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("Wrong database") vertices[firstVertexID]?.adjacentVertices?.add(vertices[secondVertexID]!!) return edges.getOrPut(edgeID) { Edge(Pair(firstVertexID,secondVertexID), weight, edgeID) } From a7bb01aadd6cc6404e812124cacb9192aa4b3664 Mon Sep 17 00:00:00 2001 From: suvorovrain Date: Thu, 30 May 2024 21:19:31 +0000 Subject: [PATCH 191/211] fix: format code --- src/main/kotlin/Main.kt | 268 +----------------- .../controller/GraphPainterByCommunity.kt | 2 +- .../controller/GraphPainterByDjikstra.kt | 16 +- .../controller/GraphPainterByKosaraju.kt | 2 +- .../kotlin/model/algorithms/BridgeFinder.kt | 46 ++- src/main/kotlin/model/algorithms/Djikstra.kt | 8 +- .../kotlin/model/algorithms/FindCycles.kt | 14 +- .../kotlin/model/algorithms/FordBellman.kt | 21 +- src/main/kotlin/model/algorithms/Kosaraju.kt | 2 +- .../model/algorithms/KruskalsAlgorithm.kt | 10 +- .../TarjanStrongConnecedComponent.kt | 3 +- .../model/databases/sqlite/SQLiteDBHandler.kt | 4 +- .../model/databases/sqlite/dao/edge/Edge.kt | 3 +- .../model/databases/sqlite/dao/edge/Edges.kt | 2 +- .../databases/sqlite/dao/vertices/Vertices.kt | 2 +- .../sqlite/dao/verticesView/VerticesView.kt | 2 +- src/main/kotlin/model/graph/Edge.kt | 6 +- src/main/kotlin/model/graph/Graph.kt | 8 +- src/main/kotlin/model/graph/Vertex.kt | 4 +- src/main/kotlin/view/AlgorithmSubMenu.kt | 2 +- src/main/kotlin/view/CanvasView.kt | 21 +- src/main/kotlin/view/CustomRadioView.kt | 23 +- src/main/kotlin/view/LoadGraphMenu.kt | 60 ++-- src/main/kotlin/view/MainScreen.kt | 37 --- src/main/kotlin/view/NavigationDrawer.kt | 13 +- src/main/kotlin/view/graph/EdgeView.kt | 12 - src/main/kotlin/view/graph/GraphView.kt | 5 +- src/main/kotlin/view/graph/VertexView.kt | 2 +- src/main/kotlin/viewmodel/CanvasViewModel.kt | 4 +- .../viewmodel/LoadGraphMenuViewModel.kt | 3 - .../kotlin/viewmodel/graph/GraphViewModel.kt | 9 +- .../layouts}/ForceAtlas2Layout.kt | 27 +- .../kotlin/viewmodel/layouts/TsNETLayout.kt | 4 - 33 files changed, 168 insertions(+), 477 deletions(-) delete mode 100644 src/main/kotlin/view/MainScreen.kt rename src/main/kotlin/{model/layout => viewmodel/layouts}/ForceAtlas2Layout.kt (70%) delete mode 100644 src/main/kotlin/viewmodel/layouts/TsNETLayout.kt diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index e1f2d3b..9352508 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.window.application import androidx.compose.ui.window.rememberWindowState import model.graph.Graph -import model.layout.ForceAtlas2Layout +import viewmodel.layouts.ForceAtlas2Layout import view.Canvas import viewmodel.CanvasViewModel @@ -66,271 +66,7 @@ val graph = Graph().apply { addEdge(20, 15, 5,19) addEdge(17, 20, 0,20) addEdge(14, 20, 0,21) -// addVertex(1,"1") -// addVertex(2,"2") -// addVertex(3,"3") -// addVertex(4,"4") -// addVertex(5,"5") -// addVertex(6,"6") -// addVertex(7,"7") -// addVertex(8,"8") -// addVertex(9,"9") -// addVertex(10,"10") -// addVertex(11,"11") -// addVertex(12,"12") -// addVertex(13,"13") -// addVertex(14,"14") -// addVertex(15,"15") -// addVertex(16,"16") -// addVertex(17,"17") -// addVertex(18,"18") -// addVertex(19,"19") -// addVertex(20,"20") -// addVertex(21,"21") -// addVertex(22,"22") -// addVertex(23,"23") -// addVertex(24,"24") -// addVertex(25,"25") -// addVertex(26,"26") -// addVertex(27,"27") -// addVertex(28,"28") -// addVertex(29,"29") -// addVertex(30,"30") -// addVertex(31,"31") -// addVertex(32,"32") -// addVertex(33,"33") -// addVertex(34,"34") -// addVertex(35,"35") -// addVertex(36,"36") -// addVertex(37,"37") -// addVertex(38,"38") -// addVertex(39,"39") -// addVertex(40,"40") -// addVertex(41,"41") -// addVertex(42,"42") -// addVertex(43,"43") -// addVertex(44,"44") -// addVertex(45,"45") -// addVertex(46,"46") -// addVertex(47,"47") -// addVertex(48,"48") -// addVertex(49,"49") -// addVertex(50,"50") -// addVertex(51,"51") -// addVertex(52,"52") -// addVertex(53,"53") -// addVertex(54,"54") -// addVertex(55,"55") -// addVertex(56,"56") -// addVertex(57,"57") -// addVertex(58,"58") -// addVertex(59,"59") -// addVertex(60,"60") -// addVertex(61,"61") -// addVertex(62,"62") -// addVertex(63,"63") -// addVertex(64,"64") -// addVertex(65,"65") -// addVertex(66,"66") -// addVertex(67,"67") -// addVertex(68,"68") -// addVertex(69,"69") -// addVertex(70,"70") -// addVertex(71,"71") -// addVertex(72,"72") -// addVertex(73,"73") -// addVertex(74,"74") -// addVertex(75,"75") -// addVertex(76,"76") -// addVertex(77,"77") -// addVertex(78,"78") -// addVertex(79,"79") -// addVertex(80,"80") -// addVertex(81,"81") -// addVertex(82,"82") -// addVertex(83,"83") -// addVertex(84,"84") -// addVertex(85,"85") -// addVertex(86,"86") -// addVertex(87,"87") -// addVertex(88,"88") -// addVertex(89,"89") -// addVertex(90,"90") -// addVertex(91,"91") -// addVertex(92,"92") -// addVertex(93,"93") -// addVertex(94,"94") -// addVertex(95,"95") -// addVertex(96,"96") -// addVertex(97,"97") -// addVertex(98,"98") -// addVertex(99,"99") -// addVertex(100,"100") -// addEdge(74,14,59,1) -// addEdge(93,86,82,2) -// addEdge(73,67,20,3) -// addEdge(7,27,20,4) -// addEdge(30,6,19,5) -// addEdge(90,64,96,6) -// addEdge(4,39,0,7) -// addEdge(33,80,6,8) -// addEdge(82,42,98,9) -// addEdge(9,21,93,10) -// addEdge(34,13,63,11) -// addEdge(84,93,49,12) -// addEdge(68,78,97,13) -// addEdge(25,82,59,14) -// addEdge(66,85,38,15) -// addEdge(91,56,45,16) -// addEdge(42,64,79,17) -// addEdge(14,66,64,18) -// addEdge(98,2,0,19) -// addEdge(82,35,61,20) -// addEdge(72,10,8,21) -// addEdge(62,63,52,22) -// addEdge(11,36,89,23) -// addEdge(91,62,75,24) -// addEdge(2,24,18,25) -// addEdge(89,80,68,26) -// addEdge(43,84,25,27) -// addEdge(91,48,11,28) -// addEdge(63,26,51,29) -// addEdge(38,58,42,30) -// addEdge(24,15,61,31) -// addEdge(48,88,7,32) -// addEdge(65,38,23,33) -// addEdge(70,51,34,34) -// addEdge(33,38,82,35) -// addEdge(14,13,61,36) -// addEdge(74,54,72,37) -// addEdge(100,87,22,38) -// addEdge(34,24,23,39) -// addEdge(8,100,9,40) -// addEdge(37,4,24,41) -// addEdge(19,21,39,42) -// addEdge(41,60,37,43) -// addEdge(20,67,6,44) -// addEdge(99,52,82,45) -// addEdge(67,30,99,46) -// addEdge(10,45,70,47) -// addEdge(5,47,66,48) -// addEdge(87,74,21,49) -// addEdge(65,29,33,50) -// addEdge(38,37,86,51) -// addEdge(17,68,63,52) -// addEdge(72,73,73,53) -// addEdge(24,52,74,54) -// addEdge(49,42,56,55) -// addEdge(38,4,24,56) -// addEdge(18,63,46,57) -// addEdge(46,77,69,58) -// addEdge(94,16,15,59) -// addEdge(27,50,29,60) -// addEdge(91,24,30,61) -// addEdge(97,46,89,62) -// addEdge(59,77,37,63) -// addEdge(48,95,64,64) -// addEdge(91,11,47,65) -// addEdge(33,37,6,66) -// addEdge(75,89,4,67) -// addEdge(96,87,21,68) -// addEdge(58,61,58,69) -// addEdge(71,47,92,70) -// addEdge(50,96,40,71) -// addEdge(45,63,45,72) -// addEdge(60,48,79,73) -// addEdge(95,90,75,74) -// addEdge(91,15,58,75) -// addEdge(90,53,97,76) -// addEdge(97,14,46,77) -// addEdge(90,57,4,78) -// addEdge(8,51,72,79) -// addEdge(7,42,44,80) -// addEdge(46,22,64,81) -// addEdge(18,72,54,82) -// addEdge(12,71,68,83) -// addEdge(22,10,94,84) -// addEdge(6,100,89,85) -// addEdge(6,87,27,86) -// addEdge(79,46,84,87) -// addEdge(42,87,23,88) -// addEdge(58,81,81,89) -// addEdge(45,67,91,90) -// addEdge(27,58,93,91) -// addEdge(8,1,47,92) -// addEdge(46,59,74,93) -// addEdge(58,90,23,94) -// addEdge(82,81,29,95) -// addEdge(25,30,17,96) -// addEdge(79,21,49,97) -// addEdge(100,28,17,98) -// addEdge(57,85,1,99) -// addEdge(51,3,37,100) -// addEdge(41,54,30,101) -// addEdge(27,1,41,102) -// addEdge(42,89,47,103) -// addEdge(85,40,57,104) -// addEdge(13,46,26,105) -// addEdge(53,51,51,106) -// addEdge(17,45,95,107) -// addEdge(28,83,50,108) -// addEdge(72,15,10,109) -// addEdge(30,47,47,110) -// addEdge(32,43,41,111) -// addEdge(17,84,46,112) -// addEdge(32,66,62,113) -// addEdge(66,82,79,114) -// addEdge(21,36,48,115) -// addEdge(19,32,73,116) -// addEdge(77,83,59,117) -// addEdge(22,24,66,118) -// addEdge(63,10,54,119) -// addEdge(20,44,38,120) -// addEdge(19,17,25,121) -// addEdge(28,51,19,122) -// addEdge(67,8,68,123) -// addEdge(3,81,47,124) -// addEdge(88,93,13,125) -// addEdge(89,79,56,126) -// addEdge(44,89,97,127) -// addEdge(92,29,58,128) -// addEdge(47,52,68,129) -// addEdge(70,52,34,130) -// addEdge(76,95,4,131) -// addEdge(75,69,88,132) -// addEdge(57,97,33,133) -// addEdge(67,31,8,134) -// addEdge(11,15,50,135) -// addEdge(51,89,89,136) -// addEdge(9,71,67,137) -// addEdge(8,11,57,138) -// addEdge(3,53,13,139) -// addEdge(84,67,42,140) -// addEdge(37,76,74,141) -// addEdge(41,68,33,142) -// addEdge(89,12,66,143) -// addEdge(41,56,88,144) -// addEdge(96,96,3,145) -// addEdge(14,34,47,146) -// addEdge(80,73,99,147) -// addEdge(20,84,11,148) -// addEdge(68,30,58,149) -// addEdge(91,32,57,150) -// addEdge(64,44,31,151) -// addEdge(89,92,18,152) -// addEdge(38,72,40,153) -// addEdge(44,70,99,154) -// addEdge(57,13,98,155) -// addEdge(46,76,58,156) -// addEdge(10,8,98,157) -// addEdge(75,37,89,158) -// addEdge(64,21,38,159) -// addEdge(60,29,19,160) -// addEdge(91,73,84,161) -// addEdge(33,76,55,162) -// addEdge(32,34,51,163) -// addEdge(68,48,35,164) -// addEdge(51,63,24,165) + } val windowSizeStart = Pair(820,640) @Composable diff --git a/src/main/kotlin/controller/GraphPainterByCommunity.kt b/src/main/kotlin/controller/GraphPainterByCommunity.kt index 99d4f69..cb55dff 100644 --- a/src/main/kotlin/controller/GraphPainterByCommunity.kt +++ b/src/main/kotlin/controller/GraphPainterByCommunity.kt @@ -13,7 +13,7 @@ class GraphPainterByCommunity(private val graph: Graph, private val graphViewMod val communityColor = generateRandomColor(i * 123) for (vertexID in community) { val currVertex = graph.vertices[vertexID] - graphViewModel.verticesView[currVertex]!!.color=communityColor + graphViewModel.verticesView[currVertex]!!.color = communityColor } } } diff --git a/src/main/kotlin/controller/GraphPainterByDjikstra.kt b/src/main/kotlin/controller/GraphPainterByDjikstra.kt index 721e126..aaff5bd 100644 --- a/src/main/kotlin/controller/GraphPainterByDjikstra.kt +++ b/src/main/kotlin/controller/GraphPainterByDjikstra.kt @@ -4,19 +4,21 @@ import model.algorithms.Djikstra import model.graph.Graph import viewmodel.graph.GraphViewModel -class GraphPainterByDjikstra(private val graph: Graph, - private val graphViewModel: GraphViewModel, - private val startIdx: Int, - private val endIdx: Int) { - private val pathFinder = Djikstra(graph,startIdx) +class GraphPainterByDjikstra( + private val graph: Graph, + private val graphViewModel: GraphViewModel, + private val startIdx: Int, + private val endIdx: Int +) { + private val pathFinder = Djikstra(graph, startIdx) private val path = pathFinder.findShortestPaths() val currPath = pathFinder.reconstructPath(endIdx) fun paint() { val vertexColor = generateRandomColor(startIdx * 123) for (vertexID in currPath) { - val currVertex = graph.vertices[vertexID] - graphViewModel.verticesView[currVertex]!!.color=vertexColor + val currVertex = graph.vertices[vertexID] + graphViewModel.verticesView[currVertex]!!.color = vertexColor } } } \ No newline at end of file diff --git a/src/main/kotlin/controller/GraphPainterByKosaraju.kt b/src/main/kotlin/controller/GraphPainterByKosaraju.kt index f63889e..8154fc5 100644 --- a/src/main/kotlin/controller/GraphPainterByKosaraju.kt +++ b/src/main/kotlin/controller/GraphPainterByKosaraju.kt @@ -13,7 +13,7 @@ class GraphPainterByKosaraju(private val graph: Graph, private val graphViewMode val communityColor = generateRandomColor(i * 123) for (vertexID in component) { val currVertex = graph.vertices[vertexID] - graphViewModel.verticesView[currVertex]!!.color=communityColor + graphViewModel.verticesView[currVertex]!!.color = communityColor } } } diff --git a/src/main/kotlin/model/algorithms/BridgeFinder.kt b/src/main/kotlin/model/algorithms/BridgeFinder.kt index ae466d9..db1515d 100644 --- a/src/main/kotlin/model/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/model/algorithms/BridgeFinder.kt @@ -6,53 +6,51 @@ import kotlin.math.min class BridgeFinder(graph: Graph) { private val arraySize = graph.vertices.size - private val visitedVertices = Array(arraySize) {false} - private val timeIn = Array(arraySize) {-1} - private val fUp = Array(arraySize) {-1} + private val visitedVertices = Array(arraySize) { false } + private val timeIn = Array(arraySize) { -1 } + private val fUp = Array(arraySize) { -1 } val bridges = mutableListOf() private val curGraph = graph - fun findBridges(){ + fun findBridges() { var timer = 0 - fun isBridge(edgeID: Int): Int?{ + fun isBridge(edgeID: Int): Int? { val destination = curGraph.edges[edgeID]?.vertices?.second ?: throw Exception("Incorrect Database") val bridge = curGraph.edges[edgeID] - val bridges = curGraph.vertices[bridge?.vertices?.first]?.incidentEdges ?: throw Exception("Incorrect Database") + val bridges = + curGraph.vertices[bridge?.vertices?.first]?.incidentEdges ?: throw Exception("Incorrect Database") for (curBridge in bridges) { - if (curGraph.edges[curBridge]!!.vertices.second==destination && curBridge!=edgeID){ + if (curGraph.edges[curBridge]!!.vertices.second == destination && curBridge != edgeID) { return null } } return edgeID } - fun dfs(vertexID: Int, parent: Int = -1){ + fun dfs(vertexID: Int, parent: Int = -1) { visitedVertices[vertexID] = true timer++ timeIn[vertexID] = timer fUp[vertexID] = timer - val incidentEdgesID = curGraph.vertices[vertexID+1]!!.incidentEdges - for (edgeID in incidentEdgesID){ + val incidentEdgesID = curGraph.vertices[vertexID + 1]!!.incidentEdges + for (edgeID in incidentEdgesID) { val edge = curGraph.edges[edgeID]!!.vertices - val newVertexID = if (vertexID == edge.first-1){ - edge.second-1 - } - else{ - edge.first-1 + val newVertexID = if (vertexID == edge.first - 1) { + edge.second - 1 + } else { + edge.first - 1 } if (newVertexID == parent) continue - if (visitedVertices[newVertexID]){ + if (visitedVertices[newVertexID]) { fUp[vertexID] = min(timeIn[newVertexID], fUp[vertexID]) - } - - else{ + } else { dfs(newVertexID, vertexID) fUp[vertexID] = min(fUp[newVertexID], fUp[vertexID]) - if(fUp[newVertexID] > timeIn[vertexID]){ - if (isBridge(edgeID)!=null){ + if (fUp[newVertexID] > timeIn[vertexID]) { + if (isBridge(edgeID) != null) { bridges.add(edgeID) } } @@ -60,9 +58,9 @@ class BridgeFinder(graph: Graph) { } } - for (i in 1..arraySize){ - if (!visitedVertices[i-1]){ - dfs(i-1) + for (i in 1..arraySize) { + if (!visitedVertices[i - 1]) { + dfs(i - 1) } } } diff --git a/src/main/kotlin/model/algorithms/Djikstra.kt b/src/main/kotlin/model/algorithms/Djikstra.kt index f310e4d..4945b8a 100644 --- a/src/main/kotlin/model/algorithms/Djikstra.kt +++ b/src/main/kotlin/model/algorithms/Djikstra.kt @@ -22,7 +22,11 @@ class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { var nearest = -1 for ((vertexID, _) in graph.vertices) { - if (!visited.getOrDefault(vertexID, false) && (nearest == -1 || distance[vertexID]!! < distance[nearest]!!)) { + if (!visited.getOrDefault( + vertexID, + false + ) && (nearest == -1 || distance[vertexID]!! < distance[nearest]!!) + ) { nearest = vertexID } } @@ -47,7 +51,7 @@ class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { fun reconstructPath(endVertexID: Int): List { val path = mutableListOf() var finish = endVertexID - if ((n == 0 || startVertexID <= -1) || (endVertexID <= 0))return path + if ((n == 0 || startVertexID <= -1) || (endVertexID <= 0)) return path while (finish != startVertexID) { path.add(finish) diff --git a/src/main/kotlin/model/algorithms/FindCycles.kt b/src/main/kotlin/model/algorithms/FindCycles.kt index a3c67bc..e33106e 100644 --- a/src/main/kotlin/model/algorithms/FindCycles.kt +++ b/src/main/kotlin/model/algorithms/FindCycles.kt @@ -25,7 +25,7 @@ class AllCyclesInDirectedGraphJohnson { val leastVertex: Vertex = maybeLeastVertex blockedSet.clear() blockedMap.clear() - findCyclesInSCG(graph,leastVertex, leastVertex) + findCyclesInSCG(graph, leastVertex, leastVertex) startIndex = leastVertex.id + 1 } else { break @@ -87,7 +87,7 @@ class AllCyclesInDirectedGraphJohnson { stack.push(currentVertex) blockedSet.add(currentVertex) - for (e in graph.edges.filterKeys{it in currentVertex.incidentEdges}.values) { + for (e in graph.edges.filterKeys { it in currentVertex.incidentEdges }.values) { val neighbor: Vertex = graph.vertices[e.vertices.second]!! if (neighbor === startVertex) { val cycle: MutableList = ArrayList() @@ -97,17 +97,16 @@ class AllCyclesInDirectedGraphJohnson { stack.pop() allCycles.add(cycle) foundCycle = true - } - else if (!blockedSet.contains(neighbor)) { + } else if (!blockedSet.contains(neighbor)) { val gotCycle = - findCyclesInSCG(graph,startVertex, neighbor) + findCyclesInSCG(graph, startVertex, neighbor) foundCycle = foundCycle || gotCycle } } if (foundCycle) { unblock(currentVertex) } else { - for (e in graph.edges.filterKeys{it in currentVertex.incidentEdges}.values) { + for (e in graph.edges.filterKeys { it in currentVertex.incidentEdges }.values) { val w: Vertex = graph.vertices[e.vertices.second]!! val bSet: MutableSet = getBSet(w) bSet.add(currentVertex) @@ -118,7 +117,8 @@ class AllCyclesInDirectedGraphJohnson { } private fun getBSet(v: Vertex): MutableSet { - return (blockedMap.computeIfAbsent(v + return (blockedMap.computeIfAbsent( + v ) { HashSet() } as MutableSet?)!! } diff --git a/src/main/kotlin/model/algorithms/FordBellman.kt b/src/main/kotlin/model/algorithms/FordBellman.kt index 26da087..b9e1d5e 100644 --- a/src/main/kotlin/model/algorithms/FordBellman.kt +++ b/src/main/kotlin/model/algorithms/FordBellman.kt @@ -12,8 +12,8 @@ class FordBellman(graph: Graph) { private val pathsLength = Array(verticesNumber) { INF } val pathVertices = Array(verticesNumber) { -1 } val pathEdges = Array(edgesNumber) { -1 } - val resultPathVertices:MutableList = mutableListOf() - val resultPathEdges:MutableList = mutableListOf() + val resultPathVertices: MutableList = mutableListOf() + val resultPathEdges: MutableList = mutableListOf() private val curGraph = graph var disconnectedGraphFlag = false @@ -22,15 +22,14 @@ class FordBellman(graph: Graph) { private fun negativeCycleBuilder(cycleFlag: Int) { var tmpCycleFlag = cycleFlag for (i in 1 until verticesNumber) { - tmpCycleFlag = pathVertices[tmpCycleFlag-1]+1 + tmpCycleFlag = pathVertices[tmpCycleFlag - 1] + 1 } var current = tmpCycleFlag - var cycleEndFlag = true + val cycleEndFlag = true while (cycleEndFlag) { if (current == tmpCycleFlag && resultPathVertices.size > 1) { - cycleEndFlag = false break } resultPathVertices.add(current) @@ -42,7 +41,7 @@ class FordBellman(graph: Graph) { break } } - current = pathVertices[current-1]+1 + current = pathVertices[current - 1] + 1 } } @@ -53,7 +52,7 @@ class FordBellman(graph: Graph) { curCycleFlag = -1 for (j in 0 until edgesNumber) { val firstVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.first - 1] - var secondVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] + val secondVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] if (firstVertexPath < INF) { if (secondVertexPath > firstVertexPath + curGraph.edges[j + 1]!!.weight) { pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] = @@ -74,7 +73,7 @@ class FordBellman(graph: Graph) { pathBuilder(endVertexID) } } else { - cycleFlag=true + cycleFlag = true negativeCycleBuilder(curCycleFlag) } } @@ -85,15 +84,15 @@ class FordBellman(graph: Graph) { do { val destVertexID = tmp val sourceVertexID = pathVertices[tmp - 1] + 1 - for (edgeID:Int in curGraph.vertices[sourceVertexID]!!.incidentEdges) { + for (edgeID: Int in curGraph.vertices[sourceVertexID]!!.incidentEdges) { if (curGraph.edges[edgeID]!!.vertices.second == destVertexID) { resultPathEdges.add(edgeID) break } } resultPathVertices.add(sourceVertexID) - tmp = pathVertices[tmp-1] + 1 - } while (pathVertices[tmp-1] != -1) + tmp = pathVertices[tmp - 1] + 1 + } while (pathVertices[tmp - 1] != -1) } } diff --git a/src/main/kotlin/model/algorithms/Kosaraju.kt b/src/main/kotlin/model/algorithms/Kosaraju.kt index e8e37d6..7856161 100644 --- a/src/main/kotlin/model/algorithms/Kosaraju.kt +++ b/src/main/kotlin/model/algorithms/Kosaraju.kt @@ -32,7 +32,7 @@ class Kosaraju(private val graph: Graph) { return components } - private fun topologySort(graph: Graph, vertexID: Int) { + private fun topologySort(graph: Graph, vertexID: Int) { used[vertexID] = true val vertex = graph.vertices[vertexID] ?: return for (edgeID in vertex.incidentEdges) { diff --git a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt index d2a8c34..9b49011 100644 --- a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt @@ -3,7 +3,7 @@ package model.algorithms import model.graph.Graph import model.graph.Edge -class KruskalsMST { +class KruskalsMST { var resultsId: List = emptyList() internal fun kruskals(graph: Graph) { var j = 0 @@ -11,15 +11,15 @@ class KruskalsMST { val V = graph.getVertices().size if (V == 1 || V == 0) return - val results = arrayOfNulls(V-1) + val results = arrayOfNulls(V - 1) val subsets = arrayOfNulls(V) - for (i in 0 ..< V) { + for (i in 0..) : IntEntity(id){ +class Edge(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(Edges) + var first by Vertex optionalReferencedOn Edges.first var second by Vertex optionalReferencedOn Edges.second var weight by Edges.weight diff --git a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt index d421e13..a60d221 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt @@ -3,7 +3,7 @@ package model.databases.sqlite.dao.edge import model.databases.sqlite.dao.vertices.Vertices import org.jetbrains.exposed.dao.id.IntIdTable -object Edges: IntIdTable("Edges") { +object Edges : IntIdTable("Edges") { val first = reference("first", Vertices).nullable() val second = reference("second", Vertices).nullable() val weight = long("weight") diff --git a/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt index 35a2d02..06f96d1 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt @@ -2,7 +2,7 @@ package model.databases.sqlite.dao.vertices import org.jetbrains.exposed.dao.id.IntIdTable -object Vertices: IntIdTable("Vertices") { +object Vertices : IntIdTable("Vertices") { val data = varchar("data", 255) val community = integer("community") } \ No newline at end of file diff --git a/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt index bea6ab6..255704d 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt @@ -3,7 +3,7 @@ package model.databases.sqlite.dao.verticesView import model.databases.sqlite.dao.vertices.Vertices import org.jetbrains.exposed.dao.id.IntIdTable -object VerticesView: IntIdTable("VerticesView") { +object VerticesView : IntIdTable("VerticesView") { val vertex = reference("vertex", Vertices).nullable() val x = double("x") val y = double("y") diff --git a/src/main/kotlin/model/graph/Edge.kt b/src/main/kotlin/model/graph/Edge.kt index 55de8d4..e3968da 100644 --- a/src/main/kotlin/model/graph/Edge.kt +++ b/src/main/kotlin/model/graph/Edge.kt @@ -1,9 +1,9 @@ package model.graph -class Edge ( +class Edge( val vertices: Pair, var weight: Long = 1L, var id: Int = 1, -){ - fun incident(v: Int) = v == vertices.first || v == vertices.second +) { + //fun incident(v: Int) = v == vertices.first || v == vertices.second } \ No newline at end of file diff --git a/src/main/kotlin/model/graph/Graph.kt b/src/main/kotlin/model/graph/Graph.kt index 55a221c..8fb2db2 100644 --- a/src/main/kotlin/model/graph/Graph.kt +++ b/src/main/kotlin/model/graph/Graph.kt @@ -1,6 +1,6 @@ package model.graph -class Graph{ +class Graph { var isDirected: Boolean = false val vertices = hashMapOf() val edges = hashMapOf() @@ -15,14 +15,14 @@ class Graph{ return vertices.getOrPut(id) { newVertex } } - fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long=1L, edgeID:Int): Edge { - if (!isDirected){ + fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long = 1L, edgeID: Int): Edge { + if (!isDirected) { vertices[secondVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("Wrong database") vertices[secondVertexID]?.adjacentVertices?.add(vertices[firstVertexID]!!) } vertices[firstVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("Wrong database") vertices[firstVertexID]?.adjacentVertices?.add(vertices[secondVertexID]!!) - return edges.getOrPut(edgeID) { Edge(Pair(firstVertexID,secondVertexID), weight, edgeID) } + return edges.getOrPut(edgeID) { Edge(Pair(firstVertexID, secondVertexID), weight, edgeID) } } } diff --git a/src/main/kotlin/model/graph/Vertex.kt b/src/main/kotlin/model/graph/Vertex.kt index d39f50c..ef4b3d2 100644 --- a/src/main/kotlin/model/graph/Vertex.kt +++ b/src/main/kotlin/model/graph/Vertex.kt @@ -3,8 +3,8 @@ package model.graph class Vertex( var data: String, var incidentEdges: MutableList = mutableListOf(), -){ +) { var id: Int = 0 var community: Int = -1 - val adjacentVertices: MutableList = mutableListOf() + val adjacentVertices: MutableList = mutableListOf() } \ No newline at end of file diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index 35c80c6..0bfedb8 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -79,7 +79,7 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { text = "Поиск мостов", ) } - if(bridgesHiglight.value){ + if (bridgesHiglight.value) { bridgeHighlighter(viewModel.bridges) } Button( diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index d109fcc..7380e8a 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -2,16 +2,13 @@ package view import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.background - -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.material.Surface import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu -import androidx.compose.material.icons.filled.Settings + import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf @@ -22,8 +19,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp - import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch @@ -49,8 +44,6 @@ fun Canvas(viewModel: CanvasViewModel) { val uri = remember { mutableStateOf("") } val login = remember { mutableStateOf("") } val password = remember { mutableStateOf("") } - var sqlPath = remember { mutableStateOf("") } - val interactionSource = remember { MutableInteractionSource() } AnimatedVisibility(visible = showDialog.value) { Dialog( @@ -63,7 +56,11 @@ fun Canvas(viewModel: CanvasViewModel) { Text("Choose where to save the graph:") CustomRadioGroup( selectedOption = storageType.value.toString(), - options = listOf(StorageType.FILE.toString(), StorageType.NEO4J.toString(), StorageType.SQLITE.toString()), + options = listOf( + StorageType.FILE.toString(), + StorageType.NEO4J.toString(), + StorageType.SQLITE.toString() + ), onOptionSelected = { storageType.value = StorageType.valueOf(it) } ) @@ -88,6 +85,7 @@ fun Canvas(viewModel: CanvasViewModel) { ) Spacer(modifier = Modifier.width(8.dp)) } + StorageType.NEO4J -> { TextField( value = uri.value, @@ -119,6 +117,7 @@ fun Canvas(viewModel: CanvasViewModel) { ) Spacer(modifier = Modifier.width(8.dp)) } + StorageType.SQLITE -> { TextField( value = fileName.value, @@ -143,6 +142,7 @@ fun Canvas(viewModel: CanvasViewModel) { StorageType.FILE -> { // Логика сохранения в файл с использованием fileName и isDirectedGraph } + StorageType.NEO4J -> { // Логика сохранения в Neo4j val repo = Neo4jRepository(uri.value, login.value, password.value) @@ -152,11 +152,12 @@ fun Canvas(viewModel: CanvasViewModel) { handler.saveGraphToNeo4j(viewModel.graph) viewModel.graph.isDirected = wasGraphDirected } + StorageType.SQLITE -> { val fileAddress = "saves/sqlite/${fileName.value}" val dataBase = File(fileAddress) val sqlHandler = SQLiteDBHandler() - sqlHandler.save(dataBase,viewModel.graph,viewModel.graphViewModel,isWeighted.value) + sqlHandler.save(dataBase, viewModel.graph, viewModel.graphViewModel, isWeighted.value) } } showDialog.value = false diff --git a/src/main/kotlin/view/CustomRadioView.kt b/src/main/kotlin/view/CustomRadioView.kt index 60921ee..5523579 100644 --- a/src/main/kotlin/view/CustomRadioView.kt +++ b/src/main/kotlin/view/CustomRadioView.kt @@ -1,7 +1,7 @@ package view import androidx.compose.foundation.background -import androidx.compose.foundation.border + import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button @@ -30,20 +30,22 @@ fun CustomRadioGroup( ) { Box( modifier = Modifier + .background(shape = CircleShape, color = Color.Gray) .background(if (isBoxSelected1) Color.DarkGray else Color.Gray) .height(50.dp) .padding(8.dp) .weight(1f) - //.border(2.dp, Color.Black, CircleShape), ) { Text("NEO4J", color = Color.Black) } Spacer(modifier = Modifier.width(8.dp)) Button( - onClick = { onOptionSelected(StorageType.NEO4J.name) + onClick = { + onOptionSelected(StorageType.NEO4J.name) isBoxSelected3 = false isBoxSelected2 = false - isBoxSelected1 = !isBoxSelected1} + isBoxSelected1 = !isBoxSelected1 + } ) { Text("Select") } @@ -58,16 +60,18 @@ fun CustomRadioGroup( .background(if (isBoxSelected2) Color.DarkGray else Color.Gray) .padding(8.dp) .weight(1f) - //.border(2.dp, Color.Black, CircleShape), + ) { Text("FILE", color = Color.Black) } Spacer(modifier = Modifier.width(8.dp)) Button( - onClick = { onOptionSelected(StorageType.FILE.name) + onClick = { + onOptionSelected(StorageType.FILE.name) isBoxSelected3 = false isBoxSelected2 = !isBoxSelected2 - isBoxSelected1 = false} + isBoxSelected1 = false + } ) { Text("Select") } @@ -82,7 +86,7 @@ fun CustomRadioGroup( .background(if (isBoxSelected3) Color.DarkGray else Color.Gray) .padding(8.dp) .weight(1f) - // .border(2.dp, Color.Black, CircleShape), + ) { Text("SQLITE", color = Color.Black) } @@ -92,7 +96,8 @@ fun CustomRadioGroup( onOptionSelected(StorageType.SQLITE.name) isBoxSelected3 = !isBoxSelected3 isBoxSelected2 = false - isBoxSelected1 = false} + isBoxSelected1 = false + } ) { Text("Select") } diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 4ab7f47..9105563 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -1,31 +1,27 @@ package view -import androidx.compose.foundation.background + import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogWindow import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.rememberDialogState -import kotlinx.coroutines.launch import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository import model.databases.sqlite.SQLiteDBHandler -import model.graph.Graph import viewmodel.LoadGraphMenuViewModel import viewmodel.graph.GraphViewModel import java.io.File @Composable -fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { - val coroutineScope = rememberCoroutineScope() +fun LoadGraph(viewModel: LoadGraphMenuViewModel) { + var isWeighted by remember { mutableStateOf(false) } var isDirected by remember { mutableStateOf(false) } @@ -55,11 +51,12 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { } Row(modifierRow, verticalAlignment = verticalRow) { - Column ( modifier = Modifier - .height(450.dp) - .padding(16.dp), + Column( + modifier = Modifier + .height(450.dp) + .padding(16.dp), verticalArrangement = Arrangement.Top - ){ + ) { CustomRadioGroup( options = listOf( StorageType.FILE.toString(), @@ -98,8 +95,10 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue - uri = newValue}, + onValueChange = { newValue -> + viewModel.graphName.value = newValue + uri = newValue + }, label = { Text("URI") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -114,8 +113,10 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue - login = newValue}, + onValueChange = { newValue -> + viewModel.graphName.value = newValue + login = newValue + }, label = { Text("Login") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -130,8 +131,10 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue - password = newValue}, + onValueChange = { newValue -> + viewModel.graphName.value = newValue + password = newValue + }, label = { Text("Password") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -151,7 +154,8 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { value = viewModel.graphName.value, onValueChange = { newValue -> viewModel.graphName.value = newValue - fileAddress=newValue}, + fileAddress = newValue + }, label = { Text("Path") }, singleLine = true, colors = TextFieldDefaults.textFieldColors( @@ -190,6 +194,7 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { StorageType.FILE -> { // Логика сохранения в файл с использованием fileName и isDirectedGraph } + StorageType.NEO4J -> { val repository = Neo4jRepository(uri, login, password) val handler = Neo4jHandler(repository) @@ -198,26 +203,29 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel,) { viewModel.canvasViewModel.graph = newGraph viewModel.canvasViewModel.graphViewModel = GraphViewModel(newGraph) viewModel.canvasViewModel.isOpenLoadGraph = false - } + } + StorageType.SQLITE -> { fileAddress = "saves/sqlite/$fileAddress" val dataBase: File = File(fileAddress) val sqlHandler = SQLiteDBHandler() - sqlHandler.open(dataBase,isWeighted,isDirected) + sqlHandler.open(dataBase, isWeighted, isDirected) viewModel.canvasViewModel.graph = sqlHandler.graph - if(sqlHandler.vertexViewModelFlag){ + if (sqlHandler.vertexViewModelFlag) { viewModel.canvasViewModel.graphViewModel.graph = sqlHandler.graph viewModel.canvasViewModel.graphViewModel = sqlHandler.graphViewModel - } - else{ + } else { viewModel.canvasViewModel.graphViewModel = GraphViewModel(sqlHandler.graph) } - viewModel.canvasViewModel.representationStrategy.place(1280.0, 860.0, - viewModel.canvasViewModel.graphViewModel) + viewModel.canvasViewModel.representationStrategy.place( + 1280.0, 860.0, + viewModel.canvasViewModel.graphViewModel + ) } } - viewModel.canvasViewModel.isOpenLoadGraph = false } + viewModel.canvasViewModel.isOpenLoadGraph = false + } ) { Text("Load") } diff --git a/src/main/kotlin/view/MainScreen.kt b/src/main/kotlin/view/MainScreen.kt deleted file mode 100644 index 58cb30c..0000000 --- a/src/main/kotlin/view/MainScreen.kt +++ /dev/null @@ -1,37 +0,0 @@ -package view - -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Button -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp -import javax.swing.border.Border - - -@Composable -fun MainScreen() { - Box(modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.Center){ - Box() { - Column(modifier = Modifier.fillMaxWidth().fillMaxHeight(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally) { - Button(onClick = { } - ){ - Text("Load Graph") - } - - Button(onClick = { }) { - Text("Exit") - } - } - } - } - -} \ No newline at end of file diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index c2b770f..7ad1497 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -1,30 +1,23 @@ package view import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.background -import androidx.compose.foundation.interaction.MutableInteractionSource + import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu -import androidx.compose.material.icons.filled.Settings + import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Alignment + import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties import kotlinx.coroutines.launch -import model.databases.neo4j.Neo4jHandler -import model.databases.neo4j.Neo4jRepository import view.graph.GraphView import viewmodel.CanvasViewModel diff --git a/src/main/kotlin/view/graph/EdgeView.kt b/src/main/kotlin/view/graph/EdgeView.kt index 9b9512d..165e79c 100644 --- a/src/main/kotlin/view/graph/EdgeView.kt +++ b/src/main/kotlin/view/graph/EdgeView.kt @@ -2,10 +2,8 @@ package view.graph import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.offset import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.material.Text import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.zIndex @@ -29,14 +27,4 @@ fun EdgeView( color = Color.Black ) } -// if (viewModel.labelVisible) { -// Text( -// modifier = Modifier -// .offset( -// viewModel.u.x + (viewModel.v.x - viewModel.u.x) / 2, -// viewModel.u.y + (viewModel.v.y - viewModel.u.y) / 2 -// ), -// text = viewModel.weight, -// ) -// } } \ No newline at end of file diff --git a/src/main/kotlin/view/graph/GraphView.kt b/src/main/kotlin/view/graph/GraphView.kt index 8bb537e..6742eb5 100644 --- a/src/main/kotlin/view/graph/GraphView.kt +++ b/src/main/kotlin/view/graph/GraphView.kt @@ -10,8 +10,9 @@ import viewmodel.graph.GraphViewModel fun GraphView( viewModel: GraphViewModel, ) { - Box(modifier = Modifier - .fillMaxSize() + Box( + modifier = Modifier + .fillMaxSize() ) { viewModel.verticesViewValues.forEach { v -> diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt index d89a170..c7d6959 100644 --- a/src/main/kotlin/view/graph/VertexView.kt +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -22,7 +22,7 @@ fun VertexView( modifier: Modifier = Modifier, ) { Box(modifier = modifier - .size(viewModel.radius+10.dp, viewModel.radius+10.dp) + .size(viewModel.radius + 10.dp, viewModel.radius + 10.dp) .offset(viewModel.x, viewModel.y) .border(2.dp, Color.Black, CircleShape) .background( diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 7a7762a..623a6d1 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -6,11 +6,11 @@ import viewmodel.algos.BridgeFinderViewModel import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -class CanvasViewModel(var graph: Graph, val representationStrategy: RepresentationStrategy,) { +class CanvasViewModel(var graph: Graph, val representationStrategy: RepresentationStrategy) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) var graphViewModel = GraphViewModel(graph) - val bridges = BridgeFinderViewModel(graph,graphViewModel) + val bridges = BridgeFinderViewModel(graph, graphViewModel) private val _isOpenLoadGraph = mutableStateOf(false) var isOpenLoadGraph: Boolean diff --git a/src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt b/src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt index b663c58..cea530b 100644 --- a/src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt +++ b/src/main/kotlin/viewmodel/LoadGraphMenuViewModel.kt @@ -4,7 +4,4 @@ import androidx.compose.runtime.mutableStateOf class LoadGraphMenuViewModel(val canvasViewModel: CanvasViewModel) { val graphName = mutableStateOf("") - val isGraphWeighted = mutableStateOf(false) - val isGraphDirected = mutableStateOf(false) -// val selectedSaveType = mutableStateOf(GraphSavingType.LOCAL_FILE) } diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 039f728..153bf32 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -1,12 +1,11 @@ package viewmodel.graph -import androidx.compose.runtime.State + import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import model.graph.Graph import model.graph.Edge import model.graph.Vertex -import viewmodel.algos.BridgeFinderViewModel class GraphViewModel( @@ -14,7 +13,8 @@ class GraphViewModel( ) { - val verticesView: HashMap = hashMapOf() + val verticesView: HashMap = hashMapOf() + init { graph.getVertices().forEach { vertex -> verticesView[vertex] = VertexViewModel(0.dp, 0.dp, Color.Black, vertex) @@ -22,6 +22,7 @@ class GraphViewModel( } val edgesView: HashMap = hashMapOf() + init { graph.getEdges().forEach { edge -> val fst = verticesView[graph.vertices[edge.vertices.first]] @@ -29,7 +30,7 @@ class GraphViewModel( val snd = verticesView[graph.vertices[edge.vertices.second]] ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.second} not found") val currentEdgeView = EdgeViewModel(fst, snd, edge) - edgesView[edge]=currentEdgeView + edgesView[edge] = currentEdgeView } } diff --git a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt b/src/main/kotlin/viewmodel/layouts/ForceAtlas2Layout.kt similarity index 70% rename from src/main/kotlin/model/layout/ForceAtlas2Layout.kt rename to src/main/kotlin/viewmodel/layouts/ForceAtlas2Layout.kt index 9fe35b3..e446f00 100644 --- a/src/main/kotlin/model/layout/ForceAtlas2Layout.kt +++ b/src/main/kotlin/viewmodel/layouts/ForceAtlas2Layout.kt @@ -1,8 +1,7 @@ -package model.layout +package viewmodel.layouts import androidx.compose.ui.unit.dp import viewmodel.graph.GraphViewModel -import viewmodel.layouts.RepresentationStrategy import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 import org.gephi.graph.api.Edge import org.gephi.graph.api.GraphController @@ -13,25 +12,25 @@ import viewmodel.graph.VertexViewModel import kotlin.random.Random -class ForceAtlas2Layout:RepresentationStrategy{ +class ForceAtlas2Layout : RepresentationStrategy { - override fun place(width: Double, height: Double, graphViewModel:GraphViewModel){ + override fun place(width: Double, height: Double, graphViewModel: GraphViewModel) { val pc = Lookup.getDefault().lookup(ProjectController::class.java) pc.newProject() val graphModel = Lookup.getDefault().lookup(GraphController::class.java).graphModel val graph = graphModel.undirectedGraph - val verticesMap = mutableMapOf() - for (vertex in graphViewModel.verticesViewValues){ - val v: Node =graphModel.factory().newNode(vertex.vertex.id.toString()) - v.setX(Random.nextFloat()*10) - v.setY(Random.nextFloat()*10) + val verticesMap = mutableMapOf() + for (vertex in graphViewModel.verticesViewValues) { + val v: Node = graphModel.factory().newNode(vertex.vertex.id.toString()) + v.setX(Random.nextFloat() * 10) + v.setY(Random.nextFloat() * 10) graph.addNode(v) - verticesMap[vertex.vertex.id]=v + verticesMap[vertex.vertex.id] = v } - //TODO добавить возможность получения информации об ориентированности графа - for (edge in graphViewModel.edgesViewValues){ + //TODO добавить возможность получения информации об ориентированности графа + for (edge in graphViewModel.edgesViewValues) { val e: Edge = graphModel.factory().newEdge( verticesMap[edge.u.vertex.id], verticesMap[edge.v.vertex.id], @@ -58,8 +57,8 @@ class ForceAtlas2Layout:RepresentationStrategy{ for (vertex in graphViewModel.verticesViewValues) { val v: Node = graph.getNode(vertex.vertex.id.toString()) - val x = ((width/2 + v.x())) - val y = ((height/2 + v.y())) + val x = ((width / 2 + v.x())) + val y = ((height / 2 + v.y())) vertex.x = (x).toInt().dp vertex.y = (y).toInt().dp } diff --git a/src/main/kotlin/viewmodel/layouts/TsNETLayout.kt b/src/main/kotlin/viewmodel/layouts/TsNETLayout.kt deleted file mode 100644 index fa631c2..0000000 --- a/src/main/kotlin/viewmodel/layouts/TsNETLayout.kt +++ /dev/null @@ -1,4 +0,0 @@ -package viewmodel.layouts - -class TsNETLayout { -} \ No newline at end of file From f6f6416a319954bb9e30cce166ef51009d393b24 Mon Sep 17 00:00:00 2001 From: Rodion Suvorov <107667059+suvorovrain@users.noreply.github.com> Date: Fri, 31 May 2024 14:45:50 +0300 Subject: [PATCH 192/211] fix: format text --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 38aa11a..1bd890a 100644 --- a/README.md +++ b/README.md @@ -46,19 +46,20 @@ git@github.com:spbu-coding-2023/graphs-graph-7.git | id | data | community | |--|--|--| | *integer* | *text* | -1 | -`id` -- уникальный идентификационный номер -`data` -- информация, хранимая в вершине -`community` -- информация о том, находится ли вершина в сообществе. Изначально равняется `-1`, после выполнения алгоритма кластеризации, равняется номеру сообщества + +`id` - уникальный идентификационный номер +`data` - информация, хранимая в вершине +`community` - информация о том, находится ли вершина в сообществе. Изначально равняется `-1`, после выполнения алгоритма кластеризации, равняется номеру сообщества ### Edges | id | first | second | weight | |--|--|--| -- | | *integer* | *int* | *int* |*Long* | - `id` -- уникальный идентификационный номер - `first` -- **id** первой вершины, в случае направленного графа, считается началом ребра - `second` --**id** второй вершины, в случае направленного графа, считается концом ребра - `weight` -- вес ребра. В случае не взвешенного графа, у всех ребер он равен единице + `id` - уникальный идентификационный номер + `first` - **id** первой вершины, в случае направленного графа, считается началом ребра + `second` -**id** второй вершины, в случае направленного графа, считается концом ребра + `weight` - вес ребра. В случае не взвешенного графа, у всех ребер он равен единице 2. Обработанный граф. В таком случае должна быть третья таблица, а в таблице **Vertices** в поле **community** вместо -1 могут стоять непосредственно номера community @@ -68,13 +69,13 @@ git@github.com:spbu-coding-2023/graphs-graph-7.git |--|--|--|--|--| | *integer* | *int* | *double*| *double*| *text*| - `id` -- уникальный идентификационный номер + `id` - уникальный идентификационный номер `vertex`- **id** вершины из таблицы **Vertices** - `x, y` -- координаты вершины + `x, y` - координаты вершины - `color` -- цвет формата RGB в следующем виде "r:g:b", где r,g,b - float. + `color` - цвет формата RGB в следующем виде "r:g:b", где r,g,b - float. ### Как открыть граф? (SQL) From 907660f55917f487ba8228bd0bd62c6282fd5aa4 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 24 Oct 2024 19:30:25 +0300 Subject: [PATCH 193/211] style: add spaces at the end of the file --- .github/formatter.yml | 3 ++- gradle.properties | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/formatter.yml b/.github/formatter.yml index 39bbb09..bcebeb0 100644 --- a/.github/formatter.yml +++ b/.github/formatter.yml @@ -9,4 +9,5 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 - name: Check formatter - run: ./gradlew ktfmtCheck \ No newline at end of file + run: ./gradlew ktfmtCheck + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index d8f5256..5cbac2b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 kotlin.code.style=official kotlin.version=1.9.22 compose.version=1.6.0 -exposedVersion=0.50.1 \ No newline at end of file +exposedVersion=0.50.1 From d8b92e31e83a89066b1b17b10194a8a14860f1f7 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 24 Oct 2024 19:33:21 +0300 Subject: [PATCH 194/211] style: remove empty strings --- README.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.md b/README.md index 1bd890a..161aefd 100644 --- a/README.md +++ b/README.md @@ -21,15 +21,6 @@ git@github.com:spbu-coding-2023/graphs-graph-7.git ./gradlew run ``` - - - - - - - - - ## Раскладка графа Для раскладки графа используется алгоритм [ForceAtlas2](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0098679). From ca681ac80553a0c2a04d00cf94af1e2b93a2833f Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 24 Oct 2024 19:42:37 +0300 Subject: [PATCH 195/211] docs(license): switch from MIT to GPL-V3 --- LICENSE | 890 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 869 insertions(+), 21 deletions(-) diff --git a/LICENSE b/LICENSE index 3ef22ba..c2e13c1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,869 @@ -MIT License - -Copyright (c) 2024 Suvorov Rodion, Strelnikov Andrei, Kremnev Semyon - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + +--- + +All files in the package model.algorithms.clustering.implementation are provided under the following license: + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +Copyright 2021-2022 JetBrains s.r.o. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file From 2a2bf4c9cb452657c20fdb2f1ab5e414dd93e573 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 24 Oct 2024 20:18:30 +0300 Subject: [PATCH 196/211] style: run ktfmtFormat --- src/main/kotlin/Main.kt | 110 +++++++++--------- .../controller/GraphPainterByCommunity.kt | 9 +- .../controller/GraphPainterByDjikstra.kt | 2 +- .../controller/GraphPainterByKosaraju.kt | 2 +- src/main/kotlin/controller/RandomColor.kt | 2 +- .../kotlin/model/algorithms/BridgeFinder.kt | 27 +++-- src/main/kotlin/model/algorithms/Djikstra.kt | 21 ++-- .../kotlin/model/algorithms/FindCycles.kt | 16 +-- .../kotlin/model/algorithms/FordBellman.kt | 15 +-- src/main/kotlin/model/algorithms/Kosaraju.kt | 8 +- .../model/algorithms/KruskalsAlgorithm.kt | 20 ++-- .../TarjanStrongConnecedComponent.kt | 6 +- src/main/kotlin/model/community/Louvain.kt | 31 +++-- src/main/kotlin/model/community/Neighbours.kt | 4 +- src/main/kotlin/model/community/Relation.kt | 3 +- .../model/databases/CSV/CSVFileHandler.kt | 101 +++++++++------- .../model/databases/CSV/data/CSVGraphData.kt | 6 +- .../databases/CSV/data/VertexViewData.kt | 3 +- .../model/databases/neo4j/Neo4jDBHandler.kt | 10 +- .../model/databases/neo4j/Repository.kt | 59 +++++++--- .../model/databases/sqlite/SQLiteDBHandler.kt | 43 ++++--- .../model/databases/sqlite/dao/edge/Edge.kt | 2 +- .../model/databases/sqlite/dao/edge/Edges.kt | 2 +- .../databases/sqlite/dao/vertices/Vertex.kt | 2 +- .../databases/sqlite/dao/vertices/Vertices.kt | 2 +- .../sqlite/dao/verticesView/VertexView.kt | 3 +- .../sqlite/dao/verticesView/VerticesView.kt | 2 +- src/main/kotlin/model/graph/Edge.kt | 6 +- src/main/kotlin/model/graph/Graph.kt | 5 +- src/main/kotlin/model/graph/Vertex.kt | 2 +- src/main/kotlin/view/AlgorithmSubMenu.kt | 29 ++--- src/main/kotlin/view/CanvasView.kt | 78 ++++--------- src/main/kotlin/view/CustomRadioView.kt | 47 +++----- src/main/kotlin/view/LoadGraphMenu.kt | 106 +++++++---------- src/main/kotlin/view/NavigationDrawer.kt | 53 ++++----- src/main/kotlin/view/ShortestPathDialog.kt | 17 ++- src/main/kotlin/view/StorageType.kt | 2 +- .../kotlin/view/algos/BridgeFinderView.kt | 12 +- src/main/kotlin/view/graph/EdgeView.kt | 20 ++-- src/main/kotlin/view/graph/GraphView.kt | 16 +-- src/main/kotlin/view/graph/VertexView.kt | 35 +++--- src/main/kotlin/viewmodel/CanvasViewModel.kt | 3 +- .../viewmodel/algos/BridgeFinderViewModel.kt | 9 +- .../kotlin/viewmodel/graph/EdgeViewModel.kt | 2 +- .../kotlin/viewmodel/graph/GraphViewModel.kt | 27 ++--- .../kotlin/viewmodel/graph/VertexViewModel.kt | 5 +- .../viewmodel/layouts/CircularLayout.kt | 40 +++---- .../viewmodel/layouts/ForceAtlas2Layout.kt | 21 ++-- .../layouts/RepresentationStrategy.kt | 3 +- .../graphs/algorithms/BridgeFinderTest.kt | 77 ++++++------ .../kotlin/graphs/algorithms/DjikstraTest.kt | 26 ++--- .../graphs/algorithms/FordBellmanTest.kt | 101 ++++++++-------- .../kotlin/graphs/algorithms/KosajaruTest.kt | 60 +++++----- .../kotlin/graphs/algorithms/KruskalTest.kt | 3 +- .../kotlin/graphs/algorithms/LouvainTest.kt | 15 ++- 55 files changed, 647 insertions(+), 684 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 9352508..8ea737a 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,4 +1,3 @@ - import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable @@ -6,86 +5,81 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.application - import androidx.compose.ui.window.rememberWindowState - +import java.awt.Dimension import model.graph.Graph -import viewmodel.layouts.ForceAtlas2Layout import view.Canvas - import viewmodel.CanvasViewModel -import java.awt.Dimension - -val graph = Graph().apply { - addVertex(1,"Thomas") - addVertex(2, "Andrew") - addVertex(3, "Iakov") - addVertex(4, "John") - addVertex(5, "Tristan") - addVertex(6, "Arthur") - addVertex(7, "Ryan") - - addEdge(1, 2, 1,1) - addEdge(3, 4, 2,2) - addEdge(1, 3, 3,3) - addEdge(2, 3, 4,4) - addEdge(5, 3, 5,5) - addEdge(3, 7, 6,6) +import viewmodel.layouts.ForceAtlas2Layout - addVertex(8, "Pudge") - addVertex(9,"Tiny") - addVertex(10, "Lycan") - addVertex(11,"Io") - addVertex(12,"Lion") - addVertex(13,"Sniper") - addVertex(14,"Roshan") +val graph = + Graph().apply { + addVertex(1, "Thomas") + addVertex(2, "Andrew") + addVertex(3, "Iakov") + addVertex(4, "John") + addVertex(5, "Tristan") + addVertex(6, "Arthur") + addVertex(7, "Ryan") - addEdge(14, 8, 6,7) - addEdge(14, 9, 6,8) - addEdge(14, 10, 6,9) - addEdge(14, 11, 6,10) - addEdge(14, 12, 6,11) - addEdge(14, 13, 5,12) - addEdge(14, 3, 0,13) + addEdge(1, 2, 1f, 1) + addEdge(3, 4, 2f, 2) + addEdge(1, 3, 3f, 3) + addEdge(2, 3, 4f, 4) + addEdge(5, 3, 5f, 5) + addEdge(3, 7, 6f, 6) + addVertex(8, "Pudge") + addVertex(9, "Tiny") + addVertex(10, "Lycan") + addVertex(11, "Io") + addVertex(12, "Lion") + addVertex(13, "Sniper") + addVertex(14, "Roshan") - addVertex(15, "1") - addVertex(16,"2") - addVertex(17, "3") - addVertex(18,"4") - addVertex(19,"5") - addVertex(20,"6") - addVertex(21,"7") + addEdge(14, 8, 6f, 7) + addEdge(14, 9, 6f, 8) + addEdge(14, 10, 6f, 9) + addEdge(14, 11, 6f, 10) + addEdge(14, 12, 6f, 11) + addEdge(14, 13, 5f, 12) + addEdge(14, 3, 0f, 13) + addVertex(15, "1") + addVertex(16, "2") + addVertex(17, "3") + addVertex(18, "4") + addVertex(19, "5") + addVertex(20, "6") + addVertex(21, "7") - addEdge(16, 15, 22,14) - addEdge(15, 17, 1,15) - addEdge(15, 18, 6,16) - addEdge(19, 15, 2,17) - addEdge(15, 21, 3,18) - addEdge(20, 15, 5,19) - addEdge(17, 20, 0,20) - addEdge(14, 20, 0,21) + addEdge(16, 15, 22f, 14) + addEdge(15, 17, 1f, 15) + addEdge(15, 18, 6f, 16) + addEdge(19, 15, 2f, 17) + addEdge(15, 21, 3f, 18) + addEdge(20, 15, 5f, 19) + addEdge(17, 20, 0f, 20) + addEdge(14, 20, 0f, 21) + } +val windowSizeStart = Pair(820, 640) -} -val windowSizeStart = Pair(820,640) @Composable @Preview fun App() { MaterialTheme { val canvasGraph = CanvasViewModel(graph, ForceAtlas2Layout()) - MaterialTheme { - Canvas(canvasGraph) - } + MaterialTheme { Canvas(canvasGraph) } } } fun main() = application { - Window(onCloseRequest = ::exitApplication, + Window( + onCloseRequest = ::exitApplication, title = "ZeitNot", state = rememberWindowState(position = WindowPosition(Alignment.Center)) ) { window.minimumSize = Dimension(windowSizeStart.first, windowSizeStart.second) App() } -} \ No newline at end of file +} diff --git a/src/main/kotlin/controller/GraphPainterByCommunity.kt b/src/main/kotlin/controller/GraphPainterByCommunity.kt index cb55dff..41c645f 100644 --- a/src/main/kotlin/controller/GraphPainterByCommunity.kt +++ b/src/main/kotlin/controller/GraphPainterByCommunity.kt @@ -1,10 +1,13 @@ package controller -import model.graph.Graph import model.community.Louvain +import model.graph.Graph import viewmodel.graph.GraphViewModel -class GraphPainterByCommunity(private val graph: Graph, private val graphViewModel: GraphViewModel) { +class GraphPainterByCommunity( + private val graph: Graph, + private val graphViewModel: GraphViewModel +) { private val finder = Louvain(graph) private val communities = finder.findCommunities() @@ -17,4 +20,4 @@ class GraphPainterByCommunity(private val graph: Graph, private val graphViewMod } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/controller/GraphPainterByDjikstra.kt b/src/main/kotlin/controller/GraphPainterByDjikstra.kt index aaff5bd..a21af75 100644 --- a/src/main/kotlin/controller/GraphPainterByDjikstra.kt +++ b/src/main/kotlin/controller/GraphPainterByDjikstra.kt @@ -21,4 +21,4 @@ class GraphPainterByDjikstra( graphViewModel.verticesView[currVertex]!!.color = vertexColor } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/controller/GraphPainterByKosaraju.kt b/src/main/kotlin/controller/GraphPainterByKosaraju.kt index 8154fc5..e00d90b 100644 --- a/src/main/kotlin/controller/GraphPainterByKosaraju.kt +++ b/src/main/kotlin/controller/GraphPainterByKosaraju.kt @@ -17,4 +17,4 @@ class GraphPainterByKosaraju(private val graph: Graph, private val graphViewMode } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/controller/RandomColor.kt b/src/main/kotlin/controller/RandomColor.kt index 05b5051..652144f 100644 --- a/src/main/kotlin/controller/RandomColor.kt +++ b/src/main/kotlin/controller/RandomColor.kt @@ -9,4 +9,4 @@ fun generateRandomColor(base: Int): Color { val green: Int = (base + mRandom.nextInt(256)) / 2 val blue: Int = (base + mRandom.nextInt(256)) / 2 return Color(red, green, blue) -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/algorithms/BridgeFinder.kt b/src/main/kotlin/model/algorithms/BridgeFinder.kt index db1515d..aee724f 100644 --- a/src/main/kotlin/model/algorithms/BridgeFinder.kt +++ b/src/main/kotlin/model/algorithms/BridgeFinder.kt @@ -1,8 +1,7 @@ package model.algorithms -import model.graph.Graph -import java.awt.geom.Point2D.distance import kotlin.math.min +import model.graph.Graph class BridgeFinder(graph: Graph) { private val arraySize = graph.vertices.size @@ -16,12 +15,17 @@ class BridgeFinder(graph: Graph) { var timer = 0 fun isBridge(edgeID: Int): Int? { - val destination = curGraph.edges[edgeID]?.vertices?.second ?: throw Exception("Incorrect Database") + val destination = + curGraph.edges[edgeID]?.vertices?.second ?: throw Exception("Incorrect Database") val bridge = curGraph.edges[edgeID] val bridges = - curGraph.vertices[bridge?.vertices?.first]?.incidentEdges ?: throw Exception("Incorrect Database") + curGraph.vertices[bridge?.vertices?.first]?.incidentEdges + ?: throw Exception("Incorrect Database") for (curBridge in bridges) { - if (curGraph.edges[curBridge]!!.vertices.second == destination && curBridge != edgeID) { + if ( + curGraph.edges[curBridge]!!.vertices.second == destination && + curBridge != edgeID + ) { return null } } @@ -36,11 +40,12 @@ class BridgeFinder(graph: Graph) { val incidentEdgesID = curGraph.vertices[vertexID + 1]!!.incidentEdges for (edgeID in incidentEdgesID) { val edge = curGraph.edges[edgeID]!!.vertices - val newVertexID = if (vertexID == edge.first - 1) { - edge.second - 1 - } else { - edge.first - 1 - } + val newVertexID = + if (vertexID == edge.first - 1) { + edge.second - 1 + } else { + edge.first - 1 + } if (newVertexID == parent) continue @@ -64,4 +69,4 @@ class BridgeFinder(graph: Graph) { } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/algorithms/Djikstra.kt b/src/main/kotlin/model/algorithms/Djikstra.kt index 4945b8a..027a140 100644 --- a/src/main/kotlin/model/algorithms/Djikstra.kt +++ b/src/main/kotlin/model/algorithms/Djikstra.kt @@ -3,7 +3,7 @@ package model.algorithms import model.graph.Graph class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { - private val distance = hashMapOf() + private val distance = hashMapOf() private val visited = hashMapOf() private val from = hashMapOf() private val n = graph.vertices.size @@ -12,32 +12,33 @@ class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { if (n == 0 || startVertexID <= -1) return for ((id, _) in graph.vertices) { - distance[id] = Long.MAX_VALUE + distance[id] = Float.MAX_VALUE from[id] = -1 } - distance[startVertexID] = 0 + distance[startVertexID] = 0f for (i in 0 until n) { var nearest = -1 for ((vertexID, _) in graph.vertices) { - if (!visited.getOrDefault( - vertexID, - false - ) && (nearest == -1 || distance[vertexID]!! < distance[nearest]!!) + if ( + !visited.getOrDefault(vertexID, false) && + (nearest == -1 || distance[vertexID]!! < distance[nearest]!!) ) { nearest = vertexID } } visited[nearest] = true - if (distance[nearest] == Long.MAX_VALUE) break + if (distance[nearest] == Float.MAX_VALUE) break for (edgeID in graph.vertices[nearest]!!.incidentEdges) { val edge = graph.edges[edgeID]!! - val to = if (nearest == edge.vertices.first) edge.vertices.second else edge.vertices.first + val to = + if (nearest == edge.vertices.first) edge.vertices.second + else edge.vertices.first val weight = edge.weight if (distance[nearest]!! + weight < distance[to]!!) { @@ -66,4 +67,4 @@ class Djikstra(private val graph: Graph, private val startVertexID: Int = -1) { path.reverse() return path } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/algorithms/FindCycles.kt b/src/main/kotlin/model/algorithms/FindCycles.kt index e33106e..59330c6 100644 --- a/src/main/kotlin/model/algorithms/FindCycles.kt +++ b/src/main/kotlin/model/algorithms/FindCycles.kt @@ -1,8 +1,8 @@ package algorithms +import java.util.* import model.graph.Graph import model.graph.Vertex -import java.util.* class AllCyclesInDirectedGraphJohnson { private var blockedSet: MutableSet = mutableSetOf() @@ -57,7 +57,10 @@ class AllCyclesInDirectedGraphJohnson { val graphScc = Graph() graphScc.isDirected = true for ((i, edge) in subGraph.getEdges().withIndex()) { - if ((subGraph.vertices[edge.vertices.first] in minScc) && (subGraph.vertices[edge.vertices.second] in minScc)) { + if ( + (subGraph.vertices[edge.vertices.first] in minScc) && + (subGraph.vertices[edge.vertices.second] in minScc) + ) { graphScc.addVertex(edge.vertices.first, "") graphScc.addVertex(edge.vertices.second, "") graphScc.addEdge(edge.vertices.first, edge.vertices.second, edgeID = i) @@ -98,8 +101,7 @@ class AllCyclesInDirectedGraphJohnson { allCycles.add(cycle) foundCycle = true } else if (!blockedSet.contains(neighbor)) { - val gotCycle = - findCyclesInSCG(graph, startVertex, neighbor) + val gotCycle = findCyclesInSCG(graph, startVertex, neighbor) foundCycle = foundCycle || gotCycle } } @@ -117,9 +119,7 @@ class AllCyclesInDirectedGraphJohnson { } private fun getBSet(v: Vertex): MutableSet { - return (blockedMap.computeIfAbsent( - v - ) { HashSet() } as MutableSet?)!! + return (blockedMap.computeIfAbsent(v) { HashSet() } as MutableSet?)!! } private fun createSubGraph(startVertex: Int, graph: Graph): Graph { @@ -134,4 +134,4 @@ class AllCyclesInDirectedGraphJohnson { } return subGraph } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/algorithms/FordBellman.kt b/src/main/kotlin/model/algorithms/FordBellman.kt index b9e1d5e..44515ef 100644 --- a/src/main/kotlin/model/algorithms/FordBellman.kt +++ b/src/main/kotlin/model/algorithms/FordBellman.kt @@ -1,11 +1,10 @@ package model.algorithms -import model.graph.Graph import kotlin.math.max - +import model.graph.Graph class FordBellman(graph: Graph) { - val INF = Long.MAX_VALUE + val INF = Float.MAX_VALUE private val verticesNumber = graph.vertices.size private val edgesNumber = graph.edges.size @@ -28,7 +27,6 @@ class FordBellman(graph: Graph) { val cycleEndFlag = true while (cycleEndFlag) { - if (current == tmpCycleFlag && resultPathVertices.size > 1) { break } @@ -46,13 +44,13 @@ class FordBellman(graph: Graph) { } fun shortestPath(startVertexID: Int, endVertexID: Int) { - pathsLength[startVertexID - 1] = 0 + pathsLength[startVertexID - 1] = 0f var curCycleFlag = -1 for (i in 0 until verticesNumber) { curCycleFlag = -1 for (j in 0 until edgesNumber) { - val firstVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.first - 1] - val secondVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] + val firstVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.first - 1].toFloat() + val secondVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1].toFloat() if (firstVertexPath < INF) { if (secondVertexPath > firstVertexPath + curGraph.edges[j + 1]!!.weight) { pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] = @@ -95,6 +93,3 @@ class FordBellman(graph: Graph) { } while (pathVertices[tmp - 1] != -1) } } - - - diff --git a/src/main/kotlin/model/algorithms/Kosaraju.kt b/src/main/kotlin/model/algorithms/Kosaraju.kt index 7856161..ea5e02c 100644 --- a/src/main/kotlin/model/algorithms/Kosaraju.kt +++ b/src/main/kotlin/model/algorithms/Kosaraju.kt @@ -37,7 +37,8 @@ class Kosaraju(private val graph: Graph) { val vertex = graph.vertices[vertexID] ?: return for (edgeID in vertex.incidentEdges) { val edge = graph.edges[edgeID] ?: continue - val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first + val nextVertexID = + if (vertexID == edge.vertices.first) edge.vertices.second else edge.vertices.first if (used[nextVertexID] != true) { topologySort(graph, nextVertexID) } @@ -56,7 +57,8 @@ class Kosaraju(private val graph: Graph) { val vertex = graph.vertices[vertexID] ?: return for (edgeID in vertex.incidentEdges) { val edge = graph.edges[edgeID] ?: continue - val nextVertexID = if (vertexID == edge.vertices.first) edge.vertices.second else continue + val nextVertexID = + if (vertexID == edge.vertices.first) edge.vertices.second else continue if (used[nextVertexID] != true) { dfs(nextVertexID) } @@ -80,4 +82,4 @@ class Kosaraju(private val graph: Graph) { return transposedGraph } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt index 9b49011..12ba900 100644 --- a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt @@ -1,19 +1,19 @@ package model.algorithms -import model.graph.Graph import model.graph.Edge +import model.graph.Graph class KruskalsMST { var resultsId: List = emptyList() + internal fun kruskals(graph: Graph) { var j = 0 var noOfEdges = 0 val V = graph.getVertices().size - if (V == 1 || V == 0) - return + if (V == 1 || V == 0) return val results = arrayOfNulls(V - 1) val subsets = arrayOfNulls(V) - for (i in 0.., x: Int, + subsets: Array, + x: Int, y: Int, ) { val rootX = findRoot(subsets, x) @@ -44,9 +45,7 @@ class KruskalsMST { if (subsets[rootY]!!.rank < subsets[rootX]!!.rank) { subsets[rootY]!!.parent = rootX - } else if ((subsets[rootX]!!.rank - < subsets[rootY]!!.rank) - ) { + } else if ((subsets[rootX]!!.rank < subsets[rootY]!!.rank)) { subsets[rootX]!!.parent = rootY } else { subsets[rootY]!!.parent = rootX @@ -55,10 +54,9 @@ class KruskalsMST { } private fun findRoot(subsets: Array, i: Int): Int { - if (subsets[i]!!.parent != i) - subsets[i]!!.parent = findRoot(subsets, subsets[i]!!.parent) + if (subsets[i]!!.parent != i) subsets[i]!!.parent = findRoot(subsets, subsets[i]!!.parent) return subsets[i]!!.parent } internal class Subset(var parent: Int, var rank: Int) -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt b/src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt index d6c7fd5..5612ca9 100644 --- a/src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt +++ b/src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt @@ -1,9 +1,9 @@ package algorithms -import model.graph.Graph -import model.graph.Vertex import java.util.* import kotlin.math.min +import model.graph.Graph +import model.graph.Vertex class TarjanStronglyConnectedComponent { private var visitedTime: MutableMap = mutableMapOf() @@ -53,4 +53,4 @@ class TarjanStronglyConnectedComponent { result.add(stronglyConnectedComponent) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/community/Louvain.kt b/src/main/kotlin/model/community/Louvain.kt index 8209106..5db05ff 100644 --- a/src/main/kotlin/model/community/Louvain.kt +++ b/src/main/kotlin/model/community/Louvain.kt @@ -8,14 +8,17 @@ class Louvain(private val graph: Graph) { private var targetCommunity = currCommunities private var modularity = calculateModularity(currCommunities) - fun findCommunities() : List> { + fun findCommunities(): List> { do { var stop = false for (anchor in n.neighbours.keys) { for (neighbourCommunity in n.neighbours.keys) { - if (anchor != neighbourCommunity && currCommunities[anchor] != neighbourCommunity) { + if ( + anchor != neighbourCommunity && + currCommunities[anchor] != neighbourCommunity + ) { val newCommunities = targetCommunity.toMutableMap() newCommunities[anchor] = currCommunities[neighbourCommunity]!! @@ -39,8 +42,7 @@ class Louvain(private val graph: Graph) { for (value in targetCommunity.values.toSet()) { val keys = mutableSetOf() for ((key, value1) in targetCommunity) { - if (value1 == value) - keys.add(key) + if (value1 == value) keys.add(key) } answer.add(keys) @@ -63,10 +65,16 @@ class Louvain(private val graph: Graph) { val neighbour2 = edge.vertices.second val closeness = edge.weight if (graph.isDirected) { - n.neighbours.getOrPut(neighbour1) { mutableSetOf() }.add(Relation(closeness, neighbour2)) + n.neighbours + .getOrPut(neighbour1) { mutableSetOf() } + .add(Relation(closeness, neighbour2)) } else { - n.neighbours.getOrPut(neighbour1) { mutableSetOf() }.add(Relation(closeness, neighbour2)) - n.neighbours.getOrPut(neighbour2) { mutableSetOf() }.add(Relation(closeness, neighbour1)) + n.neighbours + .getOrPut(neighbour1) { mutableSetOf() } + .add(Relation(closeness, neighbour2)) + n.neighbours + .getOrPut(neighbour2) { mutableSetOf() } + .add(Relation(closeness, neighbour1)) } } @@ -86,7 +94,10 @@ class Louvain(private val graph: Graph) { for (relation in n.neighbours[anchor]!!) { val neighbour = relation.id if (communities[anchor] == communities[neighbour]) { - link += 1.0 - (n.neighbours[anchor]!!.size * n.neighbours[neighbour]!!.size) / (2 * closeness) + link += + 1.0 - + (n.neighbours[anchor]!!.size * n.neighbours[neighbour]!!.size) / + (2 * closeness) } } } @@ -94,7 +105,7 @@ class Louvain(private val graph: Graph) { return link / (2 * closeness) } - private fun paintGraph(comm : List>) : List> { + private fun paintGraph(comm: List>): List> { for ((newCommunityIndex, community) in comm.withIndex()) { for (vertexIdx in community) { graph.vertices[vertexIdx]!!.community = newCommunityIndex @@ -103,4 +114,4 @@ class Louvain(private val graph: Graph) { return comm } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/community/Neighbours.kt b/src/main/kotlin/model/community/Neighbours.kt index 3273637..26f84b8 100644 --- a/src/main/kotlin/model/community/Neighbours.kt +++ b/src/main/kotlin/model/community/Neighbours.kt @@ -1,5 +1,5 @@ package model.community class Neighbours { - val neighbours : MutableMap> = mutableMapOf() -} \ No newline at end of file + val neighbours: MutableMap> = mutableMapOf() +} diff --git a/src/main/kotlin/model/community/Relation.kt b/src/main/kotlin/model/community/Relation.kt index b376329..30d34e5 100644 --- a/src/main/kotlin/model/community/Relation.kt +++ b/src/main/kotlin/model/community/Relation.kt @@ -1,4 +1,3 @@ package model.community -class Relation(val closeness: Long = 1L, val id: Int) { -} \ No newline at end of file +class Relation(val closeness: Float = 1f, val id: Int) {} diff --git a/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt b/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt index f3b9e77..d13c77a 100644 --- a/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt +++ b/src/main/kotlin/model/databases/CSV/CSVFileHandler.kt @@ -5,11 +5,11 @@ import androidx.compose.ui.unit.dp import com.github.doyaaaaaken.kotlincsv.dsl.csvReader import com.github.doyaaaaaken.kotlincsv.dsl.csvWriter import io.github.blackmo18.grass.dsl.grass +import java.io.File import model.databases.CSV.data.CSVGraphData import model.databases.CSV.data.VertexViewData import model.graph.Graph import viewmodel.graph.GraphViewModel -import java.io.File @ExperimentalStdlibApi class CSVFileHandler { @@ -20,7 +20,20 @@ class CSVFileHandler { graphViewModel.addEdgesToData(data) val csvWriter = csvWriter { delimiter = ',' } - val header = listOf("isNode", "name", "id", "x", "y", "color", "radius", "community", "from", "to", "weight") + val header = + listOf( + "isNode", + "name", + "id", + "x", + "y", + "color", + "radius", + "community", + "from", + "to", + "weight" + ) csvWriter.writeAll(listOf(header), file) csvWriter.writeAll(data, file, append = true) @@ -37,19 +50,23 @@ class CSVFileHandler { data.onEach { if (it.isNode) { newGraph.addVertex(it.id, it.name) - val rgb:List = it.color?.split("/")?.map { color -> color.toFloat()} ?: listOf(0f, 0f, 0f) - val vertex = VertexViewData( - it.x, - it.y, - it.community ?: -1, - it.radius ?: 2.5, - Color(rgb[0], rgb[1], rgb[2]) - ) + val rgb: List = + it.color?.split("/")?.map { color -> color.toFloat() } ?: listOf(0f, 0f, 0f) + val vertex = + VertexViewData( + it.x, + it.y, + it.community ?: -1, + it.radius ?: 2.5, + Color(rgb[0], rgb[1], rgb[2]) + ) vertices[it.id] = vertex } - } - data.onEach { if (!it.isNode) newGraph.addEdge(it.from!!.toInt(), it.to!!.toInt(), it.weight!!, it.id) } + data.onEach { + if (!it.isNode) + newGraph.addEdge(it.from!!.toInt(), it.to!!.toInt(), it.weight!!, it.id) + } val newGraphView = GraphViewModel(newGraph) newGraphView.verticesViewValues.onEach { @@ -69,39 +86,45 @@ class CSVFileHandler { private fun GraphViewModel.addVerticesToData(data: MutableList>) { verticesViewValues.onEach { - val csvRow = mutableListOf( - "true", - it.vertex.id.toString(), - it.vertex.data, - it.x.toString(), - it.y.toString(), - it.color.red.toString() + "/" + it.color.green.toString() + "/" + it.color.blue.toString(), - it.radius.toString(), - it.vertex.community.toString(), - "", - "", - "" - ) + val csvRow = + mutableListOf( + "true", + it.vertex.id.toString(), + it.vertex.data, + it.x.toString(), + it.y.toString(), + it.color.red.toString() + + "/" + + it.color.green.toString() + + "/" + + it.color.blue.toString(), + it.radius.toString(), + it.vertex.community.toString(), + "", + "", + "" + ) data.add(csvRow) } } private fun GraphViewModel.addEdgesToData(data: MutableList>) { edgesViewValues.onEach { - val csvRow = mutableListOf( - "false", - it.e.id.toString(), - "", - "", - "", - "", - "", - "", - it.u.vertex.id.toString(), - it.v.vertex.id.toString(), - it.weight - ) + val csvRow = + mutableListOf( + "false", + it.e.id.toString(), + "", + "", + "", + "", + "", + "", + it.u.vertex.id.toString(), + it.v.vertex.id.toString(), + it.weight + ) data.add(csvRow) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt b/src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt index b873b4d..ff83ce5 100644 --- a/src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt +++ b/src/main/kotlin/model/databases/CSV/data/CSVGraphData.kt @@ -1,7 +1,6 @@ package model.databases.CSV.data data class CSVGraphData( - var isNode: Boolean, var id: Int, var name: String, @@ -10,8 +9,7 @@ data class CSVGraphData( var color: String?, var radius: Double?, var community: Int?, - var from: String?, var to: String?, - var weight: Long? -) \ No newline at end of file + var weight: Float? +) diff --git a/src/main/kotlin/model/databases/CSV/data/VertexViewData.kt b/src/main/kotlin/model/databases/CSV/data/VertexViewData.kt index 3fd8040..492968f 100644 --- a/src/main/kotlin/model/databases/CSV/data/VertexViewData.kt +++ b/src/main/kotlin/model/databases/CSV/data/VertexViewData.kt @@ -3,10 +3,9 @@ package model.databases.CSV.data import androidx.compose.ui.graphics.Color data class VertexViewData( - var x: Double?, var y: Double?, var community: Int = -1, var radius: Double?, var color: Color -) \ No newline at end of file +) diff --git a/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt b/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt index 2e7dcdc..02d1917 100644 --- a/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt +++ b/src/main/kotlin/model/databases/neo4j/Neo4jDBHandler.kt @@ -11,9 +11,13 @@ class Neo4jHandler(private val repository: Neo4jRepository) { if (graph.isDirected) { for (edge in graph.getEdges()) { - repository.addDirectedEdge(edge.vertices.first, edge.vertices.second, edge.weight, edge.id) + repository.addDirectedEdge( + edge.vertices.first, + edge.vertices.second, + edge.weight, + edge.id + ) } - } else { for (edge in graph.getEdges()) { repository.addEdge(edge.vertices.first, edge.vertices.second, edge.weight, edge.id) @@ -25,4 +29,4 @@ class Neo4jHandler(private val repository: Neo4jRepository) { val graph = repository.getGraph() return graph } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/databases/neo4j/Repository.kt b/src/main/kotlin/model/databases/neo4j/Repository.kt index 450d22f..604fead 100644 --- a/src/main/kotlin/model/databases/neo4j/Repository.kt +++ b/src/main/kotlin/model/databases/neo4j/Repository.kt @@ -1,46 +1,72 @@ package model.databases.neo4j +import java.io.Closeable import model.graph.Graph import org.neo4j.driver.AuthTokens import org.neo4j.driver.Driver import org.neo4j.driver.GraphDatabase import org.neo4j.driver.Session import org.neo4j.driver.Values -import java.io.Closeable class Neo4jRepository(uri: String, user: String, password: String) : Closeable { private val driver: Driver = GraphDatabase.driver(uri, AuthTokens.basic(user, password)) private val session: Session = driver.session() - fun addVertex(vertexId: Int, vertexData: String, vertexCommunity : Int) { + fun addVertex(vertexId: Int, vertexData: String, vertexCommunity: Int) { session.writeTransaction { tx -> - tx.run("CREATE (:Vertex {id:\$id, data:\$data, community:\$community})", Values.parameters("id", vertexId, "data", vertexData, "community", vertexCommunity)) + tx.run( + "CREATE (:Vertex {id:\$id, data:\$data, community:\$community})", + Values.parameters("id", vertexId, "data", vertexData, "community", vertexCommunity) + ) } } - fun addDirectedEdge(firstVertexId: Int,secondVertexId: Int, weight: Long, edgeId: Int) { + fun addDirectedEdge(firstVertexId: Int, secondVertexId: Int, weight: Float, edgeId: Int) { session.writeTransaction { tx -> - tx.run("MATCH (v1:Vertex {id:\$id1}) MATCH (v2:Vertex {id:\$id2}) " + + tx.run( + "MATCH (v1:Vertex {id:\$id1}) MATCH (v2:Vertex {id:\$id2}) " + "CREATE (v1)-[:Edge {id:\$edgeId, weight:\$weight}]->(v2)", - Values.parameters("id1", firstVertexId, "id2", secondVertexId, "edgeId", edgeId, "weight", weight)) + Values.parameters( + "id1", + firstVertexId, + "id2", + secondVertexId, + "edgeId", + edgeId, + "weight", + weight + ) + ) } } - - fun addEdge(firstVertexId: Int,secondVertexId: Int, weight: Long, edgeId: Int) { + fun addEdge(firstVertexId: Int, secondVertexId: Int, weight: Float, edgeId: Int) { session.writeTransaction { tx -> - tx.run("MATCH (v1:Vertex {id:\$id1}) MATCH (v2:Vertex {id:\$id2}) " + + tx.run( + "MATCH (v1:Vertex {id:\$id1}) MATCH (v2:Vertex {id:\$id2}) " + "MERGE (v1)-[:Edge {id:\$edgeId, weight:\$weight}]-(v2)", - Values.parameters("id1", firstVertexId, "id2", secondVertexId, "edgeId", edgeId, "weight", weight)) + Values.parameters( + "id1", + firstVertexId, + "id2", + secondVertexId, + "edgeId", + edgeId, + "weight", + weight + ) + ) } } - fun getGraph(): Graph { val graph = Graph() session.readTransaction { tx -> - val verticesResult = tx.run("MATCH (v:Vertex) RETURN v.id AS id, v.data AS data, v.community AS community",) + val verticesResult = + tx.run( + "MATCH (v:Vertex) RETURN v.id AS id, v.data AS data, v.community AS community", + ) verticesResult.list().forEach { record -> val vertexId = record.get("id").asInt() val vertexData = record.get("data").asString() @@ -49,12 +75,15 @@ class Neo4jRepository(uri: String, user: String, password: String) : Closeable { graph.vertices[vertexId]!!.community = vertexCommunity } - val edgesResult = tx.run("MATCH (v1:Vertex)-[e:Edge]->(v2:Vertex) RETURN e.id AS id, v1.id AS v1, v2.id AS v2, e.weight AS weight") + val edgesResult = + tx.run( + "MATCH (v1:Vertex)-[e:Edge]->(v2:Vertex) RETURN e.id AS id, v1.id AS v1, v2.id AS v2, e.weight AS weight" + ) edgesResult.list().forEach { record -> val edgeId = record.get("id").asInt() val firstVertexId = record.get("v1").asInt() val secondVertexId = record.get("v2").asInt() - val weight = record.get("weight").asLong() + val weight = record.get("weight").asFloat() graph.addEdge(firstVertexId, secondVertexId, weight, edgeId) } } @@ -66,4 +95,4 @@ class Neo4jRepository(uri: String, user: String, password: String) : Closeable { session.close() driver.close() } -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt index 823393b..8c00d54 100644 --- a/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt +++ b/src/main/kotlin/model/databases/sqlite/SQLiteDBHandler.kt @@ -1,26 +1,26 @@ package model.databases.sqlite import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import java.io.File import model.databases.sqlite.dao.edge.Edge +import model.databases.sqlite.dao.edge.Edges import model.databases.sqlite.dao.vertices.Vertex import model.databases.sqlite.dao.vertices.Vertices import model.databases.sqlite.dao.verticesView.VertexView import model.databases.sqlite.dao.verticesView.VerticesView -import androidx.compose.ui.unit.dp -import model.databases.sqlite.dao.edge.Edges import model.graph.Graph - import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.exists import org.jetbrains.exposed.sql.transactions.transaction import viewmodel.graph.GraphViewModel -import java.io.File class SQLiteDBHandler { lateinit var graph: Graph lateinit var graphViewModel: GraphViewModel var vertexViewModelFlag = false + fun open(file: File, weighted: Boolean, directed: Boolean) { Database.connect("jdbc:sqlite:$file", driver = "org.sqlite.JDBC") val newGraph = Graph() @@ -33,24 +33,26 @@ class SQLiteDBHandler { Edge.all().forEach { edge -> var weight = edge.weight if (!weighted) { - weight = 1L + weight = 1f } newGraph.addEdge( - edge.first!!.id.toString().toInt(), edge.second!!.id.toString().toInt(), + edge.first!!.id.toString().toInt(), + edge.second!!.id.toString().toInt(), weight, edge.id.toString().toInt() ) if (!newGraph.isDirected) { - newGraph.vertices[edge.second!!.id.toString().toInt()]!!.incidentEdges.add( - edge.id.toString().toInt() - ) + newGraph.vertices[edge.second!!.id.toString().toInt()]!! + .incidentEdges + .add(edge.id.toString().toInt()) } - newGraph.vertices[edge.first!!.id.toString().toInt()]!!.incidentEdges.add(edge.id.toString().toInt()) + newGraph.vertices[edge.first!!.id.toString().toInt()]!! + .incidentEdges + .add(edge.id.toString().toInt()) if (VerticesView.exists()) { vertexViewModelFlag = true } } - } if (vertexViewModelFlag) { val newGraphViewModel = GraphViewModel(newGraph) @@ -86,7 +88,7 @@ class SQLiteDBHandler { graph.getEdges().forEach { var newWeight = it.weight if (!weighted) { - newWeight = 1L + newWeight = 1f } Edge.new { first = Vertex.find { Vertices.id eq it.vertices.first }.first() @@ -95,14 +97,21 @@ class SQLiteDBHandler { } } graphView.verticesViewValues.forEach { - - val xDoubled: Double = it.x.toString().substring(0, it.x.toString().length - 4).toDouble() - val yDoubled: Double = it.y.toString().substring(0, it.x.toString().length - 4).toDouble() - val rDoubled: Double = it.radius.toString().substring(0, it.x.toString().length - 4).toDouble() + val xDoubled: Double = + it.x.toString().substring(0, it.x.toString().length - 4).toDouble() + val yDoubled: Double = + it.y.toString().substring(0, it.x.toString().length - 4).toDouble() + val rDoubled: Double = + it.radius.toString().substring(0, it.x.toString().length - 4).toDouble() VertexView.new { vertex = Vertex.find { Vertices.id eq it.vertex.id }.first() - color = it.color.red.toString() + ":" + it.color.green.toString() + ":" + it.color.blue.toString() + color = + it.color.red.toString() + + ":" + + it.color.green.toString() + + ":" + + it.color.blue.toString() x = xDoubled y = yDoubled r = rDoubled diff --git a/src/main/kotlin/model/databases/sqlite/dao/edge/Edge.kt b/src/main/kotlin/model/databases/sqlite/dao/edge/Edge.kt index 7d966e3..d18bbd0 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/edge/Edge.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/edge/Edge.kt @@ -11,4 +11,4 @@ class Edge(id: EntityID) : IntEntity(id) { var first by Vertex optionalReferencedOn Edges.first var second by Vertex optionalReferencedOn Edges.second var weight by Edges.weight -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt index a60d221..3e9cad4 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt @@ -6,5 +6,5 @@ import org.jetbrains.exposed.dao.id.IntIdTable object Edges : IntIdTable("Edges") { val first = reference("first", Vertices).nullable() val second = reference("second", Vertices).nullable() - val weight = long("weight") + val weight = float("weight") } \ No newline at end of file diff --git a/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertex.kt b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertex.kt index c9f30bd..b96086a 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertex.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertex.kt @@ -10,4 +10,4 @@ class Vertex(id: EntityID) : IntEntity(id) { var data by Vertices.data var community by Vertices.community -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt index 06f96d1..baffd24 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/vertices/Vertices.kt @@ -5,4 +5,4 @@ import org.jetbrains.exposed.dao.id.IntIdTable object Vertices : IntIdTable("Vertices") { val data = varchar("data", 255) val community = integer("community") -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/databases/sqlite/dao/verticesView/VertexView.kt b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VertexView.kt index e945ef7..ad14208 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/verticesView/VertexView.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VertexView.kt @@ -1,6 +1,5 @@ package model.databases.sqlite.dao.verticesView - import model.databases.sqlite.dao.vertices.Vertex import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass @@ -15,4 +14,4 @@ class VertexView(id: EntityID) : IntEntity(id) { var y by VerticesView.y var r by VerticesView.r var color by VerticesView.color -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt index 255704d..bf46353 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/verticesView/VerticesView.kt @@ -9,4 +9,4 @@ object VerticesView : IntIdTable("VerticesView") { val y = double("y") val r = double("r") val color = varchar("color", 255) -} \ No newline at end of file +} diff --git a/src/main/kotlin/model/graph/Edge.kt b/src/main/kotlin/model/graph/Edge.kt index e3968da..73c449f 100644 --- a/src/main/kotlin/model/graph/Edge.kt +++ b/src/main/kotlin/model/graph/Edge.kt @@ -2,8 +2,8 @@ package model.graph class Edge( val vertices: Pair, - var weight: Long = 1L, + var weight: Float = 1f, var id: Int = 1, ) { - //fun incident(v: Int) = v == vertices.first || v == vertices.second -} \ No newline at end of file + // fun incident(v: Int) = v == vertices.first || v == vertices.second +} diff --git a/src/main/kotlin/model/graph/Graph.kt b/src/main/kotlin/model/graph/Graph.kt index 8fb2db2..e98d625 100644 --- a/src/main/kotlin/model/graph/Graph.kt +++ b/src/main/kotlin/model/graph/Graph.kt @@ -15,9 +15,10 @@ class Graph { return vertices.getOrPut(id) { newVertex } } - fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Long = 1L, edgeID: Int): Edge { + fun addEdge(firstVertexID: Int, secondVertexID: Int, weight: Float = 1f, edgeID: Int): Edge { if (!isDirected) { - vertices[secondVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("Wrong database") + vertices[secondVertexID]?.incidentEdges?.add(edgeID) + ?: throw Exception("Wrong database") vertices[secondVertexID]?.adjacentVertices?.add(vertices[firstVertexID]!!) } vertices[firstVertexID]?.incidentEdges?.add(edgeID) ?: throw Exception("Wrong database") diff --git a/src/main/kotlin/model/graph/Vertex.kt b/src/main/kotlin/model/graph/Vertex.kt index ef4b3d2..1e4a000 100644 --- a/src/main/kotlin/model/graph/Vertex.kt +++ b/src/main/kotlin/model/graph/Vertex.kt @@ -7,4 +7,4 @@ class Vertex( var id: Int = 0 var community: Int = -1 val adjacentVertices: MutableList = mutableListOf() -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index 0bfedb8..91feba8 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -1,22 +1,15 @@ package view -import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.* -import androidx.compose.material.AlertDialog import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import controller.GraphPainterByCommunity import controller.GraphPainterByDjikstra import controller.GraphPainterByKosaraju -import model.algorithms.BridgeFinder import view.algos.bridgeHighlighter import viewmodel.CanvasViewModel -import viewmodel.graph.VertexViewModel @Composable fun AlgorithmSubMenu(viewModel: CanvasViewModel) { @@ -27,7 +20,7 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { Column(Modifier.padding(start = 16.dp, end = 0.dp, top = 15.dp)) { Button( - onClick = { /*TODO*/ }, + onClick = { /*TODO*/}, enabled = true, ) { Text( @@ -64,17 +57,13 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { showDialog.value = false viewModel.graph.let { graph -> - val painter = GraphPainterByDjikstra(graph, viewModel.graphViewModel, startIdx, endIdx) + val painter = + GraphPainterByDjikstra(graph, viewModel.graphViewModel, startIdx, endIdx) painter.paint() } } } - Button( - enabled = true, - onClick = { - bridgesHiglight.value = !bridgesHiglight.value - }) - { + Button(enabled = true, onClick = { bridgesHiglight.value = !bridgesHiglight.value }) { Text( text = "Поиск мостов", ) @@ -83,7 +72,7 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { bridgeHighlighter(viewModel.bridges) } Button( - onClick = { /*TODO*/ }, + onClick = { /*TODO*/}, enabled = true, ) { Text( @@ -91,16 +80,14 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { ) } Button( - onClick = { - showDialog.value = true - }, + onClick = { showDialog.value = true }, enabled = true, modifier = Modifier.padding(top = 3.dp) ) { Text(text = "Кратчайший путь алгоритмом Дейкстры") } Button( - onClick = { /*TODO*/ }, + onClick = { /*TODO*/}, enabled = true, modifier = Modifier.padding(top = 3.dp), ) { @@ -109,4 +96,4 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { ) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 7380e8a..e602958 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -1,14 +1,12 @@ package view import androidx.compose.animation.AnimatedVisibility - import androidx.compose.foundation.layout.* import androidx.compose.material.Surface import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu - import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf @@ -18,19 +16,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp - import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties +import java.io.File import kotlinx.coroutines.launch import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository import model.databases.sqlite.SQLiteDBHandler import view.graph.GraphView import viewmodel.CanvasViewModel - import viewmodel.LoadGraphMenuViewModel -import java.io.File - @Composable fun Canvas(viewModel: CanvasViewModel) { @@ -50,17 +45,16 @@ fun Canvas(viewModel: CanvasViewModel) { onDismissRequest = { showDialog.value = false }, properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) ) { - Column( - modifier = Modifier.padding(16.dp) - ) { + Column(modifier = Modifier.padding(16.dp)) { Text("Choose where to save the graph:") CustomRadioGroup( selectedOption = storageType.value.toString(), - options = listOf( - StorageType.FILE.toString(), - StorageType.NEO4J.toString(), - StorageType.SQLITE.toString() - ), + options = + listOf( + StorageType.FILE.toString(), + StorageType.NEO4J.toString(), + StorageType.SQLITE.toString() + ), onOptionSelected = { storageType.value = StorageType.valueOf(it) } ) @@ -85,7 +79,6 @@ fun Canvas(viewModel: CanvasViewModel) { ) Spacer(modifier = Modifier.width(8.dp)) } - StorageType.NEO4J -> { TextField( value = uri.value, @@ -117,7 +110,6 @@ fun Canvas(viewModel: CanvasViewModel) { ) Spacer(modifier = Modifier.width(8.dp)) } - StorageType.SQLITE -> { TextField( value = fileName.value, @@ -140,9 +132,9 @@ fun Canvas(viewModel: CanvasViewModel) { onClick = { when (storageType.value) { StorageType.FILE -> { - // Логика сохранения в файл с использованием fileName и isDirectedGraph + // Логика сохранения в файл с использованием fileName и + // isDirectedGraph } - StorageType.NEO4J -> { // Логика сохранения в Neo4j val repo = Neo4jRepository(uri.value, login.value, password.value) @@ -152,12 +144,16 @@ fun Canvas(viewModel: CanvasViewModel) { handler.saveGraphToNeo4j(viewModel.graph) viewModel.graph.isDirected = wasGraphDirected } - StorageType.SQLITE -> { val fileAddress = "saves/sqlite/${fileName.value}" val dataBase = File(fileAddress) val sqlHandler = SQLiteDBHandler() - sqlHandler.save(dataBase, viewModel.graph, viewModel.graphViewModel, isWeighted.value) + sqlHandler.save( + dataBase, + viewModel.graph, + viewModel.graphViewModel, + isWeighted.value + ) } } showDialog.value = false @@ -173,17 +169,14 @@ fun Canvas(viewModel: CanvasViewModel) { contentColor = Color.LightGray, color = Color.DarkGray ) { - val showSubMenu = remember { - mutableStateOf(false) - } + val showSubMenu = remember { mutableStateOf(false) } ModalNavigationDrawer( drawerState = drawerState, gesturesEnabled = true, drawerContent = { ModalDrawerSheet { Row { - IconButton(onClick = { scope.launch { drawerState.close() } } - ) { + IconButton(onClick = { scope.launch { drawerState.close() } }) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } Text("Menu", modifier = Modifier.padding(16.dp)) @@ -192,32 +185,15 @@ fun Canvas(viewModel: CanvasViewModel) { NavigationDrawerItem( label = { Text(text = "Доступные алгоритмы") }, - icon = { - Icon( - Icons.Filled.List, - contentDescription = null - ) - }, + icon = { Icon(Icons.Filled.List, contentDescription = null) }, selected = false, onClick = { showSubMenu.value = !showSubMenu.value } ) - AnimatedVisibility(visible = showSubMenu.value) { - AlgorithmSubMenu(viewModel) - } - Button(onClick = { viewModel.isOpenLoadGraph = true }) { - Text("Load graph") - } - Button( - enabled = true, - onClick = { - scope.launch { - showDialog.value = true - } - } - ) { + AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu(viewModel) } + Button(onClick = { viewModel.isOpenLoadGraph = true }) { Text("Load graph") } + Button(enabled = true, onClick = { scope.launch { showDialog.value = true } }) { Text(text = "Save Graph") } - } }, ) { @@ -227,16 +203,11 @@ fun Canvas(viewModel: CanvasViewModel) { text = { Text("Show drawer") }, icon = { Icon(Icons.Filled.Add, contentDescription = "") }, onClick = { - scope.launch { - drawerState.apply { - if (isClosed) open() else close() - } - } + scope.launch { drawerState.apply { if (isClosed) open() else close() } } } ) } - ) - { + ) { IconButton(onClick = { scope.launch { drawerState.open() } }) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } @@ -249,4 +220,3 @@ fun Canvas(viewModel: CanvasViewModel) { LoadGraph(LoadGraphMenuViewModel(viewModel)) } } - diff --git a/src/main/kotlin/view/CustomRadioView.kt b/src/main/kotlin/view/CustomRadioView.kt index 5523579..3e6e405 100644 --- a/src/main/kotlin/view/CustomRadioView.kt +++ b/src/main/kotlin/view/CustomRadioView.kt @@ -1,7 +1,6 @@ package view import androidx.compose.foundation.background - import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button @@ -10,7 +9,6 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @Composable @@ -18,23 +16,20 @@ fun CustomRadioGroup( options: List, selectedOption: String, onOptionSelected: (String) -> Unit - ) { var isBoxSelected1 by remember { mutableStateOf(false) } var isBoxSelected2 by remember { mutableStateOf(false) } var isBoxSelected3 by remember { mutableStateOf(false) } Column { - Row( - verticalAlignment = Alignment.CenterVertically - ) { + Row(verticalAlignment = Alignment.CenterVertically) { Box( - modifier = Modifier - .background(shape = CircleShape, color = Color.Gray) - .background(if (isBoxSelected1) Color.DarkGray else Color.Gray) - .height(50.dp) - .padding(8.dp) - .weight(1f) + modifier = + Modifier.background(shape = CircleShape, color = Color.Gray) + .background(if (isBoxSelected1) Color.DarkGray else Color.Gray) + .height(50.dp) + .padding(8.dp) + .weight(1f) ) { Text("NEO4J", color = Color.Black) } @@ -52,15 +47,12 @@ fun CustomRadioGroup( } Spacer(modifier = Modifier.height(8.dp)) - Row( - verticalAlignment = Alignment.CenterVertically - ) { + Row(verticalAlignment = Alignment.CenterVertically) { Box( - modifier = Modifier - .background(if (isBoxSelected2) Color.DarkGray else Color.Gray) - .padding(8.dp) - .weight(1f) - + modifier = + Modifier.background(if (isBoxSelected2) Color.DarkGray else Color.Gray) + .padding(8.dp) + .weight(1f) ) { Text("FILE", color = Color.Black) } @@ -78,15 +70,12 @@ fun CustomRadioGroup( } Spacer(modifier = Modifier.height(8.dp)) - Row( - verticalAlignment = Alignment.CenterVertically - ) { + Row(verticalAlignment = Alignment.CenterVertically) { Box( - modifier = Modifier - .background(if (isBoxSelected3) Color.DarkGray else Color.Gray) - .padding(8.dp) - .weight(1f) - + modifier = + Modifier.background(if (isBoxSelected3) Color.DarkGray else Color.Gray) + .padding(8.dp) + .weight(1f) ) { Text("SQLITE", color = Color.Black) } @@ -103,4 +92,4 @@ fun CustomRadioGroup( } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/LoadGraphMenu.kt b/src/main/kotlin/view/LoadGraphMenu.kt index 9105563..912df3b 100644 --- a/src/main/kotlin/view/LoadGraphMenu.kt +++ b/src/main/kotlin/view/LoadGraphMenu.kt @@ -1,6 +1,5 @@ package view - import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* @@ -12,12 +11,12 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogWindow import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.rememberDialogState +import java.io.File import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository import model.databases.sqlite.SQLiteDBHandler import viewmodel.LoadGraphMenuViewModel import viewmodel.graph.GraphViewModel -import java.io.File @Composable fun LoadGraph(viewModel: LoadGraphMenuViewModel) { @@ -25,44 +24,40 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { var isWeighted by remember { mutableStateOf(false) } var isDirected by remember { mutableStateOf(false) } - val storageType = remember { mutableStateOf(StorageType.FILE) } var fileAddress by remember { mutableStateOf("") } var uri by remember { mutableStateOf("") } var login by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } - DialogWindow( onCloseRequest = { viewModel.canvasViewModel.isOpenLoadGraph = false }, - state = rememberDialogState(position = WindowPosition(Alignment.Center), size = DpSize(800.dp, 640.dp)), + state = + rememberDialogState( + position = WindowPosition(Alignment.Center), + size = DpSize(800.dp, 640.dp) + ), title = "Load New Graph", resizable = false ) { - Column( - Modifier - .fillMaxSize() - .padding(4.dp) - ) { + Column(Modifier.fillMaxSize().padding(4.dp)) { val modifierRow = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) val verticalRow = Alignment.CenterVertically - Row(modifierRow, verticalAlignment = verticalRow) { + Row(modifierRow, verticalAlignment = verticalRow) {} - } Row(modifierRow, verticalAlignment = verticalRow) { Column( - modifier = Modifier - .height(450.dp) - .padding(16.dp), + modifier = Modifier.height(450.dp).padding(16.dp), verticalArrangement = Arrangement.Top ) { CustomRadioGroup( - options = listOf( - StorageType.FILE.toString(), - StorageType.NEO4J.toString(), - StorageType.SQLITE.toString() - ), + options = + listOf( + StorageType.FILE.toString(), + StorageType.NEO4J.toString(), + StorageType.SQLITE.toString() + ), selectedOption = storageType.value.toString(), onOptionSelected = { storageType.value = StorageType.valueOf(it) } ) @@ -72,26 +67,24 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { "Path to Database:", modifier = Modifier.weight(0.5f), textAlign = TextAlign.Center, - - ) + ) OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, - onValueChange = { newValue -> viewModel.graphName.value = newValue }, + onValueChange = { newValue -> + viewModel.graphName.value = newValue + }, label = { Text("Path") }, singleLine = true, - colors = TextFieldDefaults.textFieldColors( - ), + colors = TextFieldDefaults.textFieldColors(), ) } - StorageType.NEO4J -> { Text( "URI:", modifier = Modifier.weight(0.5f), textAlign = TextAlign.Center, - - ) + ) OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, @@ -101,15 +94,13 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { }, label = { Text("URI") }, singleLine = true, - colors = TextFieldDefaults.textFieldColors( - ), + colors = TextFieldDefaults.textFieldColors(), ) Text( "Login:", modifier = Modifier.weight(0.5f), textAlign = TextAlign.Center, - - ) + ) OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, @@ -119,15 +110,13 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { }, label = { Text("Login") }, singleLine = true, - colors = TextFieldDefaults.textFieldColors( - ), + colors = TextFieldDefaults.textFieldColors(), ) Text( "Password:", modifier = Modifier.weight(0.5f), textAlign = TextAlign.Center, - - ) + ) OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, @@ -137,18 +126,15 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { }, label = { Text("Password") }, singleLine = true, - colors = TextFieldDefaults.textFieldColors( - ), + colors = TextFieldDefaults.textFieldColors(), ) } - StorageType.SQLITE -> { Text( "Path to Database:", modifier = Modifier.weight(0.5f), textAlign = TextAlign.Center, - - ) + ) OutlinedTextField( modifier = Modifier.weight(1f), value = viewModel.graphName.value, @@ -158,33 +144,21 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { }, label = { Text("Path") }, singleLine = true, - colors = TextFieldDefaults.textFieldColors( - ), + colors = TextFieldDefaults.textFieldColors(), ) - } } } - } Row(modifierRow, verticalAlignment = verticalRow) { - Checkbox( - checked = isWeighted, - onCheckedChange = { isWeighted = it } - ) + Checkbox(checked = isWeighted, onCheckedChange = { isWeighted = it }) Text("Weighted") - Checkbox( - checked = isDirected, - onCheckedChange = { isDirected = it } - ) + Checkbox(checked = isDirected, onCheckedChange = { isDirected = it }) Text("Directed") - } Row(modifierRow, verticalAlignment = verticalRow) { Spacer(modifier = Modifier.weight(1f)) - Button(onClick = { viewModel.canvasViewModel.isOpenLoadGraph = false } - - ) { + Button(onClick = { viewModel.canvasViewModel.isOpenLoadGraph = false }) { Text("Cancel") } Spacer(modifier = Modifier.weight(0.01f)) @@ -192,9 +166,9 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { onClick = { when (storageType.value) { StorageType.FILE -> { - // Логика сохранения в файл с использованием fileName и isDirectedGraph + // Логика сохранения в файл с использованием fileName и + // isDirectedGraph } - StorageType.NEO4J -> { val repository = Neo4jRepository(uri, login, password) val handler = Neo4jHandler(repository) @@ -204,7 +178,6 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { viewModel.canvasViewModel.graphViewModel = GraphViewModel(newGraph) viewModel.canvasViewModel.isOpenLoadGraph = false } - StorageType.SQLITE -> { fileAddress = "saves/sqlite/$fileAddress" val dataBase: File = File(fileAddress) @@ -212,17 +185,20 @@ fun LoadGraph(viewModel: LoadGraphMenuViewModel) { sqlHandler.open(dataBase, isWeighted, isDirected) viewModel.canvasViewModel.graph = sqlHandler.graph if (sqlHandler.vertexViewModelFlag) { - viewModel.canvasViewModel.graphViewModel.graph = sqlHandler.graph - viewModel.canvasViewModel.graphViewModel = sqlHandler.graphViewModel + viewModel.canvasViewModel.graphViewModel.graph = + sqlHandler.graph + viewModel.canvasViewModel.graphViewModel = + sqlHandler.graphViewModel } else { - viewModel.canvasViewModel.graphViewModel = GraphViewModel(sqlHandler.graph) + viewModel.canvasViewModel.graphViewModel = + GraphViewModel(sqlHandler.graph) } viewModel.canvasViewModel.representationStrategy.place( - 1280.0, 860.0, + 1280.0, + 860.0, viewModel.canvasViewModel.graphViewModel ) } - } viewModel.canvasViewModel.isOpenLoadGraph = false } diff --git a/src/main/kotlin/view/NavigationDrawer.kt b/src/main/kotlin/view/NavigationDrawer.kt index 7ad1497..185bfb5 100644 --- a/src/main/kotlin/view/NavigationDrawer.kt +++ b/src/main/kotlin/view/NavigationDrawer.kt @@ -1,19 +1,16 @@ package view import androidx.compose.animation.AnimatedVisibility - import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu - import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope - import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -26,17 +23,14 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() - val showSubMenu = remember { - mutableStateOf(false) - } + val showSubMenu = remember { mutableStateOf(false) } ModalNavigationDrawer( drawerState = drawerState, gesturesEnabled = true, drawerContent = { ModalDrawerSheet { Row { - IconButton(onClick = { scope.launch { drawerState.close() } } - ) { + IconButton(onClick = { scope.launch { drawerState.close() } }) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } Text("Menu", modifier = Modifier.padding(16.dp)) @@ -44,28 +38,27 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { Divider() NavigationDrawerItem( label = { Text(text = "Доступные алгоритмы") }, - icon = { - Icon( - Icons.Filled.List, - contentDescription = null - ) - }, + icon = { Icon(Icons.Filled.List, contentDescription = null) }, selected = false, onClick = { showSubMenu.value = !showSubMenu.value } ) - AnimatedVisibility(visible = showSubMenu.value) { - AlgorithmSubMenu(viewModel) - } + AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu(viewModel) } Row { - Checkbox(checked = viewModel.showVerticesLabels.value, onCheckedChange = { - viewModel.showVerticesLabels.value = it - }) - Text("Show vertices labels", fontSize = 20.sp, modifier = Modifier.padding(0.dp)) + Checkbox( + checked = viewModel.showVerticesLabels.value, + onCheckedChange = { viewModel.showVerticesLabels.value = it } + ) + Text( + "Show vertices labels", + fontSize = 20.sp, + modifier = Modifier.padding(0.dp) + ) } Row { - Checkbox(checked = viewModel.showEdgesLabels.value, onCheckedChange = { - viewModel.showEdgesLabels.value = it - }) + Checkbox( + checked = viewModel.showEdgesLabels.value, + onCheckedChange = { viewModel.showEdgesLabels.value = it } + ) Text("Show edges labels", fontSize = 20.sp, modifier = Modifier.padding(4.dp)) } } @@ -77,17 +70,15 @@ fun NavigationDrawer(viewModel: CanvasViewModel) { text = { Text("Add graph") }, icon = { Icon(Icons.Filled.Add, contentDescription = "") }, onClick = { - scope.launch { - drawerState.apply { - if (isClosed) open() else close() - } - } + scope.launch { drawerState.apply { if (isClosed) open() else close() } } } ) } - ) { GraphView(viewModel.graphViewModel) } + ) { + GraphView(viewModel.graphViewModel) + } IconButton(onClick = { scope.launch { drawerState.open() } }) { Icon(Icons.Filled.Menu, contentDescription = "Меню") } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/ShortestPathDialog.kt b/src/main/kotlin/view/ShortestPathDialog.kt index e915910..e0048bc 100644 --- a/src/main/kotlin/view/ShortestPathDialog.kt +++ b/src/main/kotlin/view/ShortestPathDialog.kt @@ -14,10 +14,7 @@ import androidx.compose.ui.unit.dp @OptIn(ExperimentalMaterial3Api::class) @Composable -fun ShortestPathDialog( - showDialog: MutableState, - onPathSelected: (Int, Int) -> Unit -) { +fun ShortestPathDialog(showDialog: MutableState, onPathSelected: (Int, Int) -> Unit) { var startIdx by remember { mutableStateOf(0) } var endIdx by remember { mutableStateOf(0) } @@ -25,10 +22,12 @@ fun ShortestPathDialog( AlertDialog( onDismissRequest = { showDialog.value = false }, buttons = { - Button(onClick = { - onPathSelected(startIdx, endIdx) - showDialog.value = false - }) { + Button( + onClick = { + onPathSelected(startIdx, endIdx) + showDialog.value = false + } + ) { Text("Найти кратчайший путь") } }, @@ -49,4 +48,4 @@ fun ShortestPathDialog( } ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/StorageType.kt b/src/main/kotlin/view/StorageType.kt index cb8120d..2c4af37 100644 --- a/src/main/kotlin/view/StorageType.kt +++ b/src/main/kotlin/view/StorageType.kt @@ -4,4 +4,4 @@ enum class StorageType { FILE, NEO4J, SQLITE -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/algos/BridgeFinderView.kt b/src/main/kotlin/view/algos/BridgeFinderView.kt index 2a2451b..6b0d630 100644 --- a/src/main/kotlin/view/algos/BridgeFinderView.kt +++ b/src/main/kotlin/view/algos/BridgeFinderView.kt @@ -1,18 +1,10 @@ package view.algos -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.ui.Modifier -import androidx.compose.foundation.Canvas import androidx.compose.runtime.Composable -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.zIndex - -import viewmodel.CanvasViewModel import viewmodel.algos.BridgeFinderViewModel -import viewmodel.graph.VertexViewModel -//просто окрашиваю прилегающие вершины в красный цвет +// просто окрашиваю прилегающие вершины в красный цвет @Composable fun bridgeHighlighter(bridges: BridgeFinderViewModel) { val pairs = bridges.pairsList @@ -20,4 +12,4 @@ fun bridgeHighlighter(bridges: BridgeFinderViewModel) { pair.first.color = Color.Red pair.second.color = Color.Red } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/graph/EdgeView.kt b/src/main/kotlin/view/graph/EdgeView.kt index 165e79c..983ee1b 100644 --- a/src/main/kotlin/view/graph/EdgeView.kt +++ b/src/main/kotlin/view/graph/EdgeView.kt @@ -16,15 +16,17 @@ fun EdgeView( ) { Canvas(modifier = modifier.fillMaxSize().zIndex(-1f)) { drawLine( - start = Offset( - viewModel.u.x.toPx() + viewModel.u.radius.toPx(), - viewModel.u.y.toPx() + viewModel.u.radius.toPx(), - ), - end = Offset( - viewModel.v.x.toPx() + viewModel.v.radius.toPx(), - viewModel.v.y.toPx() + viewModel.v.radius.toPx(), - ), + start = + Offset( + viewModel.u.x.toPx() + viewModel.u.radius.toPx(), + viewModel.u.y.toPx() + viewModel.u.radius.toPx(), + ), + end = + Offset( + viewModel.v.x.toPx() + viewModel.v.radius.toPx(), + viewModel.v.y.toPx() + viewModel.v.radius.toPx(), + ), color = Color.Black ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/graph/GraphView.kt b/src/main/kotlin/view/graph/GraphView.kt index 6742eb5..219a180 100644 --- a/src/main/kotlin/view/graph/GraphView.kt +++ b/src/main/kotlin/view/graph/GraphView.kt @@ -10,16 +10,8 @@ import viewmodel.graph.GraphViewModel fun GraphView( viewModel: GraphViewModel, ) { - Box( - modifier = Modifier - .fillMaxSize() - - ) { - viewModel.verticesViewValues.forEach { v -> - VertexView(v, Modifier) - } - viewModel.edgesViewValues.forEach { e -> - EdgeView(e, Modifier) - } + Box(modifier = Modifier.fillMaxSize()) { + viewModel.verticesViewValues.forEach { v -> VertexView(v, Modifier) } + viewModel.edgesViewValues.forEach { e -> EdgeView(e, Modifier) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt index c7d6959..7668cc1 100644 --- a/src/main/kotlin/view/graph/VertexView.kt +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -7,10 +7,10 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.material.Text import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp @@ -21,28 +21,25 @@ fun VertexView( viewModel: VertexViewModel, modifier: Modifier = Modifier, ) { - Box(modifier = modifier - .size(viewModel.radius + 10.dp, viewModel.radius + 10.dp) - .offset(viewModel.x, viewModel.y) - .border(2.dp, Color.Black, CircleShape) - .background( - color = viewModel.color, - shape = CircleShape - ) - .pointerInput(viewModel) { - detectDragGestures { change, dragAmount -> - change.consume() - viewModel.onDrag(dragAmount) - } - } + Box( + modifier = + modifier + .size(viewModel.radius + 10.dp, viewModel.radius + 10.dp) + .offset(viewModel.x, viewModel.y) + .border(2.dp, Color.Black, CircleShape) + .background(color = viewModel.color, shape = CircleShape) + .pointerInput(viewModel) { + detectDragGestures { change, dragAmount -> + change.consume() + viewModel.onDrag(dragAmount) + } + } ) { if (viewModel.labelVisible) { Text( - modifier = Modifier - .align(Alignment.Center) - .offset(0.dp, -viewModel.radius - 10.dp), + modifier = Modifier.align(Alignment.Center).offset(0.dp, -viewModel.radius - 10.dp), text = viewModel.label, ) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 623a6d1..c7cdcd8 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -21,6 +21,5 @@ class CanvasViewModel(var graph: Graph, val representationStrategy: Representati init { representationStrategy.place(1280.0, 860.0, graphViewModel) - } -} \ No newline at end of file +} diff --git a/src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt b/src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt index dd34121..fdb2ac2 100644 --- a/src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt +++ b/src/main/kotlin/viewmodel/algos/BridgeFinderViewModel.kt @@ -2,14 +2,14 @@ package viewmodel.algos import model.algorithms.BridgeFinder import model.graph.Graph -import org.gephi.graph.api.GraphView import viewmodel.graph.GraphViewModel import viewmodel.graph.VertexViewModel class BridgeFinderViewModel(graph: Graph, graphView: GraphViewModel) { val bridgeFinder = BridgeFinder(graph) val pairsList = mutableListOf>() - init{ + + init { bridgeFinder.findBridges() val edges = bridgeFinder.bridges edges.forEach { bridge -> @@ -19,7 +19,4 @@ class BridgeFinderViewModel(graph: Graph, graphView: GraphViewModel) { pairsList.add(Pair(firstEnd, secondEnd)) } } - - - -} \ No newline at end of file +} diff --git a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt index 3e96307..41ecd88 100644 --- a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt @@ -9,4 +9,4 @@ class EdgeViewModel( ) { val weight get() = e.weight.toString() -} \ No newline at end of file +} diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index 153bf32..a07f89f 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -1,17 +1,14 @@ package viewmodel.graph - import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import model.graph.Graph import model.graph.Edge +import model.graph.Graph import model.graph.Vertex - class GraphViewModel( var graph: Graph, - - ) { +) { val verticesView: HashMap = hashMapOf() @@ -25,24 +22,24 @@ class GraphViewModel( init { graph.getEdges().forEach { edge -> - val fst = verticesView[graph.vertices[edge.vertices.first]] - ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.first} not found") - val snd = verticesView[graph.vertices[edge.vertices.second]] - ?: throw IllegalStateException("VertexView for vertex with id: ${edge.vertices.second} not found") + val fst = + verticesView[graph.vertices[edge.vertices.first]] + ?: throw IllegalStateException( + "VertexView for vertex with id: ${edge.vertices.first} not found" + ) + val snd = + verticesView[graph.vertices[edge.vertices.second]] + ?: throw IllegalStateException( + "VertexView for vertex with id: ${edge.vertices.second} not found" + ) val currentEdgeView = EdgeViewModel(fst, snd, edge) edgesView[edge] = currentEdgeView } - } - val verticesViewValues: Collection get() = verticesView.values val edgesViewValues: Collection get() = edgesView.values - } - - - diff --git a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt index bc56fc1..3470036 100644 --- a/src/main/kotlin/viewmodel/graph/VertexViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/VertexViewModel.kt @@ -23,12 +23,14 @@ class VertexViewModel( set(value) { _x.value = value } + private var _y = mutableStateOf(y) var y: Dp get() = _y.value set(value) { _y.value = value } + private var _color = mutableStateOf(color) var color: Color get() = _color.value @@ -38,6 +40,7 @@ class VertexViewModel( val label get() = vertex.data + val labelVisible get() = _labelVisible.value @@ -45,4 +48,4 @@ class VertexViewModel( _x.value += offset.x.dp _y.value += offset.y.dp } -} \ No newline at end of file +} diff --git a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt index 572f58a..eb8b83f 100644 --- a/src/main/kotlin/viewmodel/layouts/CircularLayout.kt +++ b/src/main/kotlin/viewmodel/layouts/CircularLayout.kt @@ -2,15 +2,14 @@ package viewmodel.layouts import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import org.gephi.graph.api.GraphView -import viewmodel.graph.GraphViewModel -import viewmodel.graph.VertexViewModel import kotlin.math.cos import kotlin.math.min import kotlin.math.sin import kotlin.random.Random +import viewmodel.graph.GraphViewModel +import viewmodel.graph.VertexViewModel -class CircularLayout: RepresentationStrategy { +class CircularLayout : RepresentationStrategy { override fun place(width: Double, height: Double, graph: GraphViewModel) { val vertices = graph.verticesViewValues if (vertices.isEmpty()) { @@ -28,31 +27,30 @@ class CircularLayout: RepresentationStrategy { first.y = point.second.dp first.color = Color.Gray - sorted - .drop(1) - .onEach { - point = point.rotate(center, angle) - it.x = point.first.dp - it.y = point.second.dp - } + sorted.drop(1).onEach { + point = point.rotate(center, angle) + it.x = point.first.dp + it.y = point.second.dp + } } override fun highlight(vertices: Collection) { - vertices - .onEach { - it.color = if (Random.nextBoolean()) Color.Green else Color.Blue - } + vertices.onEach { it.color = if (Random.nextBoolean()) Color.Green else Color.Blue } } - private fun Pair.rotate(pivot: Pair, angle: Double): Pair { + private fun Pair.rotate( + pivot: Pair, + angle: Double + ): Pair { val sin = sin(angle) val cos = cos(angle) val diff = first - pivot.first to second - pivot.second - val rotated = Pair( - diff.first * cos - diff.second * sin, - diff.first * sin + diff.second * cos, - ) + val rotated = + Pair( + diff.first * cos - diff.second * sin, + diff.first * sin + diff.second * cos, + ) return rotated.first + pivot.first to rotated.second + pivot.second } -} \ No newline at end of file +} diff --git a/src/main/kotlin/viewmodel/layouts/ForceAtlas2Layout.kt b/src/main/kotlin/viewmodel/layouts/ForceAtlas2Layout.kt index e446f00..10ca9d3 100644 --- a/src/main/kotlin/viewmodel/layouts/ForceAtlas2Layout.kt +++ b/src/main/kotlin/viewmodel/layouts/ForceAtlas2Layout.kt @@ -1,16 +1,15 @@ package viewmodel.layouts import androidx.compose.ui.unit.dp -import viewmodel.graph.GraphViewModel -import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 +import kotlin.random.Random import org.gephi.graph.api.Edge import org.gephi.graph.api.GraphController import org.gephi.graph.api.Node +import org.gephi.layout.plugin.forceAtlas2.ForceAtlas2 import org.gephi.project.api.ProjectController import org.openide.util.Lookup +import viewmodel.graph.GraphViewModel import viewmodel.graph.VertexViewModel -import kotlin.random.Random - class ForceAtlas2Layout : RepresentationStrategy { @@ -29,14 +28,12 @@ class ForceAtlas2Layout : RepresentationStrategy { graph.addNode(v) verticesMap[vertex.vertex.id] = v } - //TODO добавить возможность получения информации об ориентированности графа + // TODO добавить возможность получения информации об ориентированности графа for (edge in graphViewModel.edgesViewValues) { - val e: Edge = graphModel.factory().newEdge( - verticesMap[edge.u.vertex.id], - verticesMap[edge.v.vertex.id], - 1, - false - ) + val e: Edge = + graphModel + .factory() + .newEdge(verticesMap[edge.u.vertex.id], verticesMap[edge.v.vertex.id], 1, false) graph.addEdge(e) } val layout = ForceAtlas2(null) @@ -67,4 +64,4 @@ class ForceAtlas2Layout : RepresentationStrategy { override fun highlight(vertices: Collection) { TODO("Not yet implemented") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt index f4f9019..7421170 100644 --- a/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt +++ b/src/main/kotlin/viewmodel/layouts/RepresentationStrategy.kt @@ -5,5 +5,6 @@ import viewmodel.graph.VertexViewModel interface RepresentationStrategy { fun place(width: Double, height: Double, graph: GraphViewModel) + fun highlight(vertices: Collection) -} \ No newline at end of file +} diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index d911485..e052c04 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -2,56 +2,59 @@ package graphs.algorithms import model.algorithms.BridgeFinder import model.graph.Graph +import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.junit.jupiter.api.Assertions.* class BridgeFinderTest { private lateinit var graph: Graph + @BeforeEach fun setup() { - graph = Graph().apply { - addVertex(1,"Thomas Shelby") - addVertex(2, "Andrew Tate") - addVertex(3, "Iakov") - addVertex(4, "John Shelby") - addVertex(5, "Tristan Tate") - addVertex(6, "Arthur Shelby") - addVertex(7, "Ryan Gosling") - - addEdge(1, 2, 1,1) - addEdge(3, 4, 2,2) - addEdge(1, 3, 3,3) - addEdge(2, 4, 4,4) - addEdge(2, 5, 5,5) - addEdge(5, 7, 6,6) - - addVertex(8, "Pudge") - addVertex(9,"Tiny") - addVertex(10, "Lycan") - addVertex(11,"Io") - addVertex(12,"Lion") - addVertex(13,"Sniper") - addVertex(14,"Roshan") - - addEdge(14, 8, 7,7) - addEdge(14, 9, 8,8) - addEdge(14, 10, 9,9) - addEdge(14, 11, 10,10) - addEdge(14, 12, 11,11) - addEdge(14, 13, 12,12) - - addEdge(14, 3, 0,13) - } + graph = + Graph().apply { + addVertex(1, "Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "Tristan Tate") + addVertex(6, "Arthur Shelby") + addVertex(7, "Ryan Gosling") + + addEdge(1, 2, 1, 1) + addEdge(3, 4, 2, 2) + addEdge(1, 3, 3, 3) + addEdge(2, 4, 4, 4) + addEdge(2, 5, 5, 5) + addEdge(5, 7, 6, 6) + + addVertex(8, "Pudge") + addVertex(9, "Tiny") + addVertex(10, "Lycan") + addVertex(11, "Io") + addVertex(12, "Lion") + addVertex(13, "Sniper") + addVertex(14, "Roshan") + + addEdge(14, 8, 7, 7) + addEdge(14, 9, 8, 8) + addEdge(14, 10, 9, 9) + addEdge(14, 11, 10, 10) + addEdge(14, 12, 11, 11) + addEdge(14, 13, 12, 12) + + addEdge(14, 3, 0, 13) + } } + @Test @DisplayName("Multiple bridges, no multiple edges") - public fun MultipleBridgesNoMultipleEdges(){ + public fun MultipleBridgesNoMultipleEdges() { val bridgeFinder = BridgeFinder(graph) bridgeFinder.findBridges() val result = bridgeFinder.bridges val expectedBridges = listOf(7, 8, 9, 10, 11, 12, 13, 6, 5) - assertEquals(expectedBridges,result) + assertEquals(expectedBridges, result) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt index faea265..25b28af 100644 --- a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt +++ b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt @@ -2,8 +2,8 @@ package graphs.algorithms import model.algorithms.Djikstra import model.graph.Graph -import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test // table of path's // _________________________________________________________ @@ -64,12 +64,11 @@ class DjikstraTest { @Test fun `test findShortestPaths with sample graph start from 1 to 5 started from 1`() { // graph and algo initialization - val expected = mutableListOf(1,4,3,5) - val algorithm = Djikstra(graphD,1) + val expected = mutableListOf(1, 4, 3, 5) + val algorithm = Djikstra(graphD, 1) // path created from 1 algorithm.findShortestPaths() - val currently = algorithm.reconstructPath(5) assertTrue(expected == currently) @@ -78,7 +77,7 @@ class DjikstraTest { @Test fun `test findShortestPaths with sample graph start from 1 to 2`() { // graph and algo initialization - val expected = mutableListOf(1,2) + val expected = mutableListOf(1, 2) val algorithm = Djikstra(graphD, 1) algorithm.findShortestPaths() @@ -90,12 +89,11 @@ class DjikstraTest { @Test fun `test findShortestPaths with sample graph start from 2 to 3 started from 2`() { // graph and algo initialization - val expected = mutableListOf(2,3) - val algorithm = Djikstra(graphD,2) + val expected = mutableListOf(2, 3) + val algorithm = Djikstra(graphD, 2) // path created from 2 algorithm.findShortestPaths() - val currently = algorithm.reconstructPath(3) assertTrue(expected == currently) @@ -105,7 +103,7 @@ class DjikstraTest { fun `test findShortestPaths path does not exist`() { // graph and algo initialization val expected = mutableListOf() - val algorithm = Djikstra(graphD,2) + val algorithm = Djikstra(graphD, 2) // path created from 2 algorithm.findShortestPaths() @@ -117,8 +115,8 @@ class DjikstraTest { @Test fun `test findShortestPaths from 2 to 1 not directed graph`() { // graph and algo initialization - val expected = mutableListOf(2,1) - val algorithm = Djikstra(graph,2) + val expected = mutableListOf(2, 1) + val algorithm = Djikstra(graph, 2) // path created from 2 algorithm.findShortestPaths() @@ -130,8 +128,8 @@ class DjikstraTest { @Test fun `test findShortestPaths from 5 to 1 not directed graph`() { // graph and algo initialization - val expected = mutableListOf(5,3,4,1) - val algorithm = Djikstra(graph,5) + val expected = mutableListOf(5, 3, 4, 1) + val algorithm = Djikstra(graph, 5) // path created from 2 algorithm.findShortestPaths() @@ -210,4 +208,4 @@ class DjikstraTest { assertTrue(expected == currently) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt index 2a259ae..88e7226 100644 --- a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -3,7 +3,6 @@ package graphs.algorithms import model.algorithms.FordBellman import model.graph.Graph import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -12,84 +11,88 @@ class FordBellmanTest { @Test @DisplayName("Path without negative cycles") - public fun PathWithoutNegativeCycles(){ - graph = Graph().apply { - addVertex(1, "Thomas Shelby") - addVertex(2, "Andrew Tate") - addVertex(3, "Iakov") - addVertex(4, "John Shelby") - addVertex(5, "Arthur Shelby") - addEdge(1, 2, 3, 5) - addEdge(2, 3, 6, 2) - addEdge(1, 4, 2, 4) - addEdge(5, 3, 1, 3) - addEdge(1, 3, 5, 1) - addEdge(4, 5, 1, 6) - } + public fun PathWithoutNegativeCycles() { + graph = + Graph().apply { + addVertex(1, "Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "Arthur Shelby") + addEdge(1, 2, 3, 5) + addEdge(2, 3, 6, 2) + addEdge(1, 4, 2, 4) + addEdge(5, 3, 1, 3) + addEdge(1, 3, 5, 1) + addEdge(4, 5, 1, 6) + } val fordBellman = FordBellman(graph) - fordBellman.shortestPath(1,3) + fordBellman.shortestPath(1, 3) val resultVertices = fordBellman.resultPathVertices val resultEdges = fordBellman.resultPathEdges val resultCycles = fordBellman.cycleFlag val resultConnectionFlag = fordBellman.disconnectedGraphFlag val expectedCycles = false - val expectedEdges = listOf(3,6,4) - val expectedVertices = listOf(3,5,4,1) + val expectedEdges = listOf(3, 6, 4) + val expectedVertices = listOf(3, 5, 4, 1) val expectedConnectionFlag = false assertEquals(expectedConnectionFlag, resultConnectionFlag) assertEquals(expectedCycles, resultCycles) assertEquals(expectedEdges, resultEdges) assertEquals(expectedVertices, resultVertices) } + @Test @DisplayName("Path with negative cycles") - public fun PathWithNegativeCycles(){ - graph = Graph().apply { - addVertex(1, "Thomas Shelby") - addVertex(2, "Andrew Tate") - addVertex(3, "Iakov") - addVertex(4, "John Shelby") - addVertex(5, "John Shelby") + public fun PathWithNegativeCycles() { + graph = + Graph().apply { + addVertex(1, "Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "John Shelby") - addEdge(1, 2, -2, 3) - addEdge(2, 3, 1, 2) - addEdge(4, 1, -1, 1) - addEdge(3, 4, 1, 4) - addEdge(4, 5, 5, 5) - } + addEdge(1, 2, -2, 3) + addEdge(2, 3, 1, 2) + addEdge(4, 1, -1, 1) + addEdge(3, 4, 1, 4) + addEdge(4, 5, 5, 5) + } val fordBellman = FordBellman(graph) - fordBellman.shortestPath(1,5) + fordBellman.shortestPath(1, 5) val resultVertices = fordBellman.resultPathVertices val resultEdges = fordBellman.resultPathEdges val resultCycles = fordBellman.cycleFlag val resultConnectionFlag = fordBellman.disconnectedGraphFlag val expectedCycles = true - val expectedEdges = listOf(3,1,4,2) - val expectedVertices = listOf(2,1,4,3) + val expectedEdges = listOf(3, 1, 4, 2) + val expectedVertices = listOf(2, 1, 4, 3) val expectedConnectionFlag = false assertEquals(expectedConnectionFlag, resultConnectionFlag) assertEquals(expectedCycles, resultCycles) assertEquals(expectedEdges, resultEdges) assertEquals(expectedVertices, resultVertices) } + @Test @DisplayName("Disconnected graph") - public fun DisconnectedGraph(){ - graph = Graph().apply { - addVertex(1, "Thomas Shelby") - addVertex(2, "Andrew Tate") - addVertex(3, "Iakov") - addVertex(4, "John Shelby") - addVertex(5, "John Shelby") - - addEdge(1, 2, 2, 3) - addEdge(2, 3, 1, 2) - addEdge(4, 1, -1, 1) - addEdge(3, 4, 1, 4) + public fun DisconnectedGraph() { + graph = + Graph().apply { + addVertex(1, "Thomas Shelby") + addVertex(2, "Andrew Tate") + addVertex(3, "Iakov") + addVertex(4, "John Shelby") + addVertex(5, "John Shelby") - } + addEdge(1, 2, 2, 3) + addEdge(2, 3, 1, 2) + addEdge(4, 1, -1, 1) + addEdge(3, 4, 1, 4) + } val fordBellman = FordBellman(graph) - fordBellman.shortestPath(1,5) + fordBellman.shortestPath(1, 5) val resultVertices = fordBellman.resultPathVertices val resultEdges = fordBellman.resultPathEdges val resultCycles = fordBellman.cycleFlag @@ -103,4 +106,4 @@ class FordBellmanTest { assertEquals(expectedEdges, resultEdges) assertEquals(expectedVertices, resultVertices) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt index 374f82c..a3f661f 100644 --- a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -2,8 +2,8 @@ package graphs.algorithms import model.algorithms.Kosaraju import model.graph.Graph -import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test // graph sample // @@ -15,22 +15,22 @@ import org.junit.jupiter.api.Assertions.* // // components: (0,7,1,6) (11) (9,2,4) (10,8,3,5) -fun createSampleGraph() : Graph { +fun createSampleGraph(): Graph { // Добавление вершин val graph = Graph() graph.isDirected = true - graph.addVertex(0,"A") - graph.addVertex(1,"B") - graph.addVertex(2,"C") - graph.addVertex(3,"D") - graph.addVertex(4,"E") - graph.addVertex(5,"F") - graph.addVertex(6,"G") - graph.addVertex(7,"H") - graph.addVertex(8,"I") - graph.addVertex(9,"J") - graph.addVertex(10,"K") - graph.addVertex(11,"L") + graph.addVertex(0, "A") + graph.addVertex(1, "B") + graph.addVertex(2, "C") + graph.addVertex(3, "D") + graph.addVertex(4, "E") + graph.addVertex(5, "F") + graph.addVertex(6, "G") + graph.addVertex(7, "H") + graph.addVertex(8, "I") + graph.addVertex(9, "J") + graph.addVertex(10, "K") + graph.addVertex(11, "L") // Добавление рёбер graph.addEdge(0, 7, 1L, 0) @@ -117,13 +117,14 @@ class KosarajuTest { // graph and algo initialization val graph = createSampleGraph() val algo = Kosaraju(graph) - val expected = mutableListOf( - mutableListOf(3, 8, 5, 10), - mutableListOf(2, 9, 4), - mutableListOf(11), - mutableListOf(1), - mutableListOf(0,7,6), - ) + val expected = + mutableListOf( + mutableListOf(3, 8, 5, 10), + mutableListOf(2, 9, 4), + mutableListOf(11), + mutableListOf(1), + mutableListOf(0, 7, 6), + ) // algo start from different positions val currently = algo.findStronglyConnectedComponents() @@ -138,13 +139,14 @@ class KosarajuTest { val graph = createSampleGraph() graph.isDirected = false val algo = Kosaraju(graph) - val expected = mutableListOf( - mutableListOf(3, 8, 5, 10), - mutableListOf(2, 9, 4), - mutableListOf(11), - mutableListOf(1), - mutableListOf(0,7,6), - ) + val expected = + mutableListOf( + mutableListOf(3, 8, 5, 10), + mutableListOf(2, 9, 4), + mutableListOf(11), + mutableListOf(1), + mutableListOf(0, 7, 6), + ) // algo start from different positions val currently = algo.findStronglyConnectedComponents() @@ -152,4 +154,4 @@ class KosarajuTest { // Проверьте результаты assertTrue(expected == currently) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/graphs/algorithms/KruskalTest.kt b/src/test/kotlin/graphs/algorithms/KruskalTest.kt index 9a511ba..be90236 100644 --- a/src/test/kotlin/graphs/algorithms/KruskalTest.kt +++ b/src/test/kotlin/graphs/algorithms/KruskalTest.kt @@ -34,11 +34,12 @@ class KruskalTest { algo.kruskals(graph) assertEquals(expected, algo.resultsId) } + @Test fun testSingleVertexGraph() { // Test with a single vertex to ensure the algorithm handles this case correctly val graph = Graph() - graph.addVertex(0,"") + graph.addVertex(0, "") val expected = emptyList() val algo = KruskalsMST() algo.kruskals(graph) diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index 21def72..104b07d 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -1,8 +1,7 @@ package graphs.algorithms -import model.algorithms.Kosaraju -import model.graph.Graph import model.community.Louvain +import model.graph.Graph import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test @@ -54,7 +53,7 @@ class LouvainTest { // graph and algo initialization val graph = createSampleGraph() val algo = Louvain(graph) - val expected = mutableListOf(setOf(0,7,1,6), setOf(9,11,2,4), setOf(10,5,3,8)) + val expected = mutableListOf(setOf(0, 7, 1, 6), setOf(9, 11, 2, 4), setOf(10, 5, 3, 8)) val currently = algo.findCommunities() @@ -67,7 +66,7 @@ class LouvainTest { val graph = createSampleGraph() graph.isDirected = false val algo = Louvain(graph) - val expected = mutableListOf(setOf(0,1,2,4,6,7,9,11), setOf(10,5,3,8)) + val expected = mutableListOf(setOf(0, 1, 2, 4, 6, 7, 9, 11), setOf(10, 5, 3, 8)) val currently = algo.findCommunities() @@ -80,7 +79,7 @@ class LouvainTest { val graph = createSampleGraph() val algo = Louvain(graph) - val expectedCommunities = mutableListOf(0,0,1,2,1,2,0,0,2,1,2,1) + val expectedCommunities = mutableListOf(0, 0, 1, 2, 1, 2, 0, 0, 2, 1, 2, 1) algo.findCommunities() @@ -98,7 +97,7 @@ class LouvainTest { val graph = createSampleGraph2() val algo = Louvain(graph) - val expected = mutableListOf(setOf(1,2,3), setOf(4,5,6)) + val expected = mutableListOf(setOf(1, 2, 3), setOf(4, 5, 6)) algo.findCommunities() @@ -114,7 +113,7 @@ class LouvainTest { graph.isDirected = false val algo = Louvain(graph) - val expected = mutableListOf(setOf(1,2,3), setOf(4,5,6)) + val expected = mutableListOf(setOf(1, 2, 3), setOf(4, 5, 6)) algo.findCommunities() @@ -157,4 +156,4 @@ class LouvainTest { assertTrue(expected == currentlyCommunities) } -} \ No newline at end of file +} From cfb3277412a71c3e2a162e39ebb3a71800463857 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Fri, 25 Oct 2024 11:14:58 +0300 Subject: [PATCH 197/211] feat(algo): add reuse code and remove redundant Tarjan algo --- .../kotlin/model/algorithms/FindCycles.kt | 21 +++---- .../TarjanStrongConnecedComponent.kt | 56 ------------------- 2 files changed, 11 insertions(+), 66 deletions(-) delete mode 100644 src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt diff --git a/src/main/kotlin/model/algorithms/FindCycles.kt b/src/main/kotlin/model/algorithms/FindCycles.kt index 59330c6..b05b973 100644 --- a/src/main/kotlin/model/algorithms/FindCycles.kt +++ b/src/main/kotlin/model/algorithms/FindCycles.kt @@ -3,6 +3,7 @@ package algorithms import java.util.* import model.graph.Graph import model.graph.Vertex +import model.algorithms.Kosaraju class AllCyclesInDirectedGraphJohnson { private var blockedSet: MutableSet = mutableSetOf() @@ -16,10 +17,10 @@ class AllCyclesInDirectedGraphJohnson { stack = LinkedList() allCycles = ArrayList>() var startIndex = 1 - val tarjan = TarjanStronglyConnectedComponent() + val kosaraju = Kosaraju(graph) while (startIndex <= graph.vertices.size) { val subGraph: Graph = createSubGraph(startIndex, graph) - val sccs: List> = tarjan.scc(subGraph) + val sccs: List> = kosaraju.findStronglyConnectedComponents() val maybeLeastVertex: Vertex? = leastIndexSCC(sccs, subGraph) if (maybeLeastVertex != null) { val leastVertex: Vertex = maybeLeastVertex @@ -34,18 +35,18 @@ class AllCyclesInDirectedGraphJohnson { return allCycles } - private fun leastIndexSCC(sccs: List>, subGraph: Graph): Vertex? { + private fun leastIndexSCC(sccs: List>, subGraph: Graph): Vertex? { var min = Int.MAX_VALUE var minVertex: Vertex? = null - var minScc: Set = mutableSetOf() + var minScc: List = mutableListOf() for (scc in sccs) { if (scc.size == 1) { continue } - for (vertex in scc) { - if (vertex.id < min) { - min = vertex.id - minVertex = vertex + for (vertexId in scc) { + if (vertexId < min) { + min = vertexId + minVertex = subGraph.vertices[vertexId] minScc = scc } } @@ -58,8 +59,8 @@ class AllCyclesInDirectedGraphJohnson { graphScc.isDirected = true for ((i, edge) in subGraph.getEdges().withIndex()) { if ( - (subGraph.vertices[edge.vertices.first] in minScc) && - (subGraph.vertices[edge.vertices.second] in minScc) + (subGraph.vertices[edge.vertices.first]?.id in minScc) && + (subGraph.vertices[edge.vertices.second]?.id in minScc) ) { graphScc.addVertex(edge.vertices.first, "") graphScc.addVertex(edge.vertices.second, "") diff --git a/src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt b/src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt deleted file mode 100644 index 5612ca9..0000000 --- a/src/main/kotlin/model/algorithms/TarjanStrongConnecedComponent.kt +++ /dev/null @@ -1,56 +0,0 @@ -package algorithms - -import java.util.* -import kotlin.math.min -import model.graph.Graph -import model.graph.Vertex - -class TarjanStronglyConnectedComponent { - private var visitedTime: MutableMap = mutableMapOf() - private var lowTime: MutableMap = mutableMapOf() - private var onStack: MutableSet = mutableSetOf() - private var stack: Deque = LinkedList() - private var visited: MutableSet = mutableSetOf() - private val result: MutableList> = mutableListOf() - private var time = 0 - - fun scc(graph: Graph): List> { - for (vertex in graph.getVertices()) { - if (visited.contains(vertex)) { - continue - } - sccUtil(vertex) - } - - return result - } - - private fun sccUtil(vertex: Vertex) { - visited.add(vertex) - visitedTime[vertex] = time - lowTime[vertex] = time - time++ - stack.addFirst(vertex) - onStack.add(vertex) - - for (child in vertex.adjacentVertices) { - if (child !in visited) { - sccUtil(child) - lowTime[vertex] = min(lowTime[vertex]!!, lowTime[child]!!) - } else if (child in onStack) { - lowTime[vertex] = min(lowTime[vertex]!!, visitedTime[child]!!) - } - } - - if (visitedTime[vertex] === lowTime[vertex]) { - val stronglyConnectedComponent: MutableSet = HashSet() - var v: Vertex - do { - v = stack.pollFirst() - onStack.remove(v) - stronglyConnectedComponent.add(v) - } while (vertex != v) - result.add(stronglyConnectedComponent) - } - } -} From 8abe6a6564fe03af36cf3334ca90b103a730b135 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Fri, 25 Oct 2024 21:29:12 +0300 Subject: [PATCH 198/211] feat(layouts): add circular layout representation in Canvas --- src/main/kotlin/Main.kt | 5 ++--- src/main/kotlin/view/CanvasView.kt | 22 +++++++++++++++++--- src/main/kotlin/viewmodel/CanvasViewModel.kt | 9 ++++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 8ea737a..1756cb2 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -11,6 +11,7 @@ import model.graph.Graph import view.Canvas import viewmodel.CanvasViewModel import viewmodel.layouts.ForceAtlas2Layout +import viewmodel.layouts.CircularLayout val graph = Graph().apply { @@ -67,10 +68,8 @@ val windowSizeStart = Pair(820, 640) @Composable @Preview fun App() { - MaterialTheme { - val canvasGraph = CanvasViewModel(graph, ForceAtlas2Layout()) + val canvasGraph = CanvasViewModel(graph, CircularLayout()) MaterialTheme { Canvas(canvasGraph) } - } } fun main() = application { diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index e602958..d734cb6 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -26,6 +26,8 @@ import model.databases.sqlite.SQLiteDBHandler import view.graph.GraphView import viewmodel.CanvasViewModel import viewmodel.LoadGraphMenuViewModel +import viewmodel.layouts.ForceAtlas2Layout +import viewmodel.layouts.CircularLayout @Composable fun Canvas(viewModel: CanvasViewModel) { @@ -181,8 +183,22 @@ fun Canvas(viewModel: CanvasViewModel) { } Text("Menu", modifier = Modifier.padding(16.dp)) } - Divider() - + HorizontalDivider() + Row( + modifier = Modifier.padding(16.dp), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Button(onClick = { + viewModel.switchLayout(ForceAtlas2Layout()) + }) { + Text("Force Atlas 2") + } + Button(onClick = { + viewModel.switchLayout(CircularLayout()) + }) { + Text("Circular Layout") + } + } NavigationDrawerItem( label = { Text(text = "Доступные алгоритмы") }, icon = { Icon(Icons.Filled.List, contentDescription = null) }, @@ -200,7 +216,7 @@ fun Canvas(viewModel: CanvasViewModel) { Scaffold( floatingActionButton = { ExtendedFloatingActionButton( - text = { Text("Show drawer") }, + text = { Text("По приколу чисто") }, icon = { Icon(Icons.Filled.Add, contentDescription = "") }, onClick = { scope.launch { drawerState.apply { if (isClosed) open() else close() } } diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index c7cdcd8..5590629 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -6,7 +6,7 @@ import viewmodel.algos.BridgeFinderViewModel import viewmodel.graph.GraphViewModel import viewmodel.layouts.RepresentationStrategy -class CanvasViewModel(var graph: Graph, val representationStrategy: RepresentationStrategy) { +class CanvasViewModel(var graph: Graph, var representationStrategy: RepresentationStrategy) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) var graphViewModel = GraphViewModel(graph) @@ -20,6 +20,11 @@ class CanvasViewModel(var graph: Graph, val representationStrategy: Representati } init { - representationStrategy.place(1280.0, 860.0, graphViewModel) + representationStrategy.place(1920.0, 1080.0, graphViewModel) + } + + fun switchLayout(newLayout: RepresentationStrategy) { + representationStrategy = newLayout + representationStrategy.place(1920.0, 1080.0, graphViewModel) } } From d6e17c5455c2244ae31269a171ef70cb395240bd Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Sat, 26 Oct 2024 13:37:06 +0300 Subject: [PATCH 199/211] style: run formatter --- src/main/kotlin/Main.kt | 5 ++--- src/main/kotlin/model/algorithms/FindCycles.kt | 2 +- src/main/kotlin/model/algorithms/FordBellman.kt | 6 ++++-- src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 1756cb2..2d864bf 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -10,7 +10,6 @@ import java.awt.Dimension import model.graph.Graph import view.Canvas import viewmodel.CanvasViewModel -import viewmodel.layouts.ForceAtlas2Layout import viewmodel.layouts.CircularLayout val graph = @@ -68,8 +67,8 @@ val windowSizeStart = Pair(820, 640) @Composable @Preview fun App() { - val canvasGraph = CanvasViewModel(graph, CircularLayout()) - MaterialTheme { Canvas(canvasGraph) } + val canvasGraph = CanvasViewModel(graph, CircularLayout()) + MaterialTheme { Canvas(canvasGraph) } } fun main() = application { diff --git a/src/main/kotlin/model/algorithms/FindCycles.kt b/src/main/kotlin/model/algorithms/FindCycles.kt index b05b973..0049645 100644 --- a/src/main/kotlin/model/algorithms/FindCycles.kt +++ b/src/main/kotlin/model/algorithms/FindCycles.kt @@ -1,9 +1,9 @@ package algorithms import java.util.* +import model.algorithms.Kosaraju import model.graph.Graph import model.graph.Vertex -import model.algorithms.Kosaraju class AllCyclesInDirectedGraphJohnson { private var blockedSet: MutableSet = mutableSetOf() diff --git a/src/main/kotlin/model/algorithms/FordBellman.kt b/src/main/kotlin/model/algorithms/FordBellman.kt index 44515ef..5c044a7 100644 --- a/src/main/kotlin/model/algorithms/FordBellman.kt +++ b/src/main/kotlin/model/algorithms/FordBellman.kt @@ -49,8 +49,10 @@ class FordBellman(graph: Graph) { for (i in 0 until verticesNumber) { curCycleFlag = -1 for (j in 0 until edgesNumber) { - val firstVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.first - 1].toFloat() - val secondVertexPath = pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1].toFloat() + val firstVertexPath = + pathsLength[curGraph.edges[j + 1]!!.vertices.first - 1].toFloat() + val secondVertexPath = + pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1].toFloat() if (firstVertexPath < INF) { if (secondVertexPath > firstVertexPath + curGraph.edges[j + 1]!!.weight) { pathsLength[curGraph.edges[j + 1]!!.vertices.second - 1] = diff --git a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt index 3e9cad4..667771e 100644 --- a/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt +++ b/src/main/kotlin/model/databases/sqlite/dao/edge/Edges.kt @@ -7,4 +7,4 @@ object Edges : IntIdTable("Edges") { val first = reference("first", Vertices).nullable() val second = reference("second", Vertices).nullable() val weight = float("weight") -} \ No newline at end of file +} From f476ce52c345b0c2c78590fc66f92f31623d3d4a Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Sat, 26 Oct 2024 13:37:49 +0300 Subject: [PATCH 200/211] feat(UI): change cringe save file dialog to window --- src/main/kotlin/view/CanvasView.kt | 153 ++--------------- src/main/kotlin/view/SaveGraphMenu.kt | 156 ++++++++++++++++++ src/main/kotlin/viewmodel/CanvasViewModel.kt | 9 + .../viewmodel/SaveGraphMenuViewModel.kt | 12 ++ 4 files changed, 187 insertions(+), 143 deletions(-) create mode 100644 src/main/kotlin/view/SaveGraphMenu.kt create mode 100644 src/main/kotlin/viewmodel/SaveGraphMenuViewModel.kt diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index d734cb6..6ee1fe3 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -14,7 +14,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -26,146 +25,16 @@ import model.databases.sqlite.SQLiteDBHandler import view.graph.GraphView import viewmodel.CanvasViewModel import viewmodel.LoadGraphMenuViewModel -import viewmodel.layouts.ForceAtlas2Layout +import viewmodel.SaveGraphMenuViewModel import viewmodel.layouts.CircularLayout +import viewmodel.layouts.ForceAtlas2Layout @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() - val showDialog = remember { mutableStateOf(false) } - val storageType = remember { mutableStateOf(StorageType.FILE) } - val fileName = remember { mutableStateOf("") } - val isDirectedGraph = remember { mutableStateOf(false) } - val isWeighted = remember { mutableStateOf(false) } - val uri = remember { mutableStateOf("") } - val login = remember { mutableStateOf("") } - val password = remember { mutableStateOf("") } - - AnimatedVisibility(visible = showDialog.value) { - Dialog( - onDismissRequest = { showDialog.value = false }, - properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) - ) { - Column(modifier = Modifier.padding(16.dp)) { - Text("Choose where to save the graph:") - CustomRadioGroup( - selectedOption = storageType.value.toString(), - options = - listOf( - StorageType.FILE.toString(), - StorageType.NEO4J.toString(), - StorageType.SQLITE.toString() - ), - onOptionSelected = { storageType.value = StorageType.valueOf(it) } - ) - - when (storageType.value) { - StorageType.FILE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - Text("Ориентированный ли граф") - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - - Text("Взвешанные ли рёбра") - Checkbox( - checked = isWeighted.value, - onCheckedChange = { isWeighted.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - } - StorageType.NEO4J -> { - TextField( - value = uri.value, - onValueChange = { uri.value = it }, - label = { Text("URI") } - ) - TextField( - value = login.value, - onValueChange = { login.value = it }, - label = { Text("Login") } - ) - TextField( - value = password.value, - onValueChange = { password.value = it }, - label = { Text("Password") }, - visualTransformation = PasswordVisualTransformation() - ) - Text("Ориентированный ли граф") - Checkbox( - checked = isDirectedGraph.value, - onCheckedChange = { isDirectedGraph.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - - Text("Взвешанные ли рёбра") - Checkbox( - checked = isWeighted.value, - onCheckedChange = { isWeighted.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - } - StorageType.SQLITE -> { - TextField( - value = fileName.value, - onValueChange = { fileName.value = it }, - label = { Text("File Name") } - ) - - Spacer(modifier = Modifier.width(8.dp)) - - Text("Взвешанные ли рёбра") - Checkbox( - checked = isWeighted.value, - onCheckedChange = { isWeighted.value = it }, - ) - Spacer(modifier = Modifier.width(8.dp)) - } - } + val saveGraphMenuViewModel = remember { SaveGraphMenuViewModel(viewModel) } - Button( - onClick = { - when (storageType.value) { - StorageType.FILE -> { - // Логика сохранения в файл с использованием fileName и - // isDirectedGraph - } - StorageType.NEO4J -> { - // Логика сохранения в Neo4j - val repo = Neo4jRepository(uri.value, login.value, password.value) - val handler = Neo4jHandler(repo) - val wasGraphDirected = viewModel.graph.isDirected - viewModel.graph.isDirected = isDirectedGraph.value - handler.saveGraphToNeo4j(viewModel.graph) - viewModel.graph.isDirected = wasGraphDirected - } - StorageType.SQLITE -> { - val fileAddress = "saves/sqlite/${fileName.value}" - val dataBase = File(fileAddress) - val sqlHandler = SQLiteDBHandler() - sqlHandler.save( - dataBase, - viewModel.graph, - viewModel.graphViewModel, - isWeighted.value - ) - } - } - showDialog.value = false - } - ) { - Text("Save") - } - } - } - } Surface( modifier = Modifier.fillMaxSize(), contentColor = Color.LightGray, @@ -188,14 +57,10 @@ fun Canvas(viewModel: CanvasViewModel) { modifier = Modifier.padding(16.dp), horizontalArrangement = Arrangement.SpaceEvenly ) { - Button(onClick = { - viewModel.switchLayout(ForceAtlas2Layout()) - }) { + Button(onClick = { viewModel.switchLayout(ForceAtlas2Layout()) }) { Text("Force Atlas 2") } - Button(onClick = { - viewModel.switchLayout(CircularLayout()) - }) { + Button(onClick = { viewModel.switchLayout(CircularLayout()) }) { Text("Circular Layout") } } @@ -207,9 +72,7 @@ fun Canvas(viewModel: CanvasViewModel) { ) AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu(viewModel) } Button(onClick = { viewModel.isOpenLoadGraph = true }) { Text("Load graph") } - Button(enabled = true, onClick = { scope.launch { showDialog.value = true } }) { - Text(text = "Save Graph") - } + Button(onClick = { viewModel.isOpenSaveGraph.value = true }) {Text(text = "Save Graph")} } }, ) { @@ -235,4 +98,8 @@ fun Canvas(viewModel: CanvasViewModel) { if (viewModel.isOpenLoadGraph) { LoadGraph(LoadGraphMenuViewModel(viewModel)) } + + if (viewModel.isOpenSaveGraph.value) { + SaveGraph(saveGraphMenuViewModel) + } } diff --git a/src/main/kotlin/view/SaveGraphMenu.kt b/src/main/kotlin/view/SaveGraphMenu.kt new file mode 100644 index 0000000..d84341e --- /dev/null +++ b/src/main/kotlin/view/SaveGraphMenu.kt @@ -0,0 +1,156 @@ +package view + +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.DialogWindow +import androidx.compose.ui.window.WindowPosition +import androidx.compose.ui.window.rememberDialogState +import model.databases.neo4j.Neo4jHandler +import model.databases.neo4j.Neo4jRepository +import model.databases.sqlite.SQLiteDBHandler +import viewmodel.SaveGraphMenuViewModel +import viewmodel.graph.GraphViewModel +import androidx.compose.ui.text.input.PasswordVisualTransformation +import java.io.File + +@Composable +fun SaveGraph(viewModel: SaveGraphMenuViewModel) { + var isWeighted by remember { mutableStateOf(false) } + var isDirected by remember { mutableStateOf(false) } + + DialogWindow( + onCloseRequest = { viewModel.canvasViewModel.isOpenSaveGraph.value = false }, + state = + rememberDialogState( + position = WindowPosition(Alignment.Center), + size = DpSize(800.dp, 640.dp) + ), + title = "Save New Graph", + resizable = false + ) { + Column(Modifier.fillMaxSize().padding(4.dp)) { + val modifierRow = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) + val verticalRow = Alignment.CenterVertically + + Row(modifierRow, verticalAlignment = verticalRow) {} + + Row(modifierRow, verticalAlignment = verticalRow) { + Column( + modifier = Modifier.height(450.dp).padding(16.dp), + verticalArrangement = Arrangement.Top + ) { + CustomRadioGroup( + options = + listOf( + StorageType.FILE.toString(), + StorageType.NEO4J.toString(), + StorageType.SQLITE.toString() + ), + selectedOption = viewModel.storageType.value.toString(), + onOptionSelected = { viewModel.storageType.value = StorageType.valueOf(it) } + ) + + when (viewModel.storageType.value) { + StorageType.FILE -> { + TextField( + value = viewModel.fileName.value, + onValueChange = { viewModel.fileName.value = it }, + label = { Text("File Name") } + ) + Text("Ориентированный ли граф") + Checkbox(checked = isDirected, onCheckedChange = { isDirected = it }) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox(checked = isWeighted, onCheckedChange = { isWeighted = it }) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.NEO4J -> { + TextField( + value = viewModel.uri.value, + onValueChange = { viewModel.uri.value = it }, + label = { Text("URI") } + ) + TextField( + value = viewModel.login.value, + onValueChange = { viewModel.login.value = it }, + label = { Text("Login") } + ) + TextField( + value = viewModel.password.value, + onValueChange = { viewModel.password.value = it }, + label = { Text("Password") }, + visualTransformation = PasswordVisualTransformation() + ) + Text("Ориентированный ли граф") + Checkbox(checked = isDirected, onCheckedChange = { isDirected = it }) + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox(checked = isWeighted, onCheckedChange = { isWeighted = it }) + Spacer(modifier = Modifier.width(8.dp)) + } + StorageType.SQLITE -> { + TextField( + value = viewModel.fileName.value, + onValueChange = { viewModel.fileName.value = it }, + label = { Text("File Name") } + ) + + Spacer(modifier = Modifier.width(8.dp)) + + Text("Взвешанные ли рёбра") + Checkbox(checked = isWeighted, onCheckedChange = { isWeighted = it }) + Spacer(modifier = Modifier.width(8.dp)) + } + } + } + } + + Row(modifierRow, verticalAlignment = verticalRow) { + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { viewModel.canvasViewModel.isOpenSaveGraph.value = false }) { + Text("Cancel") + } + Spacer(modifier = Modifier.weight(0.01f)) + Button( + onClick = { + when (viewModel.storageType.value) { + StorageType.FILE -> { + // Логика сохранения в файл с использованием fileName и + // isDirectedGraph + } + StorageType.NEO4J -> { + // val repo = Neo4jRepository(uri.value, login.value, password.value) + // val handler = Neo4jHandler(repo) + // val wasGraphDirected = viewModel.graph.isDirected + // viewModel.graph.isDirected = isDirectedGraph.value + // handler.saveGraphToNeo4j(viewModel.graph) + // viewModel.graph.isDirected = wasGraphDirected + } + StorageType.SQLITE -> { + val fileAddress = "saves/sqlite/${viewModel.fileName.value}" + val dataBase: File = File(fileAddress) + val sqlHandler = SQLiteDBHandler() + sqlHandler.save( + dataBase, + viewModel.canvasViewModel.graph, + viewModel.canvasViewModel.graphViewModel, + isWeighted + ) + viewModel.canvasViewModel.isOpenSaveGraph.value = false + } + } + } + ) { + Text("Save") + } + } + } + } +} diff --git a/src/main/kotlin/viewmodel/CanvasViewModel.kt b/src/main/kotlin/viewmodel/CanvasViewModel.kt index 5590629..0ee2bd7 100644 --- a/src/main/kotlin/viewmodel/CanvasViewModel.kt +++ b/src/main/kotlin/viewmodel/CanvasViewModel.kt @@ -9,6 +9,7 @@ import viewmodel.layouts.RepresentationStrategy class CanvasViewModel(var graph: Graph, var representationStrategy: RepresentationStrategy) { val showVerticesLabels = mutableStateOf(false) val showEdgesLabels = mutableStateOf(false) + val isOpenSaveGraph = mutableStateOf(false) var graphViewModel = GraphViewModel(graph) val bridges = BridgeFinderViewModel(graph, graphViewModel) @@ -27,4 +28,12 @@ class CanvasViewModel(var graph: Graph, var representationStrategy: Representati representationStrategy = newLayout representationStrategy.place(1920.0, 1080.0, graphViewModel) } + + fun openSaveGraphDialog() { + isOpenSaveGraph.value = true + } + + fun closeSaveGraphDialog() { + isOpenSaveGraph.value = false + } } diff --git a/src/main/kotlin/viewmodel/SaveGraphMenuViewModel.kt b/src/main/kotlin/viewmodel/SaveGraphMenuViewModel.kt new file mode 100644 index 0000000..098a6eb --- /dev/null +++ b/src/main/kotlin/viewmodel/SaveGraphMenuViewModel.kt @@ -0,0 +1,12 @@ +package viewmodel + +import androidx.compose.runtime.mutableStateOf +import view.StorageType + +class SaveGraphMenuViewModel(val canvasViewModel: CanvasViewModel) { + val storageType = mutableStateOf(StorageType.FILE) + val fileName = mutableStateOf("") + val uri = mutableStateOf("") + val login = mutableStateOf("") + val password = mutableStateOf("") +} From abc5ab1093d8fd51d4c50f16f2dad92a79a9f807 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Sat, 26 Oct 2024 14:16:30 +0300 Subject: [PATCH 201/211] feat(CSV): add save into CSV file --- saves/csv/Example.csv | 44 +++++++++++++++++++++++++++ src/main/kotlin/view/SaveGraphMenu.kt | 21 ++++++++----- 2 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 saves/csv/Example.csv diff --git a/saves/csv/Example.csv b/saves/csv/Example.csv new file mode 100644 index 0000000..d7f91d1 --- /dev/null +++ b/saves/csv/Example.csv @@ -0,0 +1,44 @@ +isNode,name,id,x,y,color,radius,community,from,to,weight + +true,13,Sniper,457.3282.dp,342.71585.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,14,Roshan,433.53894.dp,660.1613.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,7,Ryan,421.50995.dp,499.64575.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,12,Lion,725.70276.dp,1026.5232.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,5,Tristan,800.8322.dp,23.990685.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,10,Lycan,592.7067.dp,935.848.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,20,6,1498.49.dp,499.64575.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,17,3,1264.1929.dp,93.83106.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,11,Io,1040.4828.dp,1073.9686.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,15,1,960.0.dp,0.0.dp,0.53333336/0.53333336/0.53333336,25.0.dp,-1,,, +true,2,Andrew,1427.6537.dp,810.0.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,19,5,1462.6719.dp,342.71585.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,4,John,879.51715.dp,1073.9686.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,16,2,1119.1678.dp,23.990685.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,21,7,1486.461.dp,660.1613.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,1,Thomas,537.811.dp,203.3155.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,3,Iakov,1194.2972.dp,1026.5232.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,8,Pudge,492.34628.dp,810.0.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,18,4,1382.189.dp,203.3155.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,6,Arthur,1327.2933.dp,935.848.dp,0.0/0.0/0.0,25.0.dp,-1,,, +true,9,Tiny,655.8072.dp,93.83106.dp,0.0/0.0/0.0,25.0.dp,-1,,, +false,19,,,,,,,20,15,5.0 +false,21,,,,,,,14,20,0.0 +false,10,,,,,,,14,11,6.0 +false,20,,,,,,,17,20,0.0 +false,3,,,,,,,1,3,3.0 +false,4,,,,,,,2,3,4.0 +false,6,,,,,,,3,7,6.0 +false,15,,,,,,,15,17,1.0 +false,14,,,,,,,16,15,22.0 +false,16,,,,,,,15,18,6.0 +false,9,,,,,,,14,10,6.0 +false,12,,,,,,,14,13,5.0 +false,5,,,,,,,5,3,5.0 +false,2,,,,,,,3,4,2.0 +false,18,,,,,,,15,21,3.0 +false,8,,,,,,,14,9,6.0 +false,1,,,,,,,1,2,1.0 +false,11,,,,,,,14,12,6.0 +false,7,,,,,,,14,8,6.0 +false,13,,,,,,,14,3,0.0 +false,17,,,,,,,19,15,2.0 diff --git a/src/main/kotlin/view/SaveGraphMenu.kt b/src/main/kotlin/view/SaveGraphMenu.kt index d84341e..55b0845 100644 --- a/src/main/kotlin/view/SaveGraphMenu.kt +++ b/src/main/kotlin/view/SaveGraphMenu.kt @@ -17,8 +17,10 @@ import viewmodel.SaveGraphMenuViewModel import viewmodel.graph.GraphViewModel import androidx.compose.ui.text.input.PasswordVisualTransformation import java.io.File +import model.databases.CSV.CSVFileHandler @Composable +@ExperimentalStdlibApi fun SaveGraph(viewModel: SaveGraphMenuViewModel) { var isWeighted by remember { mutableStateOf(false) } var isDirected by remember { mutableStateOf(false) } @@ -122,16 +124,19 @@ fun SaveGraph(viewModel: SaveGraphMenuViewModel) { onClick = { when (viewModel.storageType.value) { StorageType.FILE -> { - // Логика сохранения в файл с использованием fileName и - // isDirectedGraph + val fileAddress = "saves/csv/${viewModel.fileName.value}.csv" + val file = File(fileAddress) + val csvHandler = CSVFileHandler() + csvHandler.save(file, viewModel.canvasViewModel.graphViewModel) + + viewModel.canvasViewModel.isOpenSaveGraph.value = false } StorageType.NEO4J -> { - // val repo = Neo4jRepository(uri.value, login.value, password.value) - // val handler = Neo4jHandler(repo) - // val wasGraphDirected = viewModel.graph.isDirected - // viewModel.graph.isDirected = isDirectedGraph.value - // handler.saveGraphToNeo4j(viewModel.graph) - // viewModel.graph.isDirected = wasGraphDirected + val repo = Neo4jRepository(viewModel.uri.value, viewModel.login.value, viewModel.password.value) + val handler = Neo4jHandler(repo) + val wasGraphDirected = viewModel.canvasViewModel.graph.isDirected + handler.saveGraphToNeo4j(viewModel.canvasViewModel.graph) + viewModel.canvasViewModel.graph.isDirected = wasGraphDirected } StorageType.SQLITE -> { val fileAddress = "saves/sqlite/${viewModel.fileName.value}" From 9cbc3c82ca10b58e0492330fc6687acd5db09c16 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Sat, 26 Oct 2024 15:21:25 +0300 Subject: [PATCH 202/211] fead(UI): add Kruskal algo visualization --- .../controller/GraphPainterByKruskal.kt | 21 +++++++ .../model/algorithms/KruskalsAlgorithm.kt | 62 +++++++++---------- src/main/kotlin/view/AlgorithmSubMenu.kt | 7 ++- 3 files changed, 57 insertions(+), 33 deletions(-) create mode 100644 src/main/kotlin/controller/GraphPainterByKruskal.kt diff --git a/src/main/kotlin/controller/GraphPainterByKruskal.kt b/src/main/kotlin/controller/GraphPainterByKruskal.kt new file mode 100644 index 0000000..adcff47 --- /dev/null +++ b/src/main/kotlin/controller/GraphPainterByKruskal.kt @@ -0,0 +1,21 @@ +package controller + +import model.algorithms.KruskalsMST +import model.graph.Graph +import viewmodel.graph.GraphViewModel +import androidx.compose.ui.graphics.Color + +class GraphPainterByKruskal(private val graph: Graph, private val graphViewModel: GraphViewModel) { + private val algoInitialize = KruskalsMST() + private val tree = algoInitialize.kruskals(graph) + + fun paint() { + for (edgeId in tree) { + val verticesId = graph.edges[edgeId]?.vertices + val currVertexFirst = graph.vertices[verticesId?.first] + val currVertexSecond = graph.vertices[verticesId?.second] + graphViewModel.verticesView[currVertexFirst]!!.color = Color.Red + graphViewModel.verticesView[currVertexSecond]!!.color = Color.Red + } + } +} diff --git a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt index 12ba900..2a3f8d8 100644 --- a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt @@ -4,58 +4,56 @@ import model.graph.Edge import model.graph.Graph class KruskalsMST { - var resultsId: List = emptyList() - - internal fun kruskals(graph: Graph) { - var j = 0 - var noOfEdges = 0 - val V = graph.getVertices().size - if (V == 1 || V == 0) return - val results = arrayOfNulls(V - 1) - val subsets = arrayOfNulls(V) - for (i in 0 ..< V) { - subsets[i] = Subset(i, 0) + internal fun kruskals(graph: Graph): List { + val numVertices = graph.getVertices().size + if (numVertices <= 1) return emptyList() + + val results = mutableListOf() + val subsets = mutableMapOf() + + for (vertex in 0 until numVertices) { + subsets[vertex] = Subset(vertex, 0) } + val edgesList = graph.edges.values val sortedEdges = edgesList.sortedWith(compareBy { it.weight }) - while (noOfEdges < V - 1) { + var edgeIndex = 0 + var noOfEdgesAdded = 0 - val nextEdge = sortedEdges[j] + while (noOfEdgesAdded < numVertices - 1 && edgeIndex < sortedEdges.size) { + val nextEdge = sortedEdges[edgeIndex] val x = findRoot(subsets, nextEdge.vertices.first) val y = findRoot(subsets, nextEdge.vertices.second) - if (x != y) { - results[noOfEdges] = nextEdge + if (x != y && x != null && y != null) { + results.add(nextEdge) union(subsets, x, y) - noOfEdges++ + noOfEdgesAdded++ } - j++ + edgeIndex++ } - resultsId = results.map { it!!.id }.sorted() + + return results.filterNotNull().map { it.id }.sorted() } - private fun union( - subsets: Array, - x: Int, - y: Int, - ) { + private fun union(subsets: MutableMap, x: Int, y: Int) { val rootX = findRoot(subsets, x) val rootY = findRoot(subsets, y) - if (subsets[rootY]!!.rank < subsets[rootX]!!.rank) { - subsets[rootY]!!.parent = rootX - } else if ((subsets[rootX]!!.rank < subsets[rootY]!!.rank)) { - subsets[rootX]!!.parent = rootY + if (subsets[rootY]?.rank ?: 0 < subsets[rootX]?.rank ?: 0) { + subsets[rootY]?.parent = rootX + } else if (subsets[rootX]?.rank ?: 0 < subsets[rootY]?.rank ?: 0) { + subsets[rootX]?.parent = rootY } else { - subsets[rootY]!!.parent = rootX - subsets[rootX]!!.rank++ + subsets[rootY]?.parent = rootX + subsets[rootX]?.rank = (subsets[rootX]?.rank ?: 0) + 1 } } - private fun findRoot(subsets: Array, i: Int): Int { - if (subsets[i]!!.parent != i) subsets[i]!!.parent = findRoot(subsets, subsets[i]!!.parent) - return subsets[i]!!.parent + private fun findRoot(subsets: MutableMap, i: Int): Int { + if (subsets[i]?.parent != i) subsets[i]?.parent = findRoot(subsets, subsets[i]?.parent ?: i) + return subsets[i]?.parent ?: i } internal class Subset(var parent: Int, var rank: Int) diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index 91feba8..e2f7109 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.unit.dp import controller.GraphPainterByCommunity import controller.GraphPainterByDjikstra import controller.GraphPainterByKosaraju +import controller.GraphPainterByKruskal import view.algos.bridgeHighlighter import viewmodel.CanvasViewModel @@ -72,7 +73,11 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { bridgeHighlighter(viewModel.bridges) } Button( - onClick = { /*TODO*/}, + onClick = { + val graph = viewModel.graph + val painter = GraphPainterByKruskal(graph, viewModel.graphViewModel) + painter.paint() + }, enabled = true, ) { Text( From 9c319f69e0f9a9ef9225f87f8a62e07e628ef8bc Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Sat, 26 Oct 2024 17:33:38 +0300 Subject: [PATCH 203/211] feat: add Cycles algo visualization --- .../kotlin/controller/GraphPainterByCycles.kt | 19 +++++++++++++++++++ .../kotlin/model/algorithms/FindCycles.kt | 7 +++++-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/controller/GraphPainterByCycles.kt diff --git a/src/main/kotlin/controller/GraphPainterByCycles.kt b/src/main/kotlin/controller/GraphPainterByCycles.kt new file mode 100644 index 0000000..ed56731 --- /dev/null +++ b/src/main/kotlin/controller/GraphPainterByCycles.kt @@ -0,0 +1,19 @@ +package controller + +import model.graph.Graph +import viewmodel.graph.GraphViewModel +import algorithms.FindCycles + +class GraphPainterByCycles(private val graph: Graph, private val graphViewModel: GraphViewModel) { + private val algoInitialize = FindCycles() + private val cycles = algoInitialize.simpleCycles(graph) + + fun paint() { + for ((i, cycle) in cycles.withIndex()) { + val cycleColor = generateRandomColor(i * 451) + for (vertex in cycle) { + graphViewModel.verticesView[vertex]!!.color = cycleColor + } + } + } +} diff --git a/src/main/kotlin/model/algorithms/FindCycles.kt b/src/main/kotlin/model/algorithms/FindCycles.kt index 0049645..0f1afd7 100644 --- a/src/main/kotlin/model/algorithms/FindCycles.kt +++ b/src/main/kotlin/model/algorithms/FindCycles.kt @@ -5,7 +5,7 @@ import model.algorithms.Kosaraju import model.graph.Graph import model.graph.Vertex -class AllCyclesInDirectedGraphJohnson { +class FindCycles { private var blockedSet: MutableSet = mutableSetOf() private var blockedMap: MutableMap?> = mutableMapOf() private var stack: Deque = LinkedList() @@ -120,7 +120,10 @@ class AllCyclesInDirectedGraphJohnson { } private fun getBSet(v: Vertex): MutableSet { - return (blockedMap.computeIfAbsent(v) { HashSet() } as MutableSet?)!! + if (!blockedMap.containsKey(v)) { + blockedMap[v] = HashSet() + } + return (blockedMap[v] as MutableSet?)!! } private fun createSubGraph(startVertex: Int, graph: Graph): Graph { From b5a5dadabc7ebf590496c24b4947935635b08d38 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Sat, 26 Oct 2024 17:34:02 +0300 Subject: [PATCH 204/211] style: formatter again --- src/main/kotlin/Main.kt | 2 ++ .../kotlin/controller/GraphPainterByKruskal.kt | 16 ++++++++-------- .../kotlin/model/algorithms/KruskalsAlgorithm.kt | 2 +- src/main/kotlin/view/AlgorithmSubMenu.kt | 13 +++++++++++++ src/main/kotlin/view/CanvasView.kt | 11 ++++------- src/main/kotlin/view/SaveGraphMenu.kt | 16 ++++++++++------ 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 2d864bf..dc351db 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -65,12 +65,14 @@ val graph = val windowSizeStart = Pair(820, 640) @Composable +@ExperimentalStdlibApi @Preview fun App() { val canvasGraph = CanvasViewModel(graph, CircularLayout()) MaterialTheme { Canvas(canvasGraph) } } +@ExperimentalStdlibApi fun main() = application { Window( onCloseRequest = ::exitApplication, diff --git a/src/main/kotlin/controller/GraphPainterByKruskal.kt b/src/main/kotlin/controller/GraphPainterByKruskal.kt index adcff47..e099b95 100644 --- a/src/main/kotlin/controller/GraphPainterByKruskal.kt +++ b/src/main/kotlin/controller/GraphPainterByKruskal.kt @@ -1,21 +1,21 @@ package controller +import androidx.compose.ui.graphics.Color import model.algorithms.KruskalsMST import model.graph.Graph import viewmodel.graph.GraphViewModel -import androidx.compose.ui.graphics.Color class GraphPainterByKruskal(private val graph: Graph, private val graphViewModel: GraphViewModel) { private val algoInitialize = KruskalsMST() private val tree = algoInitialize.kruskals(graph) fun paint() { - for (edgeId in tree) { - val verticesId = graph.edges[edgeId]?.vertices - val currVertexFirst = graph.vertices[verticesId?.first] - val currVertexSecond = graph.vertices[verticesId?.second] - graphViewModel.verticesView[currVertexFirst]!!.color = Color.Red - graphViewModel.verticesView[currVertexSecond]!!.color = Color.Red - } + for (edgeId in tree) { + val verticesId = graph.edges[edgeId]?.vertices + val currVertexFirst = graph.vertices[verticesId?.first] + val currVertexSecond = graph.vertices[verticesId?.second] + graphViewModel.verticesView[currVertexFirst]!!.color = Color.Red + graphViewModel.verticesView[currVertexSecond]!!.color = Color.Red + } } } diff --git a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt index 2a3f8d8..9794d8a 100644 --- a/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt +++ b/src/main/kotlin/model/algorithms/KruskalsAlgorithm.kt @@ -7,7 +7,7 @@ class KruskalsMST { internal fun kruskals(graph: Graph): List { val numVertices = graph.getVertices().size if (numVertices <= 1) return emptyList() - + val results = mutableListOf() val subsets = mutableMapOf() diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index e2f7109..f6c08ec 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import controller.GraphPainterByCommunity +import controller.GraphPainterByCycles import controller.GraphPainterByDjikstra import controller.GraphPainterByKosaraju import controller.GraphPainterByKruskal @@ -84,6 +85,18 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { text = "Построение минимального остовного дерева", ) } + Button( + onClick = { + val graph = viewModel.graph + val painter = GraphPainterByCycles(graph, viewModel.graphViewModel) + painter.paint() + }, + enabled = true, + ) { + Text( + text = "Поиск циклов", + ) + } Button( onClick = { showDialog.value = true }, enabled = true, diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 6ee1fe3..9bd9d25 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -15,13 +15,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties -import java.io.File import kotlinx.coroutines.launch -import model.databases.neo4j.Neo4jHandler -import model.databases.neo4j.Neo4jRepository -import model.databases.sqlite.SQLiteDBHandler import view.graph.GraphView import viewmodel.CanvasViewModel import viewmodel.LoadGraphMenuViewModel @@ -29,6 +23,7 @@ import viewmodel.SaveGraphMenuViewModel import viewmodel.layouts.CircularLayout import viewmodel.layouts.ForceAtlas2Layout +@ExperimentalStdlibApi @Composable fun Canvas(viewModel: CanvasViewModel) { val drawerState = rememberDrawerState(DrawerValue.Closed) @@ -72,7 +67,9 @@ fun Canvas(viewModel: CanvasViewModel) { ) AnimatedVisibility(visible = showSubMenu.value) { AlgorithmSubMenu(viewModel) } Button(onClick = { viewModel.isOpenLoadGraph = true }) { Text("Load graph") } - Button(onClick = { viewModel.isOpenSaveGraph.value = true }) {Text(text = "Save Graph")} + Button(onClick = { viewModel.isOpenSaveGraph.value = true }) { + Text(text = "Save Graph") + } } }, ) { diff --git a/src/main/kotlin/view/SaveGraphMenu.kt b/src/main/kotlin/view/SaveGraphMenu.kt index 55b0845..e5fbe95 100644 --- a/src/main/kotlin/view/SaveGraphMenu.kt +++ b/src/main/kotlin/view/SaveGraphMenu.kt @@ -5,19 +5,18 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogWindow import androidx.compose.ui.window.WindowPosition import androidx.compose.ui.window.rememberDialogState +import java.io.File +import model.databases.CSV.CSVFileHandler import model.databases.neo4j.Neo4jHandler import model.databases.neo4j.Neo4jRepository import model.databases.sqlite.SQLiteDBHandler import viewmodel.SaveGraphMenuViewModel -import viewmodel.graph.GraphViewModel -import androidx.compose.ui.text.input.PasswordVisualTransformation -import java.io.File -import model.databases.CSV.CSVFileHandler @Composable @ExperimentalStdlibApi @@ -128,11 +127,16 @@ fun SaveGraph(viewModel: SaveGraphMenuViewModel) { val file = File(fileAddress) val csvHandler = CSVFileHandler() csvHandler.save(file, viewModel.canvasViewModel.graphViewModel) - + viewModel.canvasViewModel.isOpenSaveGraph.value = false } StorageType.NEO4J -> { - val repo = Neo4jRepository(viewModel.uri.value, viewModel.login.value, viewModel.password.value) + val repo = + Neo4jRepository( + viewModel.uri.value, + viewModel.login.value, + viewModel.password.value + ) val handler = Neo4jHandler(repo) val wasGraphDirected = viewModel.canvasViewModel.graph.isDirected handler.saveGraphToNeo4j(viewModel.canvasViewModel.graph) From 3847a869494770d325f0da9148ee0e4ab50e30fe Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Sat, 26 Oct 2024 18:58:30 +0300 Subject: [PATCH 205/211] feat(algo): implement Key Vertices Search visualization --- .../controller/GraphSizerByCentrality.kt | 17 ++++++ .../model/keyVertices/KeyVerticesSearch.kt | 59 +++++++++++++++++++ src/main/kotlin/view/AlgorithmSubMenu.kt | 7 ++- 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/controller/GraphSizerByCentrality.kt create mode 100644 src/main/kotlin/model/keyVertices/KeyVerticesSearch.kt diff --git a/src/main/kotlin/controller/GraphSizerByCentrality.kt b/src/main/kotlin/controller/GraphSizerByCentrality.kt new file mode 100644 index 0000000..58ec6a5 --- /dev/null +++ b/src/main/kotlin/controller/GraphSizerByCentrality.kt @@ -0,0 +1,17 @@ +package controller + +import androidx.compose.ui.unit.dp +import model.graph.Graph +import model.keyVertices.GraphBetweennessCentrality +import viewmodel.graph.GraphViewModel + +class GraphSizerByCentrality(private val graph: Graph, private val graphViewModel: GraphViewModel) { + private val algoInitialize = GraphBetweennessCentrality() + private val centrality = algoInitialize.getKeyVertices(graph) + + fun changeSize() { + for (vertex in centrality.keys) { + graphViewModel.verticesView[vertex]!!.radius = centrality[vertex]!!.dp + } + } +} diff --git a/src/main/kotlin/model/keyVertices/KeyVerticesSearch.kt b/src/main/kotlin/model/keyVertices/KeyVerticesSearch.kt new file mode 100644 index 0000000..c32f9ab --- /dev/null +++ b/src/main/kotlin/model/keyVertices/KeyVerticesSearch.kt @@ -0,0 +1,59 @@ +package model.keyVertices + +import model.graph.Graph +import model.graph.Vertex +import java.util.* + +class GraphBetweennessCentrality { + fun getKeyVertices(graph: Graph): Map { + val betweennessMap = mutableMapOf().withDefault { 0f } + val vertices = graph.vertices.values + + for (sourceVertex in vertices) { + val stack = Stack() + val predecessors = mutableMapOf>().withDefault { mutableListOf() } + val sourceVertexWeight = mutableMapOf().withDefault { 0f } + val distance = mutableMapOf().withDefault { -1 } + val sourceVertexDependency = mutableMapOf().withDefault { 0f } + + sourceVertexWeight[sourceVertex] = 1f + distance[sourceVertex] = 0 + + val queue: Queue = LinkedList() + queue.add(sourceVertex) + + while (queue.isNotEmpty()) { + val currentVertex = queue.poll() + stack.push(currentVertex) + + for (successorVertex in currentVertex.adjacentVertices) { + if (!distance.containsKey(successorVertex)) { + queue.offer(successorVertex) + distance[successorVertex] = distance.getOrDefault(currentVertex, 0) + 1 + } + if (distance.getOrDefault(successorVertex, 0) == distance.getOrDefault(currentVertex, 0) + 1) { + sourceVertexWeight[successorVertex] = sourceVertexWeight.getOrDefault(successorVertex, 0f) + sourceVertexWeight.getOrDefault(currentVertex, 0f) + if (!predecessors.containsKey(successorVertex)) { + predecessors[successorVertex] = mutableListOf() + } + predecessors[successorVertex]!!.add(currentVertex) + } + } + } + + while (stack.isNotEmpty()) { + val successorVertex = stack.pop() + for (currentVertex in predecessors.getOrDefault(successorVertex, emptyList())) { + sourceVertexDependency[currentVertex] = sourceVertexDependency.getOrDefault(currentVertex, 0f) + + (sourceVertexWeight.getOrDefault(currentVertex, 0f) / sourceVertexWeight.getOrDefault(successorVertex, 0f)) * + (1 + sourceVertexDependency.getOrDefault(successorVertex, 0f)) + } + if (successorVertex != sourceVertex) { + betweennessMap[successorVertex] = betweennessMap.getOrDefault(successorVertex, 0f) + sourceVertexDependency.getOrDefault(successorVertex, 0f) + } + } + } + + return betweennessMap + } +} diff --git a/src/main/kotlin/view/AlgorithmSubMenu.kt b/src/main/kotlin/view/AlgorithmSubMenu.kt index f6c08ec..c6fd900 100644 --- a/src/main/kotlin/view/AlgorithmSubMenu.kt +++ b/src/main/kotlin/view/AlgorithmSubMenu.kt @@ -10,6 +10,7 @@ import controller.GraphPainterByCycles import controller.GraphPainterByDjikstra import controller.GraphPainterByKosaraju import controller.GraphPainterByKruskal +import controller.GraphSizerByCentrality import view.algos.bridgeHighlighter import viewmodel.CanvasViewModel @@ -22,7 +23,11 @@ fun AlgorithmSubMenu(viewModel: CanvasViewModel) { Column(Modifier.padding(start = 16.dp, end = 0.dp, top = 15.dp)) { Button( - onClick = { /*TODO*/}, + onClick = { + val graph = viewModel.graph + val changer = GraphSizerByCentrality(graph, viewModel.graphViewModel) + changer.changeSize() + }, enabled = true, ) { Text( From 6a65918a2781d35078dbad895ea3b0f8e9903cca Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 31 Oct 2024 13:29:57 +0300 Subject: [PATCH 206/211] fix(Kruskal): add properly visualization for Kruskal algo --- src/main/kotlin/controller/GraphPainterByKruskal.kt | 7 ++----- src/main/kotlin/view/graph/EdgeView.kt | 2 +- src/main/kotlin/viewmodel/graph/EdgeViewModel.kt | 2 ++ src/main/kotlin/viewmodel/graph/GraphViewModel.kt | 3 ++- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/controller/GraphPainterByKruskal.kt b/src/main/kotlin/controller/GraphPainterByKruskal.kt index e099b95..97c2f90 100644 --- a/src/main/kotlin/controller/GraphPainterByKruskal.kt +++ b/src/main/kotlin/controller/GraphPainterByKruskal.kt @@ -11,11 +11,8 @@ class GraphPainterByKruskal(private val graph: Graph, private val graphViewModel fun paint() { for (edgeId in tree) { - val verticesId = graph.edges[edgeId]?.vertices - val currVertexFirst = graph.vertices[verticesId?.first] - val currVertexSecond = graph.vertices[verticesId?.second] - graphViewModel.verticesView[currVertexFirst]!!.color = Color.Red - graphViewModel.verticesView[currVertexSecond]!!.color = Color.Red + val currEdge = graph.edges[edgeId] + graphViewModel.edgesView[currEdge]!!.color = Color.Red } } } diff --git a/src/main/kotlin/view/graph/EdgeView.kt b/src/main/kotlin/view/graph/EdgeView.kt index 983ee1b..250a28f 100644 --- a/src/main/kotlin/view/graph/EdgeView.kt +++ b/src/main/kotlin/view/graph/EdgeView.kt @@ -26,7 +26,7 @@ fun EdgeView( viewModel.v.x.toPx() + viewModel.v.radius.toPx(), viewModel.v.y.toPx() + viewModel.v.radius.toPx(), ), - color = Color.Black + color = viewModel.color ) } } diff --git a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt index 41ecd88..ec5f976 100644 --- a/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/EdgeViewModel.kt @@ -1,11 +1,13 @@ package viewmodel.graph import model.graph.Edge +import androidx.compose.ui.graphics.Color class EdgeViewModel( val u: VertexViewModel, val v: VertexViewModel, val e: Edge, + var color: Color, ) { val weight get() = e.weight.toString() diff --git a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt index a07f89f..fe94dee 100644 --- a/src/main/kotlin/viewmodel/graph/GraphViewModel.kt +++ b/src/main/kotlin/viewmodel/graph/GraphViewModel.kt @@ -32,7 +32,8 @@ class GraphViewModel( ?: throw IllegalStateException( "VertexView for vertex with id: ${edge.vertices.second} not found" ) - val currentEdgeView = EdgeViewModel(fst, snd, edge) + val color = Color.Black + val currentEdgeView = EdgeViewModel(fst, snd, edge, color) edgesView[edge] = currentEdgeView } } From bf9c81e81cf238eaf682ef2e8b47858304a1951a Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 31 Oct 2024 13:30:51 +0300 Subject: [PATCH 207/211] fix(keyValues): add instant redrawing of graph --- src/main/kotlin/controller/GraphSizerByCentrality.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/controller/GraphSizerByCentrality.kt b/src/main/kotlin/controller/GraphSizerByCentrality.kt index 58ec6a5..f91f83d 100644 --- a/src/main/kotlin/controller/GraphSizerByCentrality.kt +++ b/src/main/kotlin/controller/GraphSizerByCentrality.kt @@ -1,5 +1,6 @@ package controller +import androidx.compose.runtime.Composable import androidx.compose.ui.unit.dp import model.graph.Graph import model.keyVertices.GraphBetweennessCentrality @@ -8,10 +9,11 @@ import viewmodel.graph.GraphViewModel class GraphSizerByCentrality(private val graph: Graph, private val graphViewModel: GraphViewModel) { private val algoInitialize = GraphBetweennessCentrality() private val centrality = algoInitialize.getKeyVertices(graph) - + fun changeSize() { for (vertex in centrality.keys) { graphViewModel.verticesView[vertex]!!.radius = centrality[vertex]!!.dp + graphViewModel.verticesView[vertex]!!.x += 1.dp } } } From 14cb448e8def21b5e9d2945e81696fd4f13f8ad4 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 31 Oct 2024 13:59:18 +0300 Subject: [PATCH 208/211] fix: correct edges drawing --- src/main/kotlin/controller/GraphSizerByCentrality.kt | 2 +- src/main/kotlin/view/graph/VertexView.kt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/controller/GraphSizerByCentrality.kt b/src/main/kotlin/controller/GraphSizerByCentrality.kt index f91f83d..3dabc7c 100644 --- a/src/main/kotlin/controller/GraphSizerByCentrality.kt +++ b/src/main/kotlin/controller/GraphSizerByCentrality.kt @@ -12,7 +12,7 @@ class GraphSizerByCentrality(private val graph: Graph, private val graphViewMode fun changeSize() { for (vertex in centrality.keys) { - graphViewModel.verticesView[vertex]!!.radius = centrality[vertex]!!.dp + graphViewModel.verticesView[vertex]!!.radius += (centrality[vertex]!!*0.2).dp graphViewModel.verticesView[vertex]!!.x += 1.dp } } diff --git a/src/main/kotlin/view/graph/VertexView.kt b/src/main/kotlin/view/graph/VertexView.kt index 7668cc1..1a7b7a7 100644 --- a/src/main/kotlin/view/graph/VertexView.kt +++ b/src/main/kotlin/view/graph/VertexView.kt @@ -21,10 +21,11 @@ fun VertexView( viewModel: VertexViewModel, modifier: Modifier = Modifier, ) { + var diametr = viewModel.radius + viewModel.radius Box( modifier = modifier - .size(viewModel.radius + 10.dp, viewModel.radius + 10.dp) + .size(diametr, diametr) .offset(viewModel.x, viewModel.y) .border(2.dp, Color.Black, CircleShape) .background(color = viewModel.color, shape = CircleShape) From 1fcda1b5f9c9b5b0c48e75ea23cb2f75fdcd5031 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 31 Oct 2024 15:32:30 +0300 Subject: [PATCH 209/211] feat(findCycles): add findCycles algo visualization --- .../kotlin/controller/GraphPainterByCycles.kt | 9 +- .../kotlin/model/algorithms/FindCycles.kt | 159 ++++-------------- 2 files changed, 38 insertions(+), 130 deletions(-) diff --git a/src/main/kotlin/controller/GraphPainterByCycles.kt b/src/main/kotlin/controller/GraphPainterByCycles.kt index ed56731..e89e77e 100644 --- a/src/main/kotlin/controller/GraphPainterByCycles.kt +++ b/src/main/kotlin/controller/GraphPainterByCycles.kt @@ -1,14 +1,19 @@ package controller import model.graph.Graph +import model.graph.Vertex import viewmodel.graph.GraphViewModel -import algorithms.FindCycles +import model.algorithms.FindCycles class GraphPainterByCycles(private val graph: Graph, private val graphViewModel: GraphViewModel) { private val algoInitialize = FindCycles() - private val cycles = algoInitialize.simpleCycles(graph) + private val cycles = mutableListOf>() + private val vertices = graph.getVertices() fun paint() { + for(vertex in vertices){ + cycles.add(algoInitialize.simpleCycles(graph, vertex)) + } for ((i, cycle) in cycles.withIndex()) { val cycleColor = generateRandomColor(i * 451) for (vertex in cycle) { diff --git a/src/main/kotlin/model/algorithms/FindCycles.kt b/src/main/kotlin/model/algorithms/FindCycles.kt index 0f1afd7..a4f7147 100644 --- a/src/main/kotlin/model/algorithms/FindCycles.kt +++ b/src/main/kotlin/model/algorithms/FindCycles.kt @@ -1,141 +1,44 @@ -package algorithms +package model.algorithms -import java.util.* -import model.algorithms.Kosaraju import model.graph.Graph import model.graph.Vertex class FindCycles { - private var blockedSet: MutableSet = mutableSetOf() - private var blockedMap: MutableMap?> = mutableMapOf() - private var stack: Deque = LinkedList() - private var allCycles: MutableList> = mutableListOf() - - fun simpleCycles(graph: Graph): List> { - blockedSet = HashSet() - blockedMap = HashMap?>() - stack = LinkedList() - allCycles = ArrayList>() - var startIndex = 1 - val kosaraju = Kosaraju(graph) - while (startIndex <= graph.vertices.size) { - val subGraph: Graph = createSubGraph(startIndex, graph) - val sccs: List> = kosaraju.findStronglyConnectedComponents() - val maybeLeastVertex: Vertex? = leastIndexSCC(sccs, subGraph) - if (maybeLeastVertex != null) { - val leastVertex: Vertex = maybeLeastVertex - blockedSet.clear() - blockedMap.clear() - findCyclesInSCG(graph, leastVertex, leastVertex) - startIndex = leastVertex.id + 1 - } else { - break - } - } - return allCycles - } - - private fun leastIndexSCC(sccs: List>, subGraph: Graph): Vertex? { - var min = Int.MAX_VALUE - var minVertex: Vertex? = null - var minScc: List = mutableListOf() - for (scc in sccs) { - if (scc.size == 1) { - continue - } - for (vertexId in scc) { - if (vertexId < min) { - min = vertexId - minVertex = subGraph.vertices[vertexId] - minScc = scc + fun simpleCycles(graph: Graph, startingVertex: Vertex): List { + val isDirected = graph.isDirected + val cameFrom = HashMap(graph.vertices.size) + val visited = HashSet(graph.vertices.size) + val stack = mutableListOf(startingVertex) + + while (stack.isNotEmpty()) { + val currentVertex = stack.removeLast() + visited.add(currentVertex) + for (neighbourVertex in currentVertex.adjacentVertices) { + + if (neighbourVertex == startingVertex) { + cameFrom[neighbourVertex] = currentVertex } - } - } - - if (minVertex == null) { - return null - } - val graphScc = Graph() - graphScc.isDirected = true - for ((i, edge) in subGraph.getEdges().withIndex()) { - if ( - (subGraph.vertices[edge.vertices.first]?.id in minScc) && - (subGraph.vertices[edge.vertices.second]?.id in minScc) - ) { - graphScc.addVertex(edge.vertices.first, "") - graphScc.addVertex(edge.vertices.second, "") - graphScc.addEdge(edge.vertices.first, edge.vertices.second, edgeID = i) - } - } - return graphScc.vertices[(minVertex.id)] - } - private fun unblock(u: Vertex) { - blockedSet.remove(u) - if (blockedMap[u] != null) { - blockedMap[u]!!.forEach { v: Vertex -> - if (blockedSet.contains(v)) { - unblock(v) + if (neighbourVertex == startingVertex && (isDirected || cameFrom[currentVertex] != startingVertex)) { + // found path + val path = mutableListOf(startingVertex) + var cur = cameFrom[neighbourVertex] + while (cur != startingVertex) { + if (cur == null) break + path.add(cur) + cur = cameFrom[cur] + } + path.add(startingVertex) + return path.reversed() } - } - blockedMap.remove(u) - } - } - - private fun findCyclesInSCG( - graph: Graph, - startVertex: Vertex, - currentVertex: Vertex, - ): Boolean { - var foundCycle = false - stack.push(currentVertex) - blockedSet.add(currentVertex) - for (e in graph.edges.filterKeys { it in currentVertex.incidentEdges }.values) { - val neighbor: Vertex = graph.vertices[e.vertices.second]!! - if (neighbor === startVertex) { - val cycle: MutableList = ArrayList() - stack.push(startVertex) - cycle.addAll(stack) - cycle.reverse() - stack.pop() - allCycles.add(cycle) - foundCycle = true - } else if (!blockedSet.contains(neighbor)) { - val gotCycle = findCyclesInSCG(graph, startVertex, neighbor) - foundCycle = foundCycle || gotCycle - } - } - if (foundCycle) { - unblock(currentVertex) - } else { - for (e in graph.edges.filterKeys { it in currentVertex.incidentEdges }.values) { - val w: Vertex = graph.vertices[e.vertices.second]!! - val bSet: MutableSet = getBSet(w) - bSet.add(currentVertex) + if (neighbourVertex !in visited) { + cameFrom[neighbourVertex] = currentVertex + stack.add(neighbourVertex) + } } } - stack.pop() - return foundCycle - } - - private fun getBSet(v: Vertex): MutableSet { - if (!blockedMap.containsKey(v)) { - blockedMap[v] = HashSet() - } - return (blockedMap[v] as MutableSet?)!! - } - private fun createSubGraph(startVertex: Int, graph: Graph): Graph { - val subGraph = Graph() - subGraph.isDirected = true - for ((i, edge) in graph.getEdges().withIndex()) { - if (edge.vertices.first >= startVertex && edge.vertices.second >= startVertex) { - subGraph.addVertex(edge.vertices.first, "") - subGraph.addVertex(edge.vertices.second, "") - subGraph.addEdge(edge.vertices.first, edge.vertices.second, edgeID = i) - } - } - return subGraph + return listOf() } -} +} \ No newline at end of file From d8d604739a2175a7bc1c9158e9573efdde0b58c2 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 31 Oct 2024 15:34:52 +0300 Subject: [PATCH 210/211] fix(tests): update tests after change weight Type --- .../graphs/algorithms/BridgeFinderTest.kt | 26 ++++++------ .../kotlin/graphs/algorithms/DjikstraTest.kt | 28 ++++++------- .../graphs/algorithms/FordBellmanTest.kt | 30 +++++++------- .../kotlin/graphs/algorithms/KosajaruTest.kt | 38 +++++++++--------- .../kotlin/graphs/algorithms/KruskalTest.kt | 40 +++++++++---------- .../kotlin/graphs/algorithms/LouvainTest.kt | 14 +++---- 6 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt index e052c04..34454a1 100644 --- a/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt +++ b/src/test/kotlin/graphs/algorithms/BridgeFinderTest.kt @@ -22,12 +22,12 @@ class BridgeFinderTest { addVertex(6, "Arthur Shelby") addVertex(7, "Ryan Gosling") - addEdge(1, 2, 1, 1) - addEdge(3, 4, 2, 2) - addEdge(1, 3, 3, 3) - addEdge(2, 4, 4, 4) - addEdge(2, 5, 5, 5) - addEdge(5, 7, 6, 6) + addEdge(1, 2, 1f, 1) + addEdge(3, 4, 2f, 2) + addEdge(1, 3, 3f, 3) + addEdge(2, 4, 4f, 4) + addEdge(2, 5, 5f, 5) + addEdge(5, 7, 6f, 6) addVertex(8, "Pudge") addVertex(9, "Tiny") @@ -37,14 +37,14 @@ class BridgeFinderTest { addVertex(13, "Sniper") addVertex(14, "Roshan") - addEdge(14, 8, 7, 7) - addEdge(14, 9, 8, 8) - addEdge(14, 10, 9, 9) - addEdge(14, 11, 10, 10) - addEdge(14, 12, 11, 11) - addEdge(14, 13, 12, 12) + addEdge(14, 8, 7f, 7) + addEdge(14, 9, 8f, 8) + addEdge(14, 10, 9f, 9) + addEdge(14, 11, 10f, 10) + addEdge(14, 12, 11f, 11) + addEdge(14, 13, 12f, 12) - addEdge(14, 3, 0, 13) + addEdge(14, 3, 0f, 13) } } diff --git a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt index 25b28af..f48dfeb 100644 --- a/src/test/kotlin/graphs/algorithms/DjikstraTest.kt +++ b/src/test/kotlin/graphs/algorithms/DjikstraTest.kt @@ -25,13 +25,13 @@ fun createSampleGraphDjikstraDirected(): Graph { graph.addVertex(4, "D") graph.addVertex(5, "E") - graph.addEdge(1, 2, 10L, 0) - graph.addEdge(1, 5, 100L, 1) - graph.addEdge(1, 4, 30L, 2) - graph.addEdge(2, 3, 50L, 3) - graph.addEdge(3, 5, 10L, 4) - graph.addEdge(4, 3, 20L, 5) - graph.addEdge(4, 5, 60L, 6) + graph.addEdge(1, 2, 10f, 0) + graph.addEdge(1, 5, 100f, 1) + graph.addEdge(1, 4, 30f, 2) + graph.addEdge(2, 3, 50f, 3) + graph.addEdge(3, 5, 10f, 4) + graph.addEdge(4, 3, 20f, 5) + graph.addEdge(4, 5, 60f, 6) return graph } @@ -46,13 +46,13 @@ fun createSampleGraphDjikstra(): Graph { graph.addVertex(4, "D") graph.addVertex(5, "E") - graph.addEdge(1, 2, 10L, 0) - graph.addEdge(1, 5, 100L, 1) - graph.addEdge(1, 4, 30L, 2) - graph.addEdge(2, 3, 50L, 3) - graph.addEdge(3, 5, 10L, 4) - graph.addEdge(4, 3, 20L, 5) - graph.addEdge(4, 5, 60L, 6) + graph.addEdge(1, 2, 10f, 0) + graph.addEdge(1, 5, 100f, 1) + graph.addEdge(1, 4, 30f, 2) + graph.addEdge(2, 3, 50f, 3) + graph.addEdge(3, 5, 10f, 4) + graph.addEdge(4, 3, 20f, 5) + graph.addEdge(4, 5, 60f, 6) return graph } diff --git a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt index 88e7226..60044f7 100644 --- a/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt +++ b/src/test/kotlin/graphs/algorithms/FordBellmanTest.kt @@ -19,12 +19,12 @@ class FordBellmanTest { addVertex(3, "Iakov") addVertex(4, "John Shelby") addVertex(5, "Arthur Shelby") - addEdge(1, 2, 3, 5) - addEdge(2, 3, 6, 2) - addEdge(1, 4, 2, 4) - addEdge(5, 3, 1, 3) - addEdge(1, 3, 5, 1) - addEdge(4, 5, 1, 6) + addEdge(1, 2, 3f, 5) + addEdge(2, 3, 6f, 2) + addEdge(1, 4, 2f, 4) + addEdge(5, 3, 1f, 3) + addEdge(1, 3, 5f, 1) + addEdge(4, 5, 1f, 6) } val fordBellman = FordBellman(graph) fordBellman.shortestPath(1, 3) @@ -53,11 +53,11 @@ class FordBellmanTest { addVertex(4, "John Shelby") addVertex(5, "John Shelby") - addEdge(1, 2, -2, 3) - addEdge(2, 3, 1, 2) - addEdge(4, 1, -1, 1) - addEdge(3, 4, 1, 4) - addEdge(4, 5, 5, 5) + addEdge(1, 2, -2f, 3) + addEdge(2, 3, 1f, 2) + addEdge(4, 1, -1f, 1) + addEdge(3, 4, 1f, 4) + addEdge(4, 5, 5f, 5) } val fordBellman = FordBellman(graph) fordBellman.shortestPath(1, 5) @@ -86,10 +86,10 @@ class FordBellmanTest { addVertex(4, "John Shelby") addVertex(5, "John Shelby") - addEdge(1, 2, 2, 3) - addEdge(2, 3, 1, 2) - addEdge(4, 1, -1, 1) - addEdge(3, 4, 1, 4) + addEdge(1, 2, 2f, 3) + addEdge(2, 3, 1f, 2) + addEdge(4, 1, -1f, 1) + addEdge(3, 4, 1f, 4) } val fordBellman = FordBellman(graph) fordBellman.shortestPath(1, 5) diff --git a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt index a3f661f..221568d 100644 --- a/src/test/kotlin/graphs/algorithms/KosajaruTest.kt +++ b/src/test/kotlin/graphs/algorithms/KosajaruTest.kt @@ -33,25 +33,25 @@ fun createSampleGraph(): Graph { graph.addVertex(11, "L") // Добавление рёбер - graph.addEdge(0, 7, 1L, 0) - graph.addEdge(7, 6, 1L, 1) - graph.addEdge(6, 0, 1L, 2) - graph.addEdge(6, 1, 1L, 3) - graph.addEdge(6, 4, 1L, 4) - graph.addEdge(7, 1, 1L, 5) - graph.addEdge(1, 9, 1L, 6) - graph.addEdge(9, 4, 1L, 7) - graph.addEdge(4, 2, 1L, 8) - graph.addEdge(2, 9, 1L, 9) - graph.addEdge(2, 10, 1L, 10) - graph.addEdge(11, 9, 1L, 11) - graph.addEdge(11, 2, 1L, 12) - graph.addEdge(11, 5, 1L, 13) - graph.addEdge(10, 8, 1L, 14) - graph.addEdge(8, 5, 1L, 15) - graph.addEdge(5, 10, 1L, 16) - graph.addEdge(5, 3, 1L, 17) - graph.addEdge(3, 8, 1L, 18) + graph.addEdge(0, 7, 1f, 0) + graph.addEdge(7, 6, 1f, 1) + graph.addEdge(6, 0, 1f, 2) + graph.addEdge(6, 1, 1f, 3) + graph.addEdge(6, 4, 1f, 4) + graph.addEdge(7, 1, 1f, 5) + graph.addEdge(1, 9, 1f, 6) + graph.addEdge(9, 4, 1f, 7) + graph.addEdge(4, 2, 1f, 8) + graph.addEdge(2, 9, 1f, 9) + graph.addEdge(2, 10, 1f, 10) + graph.addEdge(11, 9, 1f, 11) + graph.addEdge(11, 2, 1f, 12) + graph.addEdge(11, 5, 1f, 13) + graph.addEdge(10, 8, 1f, 14) + graph.addEdge(8, 5, 1f, 15) + graph.addEdge(5, 10, 1f, 16) + graph.addEdge(5, 3, 1f, 17) + graph.addEdge(3, 8, 1f, 18) return graph } diff --git a/src/test/kotlin/graphs/algorithms/KruskalTest.kt b/src/test/kotlin/graphs/algorithms/KruskalTest.kt index be90236..03eeb91 100644 --- a/src/test/kotlin/graphs/algorithms/KruskalTest.kt +++ b/src/test/kotlin/graphs/algorithms/KruskalTest.kt @@ -15,24 +15,24 @@ class KruskalTest { for (i in 0..8) { graph.addVertex(i, "") } - graph.addEdge(0, 1, 4L, 0) - graph.addEdge(0, 7, 8L, 1) - graph.addEdge(1, 2, 8L, 2) - graph.addEdge(1, 7, 11L, 3) - graph.addEdge(2, 3, 7L, 4) - graph.addEdge(2, 8, 2L, 5) - graph.addEdge(2, 5, 4L, 6) - graph.addEdge(3, 4, 9L, 7) - graph.addEdge(3, 5, 14L, 8) - graph.addEdge(4, 5, 10L, 9) - graph.addEdge(5, 6, 2L, 10) - graph.addEdge(6, 7, 1L, 11) - graph.addEdge(6, 8, 6L, 12) - graph.addEdge(7, 8, 7L, 13) + graph.addEdge(0, 1, 4f, 0) + graph.addEdge(0, 7, 8f, 1) + graph.addEdge(1, 2, 8f, 2) + graph.addEdge(1, 7, 11f, 3) + graph.addEdge(2, 3, 7f, 4) + graph.addEdge(2, 8, 2f, 5) + graph.addEdge(2, 5, 4f, 6) + graph.addEdge(3, 4, 9f, 7) + graph.addEdge(3, 5, 14f, 8) + graph.addEdge(4, 5, 10f, 9) + graph.addEdge(5, 6, 2f, 10) + graph.addEdge(6, 7, 1f, 11) + graph.addEdge(6, 8, 6f, 12) + graph.addEdge(7, 8, 7f, 13) val expected = setOf(0, 1, 4, 5, 6, 7, 10, 11).sorted() val algo = KruskalsMST() - algo.kruskals(graph) - assertEquals(expected, algo.resultsId) + val resultsId = algo.kruskals(graph) + assertEquals(expected, resultsId) } @Test @@ -42,8 +42,8 @@ class KruskalTest { graph.addVertex(0, "") val expected = emptyList() val algo = KruskalsMST() - algo.kruskals(graph) - assertEquals(expected, algo.resultsId) + val resultsId = algo.kruskals(graph) + assertEquals(expected, resultsId) } @Test @@ -52,7 +52,7 @@ class KruskalTest { val graph = Graph() val expected = emptyList() val algo = KruskalsMST() - algo.kruskals(graph) - assertEquals(expected, algo.resultsId) + val resultsId = algo.kruskals(graph) + assertEquals(expected, resultsId) } } diff --git a/src/test/kotlin/graphs/algorithms/LouvainTest.kt b/src/test/kotlin/graphs/algorithms/LouvainTest.kt index 104b07d..ee76fbe 100644 --- a/src/test/kotlin/graphs/algorithms/LouvainTest.kt +++ b/src/test/kotlin/graphs/algorithms/LouvainTest.kt @@ -37,13 +37,13 @@ fun createSampleGraph2(): Graph { graph.addVertex(5, "E") graph.addVertex(6, "F") - graph.addEdge(1, 2, 10L, 1) - graph.addEdge(1, 3, 5L, 2) - graph.addEdge(2, 3, 5L, 3) - graph.addEdge(3, 4, 15L, 4) - graph.addEdge(4, 5, 5L, 5) - graph.addEdge(4, 6, 5L, 6) - graph.addEdge(5, 6, 10L, 7) + graph.addEdge(1, 2, 10f, 1) + graph.addEdge(1, 3, 5f, 2) + graph.addEdge(2, 3, 5f, 3) + graph.addEdge(3, 4, 15f, 4) + graph.addEdge(4, 5, 5f, 5) + graph.addEdge(4, 6, 5f, 6) + graph.addEdge(5, 6, 10f, 7) return graph } From 5a484c8069f80a2ed1136471d7c7d831c82511d0 Mon Sep 17 00:00:00 2001 From: Andrew Strelnikov Date: Thu, 31 Oct 2024 16:36:27 +0300 Subject: [PATCH 211/211] feat: release verison --- src/main/kotlin/view/CanvasView.kt | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/view/CanvasView.kt b/src/main/kotlin/view/CanvasView.kt index 9bd9d25..0f22fca 100644 --- a/src/main/kotlin/view/CanvasView.kt +++ b/src/main/kotlin/view/CanvasView.kt @@ -73,20 +73,8 @@ fun Canvas(viewModel: CanvasViewModel) { } }, ) { - Scaffold( - floatingActionButton = { - ExtendedFloatingActionButton( - text = { Text("По приколу чисто") }, - icon = { Icon(Icons.Filled.Add, contentDescription = "") }, - onClick = { - scope.launch { drawerState.apply { if (isClosed) open() else close() } } - } - ) - } - ) { - IconButton(onClick = { scope.launch { drawerState.open() } }) { - Icon(Icons.Filled.Menu, contentDescription = "Меню") - } + IconButton(onClick = { scope.launch { drawerState.open() } }) { + Icon(Icons.Filled.Menu, contentDescription = "Меню") } GraphView(viewModel.graphViewModel) }