Explanation for Bell's theorem modeling program
Today I will explain in detail the code from last time and show how can you change it to experiment with Bell's theorem. The code below needs only a text editor to make modifications and requires only a web browser to run. In other words, it is trivial to play with provided you understand the basics of HTML and Java Script. For elementary introductions to those topics see here and here.
In a standard HTML page we start in the body section with 3 entrees responsible to plot the graph in the end.
<link href="http://jsxgraph.uni-bayreuth.de/distrib/jsxgraph.css" rel="stylesheet" type="text/css"></link>
<script src="http://jsxgraph.uni-bayreuth.de/distrib/jsxgraphcore.js" type="text/javascript"></script>
<script src="http://jsxgraph.uni-bayreuth.de/distrib/GeonextReader.js" type="text/javascript"></script>
Then we have the following HTML table
<table border="4" style="width: 50%px;">
<tr><td style="width: 25%;">
<br />
Number of experiments: <input id="totAngMom" type="text" value="100" />
<br />
Number of directions: <input id="totTestDir" type="text" value="100" />
<br />
<input onclick="clearInput();" type="button" value="Clear Data" />
<input onclick="generateRandomData();" type="button" value="Generate Shared Random Data" />
<br />
<textarea cols="65" id="in_data" rows="7">
</textarea>
<br />
<input onclick="clearTestDir();" type="button" value="Clear data" />
<input onclick="generateTestDir();" type="button" value="Generate Random Alice Bob directions (x,y,z,x,y,z)" />
<textarea cols="65" id="in_test" rows="4">
</textarea>
<br />
<input onclick="clearOutput();" type="button" value="Clear Data" />
<input onclick="generateData();" type="button" value="Generate Data from shared randomness" />
<br />
Legend: Direction index|Data index|Measurement Alice|Measurement Bob
<textarea cols="65" id="out_measurements" rows="4">
</textarea>
<input onclick="clearBoard();" type="button" value="Clear Graph" />
<input onclick="plotData();" type="button" value="Plot Data" />
</td>
</tr>
<tr>
<td>
<div class="jxgbox" id="jxgboxCorrelations" style="height: 400px; width: 550px;">
</div>
</td></tr>
</table>
and we close the body:
</body>
The brain of the page is encapsulated by script tags:
<script type="text/javascript">
</script>
which can be placed anywhere inside the HTML page. Here are the functions which are declared inside the script tags:
//Dot is the scalar product of 2 3D vectors
function Dot(a, b)
{
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
};
This simply computes the dot product of two vectors in ordinary 3D Euclidean space. As a Java Script reminder, the arrays start at index zero and go to N-1. Also in Java Script comments start with two double slash // and lines end in semicolon ;
Next there is a little utility function which computes the magnitude of a vector:
//Norm computes the norm of a 3D vector
function GetNorm(vect)
{
return Math.sqrt(Dot(vect, vect));
};
This is followed by another utility function which normalizes a vector:
//Normalize generates a unit vector out of a vector
function Normalize(vect)
{
//declares the variable
var ret = new Array(3);
//computes the norm
var norm = GetNorm(vect);
//scales the vector
ret[0] = vect[0]/norm;
ret[1] = vect[1]/norm;
ret[2] = vect[2]/norm;
return ret;
};
To create an random oriented vector we use the function below which first randomly generates a point in a cube of side 2, eliminated the points outside a unit sphere, and then normalizes the vector:
//RandomDirection create a 3D unit vector of random direction
function RandomDirection()
{
//declares the variable
var ret = new Array(3);
//fills a 3D cube with coordinates from -1 to 1 on each direction
ret[0] = 2*(Math.random()-0.5);
ret[1] = 2*(Math.random()-0.5);
ret[2] = 2*(Math.random()-0.5);
//excludes the points outside of a unit sphere (tries again)
if(GetNorm(ret) > 1)
return RandomDirection();
return Normalize(ret);
};
The rest of the code is this:
var generateData = function()
{
clearBoard();
clearOutput();
//gets the data
var angMom = new Array();
var t = document.getElementById('in_data').value;
var data = t.split('\n');
for (var i=0;i<data.length;i++)
{
var vect = data[i].split(',');
if(vect.length == 3)
angMom[i] = data[i].split(',');
}
var newTotAngMom = angMom.length;
clearBoard();
var varianceLinear = 0;
var varianceCosine = 0;
var totTestDirs = document.getElementById('totTestDir').value;
var abDirections = new Array();
var AliceDirections = new Array();
var BobDirections = new Array();
var t2 = document.getElementById('in_test').value;
var data2 = t2.split('\n');
for (var k = 0; k < data2.length; k++)
{
var vect2 = data2[k].split(',');
if (vect2.length == 6)
{
abDirections[k] = data2[k].split(',');
AliceDirections[k] = data2[k].split(',');
BobDirections[k] = data2[k].split(',');
AliceDirections[k][0] = abDirections[k][0];
AliceDirections[k][1] = abDirections[k][1];
AliceDirections[k][2] = abDirections[k][2];
BobDirections[k][0] = abDirections[k][3];
BobDirections[k][1] = abDirections[k][4];
BobDirections[k][2] = abDirections[k][5];
}
}
var TempOutput = "";
//computes the output
for(var j=0; j<totTestDirs; j++)
{
var a = AliceDirections[j];
var b = BobDirections[j];
for(var i=0; i<newTotAngMom; i++)
{
TempOutput = TempOutput + (j+1);
TempOutput = TempOutput + ",";
TempOutput = TempOutput + (i+1);
TempOutput = TempOutput + ",";
TempOutput = TempOutput + (GenerateAliceOutputFromSharedRandomness(a, angMom[i]));
TempOutput = TempOutput + ",";
TempOutput = TempOutput + (GenerateBobOutputFromSharedRandomness(b, angMom[i]));
if(i != newTotAngMom-1 || j != totTestDirs-1)
TempOutput = TempOutput + " \n";
}
}
apendResults(TempOutput);
};
var plotData = function()
{
clearBoard();
boardCorrelations.suspendUpdate();
//gets the data
var angMom = new Array();
var t = document.getElementById('in_data').value;
var data = t.split('\n');
for (var i=0;i<data.length;i++)
{
var vect = data[i].split(',');
if(vect.length == 3)
angMom[i] = data[i].split(',');
}
var newTotAngMom = angMom.length;
var varianceLinear = 0;
var varianceCosine = 0;
var totTestDirs = document.getElementById('totTestDir').value;
//extract directions
var abDirections = new Array();
var AliceDirections = new Array();
var BobDirections = new Array();
var t2 = document.getElementById('in_test').value;
var data2 = t2.split('\n');
for (var k = 0; k < data2.length; k++)
{
var vect2 = data2[k].split(',');
if (vect2.length == 6)
{
abDirections[k] = data2[k].split(',');
AliceDirections[k] = data2[k].split(',');
BobDirections[k] = data2[k].split(',');
AliceDirections[k][0] = abDirections[k][0];
AliceDirections[k][1] = abDirections[k][1];
AliceDirections[k][2] = abDirections[k][2];
BobDirections[k][0] = abDirections[k][3];
BobDirections[k][1] = abDirections[k][4];
BobDirections[k][2] = abDirections[k][5];
}
}
var tempLine = new Array();
var Data_Val = document.getElementById('out_measurements').value;
var data_rows = Data_Val.split('\n');
var directionIndex = 1;
var beginNewDirection = false;
var a = new Array(3);
a[0] = AliceDirections[0][0];
a[1] = AliceDirections[0][1];
a[2] = AliceDirections[0][2];
var b = new Array(3);
b[0] = BobDirections[0][0];
b[1] = BobDirections[0][1];
b[2] = BobDirections[0][2];
var sum = 0;
for (var ii=0;ii<data_rows.length;ii++)
{
//parse the input line
var vect = data_rows[ii].split(',');
if(vect.length == 4)
tempLine = data_rows[ii].split(',');
//see if a new direction index is starting
if (directionIndex != tempLine[0])
{
beginNewDirection = true;
}
if(!beginNewDirection)
{
var sharedRandomnessIndex = tempLine[1];
var sharedRandomness = angMom[sharedRandomnessIndex];
var aliceOutcome = tempLine[2];
var bobOutcome = tempLine[3];
sum = sum + aliceOutcome*bobOutcome;
}
if (beginNewDirection)
{
//finish computation
var epsilon = sum/newTotAngMom;
var angle = Math.acos(Dot(a, b));
boardCorrelations.createElement('point', [angle,epsilon],{size:0.1,withLabel:false});
var diffLinear = epsilon - (-1+2/Math.PI*angle);
varianceLinear = varianceLinear + diffLinear*diffLinear;
var diffCosine = epsilon + Math.cos(angle);
varianceCosine = varianceCosine + diffCosine*diffCosine;
//reset and start a new cycle
directionIndex = tempLine[0];
a[0] = AliceDirections[directionIndex-1][0];
a[1] = AliceDirections[directionIndex-1][1];
a[2] = AliceDirections[directionIndex-1][2];
b[0] = BobDirections[directionIndex-1][0];
b[1] = BobDirections[directionIndex-1][1];
b[2] = BobDirections[directionIndex-1][2];
sum = 0;
var sharedRandomnessIndex = tempLine[1];
var sharedRandomness = angMom[sharedRandomnessIndex];
var aliceOutcome = tempLine[2];
var bobOutcome = tempLine[3];
sum = sum + aliceOutcome*bobOutcome;
beginNewDirection = false;
}
}
//finish computation for last element of the loop above
var epsilon = sum/newTotAngMom;
var angle = Math.acos(Dot(a, b));
boardCorrelations.createElement('point', [angle,epsilon],{size:0.1,withLabel:false});
var diffLinear = epsilon - (-1+2/Math.PI*angle);
varianceLinear = varianceLinear + diffLinear*diffLinear;
var diffCosine = epsilon + Math.cos(angle);
varianceCosine = varianceCosine + diffCosine*diffCosine;
//display total fit
boardCorrelations.createElement('text',[2.0, -0.7, 'Linear Fitting: ' + varianceLinear],{});
boardCorrelations.createElement('text',[2.0, -0.8, 'Cosine Fitting: ' + varianceCosine],{});
boardCorrelations.createElement('text',[2.0, -0.9, 'Cosine/Linear: ' + varianceCosine/varianceLinear],{});
boardCorrelations.unsuspendUpdate();
};
var clearBoard = function()
{
JXG.JSXGraph.freeBoard(boardCorrelations);
boardCorrelations = JXG.JSXGraph.initBoard('jxgboxCorrelations',{boundingbox:[-0.20, 1.25, 3.4, -1.25],axis:true,
showCopyright:false});
boardCorrelations.create('functiongraph', [function(t){ return -Math.cos(t); }, -Math.PI*10, Math.PI*10],{strokeColor:
"#66ff66", strokeWidth:2,highlightStrokeColor: "#66ff66", highlightStrokeWidth:2});
boardCorrelations.create('functiongraph', [function(t){ return -1+2/Math.PI*t; }, 0, Math.PI],{strokeColor: "#6666ff",
strokeWidth:2,highlightStrokeColor: "#6666ff", highlightStrokeWidth:2});
};
var clearInput = function()
{
document.getElementById('in_data').value = '';
};
var clearTestDir = function()
{
document.getElementById('in_test').value = '';
};
var clearOutput = function()
{
document.getElementById('out_measurements').value = '';
};
var generateTestDir = function()
{
clearBoard();
var totTestDir = document.getElementById('totTestDir').value;
var testDir = new Array(totTestDir);
var strData = "";
for(var i=0; i<totTestDir; i++)
{
//first is Alice, second is Bob
testDir[i] = RandomDirection();
strData = strData + testDir[i][0] + ", " + testDir[i][1] + ", " + testDir[i][2]+ ", " ;
testDir[i] = RandomDirection();
strData = strData + testDir[i][0] + ", " + testDir[i][1] + ", " + testDir[i][2] + '\n';
}
document.getElementById('in_test').value = strData;
};
var generateRandomData = function()
{
clearBoard();
var totAngMoms = document.getElementById('totAngMom').value;
var angMom = new Array(totAngMoms);
var strData = "";
for(var i=0; i<totAngMoms; i++)
{
angMom[i] = RandomDirection();
strData = strData + angMom[i][0] + ", " + angMom[i][1] + ", " + angMom[i][2] + '\n';
}
document.getElementById('in_data').value = strData;
};
var apendResults= function(newData)
{
var existingData = document.getElementById('out_measurements').value;
existingData = existingData + newData;
document.getElementById('out_measurements').value = existingData;
};
function GenerateAliceOutputFromSharedRandomness(direction, sharedRandomness3DVector) {
//replace this with your own function returning +1 or -1
if (Dot(direction, sharedRandomness3DVector) > 0)
return +1;
else
return -1;
};
function GenerateBobOutputFromSharedRandomness(direction, sharedRandomness3DVector) {
//replace this with your own function returning +1 or -1
if (Dot(direction, sharedRandomness3DVector) < 0)
return +1;
else
return -1;
};
var boardCorrelations = JXG.JSXGraph.initBoard('jxgboxCorrelations', {axis:true, boundingbox: [-0.25, 1.25, 3.4, -1.25], showCopyright:false});
clearBoard();
generateRandomData();
generateTestDir();
generateData();
plotData();
At loading time the page executes:
clearBoard();
generateRandomData();
generateTestDir();
generateData();
plotData();
The key to the whole exercise are the following two functions:
function GenerateAliceOutputFromSharedRandomness(direction, sharedRandomness3DVector) {
//replace this with your own function returning +1 or -1
if (Dot(direction, sharedRandomness3DVector) > 0)
return +1;
else
return -1;
};
function GenerateBobOutputFromSharedRandomness(direction, sharedRandomness3DVector) {
//replace this with your own function returning +1 or -1
if (Dot(direction, sharedRandomness3DVector) < 0)
return +1;
else
return -1;
};
To experiment with various hidden variable models all you have to do is replace the two functions above with your own concoction of hidden variable which uses the shared variable "sharedRandomness3DVector".
There are certain models for which if we return zero (which in the correlation computation is equivalent with discarding the data since the correlations are computed by this line in the code: sum = sum + aliceOutcome*bobOutcome;) a certain number of times as a function of the angle between direction and sharedRandomness3DVector, then one can obtain the quantum mechanics correlation curve. This is the famous detection loophole (or (un)fair sampling) for Bell's theorem.
If we talk about the detection loophole the paper to read is an old one by Philip Pearle: http://journals.aps.org/prd/abstract/10.1103/PhysRevD.2.1418 In there Pearle found an entire class of solutions able to generate the quantum correlations. The original paper is hard to double check (it took me more than a week and I was still not done completely), but Richard Gill did manage to extract a useful workable detection loophole model out of it: https://arxiv.org/pdf/1505.04431.pdf
Manipulating the generating functions above one can easily test various ideas about hidden variable models. For example an isotropic model of opposite spins generates -1/3 a.b correlations. It is not that hard to double check the math in this case: a simple integrals will do the trick. in particular this shows that the spins do not exist independent of measurement.
More manipulations using the detection loophole are even able to generate super-quantum Popescu-Rohrlich box correlations, but I let the user to experiment with this and discover how to do it for themselves. Happy computer modeling!
If we talk about the detection loophole the paper to read is an old one by Philip Pearle: http://journals.aps.org/prd/abstract/10.1103/PhysRevD.2.1418 In there Pearle found an entire class of solutions able to generate the quantum correlations. The original paper is hard to double check (it took me more than a week and I was still not done completely), but Richard Gill did manage to extract a useful workable detection loophole model out of it: https://arxiv.org/pdf/1505.04431.pdf
Manipulating the generating functions above one can easily test various ideas about hidden variable models. For example an isotropic model of opposite spins generates -1/3 a.b correlations. It is not that hard to double check the math in this case: a simple integrals will do the trick. in particular this shows that the spins do not exist independent of measurement.
More manipulations using the detection loophole are even able to generate super-quantum Popescu-Rohrlich box correlations, but I let the user to experiment with this and discover how to do it for themselves. Happy computer modeling!