Project P132

Fair share

One worker and one-slot jobs from a heavy tenant and light ones, first come first served or tenants in turn: the light tenants' worst wait changes a lot, the mean per job not at all.

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

One worker, jobs of one slot each, from one heavy tenant and several light ones, run first come first served or taking the tenants in turn.

  • main.eml - the menu, the tenants, the comparison slot by slot and per tenant, and the settings
  • fair.eml - the jobs, the two schedules, and the counts per tenant and per job

How each part works:

  • Tenant H sends its jobs at slot 0; each light tenant sends one at a later slot. The worker runs one job a slot and is never idle while a job waits. In turn, it takes the next waiting job of the next tenant that has one.
  • As in the corpus case fair-share-vs-fifo, first come is fair to jobs and in turn is fair to tenants. With 20 jobs from H and one each from a to e at slot 1, the light tenants' worst completion is 25 first come and 6 in turn; H's last job moves from 20 to 25.
  • Per job the two are the same: the worker is busy in the same slots either way, so the mean completion and the mean wait per job do not move at all. Taking turns never makes a light tenant's worst completion later.

What is checked: menu choices 1 to 4; 1 to 30 jobs for H, 1 to 8 light tenants, and a slot from 0 to 30 for their jobs. An empty answer cancels.

Sessions: sessions/basic.in gives: - the tenants and the comparison; - the light jobs at slot 25, after H's are done: the two run alike, the worker idle in between; - 6 jobs from H and 3 light tenants at slot 0.

sessions/bad-input.in gives: - menu choices 0 and x; - settings: a cancel, 0, 31 and x for H, then 5 with a cancel and 9 light tenants, and 5 and 2 with a cancel and slot 31; - the most of everything: 30 jobs from H and 8 light tenants at slot 0.

Built on the verified corpus case fair-share-vs-fifo (the same jobs in two orders, fair to requests or fair to tenants).

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
== Fair share ==
One worker, jobs of one slot each, from one heavy tenant and several light ones.

1) the tenants  2) compare  3) settings  4) quit
choice> 0
Pick a number from 1 to 4.

1) the tenants  2) compare  3) settings  4) quit
choice> x
Pick a number from 1 to 4.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 
Cancelled.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 0
Type a whole number from 1 to 30.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 31
Type a whole number from 1 to 30.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> x
Type a whole number from 1 to 30.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 5
light tenants (1 to 8)> 
Cancelled.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 5
light tenants (1 to 8)> 9
Type a whole number from 1 to 8.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 5
light tenants (1 to 8)> 2
slot the light tenants send at (0 to 30)> 
Cancelled.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 5
light tenants (1 to 8)> 2
slot the light tenants send at (0 to 30)> 31
Type a whole number from 0 to 30.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 30
light tenants (1 to 8)> 8
slot the light tenants send at (0 to 30)> 0
Tenant H sends 30 jobs at slot 0; tenants a to h send one each at slot 0. Every job takes one slot.

1) the tenants  2) compare  3) settings  4) quit
choice> 2
Slot by slot (H the heavy tenant, a letter each light one):
  first come HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHabcdefgh
  in turn    HabcdefghHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
  tenant   jobs   first come: worst  mean   in turn: worst  mean
  H          30                 30  15.5              38  23.2
  a           1                 31  31.0               2   2.0
  b           1                 32  32.0               3   3.0
  c           1                 33  33.0               4   4.0
  d           1                 34  34.0               5   5.0
  e           1                 35  35.0               6   6.0
  f           1                 36  36.0               7   7.0
  g           1                 37  37.0               8   8.0
  h           1                 38  38.0               9   9.0
Worst completion among the light tenants: 38 first come, 9 in turn; tenant H's: 30 and 38.
Mean completion per job: 19.5 first come, 19.5 in turn; mean wait per job: 18.5 and 18.5.
Per job the two are the same: the worker is busy in the same slots either way, and only who goes first changes.

1) the tenants  2) compare  3) settings  4) quit
choice> 4
Bye.
What was typed (30 lines)
0
x
3

