how to improve performance of finding all cycles in undirected graphs - javascript

I have reference the question Finding all cycles in undirected graphs . and write a javascript version, but I got the performance problem, I run on chrome, it took about 8 seconds, too a long time, for only 16 vertices and 33 edges on my undirected graphs. this is codes:
<script>
var graph = [[37,36], [37,168], [37,85], [37,2264], [37,3203], [36,85], [36,536], [36,5097], [85,168], [85,654], [85,755], [85,3607], [85,4021], [85,5097], [168,755], [536,4021], [536,5097], [536,5464], [536,6533], [654,3607], [654,4021], [654,5564], [654,6533], [755,2357], [755,3203], [755,3607], [2264,2357], [2264,3203], [2357,3203], [4021,5097], [5464,5564], [5464,6533], [5564,6533]];
var cycles = [];
function findAllCycles() {
var i, j, len;
var st1 = new Date().getTime();
for (i = 0; i < graph.length; i++) {
var edge = graph[i];
for (j = 0; j < 2; j++) {
findNewCycles( [edge[j]] );
}
}
var st2 = new Date().getTime();
console.log("time: " + (st2-st1));
};
function findNewCycles(path) {
var startNode = path[0],
nextNode;
// visit each edge and each node of each edge
for (var i = 0; i < graph.length; i++) {
var edge = graph[i];
for (var j = 0; j < 2; j++) {
var node = edge[j];
if (node === startNode) // edge refers to our current node
{
nextNode = edge[(j + 1) % 2];
if ( !visited(nextNode, path) ) { // neighbor node not on path yet
// explore extended path
findNewCycles( [nextNode].concat(path), graph, cycles );
}
else if ( (path.length > 2) && (nextNode === path[path.length - 1]) ) { // cycle found
//var p = normalize(path);
//var inv = invert(p);
if ( isNew(path, cycles) ) {
cycles.push(path);
}
}
}
}
}
}
// check if vertex n is contained in path
function visited(node, path) {
return (path.indexOf(node) !== -1);
}
function isNew(path, cycles) {
for (var i = 0; i < cycles.length; i++) {
if ( equal(path, cycles[i]) ) {
return false;
}
}
return true;
}
function equal(path1, path2) {
if (path1.length !== path2.length) {
return false;
}
for (var i = 0; i < path1.length; i++) {
var node1 = path1[i];
for (var j = 0; j < path2.length; j++) {
var node2 = path2[j];
if (node1 === node2) {
break;
}
}
if (j === path2.length) {
return false;
}
}
return true;
}
findAllCycles();
console.log(cycles);
</script>
how can I improve the performance.

I think you could try things differently.
You could calculate for each node it's depths. If you ever come to a node that already has a depth, then you have a cycles.
This algorithm would be in O(n) where n is the number of node. It should be much faster.
If you don't care about depth you could just "tag" the node.

