blob: 9898b5dc9d382e7000eb54b7e67af9816fa28e55 [file] [log] [blame]
// |jit-test| slow;
// XXXbz I would dearly like to wrap it up into a function to avoid polluting
// the global scope, but the function ends up heavyweight, and then we lose on
// the jit.
load(libdir + "mandelbrot-results.js");
//function testMandelbrotAll() {
// Configuration options that affect which codepaths we follow.
var doImageData = true;
var avoidSparseArray = true;
// Control of iteration numbers and sizing. We'll do
// scaler * colorNames.length iterations or so before deciding that we
// don't escape.
const scaler = 5;
const numRows = 600;
const numCols = 600;
const colorNames = [
"black",
"green",
"blue",
"red",
"purple",
"orange",
"cyan",
"yellow",
"magenta",
"brown",
"pink",
"chartreuse",
"darkorange",
"crimson",
"gray",
"deeppink",
"firebrick",
"lavender",
"lawngreen",
"lightsalmon",
"lime",
"goldenrod"
];
const threshold = (colorNames.length - 1) * scaler;
// Now set up our colors
var colors = [];
// 3-part for loop (iterators buggy, we will add a separate test for them)
for (var colorNameIdx = 0; colorNameIdx < colorNames.length; ++colorNameIdx) {
//for (var colorNameIdx in colorNames) {
colorNameIdx = parseInt(colorNameIdx);
colors.push([colorNameIdx, colorNameIdx, colorNameIdx, 0]);
}
// Storage for our point data
var points;
var scratch = {};
var scratchZ = {};
function complexMult(a, b) {
var newr = a.r * b.r - a.i * b.i;
var newi = a.r * b.i + a.i * b.r;
scratch.r = newr;
scratch.i = newi;
return scratch;
}
function complexAdd(a, b) {
scratch.r = a.r + b.r;
scratch.i = a.i + b.i;
return scratch;
}
function abs(a) {
return Math.sqrt(a.r * a.r + a.i * a.i);
}
function escapeAbsDiff(normZ, absC) {
var absZ = Math.sqrt(normZ);
return normZ > absZ + absC;
}
function escapeNorm2(normZ) {
return normZ > 4;
}
function fuzzyColors(i) {
return Math.floor(i / scaler) + 1;
}
function moddedColors(i) {
return (i % (colorNames.length - 1)) + 1;
}
function computeEscapeSpeedObjects(real, imag) {
var c = { r: real, i: imag }
scratchZ.r = scratchZ.i = 0;
var absC = abs(c);
for (var i = 0; i < threshold; ++i) {
scratchZ = complexAdd(c, complexMult(scratchZ, scratchZ));
if (escape(scratchZ.r * scratchZ.r + scratchZ.i * scratchZ.i,
absC)) {
return colorMap(i);
}
}
return 0;
}
function computeEscapeSpeedOneObject(real, imag) {
// fold in the fact that we start with 0
var r = real;
var i = imag;
var absC = abs({r: real, i: imag});
for (var j = 0; j < threshold; ++j) {
var r2 = r * r;
var i2 = i * i;
if (escape(r2 + i2, absC)) {
return colorMap(j);
}
i = 2 * r * i + imag;
r = r2 - i2 + real;
}
return 0;
}
function computeEscapeSpeedDoubles(real, imag) {
// fold in the fact that we start with 0
var r = real;
var i = imag;
var absC = Math.sqrt(real * real + imag * imag);
for (var j = 0; j < threshold; ++j) {
var r2 = r * r;
var i2 = i * i;
if (escape(r2 + i2, absC)) {
return colorMap(j);
}
i = 2 * r * i + imag;
r = r2 - i2 + real;
}
return 0;
}
var computeEscapeSpeed = computeEscapeSpeedDoubles;
var escape = escapeNorm2;
var colorMap = fuzzyColors;
function addPointOrig(pointArray, n, i, j) {
if (!points[n]) {
points[n] = [];
points[n].push([i, j, 1, 1]);
} else {
var point = points[n][points[n].length-1];
if (point[0] == i && point[1] == j - point[3]) {
++point[3];
} else {
points[n].push([i, j, 1, 1]);
}
}
}
function addPointImagedata(pointArray, n, col, row) {
var slotIdx = ((row * numCols) + col) * 4;
pointArray[slotIdx] = colors[n][0];
pointArray[slotIdx+1] = colors[n][1];
pointArray[slotIdx+2] = colors[n][2];
pointArray[slotIdx+3] = colors[n][3];
}
function createMandelSet() {
var realRange = { min: -2.1, max: 1 };
var imagRange = { min: -1.5, max: 1.5 };
var addPoint;
if (doImageData) {
addPoint = addPointImagedata;
points = new Array(4*numCols*numRows);
if (avoidSparseArray) {
for (var idx = 0; idx < 4*numCols*numRows; ++idx) {
points[idx] = 0;
}
}
} else {
addPoint = addPointOrig;
points = [];
}
var realStep = (realRange.max - realRange.min)/numCols;
var imagStep = (imagRange.min - imagRange.max)/numRows;
for (var i = 0, curReal = realRange.min;
i < numCols;
++i, curReal += realStep) {
for (var j = 0, curImag = imagRange.max;
j < numRows;
++j, curImag += imagStep) {
var n = computeEscapeSpeed(curReal, curImag);
addPoint(points, n, i, j)
}
}
var result;
if (doImageData) {
if (colorMap == fuzzyColors) {
result = mandelbrotImageDataFuzzyResult;
} else {
result = mandelbrotImageDataModdedResult;
}
} else {
result = mandelbrotNoImageDataResult;
}
return points.toSource() == result;
}
const escapeTests = [ escapeAbsDiff ];
const colorMaps = [ fuzzyColors, moddedColors ];
const escapeComputations = [ computeEscapeSpeedObjects,
computeEscapeSpeedOneObject,
computeEscapeSpeedDoubles ];
// Test all possible escape-speed generation codepaths, using the
// imageData + sparse array avoidance storage.
doImageData = true;
avoidSparseArray = true;
for (var escapeIdx in escapeTests) {
escape = escapeTests[escapeIdx];
for (var colorMapIdx in colorMaps) {
colorMap = colorMaps[colorMapIdx];
for (var escapeComputationIdx in escapeComputations) {
computeEscapeSpeed = escapeComputations[escapeComputationIdx];
assertEq(createMandelSet(), true);
}
}
}
// Test all possible storage strategies. Note that we already tested
// doImageData == true with avoidSparseArray == true.
escape = escapeAbsDiff;
colorMap = fuzzyColors; // This part doesn't really matter too much here
computeEscapeSpeed = computeEscapeSpeedDoubles;
doImageData = true;
avoidSparseArray = false;
assertEq(createMandelSet(), true);
escape = escapeNorm2;
doImageData = false; // avoidSparseArray doesn't matter here
assertEq(createMandelSet(), true);
//}
//testMandelbrotAll();