3
0
3
31
3
x
3
5

3
5
9
3
5
2

3
5
2
31
3
30
8
0
2
4

basic

interpreter: byte-equal
== Fair share ==
One worker, jobs of one slot each, from one heavy tenant and several light ones.

1) the tenants  2) compare  3) settings  4) quit
choice> 1
Tenant H sends 20 jobs at slot 0; tenants a to e send one each at slot 1. Every job takes one slot.

1) the tenants  2) compare  3) settings  4) quit
choice> 2
Slot by slot (H the heavy tenant, a letter each light one):
  first come HHHHHHHHHHHHHHHHHHHHabcde
  in turn    HabcdeHHHHHHHHHHHHHHHHHHH
  tenant   jobs   first come: worst  mean   in turn: worst  mean
  H          20                 20  10.5              25  15.3
  a           1                 21  21.0               2   2.0
  b           1                 22  22.0               3   3.0
  c           1                 23  23.0               4   4.0
  d           1                 24  24.0               5   5.0
  e           1                 25  25.0               6   6.0
Worst completion among the light tenants: 25 first come, 6 in turn; tenant H's: 20 and 25.
Mean completion per job: 13.0 first come, 13.0 in turn; mean wait per job: 11.8 and 11.8.
Per job the two are the same: the worker is busy in the same slots either way, and only who goes first changes.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 20
light tenants (1 to 8)> 5
slot the light tenants send at (0 to 30)> 25
Tenant H sends 20 jobs at slot 0; tenants a to e send one each at slot 25. Every job takes one slot.

1) the tenants  2) compare  3) settings  4) quit
choice> 2
Slot by slot (H the heavy tenant, a letter each light one):
  first come HHHHHHHHHHHHHHHHHHHHabcde
  in turn    HHHHHHHHHHHHHHHHHHHHabcde
  tenant   jobs   first come: worst  mean   in turn: worst  mean
  H          20                 20  10.5              20  10.5
  a           1                 26  26.0              26  26.0
  b           1                 27  27.0              27  27.0
  c           1                 28  28.0              28  28.0
  d           1                 29  29.0              29  29.0
  e           1                 30  30.0              30  30.0
Worst completion among the light tenants: 30 first come, 30 in turn; tenant H's: 20 and 20.
Mean completion per job: 14.0 first come, 14.0 in turn; mean wait per job: 8.0 and 8.0.
Per job the two are the same: the worker is busy in the same slots either way, and only who goes first changes.

1) the tenants  2) compare  3) settings  4) quit
choice> 3
tenant H's jobs (1 to 30)> 6
light tenants (1 to 8)> 3
slot the light tenants send at (0 to 30)> 0
Tenant H sends 6 jobs at slot 0; tenants a to c send one each at slot 0. Every job takes one slot.

1) the tenants  2) compare  3) settings  4) quit
choice> 2
Slot by slot (H the heavy tenant, a letter each light one):
  first come HHHHHHabc
  in turn    HabcHHHHH
  tenant   jobs   first come: worst  mean   in turn: worst  mean
  H           6                  6   3.5               9   6.0
  a           1                  7   7.0               2   2.0
  b           1                  8   8.0               3   3.0
  c           1                  9   9.0               4   4.0
Worst completion among the light tenants: 9 first come, 4 in turn; tenant H's: 6 and 9.
Mean completion per job: 5.0 first come, 5.0 in turn; mean wait per job: 4.0 and 4.0.
Per job the two are the same: the worker is busy in the same slots either way, and only who goes first changes.

1) the tenants  2) compare  3) settings  4) quit
choice> 4
Bye.
What was typed (13 lines)
1
2
3
20
5
25
2
3
6
3
0
2
4

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
# P132 fair share: one heavy tenant and several light ones through first
# come first served and through taking tenants in turn, slot by slot and
# per tenant.
import fair

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 letter(t):
    "Habcdefgh" => ls
    return ls[t]

