Only this pageAll pages
Powered by GitBook
1 of 30

1.1.0

Loading...

The Varphi Language Standard

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Writing Varphi Programs

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Turing Machine Theory

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Welcome

Welcome to the Official Varphi Docs

Learn everything there is to know about Varphi!

Tallies and Blanks

In Varphi, a tally represents a tape cell containing a tally and is denoted by the character 1. A blank represents an empty tape cell and is denoted by 0.

Conceptual Note

The concept of a blank in Varphi is not to be interpreted as adding a new possible tape character. In the strictest sense, there is only one possible character in the alphabet of Turing machines, and that is a tally (given by 1 in Varphi). But if a tally is not present in a tape cell, then that tape cell is blank (represented using 0 in Varphi), and does not contain any tape character.

The Varphi Language Standard

Syntax and rules.

Writing Varphi Programs

How to think about algorithms, how to run Varphi programs, and good practices.

Turing Machine Theory

The basics of Turing machines.

📜
👨‍💻
📚

State Names

A state name in Varphi starts with the letter q, followed by at least one alphanumeric character or underscore (_).

Examples of valid state names include:

  • q0

  • qzero

  • q_My_State_

  • q_my_state__

The lexer uses the following pattern to match state names:

q[a-zA-Z0-9_]+

Running Varphi Programs

File Extensions

The Varphi Interpreter does not explicitly check for a particular extension for input files. However, it is considered a good practice to use the .vp extension anyways.

Using the Varphi Interpreter

qDeleteFirstTallyOrHalt 1 qSkipLeftNumberTallies1 0 R
qDeleteFirstTallyOrHalt 0 qHalt 0 R
qSkipLeftNumberTallies1 1 qSkipLeftNumberTallies1 1 R
qSkipLeftNumberTallies1 0 qSkipRightNumberTalliesAndWriteTallyAtEnd 0 R
qSkipRightNumberTalliesAndWriteTallyAtEnd 1 qSkipRightNumberTalliesAndWriteTallyAtEnd 1 R
qSkipRightNumberTalliesAndWriteTallyAtEnd 0 qSkipRightNumberTallies 1 L
qSkipRightNumberTallies 1 qSkipRightNumberTallies 1 L
qSkipRightNumberTallies 0 qSkipLeftNumberTallies2 0 L
qSkipLeftNumberTallies2 1 qSkipLeftNumberTallies2 1 L
qSkipLeftNumberTallies2 0 qDeleteFirstTallyOrHalt 0 R

The first step is to create a file and save this code to it. We'll assume the file's name is add.vp , but feel free to name it anything you wish!

$ <PATH TO vpi> add.vp
$ <PATH TO vpi> add.vp
111011
000011111

Remark: The Varphi Interpreter does not produce any output when you execute it on an input program, since it will be waiting for the input tape on standard input. No prompt appears that asks for this. It is common to confuse this as the interpreter "loading" or "hanging," when in reality it is just waiting for the input tape.

The reason why no output is produced is to force the only standard output produced to be the output tape, which can then be easily redirected into another simulated Turing machine (this is how we do composition!).

To get a prompt asking you to provide the input tape, use the -p , or -enable-prompts option. For example:

$ <PATH TO vpi> -p add.vp
Input Tape: 111011
Output Tape: 000011111

Now recall the output convention from the last section:

The Varphi interpreter automatically prints out all tape cells that have ever been accessed. This includes tape cells that have been written to (even when writing the input tape) and read from.

This guide assumes you have already have the Varphi Interpreter (vpi) installed on your machine. If not, please refer to the .

For this guide, we'll use the Varphi program that we created from the , where we add two positive integers. For your convenience, we have included it below (the version without comments):

We'll now run this program on our example from the last section, where we added 333 and 222. To do so, run the following command

You should notice that no output is produced, for the interpreter is waiting for you to provide the input tape. Since we're adding 333 and 222, the input tape is 111011 (remember, 0 represents a blank tape cell, not a tape cell with the character "0"). Type this string into your terminal and hit ENTER. The output tape should then be printed on the terminal.

There shall only be one contiguous block of tallies, which will represent the output of the Turing machine. If there are nnn tallies in the contiguous block, then the number being represented by the tape is nnn.

Under this output convention, the output tape, 000011111 , represents the decimal number 555, which is a correct result (as 3+2=53 + 2 = 53+2=5)!

last section

Varphi Programs

Varphi programs are extremely simple. They consist of , separated by newlines. They can also include .

Varphi supports both deterministic and . Nondeterministic programs have two or more lines with the same condition, but with different instructions.

lines
comments
nondeterministic Turing programs

Debugging Varphi Programs

Things Can Go Wrong

Writing Varphi programs is not like writing programs in other languages, since it uses a completely different paradigm. It is very easy to write the wrong state name in the instruction part of a line, or to have incorrect logic somewhere. When things do go wrong, you can debug your code with Varphi.

The Varphi Command-Line Debugger

Let's run the Varphi program in debug mode. Run the following command

$ <PATH TO vpi> -d add.vp
$ <PATH TO vpi> -d add.vp
Input Tape: 111011
State:  qDeleteFirstTallyOrHalt
Tape:  [{1}]11011
Press ENTER to step...

The debugger shows you the current state, as well as some details of the tape. You may notice the square braces [] and curly braces {} . These are explained below:

  • Square braces [] around an element of the tape indicate that the head is currently stationed at that tape cell.

  • Curly braces {} around an element of the tape indicate that this tape cell was the tape cell which held the first tally in the input tape. It can be used as a "reference point" when debugging.

As you can see from the output of the debugger, you can step through the program by pressing ENTER. When the program finishes executing, the output tape will be printed and the debugger will exit.

