<commit_before>/**
 * Inferring the structure of a program from traces.
 *
 * @author <NAME> <<EMAIL>>
 */

import Data = require('./Data')
import Util = require('./util/Util')
import Recorder = require('./Recorder')
import Compile = require('./Compile')

var print = Util.print
var log = Util.log
var line = Util.line

export class Proposal {
    worksFor: number[]
    constructor(public regex: string, public loopStart: number, public loopLength: number, public numIterations: number) {
    }
    equals(o) {
        if (!(o instanceof Proposal)) {
            return false
        }
        return this.regex === o.regex
    }
    toString(): string {
        return this.regex
    }
}

/**
 * Tries to infer a loop structure of the given traces.  Returns a set of proposals, ordered by
 * confidence in them (best proposal first).
 */
export function infer(traces: Data.Trace[], minIterations: number = 3, minBodyLength: number = 1, maxBodyLength: number = 100000) {
    var candidates: Proposal[] = []
    for (var k = 0; k < traces.length; k++) {
        var trace = traces[k]
        var tlen = trace.getLength()
        for (var start = 0; start < tlen-1; start++) {
            // not enough space for minIterations
            if (start + minIterations >= tlen) break;
            length: for (var len = minBodyLength; len < maxBodyLength; len++) {
                // not enough space for minIterations
                if (start + len*minIterations >= tlen) break;
                // get a candidate body
                var body = trace.getSubSkeleton(start, len)
                var iterations = 0
                // check that we have at least minIterations many times our candidate body
                while (iterations < minIterations-1) {
                    iterations++
                    if (body !== trace.getSubSkeleton(start + iterations*len, len)) {
                        continue length
                    }
                }
                // output all possible iteration counts
                while (true) {
                    iterations++
                    var regex = trace.getSubSkeleton(0, start) + "(" + body + ")*" + trace.getSubSkeleton(start+iterations*len)
                    candidates.push(new Proposal(regex, start, len, iterations))
                    if (body !== trace.getSubSkeleton(start + iterations*len, len)) {
                        break
                    }
                }
            }
        }
    }
    candidates = Util.dedup2(candidates)
    var howMany = (a) => {
        if (a.worksFor !== undefined) {
            return a.worksFor.length
        }
        var i = 0
        a.worksFor = []
        var res = traces.filter((t) => {
            var res = new RegExp("^" + a.regex + "$").test(t.getSkeleton())
            if (res) {
                a.worksFor.push(i)<commit_msg>fix bug in loop inference<commit_after>/**
 * Inferring the structure of a program from traces.
 *
 * @author <NAME> <<EMAIL>>
 */

import Data = require('./Data')
import Util = require('./util/Util')
import Recorder = require('./Recorder')
import Compile = require('./Compile')

var print = Util.print
var log = Util.log
var line = Util.line

export class Proposal {
    worksFor: number[]
    private numIterations: number = -1
    constructor(public regex: string, public loopStart: number, public loopLength: number) {
    }
    equals(o) {
        if (!(o instanceof Proposal)) {
            return false
        }
        return this.regex === o.regex
    }
    toString(): string {
        return this.regex
    }
    getNumIterations(trace: Data.Trace) {
        if (this.numIterations < 0) {
            // this caching is ignoring the argument.. if it changes, the result will be wrong
            var myRe = new RegExp("^([^(]*)(\(.+\)\*)([^(]*)$", "g")
            var res = myRe.exec(this.regex)
            var pre = res[1].split(";").length - 1
            var post = res[1].split(";").length - 1
            var body = res[1].split(";").length - 1
            var total = trace.events.length
            this.numIterations = (total - pre - post) / body
        }
        return this.numIterations
    }
}

/**
 * Tries to infer a loop structure of the given traces.  Returns a set of proposals, ordered by
 * confidence in them (best proposal first).
 */
export function infer(traces: Data.Trace[], minIterations: number = 3, minBodyLength: number = 1, maxBodyLength: number = 100000) {
    var candidates: Proposal[] = []
    for (var k = 0; k < traces.length; k++) {
        var trace = traces[k]
        var tlen = trace.getLength()
        for (var start = 0; start < tlen-1; start++) {
            // not enough space for minIterations
            if (start + minIterations >= tlen) break;
            length: for (var len = minBodyLength; len < maxBodyLength; len++) {
                // not enough space for minIterations
                if (start + len*minIterations >= tlen) break;
                // get a candidate body
                var body = trace.getSubSkeleton(start, len)
                var iterations = 0
                // check that we have at least minIterations many times our candidate body
                while (iterations < minIterations-1) {
                    iterations++
                    if (body !== trace.getSubSkeleton(start + iterations*len, len)) {
                        continue length
                    }
                }
                // output all possible iteration counts
                while (true) {
                    iterations++
                    var regex = trace.getSubSkeleton(0, start) + "(" + body + ")*" + trace.getSubSkeleton(start+iterations*len)
                    candidates.push(new Proposal(regex, start, len))
                    if (body !== trace.getSubSkeleton(start + iterations*len, len)) {
                        break
                    }
                }
            }
        }
    }
    candidates = Util.dedup2(candidates)
    var howMany = (a) => {
        if (a.worksFor !== undefined) {
            return a.worksFor.length
        }
        var i = 0
        a.worksFor = []
        var res = traces.filter((t) => {
            var res = new RegExp("^" + a.regex + "$").test(t.getSkeleton())
            if (res) {
                a.worksFor.push(i)
{'fraction_non_alphanumeric': 0.1178147268408551, 'fraction_numerical': 0.006334125098970704, 'mean_word_length': 1.7212408444635934, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7280446', 'n_tokens_mistral': 1778, 'n_tokens_neox': 1682, 'n_words': 524}