learn's notebooks

  • math js parse constants - /learn/math-js-parse-constants
    Last edited 5 years ago
    const TOKENTYPE = { NULL: 0, DELIMITER: 1, NUMBER: 2, SYMBOL: 3, UNKNOWN: 4 } const DELIMITERS = { ',': true, '(': true, ')': true, '[': true, ']': true, '{': true, '}': true, '"': true, '\'': true, ';': true, '+': true, '-': true, '*': true, '.*': true, '/': true, './': true, '%': true, '^': true, '.^': true, '~': true, '!': true, '&': true, '|': true, '^|': true, '=': true, ':': true, '?': true, '==': true, '!=': true, '<': true, '>': true, '<=': true, '>=': true, '<<': true, '>>': true, '>>>': true } // map with all named delimiters const NAMED_DELIMITERS = { 'mod': true, 'to': true, 'in': true, 'and': true, 'xor': true, 'or': true, 'not': true } const CONSTANTS = { 'true': true, 'false': false, 'null': null, 'undefined': undefined } const NUMERIC_CONSTANTS = [ 'NaN', 'Infinity' ] module.exports = {TOKENTYPE, DELIMITERS, NAMED_DELIMITERS, CONSTANTS, NUMERIC_CONSTANTS}
  • math js parser dependencies - /learn/math-js-parser-dependencies
    Last edited 5 years ago
    const numeric = require("numeric") function deepMap (array, callback, skipZeros) { if (array && (typeof array.map === 'function')) { return array.map(function (x) { return deepMap(x, callback, skipZeros) }) } else { return callback(array) } } function isAccessorNode (x) { return (x && x.isAccessorNode === true && x.constructor.prototype.isNode === true) || false } function isConstantNode (x) { return (x && x.isConstantNode === true && x.constructor.prototype.isNode === true) || false } function isFunctionNode (x) { return (x && x.isFunctionNode === true && x.constructor.prototype.isNode === true) || false } function isOperatorNode (x) { return (x && x.isOperatorNode === true && x.constructor.prototype.isNode === true) || false } function isSymbolNode (x) { return (x && x.isSymbolNode === true && x.constructor.prototype.isNode === true) || false } module.exports = {deepMap, numeric, isAccessorNode,isConstantNode, isFunctionNode, isOperatorNode, isSymbolNode}
  • bezier - /learn/morpharc
    Last edited 5 years ago
    var _DEG2RAD = Math.PI / 180, _RAD2DEG = 180 / Math.PI, _svgPathExp = /[achlmqstvz]|(-?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig, _numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig, _selectorExp = /(^[#\.]|[a-y][a-z])/gi, _commands = /[achlmqstvz]/ig, _scientific = /[\+\-]?\d*\.?\d+e[\+\-]?\d+/ig, // translates an arc into a normalized array of cubic beziers excluding the starting x/y. The circle the arc follows will be centered at 0,0 and have a radius of 1 (hence normalized). Each bezier covers no more than 90 degrees; the arc will be divided evenly into a maximum of four curves. _normalizedArcToBeziers = function(angleStart, angleExtent) { var segments = Math.ceil(Math.abs(angleExtent) / 90), l = 0, a = [], angleIncrement, controlLength, angle, dx, dy, i; angleStart *= _DEG2RAD; angleExtent *= _DEG2RAD; angleIncrement = angleExtent / segments; controlLength = 4 / 3 * Math.sin(angleIncrement / 2) / (1 + Math.cos(angleIncrement / 2)); for (i = 0; i < segments; i++) { angle = angleStart + i * angleIncrement; dx = Math.cos(angle); dy = Math.sin(angle); a[l++] = dx - controlLength * dy; a[l++] = dy + controlLength * dx; angle += angleIncrement; dx = Math.cos(angle); dy = Math.sin(angle); a[l++] = dx + controlLength * dy; a[l++] = dy - controlLength * dx; a[l++] = dx; a[l++] = dy; } return a; }, // translates SVG arc data into an array of cubic beziers _arcToBeziers = function(lastX, lastY, rx, ry, angle, largeArcFlag, sweepFlag, x, y) { if (lastX === x && lastY === y) { return; } rx = Math.abs(rx); ry = Math.abs(ry); var angleRad = (angle % 360) * _DEG2RAD, cosAngle = Math.cos(angleRad), sinAngle = Math.sin(angleRad), dx2 = (lastX - x) / 2, dy2 = (lastY - y) / 2, x1 = (cosAngle * dx2 + sinAngle * dy2), y1 = (-sinAngle * dx2 + cosAngle * dy2), rx_sq = rx * rx, ry_sq = ry * ry, x1_sq = x1 * x1, y1_sq = y1 * y1, radiiCheck = x1_sq / rx_sq + y1_sq / ry_sq; if (radiiCheck > 1) { rx = Math.sqrt(radiiCheck) * rx; ry = Math.sqrt(radiiCheck) * ry; rx_sq = rx * rx; ry_sq = ry * ry; } var sign = (largeArcFlag === sweepFlag) ? -1 : 1, sq = ((rx_sq * ry_sq) - (rx_sq * y1_sq) - (ry_sq * x1_sq)) / ((rx_sq * y1_sq) + (ry_sq * x1_sq)); if (sq < 0) { sq = 0; } var coef = (sign * Math.sqrt(sq)), cx1 = coef * ((rx * y1) / ry), cy1 = coef * -((ry * x1) / rx), sx2 = (lastX + x) / 2, sy2 = (lastY + y) / 2, cx = sx2 + (cosAngle * cx1 - sinAngle * cy1), cy = sy2 + (sinAngle * cx1 + cosAngle * cy1), ux = (x1 - cx1) / rx, uy = (y1 - cy1) / ry, vx = (-x1 - cx1) / rx, vy = (-y1 - cy1) / ry, n = Math.sqrt((ux * ux) + (uy * uy)), p = ux; sign = (uy < 0) ? -1 : 1; var angleStart = (sign * Math.acos(p / n)) * _RAD2DEG; n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); p = ux * vx + uy * vy; sign = (ux * vy - uy * vx < 0) ? -1 : 1; var angleExtent = (sign * Math.acos(p / n)) * _RAD2DEG; if (!sweepFlag && angleExtent > 0) { angleExtent -= 360; } else if (sweepFlag && angleExtent < 0) { angleExtent += 360; } angleExtent %= 360; angleStart %= 360; var bezierPoints = _normalizedArcToBeziers(angleStart, angleExtent), a = cosAngle * rx, b = sinAngle * rx, c = sinAngle * -ry, d = cosAngle * ry, l = bezierPoints.length - 2, i, px, py; //translate all the bezier points according to the matrix... for (i = 0; i < l; i += 2) { px = bezierPoints[i]; py = bezierPoints[i+1]; bezierPoints[i] = px * a + py * c + cx; bezierPoints[i+1] = px * b + py * d + cy; } bezierPoints[bezierPoints.length-2] = x; //always set the end to exactly where it's supposed to be bezierPoints[bezierPoints.length-1] = y; return bezierPoints; }, //Spits back an array of cubic Bezier segments that use absolute coordinates. Each segment starts with a "moveTo" command (x coordinate, then y) and then 2 control points (x, y, x, y), then anchor. The goal is to minimize memory and maximize speed. _pathDataToBezier = function(d) { var a = (d + "").match(_svgPathExp) || [], //some authoring programs spit out very small numbers in scientific notation like "1e-5", so make sure we round that down to 0 first path = [], relativeX = 0, relativeY = 0, elements = a.length, l = 2, points = 0, i, j, x, y, command, isRelative, segment, startX, startY, difX, difY, beziers, prevCommand; if (!d || !isNaN(a[0]) || isNaN(a[1])) { _log("ERROR: malformed path data: " + d); return path; } for (i = 0; i < elements; i++) { prevCommand = command; if (isNaN(a[i])) { command = a[i].toUpperCase(); isRelative = (command !== a[i]); //lower case means relative } else { //commands like "C" can be strung together without any new command characters between. i--; } x = +a[i+1]; y = +a[i+2]; if (isRelative) { x += relativeX; y += relativeY; } if (i === 0) { startX = x; startY = y; } // "M" (move) if (command === "M") { if (segment && segment.length < 8) { //if the path data was funky and just had a M with no actual drawing anywhere, skip it. path.length-=1; l = 0; } relativeX = startX = x; relativeY = startY = y; segment = [x, y]; points += l; l = 2; path.push(segment); i += 2; command = "L"; //an "M" with more than 2 values gets interpreted as "lineTo" commands ("L"). // "C" (cubic bezier) } else if (command === "C") { if (!segment) { segment = [0, 0]; } segment[l++] = x; segment[l++] = y; if (!isRelative) { relativeX = relativeY = 0; } segment[l++] = relativeX + a[i + 3] * 1; //note: "*1" is just a fast/short way to cast the value as a Number. WAAAY faster in Chrome, slightly slower in Firefox. segment[l++] = relativeY + a[i + 4] * 1; segment[l++] = relativeX = relativeX + a[i + 5] * 1; segment[l++] = relativeY = relativeY + a[i + 6] * 1; //if (y === segment[l-1] && y === segment[l-3] && x === segment[l-2] && x === segment[l-4]) { //if all the values are the same, eliminate the waste. // segment.length = l = l-6; //} i += 6; // "S" (continuation of cubic bezier) } else if (command === "S") { if (prevCommand === "C" || prevCommand === "S") { difX = relativeX - segment[l - 4]; difY = relativeY - segment[l - 3]; segment[l++] = relativeX + difX; segment[l++] = relativeY + difY; } else { segment[l++] = relativeX; segment[l++] = relativeY; } segment[l++] = x; segment[l++] = y; if (!isRelative) { relativeX = relativeY = 0; } segment[l++] = relativeX = relativeX + a[i + 3] * 1; segment[l++] = relativeY = relativeY + a[i + 4] * 1; //if (y === segment[l-1] && y === segment[l-3] && x === segment[l-2] && x === segment[l-4]) { //if all the values are the same, eliminate the waste. // segment.length = l = l-6; //} i += 4; // "Q" (quadratic bezier) } else if (command === "Q") { difX = x - relativeX; difY = y - relativeY; segment[l++] = relativeX + difX * 2 / 3; segment[l++] = relativeY + difY * 2 / 3; if (!isRelative) { relativeX = relativeY = 0; } relativeX = relativeX + a[i + 3] * 1; relativeY = relativeY + a[i + 4] * 1; difX = x - relativeX; difY = y - relativeY; segment[l++] = relativeX + difX * 2 / 3; segment[l++] = relativeY + difY * 2 / 3; segment[l++] = relativeX; segment[l++] = relativeY; i += 4; // "T" (continuation of quadratic bezier) } else if (command === "T") { difX = relativeX - segment[l-4]; difY = relativeY - segment[l-3]; segment[l++] = relativeX + difX; segment[l++] = relativeY + difY; difX = (relativeX + difX * 1.5) - x; difY = (relativeY + difY * 1.5) - y; segment[l++] = x + difX * 2 / 3; segment[l++] = y + difY * 2 / 3; segment[l++] = relativeX = x; segment[l++] = relativeY = y; i += 2; // "H" (horizontal line) } else if (command === "H") { y = relativeY; //if (x !== relativeX) { segment[l++] = relativeX + (x - relativeX) / 3; segment[l++] = relativeY + (y - relativeY) / 3; segment[l++] = relativeX + (x - relativeX) * 2 / 3; segment[l++] = relativeY + (y - relativeY) * 2 / 3; segment[l++] = relativeX = x; segment[l++] = y; //} i += 1; // "V" (horizontal line) } else if (command === "V") { y = x; //adjust values because the first (and only one) isn't x in this case, it's y. x = relativeX; if (isRelative) { y += relativeY - relativeX; } //if (y !== relativeY) { segment[l++] = x; segment[l++] = relativeY + (y - relativeY) / 3; segment[l++] = x; segment[l++] = relativeY + (y - relativeY) * 2 / 3; segment[l++] = x; segment[l++] = relativeY = y; //} i += 1; // "L" (line) or "Z" (close) } else if (command === "L" || command === "Z") { if (command === "Z") { x = startX; y = startY; segment.closed = true; } if (command === "L" || Math.abs(relativeX - x) > 0.5 || Math.abs(relativeY - y) > 0.5) { segment[l++] = relativeX + (x - relativeX) / 3; segment[l++] = relativeY + (y - relativeY) / 3; segment[l++] = relativeX + (x - relativeX) * 2 / 3; segment[l++] = relativeY + (y - relativeY) * 2 / 3; segment[l++] = x; segment[l++] = y; if (command === "L") { i += 2; } } relativeX = x; relativeY = y; // "A" (arc) } else if (command === "A") { beziers = _arcToBeziers(relativeX, relativeY, a[i+1]*1, a[i+2]*1, a[i+3]*1, a[i+4]*1, a[i+5]*1, (isRelative ? relativeX : 0) + a[i+6]*1, (isRelative ? relativeY : 0) + a[i+7]*1); if (beziers) { for (j = 0; j < beziers.length; j++) { segment[l++] = beziers[j]; } } relativeX = segment[l-2]; relativeY = segment[l-1]; i += 7; } else { _log("Error: malformed path data: " + d); } } path.totalPoints = points + l; return path; }; _pathDataToBezier('M 100 300 c 150 50 200 300 200 900')
  • nand2chip - /learn/nand2chip
    Last edited 5 years ago
    const nand= (a, b) => a==1 && b==1 ? 0 : 1 const not = a => nand(a, a) const and = (a, b) => not(nand(a, b)) const or = (a, b) => not(and(not(a), not(b))) const xor = (a, b) => or(and(not(a), b), and(a, not(b))) const mux = (a, b, sel) => or(and(a, not(sel)), and(b, sel)) const dmux = (a, sel) => [and(a, not(sel)), and(a, sel)] const not16 = a => a.map((_) => not(_)) const and16 = (a, b) => _.zipWith(a, b, (x, y) => (and(x, y))) const or16 = (a, b) => _.zipWith(a, b, (x, y) => (or(x, y))) const mux16 = (a, b, sel) => _.zipWith(a, b, (x, y) => (mux(x, y, sel))) const mux4way16 = (a, b, c, d, sel) => mux16( mux16(a, b, sel[0]), mux16(c, d, sel[0]), sel[1]) const mux8Way16 = (a, b, c, d, e, f, g, h, sel) => mux16( mux16(a, b, sel[0]), mux16(c, d, sel[0]), sel[1]) const dmux4way = (input, sel) => { const sel0 = dmux(input, sel[0]); const ac = dmux(sel0[0], sel[1]); const bd = dmux(sel0[0], sel[1]) return { a: ac[0], b: bd[0], c: ac[1], d: bd[1] } } const dmux8way = (input, sel) => { const aecgbfdh = dmux(input, sel[0]); const aecg = dmux(aecgbfdh[0], sel[1]); const bfdh = dmux(aecgbfdh[1], sel[1]); const ae = dmux(aecg[0], sel[2]); const cg = dmux(aecg[1], sel[2]); const bf = dmux(bfdh[0], sel[2]); const dh = dmux(bfdh[1], sel[2]); return { a: ae[0], b: bf[0], c: cg[0], d: dh[0], e: ae[1], f: bf[1], g: cg[1], h: dh[1] } }
  • gate - /learn/gate
    Last edited 5 years ago
    function and(a, b) { switch (a) { case 0: switch (b) { case 0: return 0; case 1: return 0; } case 1: switch (b) { case 0: return 0; case 1: return 1; } } } function or(a, b) { switch (a) { case 0: switch (b) { case 0: return 0; case 1: return 1; } case 1: switch (b) { case 0: return 1; case 1: return 1; } } } function not(a) { switch (a) { case 0: return 1; case 1: return 0; } } // nand nor xor function nand(a, b) { return not(and(a, b)) } function nor(a, b) { return not(or(a, b)) } function xor(a, b) { return and(or(a, b), nand(a,b)) }
  • adder - /learn/adder
    Last edited 5 years ago
    const gate = require('@runkit/learn/gate/3.0.0') const halfAdder = (a, b) => ({sum: gate.xor(a, b), carry: gate.and(a,b)}) const fullAdder = (a, b, carry) => { const result1 = halfAdder(a, b) const result2 = halfAdder((carry || 0), result1.sum) return {sum: result2.sum, carry: gate.or(result1.carry, result2.carry)} } const multiBitsSum = (inputA, inputB, carryIn) => { let output = [] let carry = carryIn || 0 for (var i = 0; i < inputA.length; i++) { let result = fullAdder(inputA[i], inputB[i], carry) output[i] = result.sum carry = result.carry } return {output: output, carry: carry} } const multiBitsSumByComps = (inputAHigh, inputBHigh, inputALow, inputBLow, carryIn) => { let output = [] let carry = carryIn || 0 const lowResult = multiBitsSum(inputALow, inputBLow, carry) const highResult = multiBitsSum(inputAHigh, inputBHigh, lowResult.carry) return {output: highResult.output.concat(highResult.output), carry: highResult.carry} }
  • Adding Machine - /learn/adding-machine
    Last edited 5 years ago
    // It seems like this is the journey for me to understanding the foundations of mathematics. // and or not const and = (a, b) => { switch (a) { case 0: switch (b) { case 0: return 0; case 1: return 0; } case 1: switch (b) { case 0: return 0; case 1: return 1; } } } const or = (a, b) => { switch (a) { case 0: switch (b) { case 0: return 0; case 1: return 1; } case 1: switch (b) { case 0: return 1; case 1: return 1; } } } const not = (a) => { switch (a) { case 0: return 1; case 1: return 0; } }