In case you're interested, here's the whole session output for this debugger run:

$ <PATH TO vpi> -d add.vp
Input Tape: 111011
State:  qDeleteFirstTallyOrHalt
Tape:  [{1}]11011
Press ENTER to step...

State:  qSkipLeftNumberTallies1
Tape:  {0}[1]1011
Press ENTER to step...

State:  qSkipLeftNumberTallies1
Tape:  {0}1[1]011
Press ENTER to step...

State:  qSkipLeftNumberTallies1
Tape:  {0}11[0]11
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}110[1]1
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}1101[1]
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}11011[0]
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}1101[1]1
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}110[1]11
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}11[0]111
Press ENTER to step...

State:  qSkipLeftNumberTallies2
Tape:  {0}1[1]0111
Press ENTER to step...

State:  qSkipLeftNumberTallies2
Tape:  {0}[1]10111
Press ENTER to step...

State:  qSkipLeftNumberTallies2
Tape:  [{0}]110111
Press ENTER to step...

State:  qDeleteFirstTallyOrHalt
Tape:  {0}[1]10111
Press ENTER to step...

State:  qSkipLeftNumberTallies1
Tape:  {0}0[1]0111
Press ENTER to step...

State:  qSkipLeftNumberTallies1
Tape:  {0}01[0]111
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}010[1]11
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}0101[1]1
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}01011[1]
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}010111[0]
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}01011[1]1
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}0101[1]11
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}010[1]111
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}01[0]1111
Press ENTER to step...

State:  qSkipLeftNumberTallies2
Tape:  {0}0[1]01111
Press ENTER to step...

State:  qSkipLeftNumberTallies2
Tape:  {0}[0]101111
Press ENTER to step...

State:  qDeleteFirstTallyOrHalt
Tape:  {0}0[1]01111
Press ENTER to step...

State:  qSkipLeftNumberTallies1
Tape:  {0}00[0]1111
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}000[1]111
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}0001[1]11
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}00011[1]1
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}000111[1]
Press ENTER to step...

State:  qSkipRightNumberTalliesAndWriteTallyAtEnd
Tape:  {0}0001111[0]
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}000111[1]1
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}00011[1]11
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}0001[1]111
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}000[1]1111
Press ENTER to step...

State:  qSkipRightNumberTallies
Tape:  {0}00[0]11111
Press ENTER to step...

State:  qSkipLeftNumberTallies2
Tape:  {0}0[0]011111
Press ENTER to step...

State:  qDeleteFirstTallyOrHalt
Tape:  {0}00[0]11111
Press ENTER to step...

State:  qHalt
Tape:  {0}000[1]1111
Press ENTER to step...

Output Tape: 000011111
Number of Steps: 40
Number of Tape Cells Accessed: 9
$ 

The Varphi Command-Line Debugger ships with the Varphi interpreter, and can be used by supplying the -d option to vpi . We'll continue to use our running example of the addition program from .

Running with the -d option automatically enables prompting (and also, it will enable ), so you will be prompted for an input tape this time. Let's do that:

this section
Complexity Analysis

Addressing Ambiguities

The "Top-Left" Rule

Arguably the only ambiguity in a Varphi program is the starting state. How is the state which the Turing machine starts with determined?

The "Top-Left" Rule is a rule that can be applied to determine the starting state of any Varphi program. Simply select the state located at the top-left corner of the program. For example, suppose your program looks like this:

q0 1 q0 1 R
q0 0 q1 1 R
q1 0 q2 1 R

Then, the starting state is q0.

The "At Least One Tally" Rule

Input tapes must include at least one tape cell with a tally. If not, a runtime error will be thrown.

The "Leftmost Tally" Rule

A standard that is followed by Turing machine developers is to make the initial position of the head be the leftmost tally on the tape. This convention is adopted by Varphi. The leftmost tally is guaranteed to exist by the .

"At Least One Tally" Rule

Your First Varphi Program

Get started with Varphi and write your first program from scratch.

The objective of this tutorial is to show how to write a simple program with Varphi. We will show how to go about thinking about the algorithm, and then how to translate that algorithm into Varphi.

Objective of the Turing Machine

Input and Output Representation Conventions

The input tape's representation convention will be as follows:

To represent two positive integers xxx and yyy, repeat xxx tallies, followed by a blank, followed by yyy tallies. Leave the rest of the tape blank.

The output tape's representation convention will be as follows:

There shall only be one contiguous block of tallies, which will represent the output of the Turing machine. If there are nnn tallies in the contiguous block, then the number being represented by the tape is nnn.

Thinking About the Algorithm

When thinking about how to design Turing machine algorithms, it often helps to think about an example. Suppose we would like to add the positive integers 333 and 222. Under the input representation convention, the input tape to the machine will look like the following:

We would like to "merge" these two numbers to form a contiguous block with five tallies on it. One may think about this as perhaps shifting all the tallies of the left (or right) number to the right (or left) by one tape cell. The way we will implement it is by "teleporting" the left (or right) number to appear immediately to the right (or left) of the right (or left) number. This is depicted below. Again, this is by no means the most efficient way to do this, but we implement it in this way for demonstration purposes.

A way to perform such an algorithm is to transfer each individual tally to the left of the right number, one-by-one. That is, for every tally in the left number, delete it, then go to the rightmost tally of the right number and replace the blank cell to the right of it with a tally.

