{"version":3,"sources":["https://lively-kernel.org/lively4/lively4-seminars/EUD2020/project_2/stringBackprop.js"],"names":["_","Levenshtein","lsd","s","sp","slice","concat","split","map","k","i","ops","getSteps","reverse","actions","forEach","op","a","b","push","backprop_strings","values","probes","targetValue","fn","sentinel","knobs","probe","id","currentValue","deltas","length","params","fromPairs","value","offset","lastReference","start","end","sub","ref","p","e","str","Math","max","viableProbes","filter","alt","clone","join","output","Object","difference","changed","index","pval","insertLeft","alt0","alt1","out0","out1","indexOf","j"],"mappings":"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","file":"stringBackprop.js","sourcesContent":["// code taken from Carbide and adjusted to fit our data format\n\nimport _ from 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.js';\nimport Levenshtein from './levenshtein.js';\n\n// string backprop\n\n// this tracks the provenance of characters in string\n// literals of the program allowing you to type in\n// the output to adjust the input\n\n\n// converts two strings into a sequence of substitution operations\nfunction lsd(s, sp){\n    // having to special case these is silly\n    if(s === sp) return [];\n    if(sp === '') return lsd(s, s.slice(-1)).concat([[0, 1, '']]);\n    if(s === '') return sp.split('').map((k, i) => [i, i, k]);\n\n    var ops = new Levenshtein(s, sp).getSteps();\n    ops.reverse()\n    var actions = []\n    ops.forEach(([op, a, b]) => {\n        if(op == 'delete'){\n            actions.push([b, b + 1, ''])\n        }else if(op == 'substitute'){\n            actions.push([b-1, b, sp[b-1]])\n        }else if(op == 'insert'){\n            actions.push([b-1, b-1, sp[b-1]])\n        }\n    })\n    return actions;\n}\n\n\nexport default function backprop_strings(values, probes, targetValue, fn){\n    if(typeof targetValue != 'string') return null;\n\n    var sentinel = '~'; // must be 1 character, preferably not unicode\n    var knobs = probes.map(probe => [probe, probe.id])\n    var currentValue = fn(values)\n    var deltas = lsd(currentValue, targetValue);\n\n    if(knobs.length == 0){\n        // return \"No free string parameters!\"\n        return null\n    }\n\n    var params = _.fromPairs(knobs.map(([probe, id]) => [id, probe.value]));\n\n    var offset = 0;\n    var lastReference;\n\n    for(var a = 0; a < deltas.length; a++){\n        var [start, end, sub] = deltas[a];\n\n        var ref = fn(probes.map(p => p.value))\n        if(lastReference){\n\n            // calculate offset due to prior transformations\n            lsd(lastReference, ref).forEach(([s, e, b]) => {\n                if(s < start + offset){\n                    // start += (s - e) + b.length;\n                    // console.log('adding', s - e + b.length)\n                    offset += s - e + b.length\n                }\n            })\n\n            start += offset\n            end += offset\n        }\n        lastReference = ref;\n\n        function slice(str){\n            return str.slice(Math.max(0, start - 1), end + 1)\n        }\n\n        var viableProbes = knobs.filter(([k, i]) => {\n            var alt = _.clone(params)\n            \n            alt[i] = alt[i].split('').map(k => sentinel).join('')\n            var output = fn(Object.values(alt))\n            if(typeof output != 'string') return false;\n            if(output.length != ref.length) return false;\n            if(slice(output) != slice(ref)) return true;\n            return false\n        })\n        viableProbes = viableProbes.concat(_.difference(knobs, viableProbes)\n            .filter(([k, i]) => params[i] === '')\n            .filter(([k, i]) => {\n                var alt = _.clone(params)\n                alt[i] = sentinel\n                var output = fn(Object.values(alt))\n                if(slice(output) != slice(ref)) return true;\n                return false\n            }))\n\n        var changed;\n        for(var b = 0; b < viableProbes.length && !changed; b++){\n            // console.log('found relevant probe', relevantProbe)\n            var [probe, index] = viableProbes[b];\n            // TODO: figuring out which index of the string is relevant\n            // can probably be done more efficiently with a binary search\n\n            var pval = params[index];\n            var insertLeft = false;\n            // check reversal\n            var alt0 = _.clone(params), alt1 = _.clone(params)\n            // if(pval.length > 0){\n            //     alt0[index] = pval.slice(0, -1) + sentinel\n            //     alt1[index] = pval + sentinel    \n            // }\n            alt0[index] = sentinel + 'X';\n            alt1[index] = 'X' + sentinel;\n\n            var out0 = fn(Object.values(alt0)),\n                out1 = fn(Object.values(alt1));\n            insertLeft = out0.indexOf(sentinel) > out1.indexOf(sentinel)\n            // console.log('checked reversal', insertLeft, out0, out1)\n\n        \n\n            // loop backwards to prioritize appending to stuff rather than prepending\n            for(var i = pval.length - 1; i >= 0; i--){\n                var alt = _.clone(params)\n                alt[index] = alt[index].split('').map((k, j) => j == i ? sentinel : k).join('')\n                var output = fn(Object.values(alt))\n                if(output.length != ref.length){\n                \n                    // return 'substitution length invariant violation'\n                    continue\n                }\n                \n                \n                if(start === end){ // insertion\n                    if(!insertLeft){\n                        if(i === pval.length - 1 && output[start-1] != ref[start-1]){\n                            // console.log('insert@end', pval, i, output[start], ref[start])    \n                            params[index] = pval + sub\n                            changed = true;\n                            break\n                        }else if(output[start] != ref[start]){\n                            // console.log('insert@after', pval, i, output[start], ref[start]) \n                            params[index] = pval.slice(0, i) + sub + pval.slice(i)\n                            changed = true;\n                            \n                            break\n                        }\n                    }else{\n                        if(i === 0 && output[start-1] != ref[start-1]){\n                            // console.log('insert@start', pval, i, output[start], ref[start])    \n                            params[index] = sub + pval\n                            changed = true;\n                            break\n                        }else if(output[start] != ref[start]){\n                            // console.log('insert@before', pval, i, output[start], ref[start]) \n                            params[index] = pval.slice(0, i + 1) + sub + pval.slice(i + 1)\n                            changed = true;\n                            break\n                        }\n                    }\n                }else if(output.slice(start, end) != ref.slice(start, end)){\n\n                    // console.log('subs', output.slice(start, end))\n                    params[index] = pval.slice(0, i) + sub + pval.slice(i + end - start)\n                    changed = true;\n                    \n                    break;\n                }\n                // console.log(output)\n            }\n            if(pval.length === 0 && start === end){\n                changed = true;\n                params[index] = sub\n            }\n        }\n        if(!changed){\n            // return \"Could not find viable string parameter to modify\"\n            return null\n        }\n    }\n\n    return Object.values(params);\n}"]}