There are two python files included in the supplementary material.

- common.py
    This implements the KMP DFA construction algorithm and weighted automata

- incremental.py
    This implements each of the algorithms and the code to run each experiment

To view an example run of the algorithms, use the following command:

        python3 incremental.py

You should see an output similar to the following:

        Probabilities

        Algorithm 1
        Infix probability of [('b', 'w')]:  0.9952635205197583
        Infix probability of [('b', 'w'), ('a', 'i')]:  0.8080924357367227
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k')]:  0.07744971810039285
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y')]:  0.0016744577864099587
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k')]:  3.342896474362169e-05
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q')]:  6.695273481656231e-07
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's')]:  1.332807500615156e-08
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e')]:  2.672175242894002e-10
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e'), ('b', 'd')]:  5.330348247225264e-12
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e'), ('b', 'd'), ('a', 's')]:  1.060923144233668e-13



        Improved Algorithm
        Infix probability of [('b', 'w')]:  0.9952635205197583
        Infix probability of [('b', 'w'), ('a', 'i')]:  0.8080924357367227
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k')]:  0.07744971810039285
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y')]:  0.0016744577864099587
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k')]:  3.342896474362169e-05
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q')]:  6.695273481656231e-07
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's')]:  1.332807500615156e-08
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e')]:  2.672175242894002e-10
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e'), ('b', 'd')]:  5.330348247225264e-12
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e'), ('b', 'd'), ('a', 's')]:  1.060923144233668e-13



        Online version
        Infix probability of [('b', 'w')]:  0.9952635205197582
        Infix probability of [('b', 'w'), ('a', 'i')]:  0.8080924357367225
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k')]:  0.07744971810039276
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y')]:  0.0016744577864099565
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k')]:  3.3428964743621645e-05
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q')]:  6.695273481656223e-07
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's')]:  1.3328075006151541e-08
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e')]:  2.672175242893999e-10
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e'), ('b', 'd')]:  5.330348247225258e-12
        Infix probability of [('b', 'w'), ('a', 'i'), ('b', 'k'), ('a', 'y'), ('b', 'k'), ('a', 'q'), ('a', 's'), ('a', 'e'), ('b', 'd'), ('a', 's')]:  1.0609231442336668e-13

        ==================================

        Timings

        Algorithm 1
        [0.09060931205749512, 0.09001040458679199, 0.07242321968078613, 0.07245993614196777, 0.07245516777038574, 0.0725564956665039, 0.07254409790039062, 0.07378077507019043, 0.07281374931335449, 0.0728297233581543]
        Total: 0.762483 seconds

        Improved version
        [0.010109186172485352, 0.008900165557861328, 0.008295059204101562, 0.0074732303619384766, 0.007059335708618164, 0.005979776382446289, 0.008183479309082031, 0.011106491088867188, 0.007547140121459961, 0.003070354461669922]
        Total: 0.077724 seconds

        Online version
        [0.01144099235534668, 0.009813070297241211, 0.01056981086730957, 0.011487483978271484, 0.01223301887512207, 0.01819300651550293, 0.014515399932861328, 0.01447916030883789, 0.020655155181884766, 0.008821964263916016]
        Total: 0.132209 seconds


To generate your own test cases, one can construct a different random PFA (using random_PFA) and strings. For example,

        >>> P = random_PFA(1000, ['a', 'b', 'c']) # a PFA with 1000 states and an alphabet of size 3
        >>> w = ['a', 'b', 'a', 'c'] # an input word over the same alphabet
        >>> res = fast_incremental_test(P, w, trials=10) # run the improved algorithm with 10 trials per iteration
        >>> print(res) # display the median time it took for each iteration