Project P131

Event log

An account replayed from its events beside a stored balance column one write path forgets: a check that compares the column with itself, a replay that finds where they part, and how many orders of the events end where the log does.

2 modules · 2 recorded sessionstext-menu UI in the terminalupdated 2026-10-17

Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.

About

An account kept two ways: the balance replayed from its events, and a stored balance column that each write path updates.

  • main.eml - the menu, the log with both balances, the two reconciliations, every order of the events, and adding or removing one
  • events.eml - an event's effect, a replay, the ledger with the stored column, every order, and which pairs of events commute

How each part works:

  • An event is a deposit, a withdrawal (refused if more than the balance), a fee of a percentage of the balance (rounded down), or an adjustment of either sign.
  • As in the corpus case denormalized-total-drifts, the adjustment's write path forgets the stored column. The column is always the replayed balance less the adjustments: after adjust +20 it is 20 short, and a later withdrawal of 120 takes it to -7, while the replayed balance is 13.
  • The check the system has compares the column with a copy kept by the same write paths, so it compares a number with itself and never finds a difference. Replaying the events finds it, and where they part.
  • As in the corpus case state-from-events-vs-stored, replaying is right only in the order the events happened: the 720 orders of the 6 events end at 40 different balances, and only 3 of the 15 pairs give the same balance in either order from every balance from 0 to 300.

What is checked: menu choices 1 to 6; an event as deposit, withdraw, fee or adjust and a whole number up to 9999 (a fee from 1 to 100%, only an adjustment negative), at most 6 events. An empty answer cancels.

Sessions: sessions/basic.in gives: - the log, the reconciliations and every order; - the last event removed, and the same again; - fee 5% added at the end, and every order again.

sessions/bad-input.in gives: - menu choices 0 and x; - one event removed; then events: a cancel, pay 10, deposit alone, x, 0 and 10000, fee 101 and withdraw -5, then adjust -15, and a seventh; - the log emptied one event at a time, with every order, the log and the reconciliations on the way and at the end.

Built on the verified corpus cases denormalized-total-drifts (a stored total kept by every write path, and a reconciliation that compares it with itself) and state-from-events-vs-stored (replaying events is right only for some orders).

Recorded sessions

What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.

bad-input

interpreter: byte-equal
== Event log ==
An account kept two ways: the balance replayed from its events, and a stored balance column that each write path updates.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 0
Pick a number from 1 to 6.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> x
Pick a number from 1 to 6.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 5 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> 
Cancelled.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> pay 10
Type deposit, withdraw, fee or adjust, then a number.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> deposit
Type a whole number up to 9999 (a fee from 1 to 100).

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> deposit x
Type a whole number up to 9999 (a fee from 1 to 100).

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> deposit 0
Type a whole number up to 9999 (a fee from 1 to 100).

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> deposit 10000
Type a whole number up to 9999 (a fee from 1 to 100).

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> fee 101
Type a whole number up to 9999 (a fee from 1 to 100).

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> withdraw -5
Type a whole number up to 9999 (a fee from 1 to 100).

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> adjust -15
Added: adjust -15.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
6 events is the most.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 5 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 4 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 3 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 2 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 1 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 3
Two events or more are needed.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 0 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 1
The log is empty.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 2
The log is empty.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 3
Two events or more are needed.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
The log is empty.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 6
Bye.
What was typed (34 lines)
0
x
5
4

4
pay 10
4
deposit
4
deposit x
4
deposit 0
4
deposit 10000
4
fee 101
4
withdraw -5
4
adjust -15
4
5
5
5
5
5
3
5
1
2
3
5
6

basic