def tenths(p, q):
    # p / q to one decimal, rounded half up
    int((20 * p + q) / (2 * q)) => t
    while t * 2 * q > 20 * p + q:
        t - 1 => t
    while (t + 1) * 2 * q <= 20 * p + q:
        t + 1 => t
    return str(int(t / 10)) + "." + str(t % 10)

def show(heavy, light, late):
    ("Tenant H sends " + str(heavy) + " jobs at slot 0; tenants a to " + letter(light) + " send one each at slot " + str(late) + ". Every job takes one slot.") ^0

def compare(heavy, light, late):
    fair.jobs(heavy, light, late) => js
    light + 1 => tenants
    "Slot by slot (H the heavy tenant, a letter each light one):" ^0
    [] => orders
    for plan in ["fifo", "fair"]:
        fair.schedule(js, tenants, plan) => o
        orders + [o] => orders
        "" => line
        for e in o:
            line + letter(js[e[0]][0]) => line
        "first come" => label
        if plan == "fair":
            "in turn" => label
        ("  " + pad(label, 11) + line) ^0
    "  tenant   jobs   first come: worst  mean   in turn: worst  mean" ^0
    fair.per_tenant(js, tenants, orders[0]) => a
    fair.per_tenant(js, tenants, orders[1]) => b
    0 => worst_a
    0 => worst_b
    for t in [0:tenants - 1]:
        ("  " + pad(letter(t), 7) + lpad(str(a[t][0]), 6) + lpad(str(a[t][1]), 19) + lpad(tenths(a[t][2], a[t][0]), 6) + lpad(str(b[t][1]), 16) + lpad(tenths(b[t][2], b[t][0]), 6)) ^0
        if t > 0:
            if a[t][1] > worst_a:
                a[t][1] => worst_a
            if b[t][1] > worst_b:
                b[t][1] => worst_b
    fair.per_job(js, orders[0]) => ja
    fair.per_job(js, orders[1]) => jb
    ("Worst completion among the light tenants: " + str(worst_a) + " first come, " + str(worst_b) + " in turn; tenant H's: " + str(a[0][1]) + " and " + str(b[0][1]) + ".") ^0
    ("Mean completion per job: " + tenths(ja[0], len(js)) + " first come, " + tenths(jb[0], len(js)) + " in turn; mean wait per job: " + tenths(ja[1], len(js)) + " and " + tenths(jb[1], len(js)) + ".") ^0
    if ja[0] == jb[0]:
        "Per job the two are the same: the worker is busy in the same slots either way, and only who goes first changes." ^0

def ask_int(prompt, low, high):
    plain(input(prompt)) => t
    if t == "":
        "Cancelled." ^0
        return 0 - 1
    if len(t) > 2:
        ("Type a whole number from " + str(low) + " to " + str(high) + ".") ^0
        return 0 - 1
    for c in t:
        if c < "0" or c > "9":
            ("Type a whole number from " + str(low) + " to " + str(high) + ".") ^0
            return 0 - 1
    if int(t) < low or int(t) > high:
        ("Type a whole number from " + str(low) + " to " + str(high) + ".") ^0
        return 0 - 1
    return int(t)

def settings(heavy, light, late):
    ask_int("tenant H's jobs (1 to 30)> ", 1, 30) => h
    if h < 0:
        return [heavy, light, late]
    ask_int("light tenants (1 to 8)> ", 1, 8) => l
    if l < 0:
        return [heavy, light, late]
    ask_int("slot the light tenants send at (0 to 30)> ", 0, 30) => s
    if s < 0:
        return [heavy, light, late]
    show(h, l, s)
    return [h, l, s]

20 => heavy
5 => light
1 => late

"== Fair share ==" ^0
"One worker, jobs of one slot each, from one heavy tenant and several light ones." ^0
True => running
while running:
    "" ^0
    "1) the tenants  2) compare  3) settings  4) quit" ^0
    plain(input("choice> ")) => choice
    if choice == "1":
        show(heavy, light, late)
    elif choice == "2":
        compare(heavy, light, late)
    elif choice == "3":
        settings(heavy, light, late) => s
        s[0] => heavy
        s[1] => light
        s[2] => late
    elif choice == "4":
        False => running
    else:
        "Pick a number from 1 to 4." ^0
