{
  "id": "P099",
  "slug": "message-timeline",
  "key": "P099-message-timeline",
  "title": "Message timeline",
  "summary": "Three people send messages, each stamping events with a clock of their own: the events put back in order by wall clock, by a Lamport counter and by vector clocks; cause-and-effect pairs each order gets backwards; and for any two events, whether one could have caused the other, with the chain of steps.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P099 - Message timeline\n\nThree people, A, B and C, send each other messages, and each stamps\nevents with a clock of their own. The program puts the events back in\norder three ways: by wall clock, by a Lamport counter, and by vector\nclocks. Only the vector clocks can say what could have caused what. It\nstarts with 11 events; B's clock is 5 ms slow and C's 3 ms fast.\n\n- `main.eml` - the menu, the timeline, the orderings, and questions about\n  two events\n- `causal.eml` - reading events, the clocks, happened-before, chains,\n  orderings and what they get backwards\n\nHow each part works:\n\n- Events are typed in the order they happen:\n  - A. - something happens to A;\n  - A>B - A sends to B;\n  - B<A - B receives the oldest message from A still waiting for it.\n\n  One event happens every 4 ms of true time. Each person's clock reads\n  the true time plus that clock's skew.\n- Sorting by wall clock, as in the corpus case\n  `event-order-without-clock`, can put a receive before its send when the\n  receiver's clock is behind. The program counts the cause-and-effect\n  pairs that such an order puts backwards.\n- A Lamport counter: each event counts one more than that person's last\n  count, and a receive first takes the larger of its own count and the\n  message's. A cause always gets the smaller count, so the Lamport order\n  never puts a cause after its effect. But a smaller count does not make\n  a cause. Concurrent events get counts too, and the order puts them one\n  after the other.\n- Vector clocks: each person counts their own events, and on a receive\n  takes the larger of each count. One event happened before another\n  exactly when none of its counts is larger. When each has a count larger\n  than the other's, they are concurrent. For a pair that is cause and\n  effect, the program shows a shortest chain of steps from one to the\n  other. A step is the same person's next event, or a message.\n\nWhat is checked: menu choices 1 to 6; two different event numbers in\nrange; events of the three forms, nobody sending to themselves, a receive\nonly of a message that is waiting, and 2 to 30 events; clocks from -50 to\n50 ms. An empty answer cancels.\n\nSessions: `sessions/basic.in` gives:\n- the timeline with its clocks;\n- the orderings: by wall clock, one message is received 1 ms before it\n  was sent;\n- five pairs:\n  - a message and its receive;\n  - the first event and the last, with a chain of 5;\n  - two concurrent events;\n  - two concurrent events with equal Lamport counts;\n  - a pair asked the other way round;\n- the clocks set right, with no pair backwards; then B 20 ms slow and C\n  15 ms fast, with 7 pairs backwards, 2 of them messages;\n- new events in which one message is never received, with their\n  timeline and orderings.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- pairs: a cancel, one number, the same number twice, 0, letters, and 12;\n- the events A, D., A>A, B<A with nothing waiting, a single event, a\n  second receive with nothing waiting, A.B, and 31 events; a cancel;\n- clocks 51 and x, a cancel after A; then +5, -50 and 50, and the\n  timeline with them.\n\nBuilt on the verified corpus case `event-order-without-clock` (a skewed\nclock orders most pairs right and inverts the ones that matter; a\nLamport counter keeps every cause before its effect).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P099 message timeline: three people send messages, each stamping events\n# with their own clock. Wall clocks, a Lamport counter and vector clocks\n# put the events in order - and only one of them can say what could have\n# caused what.\nimport causal\n\ndef plain(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef number(s, most):\n    if len(s) == 0 or len(s) > most:\n        return -1\n    0 => n\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef pad(s, n):\n    while len(s) < n:\n        s + \" \" => s\n    return s\n\ndef lpad(s, n):\n    while len(s) < n:\n        \" \" + s => s\n    return s\n\ndef label(events, i):\n    return causal.letter(events[i][0]) + str(i + 1)\n\ndef what(e):\n    if e[1] == \".\":\n        return \"something happens\"\n    if e[1] == \">\":\n        return \"sends m\" + str(e[3]) + \" to \" + causal.letter(e[2])\n    return \"receives m\" + str(e[3]) + \" from \" + causal.letter(e[2])\n\ndef vec(v):\n    return \"(\" + str(v[0]) + \",\" + str(v[1]) + \",\" + str(v[2]) + \")\"\n\ndef signed(n):\n    if n > 0:\n        return \"+\" + str(n)\n    return str(n)\n\ndef timeline(events, skew):\n    causal.stamps(events, skew, 4) => st\n    (\"Clocks: A \" + signed(skew[0]) + \" ms, B \" + signed(skew[1]) + \" ms, C \" + signed(skew[2]) + \" ms from the true time; one event every 4 ms.\") ^0\n    \"  event  what                  true  wall  Lamport  vector\" ^0\n    for i in [0:len(events) - 1]:\n        (\"  \" + pad(label(events, i), 7) + pad(what(events[i]), 22) + lpad(str(st[i][0]), 4) + lpad(str(st[i][1]), 6) + lpad(str(st[i][2]), 9) + \"  \" + vec(st[i][3])) ^0\n    \"Lamport: one more than the last count; a receive first takes the larger of its own count and the message's.\" ^0\n    \"Vector: each person counts their own events and, on a receive, takes the larger of each count.\" ^0\n\ndef show_order(events, st, order):\n    \"\" => line\n    for i in order:\n        if line != \"\":\n            line + \" \" => line\n        line + label(events, i) => line\n    return line\n\ndef received(n):\n    if n == 0:\n        return \"none is a message received before it was sent.\"\n    if n == 1:\n        return \"1 is a message received before it was sent.\"\n    return str(n) + \" are messages received before they were sent.\"\n\ndef orderings(events, skew):\n    causal.stamps(events, skew, 4) => st\n    0 => causal_pairs\n    0 => apart\n    for a in [0:len(events) - 1]:\n        for b in [a + 1:len(events) - 1]:\n            if causal.before(st[a][3], st[b][3]) or causal.before(st[b][3], st[a][3]):\n                causal_pairs + 1 => causal_pairs\n            else:\n                apart + 1 => apart\n    [] => truth\n    for i in [0:len(events) - 1]:\n        truth + [i] => truth\n    (\"  true order       \" + show_order(events, st, truth)) ^0\n    causal.order_by(events, st, 1) => by_wall\n    (\"  by wall clock    \" + show_order(events, st, by_wall) + \"   (ties by person)\") ^0\n    causal.order_by(events, st, 2) => by_lamport\n    (\"  by Lamport       \" + show_order(events, st, by_lamport) + \"   (ties by person)\") ^0\n    causal.inversions(events, st, by_wall) => w\n    causal.inversions(events, st, by_lamport) => l\n    (str(len(events)) + \" events: of the \" + str(causal_pairs + apart) + \" pairs, \" + str(causal_pairs) + \" are cause and effect - one could have led to the other - and \" + str(apart) + \" are concurrent.\") ^0\n    if w[0] == 0:\n        \"By wall clock, no cause-and-effect pair comes out backwards.\" ^0\n    elif w[0] == 1:\n        (\"By wall clock, 1 cause-and-effect pair comes out backwards; \" + received(w[1])) ^0\n    else:\n        (\"By wall clock, \" + str(w[0]) + \" cause-and-effect pairs come out backwards; \" + received(w[1])) ^0\n    (\"By Lamport, \" + str(l[0]) + \" come out backwards: a cause always gets the smaller count. But the order puts each of the \" + str(apart) + \" concurrent pairs one after the other too, as if one came first; only the vector clocks show which pairs are concurrent.\") ^0\n\ndef ask(events, skew):\n    (\"Two events by number, 1 to \" + str(len(events)) + \", for example 2 6.\") ^0\n    plain(input(\"events> \")) => t\n    if t == \"\":\n        \"Cancelled.\" ^0\n        return\n    [] => nums\n    \"\" => w\n    True => ok\n    for c in t + \" \":\n        if c == \" \":\n            if w != \"\":\n                number(w, 2) => v\n                if v < 1 or v > len(events):\n                    False => ok\n                nums + [v - 1] => nums\n            \"\" => w\n        else:\n            w + c => w\n    if not ok or len(nums) != 2 or nums[0] == nums[1]:\n        (\"Type two different numbers from 1 to \" + str(len(events)) + \".\") ^0\n        return\n    causal.stamps(events, skew, 4) => st\n    nums[0] => a\n    nums[1] => b\n    label(events, a) => la\n    label(events, b) => lb\n    if causal.before(st[a][3], st[b][3]):\n        (\"Vector clocks: \" + la + \" \" + vec(st[a][3]) + \" happened before \" + lb + \" \" + vec(st[b][3]) + \": none of its counts is larger, so it could have caused it.\") ^0\n        \"\" => line\n        for i in causal.chain(events, a, b):\n            if line != \"\":\n                line + \" -> \" => line\n            line + label(events, i) => line\n        (\"  The chain: \" + line + \".\") ^0\n    elif causal.before(st[b][3], st[a][3]):\n        (\"Vector clocks: \" + la + \" \" + vec(st[a][3]) + \" happened after \" + lb + \" \" + vec(st[b][3]) + \", so it could not have caused it.\") ^0\n    else:\n        (\"Vector clocks: \" + la + \" \" + vec(st[a][3]) + \" and \" + lb + \" \" + vec(st[b][3]) + \" are concurrent: each has a count larger than the other's, so neither could have led to the other.\") ^0\n    if st[a][2] == st[b][2]:\n        (\"Lamport: both \" + str(st[a][2]) + \", so they are concurrent: a cause always gets the smaller count.\") ^0\n    else:\n        (\"Lamport: \" + str(st[a][2]) + \" and \" + str(st[b][2]) + \". The smaller count may belong to a cause, or the two may be concurrent; Lamport alone cannot tell which.\") ^0\n    (\"Wall clocks: \" + la + \" at \" + str(st[a][1]) + \" ms, \" + lb + \" at \" + str(st[b][1]) + \" ms (true \" + str(st[a][0]) + \" and \" + str(st[b][0]) + \").\") ^0\n    if (st[a][1] - st[b][1]) * (st[a][0] - st[b][0]) < 0:\n        \"The wall clocks have this pair the wrong way round.\" ^0\n    elif st[a][1] == st[b][1]:\n        \"The wall clocks cannot tell this pair apart.\" ^0\n\ndef script(events):\n    \"Events, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\" ^0\n    plain(input(\"events> \")) => t\n    if t == \"\":\n        \"Cancelled.\" ^0\n        return events\n    causal.build(t) => r\n    if r[1] != \"\":\n        (\"Not taken: \" + r[1] + \".\") ^0\n        return events\n    0 => waiting\n    {} => got\n    for e in r[0]:\n        if e[1] == \"<\":\n            True => got[e[3]]\n    for e in r[0]:\n        if e[1] == \">\" and not (e[3] in got):\n            waiting + 1 => waiting\n    (str(len(r[0])) + \" events.\") ^0\n    if waiting == 1:\n        \"1 message is never received.\" ^0\n    elif waiting > 1:\n        (str(waiting) + \" messages are never received.\") ^0\n    return r[0]\n\ndef clocks(skew):\n    \"How far each clock is from the true time, in ms, -50 to 50.\" ^0\n    [] => out\n    for n in [0:2]:\n        plain(input(causal.letter(n) + \" (ms)> \")) => t\n        if t == \"\":\n            \"Cancelled.\" ^0\n            return skew\n        1 => sign\n        if len(t) > 0 and t[0] == \"-\":\n            0 - 1 => sign\n            t[1:len(t)] => t\n        elif len(t) > 0 and t[0] == \"+\":\n            t[1:len(t)] => t\n        number(t, 2) => v\n        if v < 0 or v > 50:\n            \"Type a whole number from -50 to 50.\" ^0\n            return skew\n        out + [sign * v] => out\n    (\"Clocks: A \" + signed(out[0]) + \", B \" + signed(out[1]) + \", C \" + signed(out[2]) + \" ms.\") ^0\n    return out\n\ncausal.build(\"A. A>B B<A B>C C. C<B C>A B. A<C A>C C<A\")[0] => events\n[0, 0 - 5, 3] => skew\n\n\"== Message timeline ==\" ^0\n\"Three people, three clocks: putting their events back in order, and what could have caused what.\" ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\" ^0\n    plain(input(\"choice> \")) => choice\n    if choice == \"1\":\n        timeline(events, skew)\n    elif choice == \"2\":\n        orderings(events, skew)\n    elif choice == \"3\":\n        ask(events, skew)\n    elif choice == \"4\":\n        script(events) => events\n    elif choice == \"5\":\n        clocks(skew) => skew\n    elif choice == \"6\":\n        False => running\n    else:\n        \"Pick a number from 1 to 6.\" ^0\n\"Bye.\" ^0\n",
      "python": "import causal\n\ndef plain(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef number(s, most):\n    if len(s) == 0 or len(s) > most:\n        return -1\n    n = 0\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef pad(s, n):\n    while len(s) < n:\n        s = s + \" \"\n    return s\n\ndef lpad(s, n):\n    while len(s) < n:\n        s = \" \" + s\n    return s\n\ndef label(events, i):\n    return causal.letter(events[i][0]) + str(i + 1)\n\ndef what(e):\n    if e[1] == \".\":\n        return \"something happens\"\n    if e[1] == \">\":\n        return \"sends m\" + str(e[3]) + \" to \" + causal.letter(e[2])\n    return \"receives m\" + str(e[3]) + \" from \" + causal.letter(e[2])\n\ndef vec(v):\n    return \"(\" + str(v[0]) + \",\" + str(v[1]) + \",\" + str(v[2]) + \")\"\n\ndef signed(n):\n    if n > 0:\n        return \"+\" + str(n)\n    return str(n)\n\ndef timeline(events, skew):\n    st = causal.stamps(events, skew, 4)\n    print(\"Clocks: A \" + signed(skew[0]) + \" ms, B \" + signed(skew[1]) + \" ms, C \" + signed(skew[2]) + \" ms from the true time; one event every 4 ms.\")\n    print(\"  event  what                  true  wall  Lamport  vector\")\n    for i in range(0, len(events)):\n        print(\"  \" + pad(label(events, i), 7) + pad(what(events[i]), 22) + lpad(str(st[i][0]), 4) + lpad(str(st[i][1]), 6) + lpad(str(st[i][2]), 9) + \"  \" + vec(st[i][3]))\n    print(\"Lamport: one more than the last count; a receive first takes the larger of its own count and the message's.\")\n    print(\"Vector: each person counts their own events and, on a receive, takes the larger of each count.\")\n\ndef show_order(events, st, order):\n    line = \"\"\n    for i in order:\n        if line != \"\":\n            line = line + \" \"\n        line = line + label(events, i)\n    return line\n\ndef received(n):\n    if n == 0:\n        return \"none is a message received before it was sent.\"\n    if n == 1:\n        return \"1 is a message received before it was sent.\"\n    return str(n) + \" are messages received before they were sent.\"\n\ndef orderings(events, skew):\n    st = causal.stamps(events, skew, 4)\n    causal_pairs = 0\n    apart = 0\n    for a in range(0, len(events)):\n        for b in range(a + 1, len(events)):\n            if causal.before(st[a][3], st[b][3]) or causal.before(st[b][3], st[a][3]):\n                causal_pairs = causal_pairs + 1\n            else:\n                apart = apart + 1\n    truth = []\n    for i in range(0, len(events)):\n        truth = truth + [i]\n    print(\"  true order       \" + show_order(events, st, truth))\n    by_wall = causal.order_by(events, st, 1)\n    print(\"  by wall clock    \" + show_order(events, st, by_wall) + \"   (ties by person)\")\n    by_lamport = causal.order_by(events, st, 2)\n    print(\"  by Lamport       \" + show_order(events, st, by_lamport) + \"   (ties by person)\")\n    w = causal.inversions(events, st, by_wall)\n    l = causal.inversions(events, st, by_lamport)\n    print(str(len(events)) + \" events: of the \" + str(causal_pairs + apart) + \" pairs, \" + str(causal_pairs) + \" are cause and effect - one could have led to the other - and \" + str(apart) + \" are concurrent.\")\n    if w[0] == 0:\n        print(\"By wall clock, no cause-and-effect pair comes out backwards.\")\n    elif w[0] == 1:\n        print(\"By wall clock, 1 cause-and-effect pair comes out backwards; \" + received(w[1]))\n    else:\n        print(\"By wall clock, \" + str(w[0]) + \" cause-and-effect pairs come out backwards; \" + received(w[1]))\n    print(\"By Lamport, \" + str(l[0]) + \" come out backwards: a cause always gets the smaller count. But the order puts each of the \" + str(apart) + \" concurrent pairs one after the other too, as if one came first; only the vector clocks show which pairs are concurrent.\")\n\ndef ask(events, skew):\n    print(\"Two events by number, 1 to \" + str(len(events)) + \", for example 2 6.\")\n    t = plain(input(\"events> \"))\n    if t == \"\":\n        print(\"Cancelled.\")\n        return\n    nums = []\n    w = \"\"\n    ok = True\n    for c in t + \" \":\n        if c == \" \":\n            if w != \"\":\n                v = number(w, 2)\n                if v < 1 or v > len(events):\n                    ok = False\n                nums = nums + [v - 1]\n            w = \"\"\n        else:\n            w = w + c\n    if not ok or len(nums) != 2 or nums[0] == nums[1]:\n        print(\"Type two different numbers from 1 to \" + str(len(events)) + \".\")\n        return\n    st = causal.stamps(events, skew, 4)\n    a = nums[0]\n    b = nums[1]\n    la = label(events, a)\n    lb = label(events, b)\n    if causal.before(st[a][3], st[b][3]):\n        print(\"Vector clocks: \" + la + \" \" + vec(st[a][3]) + \" happened before \" + lb + \" \" + vec(st[b][3]) + \": none of its counts is larger, so it could have caused it.\")\n        line = \"\"\n        for i in causal.chain(events, a, b):\n            if line != \"\":\n                line = line + \" -> \"\n            line = line + label(events, i)\n        print(\"  The chain: \" + line + \".\")\n    elif causal.before(st[b][3], st[a][3]):\n        print(\"Vector clocks: \" + la + \" \" + vec(st[a][3]) + \" happened after \" + lb + \" \" + vec(st[b][3]) + \", so it could not have caused it.\")\n    else:\n        print(\"Vector clocks: \" + la + \" \" + vec(st[a][3]) + \" and \" + lb + \" \" + vec(st[b][3]) + \" are concurrent: each has a count larger than the other's, so neither could have led to the other.\")\n    if st[a][2] == st[b][2]:\n        print(\"Lamport: both \" + str(st[a][2]) + \", so they are concurrent: a cause always gets the smaller count.\")\n    else:\n        print(\"Lamport: \" + str(st[a][2]) + \" and \" + str(st[b][2]) + \". The smaller count may belong to a cause, or the two may be concurrent; Lamport alone cannot tell which.\")\n    print(\"Wall clocks: \" + la + \" at \" + str(st[a][1]) + \" ms, \" + lb + \" at \" + str(st[b][1]) + \" ms (true \" + str(st[a][0]) + \" and \" + str(st[b][0]) + \").\")\n    if (st[a][1] - st[b][1]) * (st[a][0] - st[b][0]) < 0:\n        print(\"The wall clocks have this pair the wrong way round.\")\n    elif st[a][1] == st[b][1]:\n        print(\"The wall clocks cannot tell this pair apart.\")\n\ndef script(events):\n    print(\"Events, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\")\n    t = plain(input(\"events> \"))\n    if t == \"\":\n        print(\"Cancelled.\")\n        return events\n    r = causal.build(t)\n    if r[1] != \"\":\n        print(\"Not taken: \" + r[1] + \".\")\n        return events\n    waiting = 0\n    got = {}\n    for e in r[0]:\n        if e[1] == \"<\":\n            got[e[3]] = True\n    for e in r[0]:\n        if e[1] == \">\" and not e[3] in got:\n            waiting = waiting + 1\n    print(str(len(r[0])) + \" events.\")\n    if waiting == 1:\n        print(\"1 message is never received.\")\n    elif waiting > 1:\n        print(str(waiting) + \" messages are never received.\")\n    return r[0]\n\ndef clocks(skew):\n    print(\"How far each clock is from the true time, in ms, -50 to 50.\")\n    out = []\n    for n in range(0, 3):\n        t = plain(input(causal.letter(n) + \" (ms)> \"))\n        if t == \"\":\n            print(\"Cancelled.\")\n            return skew\n        sign = 1\n        if len(t) > 0 and t[0] == \"-\":\n            sign = 0 - 1\n            t = t[1:len(t)]\n        elif len(t) > 0 and t[0] == \"+\":\n            t = t[1:len(t)]\n        v = number(t, 2)\n        if v < 0 or v > 50:\n            print(\"Type a whole number from -50 to 50.\")\n            return skew\n        out = out + [sign * v]\n    print(\"Clocks: A \" + signed(out[0]) + \", B \" + signed(out[1]) + \", C \" + signed(out[2]) + \" ms.\")\n    return out\n\nevents = causal.build(\"A. A>B B<A B>C C. C<B C>A B. A<C A>C C<A\")[0]\nskew = [0, 0 - 5, 3]\nprint(\"== Message timeline ==\")\nprint(\"Three people, three clocks: putting their events back in order, and what could have caused what.\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\")\n    choice = plain(input(\"choice> \"))\n    if choice == \"1\":\n        timeline(events, skew)\n    elif choice == \"2\":\n        orderings(events, skew)\n    elif choice == \"3\":\n        ask(events, skew)\n    elif choice == \"4\":\n        events = script(events)\n    elif choice == \"5\":\n        skew = clocks(skew)\n    elif choice == \"6\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 6.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "causal.eml",
      "eml": "# P099 message timeline - three people, A, B and C, each with a clock of\n# their own, sending messages. Putting the events back in order by wall\n# clock can put a reply before its message, as in the corpus case\n# event-order-without-clock; a Lamport counter keeps every cause before its\n# effect but cannot tell \"before\" from \"at the same time\"; vector clocks\n# can.\n#\n# An event is [node, kind, other, message]: node and other 0, 1, 2 for A,\n# B, C; kind \".\" (something happens), \">\" (sends to other) or \"<\"\n# (receives from other); message is the message's number from 1, or 0.\n\ndef letter(n):\n    return [\"A\", \"B\", \"C\"][n]\n\ndef node_of(c):\n    if c == \"A\":\n        return 0\n    if c == \"B\":\n        return 1\n    if c == \"C\":\n        return 2\n    return -1\n\ndef build(text):\n    # \"A. A>B B<A\": [events, \"\"] or [[], why]. A receive takes the oldest\n    # message from that sender still waiting for this node.\n    [] => events\n    [] => waiting\n    0 => sent\n    \"\" => w\n    for c in text + \" \":\n        if c == \" \":\n            if w != \"\":\n                if len(w) < 2 or len(w) > 3 or node_of(w[0]) == -1:\n                    return [[], w + \" is not an event\"]\n                node_of(w[0]) => n\n                if w == w[0] + \".\":\n                    events + [[n, \".\", -1, 0]] => events\n                elif len(w) == 3 and (w[1] == \">\" or w[1] == \"<\") and node_of(w[2]) != -1:\n                    node_of(w[2]) => o\n                    if o == n:\n                        return [[], w + \": nobody sends to themselves\"]\n                    if w[1] == \">\":\n                        sent + 1 => sent\n                        events + [[n, \">\", o, sent]] => events\n                        waiting + [[n, o, sent]] => waiting\n                    else:\n                        -1 => found\n                        for i in [0:len(waiting) - 1]:\n                            if found == -1 and waiting[i][0] == o and waiting[i][1] == n:\n                                i => found\n                        if found == -1:\n                            return [[], w + \": no message from \" + w[2] + \" is waiting for \" + w[0]]\n                        events + [[n, \"<\", o, waiting[found][2]]] => events\n                        [] => rest\n                        for i in [0:len(waiting) - 1]:\n                            if i != found:\n                                rest + [waiting[i]] => rest\n                        rest => waiting\n                else:\n                    return [[], w + \" is not an event\"]\n            \"\" => w\n        else:\n            w + c => w\n    if len(events) < 2 or len(events) > 30:\n        return [[], \"a timeline has 2 to 30 events\"]\n    return [events, \"\"]\n\ndef stamps(events, skew, step):\n    # For each event: [true time, wall clock, Lamport, vector]. Event i\n    # happens at true time step x (i + 1); a node's clock reads true time\n    # plus its skew.\n    [0, 0, 0] => lamport\n    [[0, 0, 0], [0, 0, 0], [0, 0, 0]] => vector\n    {} => carried\n    [] => out\n    for i in [0:len(events) - 1]:\n        events[i] => e\n        e[0] => n\n        if e[1] == \"<\":\n            carried[e[3]] => m\n            if m[0] > lamport[n]:\n                m[0] => lamport[n]\n            for k in [0:2]:\n                if m[1][k] > vector[n][k]:\n                    m[1][k] => vector[n][k]\n        lamport[n] + 1 => lamport[n]\n        vector[n][n] + 1 => vector[n][n]\n        [vector[n][0], vector[n][1], vector[n][2]] => v\n        if e[1] == \">\":\n            [lamport[n], v] => carried[e[3]]\n        step * (i + 1) => t\n        out + [[t, t + skew[n], lamport[n], v]] => out\n    return out\n\ndef before(u, v):\n    # u happened before v: no part of u is later than v, and they differ\n    return u[0] <= v[0] and u[1] <= v[1] and u[2] <= v[2] and (u[0] != v[0] or u[1] != v[1] or u[2] != v[2])\n\ndef chain(events, a, b):\n    # A shortest chain of steps from event a to event b - the next event of\n    # the same person, or a message from its send to its receive - or [].\n    [] => prev\n    for i in [0:len(events) - 1]:\n        prev + [-1] => prev\n    [a] => queue\n    0 => head\n    a => prev[a]\n    while head < len(queue):\n        queue[head] => i\n        head + 1 => head\n        [] => nexts\n        -1 => same\n        for j in [i + 1:len(events) - 1]:\n            if same == -1 and events[j][0] == events[i][0]:\n                j => same\n        if same != -1:\n            nexts + [same] => nexts\n        if events[i][1] == \">\":\n            for j in [i + 1:len(events) - 1]:\n                if events[j][1] == \"<\" and events[j][3] == events[i][3]:\n                    nexts + [j] => nexts\n        for j in nexts:\n            if prev[j] == -1:\n                i => prev[j]\n                queue + [j] => queue\n    if prev[b] == -1 or a == b:\n        return []\n    [b] => back\n    b => j\n    while j != a:\n        prev[j] => j\n        back + [j] => back\n    [] => out\n    for k in [0:len(back) - 1]:\n        out + [back[len(back) - 1 - k]] => out\n    return out\n\ndef order_by(events, st, key):\n    # Event numbers sorted by wall clock (key 1) or Lamport (key 2), ties\n    # by person, then by number.\n    [] => out\n    for i in [0:len(events) - 1]:\n        out + [i] => out\n    for i in [1:len(out) - 1]:\n        i => j\n        while j > 0 and later(events, st, key, out[j - 1], out[j]):\n            out[j] => x\n            out[j - 1] => out[j]\n            x => out[j - 1]\n            j - 1 => j\n    return out\n\ndef later(events, st, key, a, b):\n    if st[a][key] != st[b][key]:\n        return st[a][key] > st[b][key]\n    if events[a][0] != events[b][0]:\n        return events[a][0] > events[b][0]\n    return a > b\n\ndef inversions(events, st, order):\n    # [pairs where one happened before the other but comes after it,\n    #  receives placed before their own send]\n    {} => pos\n    for k in [0:len(order) - 1]:\n        k => pos[order[k]]\n    0 => bad\n    0 => replies\n    for a in [0:len(events) - 1]:\n        for b in [0:len(events) - 1]:\n            if before(st[a][3], st[b][3]) and pos[b] < pos[a]:\n                bad + 1 => bad\n                if events[a][1] == \">\" and events[b][1] == \"<\" and events[b][3] == events[a][3]:\n                    replies + 1 => replies\n    return [bad, replies]\n",
      "python": "def letter(n):\n    return [\"A\", \"B\", \"C\"][n]\n\ndef node_of(c):\n    if c == \"A\":\n        return 0\n    if c == \"B\":\n        return 1\n    if c == \"C\":\n        return 2\n    return -1\n\ndef build(text):\n    events = []\n    waiting = []\n    sent = 0\n    w = \"\"\n    for c in text + \" \":\n        if c == \" \":\n            if w != \"\":\n                if len(w) < 2 or len(w) > 3 or node_of(w[0]) == -1:\n                    return [[], w + \" is not an event\"]\n                n = node_of(w[0])\n                if w == w[0] + \".\":\n                    events = events + [[n, \".\", -1, 0]]\n                elif len(w) == 3 and (w[1] == \">\" or w[1] == \"<\") and node_of(w[2]) != -1:\n                    o = node_of(w[2])\n                    if o == n:\n                        return [[], w + \": nobody sends to themselves\"]\n                    if w[1] == \">\":\n                        sent = sent + 1\n                        events = events + [[n, \">\", o, sent]]\n                        waiting = waiting + [[n, o, sent]]\n                    else:\n                        found = -1\n                        for i in range(0, len(waiting)):\n                            if found == -1 and waiting[i][0] == o and waiting[i][1] == n:\n                                found = i\n                        if found == -1:\n                            return [[], w + \": no message from \" + w[2] + \" is waiting for \" + w[0]]\n                        events = events + [[n, \"<\", o, waiting[found][2]]]\n                        rest = []\n                        for i in range(0, len(waiting)):\n                            if i != found:\n                                rest = rest + [waiting[i]]\n                        waiting = rest\n                else:\n                    return [[], w + \" is not an event\"]\n            w = \"\"\n        else:\n            w = w + c\n    if len(events) < 2 or len(events) > 30:\n        return [[], \"a timeline has 2 to 30 events\"]\n    return [events, \"\"]\n\ndef stamps(events, skew, step):\n    lamport = [0, 0, 0]\n    vector = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n    carried = {}\n    out = []\n    for i in range(0, len(events)):\n        e = events[i]\n        n = e[0]\n        if e[1] == \"<\":\n            m = carried[e[3]]\n            if m[0] > lamport[n]:\n                lamport[n] = m[0]\n            for k in range(0, 3):\n                if m[1][k] > vector[n][k]:\n                    vector[n][k] = m[1][k]\n        lamport[n] = lamport[n] + 1\n        vector[n][n] = vector[n][n] + 1\n        v = [vector[n][0], vector[n][1], vector[n][2]]\n        if e[1] == \">\":\n            carried[e[3]] = [lamport[n], v]\n        t = step * (i + 1)\n        out = out + [[t, t + skew[n], lamport[n], v]]\n    return out\n\ndef before(u, v):\n    return u[0] <= v[0] and u[1] <= v[1] and u[2] <= v[2] and (u[0] != v[0] or u[1] != v[1] or u[2] != v[2])\n\ndef chain(events, a, b):\n    prev = []\n    for i in range(0, len(events)):\n        prev = prev + [-1]\n    queue = [a]\n    head = 0\n    prev[a] = a\n    while head < len(queue):\n        i = queue[head]\n        head = head + 1\n        nexts = []\n        same = -1\n        for j in range(i + 1, len(events)):\n            if same == -1 and events[j][0] == events[i][0]:\n                same = j\n        if same != -1:\n            nexts = nexts + [same]\n        if events[i][1] == \">\":\n            for j in range(i + 1, len(events)):\n                if events[j][1] == \"<\" and events[j][3] == events[i][3]:\n                    nexts = nexts + [j]\n        for j in nexts:\n            if prev[j] == -1:\n                prev[j] = i\n                queue = queue + [j]\n    if prev[b] == -1 or a == b:\n        return []\n    back = [b]\n    j = b\n    while j != a:\n        j = prev[j]\n        back = back + [j]\n    out = []\n    for k in range(0, len(back)):\n        out = out + [back[len(back) - 1 - k]]\n    return out\n\ndef order_by(events, st, key):\n    out = []\n    for i in range(0, len(events)):\n        out = out + [i]\n    for i in range(1, len(out)):\n        j = i\n        while j > 0 and later(events, st, key, out[j - 1], out[j]):\n            x = out[j]\n            out[j] = out[j - 1]\n            out[j - 1] = x\n            j = j - 1\n    return out\n\ndef later(events, st, key, a, b):\n    if st[a][key] != st[b][key]:\n        return st[a][key] > st[b][key]\n    if events[a][0] != events[b][0]:\n        return events[a][0] > events[b][0]\n    return a > b\n\ndef inversions(events, st, order):\n    pos = {}\n    for k in range(0, len(order)):\n        pos[order[k]] = k\n    bad = 0\n    replies = 0\n    for a in range(0, len(events)):\n        for b in range(0, len(events)):\n            if before(st[a][3], st[b][3]) and pos[b] < pos[a]:\n                bad = bad + 1\n                if events[a][1] == \">\" and events[b][1] == \"<\" and events[b][3] == events[a][3]:\n                    replies = replies + 1\n    return [bad, replies]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n3\n\n3\n1\n3\n1 1\n3\n0 5\n3\na b\n3\n1 12\n4\nA\n4\nD.\n4\nA>A\n4\nB<A\n4\nA.\n4\nA>B B<A B<A\n4\nA.B C.\n4\nA. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A.\n4\n\n5\n51\n5\nx\n5\n-5\n\n5\n+5\n-50\n50\n1\n6\n",
      "screen": "== Message timeline ==\nThree people, three clocks: putting their events back in order, and what could have caused what.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 0\nPick a number from 1 to 6.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> x\nPick a number from 1 to 6.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> \nCancelled.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 1\nType two different numbers from 1 to 11.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 1 1\nType two different numbers from 1 to 11.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 0 5\nType two different numbers from 1 to 11.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> a b\nType two different numbers from 1 to 11.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 1 12\nType two different numbers from 1 to 11.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> A\nNot taken: A is not an event.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> D.\nNot taken: D. is not an event.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> A>A\nNot taken: A>A: nobody sends to themselves.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> B<A\nNot taken: B<A: no message from A is waiting for B.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> A.\nNot taken: a timeline has 2 to 30 events.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> A>B B<A B<A\nNot taken: B<A: no message from A is waiting for B.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> A.B C.\nNot taken: A.B is not an event.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A. A.\nNot taken: a timeline has 2 to 30 events.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> \nCancelled.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 5\nHow far each clock is from the true time, in ms, -50 to 50.\nA (ms)> 51\nType a whole number from -50 to 50.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 5\nHow far each clock is from the true time, in ms, -50 to 50.\nA (ms)> x\nType a whole number from -50 to 50.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 5\nHow far each clock is from the true time, in ms, -50 to 50.\nA (ms)> -5\nB (ms)> \nCancelled.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 5\nHow far each clock is from the true time, in ms, -50 to 50.\nA (ms)> +5\nB (ms)> -50\nC (ms)> 50\nClocks: A +5, B -50, C +50 ms.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 1\nClocks: A +5 ms, B -50 ms, C +50 ms from the true time; one event every 4 ms.\n  event  what                  true  wall  Lamport  vector\n  A1     something happens        4     9        1  (1,0,0)\n  A2     sends m1 to B            8    13        2  (2,0,0)\n  B3     receives m1 from A      12   -38        3  (2,1,0)\n  B4     sends m2 to C           16   -34        4  (2,2,0)\n  C5     something happens       20    70        1  (0,0,1)\n  C6     receives m2 from B      24    74        5  (2,2,2)\n  C7     sends m3 to A           28    78        6  (2,2,3)\n  B8     something happens       32   -18        5  (2,3,0)\n  A9     receives m3 from C      36    41        7  (3,2,3)\n  A10    sends m4 to C           40    45        8  (4,2,3)\n  C11    receives m4 from A      44    94        9  (4,2,4)\nLamport: one more than the last count; a receive first takes the larger of its own count and the message's.\nVector: each person counts their own events and, on a receive, takes the larger of each count.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 6\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n2\n3\n2 3\n3\n1 11\n3\n5 8\n3\n1 5\n3\n6 5\n5\n0\n0\n0\n2\n5\n0\n-20\n15\n2\n4\nA>B C>A A<C B. A>C C<A B<A C>B\n1\n2\n6\n",
      "screen": "== Message timeline ==\nThree people, three clocks: putting their events back in order, and what could have caused what.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 1\nClocks: A 0 ms, B -5 ms, C +3 ms from the true time; one event every 4 ms.\n  event  what                  true  wall  Lamport  vector\n  A1     something happens        4     4        1  (1,0,0)\n  A2     sends m1 to B            8     8        2  (2,0,0)\n  B3     receives m1 from A      12     7        3  (2,1,0)\n  B4     sends m2 to C           16    11        4  (2,2,0)\n  C5     something happens       20    23        1  (0,0,1)\n  C6     receives m2 from B      24    27        5  (2,2,2)\n  C7     sends m3 to A           28    31        6  (2,2,3)\n  B8     something happens       32    27        5  (2,3,0)\n  A9     receives m3 from C      36    36        7  (3,2,3)\n  A10    sends m4 to C           40    40        8  (4,2,3)\n  C11    receives m4 from A      44    47        9  (4,2,4)\nLamport: one more than the last count; a receive first takes the larger of its own count and the message's.\nVector: each person counts their own events and, on a receive, takes the larger of each count.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 2\n  true order       A1 A2 B3 B4 C5 C6 C7 B8 A9 A10 C11\n  by wall clock    A1 B3 A2 B4 C5 B8 C6 C7 A9 A10 C11   (ties by person)\n  by Lamport       A1 C5 A2 B3 B4 B8 C6 C7 A9 A10 C11   (ties by person)\n11 events: of the 55 pairs, 45 are cause and effect - one could have led to the other - and 10 are concurrent.\nBy wall clock, 1 cause-and-effect pair comes out backwards; 1 is a message received before it was sent.\nBy Lamport, 0 come out backwards: a cause always gets the smaller count. But the order puts each of the 10 concurrent pairs one after the other too, as if one came first; only the vector clocks show which pairs are concurrent.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 2 3\nVector clocks: A2 (2,0,0) happened before B3 (2,1,0): none of its counts is larger, so it could have caused it.\n  The chain: A2 -> B3.\nLamport: 2 and 3. The smaller count may belong to a cause, or the two may be concurrent; Lamport alone cannot tell which.\nWall clocks: A2 at 8 ms, B3 at 7 ms (true 8 and 12).\nThe wall clocks have this pair the wrong way round.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 1 11\nVector clocks: A1 (1,0,0) happened before C11 (4,2,4): none of its counts is larger, so it could have caused it.\n  The chain: A1 -> A2 -> A9 -> A10 -> C11.\nLamport: 1 and 9. The smaller count may belong to a cause, or the two may be concurrent; Lamport alone cannot tell which.\nWall clocks: A1 at 4 ms, C11 at 47 ms (true 4 and 44).\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 5 8\nVector clocks: C5 (0,0,1) and B8 (2,3,0) are concurrent: each has a count larger than the other's, so neither could have led to the other.\nLamport: 1 and 5. The smaller count may belong to a cause, or the two may be concurrent; Lamport alone cannot tell which.\nWall clocks: C5 at 23 ms, B8 at 27 ms (true 20 and 32).\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 1 5\nVector clocks: A1 (1,0,0) and C5 (0,0,1) are concurrent: each has a count larger than the other's, so neither could have led to the other.\nLamport: both 1, so they are concurrent: a cause always gets the smaller count.\nWall clocks: A1 at 4 ms, C5 at 23 ms (true 4 and 20).\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 3\nTwo events by number, 1 to 11, for example 2 6.\nevents> 6 5\nVector clocks: C6 (2,2,2) happened after C5 (0,0,1), so it could not have caused it.\nLamport: 5 and 1. The smaller count may belong to a cause, or the two may be concurrent; Lamport alone cannot tell which.\nWall clocks: C6 at 27 ms, C5 at 23 ms (true 24 and 20).\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 5\nHow far each clock is from the true time, in ms, -50 to 50.\nA (ms)> 0\nB (ms)> 0\nC (ms)> 0\nClocks: A 0, B 0, C 0 ms.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 2\n  true order       A1 A2 B3 B4 C5 C6 C7 B8 A9 A10 C11\n  by wall clock    A1 A2 B3 B4 C5 C6 C7 B8 A9 A10 C11   (ties by person)\n  by Lamport       A1 C5 A2 B3 B4 B8 C6 C7 A9 A10 C11   (ties by person)\n11 events: of the 55 pairs, 45 are cause and effect - one could have led to the other - and 10 are concurrent.\nBy wall clock, no cause-and-effect pair comes out backwards.\nBy Lamport, 0 come out backwards: a cause always gets the smaller count. But the order puts each of the 10 concurrent pairs one after the other too, as if one came first; only the vector clocks show which pairs are concurrent.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 5\nHow far each clock is from the true time, in ms, -50 to 50.\nA (ms)> 0\nB (ms)> -20\nC (ms)> 15\nClocks: A 0, B -20, C +15 ms.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 2\n  true order       A1 A2 B3 B4 C5 C6 C7 B8 A9 A10 C11\n  by wall clock    B3 B4 A1 A2 B8 C5 A9 C6 A10 C7 C11   (ties by person)\n  by Lamport       A1 C5 A2 B3 B4 B8 C6 C7 A9 A10 C11   (ties by person)\n11 events: of the 55 pairs, 45 are cause and effect - one could have led to the other - and 10 are concurrent.\nBy wall clock, 7 cause-and-effect pairs come out backwards; 2 are messages received before they were sent.\nBy Lamport, 0 come out backwards: a cause always gets the smaller count. But the order puts each of the 10 concurrent pairs one after the other too, as if one came first; only the vector clocks show which pairs are concurrent.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 4\nEvents, in the order they happen: A. (something happens to A), A>B (A sends to B), B<A (B receives the oldest message from A waiting for it). Persons A, B and C.\nevents> A>B C>A A<C B. A>C C<A B<A C>B\n8 events.\n1 message is never received.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 1\nClocks: A 0 ms, B -20 ms, C +15 ms from the true time; one event every 4 ms.\n  event  what                  true  wall  Lamport  vector\n  A1     sends m1 to B            4     4        1  (1,0,0)\n  C2     sends m2 to A            8    23        1  (0,0,1)\n  A3     receives m2 from C      12    12        2  (2,0,1)\n  B4     something happens       16    -4        1  (0,1,0)\n  A5     sends m3 to C           20    20        3  (3,0,1)\n  C6     receives m3 from A      24    39        4  (3,0,2)\n  B7     receives m1 from A      28     8        2  (1,2,0)\n  C8     sends m4 to B           32    47        5  (3,0,3)\nLamport: one more than the last count; a receive first takes the larger of its own count and the message's.\nVector: each person counts their own events and, on a receive, takes the larger of each count.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 2\n  true order       A1 C2 A3 B4 A5 C6 B7 C8\n  by wall clock    B4 A1 B7 A3 A5 C2 C6 C8   (ties by person)\n  by Lamport       A1 B4 C2 A3 B7 A5 C6 C8   (ties by person)\n8 events: of the 28 pairs, 16 are cause and effect - one could have led to the other - and 12 are concurrent.\nBy wall clock, 2 cause-and-effect pairs come out backwards; 1 is a message received before it was sent.\nBy Lamport, 0 come out backwards: a cause always gets the smaller count. But the order puts each of the 12 concurrent pairs one after the other too, as if one came first; only the vector clocks show which pairs are concurrent.\n\n1) timeline  2) orderings  3) two events  4) new events  5) clocks  6) quit\nchoice> 6\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "event-order-without-clock",
      "caseId": "237-event-order-without-clock",
      "title": "Most pairs right, and the ones that matter inverted"
    }
  ],
  "updated": "2026-10-15"
}