interpreter: byte-equal
== Event log ==
An account kept two ways: the balance replayed from its events, and a stored balance column that each write path updates.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 1
  #  event                              replayed  stored
  1  deposit 100                             100     100
  2  withdraw 30                              70      70
  3  fee 10% = 7                              63      63
  4  deposit 50                              113     113
  5  adjust +20                              133     113
  6  withdraw 120                             13      -7

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 2
The check the system has: the stored column, -7, against the copy the same write paths keep, -7: no difference.
Replaying the events: 13, and stored says -7: off by -20.
They part at event 5, adjust +20: that write path never touches the stored column.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 3
Every order of these 6 events, replayed: 720 orders, 40 different final balances; 8 end as the log does.
Of the 15 pairs of events, 3 give the same balance in either order from every starting balance from 0 to 300.
Replaying gives the truth only in the order the events happened: the log's order is part of what it records.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 5
Removed the last event; 5 left.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 1
  #  event                              replayed  stored
  1  deposit 100                             100     100
  2  withdraw 30                              70      70
  3  fee 10% = 7                              63      63
  4  deposit 50                              113     113
  5  adjust +20                              133     113

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 2
The check the system has: the stored column, 113, against the copy the same write paths keep, 113: no difference.
Replaying the events: 133, and stored says 113: off by -20.
They part at event 5, adjust +20: that write path never touches the stored column.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 3
Every order of these 5 events, replayed: 120 orders, 19 different final balances; 6 end as the log does.
Of the 10 pairs of events, 3 give the same balance in either order from every starting balance from 0 to 300.
Replaying gives the truth only in the order the events happened: the log's order is part of what it records.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 4
An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.
event> fee 5
Added: fee 5%.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 3
Every order of these 6 events, replayed: 720 orders, 47 different final balances; 17 end as the log does.
Of the 15 pairs of events, 3 give the same balance in either order from every starting balance from 0 to 300.
Replaying gives the truth only in the order the events happened: the log's order is part of what it records.

1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit
choice> 6
Bye.
What was typed (11 lines)
1
2
3
5
1
2
3
4
fee 5
3
6

Modules

The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.

main.eml(entry)

eml
# P131 event log: the log with both balances, two reconciliations, every
# order of the events, and adding or removing events.
import events

def plain(s):
    0 => i
    len(s) => j
    while i < j and s[i] == " ":
        i + 1 => i
    while j > i and s[j - 1] == " ":
        j - 1 => j
    return s[i:j]

def pad(s, n):
    s => out
    while len(out) < n:
        out + " " => out
    return out

def lpad(s, n):
    s => out
    while len(out) < n:
        " " + out => out
    return out

def show(log):
    if len(log) == 0:
        "The log is empty." ^0
        return
    events.ledger(log) => rows
    "  #  event                              replayed  stored" ^0
    for k in [0:len(log) - 1]:
        rows[k] => r
        ("  " + str(k + 1) + "  " + pad(r[0], 33) + lpad(str(r[1]), 10) + lpad(str(r[2]), 8)) ^0

def reconcile(log):
    if len(log) == 0:
        "The log is empty." ^0
        return
    events.ledger(log) => rows
    rows[len(rows) - 1] => last
    if last[2] == last[3]:
        ("The check the system has: the stored column, " + str(last[2]) + ", against the copy the same write paths keep, " + str(last[3]) + ": no difference.") ^0
    else:
        ("The check the system has finds a difference: " + str(last[2]) + " against " + str(last[3]) + ".") ^0
    if last[1] == last[2]:
        ("Replaying the events: " + str(last[1]) + ", the same as stored.") ^0
    else:
        ("Replaying the events: " + str(last[1]) + ", and stored says " + str(last[2]) + ": off by " + events.signed(last[2] - last[1]) + ".") ^0
        0 => first
        for k in [0:len(rows) - 1]:
            if first == 0 and rows[k][1] != rows[k][2]:
                k + 1 => first
        ("They part at event " + str(first) + ", " + rows[first - 1][0] + ": that write path never touches the stored column.") ^0

def orders(log):
    if len(log) < 2:
        "Two events or more are needed." ^0
        return
    events.orders(log) => o
    events.pairs(log, 300) => p
    ("Every order of these " + str(len(log)) + " events, replayed: " + str(o[0]) + " orders, " + str(o[1]) + " different final balances; " + str(o[2]) + " end as the log does.") ^0
    ("Of the " + str(p[0]) + " pairs of events, " + str(p[1]) + " give the same balance in either order from every starting balance from 0 to 300.") ^0
    if o[1] > 1:
        "Replaying gives the truth only in the order the events happened: the log's order is part of what it records." ^0

