Skip to content

Commit

Permalink
*
Browse files Browse the repository at this point in the history
  • Loading branch information
neauoire committed Dec 13, 2024
1 parent 4acd04b commit bdc6b3a
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 253 deletions.
26 changes: 19 additions & 7 deletions etc/fractran.c.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef struct Frag {
typedef struct Rule {
unsigned long num, den;
Frag fnum, fden;
int exhaustive;
} Rule;

char dict[DIC_SZ], *_dict = dict, *syms[PRM_SZ];
Expand Down Expand Up @@ -221,10 +222,17 @@ parse_symbol(char **dst, char *s)
static void
validate(Rule *r)
{
int i;
for(i = r - rules - 1; i >= 0; i--)
int i, j, reafail = 0;
for(i = r - rules - 1, r->exhaustive = 1; i >= 0; i--) {
if(mask(&r->fden, rules[i].den))
fprintf(stdout, "(unreachable)\n");
reafail = 1;
for(j = 0; j < PRM_SZ; j++)
if(r->fnum.regs[j] && rules[i].fden.regs[j]) r->exhaustive = 0;
}
if(reafail)
fprintf(stderr, "(unreachable)");
else if(r->exhaustive)
fprintf(stderr, "(exhaustive)");
r++;
}

Expand Down Expand Up @@ -280,23 +288,27 @@ tokenize(char *buf)
static void
eval(int fuel)
{
int pc = 0;
int pc = 0, steps = 0;
Rule *r = &rules[pc];
while(fuel-- && r->den) {
r = &rules[pc];
if(!mask(&accu, r->den))
pc++;
else {
unsigned long a = frag_int(&accu);
subtractive(&accu, r->den), additive(&accu, r->num);
if(r->exhaustive) {
while(mask(&accu, r->den))
subtractive(&accu, r->den), additive(&accu, r->num);
} else
subtractive(&accu, r->den), additive(&accu, r->num);
if(r->den) {
fprintf(stderr, "%02d %lu × %lu/%lu = %lu, ", pc, a, r->num, r->den, frag_int(&accu));
print_frag(stderr, &accu, 0), fprintf(stderr, "\n");
}
pc = 0;
pc = 0, steps++;
}
}
putchar('\n'), print_frag(stdout, &accu, 0), putchar('\n');
putchar('\n'), print_frag(stdout, &accu, 0), putchar('\n'), fprintf(stderr, "Completed in %d steps.\n", steps - 1);
}

int
Expand Down
179 changes: 97 additions & 82 deletions site/fractran.html
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ <h3 id='fib'>Example: Fibonacci</h3>
08 15869140625 × 1/13 = 1220703125, res^13
</pre>

<h3>Example: Tic-Tac-Toe</h3>
<h3 id='tictactoe'>Example: Tic-Tac-Toe</h3>

<p>Fractran's <b>output</b> capability is limited to the resulting accumulator at the end of an evaluation. The advantage of symbolic rewriting is that registers are already assigned names, so we shall print those instead. As for <b>input</b>, we can type in new symbol tokens and appending their value to the accumulator between evaluations. We can implement a <i>tic-tac-toe</i> in a mere 16 rules:</p>

Expand Down Expand Up @@ -466,7 +466,7 @@ <h3>Example: Tic-Tac-Toe</h3>

<p>A Fractran program specifies the wiring and logic of an interactive application, registers point to symbols in memory and so the bytecode itself is never localized as these strings reside in the application's front-end far from its logic.</p>

<h3>Example: Fizzbuzz</h3>
<h3 id='fizzbuzz'>Example: Fizzbuzz</h3>

<p>Alternatively to getting the resulting program state at the end of an evaluation, we can emit the accumulator at a specific rate during the evaluation by checking if a register is active or not.</p>

Expand Down Expand Up @@ -543,6 +543,71 @@ <h3>Example: Fizzbuzz</h3>
..
</pre>

<h3 id='stack'>Example: Stack Machines</h3>

<p>A <a href='concatenative.html'>stack-machine</a> can be implemented in Fractran, but it's <i>not for the faint of heart</i>. This computation model keeps an entire program state in a single number, and the following stack machine allocates a whole stack into a single register of that number. The theory is that it is possible to keep a stack of zeros and ones in a single register using a <a href='binary.html#stack'>binary encoding</a> for that number.</p>

<ul>
<li>Pushing a <kbd>0</kbd> onto the stack is equivalent to doubling the number.</li>
<li>Pushing a <kbd>1</kbd> is equivalent to doubling and adding 1.</li>
<li>Popping is equivalent to dividing by 2, where the remainder is the number.</li>
</ul>

<p>If we begin with <b>push</b>, we can see that we are doubling the x register, same as demonstrated above. After the evaluation, our LIFO stack has a value of 30, and is equal to <kbd>1</kbd> <kbd>1</kbd> <kbd>1</kbd> <kbd>0</kbd>, where the right-most one is the item on top. Now, for <b>pop</b>, we can halve the x register, again, same as demonstrated above, and keeping the result of the value in a register for 0, and a register for 1.</p>

<pre>
:: push 1 x > A A push 1
:: push 1 > x
:: push 0 x > A A push 0
:: push 0 >

:: pop x x > A pop
:: pop x > 1
:: pop > 0

:: A A > x x
:: A > x
<i>
x push 1 = x^3
x^3 push 1 = x^7
x^7 push 1 = x^15
x^13 push 0 = x^30

x^30 pop : 0 x^15
x^15 pop : 1 x^7
x^7 pop : 1 x^3
x^3 pop : 1 x</i>
</pre>

<p>We can build on these two primitives and define temporary register to keep the result of popping, extra stack operations <b>dup</b> and <b>swap</b>, and a little state-machine to input some of these commands:</p>

<pre>
:: ?#a 0 > 0#a :: ?#a 1 > 1#a
:: ?#b 0 > 0#b :: ?#b 1 > 1#b

:: dup > pop ?#a dup-next
:: dup-next 0#a > 0#a 0#a push-a push-a
:: dup-next 1#a > 1#a 1#a push-a push-a

:: swap > swap-next pop ?#a
:: swap-next > swap-last pop ?#b push-a
:: swap-last > push-b

:: push-a 0#a > push 0
:: push-a 1#a > push 1
:: push-b 0#b > push 0
:: push-b 1#b > push 1

:: 1) > push 1 2) <i>1</i>
:: 2) > push 1 3) <i>1 1</i>
:: 3) > push 1 4) <i>1 1 1</i>
:: 4) > push 0 5) <i>1 1 1 0</i>
:: 5) > swap 6) <i>1 1 0 1</i>
:: 6) > dup <i>1 1 0 1 1</i>