Let's phrase this in a more "Turing-machine-like" way. For the purposes of this algorithm, let's call the blank tape cell separating the two numbers on the input tape the middle blank. Now recall that the Turing machine's head always starts off at the leftmost tally. So, what we'll do is replace that tally with a blank, then pass all of the remaining tallies of the left number (moving the head to the right) until we hit the middle blank. Once we hit this middle blank, we'll skip it, then skip all of the tallies of the right number (again, still moving the head to the right) until we hit the first blank to the right of the right number. Then, write a tally to this blank tape cell. Now we have successfully transferred the first tally of the left number to the right place. To start working on the rest of the tallies of the left number, skip through the tallies of the right number (moving the head left this time) until we hit the middle blank. Once we hit the middle blank, we'll skip it, then skip all of the tallies of the left number (again, still moving the head to the left) until we hit the first blank to the left of the left number. Then, move the head one position to the right. If the tape cell at this tape cell is blank, then we've successfully moved all the tallies of the left number to the right of the right number. Otherwise, we still have tallies to move, and we can restart the same process we took with the initial tally we moved.

Hopefully this algorithm makes intuitive sense. However, notice how much it took us to describe it in English. Below, you'll see the equivalent Varphi algorithm, and you can judge for yourself if it makes writing such algorithms easier!

Writing the Varphi Program

Now that we have an algorithm, we can start to write it in Varphi. You may be able to see from the algorithm's description that we need six states:

  1. A state for replacing the leftmost tally of the left number with a blank

  2. A state for skipping the tallies of the left number, moving towards the right

  3. A state for skipping the tallies of the right number, moving towards the right

  4. A state for skipping the tallies of the right number, moving towards the left

  5. A state for skipping the tallies of the left number, moving towards the left

  6. A halting state

Instead of describing in English the function of each state and how it connects with other states, we've decided that a Varphi program may actually be the clearest way to do this. Here's the Varphi program describing this Turing machine:

/*
qDeleteFirstTallyOrHalt
Replace the leftmost tally of the left number with a blank.
If there are no tallies left in the number, halt.
This state assumes the head is pointed towards the first tally of the left number,
if any tallies remain.
After erasing the first tally, transition to qSkipLeftNumberTallies.
*/
qDeleteFirstTallyOrHalt 1 qSkipLeftNumberTallies1 0 R
qDeleteFirstTallyOrHalt 0 qHalt 0 R

/*
qSkipLeftNumberTallies
Traverse the tallies of the left number (moving right) without modifying them, then
transition to qSkipRightNumberTalliesAndWriteTallyAtEnd.
*/
qSkipLeftNumberTallies1 1 qSkipLeftNumberTallies1 1 R
qSkipLeftNumberTallies1 0 qSkipRightNumberTalliesAndWriteTallyAtEnd 0 R

/*
qSkipRightNumberTalliesAndWriteTallyAtEnd
Traverse the tallies of the right number (moving right) without modifying them.
After reaching the end of the right number, insert a tally at the tape cell
immediately to the right.
*/
qSkipRightNumberTalliesAndWriteTallyAtEnd 1 qSkipRightNumberTalliesAndWriteTallyAtEnd 1 R
qSkipRightNumberTalliesAndWriteTallyAtEnd 0 qSkipRightNumberTallies 1 L

/*
qSkipRightNumberTallies
Traverse the tallies of the right number (moving left) without modifying them,
then transition to qSkipLeftNumberTallies2.
*/
qSkipRightNumberTallies 1 qSkipRightNumberTallies 1 L
qSkipRightNumberTallies 0 qSkipLeftNumberTallies2 0 L


/*
qSkipLeftNumberTallies2 
Traverse the tallies of the left number (moving left) without modifying them,
then transition to qDeleteFirstTallyOrHalt, leaving the head at the first tally of the left number (if it exists).
*/
qSkipLeftNumberTallies2 1 qSkipLeftNumberTallies2 1 L
qSkipLeftNumberTallies2 0 qDeleteFirstTallyOrHalt 0 R

Here's a version without comments:

qDeleteFirstTallyOrHalt 1 qSkipLeftNumberTallies1 0 R
qDeleteFirstTallyOrHalt 0 qHalt 0 R
qSkipLeftNumberTallies1 1 qSkipLeftNumberTallies1 1 R
qSkipLeftNumberTallies1 0 qSkipRightNumberTalliesAndWriteTallyAtEnd 0 R
qSkipRightNumberTalliesAndWriteTallyAtEnd 1 qSkipRightNumberTalliesAndWriteTallyAtEnd 1 R
qSkipRightNumberTalliesAndWriteTallyAtEnd 0 qSkipRightNumberTallies 1 L
qSkipRightNumberTallies 1 qSkipRightNumberTallies 1 L
qSkipRightNumberTallies 0 qSkipLeftNumberTallies2 0 L
qSkipLeftNumberTallies2 1 qSkipLeftNumberTallies2 1 L
qSkipLeftNumberTallies2 0 qDeleteFirstTallyOrHalt 0 R

The Turing machine we will design for this guide performs binary addition (that is, addition of two numbers), specifically on numbers from the set of positive integers, Z+\mathbb{Z}^+Z+ in a more unique way (a more efficient way is given ).

That's it! You've just written your first Varphi program

🎉
here

Comments

Comments enhance code readability by providing explanations and context. They can also be used to temporarily disable code when testing alternate code.

Varphi conveniently uses C-style comments. There are two types of comments in Varphi:

  1. Inline (single-line) comments

  2. Block (multi-line) comments

Inline Comments

An inline comment begins with //. Any text following // on the same line is ignored by the compiler and does not affect execution.

Inline comments can appear on lines of a source file by themselves:

// This is a comment!

Inline comments can also appear at the end of a Varphi line:

q0 1 q0 1 R // If a tally is encountered while on state q0, skip it...

Block Comments

A block comment begins with /* and ends with */. Any text enclosed within these markers is ignored by the compiler. Block comments are useful for providing detailed explanations spanning multiple lines.

Here's an example of a block comment spanning multiple lines:

/* 
State q0:
- Skip all cells with tallies
- When the first blank tape cell is reached, put a tally there and halt
*/
q0 1 q0 1 R
q0 0 q1 1 L

Head Directions

In Varphi, head movement directions are represented using uppercase letters:

  1. L : Move left

  2. R : Move right

The characters "l" and "r" (lowercase "L" and "R") are not interpreted as "left" and "right" by the lexer, and will result in a syntax error.

Good Practices

Comments

  1. The purpose of the state

  2. What the machine does if a tally is encountered at the current tape cell when on the state

  3. What the machine does if a blank tape cell is encountered at the current tape cell when on the state

Number of States

When possible, try to limit the number of states your Varphi program uses to avoid a large file. This may be accomplished by moving to a simple algorithm. This is a concept that is applied in every other programming language (although not necessarily with state names like in Varphi, but perhaps with variables).

State Names

State names can follow any identifier naming case style you prefer. However, you should ensure that the names of your states are clear, especially in larger programs, as the number of states required by algorithms tends to grow extremely fast as the algorithms become more complex.

File Naming Conventions

Files should be given a name that is descriptive of the Turing machine they represent, and should end with the .vp extension.

The .vp extension is not a requirement for Varphi files, but it is conventional to give Varphi files this extension.

Final Move of the Head

On a Varphi line where you are transitioning to a halting state, pay attention to the direction you move the head before halting. If possible, move the head in a direction such that its final position will be an already-visited tape cell. If you move the head in a direction such that its final position is not an already visited tape cell, then that tape cell will be considered visited, and will be displayed in the output tape (the Varphi Interpreter will automatically display all visited tape cells in the output tape).

From our example in , it is clear that writing comments to explain what each state does is important for readers to understand your programs.

To document a state, you should open a before it and try your best to explain the following details:

this section
block comment

Complexity Analysis

A very common reason for teaching Turing machines is to give an introduction to complexity analysis. Varphi provides a mechanism for determining both the time and space complexity of a Turing machine.

$ <PATH TO vpi> -c multiplicationByTwo.vp
Input Tape: 1
Output Tape: 1100
Number of Steps: 11
Number of Tape Cells Accessed: 4

$ <PATH TO vpi> -c multiplicationByTwo.vp
Input Tape: 11
Output Tape: 111100
Number of Steps: 21
Number of Tape Cells Accessed: 6

$ <PATH TO vpi> -c multiplicationByTwo.vp
Input Tape: 111
Output Tape: 11111100
Number of Steps: 35
Number of Tape Cells Accessed: 8

$ <PATH TO vpi> -c multiplicationByTwo.vp
Input Tape: 1111
Output Tape: 1111111100
Number of Steps: 53
Number of Tape Cells Accessed: 10

$ <PATH TO vpi> -c multiplicationByTwo.vp
Input Tape: 11111
Output Tape: 111111111100
Number of Steps: 75
Number of Tape Cells Accessed: 12

$ <PATH TO vpi> -c multiplicationByTwo.vp
Input Tape: 111111
Output Tape: 11111111111100
Number of Steps: 101
Number of Tape Cells Accessed: 14

Notice that if the -c or --complexity option is specified, prompts asking for the input tape will automatically appear.

If you do the math, you will see that the time-complexity of this machine is quadratic in nature, and follows the following quadratic equation (where nnn is the length of the input tape):

f(n)=2n2+4n+5f(n)=2n ^2 +4n+5f(n)=2n2+4n+5

Therefore, we can conclude that the runtime complexity (both best- and worst-case) is Θ(n2)\Theta(n^2)Θ(n2) for this Turing machine.

On the other hand, the space-complexity of this machine is linear in nature, and follows the following linear equation (where nnn is the length of the input tape):

f(n)=2n+2f(n)=2n+2f(n)=2n+2

Therefore, we can conclude that the space complexity (both best- and worst-case) is Θ(n)\Theta(n)Θ(n) for this Turing machine.

To analyze the complexity of a Turing machine, pass the -c, or --complexity, option to the Varphi Interpreter. For example, below we show a session where the complexity of a is computed on various input tapes:

machine that multiplies a number by two

Addition By One

q0 1 q0 1 R
q0 0 qf 1 R

Below is a program that adds one tally to an input tape (which, by the Rule, must contain at least one tally)

"At Least One Tally"

The Varphi VS Code Extension

To make development easier for those who prefer a graphical environment over a command-line, a language extension was developed for Microsoft's Visual Studio Code (VS Code). This document shows how to use the extension to enable Varphi development in VS Code.

Opening Varphi Programs in VS Code

The extension will only recognize files with the ".vp" extension as being Varphi files. Thus, please ensure you name your Varphi files with this extension.

Once you create a Varphi file and open it in VS Code, you should see several indicators that the extension is functioning properly. The first of these is that the file should be given a unique icon in the file's tab and in the explorer panel. For example, here's how the tab of a file named "merge.vp" will look like:

And here's what it will appear as in the explorer panel:

Another indicator is that the language mode (usually displayed in the bottom-right corner of the window) will indicate that the current language mode is "Varphi":

The third indicator is that there will be two buttons in the top-left of the window.

These buttons allow for debugging and running the current program, respectively.

The final indicator is that the source code will be colored. For example:

Running Varphi Programs in VS Code

With a Varphi file opened, click the "Run Program" button in the top-left corner of the window, shown below

You will then be prompted for the input tape:

After inputting this and pressing Enter, you may (if this is your first time using the extension) receive a prompt asking for the path to the Varphi Interpreter. Please input the path to the vpi binary you installed earlier.

IMPORTANT: When entering the path to the Varphi Interpreter, do not use quotes. Also, please input the complete path to the executable and not just the parent directory of the executable.