def add(log):
    if len(log) >= 6:
        "6 events is the most." ^0
        return log
    "An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25." ^0
    plain(input("event> ")) => t
    if t == "":
        "Cancelled." ^0
        return log
    "" => kind
    "" => num
    False => space
    for c in t:
        if c == " " and not space:
            True => space
        elif space:
            num + c => num
        else:
            kind + c => kind
    if kind != "deposit" and kind != "withdraw" and kind != "fee" and kind != "adjust":
        "Type deposit, withdraw, fee or adjust, then a number." ^0
        return log
    plain(num) => num
    1 => sign
    if len(num) > 0 and num[0] == "-" and kind == "adjust":
        0 - 1 => sign
        num[1:len(num)] => num
    if len(num) == 0 or len(num) > 4:
        "Type a whole number up to 9999 (a fee from 1 to 100)." ^0
        return log
    for c in num:
        if c < "0" or c > "9":
            "Type a whole number up to 9999 (a fee from 1 to 100)." ^0
            return log
    int(num) => n
    if n == 0 or (kind == "fee" and n > 100):
        "Type a whole number up to 9999 (a fee from 1 to 100)." ^0
        return log
    log + [[kind, sign * n]] => out
    if kind == "fee":
        ("Added: fee " + str(n) + "%.") ^0
    elif kind == "adjust":
        ("Added: adjust " + events.signed(sign * n) + ".") ^0
    else:
        ("Added: " + kind + " " + str(n) + ".") ^0
    return out

events.default_log() => log

"== Event log ==" ^0
"An account kept two ways: the balance replayed from its events, and a stored balance column that each write path updates." ^0
True => running
while running:
    "" ^0
    "1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit" ^0
    plain(input("choice> ")) => choice
    if choice == "1":
        show(log)
    elif choice == "2":
        reconcile(log)
    elif choice == "3":
        orders(log)
    elif choice == "4":
        add(log) => log
    elif choice == "5":
        if len(log) == 0:
            "The log is empty." ^0
        else:
            log[0:len(log) - 1] => log
            ("Removed the last event; " + str(len(log)) + " left.") ^0
    elif choice == "6":
        False => running
    else:
        "Pick a number from 1 to 6." ^0
"Bye." ^0
Python projection (main.py)
import events

def plain(s):
    i = 0
    j = len(s)
    while i < j and s[i] == " ":
        i = i + 1
    while j > i and s[j - 1] == " ":
        j = j - 1
    return s[i:j]

def pad(s, n):
    out = s
    while len(out) < n:
        out = out + " "
    return out

def lpad(s, n):
    out = s
    while len(out) < n:
        out = " " + out
    return out

def show(log):
    if len(log) == 0:
        print("The log is empty.")
        return
    rows = events.ledger(log)
    print("  #  event                              replayed  stored")
    for k in range(0, len(log)):
        r = rows[k]
        print("  " + str(k + 1) + "  " + pad(r[0], 33) + lpad(str(r[1]), 10) + lpad(str(r[2]), 8))

def reconcile(log):
    if len(log) == 0:
        print("The log is empty.")
        return
    rows = events.ledger(log)
    last = rows[len(rows) - 1]
    if last[2] == last[3]:
        print("The check the system has: the stored column, " + str(last[2]) + ", against the copy the same write paths keep, " + str(last[3]) + ": no difference.")
    else:
        print("The check the system has finds a difference: " + str(last[2]) + " against " + str(last[3]) + ".")
    if last[1] == last[2]:
        print("Replaying the events: " + str(last[1]) + ", the same as stored.")
    else:
        print("Replaying the events: " + str(last[1]) + ", and stored says " + str(last[2]) + ": off by " + events.signed(last[2] - last[1]) + ".")
        first = 0
        for k in range(0, len(rows)):
            if first == 0 and rows[k][1] != rows[k][2]:
                first = k + 1
        print("They part at event " + str(first) + ", " + rows[first - 1][0] + ": that write path never touches the stored column.")

def orders(log):
    if len(log) < 2:
        print("Two events or more are needed.")
        return
    o = events.orders(log)
    p = events.pairs(log, 300)
    print("Every order of these " + str(len(log)) + " events, replayed: " + str(o[0]) + " orders, " + str(o[1]) + " different final balances; " + str(o[2]) + " end as the log does.")
    print("Of the " + str(p[0]) + " pairs of events, " + str(p[1]) + " give the same balance in either order from every starting balance from 0 to 300.")
    if o[1] > 1:
        print("Replaying gives the truth only in the order the events happened: the log's order is part of what it records.")

