Misplaced Pages

FRACTRAN

Article snapshot taken from Wikipedia with creative commons attribution-sharealike license. Give it a read and then ask your questions in the chat. We can research this topic together.
Turing-complete esoteric programming language invented by John Conway

FRACTRAN is a Turing-complete esoteric programming language invented by the mathematician John Conway. A FRACTRAN program is an ordered list of positive fractions together with an initial positive integer input n. The program is run by updating the integer n as follows:

  1. for the first fraction f in the list for which nf is an integer, replace n by nf
  2. repeat this rule until no fraction in the list produces an integer when multiplied by n, then halt.

Conway 1987 gives the following FRACTRAN program, called PRIMEGAME, which finds successive prime numbers:

( 17 91 , 78 85 , 19 51 , 23 38 , 29 33 , 77 29 , 95 23 , 77 19 , 1 17 , 11 13 , 13 11 , 15 2 , 1 7 , 55 1 ) {\displaystyle \left({\frac {17}{91}},{\frac {78}{85}},{\frac {19}{51}},{\frac {23}{38}},{\frac {29}{33}},{\frac {77}{29}},{\frac {95}{23}},{\frac {77}{19}},{\frac {1}{17}},{\frac {11}{13}},{\frac {13}{11}},{\frac {15}{2}},{\frac {1}{7}},{\frac {55}{1}}\right)}

Starting with n=2, this FRACTRAN program generates the following sequence of integers:

  • 2, 15, 825, 725, 1925, 2275, 425, 390, 330, 290, 770, ... (sequence A007542 in the OEIS)

After 2, this sequence contains the following powers of 2:

2 2 = 4 , 2 3 = 8 , 2 5 = 32 , 2 7 = 128 , 2 11 = 2048 , 2 13 = 8192 , 2 17 = 131072 , 2 19 = 524288 , {\displaystyle 2^{2}=4,\,2^{3}=8,\,2^{5}=32,\,2^{7}=128,\,2^{11}=2048,\,2^{13}=8192,\,2^{17}=131072,\,2^{19}=524288,\,\dots } (sequence A034785 in the OEIS)

The exponent part of these powers of two are primes, 2, 3, 5, etc.

Understanding a FRACTRAN program

A FRACTRAN program can be seen as a type of register machine where the registers are stored in prime exponents in the argument n {\displaystyle n} .

Using Gödel numbering, a positive integer n {\displaystyle n} can encode an arbitrary number of arbitrarily large positive integer variables. The value of each variable is encoded as the exponent of a prime number in the prime factorization of the integer. For example, the integer

60 = 2 2 × 3 1 × 5 1 {\displaystyle 60=2^{2}\times 3^{1}\times 5^{1}}

represents a register state in which one variable (which we will call v 2 {\displaystyle v_{2}} ) holds the value 2 and two other variables ( v 3 {\displaystyle v_{3}} and v 5 {\displaystyle v_{5}} ) hold the value 1. All other variables hold the value 0.

A FRACTRAN program is an ordered list of positive fractions. Each fraction represents an instruction that tests one or more variables, represented by the prime factors of its denominator. For example:

f 1 = 21 20 = 3 × 7 2 2 × 5 1 {\displaystyle f_{1}={\frac {21}{20}}={\frac {3\times 7}{2^{2}\times 5^{1}}}}

tests v 2 {\displaystyle v_{2}} and v 5 {\displaystyle v_{5}} . If v 2 2 {\displaystyle v_{2}\geq 2} and v 5 1 {\displaystyle v_{5}\geq 1} , then it subtracts 2 from v 2 {\displaystyle v_{2}} and 1 from v 5 {\displaystyle v_{5}} and adds 1 to v3 and 1 to v 7 {\displaystyle v_{7}} . For example:

60 f 1 = 2 2 × 3 1 × 5 1 3 × 7 2 2 × 5 1 = 3 2 × 7 1 {\displaystyle 60\cdot f_{1}=2^{2}\times 3^{1}\times 5^{1}\cdot {\frac {3\times 7}{2^{2}\times 5^{1}}}=3^{2}\times 7^{1}}

Since the FRACTRAN program is just a list of fractions, these test-decrement-increment instructions are the only allowed instructions in the FRACTRAN language. In addition the following restrictions apply:

  • Each time an instruction is executed, the variables that are tested are also decremented.
  • The same variable cannot be both decremented and incremented in a single instruction (otherwise the fraction representing that instruction would not be in its lowest terms). Therefore each FRACTRAN instruction consumes variables as it tests them.
  • It is not possible for a FRACTRAN instruction to directly test if a variable is 0 (However, an indirect test can be implemented by creating a default instruction that is placed after other instructions that test a particular variable.).

Creating simple programs

Addition

The simplest FRACTRAN program is a single instruction such as