I believe the problem is not the implementation of your algorithm. This graph is deceptively complicated, apparently containing a total of 3930 cycles! Including 39 chordless cycles plus 3891 cycles with chords (which include smaller cycles inside).
This is similar to the "how many squares" problem, it can be surprising how quickly it adds up.
You may be able to optimize significantly if you are only interested in chordless cycles.
(Side note: the equals function seems overly complicated, but this is presumably doesn't significantly affect performance)
function pathIsEqual(path1, path2) {
if (path1.length !== path2.length) {
return false
}
for(var i = path1.length; i--;) {
if(path1[i] !== path2[i]){
return false
}
}
return true;
}

Related

Having issues trying to solve N Rook problem . Always get n*n solution and not N factorial

I'm trying to get N ways of solves a N rook problem. The issue I am having is currently, I seem to get n*n solutions while it needs to be N! . Below is my code, I have written it in simple loops and functions, so it's quite long. Any help would be greatly appreciated
Note: Please ignore case for n = 2. I get some duplicates which I thought I would handle via JSON.stringify
var createMatrix = function (n) {
var newMatrix = new Array(n);
// build matrix
for (var i = 0; i < n; i++) {
newMatrix[i] = new Array(n);
}
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
newMatrix[i][j] = 0;
}
}
return newMatrix;
};
var newMatrix = createMatrix(n);
// based on rook position, greying out function
var collision = function (i, j) {
var col = i;
var row = j;
while (col < n) {
// set the row (i) to all 'a'
col++;
if (col < n) {
if (newMatrix[col][j] !== 1) {
newMatrix[col][j] = 'x';
}
}
}
while (row < n) {
// set columns (j) to all 'a'
row++;
if (row < n) {
if (newMatrix[i][row] !== 1) {
newMatrix[i][row] = 'x';
}
}
}
if (i > 0) {
col = i;
while (col !== 0) {
col--;
if (newMatrix[col][j] !== 1) {
newMatrix[col][j] = 'x';
}
}
}
if (j > 0) {
row = j;
while (row !== 0) {
row--;
if (newMatrix[i][row] !== 1) {
newMatrix[i][row] = 'x';
}
}
}
};
// checks position with 0 and sets it with Rook
var emptyPositionChecker = function (matrix) {
for (var i = 0; i < matrix.length; i++) {
for (var j = 0; j < matrix.length; j++) {
if (matrix[i][j] === 0) {
matrix[i][j] = 1;
collision(i, j);
return true;
}
}
}
return false;
};
// loop for every position on the board
loop1:
for (var i = 0; i < newMatrix.length; i++) {
var row = newMatrix[i];
for (var j = 0; j < newMatrix.length; j++) {
// pick a position for rook
newMatrix[i][j] = 1;
// grey out collison zones due to the above position
collision(i, j);
var hasEmpty = true;
while (hasEmpty) {
//call empty position checker
if (emptyPositionChecker(newMatrix)) {
continue;
} else {
//else we found a complete matrix, break
hasEmpty = false;
solutionCount++;
// reinitiaze new array to start all over
newMatrix = createMatrix(n);
break;
}
}
}
}
There seem to be two underlying problems.
The first is that several copies of the same position are being found.
If we consider the case of N=3 and we visualise the positions by making the first rook placed red, the second placed green and the third to be placed blue, we get these three boards:
They are identical positions but will count as 3 separate ones in the given Javascript.
For a 3x3 board there are also 2 other positions which have duplicates. The gets the count of unique positions to 9 - 2 - 1 -1 = 5. But we are expecting N! = 6 positions.
This brings us to the second problem which is that some positions are missed. In the case of N=3 this occurs once when i===j==1 - ie the mid point of the board.
This position is reached:
This position is not reached:
So now we have the number of positions that should be found as 9 - 2 - 1 - 1 +1;
There appears to be nothing wrong with the actual Javascript in as much as it is implementing the given algorithm. What is wrong is the algorithm which is both finding and counting duplicates and is missing some positions.
A common way of solving the N Rooks problem is to use a recursive method rather than an iterative one, and indeed iteration might very soon get totally out of hand if it's trying to evaluate every single position on a board of any size.
This question is probably best taken up on one of the other stackexchange sites where algorithms are discussed.

How to avoid my permutation algorithm of ERROR:heap out memory

Today I try to solve a problem on codewars,it requires me give the permutations of a given string.
Firstly,I try to use a recursion function looks like:
function permutate(str) {
var result = [];
if (str.length == 1) {
return [str]
} else {
var preResult = permutate(str.slice(1));
for (var j = 0; j < preResult.length; j++) {
for (var k = 0; k < preResult[j].length + 1; k++) {
var temp = preResult[j].slice(0, k) + str[0] + preResult[j].slice(k);
result.push(temp);
}
}
return result;
}
}
After I click the attemp button,the OJ tells me there is an error caused by heap out memory.Because my function called with a long string:"abcdefghijkl".
Secondly,I rewrite my function by using loop.just like:
function perm(str) {
let result = [],tempArr = [];
let subStr = str;
while (subStr.length !== 0) {
if (result.length === 0) {
result.push(str[0]);
} else {
for (let i = 0; i < result.length; i++) {
let item = result[i];
let itemLen = item.length;
for (let j = 0; j < itemLen+1; j++) {
let temp = item.slice(0, j) + subStr[0] + item.slice(j);
tempArr.push(temp);
}
}
result = tempArr;
tempArr = [];
}
subStr = subStr.slice(1);
}
return result;
}
It works when the given string is short.But still cause Error.
So,I want to know why cause this error and if there is a permutation algorithm can run in Node(v6.11.0) without memory error?
I searched a lot and tried many methods,but nothing works.So I ask my first question on stackoverflow,hoping you can give me some help.Thanks!
Try the module https://github.com/miguelmota/permutations, or even try to use the code from the module
In addition to previous answer as a possible try out, you can try to increase process max memory limit size, for example with node --max-old-space-size=8192 which is in bytes, the node process will run with extended 8GB memory limit.