def add(log):
    if len(log) >= 6:
        print("6 events is the most.")
        return log
    print("An event: deposit n, withdraw n, fee p (percent), or adjust n (either sign), such as withdraw 25.")
    t = plain(input("event> "))
    if t == "":
        print("Cancelled.")
        return log
    kind = ""
    num = ""
    space = False
    for c in t:
        if c == " " and not space:
            space = True
        elif space:
            num = num + c
        else:
            kind = kind + c
    if kind != "deposit" and kind != "withdraw" and kind != "fee" and kind != "adjust":
        print("Type deposit, withdraw, fee or adjust, then a number.")
        return log
    num = plain(num)
    sign = 1
    if len(num) > 0 and num[0] == "-" and kind == "adjust":
        sign = 0 - 1
        num = num[1:len(num)]
    if len(num) == 0 or len(num) > 4:
        print("Type a whole number up to 9999 (a fee from 1 to 100).")
        return log
    for c in num:
        if c < "0" or c > "9":
            print("Type a whole number up to 9999 (a fee from 1 to 100).")
            return log
    n = int(num)
    if n == 0 or kind == "fee" and n > 100:
        print("Type a whole number up to 9999 (a fee from 1 to 100).")
        return log
    out = log + [[kind, sign * n]]
    if kind == "fee":
        print("Added: fee " + str(n) + "%.")
    elif kind == "adjust":
        print("Added: adjust " + events.signed(sign * n) + ".")
    else:
        print("Added: " + kind + " " + str(n) + ".")
    return out

log = events.default_log()
print("== Event log ==")
print("An account kept two ways: the balance replayed from its events, and a stored balance column that each write path updates.")
running = True
while running:
    print("")
    print("1) the log  2) reconcile  3) every order  4) add an event  5) remove the last  6) quit")
    choice = plain(input("choice> "))
    if choice == "1":
        show(log)
    elif choice == "2":
        reconcile(log)
    elif choice == "3":
        orders(log)
    elif choice == "4":
        log = add(log)
    elif choice == "5":
        if len(log) == 0:
            print("The log is empty.")
        else:
            log = log[0:len(log) - 1]
            print("Removed the last event; " + str(len(log)) + " left.")
    elif choice == "6":
        running = False
    else:
        print("Pick a number from 1 to 6.")
print("Bye.")

events.eml

eml
# P131 event log - an account kept two ways: the balance replayed from its
# events, and a stored balance column that each write path updates. As in
# the corpus case denormalized-total-drifts, one path (an adjustment)
# forgets the stored column, and a check that compares the column with a
# copy kept by the same paths compares a number with itself. As in
# state-from-events-vs-stored, replaying is right only for the order the
# events happened in: a fee and a refused withdrawal do not commute with
# the rest.
#
# An event is [kind, amount]: deposit n, withdraw n (refused if more than
# the balance), fee p (p percent of the balance, rounded down), adjust n
# (a correction, either sign).

def default_log():
    return [["deposit", 100], ["withdraw", 30], ["fee", 10], ["deposit", 50], ["adjust", 20], ["withdraw", 120]]

def div(p, q):
    int(p / q) => f
    while f * q > p:
        f - 1 => f
    while (f + 1) * q <= p:
        f + 1 => f
    return f

def apply(balance, ev):
    # [balance after, what happened]
    if ev[0] == "deposit":
        return [balance + ev[1], "deposit " + str(ev[1])]
    if ev[0] == "withdraw":
        if ev[1] > balance:
            return [balance, "withdraw " + str(ev[1]) + " refused: only " + str(balance)]
        return [balance - ev[1], "withdraw " + str(ev[1])]
    if ev[0] == "fee":
        div(balance * ev[1], 100) => f
        return [balance - f, "fee " + str(ev[1]) + "% = " + str(f)]
    return [balance + ev[1], "adjust " + signed(ev[1])]

def signed(n):
    if n < 0:
        return str(n)
    return "+" + str(n)

def replay(log):
    0 => b
    for ev in log:
        apply(b, ev)[0] => b
    return b

