// |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();