If you need to change the path to the Varphi Interpreter in VS Code (which will be saved after the first time you input it), go to File -> Preferences -> Settings, then search for "varphi", and you should see the following setting:

You can enter the new path here to overwrite the saved one.

Next, click View -> Debug Console to open the Debug Console, where the output tape will be displayed:

Debugging Varphi Programs in VS Code

Varphi's VS Code language extension provides a graphical debugging interface, enabling stepping through Varphi programs line-by-line.

To get started, open a Varphi program in VS Code and press the "Debug Program" button:

You will then be prompted for the input tape:

After inputting this and pressing Enter, you may (if this is your first time using the extension) receive a prompt asking for the path to the Varphi Interpreter. Please input the path to the vpi binary you installed earlier.

Next, from the side-menu, open the "Run and Debug" panel:

Now expand the VARIABLES > Machine Variables menu in the Run and Debug panel, and you should see the following variables:

Here's an explanation of each variable:

  1. Tape: Shows each tape cell. 1 means that tape cell has a tally, and 0 means that tape cell has a blank. The tape cell that held the leftmost tally of the input tape will be surrounded by curly braces ({}). The tape cell that the head is currently stationed at is surrounded by square brackets ([]).

  2. State: The name of the current state of the machine.

  3. Head: The index (0-indexed) of the tape cell that the head is currently positioned at. It is a redundancy with the square bracket notation in the Tape variable.

  4. Tape Zero : The index (0-indexed) of the tape cell that held the leftmost tally of the input tape. It is a redundancy with the curly brace notation in the Tape variable.

You will also notice that the source code has a line highlighted in yellow:

When a line is highlighted like this, it means that the line's condition applies, and its instruction will be executed after the next step.

To step the program, you should use the "Step Over" button in the debug options:

You can restart the debugging session with the "Restart" button:

You can stop the debugging session with the "Stop" button

Debugging with Breakpoints

The Varphi VS Code extension also supports setting breakpoints for debugging sessions. To do this, you can (before starting the debugging session) hover to the left of the line(s) you wish to set a breakpoint at in the Varphi source and then click the red dot:

After clicking, the red dot should persist (until you click it again, which will remove it):

Now, simply start debugging your program as normal, and you'll notice that the first highlighted line will be one of the lines you set a breakpoint at:

From here you can step through the code using the "Step Over" button as before and possibly hit lines that aren't breakpoints. But if you'd like to jump to the next breakpoint, you can use the "Continue" button:

This document assumes that you have the extension and all its prerequisites installed. To view installation steps for the language extension, please view the .

Welcome

Varphi Language Standard

Welcome to the official documentation for the Varphi language. This section outlines the core concepts and syntax used in Varphi programs.

Coin Flip

qStart 1 qHeads 0 R
qStart 1 qTails 0 R

qHeads 0 qWrite1 0 R
qTails 0 qWrite2 0 R

qWrite1 0 qHalt 1 R
qWrite2 0 qWrite1 1 R

Below is an example of a Varphi program that, when given an input tape containing exactly one tally, returns an output tape containing one or two tallies.

nondeterministic

Turing Machine Tapes

The Tape

In the context of a Turing machine, the tape is a component that serves as a place to store information. The tape can be thought of as as paper that is divided into squares, which we will refer to as tape cells. Each tape cell can either

  1. Be left empty

  2. Contain a tally (i.e., 111)

A special thing about the tape, and also one of the reasons why Turing machines are strictly theoretical, is that it spans infinitely. That is, there are infinitely many empty tape cells spanning in both directions.

We can use the tape as a means of representing numbers. Since tape cells can only contain the symbol 111 if they are not left blank, we will have to use the unary number system to represent numbers. For example, here's a representation of a tape containing the decimal number 777, assuming the representation convention is to repeat 111 nnn times to represent a number n∈Z+n\in\mathbb{Z}^+n∈Z+.

As you can see, we represented the decimal number 777 by writing seven 111s side-by-side. On the left and right of the number are infinite tape cells that are blank.

Since we now have access to the concept of blank tape cells on our tape, we can also use such blank tape cells in our representation conventions. For example, here's a representation convention that allows for representing multiple numbers on the tape:

To represent a multiset of positive integers [x1,x2,...,xN][x_1,x_2,...,x_N][x1​,x2​,...,xN​], write x1x_1x1​ 111s, followed by a blank, followed by x2x_2x2​ 111s, followed by a blank, and so on...

We use the terms "a blank tape cell" and "a blank" interchangeably in this text.

Here's a representation of a tape containing the two decimal numbers 222 and 333:

A Note On Representation Conventions

With Turing machines, a restriction is placed on the initial state of the tape. It must contain at least one tally initially. Therefore, when choosing your representation convention for some domain, ensure that all elements of the domain can be represented using at least one tally.

Subsection of a tape whose only contents are the decimal number 777.
Subsection of a tape containing the decimal numbers 222 and 333.
Prompt for the input tape.
\

Multiplication By Two

Below is a program accepting a single contiguous block of tallies (containing at least one tally) and duplicates it. The output tape will be a contiguous block of tallies containing double the tallies in the original contiguous block of tallies on the input tape.

q0 1 q1 0 R // "Mark" the current tally from the first number by changing it to 0
q0 0 qmerge 0 R // No more tallies from the first number, "merge" the two halves of the doubled number
q1 1 q1 1 R // Skip over the rest of the tallies from the first number
q1 0 q2 0 R // We've reached the middle blank
q2 1 q2 1 R // Skip over the tallies from the second number
q2 0 q3 1 L // We've reached the end of the first number, place a tally here
q3 1 q3 1 L // Skip over the tallies from the second number (moving left now)
q3 0 q4 0 L // We've reached the middle blank
q4 1 q4 1 L // Skip over the tallies from the first number (moving left now)
q4 0 q0 1 R // We've reached the beginning of the first number. Return the tally that we replaced with a blank, and point the head to the next tally of the first number and restart

