\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[english]{babel}
\usepackage[a4paper, total={6in, 8in}]{geometry}
\usepackage{multicol}

\setlength{\parskip}{1em}

\title{Turing completeness of Mersenne Twister}
\date{2019}
\author{Kamila Szewczyk}

\begin{document}

\maketitle

\section{Introduction}
\par In this paper, I will demonstrate Mersenne Twister-generated programs being capable of interpreting a Turing-complete language. Mersenne Twister is so far the most widespread PRNG\footnote{Pseudorandom number generator} in use as of 2019. Mersenne Twister will be described as a component of Seed esoteric programming language.

\section{Seed programming language}
\par Seed is a language based on arbitrary seeds. Programs exclusively contain two instructions, that is, length and random seed separated by a space. To execute a Seed program, the seed is fed into a Mersenne Twister random number generator, and the randomness obtained is transformed into a string of length bytes, which will be executed by a Befunge-98 interpreter (or compiler).\footnote{https://esolangs.org/wiki/Seed - accessed 16.06.2019}.

\par An illustrational Seed program looks as follows and will generate 780 bytes long valid Befunge-98 code.

\begin{verbatim}
780 983247832
\end{verbatim}

\par \textit{Since standard Befunge is considered to be a finite state machine, it is, strictly speaking, not Turing-complete; thus, Seed cannot be Turing-complete either} - states Esolang Wiki\footnote{Before correction coerced by existence of this document}. Befunge-98 (the variant used by Seed) is compliant to Funge-98 standard. Wikipedia says:

\par The Befunge-93 specification restricts each valid program to a grid of 80 instructions horizontally by 25 instructions vertically. Program execution which exceeds these limits "wraps around" to a corresponding point on the other side of the grid; a Befunge program is in this manner topologically equivalent to a torus. Since a Befunge-93 program can only have a single stack and its storage array is bounded, the Befunge-93 language is not Turing-complete (however, it has been shown that Befunge-93 is Turing-complete with unbounded stack word size). The later Funge-98 specification provides Turing completeness by removing the size restrictions on the program; rather than wrapping around at a fixed limit, the movement of a Funge-98 instruction pointer follows a model dubbed "Lahey-space" after its originator, Chris Lahey. In this model, the grid behaves like a torus of finite size concerning wrapping, while still allowing itself to be extended indefinitely.\footnote{https://en.wikipedia.org/wiki/Befunge - accessed 16.06.2019}

\par This means, Befunge-98 \textbf{is} Turing complete, but Seed might not be, because we may not be able to generate \textbf{every} imaginable Befunge-98, because Mersenne Twister has a period of \begin{math}2^{19937} - 1\end{math}, but whether it was able to generate Befunge-98 program being interpreter of another Turing complete language, the proof would have been completed (as implied by thesis of simulation - \textit{If an interpreter for A can be implemented in B, then B can solve at least as many problems as A can.}).a

\section{ByteByteJump}
\par ByteByteJump is a remarkably simplistic One Instruction Set Computer (OISC). Its sole instruction copies a byte from the given memory location to another and then performs an unconditional branch towards a point. There are two reasonable ways to prove it's Turing-complete.

\par ByteByteJump is a variation of BitBitJump, that is operating on bits, not bytes, therefore proving BitBitJump is Turing complete can prove Turing-completeness of ByteByteJump. Using BitBitJump assembler and standard library\footnote{http://mazonka.com/bbj/bbjasm.cpp and http://mazonka.com/bbj/lib.bbj - accessed 16.06.2019}, it's possible to create a Brainfuck interpreter:

\begin{verbatim}
    # BitBitJump brainfuck (DBFI) interpreter by O. Mazonka
    Z0:0 Z1:0 start
    .include lib.bbj
    :mem:0 0 0
    mem mem
    ip_start:mem ip:mem ip_end:0
    mp_start:0 mp:0 mp_end:0
    x:0 y:0 m1:-1
    SPACE:32 MINUS:45 PLUS:43
    TICK:39 EOL:10 Excl:33
    LEFT:60 RIGHT:62 LB:91
    RB:93 DOT:46 COMMA:44
start:    .copy ZERO x
    .in x
    .ifeq x ZERO initgl chkex
chkex:    .ifeq x Excl initgl storei
storei:    .toref x ip
    .add ip BASE ip
    0 0 start
initgl:    .copy ip ip_end
    .copy ip mp_start
    .copy ip mp
    .copy ip mp_end
    .add mp_end BASE mp_end
    .copy ip_start ip
loop:    0 0
    .deref ip x
    .ifeq x PLUS plus chk_ms
plus:    .plus
    0 0 next_ip
chk_ms: .ifeq x MINUS minus chk_lt
minus:    .minus
    0 0 next_ip
chk_lt:    .ifeq x LEFT left chk_rt
left:    .left
    0 0 next_ip
chk_rt: .ifeq x RIGHT right chk_dt
right:    .right
    0 0 next_ip
chk_dt: .ifeq x DOT dot chk_cm
dot:    .deref mp x
    .out x
    0 0 next_ip
chk_cm: .ifeq x COMMA comma chk_lb
comma:    .copy ZERO x
    .in x
    .toref x mp
    0 0 next_ip
chk_lb: .ifeq x LB lb chk_rb
lb:    .lb
    0 0 next_ip
chk_rb: .ifeq x RB rb next_ip
rb:    .rb
    0 0 next_ip
next_ip: 0 0
    .add ip BASE ip
    .ifeq ip ip_end exit loop
exit:    0 0 -1
    .def plus : mp x
    .deref mp x
    .inc x
    .toref x mp
    .end
    .def minus : mp x
    .deref mp x
    .dec x
    .toref x mp
    .end
    .def right : mp BASE mp_end x ZERO
    .add mp BASE mp
    .iflt mp mp_end ret incend
incend: .add mp_end BASE mp_end
    .copy ZERO x
    .toref x mp
ret:    0 0
    .end
    .def left : mp BASE
    .sub mp BASE mp
    .end
    .def lb : ip mp x y ZERO ONE BASE LB RB
    .deref mp x
    .ifeq x ZERO gort ret
gort:    .copy ONE y
loop:    .add ip BASE ip
    .deref ip cmd
    .ifeq cmd LB incy chk_rb
chk_rb: .ifeq cmd RB decy loop

incy:    .inc y
    0 0 loop
decy:    .dec y
    .iflt ZERO y loop ret
    cmd:0 0
ret:    0 0
    .end
    .def rb : ip mp x y ZERO ONE BASE LB RB
    .deref mp x
    .ifeq x ZERO ret golt
golt:    .copy ONE y
loop:    .sub ip BASE ip
    .deref ip cmd
    .ifeq cmd RB incy chk_lb
chk_lb: .ifeq cmd LB decy loop
incy:    .inc y
    0 0 loop
decy:    .dec y
    .iflt ZERO y loop ret

    cmd:0 0
ret:    0 0
    .end
    .def dump : ip_start x y BASE ip_end mp_start mp_end SPACE ip mp TICK EOL
    .copy ip_start y
dumpi:    .deref y x
    .out x
    .ifeq y ip outi noi
outi:    .out TICK
noi:    .add y BASE y
    .ifeq y ip_end dumpmst dumpi
dumpmst: 0 0
    .copy mp_start y
dumpm:    .deref y x
    .out SPACE
    .ifeq y mp outm nom
outm:    .out TICK
nom:    .prn x
    .add y BASE y
    .ifeq y mp_end ret dumpm
ret:     .out EOL
    .end
\end{verbatim}

\par To prove that Brainfuck is Turing-complete (we don't actually have to, because this has been proven before, but for the sake of consistency, the proof will be included), we will use the same rule. Daniel B. Cristofani wrote a generic Turing machine emulator, that I may use as a part of my proof:

\begin{verbatim}
+++>++>>>+[>>,[>+++++<[[->]<<]<[>]>]>-[<<+++++>>-[<<---->>-[->]<]]<[
<-<[<]+<+[>]<<+>->>>]<]<[<]>[-[>++++++<-]>[<+>-]+<<<+++>+>[-[<<+>->-
[<<[-]>>-[<<++>+>-[<<-->->>+++<-[<<+>+>>--<-[<<->->-[<<++++>+>>+<-[>
-<-[<<->->-[<<->>-[<<+++>>>-<-[<<---->>>++<-[<<++>>>+<-[>[-]<-[<<->>
>+++<-[<<->>>--<-[<<++++>+>>+<-[<<[-]>->>++<-[<<+++++>+>>--<-[<->>++
<[<<->>-]]]]]]]]]]]]]]]]]]]]]]<[->>[<<+>>-]<<<[>>>+<<<-]<[>>>+<<<-]]
>>]>[-[---[-<]]>]>[+++[<+++++>--]>]+<++[[>+++++<-]<]>>[-.>]
\end{verbatim}

\par This means, Brainfuck and BitBitJump are Turing-complete and may prove that ByteByteJump is Turing-complete too. One could argue here, how does the property of BitBitJump coerce property of ByteByteJump (albeit the only difference between them is copy size). This statement might be completely right, so I've prepared another way to prove this using Subleq as a part of my proof. It's possible to simulate one Subleq instruction tick in ByteByteJump (the solution has been partly presented by Esolang wiki). Suppose we have the following values stored in memory:

\begin{verbatim}
Address        | Value
---------------+------
000800..00087F | 01
000880..0008FF | 02
01XXYY         | XX
02XXYY         | YY
03XXYY         | XX-YY
\end{verbatim}

\par Then the following ByteByteJump program (using 3-byte addresses) will take the byte value at address 100h, subtract the byte value at address 200h, store the resulting byte value at address 300h, and jump to address 400h if the result was negative (>= 80h).

\begin{verbatim}
Big-endian version           | Little-endian version
-----------------------------+-----------------------------
000000: 000100 000013 000009 | 000000: 000100 000013 000009
000009: 000200 000014 000012 | 000009: 000200 000012 000012
000012: 030000 000300 00001B | 000012: 030000 000300 00001B
00001B: 000300 000026 000024 | 00001B: 000300 000024 000024
000024: 000800 00002D 00002D | 000024: 000800 00002F 00002D
00002D: 003F36 000035 000000 | 00002D: 003F36 000033 000000
000036: 000000 000000 000400 | 000036: 000000 000000 000400
00003F: ...... ...... ...... | 00003F: ...... ...... ......
\end{verbatim}

\par Below is the previous ByteByteJump example rewritten in ByteByte/Jump machine code.

\begin{verbatim}
Big-endian version           | Little-endian version
-----------------------------+-----------------------------
000000: 000100 00000D        | 000000: 000100 00000D
000006: 000200 00000E        | 000006: 000200 00000C
00000C: 030000 800300 000017 | 00000C: 030000 800300 000015
000015: 000800 00001B        | 000015: 000800 00001D
00001B: 002724 000023        | 00001B: 002724 000021
000021: 800000               | 000021: 800000
000024: 800400               | 000024: 800400
000027: ......               | 000027: ......
\end{verbatim}

\par The ByteByteJump version takes up 63 bytes, while the ByteByte/Jump version takes up 39 bytes. At address 00000C in the ByteByte/Jump program, notice the use of multiple (in this case 2) destinations for the move instruction. This proves that ByteByteJump can compute as much as Subleq can, therefore whether Subleq is Turing-complete, ByteByteJump is too.

\par This Subleq assembly \footnote{http://mazonka.com/subleq/sqasm.cpp - accessed 16.06.2019} program is emulating Brainfuck interpreter:

\begin{verbatim}
    top:top top sqmain

_interpret:
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; bp 0
    bp; sp bp
    c2 sp
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t1 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t2 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t3 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t4 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t5 0

    t1; t2; bp t1; c1 t1; t1 t2
    t1; t3; bp t1; c2 t1; t1 t3
    ?+23; ?+21; ?+24; t3 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; t2 Z; Z 0; Z

    t1; t2; bp t1; c4 t1; t1 t2
    ?+23; ?+21; ?+24; t2 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; c3 Z; Z 0; Z
l1:
    t2; t1; bp t2; c5 t2; t2 t1
    t2; t3; ?+11; t1 Z; Z ?+4; Z; 0 t2; t2 t3
    t1; t2; bp t1; c4 t1; t1 t2
    t1; t4; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t4
    t2; t1; t3 t2; t4 t2; t2 t1
    t2; t4; ?+11; t1 Z; Z ?+4; Z; 0 t2; t2 t4
    t1; t4 Z; Z t1 ?+3; Z Z ?+9; Z; t4 t1; t4 t1
    Z t1 l3
    t2; t4; bp t2; c5 t2; t2 t4
    t2; t3; ?+11; t4 Z; Z ?+4; Z; 0 t2; t2 t3
    t4; t2; bp t4; c4 t4; t4 t2
    t4; t5; ?+11; t2 Z; Z ?+4; Z; 0 t4; t4 t5
    t2; t4; t3 t2; t5 t2; t2 t4
    t2; t5; ?+11; t4 Z; Z ?+4; Z; 0 t2; t2 t5
    t4; t2; bp t4; dec t4; t4 t2
    ?+23; ?+21; ?+24; t2 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; t5 Z; Z 0; Z

    t2; t3; bp t2; dec t2; t2 t3
    t2; t5; ?+11; t3 Z; Z ?+4; Z; 0 t2; t2 t5
    t3; t5 Z; Z t3; Z; c14 t3 ?+3
    t3 t3 ?+9; t3 Z ?+3; Z Z ?+3; inc t3
    Z t3 l21
    t1; t2; bp t1; c2 t1; t1 t2
    t2 Z; ?+9; Z ?+5; Z; inc 0

    Z Z l22
l21:
    t5; t2; bp t5; dec t5; t5 t2
    t5; t3; ?+11; t2 Z; Z ?+4; Z; 0 t5; t5 t3
    t2; t3 Z; Z t2; Z; c13 t2 ?+3
    t2 t2 ?+9; t2 Z ?+3; Z Z ?+3; inc t2
    Z t2 l19
    t1; t2; bp t1; c2 t1; t1 t2
    t2 Z; ?+9; Z ?+5; Z; dec 0

    Z Z l20
l19:
    t3; t5; bp t3; dec t3; t3 t5
    t3; t2; ?+11; t5 Z; Z ?+4; Z; 0 t3; t3 t2
    t5; t2 Z; Z t5; Z; c12 t5 ?+3
    t5 t5 ?+9; t5 Z ?+3; Z Z ?+3; inc t5
    Z t5 l17
    t1; t2; bp t1; c2 t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t3 Z; ?+9; Z ?+5; Z; inc 0

    Z Z l18
l17:
    t2; t3; bp t2; dec t2; t2 t3
    t2; t5; ?+11; t3 Z; Z ?+4; Z; 0 t2; t2 t5
    t3; t5 Z; Z t3; Z; c11 t3 ?+3
    t3 t3 ?+9; t3 Z ?+3; Z Z ?+3; inc t3
    Z t3 l15
    t1; t2; bp t1; c2 t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t3 Z; ?+9; Z ?+5; Z; dec 0

    Z Z l16
l15:
    t5; t2; bp t5; dec t5; t5 t2
    t5; t3; ?+11; t2 Z; Z ?+4; Z; 0 t5; t5 t3
    t2; t3 Z; Z t2; Z; c10 t2 ?+3
    t2 t2 ?+9; t2 Z ?+3; Z Z ?+3; inc t2
    Z t2 l13
    t1; t2; bp t1; c2 t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t2; t1; ?+11; t3 Z; Z ?+4; Z; 0 t2; t2 t1
    t1 (-1)

    Z Z l14
l13:
    t3; t5; bp t3; dec t3; t3 t5
    t3; t2; ?+11; t5 Z; Z ?+4; Z; 0 t3; t3 t2
    t5; t2 Z; Z t5; Z; c9 t5 ?+3
    t5 t5 ?+9; t5 Z ?+3; Z Z ?+3; inc t5
    Z t5 l11
    t1; (-1) t1
    t2; t3; bp t2; c2 t2; t2 t3
    t2; t4; ?+11; t3 Z; Z ?+4; Z; 0 t2; t2 t4
    ?+23; ?+21; ?+24; t4 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; t1 Z; Z 0; Z

    Z Z l12
l11:
    t1; t2; bp t1; dec t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t2; t3 Z; Z t2; Z; c7 t2 ?+3
    t2 t2 ?+9; t2 Z ?+3; Z Z ?+3; inc t2
    t3; Z t2 l9
    t1; t4; bp t1; c2 t1; t1 t4
    t1; t5; ?+11; t4 Z; Z ?+4; Z; 0 t1; t1 t5
    t4; t1; ?+11; t5 Z; Z ?+4; Z; 0 t4; t4 t1
    t5; t1 Z; Z t5 ?+3; Z Z ?+9; Z; t1 t5; t1 t5
    Z t5 l9; inc t3;
l9:
    Z t3 l10
    t1; t2; bp t1; c6 t1; t1 t2
    ?+23; ?+21; ?+24; t2 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; dec Z; Z 0; Z

l4:
    t1; t2; bp t1; c6 t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t2; t3 Z; Z t2; Z; c3 t2
    Z t2 l5
    t1; t2; bp t1; c5 t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t2; t1; bp t2; c4 t2; t2 t1
    t1 Z; ?+9; Z ?+5; Z; dec 0
    t2; t4; ?+11; t1 Z; Z ?+4; Z; 0 t2; t2 t4
    t1; t2; t3 t1; t4 t1; t1 t2
    t1; t4; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t4
    t2; t1; bp t2; dec t2; t2 t1
    ?+23; ?+21; ?+24; t1 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; t4 Z; Z 0; Z

    t2; t3; bp t2; dec t2; t2 t3
    t2; t1; ?+11; t3 Z; Z ?+4; Z; 0 t2; t2 t1
    t3; t1 Z; Z t3; Z; c8 t3 ?+3
    t3 t3 ?+9; t3 Z ?+3; Z Z ?+3; inc t3
    Z t3 l7
    t1; t2; bp t1; c6 t1; t1 t2
    t2 Z; ?+9; Z ?+5; Z; dec 0

    Z Z l8
l7:
    t1; t2; bp t1; dec t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t2; t3 Z; Z t2; Z; c7 t2 ?+3
    t2 t2 ?+9; t2 Z ?+3; Z Z ?+3; inc t2
    Z t2 l6
    t1; t2; bp t1; c6 t1; t1 t2
    t2 Z; ?+9; Z ?+5; Z; inc 0

l6:
l8:

    Z Z l4
l5:

l10:
l12:
l14:
l16:
l18:
l20:
l22:

l2:
    t4; t2; bp t4; c4 t4; t4 t2
    t2 Z; ?+9; Z ?+5; Z; inc 0
    Z Z l1
l3:

    ?+8; sp ?+4; t5; 0 t5; inc sp
    ?+8; sp ?+4; t4; 0 t4; inc sp
    ?+8; sp ?+4; t3; 0 t3; inc sp
    ?+8; sp ?+4; t2; 0 t2; inc sp
    ?+8; sp ?+4; t1; 0 t1; inc sp
    sp; bp sp
    ?+8; sp ?+4; bp; 0 bp; inc sp
    ?+8; sp ?+4; ?+7; 0 ?+3; Z Z 0

_main:
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; bp 0
    bp; sp bp
    c15 sp
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t1 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t2 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t3 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t4 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t5 0
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; t6 0

    t1; t2; bp t1; c15 t1; t1 t2
    ?+23; ?+21; ?+24; t2 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; dec Z; Z 0; Z

l23:
    t1; t2; bp t1; c15 t1; t1 t2
    t1; t3; ?+11; t2 Z; Z ?+4; Z; 0 t1; t1 t3
    t2; t3 Z; Z t2 ?+3; Z Z ?+9; Z; t3 t2; t3 t2
    Z t2 l25
    t3; (-1) t3
    t1; t4; bp t1; dec t1; t1 t4
    t1; t5; bp t1; c16 t1; t1 t5
    t1; t6; ?+11; t5 Z; Z ?+4; Z; 0 t1; t1 t6
    t5 Z; ?+9; Z ?+5; Z; inc 0
    t5; t1; t4 t5; t6 t5; t5 t1
    ?+23; ?+21; ?+24; t1 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; t3 Z; Z 0; Z

    t2; t1; bp t2; dec t2; t2 t1
    t2; t3; bp t2; c16 t2; t2 t3
    t2; t4; ?+11; t3 Z; Z ?+4; Z; 0 t2; t2 t4
    t3; t4 Z; Z t3; Z; dec t3
    t4; t2; t1 t4; t3 t4; t4 t2
    t4; t3; ?+11; t2 Z; Z ?+4; Z; 0 t4; t4 t3
    t2; t3 Z; Z t2; Z; c17 t2 ?+3
    t2 t2 ?+9; t2 Z ?+3; Z Z ?+3; inc t2
    t3; inc t3; Z t2 ?+3; Z Z l26
    t4; t1; bp t4; dec t4; t4 t1
    t4; t5; bp t4; c16 t4; t4 t5
    t4; t6; ?+11; t5 Z; Z ?+4; Z; 0 t4; t4 t6
    t5; t6 Z; Z t5; Z; dec t5
    t6; t4; t1 t6; t5 t6; t6 t4
    t6; t5; ?+11; t4 Z; Z ?+4; Z; 0 t6; t6 t5
    t4; t5 Z; Z t4; Z; c18 t4 ?+3
    t4 t4 ?+9; t4 Z ?+3; Z Z ?+3; inc t4
    Z t4 ?+3; Z Z l26; t3;
l26:
    Z t3 l27
    t1; t2; bp t1; c15 t1; t1 t2
    ?+23; ?+21; ?+24; t2 Z; Z ?+10; Z ?+8
    Z ?+11; Z; 0; c3 Z; Z 0; Z
l27:

l24:
    Z Z l23
l25:

    t1; t2; bp t1; dec t1; t1 t2
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+9; sp ?+5; t2 Z; Z 0; Z
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; ?+2 0 _interpret; . ?;
    c5 sp

    ?+8; sp ?+4; t6; 0 t6; inc sp
    ?+8; sp ?+4; t5; 0 t5; inc sp
    ?+8; sp ?+4; t4; 0 t4; inc sp
    ?+8; sp ?+4; t3; 0 t3; inc sp
    ?+8; sp ?+4; t2; 0 t2; inc sp
    ?+8; sp ?+4; t1; 0 t1; inc sp
    sp; bp sp
    ?+8; sp ?+4; bp; 0 bp; inc sp
    ?+8; sp ?+4; ?+7; 0 ?+3; Z Z 0

sqmain:
    dec sp; ?+11; sp ?+7; ?+6; sp ?+2; 0
    ?+6; sp ?+2; ?+2 0 _main; . ?; inc sp

    Z Z (-1)

. c5:-2 c3:0 c17:10 c18:13 c4:2 c2:20 c6:3 c1:4 c12:43 c9:44 c11:45 c10:46 c16:501
 (wrapped) c15:502 c13:60 c14:62 c8:91 c7:93

. t1:0 t2:0 t3:0 t4:0 t5:0 t6:0

. inc:-1 Z:0 dec:1 ax:0 bp:0 sp:-sp

\end{verbatim}

\par The interpreter was built by translating the following C code \footnote{https://gist.github.com/maxcountryman/1699708 - accessed 16.06.2019}\footnote{Please note that the code was modified to run smoothly on the Subleq virtual machine}:

\begin{verbatim}

void interpret(char * input) {
    char current_char;
    int i, loop;
    unsigned char tape[16] = {0};
    unsigned char * ptr = tape;

    for (i = 0; input[i] != 0; i++) {
        current_char = input[i];
        if (current_char == '>') {
            ++ptr;
        } else if (current_char == '<') {
            --ptr;
        } else if (current_char == '+') {
            ++*ptr;
        } else if (current_char == '-') {
            --*ptr;
        } else if (current_char == '.' ) {
            putchar(*ptr);
        } else if (current_char == ',') {
            *ptr = getchar();
        } else if (current_char == ']' && *ptr) {
            loop = 1;
            while (loop > 0) {
                current_char = input[--i];
                if (current_char == '[') {
                    loop--;
                } else if (current_char == ']') {
                    loop++;
                }
            }
        }
    }
}

int main(void) {
    char buf[500], c, r = 1;

    while(r) {
        buf[c++] = getchar();
        if(buf[c-1] == 10 || buf[c-1] == 13)
            r = 0;
    }

    interpret(buf);
}

\end{verbatim}

\par It's able to hold up to 500 program bytes (just enough to simulate Cristofani's Turing machine emulator) and 16 memory cells. That may not be enough, but the size can be flexibly changed. The resulting Subleq code is quite large\footnote{https://pastebin.com/TEgwuLsb - accessed 16.06.2019}, scoring 16 kilobytes. Turing-completeness of Brainfuck has been proven before, therefore to prove Turing-completeness of Seed, it's required to create ByteByteJump interpreter in Befunge-98, and then transform it to Seed.

\section{Proof}

\par The following code ByteByteJump interpreter I wrote will be a reference for the later code.

\begin{verbatim}

a[99], b, c;

main() {
    for (; b<99; b++)
        scanf("%d",&a[b]);

    for (; !c<0; c++) {
        if (a[c]<0)
            a[c]=getchar();
        if (a[c+1]<0)
            putchar(a[c+1]);

        a[c+1]=a[c];
        c=a[c+2]
    }
}

\end{verbatim}

\par If elements were listed in counter-order they are pushed, A is equal to \verb|*(pc)| and is first, B is second and is equal to \verb|*(pc+1)| and C is third and is equal to \verb|*(pc+2)|, following Befunge-98 code will perform ByteByteJump instruction tick\footnote{If anything is wrong, please contact me!}:

\begin{verbatim}
v@0~$<
>:0`!|
v`0:\<
>!v  >'$\@
 v_$:^
 >:,0@
\end{verbatim}

\par The problem here is, the registers are immutable, so the place marked with apostrophe needs to implement some kind of storing register values once again.

\par Finally, the Seed code looks such:

\begin{verbatim}
45 14759728162827650584261424512858419005895877927172867170454220018091585985218474762085902733083826251068059609943840519086988076725884395078958794589042745844886106737592949672910353236907359852709093987545679606304425294765684113310391644389491473874560494776640825185411773361155300990850990369822774005176483867432996215272027868894139015703661427796383218596643499838024600655267054692077718540006877263234406979709965241888952618635321321208845458897466631763534810697993568024079129009014941717107557749850564913191661936458586791739377099530930665851468123296351748653781604913119842237411431221626790962751759928247159216436029135498781816145088780705956836618591144442152298379911771295380097462622609168342975911282939759146112865525842040088817955297926164925615287661053316861798127949983775282031545922749806825796571445652740663670545560943568367423856852634278745004342889968051785597832691204510364156575938067476085840495286933849301115231982995187446070355779282089315967458189921803153224641148350866868257788744081402232403400711780387718519011111200967606135859543595263220815717197125830578268807358371833098371448008987559913512056549120127899229363310257363705314682567898390346045689433922715130292374612103956330338234861230990694586628265712470559593219283799436217571334957194959074669358658281391263056088488615331631452088523163515312452667038411917983414222123152730195377822358717411280906290886132046223328553038872108648948685488002500392984258285670521772804200662659718966456688876707641239629764848140937577253734040416849333193209649495220839702240907687512366410404087159627475379507345483004656095914509595092592120744656029237521082380179633388759623932188746800676984948521469106535310244217239583470570828803144516575127575089541478487922869779458209619336688186293695781377232277852611840232096700715633434197235834172838066028298830539913298306562514079385583731530757687828830907931798968104273845421897680841931576575087807519612468427165214877925085362091308710344651493555326224269698020480102462098256214986612141204479950556249394957442729389916010310182484274229352308820327006866942728488835606164637637633384718157300716252802652831838292234455707099676310073946863509964330217577169726701119348589720903741735572590366753719975895356329798071254491342578606726886141228042235257952531167961035578401495446221035361455922519112517889696295907775856705173027935074881118221087955117283937630856640793386766158293318615583730085027846784366868909369106808701104715722810500352454700914118029382959923358201445770970530666384355236832284094858532979170175756493007083906372644947560502353750754104302433701657580319092649840713979529812938814823925444798691334898598601146996395667795616170894691019054564074499975646803699897858088188313547316799111829684537185669892339221485677675166394826538857356814611751087893422989500851252629265875041469005811478084658567757370493665254592190823074542933682487829202595662621724452779251016027845895376028170579041932919481628080095629700032329787577143431192413451059712145551005939179044075862878906696021238739506411122443976682274624503571069996651479567989030425139112053833195908709151452004833258943574098970080890242640710070032975540839763183356852965214952357408266397728041511478072911230530244247907641069188061548305981383288128249331680198741748360627007816561767408742470481838381203893287614662112423409172348680385845390436099186557158672446334565132794752214400565827293803272736638564580506051589204633022041245405644152844659377221167748975568757447900272588474217704585524410543455964290418303932516603192571531287464415931331557591203544702454312952663503639045304171177352543695971502657427679707817721788634603796757417783506559846731593877742404831352318677733816759718954567808593383221001679980932944637605082351078698480553524545469821458050409523938776302095284681311262044832291240798766331974504930691414248001099351825049467763278744099794384818618977532714400021702189807167336416774058995168777870770845307953994434957294550201432709796418079546060877975637811950449504681591832920381747003330383781144995956196613741607984785058262544627281237473002709018507914858905688936051131180658658054472581624787619810612875188699804432540657015668871280687303625216211285787804946220183255872567236414553614612979498889469153759765356621415952951601274027203523552356791975536845321748690233721107078460523591423868819502798793977124457663120971769418752973257093040836935902874779532902222015990433319033910492790853337934335060015613618517834944339433722887709414582825378038896641610301341802483978813619717734
\end{verbatim}

And it's \textbf{4 637 bytes} big. Given all these step-by-step chaining lemmas, the final and proven thesis is, Seed language is Turing-complete, and Mersenne Twister can generate valid Befunge-98 program, that will be capable of simulating any algorithm's logic can be constructed.

\section{How did the reversing happen?}

\par The reversal has been done step by step - first, my generator was very naive, so the program size was quite large, then I've managed to reverse Mersenne Twister in an even more efficient way, and finally, I've managed to write a pruning bruteforce program, that generated such piece of code as above. There are a couple of ways to bruteforce a program (the most common one is a naive bruteforce, a quite slow one).

\section{Sources}

\par This paper wouldn't be possible to write (or be significantly harder to) without work of Oleg Mazonka (his BitBitJump, ByteByteJump and Subleq work), Daniel B. Cristofani (for his Brainfuck universal Turing machine emulator), Esolang Wiki and Wikipedia proofreaders and content creators (for great explaining, a lot of effort and time put into the wiki), Mersenne Twister crackers preceding me (it would be significantly harder to get such score on my crack), Chris Pressey (for Befunge),

\end{document}


\section{AEROSOL PARTICLE MEASUREMENTS\label{sec:AEROSOL-PARTICLE-MEASUREMENTS}}

\subsection{Condensation Nucleus Counters}

RAF uses two modified TSI, Inc. \href{http://www.eol.ucar.edu/instruments/condensation-nucleus-counter-water-or-butanol}{condensation nucleus counters}\index{condensation nucleus counter|see {CN counter}}\index{CN counter}\index{concentration!aerosol}\index{concentration!ultrafine particles}
to measure the total concentration of ultrafine particles\index{particles!ultrafine}
in the atmosphere, a 3760A\index{CN counter!3760A} using n-butyl
alcohol and a water-based 3786\index{CN counter!3786} WCN (water
condensation nucleus) counter. Both are sensitive to particles in
the approximate diameter range from 0.010--3~\textgreek{m}m. \\

\begin{hangparagraphs}
\textbf{CN Counter Inlet Pressure (hPa):}\nop{PCN}{}\textbf{ }\textbf{\uline{PCN}}\sindex[var]{PCN}\index{PCN}\\
\emph{The absolute pressure inside the inlet tube of the instrument.}
It\index{pressure!inlet} as measured by a Heise Model 623 pressure
sensor for the 3760A, and internally by the 3786 WCN.. The measurement
is used to convert the measured mass flow (FCN or XICN) to volumetric
flow and to convert measured particle concentration to equivalent
ambient concentration.

\textbf{CN Counter Inlet Temperature ($^{\circ}$C):}\nop{CNTEMP}{}\nop{TEMP1}{}\nop{TEMP2}{}\textbf{
}\textbf{\uline{CNTEMP}}\sindex[var]{CNTEMP}\index{CNTEMP}\uline{,}
\textbf{\uline{TEMP1}}\sindex[var]{TEMP1}\textbf{\index{TEMP1},
}\textbf{\uline{TEMP2}}\sindex[var]{TEMP2}\textbf{\index{TEMP2}}\\
\emph{The sample air temperature measured at the intake of the 3760A
or within the 3786.} The value\index{temperature!inlet} is used to
convert the measured mass flow (FCN or XICN) to true volumetric flow
and to convert measured particle concentration to equivalent ambient
concentration.\index{concentration!ambient}

\textbf{}%
\noindent\begin{minipage}[t]{1\columnwidth}%
\textbf{Raw CN Counter Sample Flow Rate (SLPM):}\nop{FCN}{}\textbf{
}\textbf{\uline{FCN}}\sindex[var]{FCN}\index{FCN}\\
\textbf{Corrected CN Counter Sample Flow Rate (VLPM):}\nop{FCNC}{}\textbf{
}\textbf{\uline{FCNC}}\sindex[var]{FCNC}\textbf{\uline{\index{FCNC}}}%
\end{minipage}\\
\emph{The raw and corrected sample flows in the CN counters} are treated
differently for the two models of CN counter. In the 3760A, FCN is
measured in standard liters per minute (SLPM) with a mass flow meter.
The flow meter gives the volumetric flow rate that would apply under
standard conditions of 1013.25~hPa and 21$^{\circ}$C.\index{CN counter!flow rate}
FCNC is the corrected sample flow rate in volumetric liters per minute
(VLPM) \emph{at instrument pressure and temperature}. For the 3760A:\\
\fbox{\begin{minipage}[t]{0.9\textwidth}%
PCN = pressure at the inlet to the CN counter (hPa)\\
CNTEMP = temperature at the inlet of the sample tube ($^{\circ}$C)\\
$p_{std}$ = \sindex[lis]{Pstd@$p_{std}$=standard pressure}standard
reference pressure, 1013.25~hPa\\
$T_{std}$ = \sindex[lis]{Tstd@$T_{std}$=standard temperature}standard
reference temperature, 294.15 K \\
$T_{0}$ = 273.15~K\\
\\
\rule[0.5ex]{1\linewidth}{1pt}
\[
\mathrm{FCNC=\{FCN\}}\frac{p_{std}}{\mathrm{\{PCN\}}}\frac{(\{\mathrm{CNTEMP\}}+T_{0})}{T_{std}}
\]
%
\end{minipage}}\\
In the 3786, flows are determined in volumetric cm$^{3}\thinspace\mathrm{min}^{-1}$
from the pressure drop across an orifice. The 3786 firmware makes
density corrections internally, so its reported sample flow is brought
directly into the variable FCNC in units of VLPM.\\
\vfill\eject

\noindent\begin{minipage}[t]{1\columnwidth}%
\textbf{Raw CN Isokinetic Side Flow Rate (SLPM):}\nop{XICN}{}\textbf{
}\textbf{\uline{XICN}}\sindex[var]{XICN}\index{XICN}\\
\textbf{Corrected CN Isokinetic Side Flow Rate (VLPM):}\nop{XICNC}{}\textbf{
}\textbf{\uline{XICNC}}\sindex[var]{XICNC}\textbf{\uline{\index{XICNC}}}%
\end{minipage}\\
\emph{XICN is the raw isokinetic side flow rate in standard liters
per minute (SLPM) measured with a mass flow meter, and XICNC is that
flow corrected for pressure and temperature to be the true volumetric
flow.} The side flow\index{CN counter!side flow} is adjusted for
isokinetic sampling at the inlet, but it is not used further in processing.
\\
\fbox{\begin{minipage}[t]{0.9\textwidth}%
XICN = side-flow rate (SLPM)

PCN = pressure at the inlet to the CN counter (hPa)\\
CNTEMP = temperature at the inlet of the sample tube ($^{\circ}$C)\\
$p_{std}$ = standard reference pressure, 1013.25 mb\\
$T_{std}$\sindex[lis]{Tr@$T_{std}$= absolute reference temperature, STP}
= 294.15 K \\
$T_{0}$ = 273.15~K\\
\\
\rule[0.5ex]{1\linewidth}{1pt}
\[
\mathrm{XICNC=\{XICN\}}\frac{p_{std}}{\mathrm{\{PCN\}}}\frac{(\{\mathrm{CNTEMP\}}+T_{0})}{T_{std}}
\]
%
\end{minipage}}\\

\textbf{CN Counter Output (counts per sample interval):}\nop{CNTS}{}\textbf{
}\textbf{\uline{CNTS}}\sindex[var]{CNTS}\index{CNTS}\\
\emph{The raw output count from the condensation nucleus counter.}
For the 3760A condensation nucleus counter, the project-dependent
sample rate may be chosen in the range from 1--50~Hz but it is typically
10~Hz. In some unusual cases the counts are divided by a selected
power of two to keep the counter from overflowing; see project documentation.
The 3786 WCN may be programmed to report data at intervals from 0.1--3600~s.\label{punch:7-1}

\textbf{Condensation Nucleus (CN) Concentration (cm$^{-3}$):}\nop{CONCN}{}\textbf{
}\textbf{\uline{CONCN}}\sindex[var]{CONCN}\index{CONCN}\\
\emph{The number concentration of condensation nuclei} in units of
particles per cm$^{3}$ \emph{in the ambient air} at flight level.\emph{
}The calculation leading to CONCN\index{concentration!CN} includes
two corrections. The first\index{CN counter!coincidence in} accounts
for coincidence of particles in the viewing volume at high concentrations
and is handled differently in the two types of CN counter. For the
3760A, a statistical adjustment is made based on the average time
of a particle in the viewing volume. This correction increases from
about 1\% at a total concentration of 10$^{3}$~cm$^{-3}$ to nearly
11\% at 10$^{4}$~cm$^{-3}$, but for concentrations above about
2\texttimes 10$^{4}$~cm$^{-3}$ significant uncertainty remains.
The 3786 instead measures the time each detected particle occupies
the viewing volume, and this\emph{ }accumulated \textquotedblleft dead
time\textquotedblright \index{CN counter!dead time} in each sampling
interval is subtracted from the elapsed time yielding a \textquotedblleft live
time\textquotedblright{} for the determination of sample volume. With
this correction an accuracy of 12\%, not including statistical counting
error, is specified by the manufacturer at concentrations up to 10$^{5}$~cm$^{-3}$.
The second correction, applied to all CN counters, is a conversion
from instrument to ambient conditions.\footnote{Prior to Dec.~2007 the conversion to ambient concentration was not
made and concentration was reported for instrument conditions.} In the following formulae, the corrected flow FCNC in VLPM is explicitly
converted to cm$^{3}$s$^{-1}$ by the factor (1000/60).\emph{}\\
\emph{}\\
\noindent\begin{minipage}[t]{1\columnwidth}%
\textbf{For the 3760A:}\\
\fbox{\begin{minipage}[t]{0.9\textwidth}%
CNTS = particle counts per sample interval from the CN counter\index{CNTS}\\
$\Delta t$ = \sindex[lis]{Deltat@$\Delta t$=time interval}interval
between recorded samples (s)\\
$D$ = scale factor (legacy; normally 1)\\
$C_{flow}$ = \sindex[lis]{Cflow@$C_{flow}$ = flow conversion factor}conversion
factor, (1000/60) cm$^{3}$L$^{-1}$min s$^{-1}$\\
FCNC = corrected sample flow rate (VLPM) for instrument conditions\index{FCNC}\\
$t_{vv}$ = average time a particle is in the view volume = 0.4$\times10^{-6}$~s\\
PCN = pressure at the inlet to the CN counter (hPa)\index{PCN}\\
CNTEMP = temperature at the inlet of the sample tube ($^{\circ}$C)\index{CNTEMP}\\
PSXC = corrected ambient pressure (hPa)\index{PSXC}\\
ATX = ambient temperature ($^{\circ}$C)\index{ATX}\\
$T_{0}$ = 273.15~K\\
\\
\rule[0.5ex]{1\linewidth}{1pt}
\[
\mathrm{A=\frac{\{CNTS\}}{\mathrm{(\{FCNC\}\times C_{flow})}\Delta t}\,D}
\]
The flow under instrument conditions, corrected for coincidence, is
then\\
\[
B\mathrm{=A}\,e^{At_{vv}(\mathrm{\{FCNC\}\times C_{flow})}}
\]
and the concentration under ambient conditions is\index{CONCN}\\

\begin{equation}
\mathrm{\{CONCN\}}=B\frac{\mathrm{\{PSXC\}}}{\mathrm{\{PCN\}}}\frac{\mathrm{(\{CNTEMP\}}+T_{0})}{(\mathrm{\{ATX\}}+T_{0})}\label{eq:12.1}
\end{equation}
%
\end{minipage}} %
\end{minipage}\\
\\
\noindent\begin{minipage}[t]{1\columnwidth}%
\textbf{For the 3786 WCN:}\\
\fbox{\begin{minipage}[t]{0.9\textwidth}%
CNTS = particle counts per sample interval from the CN counter\\
$\Delta t$ = \sindex[lis]{Deltat@$\Delta t$=time interval}interval
between recorded samples (s)\\
$t_{d}$ = cumulative dead time during the sampling interval (s)\\
$C_{flow}$ {[}see preceding box{]}\\
FCNC = corrected sample flow rate (VLPM) for instrument conditions\\
PCN = internal pressure of the CN counter (hPa)\\
CNTEMP = temperature of the optics block ($^{\circ}$C)\\
PSXC = corrected ambient pressure (hPa)\\
ATX = ambient temperature ($^{\circ}$C)\\
$T_{0}$ = 273.15~K\\
\index{CONCN}\\
\rule[0.5ex]{1\linewidth}{1pt}
\[
\mathrm{A=\frac{\{CNTS\}}{\mathrm{(\{FCNC\}\times C_{flow})}(\Delta t-t_{d})}}
\]

\begin{equation}
\mathrm{\{CONCN\}}=A\frac{\mathrm{\{PSXC\}}}{\mathrm{\{PCN\}}}\frac{\mathrm{(\{CNTEMP\}}+T_{0})}{(\mathrm{\{ATX\}}+T_{0})}\label{eq:12.2}
\end{equation}
%
\end{minipage}} %
\end{minipage}

\vfill\eject
\end{hangparagraphs}

\subsection{Aerosol Spectrometers}

\index{aerosol!spectrometer}For size-resolved measurements of the
concentration of aerosol particles, RAF deploys two instruments. The
\href{https://www.eol.ucar.edu/instruments/ultra-high-sensitivity-aerosol-spectrometer}{Ultra High Sensitivity Aerosol Spectrometer}
(UHSAS)\index{UHSAS} sizes particles in 99 bins from 0.06 to 1.0~\textgreek{m}m
diameter, and the \href{http://www.eol.ucar.edu/instruments/passive-cavity-aerosol-spectrometer-probe}{Passive Cavity Aerosol Spectrometer Probe}
(PCASP)\index{PCASP} has 30 channels covering the diameter range
0.1 to 3~\textgreek{m}m. Flow and total concentration variables for
these instruments are described in this section, while additional
variables are covered along with other 1-D probes in Sect.~\ref{subsec:1DProbes},
``Sensors of individual Particles (1-D Probes).''
\begin{hangparagraphs}
\textbf{UHSAS Absolute Pressure in Optics Block (kPa):}\nop{UPRESS}{}\textbf{
}\textbf{\uline{UPRESS}}\index{UPRESS}\sindex[var]{UPRESS}\\
The pressure internal to the UHSAS instrument. This is an analog measurement
with calibration coefficients as recorded in the attributes for the
variable.\label{punch:7-2}

\noindent\begin{minipage}[t]{1\columnwidth}%
\textbf{Raw Sample Flow Rate (cm$^{3}$s$^{-1}$):}\nop{USMPFLW}{}\nop{PFLW}{}\textbf{
}\textbf{\uline{USMPFLW}}\textbf{, }\textbf{\uline{PFLW}}\index{PFLW}\index{USMPFLW}\sindex[var]{PFLW}\sindex[var]{USMPFLW}\\
\textbf{Corrected Sample Flow Rate (cm$^{3}$s$^{-1}$):}\nop{USFLWC}{}\nop{PFLWC}{}\textbf{
}\textbf{\uline{USFLWC}}\textbf{, }\textbf{\uline{PFLWC}}\index{PFLWC}\index{USFLWC}\sindex[var]{PFLWC}\sindex[var]{USFLWC}%
\end{minipage}\\
Unlike the other 1-d probes, both UHSAS and PCASP have internal pumps
so their sample volumes are determined from the measured flows and
do not depend on true air speed. The UHSAS measures volumetric flow\index{UHSAS!flow}
directly, and it is adjusted to ambient conditions for the calculation
of ambient concentration. The PCASP\index{flow!PCASP} returns a mass
flow referenced to standard conditions, and this also is converted
to equivalent ambient volumetric flow.\\
\\
\fbox{\begin{minipage}[t]{0.9\textwidth}%
UPRESS = internal UHSAS pressure (kPa)\index{UPRESS}\\
USMPFLW = measured volumetric sample flow (cm$^{3}$s$^{-1}$)\\
PFLW = sample mass flow referenced to standard conditions (cm$^{3}$s$^{-1}$)\\
$T_{blk}$ = UHSAS optical block temperature, 305 K\\
$p_{std}$ = standard pressure, 1013.25 hPa\\
$T_{std}$ = standard temperature, 298.15 K\index{UHSAS!STP}\\
PSXC = corrected ambient pressure (hPa)\\
ATX = ambient temperature ($^{\circ}$C)\\
$T_{0}$ = 273.15~K\\
\\
\rule[0.5ex]{1\linewidth}{1pt}

\begin{equation}
\mathrm{\{PFLWC\}}=\mathrm{\{PFLW\}}\frac{p_{std}}{\mathrm{\{PSXC\}}}\frac{(\mathrm{\{ATX\}}+T_{0})}{T_{std}}\label{eq:12.3}
\end{equation}
\begin{equation}
\mathrm{\{USFLWC\}}=\mathrm{\{USMPFLW\}}\frac{\mathrm{\{UPRESS/10\}}}{\mathrm{\{PSXC\}}}\frac{\mathrm{(\{ATX\}}+T_{0})}{T_{blk}}\label{eq:12.4}
\end{equation}
%
\end{minipage}} \\
\\

\textbf{Total particle counts per sample interval, UHSAS or PCASP:}\nop{TCNTL}{}\nop{TCHTP}{}\textbf{
}\textbf{\uline{TCNTU}}\textbf{, }\textbf{\uline{TCNTP}}\index{TCNTP}\index{TCNTU}\sindex[var]{TCNTP}\sindex[var]{TCNTU}\\
The total particle counts in each sample interval for, respectively,
the UHSAS and PCASP instruments. These values are the sum of counts
in all cells of the spectrometers, as represented in the vector variables
CUHSAS or CS200. See the discussion of these variables in Sect.~\ref{subsec:1DProbes},
\vpageref{CUHSAS}.

\textbf{Concentration, sum over all channels (cm$^{3}$s$^{-1}$):}\nop{CONCU}{}\nop{CONCP}{}\nop{CONCU100}{}\nop{CONCU500}{}\textbf{
}\textbf{\uline{}}\\
\textbf{\uline{CONCU}}\textbf{, }\textbf{\uline{CONCP}}\textbf{,
}\textbf{\uline{CONCU100}}\textbf{, }\textbf{\uline{CONCU500}}\index{CONCU}\index{CONCP}\index{CONCU100}\index{CONCU500}\sindex[var]{CONCU}\sindex[var]{CONCP}\sindex[var]{CONCU100}\sindex[var]{CONCU500}\\
\emph{The particle concentrations summed over all or a subset of channels.}
\index{concentration!particle}CONCU and CONCP are summed over all
channels in the UHSAS\index{UHSAS} and PCASP\index{PCASP}, respectively,
and are calculated as in the following boxed equations. CONCU100 and
CONCU500 are concentrations summed over channels in the UHSAS giving
particle concentrations for diameters greater than or equal to 100~nm
and 500~nm, respectively, and are calculated as for CONCU except
with TCNTU replaced by the sum over the appropriate channels.\\
\\
\fbox{\begin{minipage}[t]{0.9\textwidth}%
TCNTU = total particle counts per sample interval, UHSAS

TCNTP = total particle counts per sample interval, PCASP

$\Delta t$ = \sindex[lis]{Deltat@$\Delta t$=time interval}sample
interval (s)

USFLWC = corrected sample flow rate, UHSAS (cm$^{3}$s$^{-1}$)

PFLWC = corrected sample flow rate, PCASP (cm$^{3}$s$^{-1}$)\\
\\
\rule[0.5ex]{1\linewidth}{1pt}

\begin{equation}
\mathrm{\{CONCU\}}=\frac{\mathrm{\{TCNTU\}}}{\mathrm{\{USFLWC\}}\Delta t}\label{eq:12.5}
\end{equation}
\begin{equation}
\mathrm{\{CONCP\}}=\frac{\mathrm{\{TCNTP\}}}{\mathrm{\{PFLWC\}}\Delta t}\label{eq:12.6}
\end{equation}
%
\end{minipage}} \\
\\
\end{hangparagraphs}

\subsection{Special Aerosol Measurements}
\begin{hangparagraphs}
Data from an aerosol mass spectrometer\index{spectrometer!aerosol mass},
a scanning mobility particle spectrometer\index{SMPS}, and a giant
nucleus impactor\index{impactor!giant nucleus} are recorded by these
instruments in separate data files and are not recorded by the aircraft
data system. The ancillary\index{aerosol!ancillary datasets} data
sets are not merged into the netCDF archives produced by EOL, so the
special data files must be used for these measurements. The data formats
are described with the instruments at the references given below:\\
\\
\textbf{Aerosol Mass Spectrometer (AMS) data files} contain size-segregated
chemical composition of non-refractory, submicron aerosol particles.
The instrument is described here: \href{https://www.eol.ucar.edu/instruments/time-flight-aerosol-mass-spectrometer}{https://www.eol.ucar.edu/instruments/time-flight-aerosol-mass-spectrometer}.\\
\textbf{Scanning Mobility Particle Spectrometer (SMPS) files} contain
fine particle differential size distributions. The number of channels
and covered size range are variable. Diameter ranges from about 7.5~nm
up to about 500~nm (pressure-dependent), and 15 size bins are typical.
The instrument is described here: \href{https://www.eol.ucar.edu/instruments/scanning-mobility-particle-spectrometer}{https://www.eol.ucar.edu/instruments/scanning-mobility-particle-spectrometer}.\\
\textbf{Auto-GNI, GNI Giant Nuclei Impactor (GNI) files} contain dry
differential particle size distributions. The instrument is described
here: \href{https://www.eol.ucar.edu/instruments/giant-nuclei-impactor}{https://www.eol.ucar.edu/instruments/giant-nuclei-impactor}.
\end{hangparagraphs}


\documentclass[12pt, final, onecolumn, titlepage]{article}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{enumitem}
\usepackage{titlesec}
\usepackage{listings}
\usepackage[colorlinks = true,
            linkcolor = blue,
            urlcolor  = blue,
            citecolor = blue,
anchorcolor = blue]{hyperref}
\usepackage{leftidx}
\usepackage{amsthm}
\usepackage{mathtools}
\usepackage{comment}
\allowdisplaybreaks
\titlelabel{\thetitle.\quad}
\usepackage[margin=1in]{geometry}

\newcommand{\vect}[1]{\mathbf{#1}}
\newcommand{\re}{\text{Re}}
\newcommand{\imcp}{\text{Im}}
\newcommand{\CC}{\mathbb{C}}
\newcommand{\RR}{\mathbb{R}}
\newcommand{\QQ}{\mathbb{Q}}
\newcommand{\ZZ}{\mathbb{Z}}
\newcommand{\NN}{\mathbb{N}}
\newcommand{\FF}{\mathbb{F}}
\newcommand{\SL}{\text{SL}}
\newcommand{\Hom}{\text{Hom}}
\newcommand{\vol}{\text{vol}}
\newcommand{\const}{\text{const}}
\newcommand{\ord}{\text{ord}}
\newcommand\norm[1]{\left\lVert#1\right\rVert}
\newcommand\abs[1]{\left\lvert#1\right\rvert}
\newcommand\ceil[1]{\left\lceil#1\right\rceil}
\newcommand\floor[1]{\left\lfloor#1\right\rfloor}
\newcommand\parens[1]{\left(#1\right)}
\newcommand*{\pr}[2][]{\text{Pr}\ifx\\\left[#1\right]\\\else_{#1}\fi \left[#2\right]}

\theoremstyle{definition}
\newtheorem{defin}{Definition}[section]
\newtheorem{remark}[defin]{Remark}
\newtheorem{prop}[defin]{Proposition}
\newtheorem{lemma}[defin]{Lemma}
\newtheorem{theorem}[defin]{Theorem}
\newtheorem{corollary}[defin]{Corollary}
\newtheorem{example}[defin]{Example}
\newtheorem{problem}[defin]{Problem}

\begin{document}

\title{Making Fantasy Football Predictions Using Multiplicative Weights}

\author{Dylan Mavrides (\texttt{mavrides})\\Eric Neyman (\texttt{eneyman})\\Andrew Wonnacott (\texttt{awonnacott})}

\maketitle

\tableofcontents

\newpage

\section{Introduction}
The multiplicative weights algorithm, as presented in class, essentially gives a method of making a single good prediction using the predictions of many experts at a series of time steps. To do so, we fix a constant $\eta \leq 1/2$ (for theoretical results to hold), and then we associate weights $w_{i}^{(t)}$ (initialized to 1) for each expert $i$ and time step $t$. At time step $t$ we choose decision $i$ with probability
\[p_i = \frac{w_i^{(t)}}{\sum_{j}w_j^{(t)}}.\]
Now we assume some cost function associated with how incorrect each decision was. Let these costs be $m^{(t)}$, and then update the weights by multiplying them by the factor $1-\eta m_i^{(t)}$.

In the theoretical sense, this algorithm has small additive error asymptotically. However, we wanted to apply the algorithm to a more practical scenario, to see how well the algorithm performed in practice relative to the experts it was using to make predictions. After considering a few different settings in which a bunch of experts make straightforward, publicly-available predictions including weather forecasts and a website where people predict the outcomes of supreme court cases, we settled on fantasy football as our final setting, with ESPN, Fantasydata, Fantasyalarm, Yahoo, CBS, NFL, and FFToday as our experts, making predictions on the number of fantasy points for each player.\footnote{We only looked at quarterbacks (QB), running backs (RB), wide receivers (WR), and tight ends (TE) because for other positions, websites differed in what they factored into fantasy points. Fantasy points are calculated according to a linear combination of passing yards, passing touchdowns, passes intercepted, rushing yards, rushing touchdowns, receiving yards, and receiving touchdowns. The weights we used in the linear combination, for calculating overall fantasy points, were the standard ones: $0.04$, $4$, $-2$, $0.1$, $6$, $0.1$, and $6$, respectively.} We used each week of play in 2017 as our series of time steps, with data for each player in the positions quarterback, running back, wide receiver, and tight end. When a website didn't make a prediction for a particular player, we assumed that this implied a predicted fantasy score of 0. This is a reasonable assumptions, since some websites didn't include players expected not to play, but others included a score of 0 for completeness. To collect our data, we used the python packages Selenium and BeautifulSoup to download the data to CSVs and then write bits of code to standardize the formatting of the data and the names of the players (removing Jr., Sr., and other name suffices).

Since different players play different positions, and different experts may be better or worse at predicting the results of specific positions, we ran different multiplicative weights trials for different sources, as well as an algorithm that disregarded the position itself. Another thing to note is that our algorithm differs slightly from the standard multiplicative weights procedure since we make many updates at each time step, as each expert makes a prediction for each player at each time step. We continued our investigation by seeing which experts seemed more or less credible based on their final weights, adjusting $\eta$ values, and then testing in what way removing the sources that ended up with the worst weights affected our predictions' accuracy.

Of course, in reality, fantasy football involves much more than just predicting the number of fantasy points that each player scores. Importantly, it requires drafting players; according to ESPN.com, this generally includes a quarterback, 2 running backs, 3 wide receivers, one tight end, and a kicker (this may not be exhaustive, and may have some variation among leagues, but this is the setting we will consider). We finish the paper by investigating the theoretical question: given that we have predictions about how the players will perform, how can we maximize our expected chances of winning a fantasy football league?

Through our investigation we found ESPN to be the  best-scoring expert using our metrics, that the multiplicative weights algorithm generally (with reasonable $\eta$) performed better than any expert individually, that it performed a small amount better than simply averaging the experts' predictions ($\eta = 0)$, that high $\eta$ was better when we had "bad" sources, but low $\eta$ was better when only "good" sources were used, and various theoretical results. Finally, we note that we did use relatively few experts, so any conclusions we reach may not necessarily generalize to multiplicative weights when applied to larger-scale settings.

\section{Algorithm Details}
We made two separate algorithms. The first one ran multiplicative weights once: for each week, it calculated a cost for each source, taking into account, for each player, the source's prediction for number of fantasy points for that player and the true number of fantasy points scored. The second algorithm ran four different multiplicative weights algorithms --- one for each of the four positions (QB, RB, WR, TE). The theory was that the latter algorithm would outperform the second one if some sources were better at some positions and other sources were better at other positions, and would just add noise otherwise.

The costs were calculated straightforwardly. For each expert, for each player, that player's cost was the absolute difference of their points scored and the expert prediction for their points scored. This makes sense: suppose you are choosing between two players to draft; an expert says that the first player is expected to score $M - \epsilon$ points and the second player is expected to score $M$ points. You choose the second player; it turns out that actually the second player ends up scoring $m$ points. By choosing the second player, you were hurt by an expected (approximately) $M - m$ points (assuming the predictor does not consistently overshoot or undershoot). (Choosing $\epsilon$ to be small was arbitrary, but it still makes sense that you would be hurt in proportion to the absolute difference between the actual score and the predicted score.) Then, these costs were summed across all players, giving the expert's total cost. This number was scaled to lie between $-1$ and $1$.

The method of scaling was as follows: there was some constant margin $t$ (specifically, $t = 1.3$). Suppose that the first week's costs are $c_1 < \dots < c_n$, where there are $n$ sources. If all future costs lie between $\frac{c_1}{t}$ and $c_nt$, we can ensure that all costs are between $-1$ and $1$ by linearly scaling the costs $c \mapsto ac + b$, where $a$ and $b$ are such that $\frac{c_1}{t}$ maps to $-1$ and $c_nt$ maps to $1$. Specifically, this gives us:
\[a = \frac{2}{c_n t - \frac{c_1}{t}}; b = 1 - ac_nt.\]
In practice this does not always ensure that the costs lie between $-1$ and $1$ (though they are close to always lying in that range); however, we are not trying to prove theoretical results so this is fine.

\section{Analysis of Results}
The most important takeaway from our results is that the multiplicative weights approach passes two basic tests. First, even though ESPN was consistently the best expert, the multiplicative weights algorithm performed better than ESPN by itself. With $\eta = \sqrt{\frac{\ln n}{T}}$ (the default $\eta$ since this is the $\eta$ used in the theoretical result), the total accumulated cost of the algorithm was $2.7\%$ better than just ESPN's predictions.

Second, the approach was better than simply taking an average of all predictors each week (equivalently, setting $\eta = 0$), by $0.34\%$. The primary reason for that this percentage seems small is that sources' predictions were all fairly similar to each other, so although some sources were consistently better than others, they weren't better than others by large absolute amounts.

Note that we did not specify whether we were talking about the overall algorithm or the by-position algorithm (that runs multiplicative weights algorithms for each position). This is because these two algorithms always performed about equally well. In the standard setting (default $\eta$, all sources present), for instance, the by-position algorithm was better than the overall algorithm by just $0.042\%$. Our hypothesis for this result is that the amount by which sources had weak suits and strong suits in terms of positions (existent but not large) roughly cancelled out the negative effect we would expect from noise (having less data each week to update weights based on), resulting in similar performance. For a sense of the extent to which experts had strong and weak suits, see the table below. The table shows the final weights assigned to each source (scaled so the highest weight is $1$) in the overall algorithm and the by-position algorithm.
\begin{center}
\includegraphics[scale=0.8]{Scaled_Weights.png}
\end{center}
Because the algorithms always performed comparably well, no matter the specific settings, from now on we will analyze the performance of the overall algorithm without mentioning how the by-position algorithm did.

Another question is, while excluding all sources besides ESPN made things worse, perhaps excluding bad sources like FFToday would be beneficial. And indeed, excluding bad sources does make the algorithm do better. Below, we exclude sources starting from the worst overall one above (FFToday) up to the second best one (Fantasydata).

\begin{center}
\begin{tabular}{|r|l|}
\hline
Sources & Total Cost\\
\hline
FFToday, NFL, CBS, Yahoo, Fantasyalarm, Fantasydata, ESPN & 19499\\
NFL, CBS, Yahoo, Fantasyalarm, Fantasydata, ESPN & $19476$\\
CBS, Yahoo, Fantasyalarm, Fantasydata, ESPN & $19338$\\
Yahoo, Fantasyalarm, Fantasydata, ESPN & $19204$\\
Fantasyalarm, Fantasydata, ESPN & $19198$\\
Fantasydata, ESPN & $19356$\\
ESPN & $20047$\\
\hline
\end{tabular}
\end{center}
That is, it seems that a medium number of sources is optimal: bad sources should be excluded but it is suboptimal to only include the best source.

Interestingly, the optimal combination of sources actually appears to be just ESPN and Fantasyalarm, with an overall cost of $19176$. Perhaps ESPN and Fantasyalarm complement each other in some way. One conjecture would be that ESPN is better for quarterbacks, running backs, and wide receivers, while Fantasyalarm is better at tight ends (see the table with scaled weights), which is why it is good (and sufficient) to have both. However, this is not the correct explanation; if it were correct, we would see the combination of the two doing substantially better in the by-position algorithm. But this is not the case: with a cost of $19168$, the by-position algorithm does only $0.04\%$ better.

Our recommendation would not be to use just ESPN and Fantasyalarm in future years: the performance of these two in combination could just be good by coincidence. Instead, using ESPN, Fantasydata, Fantasyalarm, and Yahoo (all good sources, unlike CBS, NFL, and FFToday), would result in online correction of any potential overfitting due to the above model.

Another question is, what is the optimal $\eta$? Below is a chart showing total cost for various values of $\eta$, for both all sources and just the four best ones. (Note that for all sources included, the theoretical $\eta = \sqrt{\frac{\ln n}{T}}$ is about $0.34$, while for four sources it is about $0.29$.)
\begin{center}
\includegraphics[scale=0.7]{Cost_vs_eta.png}
\end{center}
One should not read too much into the \emph{specific} values of $\eta$, because the specific value of $\eta$ depends entirely on how we scale our costs. However, the fact that multiplicative weights with all sources prefers a higher $\eta$ makes sense. Because there are sources of varying quality, a higher $\eta$ quickly reduces the weight of the bad sources. On the other hand, when there is not much quality differentiation (as is the case if we take the top four sources), a low $\eta$ is optimal. Indeed, setting a very high $\eta$ results in nearly all the weight being put on ESPN ($78\%$ of the weight for $\eta = 1.5$), which is close to the case where ESPN is our only source (which does poorly).

\section{Trying to Win: A Theoretical Approach}
Suppose that your fantasy football league has the following format: each week, the person with the largest total number of fantasy points wins a cash prize (everyone else gets nothing). If you wish to maximize your prize money, then each week you wish to maximize the probability that you will come in first. Maximizing expected score given a belief about how many points each player is expected to score is easy: by linearity of expectation, the optimal approach is to pick the top quarterback(s), the top running back(s), etc. Maximizing probability of winning is not so straightforward: sometimes it might make sense to maximize expectation for variance. In this section, we create a simplified model of fantasy football and analyze how to maximize the probability of winning in a given week.

Suppose there are $n$ people in your league, not including you. Assume that everyone else has the na\"{i}ve strategy of trying to maximize their expected number of points. What is the maximum of their fantasy points expected to look like? One reasonable model is to model each person's point distribution as a normal distribution centered at some $\mu$ with standard deviation $\sigma$. After all, the random variable of each person's points is a sum of the random variables that are the number of fantasy points each player on that person's fantasy team scores; it makes sense for these to be jointly normally distributed, and the sum of jointly normally distributed random variables if a normally distributed random variable. We assume that $\mu$ and $\sigma$ are the same for all $n$ players: the snake draft system makes it so that equally skilled players get roughly the same expectation, and it seems likely that in practice the standard deviations won't be too different from each other.

Furthermore, we will assume that these $n$ normal random variables are independent. This makes sense because everyone has different players, and although e.g. two players on the same team are likely to have positively correlated points, this is unlikely to be a significant effect unless two people both have several players all drawn from the same team. So now our question is, how is the maximum of $n$ independent random variables $N(\mu, \sigma)$ distributed?

Let $p(x)$ and $c(x)$ be the PDF and CDF of $N(\mu, \sigma)$, respectively. The probability that the maximum of the $n$ random variables is less than $t$ is just the product of the probabilities that each of the random variables is less than $t$, i.e. $c(t)^n$. This is the CDF of the maximum of the random variables. The PDF, while not immediately relevant to the problem, is interesting. It is
\[nc(t)^{n - 1}c'(t) = nc(t)^{n - 1}p(t),\]
which looks similar to a normal distribution, but is skewed (the larger the value of $n$, the more skewed it is). Here is a picture for $n = 10$ (with $\mu = 0$ and $\sigma = 1$):
\begin{center}
\includegraphics[scale=0.7]{Maximum_Distribution_N=10.png}
\end{center}

Now, if you know the distribution of your possible scores, finding the probability that you will be the week's winner is straightforward. (You can write the exact answer as an integral, or you can approximate the probability that you will be the winner: finely subdivide the $x$-axis into regions $[-\infty, x_0), [x_0, x_1), \dots, [x_r, \infty)$, and for each $0 \le i < r$, take the probability that your score is in $[x_r, x_{r + 1})$ times the $c(x_r)^n$, and add up these products.) We now discuss how you can calculate your distribution of possible scores, given the list of players.

As we said before, the football players' scores are jointly normally distributed. However, we cannot assume that they are independent: indeed, the point of the question is how much expectation should be given up to exploit non-independence for increased variance.

Suppose that we have a list of all of the football players $p_1, \dots, p_m$ with mean fantasy scores $\mu_1, \dots, \mu_m$ (found e.g. from expert predictions via multiplicative weights). There is an associated covariance matrix $\Sigma$ (where the entry $\sigma_{ij}$ is the covariance of $p_i$'s fantasy score and $p_j$'s fantasy score). The matrix $\Sigma$ can be found empirically by examining how much variance individual players have (to determine the diagonal entries), how much a quarterback's performance affects the performance of a wide receiver on the same team, how scores of players on opposing teams are correlated, etc.

Suppose that the players that you choose are $p_{a_1}, \dots, p_{a_s}$. From statistics we know that the distribution of your total score has mean $\mu_{a_1} + \dots + \mu_{a_s}$ and variance $\sum_{1 \le i, j \le s} \sigma_{a_ia_j}$.

So now, given a set of players that you select, it is easy to find the probability that you will win (under our assumptions). And any given week, it is easy to simply check all sets of players: among the $16$ or so players that you drafted, there are only a few hundred options for whom to select. However, it is still useful to examine the question of which players you should select in full generality (i.e. if you could select any of the players), for two reasons: first, opportunities for trades; and second, in order to know whom to draft in the first place. There are too many possibilities to brute force this more general problem.

Suppose for the moment that your goal is to maximize the probability that you score better than some score $N$. Then equivalently, you want to maximize the number of standard deviations above the mean of your distribution of possible scores that $N$ is. That is, you are trying to minimize
\[\frac{N - \sum_{i \in [s]} \mu_{a_i}}{\sqrt{\sum_{i, j \in [s]} \sigma_{a_ia_j}}}.\]

This can be phrased as a minimization problem with variables and constraints by letting $x_k$ be $1$ if $k \in \{a_i\}$ (for $k \in [m]$) and $0$ otherwise, where sums of certain $x_k$'s (those corresponding to quarterbacks, those corresponding to running backs, etc.) have to equal certain numbers. Then we are trying to minimize
\[\frac{N - \sum_{i \in [m]} x_i \mu_i}{\sqrt{\sum_{i, j \in [n]} x_i x_j \sigma_{ij}}}.\]
This minimization problem is not easily approachable. Not only is it an integer program, but its natural relaxation (letting $x_i$ be in $[0, 1]$) is not a convex program: the function we wish to minimize is not convex. For example, let $m = 2$, $N = 1$, $\mu_1 = \mu_2 = 0$, $\sigma_{11} = \sigma_{22} = 1$, $\sigma_{12} = \sigma_{21} = 0$. Then the function is $\frac{1}{\sqrt{x_1^2 + x_2^2}}$, which is not convex (consider $(x_1, x_2) = (1, 0)$, $(x_1, x_2) = (0, 1)$, and their midpoint). Despite this, we can approximate the solution to the minimization problem fairly accurately under certain assumptions.

The main assumption we need is the following: if we arrange the players $p_1, \dots, p_m$ by team (each team has the same number of players in the list) and consistently arrange the players by position within each team, then the covariance matrix $\Sigma$ can be closely approximated by a matrix of the following form:
\[\Sigma_M = \begin{pmatrix}M&0&\dots&0 \\ 0&M&\dots&0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \dots & M\end{pmatrix}.\]
Here, the number of rows (and columns) in $M$ is equal to the number of players on each team. Furthermore, $M$ is a symmetric matrix with the following property: for any player of position $A$ and any other player of position $B$ (where $A$ could equal $B$), the entry for those two players in $M$ is the same as for any other pair of players with positions $A$ and $B$.

It makes sense that $\Sigma$ can be approximated in this way. First, a player from one team and a player on another team should clearly have uncorrelated performances (unless they are on opposing teams, and even then it is not obvious that they ought to be correlated; we discuss taking correlations between opposing players into account later). Second, it does not seem far removed from reality that e.g. the performance of the Patriots quarterback should be correlated with the performance of a Patriots wide receiver in a similar way to how the performance of the Seahawks quarterback should be correlated with the performance of a Seahawks wide receiver. Furthermore, the performance of e.g. a Patriots quarterback and a Patriots wide receiver should be correlated similarly to the quarterback and a different wide receiver.

Note that approximating $\Sigma$ with the closest possible such matrix $M$ is easy. We have a certain number of variables $y_1, \dots, y_q$ corresponding to the distinct entries of $M$; we are trying to minimize a sum of the form $(y_i - \sigma_{jk})^2$, which is a sum of quadratics in each variable, so we can just minimize each variable's quadratic separately.

Now, suppose we take a particular distribution of positions among unlabeled teams. For example, one distribution of \{1 QB, 2 RB, 3 WR, 1 TE, 1 K\} among unlabeled teams is \{\{1 QB, 1 RB\}, \{1 RB, 1 WR\}, \{2 WR, 1 K\}, \{1 TE\}\}, which means that the quarterback and one running back are drawn from one team, the other running back and one wide receiver are drawn from a different team, and so on. If we use $\Sigma_M$ as our covariance matrix, this distribution uniquely determines the denominator of the function we are trying to minimize. This is clear from the properties of $M$.

So suppose we have a particular distribution we want among unlabeled teams. With one caveat, determining \emph{which} teams (and players) to assign to which of the subsets is a straightforward task. Indeed, since the denominator is fixed, we want to minimize the numerator, i.e. maximize $\sum_{i \in m} x_i\mu_i$. For each subset (of the distribution), for each team we find the expected scores of its top players with positions as dictated by the subset, and take players from the team with the highest expected sum of scores. For example, if the Patriots have highest expected score of their two two wide receivers and top kicker among any team, the Patriots would be chosen for the third subset in the example in the previous paragraph.\footnote{This has the obvious problem of selecting the same player multiple times. A way to deal with this is, whenever there are e.g. wide receivers in different subsets, consider the top few choices for those subsets and pick the best valid set of choices.} This is always optimal. So what we do is, cycle through all possible distributions among unlabeled teams (there aren't that many; for eight players the number of distributions is bounded above by the eighth Bell number ($4140$) and is probably substantially lower since there are multiple wide receivers and running backs). For each distribution, calculate the optimal (smallest) value of the function we are trying to minimize. The select the distribution for which the function achieves its smallest value.

The caveat is that perhaps some of the teams assigned to the subsets are not distinct. This is bad because then our calculation for the denominator of our minimization function is wrong, since we do not consider the covariances between players on the same team but in different subsets. There are two ways to address this concern. The first is to point out that it is unlikely to happen for the optimal distribution of players among unlabeled teams. Indeed, most players on the same team are positively correlated. So if e.g. the quarterback and the tight end are in different subsets but end up being drawn from the same team, this ``dishonest" selection actually \emph{undersells} the goodness of the selected players, because after factoring in the cross-subset covariance the denominator of the minimization function will increase.

The second is to create a workaround. For example, invalid arrangements (ones where subsets are assigned to the same team) could be ignored. Or, if an arrangement is invalid, bump conflicting subsets down until there is no longer a conflict. This would most likely produce a near-optimal result.

Finally, we briefly come back to the fact that opposing teams' scores might be correlated. This has a simple fix: instead of letting $M$ have dimension equal to the number of players on each team, it has dimension equal to twice the number of players on each team, and teams are arranged so that opposing teams in a given week are consecutive. Now $\Sigma_M$ can more fully capture all of the covariance in $\Sigma$. However, now there are more distributions of players among unlabeled teams to consider. For example, one such distribution would be \{\{1 QB, 1 RB on opposite teams\}, \{1 RB, 1 WR on the same team\}, \{2 WR, 1 K with one WR on one team and one WR and one K on the opposing team\}, \{1 TE\}\}.

\section{Further Research}
One issue with multiplicative weights that comes to mind is, suppose that we clone a source. Then effectively the weight of that source nearly doubles. In practice, if two experts make similar predictions (which could be if for example they consult each other, or rely on the same techniques), this would cause a multiplicative weights approach to be biased toward those experts/techniques.

One obvious solution to this problem would be to apply known techniques in optimization for post-hoc feature selection, for instance forward and backward stepwise feature selection. In the former, we begin with no approved experts, and then iteratively adopt into our set of approved experts the non-approved expert who would decrease our cost (of running MW on the approved experts) the most, until no non-approved experts provide substantial cost decreases. In the latter, we begin with no rejected experts, and then iteratively eject the expert who would increase our cost (of running MW on the remaining experts) the least, until all remaining experts make substantial contributions to our cost minimization.

However, these techniques sacrifice one of the key advantages of multiplicative weights --- online learning. That is, the multiplicative weights algorithm does not require training to cease in order to make predictions, so there is no requirement of a training vs testing set of data to be drawn from the historical data. When post-hoc feature selection techniques are employed, they introduce the necessity of an out-of-sample data set on which to evaluate performance in order to prevent overfitting to the training data. We did not select to explore this because of the limited data set to which we had access. Readers with more historical data (produced either by the passage of time or by access to data previous to 2017) could explore the applicability of such techniques.

Given these drawbacks, it would be preferable to adapt the multiplicative weights algorithm itself to incorporate feature selection. Two approaches come to mind. First, instead of simply penalizing each expert based on costs, experts' weights could be penalized for proximity to other experts in their predictions. Second, instead of penalizing weights, experts could be penalized in a given round when their predictions are similar to others' predictions (i.e. their predictions are discounted when making the guess), without affecting the experts' weights. An interesting question would be to design an algorithm that does this, perhaps one satisfying certain interesting or useful theoretical properties. (One such property might be that if an expert is duplicated, the predictions of the algorithm do not change.)

Finally, as stated above, we were limited to only using data in 2017 and only seven sets of expert predictions since we wanted to have as complete and consistent data as possible across our sources. To avoid problems with overfitting\footnote{While multiplicative weights is specifically designed to protect against overfitting (by only using past data to predict future data), throwing out bad sources in retrospect produces results that are subject to overfitting.} and further legitimize our results, we would ideally use more data from past years and continue using our algorithm to make predictions in future years as the sites make more predictions. In a real-life setting, if we were trying to provide a service of fantasy football predictions, it would be useful to automate this process and add protocols to the algorithm to incorporate new experts as we find more sources from which to make predictions.
\newpage
\appendix
\section{Code}
Relevant constants (in clean\_data.py, which contains a clean method which returns a two-dimensional array containing players of a given position along with predicted scores for each statistics, e.g. passing yards, passing touchdowns, etc.):

\footnotesize
\begin{lstlisting}[basicstyle=\small\ttfamily,breaklines=true,breakatwhitespace=true,language=Python]
experts = ["espn", "nfl", "fftoday", "cbs", "fantasydata", "fantasyalarm", "yahoo"]
positions = ["QB", "RB", "WR", "TE"]
num_weeks = 17
points_weights = [.04, 4, -2, .1, 6, .1, 6]
\end{lstlisting}

\normalsize
\noindent Multiplicative weights (overall) algorithm:

\footnotesize
\begin{lstlisting}[basicstyle=\small\ttfamily,breaklines=true,breakatwhitespace=true,language=Python]
#!/usr/bin/env python3
from clean_data import clean, experts, positions, num_weeks, points_weights
import math

eta = (math.log(len(experts))/num_weeks)**.5
margin = 1.3

weights = {expert: 1.0 / len(experts) for expert in experts}
cost = 0
cost_scalar = 0
cost_constant = 0
print "eta: ", eta
for week in range(1, num_weeks + 1):
    print("Week:", week)
    print("Weights:", weights)
    weight_sum = sum(weights[expert] for expert in experts)
    if week == 17 and "nfl" in weights:
        weight_sum -= weights["nfl"]
    weekly_cost = 0
    costs = {expert: 0 for expert in experts}
    for pos in positions:
        true_values = clean(pos, str(week), "truevalues")
        predictions = {expert: clean(pos, str(week), expert) for expert in experts}
        for player in true_values:
            guess = 0
            true_score = sum(value * weight for value, weight in
                                                zip(true_values[player], points_weights))
            for expert in experts:
                if not(week == 17 and expert == "nfl"):
                    expert_score = 0
                    if player in predictions[expert]:
                        expert_score += sum(value * weight for value, weight in
                                        zip(predictions[expert][player], points_weights))
                    guess += expert_score * weights[expert]
                    costs[expert] += abs(expert_score - true_score)
            guess /= weight_sum
            weekly_cost += abs(guess - true_score)
    if week == 1:
        min_cost = min(costs[expert] for expert in experts)
        max_cost = max(costs[expert] for expert in experts)
        cost_scalar = 2/(max_cost*margin - min_cost/margin)
        cost_constant = 1 - cost_scalar*max_cost*margin
    for expert in experts:
        costs[expert] = cost_scalar*costs[expert] + cost_constant
        weights[expert] *= 1 - eta * costs[expert]
        if weights[expert] <= 0:
            print("Error: weight not positive.")
            exit(1)
    print("Costs:", costs, weekly_cost)
    cost += weekly_cost
print("Total cost:", cost)
\end{lstlisting}

\normalsize
\noindent Multiplicative weights (by position) algorithm:

\footnotesize
\begin{lstlisting}[basicstyle=\small\ttfamily,breaklines=true,breakatwhitespace=true,language=Python]
#!/usr/bin/env python3
from clean_data import clean, experts, positions, num_weeks, points_weights
import math

eta = (math.log(len(experts))/num_weeks)**.5
margin = 1.3
total_cost = 0
cost_scalars = {"QB": 0, "RB": 0, "WR": 0, "TE": 0}
cost_constants = {"QB": 0, "RB": 0, "WR": 0, "TE": 0}
print "eta: ", eta
for pos in positions:
    print("Position:", pos)
    weights = {expert: 1.0 / len(experts) for expert in experts}
    position_cost = 0
    for week in range(1, num_weeks + 1):
        print("Week:", week)
        print("Weights:", weights)
        weight_sum = sum(weights[expert] for expert in experts)
        if week == 17 and "nfl" in weights:
            weight_sum -= weights["nfl"]
        weekly_cost = 0
        costs = {expert: 0 for expert in experts}
        true_values = clean(pos, str(week), "truevalues")
        predictions = {expert: clean(pos, str(week), expert) for expert in experts}
        for player in true_values:
            guess = 0
            true_score = sum(value * weight for value, weight in
                            zip(true_values[player], points_weights))
            for expert in experts:
                if not(week == 17 and expert == "nfl"):
                    expert_score = 0
                    if player in predictions[expert]:
                        expert_score += sum(value * weight for value, weight in
                                        zip(predictions[expert][player], points_weights))
                    guess += expert_score * weights[expert]
                    costs[expert] += abs(expert_score - true_score)
            guess /= weight_sum
            weekly_cost += abs(guess - true_score)
            #if week == 17:
                #print player+","+str(abs(guess - true_score))
        if week == 1:
            min_cost = min(costs[expert] for expert in experts)
            max_cost = max(costs[expert] for expert in experts)
            cost_scalars[pos] = 2 / (max_cost * margin - min_cost / margin)
            cost_constants[pos] = 1 - cost_scalars[pos] * max_cost * margin
        for expert in experts:
            costs[expert] = cost_scalars[pos] * costs[expert] + cost_constants[pos]
            weights[expert] *= 1 - eta * costs[expert]
            if weights[expert] <= 0:
                print("Error: weight not positive.")
                exit(1)
        print("Costs:", costs, weekly_cost)
        position_cost += weekly_cost
    print "Total position cost:", position_cost
    total_cost += position_cost
print "Total cost: ", total_cost
\end{lstlisting}

\newpage
\section{Bibliography}
\begin{itemize}
\item Jim McCormick, \href{https://www.espn.com/fantasy/football/ffl/story?page=nfldk2k10howtoplay}{ESPN: The basics on how to play fantasy football}
\item Sanjeev Arora, \href{https://www.cs.princeton.edu/courses/archive/fall16/cos521/Lectures/lec8.pdf}{Decision-making under total uncertainty: the multiplicative weight algorithm}
\item Jamey Eisenberg, \href{https://fantasynews.cbssports.com/fantasyfootball/stats/weeklyprojections/QB/1/jamey_eisenberg/standard?&print_rows=9999}{Fantasy Football Projections on CBS Sports}
\item ESPN, \href{https://games.espn.com/ffl/tools/projections?&scoringPeriodId=1&seasonId=2017&slotCategoryId=0}{2017 Fantasy Football Rankings \& Projections}
\item FantasyAlarm, \href{https://www.fantasyalarm.com/nfl/rankings/1/STD/QB}{2017 Fantasy Football Draft Rankings} (requires trial subscription to paid service)
\item FantasyData, \href{https://fantasydata.com/nfl-stats/fantasy-football-weekly-projections.aspx?stype=0&w=1&ew=1&p=1}{NFL Projections}
\item FF Today, \href{https://www.fftoday.com/rankings/playerwkproj.php?Season=2017&GameWeek=1&PosID=10}{Projections: 2017}
\item Fleaflicker, \href{https://www.fleaflicker.com/nfl/leaders?week=1&sortMode=2&statType=2&position=4}{Fantasy Football Leaders 2017}
\item NFL Fantasy, \href{http://fantasy.nfl.com/research/projections?position=1&sort=projectedPts&statCategory=projectedStats&statSeason=2017&statType=weekProjectedStats&statWeek=1}{Fantasy Football Player Projections}
\item ESPN, \href{https://games.espn.com/ffl/leaders?&scoringPeriodId=1&seasonId=2017&slotCategoryId=0}{Scoring Leaders} (source of actual data)
\item RotoWire, \href{https://football.fantasysports.yahoo.com/f1/731507/players}{RotoWire Projections accessed through Yahoo! Fantasy} (requires paid subscription)
\end{itemize}

This paper represents our own work in accordance with University regulations.

\end{document}


\documentclass[12pt]{article}
\usepackage[margin=2.5cm]{geometry}
\usepackage{amsmath, amssymb, stmaryrd}
\usepackage[colon]{natbib}
\usepackage{microtype}
\usepackage{mathpazo}
\usepackage{url}
\usepackage{parskip}
\usepackage{multirow}

\newcommand{\sExtend}{\mathrel{\triangleright}}
\newcommand{\where}{\mathrel{|}}
\newcommand{\fun}[1]{\mathsf{#1}}
\newcommand{\type}[1]{\mathsf{#1}}

\newcommand{\sPar}{\mathrel{\parallel}}
\newcommand{\sProc}[2]{{#1}_{#2}}

\newcommand{\sSystem}[2]{\left( #1, #2 \right)}
\newcommand{\sProcess}[3]{\left( U, sk, #1, #2, #3 \right)}

\newcommand{\sChain}{C}
\newcommand{\sChains}{\mathbb{C}}
\newcommand{\sState}{st}
\newcommand{\sSlot}{sl}
\newcommand{\sLeader}{\mathsf{F}}

\newcommand{\sQueue}{\mathbb{Q}}
\newcommand{\sProcesses}{\mathbb{P}}
\newcommand{\sBlock}[4]{\left( #1 , #2 , #3 , #4 \right)}

\newcommand{\sHead}{\mathsf{head}}
\newcommand{\sSign}[4]{\mathsf{Sign}_{#1}\left(#2, #3, #4\right)}

\begin{document}

\title{Ouroboros blockchain protocol specification (DRAFT)}
\author{Duncan Coutts\footnote{Well-Typed and IOHK, \texttt{duncan@well-typed.com}, \texttt{duncan.coutts@iohk.io}}}
\date{\today}

\maketitle

\section{Introduction}

This document is intended to be an alternative formulation of the Ouroboros
blockchain protocol as described by \cite{ouroboros}.

There are two main audiences for this document: people familiar with the paper,
and developers implementing the protocol.

The purpose is in part to bridge the gap between these two audiences by
describing the protocol executed by honest parties in a precise operational
style.

It is intended to be concise by omitting proofs and other details needed to
support proofs (such as the possible behaviour of adversaries), but to
otherwise be faithful to the paper.

\section{Notation}

Because of the two audiences we pick a notation that can be read in a
mathematical style or in a computational style. That is, in a mathematical
language of logic and sets, or a computational language of computable values
(with associated types).

\paragraph{Sets and types}
The notation $x : \mathsf{X}$ can be read as $x \in \mathsf{X}$ i.e. $x$ being
a member of the set $\mathsf{X}$, but can also be read as $x$ having the type
$\mathsf{X}$.

\paragraph{Finite sets}
We use $\{\}$-notation for sets: set membership $x \in X$; the empty set $\{\}$, enumerated sets $\{x_1, \ldots, x_n\}$ and set comprehensions
$\{ f(x) \where x \in X, p(x) \}$

\paragraph{Finite maps}
TODO

\paragraph{Tuples}
We use the notation $(x,y) : (X,Y)$, meaning the pair $(x,y) \in X \times Y$,
or the standard interpretation as types. We allow tuples of any fixed size,
e.g. $(x, y, z)$.

\paragraph{Functions}
We use the notation $f : X \rightarrow Y$ to describe the domain and co-domain.

\paragraph{Predicates}
TODO: mathematical predicates, computational functions to bool

\section{Preliminaries}

A time \emph{slot}, ranged over by $\sSlot : \mathsf{Slot}$ where
$\mathsf{Slot} \cong \mathbb{N}$, represents a
period of clock time of a fixed duration.

An \emph{epoch}, ranged over by $e_j \in \mathbb{N}$, identifies a sequence of
time slots $[jR \ldots j(R+1) - 1]$ where the parameter $R \in \mathbb{N}$
is the fixed epoch length.

TODO: block, chain, hash function including codomain of hash

A \emph{blockchain} (or simply a \emph{chain}) is an inductive construction:
\begin{itemize}
\item given a genesis block $B_0$ there is a chain $\Diamond B_0$; and
\item given a chain $C$ and a block $B$ there is a chain $C \sExtend B$.
\end{itemize}

There is a function on chains
\begin{equation*}
\begin{array}{l@{\;}l@{\;}l}
  \mathsf{head} & : \mathsf{Chain} & \rightarrow \mathsf{GenesisBlock} \cup \mathsf{Block}
  \\
  \mathsf{head} &(\Diamond B_0) & = B_0
  \\
  \mathsf{head} &(C \sExtend B) & = B
\end{array}
\end{equation*}

A \emph{user} or \emph{party}, ranged over by $U \in \mathsf{User}$,
represents an identifier for a stakeholder process taking part in the
protocol. We sometimes write $U_i \in \{U_1, \ldots, U_n \}$ when describing
a party within the context of all the parties taking part in the protocol,
however user identifiers are not necessarily dense integers.

A \emph{process}, ranged over by $P \in \mathsf{Process}_\pi$ is a
state tuple. The exact type of this state tuple is different for each version
of the protocol and will be described below in the context of each protocol.
For example, in the first protocol $\pi_{\text{SPoS}}$, a process
$P$ is a tuple $\sProcess{\sChain}{\sState}{\sSlot}$.

A \emph{process group}, ranged over by $\mathbb{P} \in \mathsf{ProcessGroup}$,
is either empty, a single process $P$ or a combination of process
groups written $\mathbb{P}_1 \sPar \mathbb{P}_2$. The typical notation is
$\sProcesses \sPar ( a, b ... )$ to denote a single process state
tuple in the context of a group of other processes.

A \emph{broadcast network}, ranged over by $\sQueue \in \mathsf{BroadcastNetwork}$, consists of a set of pairs $\mathsf{Chain} \times \mathsf{User}$.
Each pair represents a message addressed to a particular user.

The overall \emph{system} is a tuple $\mathsf{ProcessGroup} \times \mathsf{BroadcastNetwork}$

The rules below are expressed as either the initial state of the system or
as valid transitions on the state of the system, in the form

\begin{equation*}
\frac{
  \text{conditions and definitions}
}{
  \sSystem{ \sProcesses }{ \sQueue }
\rightarrow
  \sSystem{ \cdots }{ \cdots }
} \textsc{rule name}
\end{equation*}

\section{Protocol $\pi_{\text{SPoS}}$}

This is the simplest of the four versions of the protocol from the paper
\citep{ouroboros}.

In this protocol, a $P \in \mathsf{Process}_{\pi_{\text{SPoS}}}$ is
a state tuple $\sProcess{\sChain}{\sState}{\sSlot} \in
\mathsf{User} \times \mathsf{PrivKey} \times \mathsf{Chain} \times \mathsf{Hash} \times \mathsf{Slot}$

The protocol has a number of global parameters.
\begin{itemize}
\item The initial users $\mathbb{U} = \{U_1, \ldots, U_n\}$ and their keys $\{(\mathsf{sk}_1, \mathsf{vk}_1), \ldots, (\mathsf{sk}_n, \mathsf{vk}_n)\}$
\item The stake distribution $\mathbb{S} \in \mathsf{Stakes}$ for the users of $\mathbb{S} = \{ (\mathsf{vk}_1, s_1), \ldots, (\mathsf{vk}_n, s_n) \}$
\item A leader selection function $\sLeader \in \mathsf{Stakes} \times \mathsf{Aux} \times \mathsf{Slot} \rightarrow \mathsf{User}$
\item A PRNG seed $\rho \in \mathsf{Aux}$ used by the leader selection function
\item A transaction data function $\mathsf{T} : \mathsf{Slot} \rightarrow \mathsf{Data}$.
\end{itemize}

Note that the transaction data function is not intended to be realistic,
it simply models the otherwise unspecified source of transaction data in
this version of the protocol description.

\bigskip

\begin{equation*}
\frac{
  B_0 = (\mathbb{S}, \rho)
  \qquad
  \sChain = B_0
  \qquad
  \sState = \fun{hash}(\sHead(\sChain)
}{
  \sSystem{ \bigparallel_{U \in \mathbb{U}} \sProcess{\sChain}{\sState}{1}}{\{\}}
} \textsc{init}
\end{equation*}

\bigskip

\begin{equation*}
\frac{
\begin{array}{l@{\;}c@{\;}l@{\qquad}l@{\;}c@{\;}l}
  \sChains & = & \left\{ \sChain' \where (\sChain', U') \in \sQueue, U' = U, \fun{valid}(\sChain', \fun{gblock}(\sChain), sl) \right\}
  &
  \sChain' & = & \fun{maxValid}(\sChain, \sChains)
  \\
  \sQueue' & = & \left\{ \sChain' \where (\sChain', U') \in \sQueue, U' \neq U \right\}
  &
  \sState' & = & \fun{hash}(\sHead(\sChain'))
\end{array}
}{
  \sSystem{\sProcesses \sPar \sProcess{\sChain}{\sState}{\sSlot} }{\sQueue}
\rightarrow
  \sSystem{\sProcesses \sPar \sProcess{\sChain'}{\sState'}{\sSlot} }{\sQueue'}
} \textsc{receive}
\end{equation*}

\bigskip

\begin{equation*}
\frac{
    \sLeader(\mathbb{S}, \rho, sl) \neq U
}{
  \sSystem{\sProcesses \sPar \sProcess{\sChain}{\sState}{\sSlot}}{\sQueue}
\rightarrow
  \sSystem{\sProcesses \sPar \sProcess{\sChain}{\sState}{\sSlot+1}}{\sQueue}
} \textsc{skip}
\end{equation*}

\bigskip

\begin{equation*}
\frac{
    \begin{array}{c}
    \sLeader(\mathbb{S}, \rho, sl) = U
    \\[1mm]
    B = \sBlock{\sState}{d}{\sSlot}{\sigma}
    \qquad
    \sigma = \sSign{sk}{\sState}{d}{\sSlot}
    \qquad
    d = \mathsf{T}(\sSlot)
    \\[1.5mm]
    \sChain' = \sChain \sExtend B
    \qquad
    \sState' = \fun{hash}(\sHead(\sChain'))
    \qquad
    \sQueue' = \sQueue \cup \{ (\sChain', U) \where U \in \mathbb{U} \}
    \end{array}
}{
  \sSystem{\sProcesses \sPar \sProcess{\sChain}{\sState}{\sSlot}}{\sQueue}
\rightarrow
  \sSystem{\sProcesses \sPar \sProcess{\sChain'}{\sState'}{\sSlot+1}}{\sQueue'}
} \textsc{diffuse}
\end{equation*}

\bigskip

These rules use a number of auxiliary definitions.

The predicate $\fun{valid}$ determines if a chain is valid. This is with
respect to a genesis block and the current time slot. Chains must have strictly
increasing time slots,

\begin{equation*}
\begin{array}{l}
\fun{valid} : (\type{Chain}, \type{GenesisBlock}, \type{Slot})
\\
\begin{array}{@{}r@{\;}r@{\;}l}
\fun{valid} \; (\sChain, B_0, sl)
  & \iff  & \mathsf{validIncreasing}(\sChain) \\
  & \land & \mathsf{validHashChain}(\sChain)  \\
  & \land & \mathsf{genesisBlock}(\sChain) = B_0 \\
  & \land & \forall (st, d, sl, \sigma) \in \mathsf{blocks}(\sChain). \;
             \fun{verify}(vk, \sigma, (st, d, sl)) \\
\end{array}
\end{array}
\end{equation*}

A function $\fun{maxValid}$ selects the longest chain from
$\mathbb{C} \cup \{C\}$, preferentially selecting $C$ and arbitrarily otherwise.
\begin{equation*}
\begin{array}{l}
\fun{maxValid} : (\mathsf{Chain}, \mathbb{P}\mathsf{Chain}) \rightarrow \mathsf{User}
\\
\begin{array}{@{}l@{\quad \iff \quad}l@{}l}
\fun{maxValid} (C, \mathbb{C}) = C'
&
C' \in \mathbb{C} \cup \{C\}\; \land \; & \forall C'' \in \mathbb{C}.\; \mathsf{length}(C') \geq \mathsf{length}(C'')
\\
\fun{maxValid} (C, \mathbb{C}) = C
&
& \forall C'' \in \mathbb{C}.\; \mathsf{length}(C) \geq \mathsf{length}(C'')
\end{array}
\end{array}
\end{equation*}

Meta-rules not currently encoded:
\begin{itemize}
\item Order: each process $P \in \mathbb{P}$ must $\textsc{receive}$ then
either $\textsc{skip}$ or $\textsc{diffuse}$.
\item Progress of time: all processes in $\mathbb{P}$ must $\textsc{skip}$ or $\textsc{diffuse}$
once in each round.
\end{itemize}

Definitions currently missing
\begin{itemize}
\item block \& chain
\item hash function, signature function, verification predicate
\item valid block function, including:
      \begin{itemize}
      \item sig checking,
      \item chaining validity
      \item blocks must come from the past, ie slot $sl' < sl$
      \end{itemize}
\item the maxValid function
\item PRNG/Aux type
\end{itemize}

\section{Protocol $\pi_{\text{DPoS}}$}

This is the second of the four versions of the protocol from the paper. It adds
epochs with a different stake distribution and PRNG per epoch.

In this protocol, a $P \in \mathsf{Process}_{\pi_{\text{DPoS}}}$ is
a state tuple $\sProcess{\sChain}{\sState}{\sSlot} \in
\mathsf{User} \times \mathsf{PrivKey} \times \mathsf{Chain} \times \mathsf{Hash} \times \mathsf{Slot}$

The protocol has a number of global parameters.
\begin{itemize}
\item The initial users $\mathbb{U} = \{U_1, \ldots, U_n\}$ and their keys $\{(\mathsf{sk}_1, \mathsf{vk}_1), \ldots, (\mathsf{sk}_n, \mathsf{vk}_n)\}$
\item The stake distribution $\mathbb{S} \in \mathsf{Stakes}$ for the users of $\mathbb{S} = \{ (\mathsf{vk}_1, s_1), \ldots, (\mathsf{vk}_n, s_n) \}$
\item A leader selection function $\sLeader \in \mathsf{Stakes} \times \mathsf{Aux} \times \mathsf{Slot} \rightarrow \mathsf{User}$
\item A PRNG seed $\rho \in \mathsf{Aux}$ used by the leader selection function
\item A transaction data function $\mathsf{T} \in \mathsf{Slot} \rightarrow \mathsf{Data}$.
\end{itemize}

Note that the transaction data function is not intended to be realistic,
it simply models the otherwise unspecified source of transaction data in
this version of the protocol description.

\begin{equation*}
\frac{
  \begin{array}{c}
    \mathsf{newEpoch}(\sSlot)
    \qquad
    j = \mathsf{epoch}(\sSlot)
    \qquad
    j \geq 2
    \\[1mm]
    \mathbb{S}_j = \mathsf{stakeDist}(\sChain, j)
    \qquad
    \rho_j = \mathsf{beacon}(j)
  \end{array}
}{
  \sSystem{\sProcesses \sPar \sProcess{\sChain}{\sState}{\sSlot}}{\sQueue}
\rightarrow
  \sSystem{\sProcesses \sPar \sProcess{\sChain}{\sState}{\sSlot}}{\sQueue}
} \textsc{epoch}
\end{equation*}

TODO
\begin{itemize}
\item remember all the $\mathbb{S}_j$ for all epochs, or compute from C.
\item remember all the $\rho_j$ for all epochs, or ask beacon
\end{itemize}

\bibliographystyle{plainnat}
\bibliography{references}

\end{document}