( 3 2 ) {\displaystyle \left({\frac {3}{2}}\right)}

This program can be represented as a (very simple) algorithm as follows:

FRACTRAN
instruction
Condition Action
3 2 {\displaystyle {\frac {3}{2}}} v 2 {\displaystyle v_{2}} > 0 Subtract 1 from v 2 {\displaystyle v_{2}}
Add 1 to v 3 {\displaystyle v_{3}}
v 2 {\displaystyle v_{2}} = 0 Stop

Given an initial input of the form 2 a 3 b {\displaystyle 2^{a}3^{b}} , this program will compute the sequence 2 a 1 3 b + 1 {\displaystyle 2^{a-1}3^{b+1}} , 2 a 2 3 b + 2 {\displaystyle 2^{a-2}3^{b+2}} , etc., until eventually, after a {\displaystyle a} steps, no factors of 2 remain and the product with 3 2 {\displaystyle {\frac {3}{2}}} no longer yields an integer; the machine then stops with a final output of 3 a + b {\displaystyle 3^{a+b}} . It therefore adds two integers together.

Multiplication

We can create a "multiplier" by "looping" through the "adder". In order to do this we need to introduce states into our algorithm. This algorithm will take a number 2 a 3 b {\displaystyle 2^{a}3^{b}} and produce 5 a b {\displaystyle 5^{ab}} :

Current state Condition Action Next state
A v 7 {\displaystyle v_{7}} > 0 Subtract 1 from v 7 {\displaystyle v_{7}}
Add 1 to v 3 {\displaystyle v_{3}}
A
v 7 {\displaystyle v_{7}} = 0 and
v 2 {\displaystyle v_{2}} > 0
Subtract 1 from v 2 {\displaystyle v_{2}} B
v 7 {\displaystyle v_{7}} = 0 and
v 2 {\displaystyle v_{2}} = 0 and
v 3 {\displaystyle v_{3}} > 0
Subtract 1 from v 3 {\displaystyle v_{3}} A
v 7 {\displaystyle v_{7}} = 0 and
v 2 {\displaystyle v_{2}} = 0 and
v 3 {\displaystyle v_{3}} = 0
Stop
B v 3 {\displaystyle v_{3}} > 0 Subtract 1 from v 3 {\displaystyle v_{3}}
Add 1 to v 5 {\displaystyle v_{5}}
Add 1 to v 7 {\displaystyle v_{7}}
B
v 3 {\displaystyle v_{3}} = 0 None A

State B is a loop that adds v 3 {\displaystyle v_{3}} to v 5 {\displaystyle v_{5}} and also moves v 3 {\displaystyle v_{3}} to v 7 {\displaystyle v_{7}} , and state A is an outer control loop that repeats the loop in state B v 2 {\displaystyle v_{2}} times. State A also restores the value of v 3 {\displaystyle v_{3}} from v 7 {\displaystyle v_{7}} after the loop in state B has completed.

We can implement states using new variables as state indicators. The state indicators for state B will be v 11 {\displaystyle v_{11}} and v 13 {\displaystyle v_{13}} . Note that we require two state control indicators for one loop; a primary flag ( v 11 {\displaystyle v_{11}} ) and a secondary flag ( v 13 {\displaystyle v_{13}} ). Because each indicator is consumed whenever it is tested, we need a secondary indicator to say "continue in the current state"; this secondary indicator is swapped back to the primary indicator in the next instruction, and the loop continues.

Adding FRACTRAN state indicators and instructions to the multiplication algorithm table, we have:

FRACTRAN
instruction
Current state State
indicators
Condition Action Next state
3 7 {\displaystyle {\frac {3}{7}}} A None v 7 {\displaystyle v_{7}} > 0 Subtract 1 from v 7 {\displaystyle v_{7}}
Add 1 to v 3 {\displaystyle v_{3}}
A
11 2 {\displaystyle {\frac {11}{2}}} v 7 {\displaystyle v_{7}} = 0 and
v 2 {\displaystyle v_{2}} > 0
Subtract 1 from v 2 {\displaystyle v_{2}} B
1 3 {\displaystyle {\frac {1}{3}}} v 7 {\displaystyle v_{7}} = 0 and
v 2 {\displaystyle v_{2}} = 0 and
v 3 {\displaystyle v_{3}} > 0
Subtract 1 from v 3 {\displaystyle v_{3}} A
v 7 {\displaystyle v_{7}} = 0 and
v 2 {\displaystyle v_{2}} = 0 and
v 3 {\displaystyle v_{3}} = 0
Stop
5 7 13 3 11 , 11 13 {\displaystyle {\frac {5\cdot 7\cdot 13}{3\cdot 11}},{\frac {11}{13}}} B v 11 {\displaystyle v_{11}} , v 13 {\displaystyle v_{13}} v 3 {\displaystyle v_{3}} > 0 Subtract 1 from v 3 {\displaystyle v_{3}}
Add 1 to v 5 {\displaystyle v_{5}}
Add 1 to v 7 {\displaystyle v_{7}}
B
1 11 {\displaystyle {\frac {1}{11}}} v 3 {\displaystyle v_{3}} = 0 None A

