From 9361664643bcfcc50ef788a82ddc22e412d545f6 Mon Sep 17 00:00:00 2001 From: Unick Soft Date: Sat, 17 Feb 2018 17:32:25 +0300 Subject: [PATCH] Added radius and diameter search --- script/Appilcation.js | 2 +- script/Graph.js | 30 +++- script/plugins/ConnectedComponent.js | 25 ++- script/plugins/Floid.js | 71 +++++---- script/plugins/RadiusAndDiameter.js | 225 +++++++++++++++++++++++++++ 5 files changed, 316 insertions(+), 37 deletions(-) create mode 100644 script/plugins/RadiusAndDiameter.js diff --git a/script/Appilcation.js b/script/Appilcation.js index 59c9ca3..1b7b48a 100644 --- a/script/Appilcation.js +++ b/script/Appilcation.js @@ -671,7 +671,7 @@ Application.prototype.GetStatus = function() Application.prototype.GetAdjacencyMatrix = function () { - return this.graph.GetAdjacencyMatrix(); + return this.graph.GetAdjacencyMatrixStr(); } Application.prototype.TestAdjacencyMatrix = function (matrix, rowsObj, colsObj, separator = ",") diff --git a/script/Graph.js b/script/Graph.js index 5609a44..167062f 100644 --- a/script/Graph.js +++ b/script/Graph.js @@ -18,6 +18,8 @@ function Graph() this.hasDirect = false; }; +// infinity +Graph.prototype.infinity = 1E8; Graph.prototype.AddNewVertex = function(vertex) { @@ -146,7 +148,7 @@ Graph.prototype.FindEdge = function(id1, id2) return res; } -Graph.prototype.GetAdjacencyMatrix = function () +Graph.prototype.GetAdjacencyMatrixStr = function () { var matrix = ""; for (var i = 0; i < this.vertices.length; i++) @@ -175,6 +177,32 @@ Graph.prototype.GetAdjacencyMatrix = function () return matrix; } +Graph.prototype.GetAdjacencyMatrix = function () +{ + var matrix = []; + + for (var i = 0; i < this.vertices.length; i ++) + { + matrix.push([]); + var v1 = this.vertices[i]; + for (var j = 0; j < this.vertices.length; j ++) + { + var v2 = this.vertices[j]; + var edge = this.FindEdge(v1.id, v2.id); + if (edge != null) + { + matrix[i][j] = edge.GetWeight(); + } + else + { + matrix[i][j] = this.infinity; + } + } + } + + return matrix; +} + Graph.prototype.TestAdjacencyMatrix = function (matrix, rowsObj, colsObj, separator = ",") { var bGoodFormat = true; diff --git a/script/plugins/ConnectedComponent.js b/script/plugins/ConnectedComponent.js index 33d9526..992ad5e 100644 --- a/script/plugins/ConnectedComponent.js +++ b/script/plugins/ConnectedComponent.js @@ -33,6 +33,17 @@ FindConnectedComponentNew.prototype.getMessage = function(local) } FindConnectedComponentNew.prototype.result = function(resultCallback) +{ + this.calculate(true); + + var result = {}; + result["version"] = 1; + this.selectedObjects = this.component; + + return result; +} + +FindConnectedComponentNew.prototype.calculate = function(fillUpText = false) { this.connectedComponentNumber = 0; this.component = {}; @@ -55,7 +66,10 @@ FindConnectedComponentNew.prototype.result = function(resultCallback) { var stackElement = stack[i]; this.component[stackElement.id] = connectedComponentNumber; - stackElement.upText = connectedComponentNumber; + if (fillUpText) + { + stackElement.upText = connectedComponentNumber; + } if (connectedVertex.hasOwnProperty(stackElement.id)) { @@ -81,11 +95,12 @@ FindConnectedComponentNew.prototype.result = function(resultCallback) } } this.connectedComponentNumber = connectedComponentNumber; - var result = {}; - result["version"] = 1; - this.selectedObjects = this.component; + + //var result = {}; + //result["version"] = 1; + //this.selectedObjects = this.component; - return result; + return this.connectedComponentNumber; } FindConnectedComponentNew.prototype.getObjectSelectedGroup = function(object) diff --git a/script/plugins/Floid.js b/script/plugins/Floid.js index 973498d..53b1902 100644 --- a/script/plugins/Floid.js +++ b/script/plugins/Floid.js @@ -46,35 +46,7 @@ FloidAlgorithm.prototype.result = function(resultCallback) this.matrix = []; - for (var i = 0; i < this.graph.vertices.length; i ++) - { - this.matrix.push([]); - var v1 = this.graph.vertices[i]; - var str = ""; - for (var j = 0; j < this.graph.vertices.length; j ++) - { - var v2 = this.graph.vertices[j]; - var edge = this.graph.FindEdge(v1.id, v2.id); - if (edge != null) - { - this.matrix[i][j] = edge.GetWeight(); - } - else - { - this.matrix[i][j] = this.infinity; - } - } - } - - for (var k = 0; k < this.graph.vertices.length; k ++) - for (var i = 0; i < this.graph.vertices.length; i ++) - for (var j = 0; j < this.graph.vertices.length; j ++) - { - if (this.matrix[i][j] > this.matrix[i][k] + this.matrix[k][j]) - { - this.matrix[i][j] = this.matrix[i][k] + this.matrix[k][j]; - } - } + this.resultMatrix(); //console.log(this.matrix); @@ -118,6 +90,45 @@ FloidAlgorithm.prototype.result = function(resultCallback) */ } + +FloidAlgorithm.prototype.resultMatrix = function() +{ + this.matrix = []; + + for (var i = 0; i < this.graph.vertices.length; i ++) + { + this.matrix.push([]); + var v1 = this.graph.vertices[i]; + var str = ""; + for (var j = 0; j < this.graph.vertices.length; j ++) + { + var v2 = this.graph.vertices[j]; + var edge = this.graph.FindEdge(v1.id, v2.id); + if (edge != null) + { + this.matrix[i][j] = edge.GetWeight(); + } + else + { + this.matrix[i][j] = this.infinity; + } + } + } + + for (var k = 0; k < this.graph.vertices.length; k ++) + for (var i = 0; i < this.graph.vertices.length; i ++) + for (var j = 0; j < this.graph.vertices.length; j ++) + { + if (this.matrix[i][j] > this.matrix[i][k] + this.matrix[k][j]) + { + this.matrix[i][j] = this.matrix[i][k] + this.matrix[k][j]; + } + } + + return this.matrix; +} + + FloidAlgorithm.prototype.getObjectSelectedGroup = function(object) { return 0; @@ -155,7 +166,7 @@ FloidAlgorithm.prototype.messageWasChanged = function() FloidAlgorithm.prototype.GetFloidMatrix = function() { - return this.graph.GetAdjacencyMatrix(); + return this.graph.GetAdjacencyMatrixStr(); } diff --git a/script/plugins/RadiusAndDiameter.js b/script/plugins/RadiusAndDiameter.js new file mode 100644 index 0000000..610b22f --- /dev/null +++ b/script/plugins/RadiusAndDiameter.js @@ -0,0 +1,225 @@ +/** + * Algorithm for reorder graph. + * + */ +function RadiusAndDiameter(graph, app) +{ + BaseAlgorithm.apply(this, arguments); + this.diameter = 0; + this.radius = 0; + this.diameterSelectedObjects = []; + this.radiusSelectedObjects = []; + this.centerVertexes = []; + this.peripheralVertexes = []; + this.isNotConnected = false; + this.isOneVertex = false; +} + + +// inheritance. +RadiusAndDiameter.prototype = Object.create(BaseAlgorithm.prototype); + + +RadiusAndDiameter.prototype.getName = function(local) +{ + return local == "ru" ? "Поиск радиуса и диаметра графа": "Search graph radius and diameter"; +} + +RadiusAndDiameter.prototype.getId = function() +{ + return "OlegSh.RadiusAndDiameter"; +} + +// @return message for user. +RadiusAndDiameter.prototype.getMessage = function(local) +{ + if (this.isNotConnected) + { + return (local == "ru" ? "Граф не является связным" : "Graph is disconnected"); + } + + if (this.isOneVertex) + { + return (local == "ru" ? "Граф содержит только одну вершину" : "Graph contains only one vertex"); + } + + var text = (local == "ru" ? "Радуис граф: " : "Graph radius: ") + this.radius; + + text = text + " ("; + for (i = 0; i < this.radiusSelectedObjects.length; i++) + { + if (this.radiusSelectedObjects[i] instanceof BaseVertex) + { + text = text + this.radiusSelectedObjects[i].mainText + ((i < this.radiusSelectedObjects.length - 1) ? "⇒" : ""); + } + } + text = text + ")."; + + text = text + (local == "ru" ? " Диаметр граф: " : "Graph diameter: ") + this.diameter; + + text = text + " ("; + for (i = 0; i < this.diameterSelectedObjects.length; i++) + { + if (this.diameterSelectedObjects[i] instanceof BaseVertex) + { + text = text + this.diameterSelectedObjects[i].mainText + ((i < this.diameterSelectedObjects.length - 1) ? "⇒" : ""); + } + } + text = text + ")."; + + return text; +} + +RadiusAndDiameter.prototype.result = function(resultCallback) +{ + var result = {}; + result["version"] = 1; + + if (this.graph.vertices.length == 1) + { + this.isOneVertex = true; + return; + } + + var connectedComponents = new FindConnectedComponentNew(this.graph, this.app); + var connectedComponentNumber = connectedComponents.calculate(); + if (connectedComponentNumber == 1) + { + var floid = new FloidAlgorithm(this.graph, this.app); + var matrix = floid.resultMatrix(); + this.diameter = -1; + var diameterStart = 0; + var diameterFinish = 0; + + this.radius = 1E10; + var radiusStart = 0; + var radiusFinish = 0; + + var eccentricity = []; + + for (var i = 0; i < matrix.length; i++) + { + var vertex = -1;//(i == 0 ? 1 : 0); + var vertexEccentricity = -1;//matrix[i][vertex]; + + for (var j = 0; j < matrix[i].length; j++) + { + if (vertexEccentricity < matrix[i][j] && i != j && matrix[i][j] != floid.infinity) + { + vertexEccentricity = matrix[i][j]; + vertex = j; + } + } + + var res = {value: vertexEccentricity, vertex: vertex}; + eccentricity.push(res); + } + + for (var i = 0; i < eccentricity.length; i++) + { + var vertexEccentricity = eccentricity[i].value; + if (vertexEccentricity < 0) + { + continue; + } + + if (this.radius > vertexEccentricity) + { + this.radius = vertexEccentricity; + radiusStart = i; + radiusFinish = eccentricity[i].vertex; + } + + if (this.diameter < vertexEccentricity) + { + this.diameter = vertexEccentricity; + diameterStart = i; + diameterFinish = eccentricity[i].vertex; + } + } + + for (var i = 0; i < eccentricity.length; i++) + { + var vertexEccentricity = eccentricity[i].value; + if (vertexEccentricity < 0) + { + continue; + } + + if (eccentricity[i].value == this.radius) + { + this.centerVertexes.push(this.graph.vertices[i].id); + this.graph.vertices[i].upText = (g_language == "ru" ? "Центральная" : "Central"); + } + if (eccentricity[i].value == this.diameter) + { + this.peripheralVertexes.push(this.graph.vertices[i].id); + this.graph.vertices[i].upText = (g_language == "ru" ? "Периферийная" : "Peripheral"); + } + } + + this.diameterSelectedObjects = this.getPathByMatrix(this.graph.GetAdjacencyMatrix(), matrix, diameterStart, diameterFinish, this.diameter); + + this.radiusSelectedObjects = this.getPathByMatrix(this.graph.GetAdjacencyMatrix(), matrix, radiusStart, radiusFinish, this.radius); + + } + else + { + this.isNotConnected = true; + } + + + return result; +} + +RadiusAndDiameter.prototype.getPathByMatrix = function(adjacencyMatrix, minPathMatrix, startNode, finishNode, length) +{ + var res = []; + vertices = this.graph.vertices; + while (length != adjacencyMatrix[startNode][finishNode]) + { + for (var i = 0; i < adjacencyMatrix.length; i ++) + { + if (minPathMatrix[i][finishNode] == length - adjacencyMatrix[startNode][i] && i != startNode) + { + res.push(vertices[startNode]); + res.push(this.graph.FindEdge(vertices[startNode].id, vertices[i].id)); + + length -= adjacencyMatrix[startNode][i]; + startNode = i; + break; + } + } + } + + res.push(vertices[startNode]); + res.push(this.graph.FindEdge(vertices[startNode].id, vertices[finishNode].id)); + res.push(vertices[finishNode]); + + return res; +} + +RadiusAndDiameter.prototype.getObjectSelectedGroup = function(object) +{ + var res = (this.diameterSelectedObjects.includes(object)) ? 1 : 0; + res = (this.radiusSelectedObjects.includes(object)) ? 2 : res; + //res = (this.centerVertexes.includes(object.id)) ? 3 : res; + //res = (this.peripheralVertexes.includes(object.id)) ? 4 : res; + + + return res; +} + +RadiusAndDiameter.prototype.getPriority = function() +{ + return -8.5; +} + +// Factory for connected components. +function CreateAlgorithmRadiusAndDiameter(graph, app) +{ + return new RadiusAndDiameter(graph, app) +} + +// Gerister connected component. +RegisterAlgorithm (CreateAlgorithmRadiusAndDiameter);