1) x
</pre>

<p>To explore further, try running these <a href='https://git.sr.ht/~rabbits/fractran/tree/main/item/examples' target='_blank'>examples</a> yourself:</p>

<ul>
Expand Down Expand Up @@ -570,17 +635,17 @@ <h3 id='reduction'>Reduction & Catalysts</h3>
href='rewriting.html#catalyst'>catalysts</a>, symbols found on both sides of a
rewrite rule, makes for a simpler implementation and a more usable runtime.</p>

<p>The following two fractions are not equal and reducing the first into the
second, eliminates the capability to match against it <b>only</b> when the
catalyst <code>green</code> is present in the accumulator:</p>

<pre>
:: 15/6 red green > green blue
:: 5/2 red > blue

red green
</pre>

<p>These two fractions are not equal and reducing the first into the
second, eliminates the capability to match against it <b>only</b> when the
catalyst <code>green</code> is present in the accumulator:</p>

<h3>Deadcode Elimination</h3>

<p>An unreachable rule is created when a rule's left-hand side is part of the left-hand side of a rule below it:</p>
Expand All @@ -602,6 +667,32 @@ <h3>Deadcode Elimination</h3>

<p>Rules that are unreachable are considered comments and should not be part of the ruleset during evaluation.</p>

<h3 id='exhaustive'>Exhaustive Rules</h3>
<p>When moving values between registers, each move takes one rewriting and thus can quickly become computationally expensive:</p>
<pre>
:: a > res
:: b > res