qmerge 1 qmerge1 1 L // When we hit qmerge, the head will be pointed at the first tally from the second half. Shift to the left to go to the middle blank
qmerge1 0 qmerge2 1 R // Change the middle blank to a tally
qmerge2 1 qmerge2 1 R // Skip over the tallies of the second half
qmerge2 0 qmerge3 0 L // We've reached the end of the second half, but there's one more tally at the far right of the second half. Remove it
qmerge3 1 qh 0 R // Replace the last tally of the second half with a blank

Add Two Numbers

Below is a Varphi program that adds (i.e., "merges") two contiguous blocks of tallies (containing at least one tally each) separated by a blank tape cell into one contiguous block of tallies.

q0 1 q1 0 R // Remove first tally of left number
q1 1 q1 1 R // Skip remaining tallies of left number
q1 0 q2 1 R // Make middle blank be a tally

Lines

Structure

A line represents a transition rule in the Turing machine. Every line consists of five elements in the following order:

  1. A state name representing the current state of the Turing machine.

  2. A tally or blank representing the condition of the tape cell that the head is currently positioned at.

  3. A state name representing the state the Turing machine is left in after the transition is applied.

  4. A tally or blank representing the condition of the tape cell after the transition is applied.

  5. A head direction representing the direction the head will move in after the transition is applied.

A general line will look like the following:

STATE_NAME1 TALLY|BLANK STATE_NAME2 TALLY|BLANK HEAD_DIRECTION

The space between elements of a line is not restricted to being a single space. Any whitespace can be added between elements of a line without causing syntax errors, which makes it possible to format programs!

The parser uses the following pattern to match lines (assuming single spaces between elements, though this is not required):

q[a-zA-Z0-9_]+ 0|1 q[a-zA-Z0-9_]+ 0|1 L|R

The Condition and the Instruction

The first two elements of a Varphi line are called the condition. The condition can be read as follows:

If

  1. the Turing machine is using state [state], and

  2. the tape cell which the head is currently situated at [contains a tally/is blank]

The remaining three elements of the line are called the instruction. They instruct the Turing machine to perform a series of actions. You can read the instruction as follows:

Make

  1. the Turing machine use state [state]

  2. the tape cell at the which the head is currently situated at [contain a tally/blank]

  3. the head move to the tape cell immediately to the [left/right] of the tape cell which it is currently situated at.

Overall, you can read a Varphi line as follows:

If

  1. the Turing machine is using state [state]

  2. the tape cell which the head is currently situated at [contains a tally/is blank],

then make

  1. the Turing machine use state [state]

  2. the tape cell at the which the head is currently situated at [contain a tally/blank]

  3. the head move to the tape cell immediately to the [left/right] of the tape cell which it is currently situated at.

More Examples

Below you can find some more examples of Turing machines described using Varphi.

Turing Machine States

To understand Turing machine states, an example is usually very helpful.

Suppose we are using the following representation convention:

To represent a number n∈Z+n\in\mathbb{Z}^+n∈Z+, repeat the symbol 111 nnn times.

Now suppose you are given the following tape:

You are tasked with making the tape, after you are done, contain one more tally (111) than what was originally on it. Specifically, you should add the extra tally to the right of the tallies that were originally on the tape. Also suppose that the only way you can access the tape is through a Turing machine head, which you control by supplying instructions to. The head will originally be stationed at the leftmost tally on the tape (which you can assume is guaranteed to exist). Also assume that there is exactly one contiguous block of tallies on the tape.

In the task description above, we stated that the head will be stationed at the the leftmost tally on the input tape. In Varphi, and in Turing machines in general, this is an assumption that holds. The head of a machine that is described using Varphi will always start at the leftmost tally on the input tape.

A natural way of doing this is as follows:

Read the current tape cell.

  • If there is a tally at the current tape cell, write a tally to the current tape cell (leaving it as-is) and move to the tape cell immediately to the right of the current one. Repeat.

  • If the current tape cell is blank, write 111 to the current tape cell and move to the tape cell immediately to the right of the current one. Stop.

Now what if the task was to add two tallies instead of just one? Let's try to write a similar algorithm:

Read the current tape cell.

  • If there is a tally at the current tape cell, write a tally to the current tape cell (leaving it as-is) and move to the tape cell immediately to the right of the current one. Repeat.

  • If the current tape cell is blank, write a tally to the current tape cell and move to the tape cell immediately to the right of the current one. What now??? We still need to add one more tally.

It turns out that we don't have enough expressive power to achieve this task without introducing the concept of states.

We can think of a Turing machine state as being a "state of mind" of the Turing machine. For the example where we are adding two 111s to the right of a number, we can rewrite the algorithm using states as follows:

Start at state q0q_0q0​. Read the current tape cell.

  • If we are on state q0q_0q0​:

    • If there is a tally at the current tape cell, write a tally to the current tape cell (leaving it as-is) and move to the tape cell immediately to the right of the current one. Stay on state q0q_0q0​. Repeat.

    • If the current tape cell is blank, write a tally to the current tape cell and move to the tape cell immediately to the right of the current one. Switch to state q1q_1q1​. Repeat.

  • If we are on state q1q_1q1​:

    • If the current tape cell is blank, write a tally to the current tape cell and move to the tape cell immediately to the right of the current one. Switch to state q2q_2q2​. Repeat.