"Bye." ^0
Python projection (main.py)
import fair

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 letter(t):
    ls = "Habcdefgh"
    return ls[t]

def tenths(p, q):
    t = int((20 * p + q) / (2 * q))
    while t * 2 * q > 20 * p + q:
        t = t - 1
    while (t + 1) * 2 * q <= 20 * p + q:
        t = t + 1
    return str(int(t / 10)) + "." + str(t % 10)

def show(heavy, light, late):
    print("Tenant H sends " + str(heavy) + " jobs at slot 0; tenants a to " + letter(light) + " send one each at slot " + str(late) + ". Every job takes one slot.")

def compare(heavy, light, late):
    js = fair.jobs(heavy, light, late)
    tenants = light + 1
    print("Slot by slot (H the heavy tenant, a letter each light one):")
    orders = []
    for plan in ["fifo", "fair"]:
        o = fair.schedule(js, tenants, plan)
        orders = orders + [o]
        line = ""
        for e in o:
            line = line + letter(js[e[0]][0])
        label = "first come"
        if plan == "fair":
            label = "in turn"
        print("  " + pad(label, 11) + line)
    print("  tenant   jobs   first come: worst  mean   in turn: worst  mean")
    a = fair.per_tenant(js, tenants, orders[0])
    b = fair.per_tenant(js, tenants, orders[1])
    worst_a = 0
    worst_b = 0
    for t in range(0, tenants):
        print("  " + pad(letter(t), 7) + lpad(str(a[t][0]), 6) + lpad(str(a[t][1]), 19) + lpad(tenths(a[t][2], a[t][0]), 6) + lpad(str(b[t][1]), 16) + lpad(tenths(b[t][2], b[t][0]), 6))
        if t > 0:
            if a[t][1] > worst_a:
                worst_a = a[t][1]
            if b[t][1] > worst_b:
                worst_b = b[t][1]
    ja = fair.per_job(js, orders[0])
    jb = fair.per_job(js, orders[1])
    print("Worst completion among the light tenants: " + str(worst_a) + " first come, " + str(worst_b) + " in turn; tenant H's: " + str(a[0][1]) + " and " + str(b[0][1]) + ".")
    print("Mean completion per job: " + tenths(ja[0], len(js)) + " first come, " + tenths(jb[0], len(js)) + " in turn; mean wait per job: " + tenths(ja[1], len(js)) + " and " + tenths(jb[1], len(js)) + ".")
    if ja[0] == jb[0]:
        print("Per job the two are the same: the worker is busy in the same slots either way, and only who goes first changes.")

def ask_int(prompt, low, high):
    t = plain(input(prompt))
    if t == "":
        print("Cancelled.")
        return 0 - 1
    if len(t) > 2:
        print("Type a whole number from " + str(low) + " to " + str(high) + ".")
        return 0 - 1
    for c in t:
        if c < "0" or c > "9":
            print("Type a whole number from " + str(low) + " to " + str(high) + ".")
            return 0 - 1
    if int(t) < low or int(t) > high:
        print("Type a whole number from " + str(low) + " to " + str(high) + ".")
        return 0 - 1
    return int(t)

def settings(heavy, light, late):
    h = ask_int("tenant H's jobs (1 to 30)> ", 1, 30)
    if h < 0:
        return [heavy, light, late]
    l = ask_int("light tenants (1 to 8)> ", 1, 8)
    if l < 0:
        return [heavy, light, late]
    s = ask_int("slot the light tenants send at (0 to 30)> ", 0, 30)
    if s < 0:
        return [heavy, light, late]
    show(h, l, s)
    return [h, l, s]

heavy = 20
light = 5
late = 1
print("== Fair share ==")
print("One worker, jobs of one slot each, from one heavy tenant and several light ones.")
running = True
while running:
    print("")
    print("1) the tenants  2) compare  3) settings  4) quit")
    choice = plain(input("choice> "))
    if choice == "1":
        show(heavy, light, late)
    elif choice == "2":
        compare(heavy, light, late)
    elif choice == "3":
        s = settings(heavy, light, late)
        heavy = s[0]
        light = s[1]
        late = s[2]
    elif choice == "4":
        running = False
    else:
        print("Pick a number from 1 to 4.")
