{"version":3,"sources":["https://lively-kernel.org/lively4/lively4-seminars/EUD2020/project_2/src/stringBackprop.js"],"names":["_","Levenshtein","lsd","s","sp","slice","concat","split","map","k","i","ops","getSteps","reverse","actions","forEach","op","a","b","push","backprop_strings","fn","values","targetValue","probes","str","idx","value","id","sentinel","knobs","probe","currentValue","deltas","length","params","fromPairs","offset","lastReference","start","end","sub","ref","p","e","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(fn, values, targetValue){\n    // add ids to be in line with Carbide's data format\n    const probes = values.map((str, idx) => ({value: str, id: idx}));\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}"]}