def ledger(log):
    # per event [what happened, replayed balance, stored column, the copy
    #  the check reads]; every path but adjust writes the column and the copy
    0 => b
    0 => stored
    0 => copy
    [] => out
    for ev in log:
        b => before
        apply(b, ev) => r
        r[0] => b
        if ev[0] != "adjust":
            stored + b - before => stored
            stored => copy
        out + [[r[1], b, stored, copy]] => out
    return out

def permutations(xs):
    if len(xs) <= 1:
        return [xs]
    [] => out
    for i in [0:len(xs) - 1]:
        [] => rest
        for j in [0:len(xs) - 1]:
            if j != i:
                rest + [xs[j]] => rest
        for p in permutations(rest):
            out + [[xs[i]] + p] => out
    return out

def orders(log):
    # [orders, distinct final balances, orders ending as the log does]
    replay(log) => right
    {} => seen
    0 => same
    permutations(log) => ps
    for p in ps:
        replay(p) => b
        1 => seen[b]
        if b == right:
            same + 1 => same
    return [len(ps), len(seen), same]

def commutes(a, b, top):
    # a then b equals b then a from every balance 0 to top
    for x in [0:top]:
        if apply(apply(x, a)[0], b)[0] != apply(apply(x, b)[0], a)[0]:
            return False
    return True

def pairs(log, top):
    # [pairs, pairs that commute]
    0 => n
    0 => c
    for i in [0:len(log) - 2]:
        for j in [i + 1:len(log) - 1]:
            n + 1 => n
            if commutes(log[i], log[j], top):
                c + 1 => c
    return [n, c]
Python projection (events.py)
def default_log():
    return [["deposit", 100], ["withdraw", 30], ["fee", 10], ["deposit", 50], ["adjust", 20], ["withdraw", 120]]

def div(p, q):
    f = int(p / q)
    while f * q > p:
        f = f - 1
    while (f + 1) * q <= p:
        f = f + 1
    return f

def apply(balance, ev):
    if ev[0] == "deposit":
        return [balance + ev[1], "deposit " + str(ev[1])]
    if ev[0] == "withdraw":
        if ev[1] > balance:
            return [balance, "withdraw " + str(ev[1]) + " refused: only " + str(balance)]
        return [balance - ev[1], "withdraw " + str(ev[1])]
    if ev[0] == "fee":
        f = div(balance * ev[1], 100)
        return [balance - f, "fee " + str(ev[1]) + "% = " + str(f)]
    return [balance + ev[1], "adjust " + signed(ev[1])]

def signed(n):
    if n < 0:
        return str(n)
    return "+" + str(n)

def replay(log):
    b = 0
    for ev in log:
        b = apply(b, ev)[0]
    return b

def ledger(log):
    b = 0
    stored = 0
    copy = 0
    out = []
    for ev in log:
        before = b
        r = apply(b, ev)
        b = r[0]
        if ev[0] != "adjust":
            stored = stored + b - before
            copy = stored
        out = out + [[r[1], b, stored, copy]]
    return out

def permutations(xs):
    if len(xs) <= 1:
        return [xs]
    out = []
    for i in range(0, len(xs)):
        rest = []
        for j in range(0, len(xs)):
            if j != i:
                rest = rest + [xs[j]]
        for p in permutations(rest):
            out = out + [[xs[i]] + p]
    return out

def orders(log):
    right = replay(log)
    seen = {}
    same = 0
    ps = permutations(log)
    for p in ps:
        b = replay(p)
        seen[b] = 1
        if b == right:
            same = same + 1
    return [len(ps), len(seen), same]

def commutes(a, b, top):
    for x in range(0, top+1):
        if apply(apply(x, a)[0], b)[0] != apply(apply(x, b)[0], a)[0]:
            return False
    return True

def pairs(log, top):
    n = 0
    c = 0
    for i in range(0, len(log) - 2+1):
        for j in range(i + 1, len(log)):
            n = n + 1
            if commutes(log[i], log[j], top):
                c = c + 1
    return [n, c]

Built on these corpus cases

ΣEML 2026

Efficient New Language — a high-density semantic overlay for humans and AI agents.

This site’s demos run on the real EML toolchain, in your browser.

© 2026 EveMissLab (一言諾科技有限公司) / Neo.K. All rights reserved.