We have written our algorithm in a completely unambiguous way. Notice that not every state needs to define rules. For example, q2q_2q2​ has no rules, which means it's a halting state (the algorithm terminates if we reach this state). Also, notice that q1q_1q1​ defines no rule for if a tally is encountered at the current tape cell, because we do not expect there to be any non-blank tape cell to the right of the tape cell containing the rightmost tally of the input number.

Rock, Paper, Scissors

The machine accepts an input tape containing two contiguous blocks of tallies separated by a blank tape cell, representing the moves of the two players. The first block of tallies (i.e., to the left) will represent the move of the first player, and the second block will represent the move of the second player.

Each contiguous block for a player's move can look like the following:

  • 1 , if the move is Rock

  • 11 , if the move is Paper

  • 111 , if the move is Scissors

For example, the input tape 110111 would represent that the first player played Paper, and the second player played Scissors.

The output tape will be a contiguous block of tallies representing the result of the game. This output tape will take on one of the following forms:

  • 1 , if the result was a tie

  • 11 , if the first player won

  • 111 , if the second player won

qUnknown 1 qRock 0 R
qRock 1 qPaper 0 R
qPaper 1 qScissors 0 R

qRock 0 qRockUnknown 0 R
qPaper 0 qPaperUnknown 0 R
qScissors 0 qScissorsUnknown 0 R

qRockUnknown 1 qRockRock 0 R
qPaperUnknown 1 qPaperRock 0 R
qScissorsUnknown 1 qScissorsRock 0 R

qRockRock 1 qRockPaper 0 R
qRockPaper 1 qRockScissors 0 R

qPaperRock 1 qPaperPaper 0 R
qPaperPaper 1 qPaperScissors 0 R

qScissorsRock 1 qScissorsPaper 0 R
qScissorsPaper 1 qScissorsScissors 0 R

qRockRock 0 qTie 0 R
qRockPaper 0 qPlayer2Won 0 R
qRockScissors 0 qPlayer1Won 0 R
qPaperRock 0 qPlayer1Won 0 R
qPaperPaper 0 qTie 0 R
qPaperScissors 0 qPlayer2Won 0 R
qScissorsRock 0 qPlayer2Won 0 R
qScissorsPaper 0 qPlayer1Won 0 R
qScissorsScissors 0 qTie 0 R

qTie 0 qWrite1 0 R
qPlayer1Won 0 qWrite2 0 R
qPlayer2Won 0 qWrite3 0 R

qWrite1 0 qHalt 1 R
qWrite2 0 qWrite1 1 R
qWrite3 0 qWrite2 1 R

A tape containing the decimal number .

Below is a program which determines the winner of a game of between two players.

Addition By One

Add Two Numbers

Multiplication By Two

Rock, Paper, Scissors

Coin Flip

Rock, Paper, Scissors
444
Installation Guide

Turing Machine Heads

The Head

In the context of a Turing machine, the head is a component that can read from, write to, and traverse the tape.

The head is restricted to being stationed at exactly one tape cell at a time. That is, it cannot read or write a block of cells (more than one cell) at one time. Additionally, the head cannot "teleport" to a certain tape cell that is not immediately to the left or right of the tape cell it is currently stationed at. It can only move to the left or to the right by exactly one tape cell at a time.

As a device, the head can perform the following actions:

  1. Read the current tape cell

  2. Write a tally (111) to the current tape cell

  3. Make the current tape cell blank

  4. Move to the tape cell immediately to the right of the current one

  5. Move to the tape cell immediately to the left of the current one

However, the head only accepts instructions that are in one of the following formats:

  1. Read the current tape cell

  2. Write a tally to the current tape cell and move to the tape cell immediately to the right of the current one

  3. Write a tally to the current tape cell and move to the tape cell immediately to the left of the current one

  4. Make the current tape cell blank and move to the tape cell immediately to the right of the current one

  5. Make the current tape cell blank and move to the tape cell immediately to the left of the current one

The Turing machine will supply such instructions to the head as part of its operation.

Nondeterministic Turing Machines

Nondeterminism

The Turing machines discussed in this section so far, such as the one that adds two tallies to any number, are called deterministic machines, since their outputs are guaranteed to be the same every time if the input tape is the same between runs.

Turing machines can also be nondeterministic, meaning their outputs can vary between runs with the same input tape.

Example

For example, consider the following transition function (written as a Turing program, or Varphi program):

qStart 1 qHalt 1 R
qStart 1 qHalt 0 R

Notice that we have defined two different rules for when the Turing machine is on state qStart and encounters a tally. The first rule instructs the Turing machine to leave the tally untouched and halt, while the other rule instructs it to make the tape cell blank and halt.

Which path will the Turing machine take on an input tape with one tally? There is no way to tell. The machine actually has a 50% chance of using the first rule over the second, and vice versa. So, for one run of the machine, the output tape may have one tally, and for another run, it will have no tallies.

installation instructions

The Unary Number System

What are Number Systems?

From Wikipedia:

There are infinitely many number systems. The most commonly used of these is the decimal (base 10) number system, which uses the symbols 0,1,...,90, 1, ..., 90,1,...,9 to represent numbers. Our modern-day computers use the binary (base 2) number system, which uses the symbols 000 and 111 to represent numbers. For example, the binary representation of the decimal number 252525 is 110011100111001.

The Unary Number System

By definition, the simplest number system is the one which uses the least number of symbols. This number system is called the unary number system, and it uses one symbol to represent numbers, which we call a tally.

We will often use the symbol 111 to denote a tally in this text.

You use this number system more than you know! Imagine trying to represent the decimal number 777 on your fingers. You would put up seven fingers (probably, unless your brain operates in binary), which is like writing seven tallies on a paper!

Although the unary number system is extremely simple, it is not any less (or more) powerful than any other number system.

