Javascript collision explanation for b-tree (Birthday Paradox)? - javascript

I want to create a b-tree for storing some data in local storage. I was thinking of using this to find the index of an ID in a sorted list.
If I index an array normally (i.e. to append like array[20032] = 123, what's the big-O of that in Javascript arrays?).
function sortedIndex(array, value) {
var low = 0,
high = array.length;
while (low < high) {
var mid = (low + high) >>> 1;
if (array[mid] < value) low = mid + 1;
else high = mid;
}
return low;
}
When I test this with random numbers, I get some collision and it exits before 10k.
for (i = 0; i < 10000; i++) {
var r = Math.random();
array[sortedIndex(array,r)] = r;
}
This exits after a certain time (I'm assuming because of a collision).
I'm thinking it's a birthday paradox kind of thing because the collisions seem to be more likely when the list is already populated (see graph link) (but no exception is thrown...).
I wanted to see the final length of the array after many iterations, I get distribution of final lengths that look like this:
sortedList = []
listLengths = []
for (j = 0; j < 100; j++) {
for (i = 0; i < 10000; i++) {
var r = Math.random();
sortedList[sortedIndex(sortedList,r)] = r;
}
listLengths.push(sortedList.length);
}
graph of final lengths of sorted array after 1-100 iterations of appending attempts
I honestly don't want to deal with this and would also appreciate some pointers on efficient localStorage libraries.

The problem is that you're not shifting all the old elements up when you insert a new element in the array. So you'll extend the array by 1 when the new item is higher than anything else, but just overwrite an existing element when it's less than or equal to the maximum element.
array.splice will insert and move everything over to make room.
array = [];
listLengths = [];
for (j = 0; j < 100; j++) {
for (i = 0; i < 100; i++) {
var r = Math.random();
array.splice(sortedIndex(array, r), 0, r);
}
listLengths.push(array.length);
}
console.log(listLengths);
function sortedIndex(array, value) {
var low = 0,
high = array.length;
while (low < high) {
var mid = (low + high) >>> 1;
if (array[mid] < value) low = mid + 1;
else high = mid;
}
return low;
}

Related

Neural network in JS does not train

I am trying to create a simple neural network in javascript with 2 inputs, 3 hidden and 1 output neurons that use matrixes of neurons and weights to pass forward, and backpropagation training to solve XOR problem for example. The problem is I get weights always fading to 0 fast and as a result I thing outputs equal to sigmoid(0) 0.5 value or really close. I am using a sigmoid function for activation while finding neuron values like this:
var multyplayMatrix = (a,b) => {
if(a.length !== b.length) return "length of matrix1 !== height of matrix2 :(";
let c = [];
let temp = 0;
for(var n = 0; n < b[0].length; n++){
for(var nn = 0; nn < a.length; nn++){
temp = temp + (a[nn] * b[nn][n]);
}
//sigmoid
c.push( 1 / (1 + Math.exp(-temp)) );
temp = 0;
}
return c;
}
After finding output from training data input I compare it with training data desired output and calculate error and weights delta with this:
var getError = () => {
let predicted;
if(desiredOutput !== undefined){
predicted = net.neurons[net.neurons.length-1][0]
}else{
return console.log("desired output not defined")
}
let error = predicted - desiredOutput[0];
let weights_delta = error * (predicted * (1 - predicted));
console.log("output error weight delta = " + weights_delta)
propogateBackward(weights_delta);
};
and start backpropagating with some learning rate - My backdrop function looks like this:
var learningRate = 0.5;
var propogateBackward = (output_weights_delta) => {
for(var n = 0; n < 3; n ++ ){
net.weights[net.weights.length-(1 + n)][0] = (net.weights[net.weights.length-(1 + n)][0] - net.neurons[net.neurons.length-2][2-n]) * output_weights_delta * learningRate;
}
let neuronErrors = [];
for(var n = 0; n < 3; n ++ ){
let hiddenError = output_weights_delta * net.weights[net.weights.length-(1 + n)][0];
let hidden_weights_delta = hiddenError * (net.neurons[net.neurons.length-2][2-n] * (1 - net.neurons[net.neurons.length-2][2-n]));
neuronErrors.push(hidden_weights_delta);
}
for(var n = 0; n < 3; n++){
for(var nn = 0; nn < 2; nn++){
net.weights[net.weights.length-(4 + nn)][n] = (net.weights[net.weights.length-(4 + nn)][0] - net.neurons[net.neurons.length-3][1-nn]) * neuronErrors[n] * learningRate;
}
}
draw();
}
Im using this function and XOR dataset to make a iteration/training loop like this and just after some iterations it already coverges close to 0.5
var train = (iterations) => {
for(var it = 0; it < iterations;it++){
for(var n = 0; n < dataset.length; n++){
addInput(dataset[n].inputs);
addOutput(dataset[n].outputs);
activate();
getError();
}
}
}
After googling most similar problems are connected with weight initiation in longer/deeper neural networks but that does not help here, and I did a couple of different variants of this net all get similar result so I'm probably loose on my theory/math..but where?:(
I'm just learning stats and this can be confusing, for me so excuse me if I didn't make 2 much sense - You can check the js live implementation here: https://codepen.io/sanchopanza/pen/MWaZJJe

Iterate through all potential starting positions in Held-karp algorithm utilizing a bit-mask

I am interested in implementing the held-karp algorithm based on a C implementation found here: https://www.math.uwaterloo.ca/~bico/papers/comp_chapterDP.pdf in javascript. However, this implementation uses only a single starting position. I have tried numerous methods for moving through all starting positions (all nodes in the graph), however, because the implementation uses a bitmask as the set of visited nodes, starting positions 1 and 0 will not change through each call of the function solve because 0 & anynumber will always be 0.
function tsp_hk(dist){
let n = dist.length;
let opt = []; //array [endPoint][set] representing the optimum paths
//Initialize array values
for(let i = 0; i < n; i++){
opt[i] = [];
opt[i][1 << (i)] = dist[i][n-1];
}
function solve(set, end){
if(opt[end][set] === undefined){
let R = set & ~(1 << end);
let minv = 99999;
for (let i = 0; i < n; i++){
if(!(R & (1 << i))) continue;
let s = solve(R, i);
let v = s + dist[i][end];
if(v < minv) minv = v;
}
opt[end][set] = minv;
}
return opt[end][set];
}
let bestlen = 99999;
let N = (1 << (n-1))-1;
for(let t = 0; t < n-1; t++){
let s = solve(N,t);
let len = s + dist[t][n-1];
if(len < bestlen) bestlen = len;
}
return bestlen;
}
If the first node is node 0 and you want node 2 as your start node, then just interchange row 0 and row 2, and column 0 and column 2. Modify the adjacency matrix instead of modifying the algorithm.

Why is my code executing far more times than it's supposed to?

I'm currently working on a poker odds generator and it's pretty much done, except for one thing. The program runs far more often than it should. I know that this is coming from the compare() function, because when I add a variable Q to keep track of the number of times the main function playPoker() has run, it produces a huge number until I comment it out - at which point it returns the exact number I'd expect.
Can any of you point out where I'm going wrong with this. I can't see why one function should lead to Q being incremented so much more than it should be. Literally, the last time I ran it the number was (32,487 instead of 100). I present the code below (without the poker hand-checking functions because they're not really important). Why is playPoker() running so many times?!
var Q = 0;
function playPoker(tableSize) {
//Create the players, the deck and the card table which stores the 5 cards the players have in common
var players = createPlayers(tableSize);
var deck = createDeck();
var cardTable = new CardTable();
//Deal each player two cards
for (i = 0; i < 2; i++) {
for (j = 0; j < players.length; j++) {
deal(deck, players[j]);
}
}
//Put five cards down on the table
for (k = 0; k < 5; k++) {
deal(deck, cardTable);
}
//Check for various winning hands here for each player
for (m = 0; m < players.length; m++) {
//Merge the player's two cards with the five cards on the table
var subjectCards = (players[m].cards).concat(cardTable.cards);
//Make an array of the values of each of the seven cards, which will be used to determine 4 of a kind, 3 of a kind and pairs
var valuesInOrder = getValuesInOrder(subjectCards);
//Create a dummy array, so that valuesInOrder remains unchanged
var straightValues = valuesInOrder.slice();
//Remove any duplicate card, meaning that the array contains only unique values (i.e. 2, 4, 5, 7, K ... NOT 2, 2, 2, 8, K, K, A)
var straightValues = straightenUp(straightValues);
//Calculate how many pairs are in the hand
var numPairs = howManyPairs(valuesInOrder, straightValues, players[m]);
//Find out whether the 5 table cards contain three cards of the same suit. If not, then a flush is impossible.
var flushPotential = threeSameSuit(cardTable.cards);
//Find out which hand each player has (i.e. straight, 3OAK, pair)
checkPokerHand(subjectCards, straightValues, valuesInOrder, flushPotential, numPairs, players[m])
}
var rankedPlayers = compare(players);
//return players;
Q++;
return Q;
}
And here's the for-loop that sets it off.
for (z = 0; z < 100; z++;) {
playPoker(4);
}
And here's the compare() function:
function compare(players) {
var remPlayers = players.slice();
var rankings = [];
var potentialWinners = [];
//Collect all the players' rankings in an array
for (i = 0; i < remPlayers.length; i++) {
rankings.push(remPlayers[i].rank);
}
//Find the highest ranking
var highestRank = getHighestValue(rankings);
//Move any players with the highest ranking to an array for potential winners
for (j = 0; j < remPlayers.length; j++) {
if (remPlayers[j].rank == highestRank) {
potentialWinners.push(remPlayers[j]);
remPlayers.splice(j, 1);
j--;
}
}
//With all potential winners gone, mark all other players with an L for losing.
for (k = 0; k < remPlayers.length; k++) {
remPlayers[k].result = 'L'
}
var foundWinner = false;
if (potentialWinners.length < 2) {
potentialWinners[0].result = 'W';
foundWinner = true;
}
//Check there is more than one potential winner. If not, the only guy in the array has won.
if (!foundWinner) {
//Loop through all players first cards and find the highest value, then delete any who don't have that, marking them with 'L'.
//If there is no single remnant, do the same for second cards, then third, then fourth, etc.
for (p = 0; p < 5; p++) {
var subRankings = [];
for (q = 0; q < potentialWinners.length; q++) {
subRankings.push(potentialWinners[q].bestHand[p]);
}
var highestSubRanking = getHighestValue(subRankings);
//Mark 'L' and remove any player who does not meet the highest subranking
for (m = 0; m < potentialWinners.length; m++) {
if (potentialWinners[m].bestHand[p] < highestSubRanking) {
potentialWinners[m].result = 'L';
potentialWinners.splice(m, 1);
}
if (potentialWinners.length < 2) {
potentialWinners[0].result = 'W';
//Set this flag to true to break the loop because a winner has been found
foundWinner = true;
break;
}
}
//Break the loop if we have found a winner
if (foundWinner) {
break;
}
//If we still haven't found a winner by the end of the 5th loop, all remaining players draw
if (p == 4) {
for (z = 0; z < potentialWinners.length; z++) {
potentialWinners[z].result = 'D';
}
}
if (foundWinner) {
break;
}
}
}
return players;
}
Try using var declarations on your variables to manage their scope within their relevant functions?

Filling up a 2D array with random numbers in javascript

I'm really sorry if anything like this has been posted here before but I couldn't find anything, I'm kinda new to the site still!
So for a while now I've been learning a bit about game development through html5 and javascript and I stumbled upon making tileset maps, I now have a tileset and an 2D array that I want to put certain tiles in (the number varies between 6 and 10 in this case).
I figured it could be a cool function to make the map choose between a small set of similar tiles so I don't have to specifically number every tile in the array(just define the type)
The method I have currently is probably the best for being able to define types but I want something that looks a bit cleaner and/or information to why my "cleaner" version dosen't work.
var ground = [
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()],
[tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile(),tile()]];
function tile() {
var y = (Math.random() * 5 | 0) + 6;
return y;
}
This is the code I've been using so far, I have to edit every element of the code with the tile() function to get a random number in each one, what I wanted to have was something like this:
for (var i = 0 ; i < 15; i++) {
for (var j = 0; j < 9; j++) {
ground[[i],[j]] = (Math.random() * 5 | 0) + 6;
}
}
to fill the array without having to add the function to each spot.
I have a feeling that I'm missing a return function or something along those lines but honestly I have no idea.
You were thinking in the right direction but there are some errors in your code ;)
You have to initialize the array first before you can push elements into it.
And you were counting i++ twice
Javascript
var ground = []; // Initialize array
for (var i = 0 ; i < 15; i++) {
ground[i] = []; // Initialize inner array
for (var j = 0; j < 9; j++) { // i++ needs to be j++
ground[i][j] = (Math.random() * 5 | 0) + 6;
}
}
Maybe even better (reusable)
function createGround(width, height){
var result = [];
for (var i = 0 ; i < width; i++) {
result[i] = [];
for (var j = 0; j < height; j++) {
result[i][j] = (Math.random() * 5 | 0) + 6;
}
}
return result;
}
// Create a new ground with width = 15 & height = 9
var ground = createGround(15, 9);
Here's a quick example. I've created a function that will take in a width and height parameter and generate the size requested. Also I placed your tile function inside generate ground to keep it private, preventing other script from invoking it.
var ground = generateGround(10, 10); //Simple usage
function generateGround(height, width)
{
var ground = [];
for (var y = 0 ; y < height; y++)
{
ground[y] = [];
for (var x = 0; x < width; x++)
{
ground[y][x] = tile();
}
}
return ground;
function tile()
{
return (Math.random() * 5 | 0) + 6;
}
}
http://jsbin.com/sukoyute/1/edit
Try removing the comma from...
ground[[i],[j]] = (Math.random() * 5 | 0) + 6;
...in your 'clean' version. Also, your incrementing 'i' in both for loops:
for (var i = 0 ; i < 15; i++) {
for (var j = 0; j < 9; i++) {
Hopefully these changes make it work for you :)

Javascript generate random unique number every time

Ok so i need to create four randomly generated numbers between 1-10 and they cannot be the same. so my thought is to add each number to an array but how can I check to see if the number is in the array, and if it is, re-generate the number and if it isnt add the new number to the array?
so basically it will go,
1.create new number and add to array
2.create second new number, check to see if it exist already, if it doesn't exist, add to array. If it does exist, re-create new number, check again etc...
3.same as above and so on.
You want what is called a 'random grab bag'. Consider you have a 'bag' of numbers, each number is only represented once in this bag. You take the numbers out, at random, for as many as you need.
The problem with some of the other solutions presented here is that they randomly generate the number, and check to see if it was already used. This will take longer and longer to complete (theoretically up to an infinite amount of time) because you are waiting for the random() function to return a value you don't already have (and it doesn't have to do that, it could give you 1-9 forever, but never return 10).
There are a lot of ways to implement a grab-bag type solution, each with varying degrees of cost (though, if done correctly, won't ever be infinite).
The most basic solution to your problem would be the following:
var grabBag = [1,2,3,4,5,6,7,8,9,10];
// randomize order of elements with a sort function that randomly returns -1/0/1
grabBag.sort(function(xx,yy){ return Math.floor(Math.random() * 3) - 1; })
function getNextRandom(){
return grabBag.shift();
};
var originalLength = grabBag.length;
for(var i = 0; i < originalLength; i++){
console.log(getNextRandom());
}
This is of course destructive to the original grabBag array. And I'm not sure how 'truly random' that sort is, but for many applications it could be 'good enough'.
An slightly different approach would be to store all the unused elements in an array, randomly select an index, and then remove the element at that index. The cost here is how frequently you are creating/destroying arrays each time you remove an element.
Here are a couple versions using Matt's grabBag technique:
function getRandoms(numPicks) {
var nums = [1,2,3,4,5,6,7,8,9,10];
var selections = [];
// randomly pick one from the array
for (var i = 0; i < numPicks; i++) {
var index = Math.floor(Math.random() * nums.length);
selections.push(nums[index]);
nums.splice(index, 1);
}
return(selections);
}
You can see it work here: http://jsfiddle.net/jfriend00/b3MF3/.
And, here's a version that lets you pass in the range you want to cover:
function getRandoms(numPicks, low, high) {
var len = high - low + 1;
var nums = new Array(len);
var selections = [], i;
// initialize the array
for (i = 0; i < len; i++) {
nums[i] = i + low;
}
// randomly pick one from the array
for (var i = 0; i < numPicks; i++) {
var index = Math.floor(Math.random() * nums.length);
selections.push(nums[index]);
nums.splice(index, 1);
}
return(selections);
}
And a fiddle for that one: http://jsfiddle.net/jfriend00/UXnGB/
Use an array to see if the number has already been generated.
var randomArr = [], trackingArr = [],
targetCount = 4, currentCount = 0,
min = 1, max = 10,
rnd;
while (currentCount < targetCount) {
rnd = Math.floor(Math.random() * (max - min + 1)) + min;
if (!trackingArr[rnd]) {
trackingArr[rnd] = rnd;
randomArr[currentCount] = rnd;
currentCount += 1;
}
}
alert(randomArr); // Will contain four unique, random numbers between 1 and 10.
Working example: http://jsfiddle.net/FishBasketGordo/J4Ly7/
var a = [];
for (var i = 0; i < 5; i++) {
var r = Math.floor(Math.random()*10) + 1;
if(!(r in a))
a.push(r);
else
i--;
}
That'll do it for you. But be careful. If you make the number of random numbers generated greater than the may number (10) you'll hit an infinite loop.
I'm using a recursive function. The test function pick 6 unique value between 1 and 9.
//test(1, 9, 6);
function test(min, max, nbValue){
var result = recursValue(min, max, nbValue, []);
alert(result);
}
function recursValue(min, max, nbValue, result){
var randomNum = Math.random() * (max-min);
randomNum = Math.round(randomNum) + min;
if(!in_array(randomNum, result)){
result.push(randomNum);
nbValue--;
}
if(nbValue>0){
recursValue(min, max, nbValue, result);
}
return result;
}
function in_array(value, my_array){
for(var i=0;i< my_array.length; i++){
if(my_array[i] == value){
console.log(my_array+" val "+value);
return true;
}
}
return false;
}
Here is a recursive function what are you looking for.
"howMany" parameter is count of how many unique numbers you want to generate.
"randomize" parameter is biggest number that function can generate.
for example : rand(4,8) function returns an array that has 4 number in it, and the numbers are between 0 and 7 ( because as you know, Math.random() function generates numbers starting from zero to [given number - 1])
var array = [];
var isMatch= false;
function rand(howMany, randomize){
if( array.length < howMany){
var r = Math.floor( Math.random() * randomize );
for( var i = 0; i < howMany; i++ ){
if( array[i] !== r ){
isMatch= false;
continue;
} else {
isMatch= true;
break;
}
}
if( isMatch == false ){
array.push(r);
ran(howMany, randomize);
}
ran(howMany, randomize);
return array;
}
}
In your answer earlier, you do have a small bug. Instead of
var originalLength = grabBag.length;
for(var i = 0; i < originalLength .length; i++){
console.log(getNextRandom());
}
I believe you meant:
var originalLength = grabBag.length;
for(var i = 0; i < originalLength; i++){
console.log(getNextRandom());
}
Thanks.

Categories

Resources