AC 1000, a^3 b^3
00 1000 × 3/2 = 1500, a^2 res b^3
00 1500 × 3/2 = 2250, a res^2 b^3
00 2250 × 3/2 = 3375, res^3 b^3
01 3375 × 3/5 = 2025, res^4 b^2
01 2025 × 3/5 = 1215, res^5 b
01 1215 × 3/5 = 729, res^6

Completed in 6 steps.
</pre>

<p>A rule with a right-hand side that does not include symbols present in any of the left-hand sides of the rules above it can be run exhaustively and perform many applications without having to look for the next applicable rule:</p>
<pre>
AC 1000, a^3 b^3
00 1000 × 3/2 = 3375, res^3 b^3
01 3375 × 3/5 = 729, res^6

Completed in 2 steps.
</pre>

<h3 id='reversibility'>Reversibility</h3>

<p>Fractran operators are <a href='reversible_computing.html'>reversible</a>,
Expand All @@ -628,82 +719,6 @@ <h3 id='reversibility'>Reversibility</h3>
:: c- t- cnot > c- t- cnot
</pre>

<h3 id='stack'>Nested Stack Machines</h3>

<p>A <a href='concatenative.html'>stack-machine</a> can be implemented in Fractran, but it's <i>not for the faint of heart</i>. This computation model keeps an entire program state in a single number, and the following stack machine allocates a whole stack into a single register of that number. The theory is that it is possible to keep a stack of zeros and ones in a single register using a <a href='binary.html#stack'>binary encoding</a> for that number.</p>

<ul>
<li>Pushing a <kbd>0</kbd> onto the stack is equivalent to doubling the number.</li>
<li>Pushing a <kbd>1</kbd> is equivalent to doubling and adding 1.</li>
<li>Popping is equivalent to dividing by 2, where the remainder is the number.</li>
</ul>

<p>If we begin with <b>push</b>, we can see that we are doubling the x register, same as demonstrated above. After the evaluation, our LIFO stack has a value of 30, and is equal to <kbd>1</kbd> <kbd>1</kbd> <kbd>1</kbd> <kbd>0</kbd>, where the right-most one is the item on top. Now, for <b>pop</b>, we can halve the x register, again, same as demonstrated above, and keeping the result of the value in a register for 0, and a register for 1.</p>

<pre>
:: push 1 x > A A push 1
:: push 1 > x
:: push 0 x > A A push 0
:: push 0 >

:: pop x x > A pop
:: pop x > 1
:: pop > 0

:: A A > x x
:: A > x
<i>
x push 1 = x^3
x^3 push 1 = x^7
x^7 push 1 = x^15
x^13 push 0 = x^30

x^30 pop : 0 x^15
x^15 pop : 1 x^7
x^7 pop : 1 x^3
x^3 pop : 1 x</i>
</pre>

<p>We can build on these two primitives and define temporary register to keep the result of popping, extra stack operations <b>dup</b> and <b>swap</b>, and a little state-machine to input some of these commands:</p>

<pre>
:: ?#a 0 > 0#a :: ?#a 1 > 1#a
:: ?#b 0 > 0#b :: ?#b 1 > 1#b

:: dup > pop ?#a dup-next
:: dup-next 0#a > 0#a 0#a push-a push-a
:: dup-next 1#a > 1#a 1#a push-a push-a

:: swap > swap-next pop ?#a
:: swap-next > swap-last pop ?#b push-a
:: swap-last > push-b

:: push-a 0#a > push 0
:: push-a 1#a > push 1
:: push-b 0#b > push 0
:: push-b 1#b > push 1

:: 1) > push 1 2) <i>1</i>
:: 2) > push 1 3) <i>1 1</i>
:: 3) > push 1 4) <i>1 1 1</i>
:: 4) > push 0 5) <i>1 1 1 0</i>
:: 5) > swap 6) <i>1 1 0 1</i>
:: 6) > dup <i>1 1 0 1 1</i>

1) x
</pre>

<h3>Nested Syntax</h3>
<p>Rules could be organized in collections reagents, this syntax is currently not supported by the interpreter but might be worthwhile to consider as a extension in the future.</p>
<pre>
:: and {
x y > true
x > false
y > false
> false
}
</pre>

<figure>
<img
src="../media/refs/jacek2.jpg"
Expand Down
Loading

0 comments on commit bdc6b3a

Please sign in to comment.