Representation Conventions

The example above about representing numbers on your fingers shows how to use the unary number system to represent positive numbers. This does not mean that the unary number can only represent positive numbers, however.

In the above example, the following representation convention was used

To represent a number n∈Z+n\in\mathbb{Z}^+n∈Z+, repeat the symbol 111 nnn times.

Suppose now that we wanted to represent the set of nonnegative integers (to be able to represent zero as well) using the unary number system. We could define the following representation convention:

To represent a number n∈Nn\in\mathbb{N}n∈N, repeat the symbol 111 n+1n + 1n+1 times.

Above, we used N\mathbb{N}N to represent the set of nonnegative integers (i.e., {x:x∈Z∧x≥0}\{x: x\in\mathbb{Z}\wedge x\geq 0\}{x:x∈Z∧x≥0}.

Under this representation convention, we can represent the number decimal number 000 with 111, the decimal number 111 with 111111, and so on...

You can theoretically come up with any convention you like to represent a set of numbers using unary. Here's a rather crazy one:

To represent a number n∈Z+n\in\mathbb{Z}^+n∈Z+, repeat the symbol 111 n2+5n^2 + 5n2+5 times.

Try to represent the decimal number 333 in unary using this convention.

The whole point of this is to show that providing a unary representation of a number to someone is not enough for them to know which number is being represented. You must also give them the convention you used to come up with that representation. The number that the unary representation 111111111111111111 represents varies greatly between the three input conventions shown above (it represents six, five, and one respectively).

A numeral system is a writing system for expressing numbers; that is, a for representing numbers of a given set, using or other symbols in a consistent manner.

mathematical notation
digits

Turing Machines

A Turing machine is a quadruple (Q,s,F,δ)(Q, s, F, \delta)(Q,s,F,δ), where

  • QQQ is a finite nonempty set of states (e.g., {q0,q1,...,qn}\{q_0, q_1,...,q_n\}{q0​,q1​,...,qn​}, for some n∈Nn\in\mathbb{N}n∈N.

  • s∈Qs\in Qs∈Q is the initial state.

  • F⊆QF\subseteq QF⊆Q is the set of final states.

  • δ:(Q∖F)×{0,1}→Q×{0,1}×{L,R}\delta: (Q\setminus F)\times\{0, 1\}\rightarrow Q\times\{0, 1\}\times\{L, R\}δ:(Q∖F)×{0,1}→Q×{0,1}×{L,R} is the transition (partial) function.

NOTE: Above, we represent "tally" using 111, "blank" using 000, "left" using LLL, and "right" using RRR.

Wow! That's a lot to take in. The first three items in the quadruple are pretty straightforward, but what is that fourth item? Let's describe this in a more gentle way:

δ:(Q∖F)×{0,1}→Q×{0,1}×{L,R}\delta: (Q\setminus F)\times\{0, 1\}\rightarrow Q\times\{0, 1\}\times\{L, R\}δ:(Q∖F)×{0,1}→Q×{0,1}×{L,R} is a partial function (may not be defined for some inputs in the domain) mapping pairs of non-final states and tape cell possibilities to triples containing a state, tape cell possibility, and head direction.

For example, if δ\deltaδ maps (q0,0)(q_0, 0)(q0​,0) to (q1,1,R)(q_1, 1, R)(q1​,1,R), then this can be read as "if the machine's state is q0q_0q0​ and the current tape cell is blank, then switch to state q1q_1q1​, place a tally at the current tape cell, and move the head to the tape cell immediately right of the current tape cell.

Since we previously mentioned that states do not need to define rules for all possible tape cell conditions, δ\deltaδ is a partial, not total, function.

Recall our example of adding two tallies to a number on a tape. We used the following algorithm:

Start at state q0q_0q0​. Read the current tape cell.

  • If we are on state q0q_0q0​:

    • If there is a tally at the current tape cell, write a tally to the current tape cell (leaving it as-is) and move to the tape cell immediately to the right of the current one. Stay on state q0q_0q0​. Repeat.

    • If the current tape cell is blank, write a tally to the current tape cell and move to the tape cell immediately to the right of the current one. Switch to state q1q_1q1​. Repeat.

  • If we are on state q1q_1q1​:

    • If the current tape cell is blank, write a tally to the current tape cell and move to the tape cell immediately to the right of the current one. Switch to state q2q_2q2​. Repeat.

The transition function for this algorithm can be represented using a table:

If on state
If read
Then switch to state
Then write
Move

0

Again, 111 means "tally", 000 means "blank", RRR means "right", and LLL means "left" here.

We can write the transition function in an even more compact notation as follows:

q01q01Rq00q11Rq10q21Rq_0\quad 1 \quad q_0 \quad 1 \quad R\\ q_0\quad 0 \quad q_1 \quad 1 \quad R\\ q_1\quad 0 \quad q_2 \quad 1 \quad Rq0​1q0​1Rq0​0q1​1Rq1​0q2​1R

Believe it or not, you've just written your first Varphi Program! Here it is in a code block.

q0 1 q0 1 R
q0 0 q1 1 R
q1 0 q2 1 R

Pretty simple, right?

The transition function of a Turing machine is extremely powerful. In fact, supplying just the transition function of a Turing machine gives you everything you need to know about the Turing machine except for the initial state of the machine. However, we will make the assumption that the initial state is the first state mentioned (that is, the state at the top left corner of the Turing program), which is called the . Writing the transition function in compact notation makes it very easy to describe Turing machines without heavy notation or tables.

q0q_0q0​
111
q0q_0q0​
111
RRR
q0q_0q0​
000
q1q_1q1​
111
RRR
q1q_1q1​
q2q_2q2​
111
RRR
Top-Left Rule for Varphi