Javascript neural network not converging [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I've been trying to evolve a neural network that prints values converging to one, using a genetic algorithm.
I've tried debugging the code but don't know what I've messed up.
I'm using fitness to chose the best "brains" and then cross them over (reproduce).
At the moment it is only trying to evolve "brains" that return the number. the fitness is a function of the difference between returned number and original number.
"use strict";
function sigmoid(x) {
return 1 / (1 + Math.E ** -x);
}
function random(min, max) {
return (max - min) * Math.random() + min
}
function toss() {
return random(-1, 1)
}
function Brain(inputs, hiddens, outputs) {
this.structure = [...arguments];
if (this.structure.length < 3) throw "Invalid layer count";
this.layers = [];
this.layers[this.structure.length - 1] = {
nodes: []
};
for (var i = this.structure.length - 1; i--;) this.layers[i] = {
bias: toss(),
nodes: []
};
for (var i = 1; i < this.structure.length; i++) {
var nodes = this.layers[i].nodes;;
for (var j = this.structure[i]; j--;) {
var node = nodes[j] = {
weights: []
};
for (var k = this.structure[i - 1]; k--;) node.weights[k] = toss();
}
};
}
Brain.prototype.compute = function() {
if (arguments[0] !== this.structure[0]) throw "Invalid input count";
for (var i = arguments.length; i--;) this.layers[0].nodes[i] = {
value: arguments[i]
};
for (var i = 1; i < this.layers.length - 1; i++) {
var layer = this.layers[i];
var feeder = this.layers[i - 1];
for (var j = layer.nodes.length; j--;) {
var node = layer.nodes[j];
var dot = 0;
for (var k = node.weights.length; k--;) dot += node.weights[k] * feeder.nodes[k].value;
node.value = sigmoid(dot + feeder.bias);
}
}
var result = [];
var layer = this.layers[this.layers.length - 1];
var feeder = this.layers[this.layers.length - 2];
for (var j = layer.nodes.length; j--;) {
var node = layer.nodes[j];
var dot = 0;
for (var k = node.weights.length; k--;) dot += node.weights[k] * feeder.nodes[k].value;
result[j] = sigmoid(dot + feeder.bias);
}
return result;
}
Brain.prototype.cross = function() {
var newBrain = new Brain(...this.structure);
var brains = [this, ...arguments];
for (var i = 1; i < newBrain.layers.length; i++) {
var layer = newBrain.layers[i];
for (var j = layer.nodes.length; j--;) {
var node = layer.nodes[j];
for (var k = node.weights.length; k--;) node.weights[k] = mutate() ||
brains[Math.floor(Math.random() * brains.length)]
.layers[i].nodes[j].weights[k];
}
}
for (var i = newBrain.layers.length - 1; i--;) newBrain.layers[i].bias = mutate() ||
brains[Math.floor(Math.random() * brains.length)]
.layers[i].bias;
return newBrain;
}
function mutate(key, nodes) {
if (Math.random() > 0.05) return toss();
}
var brain = new Brain(1, 5, 1);
var newBrain = new Brain(1, 5, 1)
var result = brain.compute(1);
var cross = brain.cross(newBrain);
var brains = [];
for (var node = 45; node--;) brains.push({
brain: new Brain(1, 5, 4, 3, 2, 1)
});
for (var count = 1000000; count--;) {
brains.push({
brain: new Brain(1, 5, 4, 3, 2, 1)
});
for (var node = brains.length; node--;) {
var brain = brains[node];
var number = 1;
var target = number;
brain.fitness = 1 / Math.abs(number - brain.brain.compute(number));
}
brains.sort((a, b) => a.fitness < b.fitness);
if (count % 10000 === 0) console.log(brains.length, brains[0].fitness);
var newBrains = [];
for (var node = 10; node--;)
for (var j = node; j--;) newBrains.push({
brain: brains[node].brain.cross(brains[j].brain)
});
brains = newBrains;
}
console.log(brains);
What will I need to improve/change?
Here is the console log:
46 1.468903884218341
46 1.1881817088540865
46 4.899728181582378
46 1.5494097713447523
46 2.4958253537304644
46 2.4091648830940953
46 1.4000955420478967
46 1.7560836401632383
46 3.3419380735652897
46 2.8290305398668245
46 2.951901023302089
46 2.9400525658126675
46 2.6769575714598948
46 1.55835425177616
As you can see, the fitness seems to be random
Some advice...
Neural networks usually take an input which should somehow be related to the output. I couldn't find any inputs for the network? If you can't come up with any good ideas just use the XOR problem and try to solve it.
When checking if your population is becoming better over time don't look at all brains of each generation. Remember, you are intentionally creating some randomized networks which may or may not be good at your task. Try printing the Top result of each generation and maybe the average score. In a working genetic algorithm both values should become better over time. (altough the top score is way more significant & important)
(Not directly adressing your issue) Don't use javascript. You could probably transscribe your current code to java/c#/c++. These languages execute way faster than JS.

Javascript - Code for finding a list of prime numbers keeps freezing

While working on problem 3 of Project Euler, I'm coming across a problem I can't seem to fix where javascript keeps freezing. Here's my code:
var is_prime = function(n) {
if (n === 1) {
return true;
}
if (n === 2) {
return true;
}
var list1 = []
for (i = 2; i < n; i++) {
list1.push(i);
}
for (i = 2; i < list1.length; i++) {
if (n % i === 0) {
return false;
}
}
return true;
}
var list_of_primes = function(n) {
var list1 = [];
var list2 = [];
for (i = 2; i < n; i++) {
list1.push(i);
}
for (i = 2; i < list1.length; i++) {
if (is_prime(i)) {
list2.push(i);
}
}
return list2;
}
confirm(list_of_primes(1000))
I know my algorithm isn't the most efficient and that I'm just brute forcing the problem, but I'm just wondering what it is I'm doing wrong. I'm pretty sure the problem lies somewhere within this block of code:
for (i = 2; i < list1.length; i++) {
if (is_prime(i)) {
list2.push(i);
}
}
I think a potential problem is that my algorithm is taking too long and that is what is causing javascript to freeze. Is there anyway to get my problem to run long enough to give me the answer?
You could try this.
var is_prime = function(n) {
if (n == 1) {
return true;
}
if (n == 2) {
return true;
}
for (var i = 2; i < n; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
var list_of_primes = function(n) {
var list2 = [];
for (var i = 2; i < n; i++) {
if (is_prime(i)) {
list2.push(i);
}
}
return list2;
}
confirm(list_of_primes(1000))
Working fine in less than seconds. https://jsfiddle.net/LL85rxv5/
A prime number (or a prime) is a natural number greater than 1 that has no positive divisors other than 1 and itself.
Strictly speaking, 1 is not a prime number so be sure to update that in your code.
Not really sure why your code is timing out, it's just a bit longhand and has an unnecessary array (list1). Anyway, here's a pretty shortened version of the code that comes up with a list of prime numbers from 2 to n.
This isn't too efficient for a large number set because it checks every number individually.
var list_of_primes = function(n) {
var list = [];
for (i = 2; i < n; i++) {
if (is_prime(i)) {
list.push(i);
}
}
return list;
}
function is_prime(i) {
for (var c = 2; c <= Math.sqrt(i); ++c)
if (i % c === 0)
return false;
return true;
}
If you want a bit more efficiency, look into the Sieve of Eratosthenes which can handle much larger sets:
// Credit: http://stackoverflow.com/a/15471749/1265817
var eratosthenes = function(n) {
// Eratosthenes algorithm to find all primes under n
var array = [], upperLimit = Math.sqrt(n), output = [];
// Make an array from 2 to (n - 1)
for (var i = 0; i < n; i++) {
array.push(true);
}
// Remove multiples of primes starting from 2, 3, 5,...
for (var i = 2; i <= upperLimit; i++) {
if (array[i]) {
for (var j = i * i; j < n; j += i) {
array[j] = false;
}
}
}
// All array[i] set to true are primes
for (var i = 2; i < n; i++) {
if(array[i]) {
output.push(i);
}
}
return output;
};
Working examples: https://jsfiddle.net/daCrosby/wfgq28no/
i is a global variable within is_prime function, which interferes with instance used in list_of_primes function. Fix by declaring i as local like this...
var is_prime = function(n) {
var i; // <~~ declare i as local variable here
if (n === 1) {

Creating A Randomised Array with a Single Pre-defined Choice in JavaScript

I'm creating a program that will ask a question and give 5 choices for answers.
One is pre-defined and is correct, the others I want to be random selections from a bank of answers and the entire array is to be shuffled too.
I've written something, but it has some inconsistencies.
For one, sometimes the pre-defined choice appears twice in the list (it appears to skip over my if check).
Another is that sometimes, the editor crashes when I run it.
I use for in loops and I'm worried the crash is caused by a never-ending loop.
Here's my code:
private var numberOfComponents:int;
private var maxComponents:int = 5;
//numberOfComponents returns the length property of my 'components' answer bank
componentsSelection = buildComponentSelectionList(0); //0 is the index of my correct answer
function buildComponentSelectionList(correctItemIndex){
var theArray:Array = new Array();
var indicesOfSelection:Array = getIndicesByIncluding(correctItemIndex);
Debug.Log(indicesOfSelection);
for (var i=0;i<indicesOfSelection.length;i++)
theArray.Push(components[indicesOfSelection[i]]);
return theArray;
}
function getIndicesByIncluding(correctItem){
var indicesArray:Array = new Array();
var numberOfChoices = maxComponents-1;
for(var i=0;i<numberOfChoices;i++){
var number = Mathf.Round(Random.value*(numberOfComponents-1));
addToRandomNumberSelection(indicesArray, number,correctItem);
}
indicesArray.Push(correctItem);
RandomizeArray(indicesArray);
return indicesArray;
}
function addToRandomNumberSelection(indicesArray:Array,number,correctItem){
if(indicesArray.length == 0){
indicesArray.Push(number);
} else {
var doesntExist = true;
for(var i=0;i<indicesArray.length;i++){
if(indicesArray[i] == correctItem)
doesntExist = false;
if (indicesArray[i] == number)
doesntExist = false;
}
if(doesntExist) {
indicesArray.Push(number);
} else {
addToRandomNumberSelection(indicesArray, Mathf.Round(Random.value*(numberOfComponents-1)),correctItem);
}
}
}
function RandomizeArray(arr : Array)
{
for (var i = arr.length - 1; i > 0; i--) {
var r = Random.Range(0,i);
var tmp = arr[i];
arr[i] = arr[r];
arr[r] = tmp;
}
}
The editor is Unity3D, and the code is a version of JavaScript; I think my error is a logic one, rather than a syntactical one.
I feel I've been staring at this code for too long now and I'm missing something obvious.
Can anybody help me?
You can loop through the options and determine the probability that it should be included, then shuffle the included options:
function getRandomOptions(allOptions, correctIndex, count){
var result = [allOptions[correctIndex]];
count--;
var left = allOptions.length;
for (var i = 0; count > 0; i++) {
if (i != correctIndex && Math.floor(Math.random() * left) < count) {
result.push(allOptions[i]);
count--;
}
left--;
}
shuffleArray(result);
return result;
}
function shuffleArray(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var r = Math.floor(Math.random() * i);
var tmp = arr[i];
arr[i] = arr[r];
arr[r] = tmp;
}
}
Demo: http://jsfiddle.net/Guffa/wXsjz/

Categories