When we write out the FRACTRAN instructions, we must put the state A instructions last, because state A has no state indicators - it is the default state if no state indicators are set. So as a FRACTRAN program, the multiplier becomes:

( 455 33 , 11 13 , 1 11 , 3 7 , 11 2 , 1 3 ) {\displaystyle \left({\frac {455}{33}},{\frac {11}{13}},{\frac {1}{11}},{\frac {3}{7}},{\frac {11}{2}},{\frac {1}{3}}\right)}

With input 23 this program produces output 5.

The above FRACTRAN program, computing 3 times 2 (so that its input is 2 3 × 3 2 = 72 {\displaystyle 2^{3}\times 3^{2}=72} and its output should be 5 6 {\displaystyle 5^{6}} because 3 times 2 equals 6.

Subtraction and division

In a similar way, we can create a FRACTRAN "subtractor", and repeated subtractions allow us to create a "quotient and remainder" algorithm as follows:

FRACTRAN
instruction
Current state State
indicators
Condition Action Next state
7 13 2 3 11 , 11 13 {\displaystyle {\frac {7\cdot 13}{2\cdot 3\cdot 11}},{\frac {11}{13}}} A v 11 {\displaystyle v_{11}} , v 13 {\displaystyle v_{13}} v 2 > 0 {\displaystyle v_{2}>0} and
v 3 > 0 {\displaystyle v_{3}>0}
Subtract 1 from v 2 {\displaystyle v_{2}}
Subtract 1 from v 3 {\displaystyle v_{3}}
Add 1 to v 7 {\displaystyle v_{7}}
A
1 3 11 {\displaystyle {\frac {1}{3\cdot 11}}} v 2 {\displaystyle v_{2}} = 0 and
v 3 {\displaystyle v_{3}} > 0
Subtract 1 from v 3 {\displaystyle v_{3}} X
5 17 11 {\displaystyle {\frac {5\cdot 17}{11}}} v 3 {\displaystyle v_{3}} = 0 Add 1 to v 5 {\displaystyle v_{5}} B
3 19 7 17 , 17 19 {\displaystyle {\frac {3\cdot 19}{7\cdot 17}},{\frac {17}{19}}} B v 17 {\displaystyle v_{17}} , v 19 {\displaystyle v_{19}} v 7 {\displaystyle v_{7}} > 0 Subtract 1 from v 7 {\displaystyle v_{7}}
Add 1 to v 3 {\displaystyle v_{3}}
B
11 17 {\displaystyle {\frac {11}{17}}} v 7 {\displaystyle v_{7}} = 0 None A
1 3 {\displaystyle {\frac {1}{3}}} X v 3 {\displaystyle v_{3}} > 0 Subtract 1 from v 3 {\displaystyle v_{3}} X
v 3 {\displaystyle v_{3}} = 0 Stop

Writing out the FRACTRAN program, we have:

( 91 66 , 11 13 , 1 33 , 85 11 , 57 119 , 17 19 , 11 17 , 1 3 ) {\displaystyle \left({\frac {91}{66}},{\frac {11}{13}},{\frac {1}{33}},{\frac {85}{11}},{\frac {57}{119}},{\frac {17}{19}},{\frac {11}{17}},{\frac {1}{3}}\right)}

and input 2311 produces output 57 where n = qd + r and 0 ≤ r < d.

Conway's prime algorithm

Conway's prime generating algorithm above is essentially a quotient and remainder algorithm within two loops. Given input of the form 2 n 7 m {\displaystyle 2^{n}7^{m}} where 0 ≤ m < n, the algorithm tries to divide n+1 by each number from n down to 1, until it finds the largest number k that is a divisor of n+1. It then returns 2 7 and repeats. The only times that the sequence of state numbers generated by the algorithm produces a power of 2 is when k is 1 (so that the exponent of 7 is 0), which only occurs if the exponent of 2 is a prime. A step-by-step explanation of Conway's algorithm can be found in Havil (2007).

For this program, reaching the prime number 2, 3, 5, 7... requires respectively 19, 69, 281, 710,... steps (sequence A007547 in the OEIS).

A variant of Conway's program also exists, which differs from the above version by two fractions: ( 17 91 , 78 85 , 19 51 , 23 38 , 29 33 , 77 29 , 95 23 , 77 19 , 1 17 , 11 13 , 13 11 , 15 14 , 15 2 , 55 1 ) {\displaystyle \left({\frac {17}{91}},{\frac {78}{85}},{\frac {19}{51}},{\frac {23}{38}},{\frac {29}{33}},{\frac {77}{29}},{\frac {95}{23}},{\frac {77}{19}},{\frac {1}{17}},{\frac {11}{13}},{\frac {13}{11}},{\frac {15}{14}},{\frac {15}{2}},{\frac {55}{1}}\right)}

This variant is a little faster: reaching 2, 3, 5, 7... takes it 19, 69, 280, 707... steps (sequence A007546 in the OEIS). A single iteration of this program, checking a particular number N for primeness, takes the following number of steps: N 1 + ( 6 N + 2 ) ( N b ) + 2 d = b N 1 N d , {\displaystyle N-1+(6N+2)(N-b)+2\sum \limits _{d=b}^{N-1}\left\lfloor {\frac {N}{d}}\right\rfloor ,} where b < N {\displaystyle b<N} is the largest integer divisor of N and x {\displaystyle \lfloor x\rfloor } is the floor function.

In 1999, Devin Kilminster demonstrated a shorter, ten-instruction program: ( 7 3 , 99 98 , 13 49 , 39 35 , 36 91 , 10 143 , 49 13 , 7 11 , 1 2 , 91 1 ) . {\displaystyle \left({\frac {7}{3}},{\frac {99}{98}},{\frac {13}{49}},{\frac {39}{35}},{\frac {36}{91}},{\frac {10}{143}},{\frac {49}{13}},{\frac {7}{11}},{\frac {1}{2}},{\frac {91}{1}}\right).} For the initial input n = 10 successive primes are generated by subsequent powers of 10.

Other examples

The following FRACTRAN program:

( 3 11 2 2 5 , 5 11 , 13 2 5 , 1 5 , 2 3 , 2 5 7 , 7 2 ) {\displaystyle \left({\frac {3\cdot 11}{2^{2}\cdot 5}},{\frac {5}{11}},{\frac {13}{2\cdot 5}},{\frac {1}{5}},{\frac {2}{3}},{\frac {2\cdot 5}{7}},{\frac {7}{2}}\right)}

calculates the Hamming weight H(a) of the binary expansion of a i.e. the number of 1s in the binary expansion of a. Given input 2, its output is 13. The program can be analysed as follows:

FRACTRAN
instruction
Current state State
indicators
Condition Action Next state
3 11 2 2 5 , 5 11 {\displaystyle {\frac {3\cdot 11}{2^{2}\cdot 5}},{\frac {5}{11}}} A v 5 {\displaystyle v_{5}} , v 11 {\displaystyle v_{11}} v 2 {\displaystyle v_{2}} > 1 Subtract 2 from v 2 {\displaystyle v_{2}}
Add 1 to v 3 {\displaystyle v_{3}}
A
13 2 5 {\displaystyle {\frac {13}{2\cdot 5}}} v 2 {\displaystyle v_{2}} = 1 Subtract 1 from v 2 {\displaystyle v_{2}}
Add 1 to v 13 {\displaystyle v_{13}}
B
1 5 {\displaystyle {\frac {1}{5}}} v 2 {\displaystyle v_{2}} = 0 None B
2 3 {\displaystyle {\frac {2}{3}}} B None v 3 {\displaystyle v_{3}} > 0 Subtract 1 from v 3 {\displaystyle v_{3}}
Add 1 to v 2 {\displaystyle v_{2}}
B
2 5 7 {\displaystyle {\frac {2\cdot 5}{7}}} v 3 {\displaystyle v_{3}} = 0 and
v 7 {\displaystyle v_{7}} > 0
Subtract 1 from v 7 {\displaystyle v_{7}}
Add 1 to v 2 {\displaystyle v_{2}}
A
7 2 {\displaystyle {\frac {7}{2}}} v 3 {\displaystyle v_{3}} = 0 and
v 7 {\displaystyle v_{7}} = 0 and
v 2 {\displaystyle v_{2}} > 0
Subtract 1 from v 2 {\displaystyle v_{2}}
add 1 to v 7 {\displaystyle v_{7}}
B
v 2 {\displaystyle v_{2}} = 0 and
v 3 {\displaystyle v_{3}} = 0 and
v 7 {\displaystyle v_{7}} = 0
Stop

Notes

  1. Gödel numbering cannot be directly used for negative integers, floating point numbers or text strings, although conventions could be adopted to represent these data types indirectly. Proposed extensions to FRACTRAN include FRACTRAN++ and Bag.
  2. A similar multiplier algorithm is described at the Esolang FRACTRAN page.

See also

References

  1. Guy 1983, p. 26; Conway & Guy 1996, p. 147
  2. Guy 1983, p. 33
  3. Havil 2007, p. 176
  4. John Baez, Puzzle #4, The n-Category Café

External links

Esoteric programming languages
Category
Categories: