Background
I am attempting to write an exercise for Khan Academy. Their code is all available here: https://github.com/Khan/khan-exercises. This is my first time really programming anything, and I am learning html and js as I go basically just by looking at example code.
As part of this exercise I need to draw a "random function", and find it's zeros. I have written a zero finding algorithm (Cutting an interval in half repeatedly to zoom in on the zero.). I know some variant of newton's method is probably faster, but I wanted to insure convergence. My "random function" takes a set of points values and interpolates those points with a polynomial spline. Each of these work independently: I can graph my "random function" and I can use my zero finding algorithm to, say, approximate the square root of 2 (zero of x^2 - 2 on interval (1,2)). When I try to find zeros of my "random function" I run into trouble: My browser goes into an infinite loop or something. I can't even see what the errors are in the developer tools.
So my questions are basically:
What mistake have I made which is using up so much computing power here?
How could the functions work independently but not together?
How can I fix my code?
Since I am working within the whole knhan academy framework, there is too much going into my program to post all the relevant code (it uses Raphael to handle images, has prewritten code to make the exercises all have the same style, etc). I can give you the html code I have written and the .js file of functions that I have written.
<!DOCTYPE html>
<html data-require="math graphie graphie-helpers steveMath8">
<head>
<title>Piecewise-defined function</title>
<script src="../khan-exercise.js"></script>
</head>
<body>
<div class="exercise">
<div class="vars">
<var id = "n">randRange(2,4)</var>
<var id = "abscissas">makeXList()</var>
<var id = "ordinates">makeYList(-8,8,abscissas.length)</var>
<var id = "points">makeCoordinates(abscissas,ordinates)</var>
<var id = "f">(function(x){return niceFunction(x,points)})</var>
<!-- <var id = "f">(function(x){return x*x-n})</var>-->
<var id = zeros>locateZeros(f,abscissas)</var>
</div>
<div class="problems">
<div id="problem-type-or-description">
<p class="problem">You are going to have to answer 5</p>
<p class="question">Answer 5</p>
<div class="graphie" id="grid">
graphInit({
range: 10,
scale: 20,
tickStep: 1,
axisArrows: "<->"
});
a =style({
stroke: "red",
strokeWidth: 2
}, function() {
plot( function( x ) { return niceFunction(x,points);
}, [ -10, 10 ] );
});;
a.plot();
</div>
<p class="solution">5</p>
</div>
</div>
<div class="hints">
<!-- Any hints to show to the student. -->
</div>
</div>
</body>
$.extend(KhanUtil, {
//takes num and returns +1 if num>0 or -1 if num<0
steveSign: function(num){
return num && num/Math.abs(num)
},
// Approximates a root of f on the interval (xmin,xmax) by successively halving the interval.
steveRoot: function(f,xmin,xmax){
var l = xmin
var r = xmax
var z = 0
for (i=0;i<10;i++){
z = (l + r)/2
if (KhanUtil.steveSign(f(l)) == KhanUtil.steveSign(f(z))){ l = z}
else{r = z}
}
return z
},
//takes a function and a list of abscissas, and returns an array of zeros - one zero between each pair of abscissas that are of
//opposite sign
locateZeros: function(f,abscissas){
var len = abscissas.length
var list = []
var z = 0
for(i=0;i<len-1;i++){
var x0 = abscissas[i]
var x1 = abscissas[i+1]
var y0 = f(x0)
var y1 = f(y0)
if (KhanUtil.steveSign(y0) !== KhanUtil.steveSign(y1)){
z = KhanUtil.steveRoot(f,x0,x1)
list.push(KhanUtil.steveSign(f(x0)))
}
}
return list
},
steveCubic: function(x){return -Math.pow(x,3)/2+3*x/2},
//niceFunction is a C^1 function which connects the points in "points". It is designed to be used
//in my "curveSketchingIntuition" exercise. Every point in the "points" will have 0 slope, except the first and last point.
niceFunction: function(x,points){
len = points.length
var x1 = points[0][0]
var x2 = points[1][0]
var y1 = points[0][1]
var y2 = points[1][1]
var k = (y1 - y2)/Math.pow(x1-x2,2)
if (x<x2){return k*Math.pow(x-x2,2)+y2}
for (i=1;i<len-2;i++){
var x1 = points[i][0]
var x2 = points[i+1][0]
var y1 = points[i][1]
var y2 = points[i+1][1]
xNew = (x-x1)*2/(x2-x1)-1
yNew = (KhanUtil.steveCubic(xNew)+1)*(y2-y1)/2+y1
if (x>=x1 && x<x2){return yNew}
}
var x1 = points[len-2][0]
var x2 = points[len-1][0]
var y1 = points[len-2][1]
var y2 = points[len-1][1]
var k = (y2 - y1)/Math.pow(x1-x2,2)
if (x>=x1){return k*Math.pow(x-x1,2)+y1}
},
makeXList: function(){
array = [-10]
i=0
while(array[i]<10){
x = array[i]+3*KhanUtil.randRange(1,3)
if (x<10){array.push(x)}
i=i+1
}
array.push(10)
return array
},
makeYList:function(min,max,n){
excluded = [0]
array = [KhanUtil.randRangeExclude(min,max,excluded)]
excluded.push(array[0])
array.push[KhanUtil.randRangeExclude(min,max,excluded)]
excluded = [0]
for (i=1;i<n;i++){
if (array[i-2]<array[i-1]){
array.push(KhanUtil.randRangeExclude(min,array[i-1]-1,excluded))
}
else{array.push(KhanUtil.randRangeExclude(array[i-1]+1,max,excluded))}
}
return array
},
makeCoordinates: function(array1,array2){
array = []
for (i=0;i<array1.length;i++){
array.push([array1[i],array2[i]])
}
return array
},
});
I think it has to do with your while loop here:
makeXList: function(){
array = [-10]
i=0
while(array[i]<10){
x = array[i]+3*KhanUtil.randRange(1,3)
if (x<10){array.push(x)}
i=i+1
}
array.push(10)
return array
},
Note that you are always incrementing i, but not always pushing a new value onto the array. If x is larger than 10, you will increment i, but there will be no element there, and that is probably what's causing your infinite loop.
I fixed my code. The problem seems to be that in both functions I had a for loop that looked like this
for(i=0;i=10;i++)
I changed that to
for(var i=0;i=10;i++)
apparently my program was treating i as a global variable, and so my two interacting functions were both incrementing the same i. Does this make sense? it seems like a pretty lousy feature to have in a programming language. Am I missing anything here?
Related
I'm trying to figure out what will be the JavaScript formula if I have a data in my database and this is i want to be the output:
if the data = 10 I want to be output that in a 100% in which I will be going to use in an div element height
if the data = 65 I want to be output that in a 0% in which I will be going to use in an div element height
and this is my code right now but I can't figure it out:
var datas = JSON.parse(data);
var ID, Bio, Non_Bio, Recy, Extra;
var div = 10;
ID = datas[0].ID;
Bio = datas[0].Bio;
Non_Bio = datas[0].Non_Bio;
Recy = datas[0].Recy;
Extra = datas[0]. Extra;
var obtained = Bio;
var obtained2 = Non_Bio;
var obtained3 = Recy;
var obt = obtained*100/div;
var obt2 = obtained2*100/div;
var obt3 = obtained3*100/div;
var water1 = $("#water1").height() + obt;
var water2 = $("#water2").height() + obt2;
var water3 = $("#water3").height() + obt3;
If the math can't be solved in one's head, doing it on paper can help, particularly when solving a pair of simultaneous equations using high school maths.
Assuming the ultrasound value to height relationship is linear you can write it as the equation of a line:
h = a * u + b ... 1)
where h is height, u is the ultrasound sensor reading, and a and b are constants.
Now take two calibration values of sensor readings taken for an empty and a full bin and call them c0 and c100 respectively.
From 1)
0 = a * c0 + b ... 2) using the c0 value , and
100 = a * c100 + b ... 3) using c100
Solving this pair of simultaneous equations proceeds along the lines of
b = 0 -a*c0 ... from 2)
b = 100 -a*c100 ... 4) from 3)
Hence
0 -a*c0 = 100 -a*c100
a*c100 - a*c0 = 100
a = 100/(c100-c0) ... 5)
and now substituting 4) back into 2) gives
b = 100 - a*c100 ... 6)
In this test example, the equations are converted into a factory function that returns an object with calibrate and height functions calibrate(c0, c100) and height( sensor). The height returned is rounded to the nearest quarter due to an overall lack of precision in the data.
function createBin() {
var a, b;
function calibrate( c0, c100) {
a = 100/(c100-c0);
b = 100 - a*c100;
}
function height( sensor) {
let h = a * sensor + b;
return Math.round( 4*h)/4;
}
return {calibrate, height};
}
const bin = createBin();
bin.calibrate (65, 10);
var readings = [67, 65, 37, 10, 5];
readings.forEach(
reading => console.log( "height( %s) = %s%", reading, bin.height(reading))
);
Note that when dealing with real world sensors, calibration data can vary between sensors and installations - hard coding equations that need to be calibrated against hardware variability is something to be avoided.
var datas=[{
ID :10,
Bio :7,
Non_Bio: 65,
Recy :75,
Extra :20
}]
var obt=[];
datas.map((data,index)=>{
console.log(data)
Object.values(data).map(item=>{
console.log(item)
if(item===10){
obt.push("100%");
}
else{
obt.push("0%");
}
})})
console.log("required output:");
console.log(obt);
Assumed: ID = datas[0].ID; since you are fetching from array 0th index and then its key.It mus be array of object (you have not given the proper inputs.) and the if logic can be changed accordingly as you mentioned if its 10 it must be 100%.
Logic: Just iterating each object of the array and then getting the object values (of each key i.e. id,bio etc..) and checking the value if divisible by 10 then pushing that data into empty array so you can use it further. You can also insert the output data into map.
I am trying to create a simple feed-forward neural network in JavaScript using a tutorial found here. I believe that I followed the tutorial correctly, as when I trained it with an input matrix of [[0,0,1],[0,1,1],[1,0,1],[1,1,1]] and a solution matrix of [[0],[1],[1],[0]] the network performed as expected. However, when I tried to train the network using the MNIST handwritten number database and passing in larger matrices, all of the elements in the output array approached zero. I suspect that this has to do with the dot product of the input array and the weights returning an array filled with large numbers, but my attempts to scale down these number have caused the outputs to approach 1. Would anybody be able to figure out what is going wrong? My neural network has only one hidden layer with 300 neurons. The code snippet below shows the methods for my neural network, because I believe that that is where I am going wrong, but if you want to see my entire messy, undocumented program, it can be found here. I am unfamiliar with the math library that I am using, which means that I made some of my own methods to go along with the math methods.
multMatrices(a, b) returns the product of matrices a and b.
math.multiply(a, b) returns the dot product of the two matrices.
math.add(a, b) and math.subtract(a, b) perform matrix addition and subtraction, and
transposeMatrix(a) returns the transpose of matrix a.
setAll(a, b) performs an operation on every element of matrix a, be it plugging the element into the sigmoid function (1 / (1 + a^-e)) in the case of "sigmoid" or the sigmoid derivative function (a * (1-a)) in the case of "sigmoidDerivitive", or setting it equal to a random value between 0 and 0.05 in the case of "randomlow".
I found that setting weights to a value between 0 and 1 kept the loss at 0.9, so I set them now using "randomlow".
function NeuralNetwork(x, y){
//Initializing the neural network
this.input = x;
this.y = y;
this.sizes = [this.input._size[1], 300, this.y._size[1]];
this.layers = this.sizes.length - 1;
this.lyrs = [this.input];
this.weights = [];
this.dweights = [];
for(var i = 0; i < this.layers; i ++){
this.weights.push(new math.matrix());
this.weights[i].resize([this.sizes[i], this.sizes[i + 1]]);
this.weights[i] = setAll(this.weights[i], "randomlow");
}
this.output = new math.matrix();
this.output.resize(this.y._size);
};
NeuralNetwork.prototype.set = function(x, y){
//I train the network by looping through values from the database and passing them into this function
this.input = x;
this.lyrs = [this.input];
this.y = y;
};
NeuralNetwork.prototype.feedforward = function(){
//Looping through the layers and multiplying them by their respective weights
for(var i = 0; i < this.weights.length; i ++){
this.lyrs[i + 1] = math.multiply(this.lyrs[i], this.weights[i]);
this.lyrs[i + 1] = setAll(this.lyrs[i + 1], "sigmoid");
}
this.output = this.lyrs[this.lyrs.length - 1];
};
NeuralNetwork.prototype.backpropogate = function(){
//Backpropogating the network. I don't fully understand this part
this.antis = [
function(a, b, c){
return(
math.multiply(transposeMatrix(a[0]), multMatrices(math.multiply(multMatrices(math.multiply(math.subtract(b.y, b.output), 2), setAll(b.output, "sigmoidDerivitive")), transposeMatrix(c)), setAll(a[1], "sigmoidDerivitive")))
);
},
function(a, b, c){
return(
math.multiply(transposeMatrix(a[0]), multMatrices(math.multiply(math.subtract(b.y, b.output), 2), setAll(b.output, "sigmoidDerivitive")))
);
}];
this.input = [];
this.weightInput = 0;
for(var i = this.weights.length - 1; i >= 0; --i){
this.input.unshift(this.lyrs[i]);
this.weightInput = (i === this.weights.length - 1 ? 0 : this.weights[i + 1]);
this.dweights[i] = this.antis[i](this.input, this, this.weightInput);
}
for(var i = 0; i < this.dweights.length; i ++){
this.weights[i] = math.add(this.weights[i], this.dweights[i]);
}
};
As always, I appreciate any time spent trying to solve my problem. If my code is unintelligible, don't bother with it. JavaScript probably isn't the best language for this purpose, but I didn't want to follow a tutorial with the same language.
EDIT: This is a potential duplicate of this post, which was answered. If anybody is facing this problem, they should see if the answer over there is of help. As of now I have not tested it with my program.
I'm trying to implement a simple Lotka-Volterra system in JavaScript, but get different result from what I see in academic papers and slides. This is my equations:
sim2.eval("dxdt(x, y) = (2 * x) - (x * y)");
sim2.eval("dydt(x, y) = (-0.25 * y) + (x * y)");
using coefficients a = 2, b = 1, c = 0.25 and d = 1. Yet, my result looks like this:
when I expected a stable oscillation as seen in these PDF slides:
Could it be the implementation of ndsolve that causes this? Or a machine error in JavaScript due to floating-point arithmetic?
Disregard, the error was simply using a too big evaluation step (dt = 0.1, must be 0.01 at least). The numerical method used is known for this problem.
For serious purposes use a higher order method, the minimum is fixed step classical Runge-Kutta. Then you can also use dt=0.1, it is stable for multiple periods, I tried tfinal=300 without problems. However you will see the step size in the graph as it is visibly piecewise linear. This is much reduced with half the step size, dt=0.05.
function odesolveRK4(f, x0, dt, tmax) {
var n = f.size()[0]; // Number of variables
var x = x0.clone(),xh=[]; // Current values of variables
var dxdt = [], k1=[], k2=[], k3=[], k4=[]; // Temporary variable to hold time-derivatives
var result = []; // Contains entire solution
var nsteps = math.divide(tmax, dt); // Number of time steps
dt2 = math.divide(dt,2);
dt6 = math.divide(dt,6);
for(var i=0; i<nsteps; i++) {
// compute the 4 stages if the classical order-4 Runge-Kutta method
k1 = f.map(function(fj) {return fj.apply(null, x.toArray()); } );
xh = math.add(x, math.multiply(k1, dt2));
k2 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k2, dt2));
k3 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k3, dt));
k4 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
x = math.add(x, math.multiply(math.add(math.add(k1,k4), math.multiply(math.add(k2,k3),2)), dt6))
if( 0==i%50) console.log("%3d %o %o",i,dt,x.toString());
result.push(x.clone());
}
return math.matrix(result);
}
math.import({odesolveRK4:odesolveRK4});
I am having a lot of trouble when directing the result of a variable to a span element. I don't know what¡s going on exactly, but I understand the mistake is likely to be in the way I'm connecting the variable with the span. However, I have recently started with javascript and I cannot target any mistake with accuracy.
The variable calculated is "a" and I want to take the numerical value to the span id="flec1".
I attach the relevant part of the code, which is part of a program that works with Flot charts.
<body>
<div style = "float: right; margin: 5px 10% 0 10%", id = "valor_flector">
Flector = <span id="flec1"> 0 </span> m x kN.<br>
</div>
function updateLegend() {
updateLegendTimeout = null;
var pos = latestPosition;
var axes = plot.getAxes();
if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
return;
var i, j, dataset = plot.getData();
var series1 = dataset[2];
//var series2 = dataset[3];
// find the nearest points, x-wise
for (i = 0; i < series1.data.length; ++i)
if (series1.data[i] > pos.x)
break;
// now interpolate
var a, p1 = series1.data[i - 1], p2 = series1.data[i];
if (p1 == null)
a = p2[1]/2;
else if (p2 == null)
a = p1[1]/2;
else
a = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
**//probable mistake**
var $a = $("#a.toFixed(2)");
$("#flec1").text($a);
}
</body>
You do not need selector, simply call numObj.toFixed(digits) on a, The toFixed() method formats a number using fixed-point notation, reference.
var $a = $(a.toFixed(2));
digits
The number of digits to appear after the decimal point; this may be a
value between 0 and 20, inclusive, and implementations may optionally
support a larger range of values. If this argument is omitted, it is
treated as 0.
Instead of these two lines
var $a = $("#a.toFixed(2)");
$("#flec1").text($a);
you can just write
$("#flec1").text(a.toFixed(2));
I have a list of data in javascript that looks like this:
[[152, 48, 'http://www.google.com'],
[198, 47, 'http://www.stackoverflow.com'],
[199, 45, 'http://www.apple.com']]
I am using flot to create a plot, and am trying to pass this third value to access a hyperlink from the point. As such, I am trying to lookup the third value of each list by using the first two as the lookup keys (i.e., [[x,y,hyperlink],[x2,y2,hyperlink2]], click on a point, then use the appropriate (x,y) to find the corresponding hyperlink)
Is there anyway to do this, or do I need to pass some dictionaries for x and y to javascript, then find the common variable from the two lists that were looked up? In python I know you could do a filter of list on the x value with itemgetter, then lookup a link corresponding to the y value. But I know almost nothing about js, so could a solution to ID-ing with (x,y) be given, or if not possible or advised, then a solution to taking two lists of (from x and y vals) and find a common value (if multiple, just one, anyone)?
You can make use of the Array .filter() method to figure out if any elements match the supplied x and y. (Note that IE didn't support .filter() until version 9, but MDN has a shim that you can include).
var data = [[152, 48, 'http://www.google.com'],
[198, 47, 'http://www.stackoverflow.com'],
[199, 45, 'http://www.apple.com']];
function getURLForPoint1(x, y) {
var p = data.filter(function(el) {
return (el[0] === x && el[1] === y);
});
if (p.length === 1) return p[0][2];
// else 0 or more than 1 elements mathced so return undefined
}
Alternatively you can create a dictionary object up front and then do future lookups from the dictionary:
var getURLForPoint2 = function() {
var dataDictionary = {}, i;
for (i = 0; i < data.length; i++)
dataDictionary[data[i][0]+" "+data[i][1]] = data[i][2];
return function(x, y) {
return dataDictionary[x + " " + y];
};
}();
Either way I've coded it so that if you ask for a point that isn't in the list you'll get undefined back, but obviously you can change that to return an empty string or throw an exception or whatever you like.
alert(getURLForPoint1(198, 47)); // 'http://www.stackoverflow.com'
alert(getURLForPoint2(198, 47)); // 'http://www.stackoverflow.com'
alert(getURLForPoint2(4, 5)); // undefined
Demo of both: http://jsfiddle.net/WdSAz/
Sorry, no shortcut way to do it in js except to just loop through the list and find the one that has the matching "x" and "y" value.
However, depending on how large your list is (and whether or not this list will be used for something else...) you could restructure the data to make it more efficient. For instance, do a structure like (assumed possible to have for instance x1, y1 vs x1, y2)
x1 > y1 > url
x1 > y2 > url
x2 > y1 > url
etc...
then you can immediately jump to the 2nd lvl "y" list by the "x" index, and the only looping would be how many "y" values share the same "x" value
edit:
actually if you wanna take it a step further with reorganizing the data, you could do something like this:
<script type='text/javascript'>
var list = {
1 : {
1 : 'foobar 1,1',
2 : 'foobar 1,2'
},
2 : {
1 : 'foobar 2,1',
2 : 'foobar 2,2'
},
};
</script>
which will allow you to do for instance this
var x = 1;
var y = 2;
alert(list[x][y]);
somthing like this maybe
var findX = 198
var findY = 47
var targetUrl
for (var i=0; i<arr.length; i++)
{
for (var j=0; j<arr[i].length; j++)
{
if (findX = j[0] && findY == j[1])
{
targetUrl = j[2]
}
}
}