print("Bye.")

fair.eml

eml
# P132 fair share - one worker, jobs of one slot each from several tenants.
# As in the corpus case fair-share-vs-fifo, first come first served is fair
# to jobs, and taking the tenants in turn is fair to tenants. Each job is
# [tenant, arrival slot]; the worker runs one job a slot, never idle while a
# job is waiting.

def jobs(heavy, light, late):
    # tenant 0 sends heavy jobs at slot 0; tenants 1 to light one each at
    # slot late
    [] => out
    for k in [1:heavy]:
        out + [[0, 0]] => out
    for t in [1:light]:
        out + [[t, late]] => out
    return out

def schedule(js, tenants, plan):
    # the order the jobs run in, as [job index, start slot]
    [] => done
    for j in js:
        done + [False] => done
    [] => out
    0 => slot
    0 => turn
    while len(out) < len(js):
        0 - 1 => pick
        if plan == "fifo":
            for i in [0:len(js) - 1]:
                if pick < 0 and not done[i] and js[i][1] <= slot:
                    i => pick
        else:
            for step in [0:tenants - 1]:
                (turn + step) % tenants => t
                if pick < 0:
                    for i in [0:len(js) - 1]:
                        if pick < 0 and not done[i] and js[i][0] == t and js[i][1] <= slot:
                            i => pick
                    if pick >= 0:
                        (t + 1) % tenants => turn
        if pick >= 0:
            True => done[pick]
            out + [[pick, slot]] => out
        slot + 1 => slot
    return out

def per_tenant(js, tenants, order):
    # per tenant [jobs, worst completion, total completion]; completion is the
    # slot after the job's slot
    [] => out
    for t in [0:tenants - 1]:
        out + [[0, 0, 0]] => out
    for e in order:
        js[e[0]][0] => t
        e[1] + 1 => c
        out[t][0] + 1 => out[t][0]
        if c > out[t][1]:
            c => out[t][1]
        out[t][2] + c => out[t][2]
    return out

def per_job(js, order):
    # [total completion, total wait] over all jobs
    0 => c
    0 => w
    for e in order:
        c + e[1] + 1 => c
        w + e[1] - js[e[0]][1] => w
    return [c, w]
Python projection (fair.py)
def jobs(heavy, light, late):
    out = []
    for k in range(1, heavy+1):
        out = out + [[0, 0]]
    for t in range(1, light+1):
        out = out + [[t, late]]
    return out

def schedule(js, tenants, plan):
    done = []
    for j in js:
        done = done + [False]
    out = []
    slot = 0
    turn = 0
    while len(out) < len(js):
        pick = 0 - 1
        if plan == "fifo":
            for i in range(0, len(js)):
                if pick < 0 and not done[i] and js[i][1] <= slot:
                    pick = i
        else:
            for step in range(0, tenants):
                t = (turn + step) % tenants
                if pick < 0:
                    for i in range(0, len(js)):
                        if pick < 0 and not done[i] and js[i][0] == t and js[i][1] <= slot:
                            pick = i
                    if pick >= 0:
                        turn = (t + 1) % tenants
        if pick >= 0:
            done[pick] = True
            out = out + [[pick, slot]]
        slot = slot + 1
    return out

def per_tenant(js, tenants, order):
    out = []
    for t in range(0, tenants):
        out = out + [[0, 0, 0]]
    for e in order:
        t = js[e[0]][0]
        c = e[1] + 1
        out[t][0] = out[t][0] + 1
        if c > out[t][1]:
            out[t][1] = c
        out[t][2] = out[t][2] + c
    return out

def per_job(js, order):
    c = 0
    w = 0
    for e in order:
        c = c + e[1] + 1
        w = w + e[1] - js[e[0]][1]
    return [c, w]

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.