owned this note
owned this note
Published
Linked with GitHub
###### tags: `Alucard`
# An Introduction to Alucard
[toc]
## Installation
The easiest way to install Alucard at the moment is through ros.
1. Install [ros](https://roswell.github.io/Installation.html)
2. Set sbcl as the default `ros install sbcl-bin`
3. Update asdf `ros install asdf`
4. run `git clone https://github.com/anoma/juvix-circuits.git`
5. cd into the cloned directory `cd juvix-circuits`
6. If you are using vscode, you should also run `ros install "nobody-famous/alive-lsp"`
7. run `make install`
- The executable should be in ~/.local/bin/
- Alternatively `make all` will install it in `./build/` as well.
The last command will add it to `~/.local/bin/`, so make sure that is on your path!
Now we can run alucard!
## Terminal Commands
There are basically 2 ways to run alucard programs.
### Interactive Mode
The interactive mode is via a REPL in Emacs/VSCode. To run the interactive mode,
```shell
$ cd ~/.local/bin
$ ./alu.image -y
;; Slynk started at port: 4005.
?
```
If you are using a SLIME (VS-Code uses SLIME), replace the `-y` with `-s`.
Then use your client (e.g. Slime or Sly) to connect to localhost with port 4005 (or whatever port is shown in the terminal). You can set the port with the `-p` option.
If you are using vscode it might spit you out in the cl-user package. to check your prompt should say `ALUSER>` in vs-code or emacs. If that is the case then run the following
```lisp=
(in-package :aluser)
```
one can quit out of the repl by typing `(quit)`.
### Batch Mode
Batch mode lets you provide input from files to the `alu.image` executable with the `-i` flag and specify the output file with the `-o` flag.
```shell
$ ./alu.image -i "my_program.lisp" -o "output/my_program_output.txt"
```
If the `-o` flag is not given, you will go into interactive mode.
To specify the function that will act as the entry point to one's circuit, you can write
`(entry-point function-name)` in the file, otherwise no code will be generated.
## Running Alucard from Emacs
If you are running sly, `M-x sly-connect` to localhost with the port number shown in your terminal earlier.
If one is using `ccl` instead of `SBCL` you might want to run:
```lisp=
(setf *print-pretty* t)
(in-package :aluser)
```
### Running Alucard as a library
You can also `(ql:quickload :alu)` if one has the `asd` file on the path or have loaded into one's environemnt, and have the same functionality!
## Running Alucard from VSCode
Please check the readme
## Writing programs and generating VAMP-IR
You know you are ready to get going when typing `*package*` in your REPL returns
```
#<PACKAGE "ALUSER">
```
or your REPL prompt says `ALUSER>`.
Let's define a simple circuit, which represents the equation, $x+3 = 0$.
```lisp!
(defcircuit add-three ((public x int) (output bool))
(= (+ x 3) 0))
```
In the above code, the keyword `defcircuit` is used to denote that we are defining a polynomial circuit, named `add-three`. The circuit takes as input the integer `x`, which is a `public` input, and the output is `true` if the equation is satisfied, and false if not.
> To get the VAMP-IR code corresponding to any circuit defined below, call the function `vampir` on it.
For example, the VAMP-IR code for `add-three` is shown below.
```
ALUSER> (vampir add-three)
def add_three x1333 -> g1335 {
g1334 = x1333 + 3
g1334 = 0
g1335 = g1334
}
```
Note that since the compiler pipeline is currently incomplete, it is not yet possible to run VAMP-IR and generate output.
Currently it's good to run `vampir` on various circuits created, as the type checker currently only runs when trying to extract.
Let's look at some more examples.
The follow circuit represents the equation $x^3 + 3x^2 + 2x + 3y+ 4 =0$.
```lisp
(defcircuit multivar ((public x int)
(public y int)
(output int))
(= (+ (exp x 3)
(* 3 (exp x 2))
(* 2 x)
(* 3 y)
4)
0))
```
We can also define a circuit to calculate the square root of an input in the following manner.
```lisp
(defcircuit square-root ((private p int)
(output int))
(def ((with-constraint (x)
(= p (* x x))))
x))
```
The `def` plays a role similar to `let` in Rust. The `with-constraint` macro can be used in any situation where we want a variable to be subject to certain constraints.
Alucard also allows us to define custom datatypes.
Let us define the type `point` which defines a point on the Cartesian plane.
```lisp
(deftype point ()
(x int)
(y int))
```
Let's write a function to calculate the distance of this point from the origin. We'll make use of the `square-root` function we wrote earlier.
```lisp
(defcircuit distance ((public pt point)
(output int))
(square-root (+ (exp (x pt) 2) (exp (y pt) 2))))
(entry-point distance) ; marking the function as the main!
```
Let us now mark this function as the entry point to the file
`(entry-point distance)`
```bash=
4 taichi@Gensokyo:~/Documents/Work/Repo/alu/alu git:main:*? % alu.image -i example.lisp -o example.vampir
4 taichi@Gensokyo:~/Documents/Work/Repo/alu/alu git:main:*? % cat example.vampir
def distance pt10733_x pt10733_y -> g10770 {
g10766 = pt10733_x ^ 2
g10768 = pt10733_y ^ 2
g10769 = g10766 + g10768
g10770 = square_root g10769
}
def square_root p10729 -> x10772 {
g10784 = x10772 * x10772
p10729 = g10784
g10785 = p10729
}%
```
We can also invoke the same functionality from the repl as well
```lisp=
ALUSER> (pipeline:dump-entry-point)
def distance pt16131_x pt16131_y -> g16712 {
g16708 = pt16131_x ^ 2
g16710 = pt16131_y ^ 2
g16711 = g16708 + g16710
g16712 = square_root g16711
}
def square_root p15972 -> x16714 {
g16726 = x16714 * x16714
p15972 = g16726
g16727 = p15972
}
#<SLYNK-GRAY::SLY-OUTPUT-STREAM #x302000D6CA7D>
ALUSER> (pipeline:dump-entry-point-to-file "example.vampir")
#<BASIC-FILE-CHARACTER-OUTPUT-STREAM ("example.vampir"/:closed #x30200297CAED>
```
Some of this formula is repetitive, namely the `(exp (lookup pt) 2)`
we can use the common lisp integration to remove such repetitive looking code.
Namely we can use `flet`, which defines a local function to be our square function.
```lisp=
(defcircuit distance ((public pt point)
(output int))
(flet ((square (cord)
(exp cord 2)))
(square-root (+ (square (x pt))
(square (y pt))))))
```
If we find this function general enough we can move it to the top level with `defun`.
```lisp=
(defun square (cord)
(exp cord 2))
(defcircuit distance ((public pt point)
(output int))
(square-root (+ (square (x pt))
(square (y pt)))))
```
A lot more can be abstracted, we have the entire toolkit of the common lisp programming language to help abstract away alucard code!
A lot more information on this can be found in the [reference manual](https://hackmd.io/emeUBiYoSqmJ95Ls2wsrMQ)
### Debugging
Let us say we try to make a type error.
```lisp=
(deftype point ()
(x int)
(y int))
(defun square (cord)
(check (exp cord 2) (int 32)))
(defcircuit distance ((public pt point)
(output int))
(square-root (+ (square (x pt))
(square (y pt)))))
```
In this code, we are saying the expected output of square should be of `(int 32)`, however the type should really just be `int`. We can move this `check` to any part of the expression in the `square` function and the error would be the same.
```lisp=
ALUSER> (vampir distance)
;;;;;;;;;;;;;;;;;;;;;;
In Function DISTANCE
;;;;;;;;;;;;;;;;;;;;;;
2022-08-08 08:35:27
[ERROR] <UNIFIER><TYPE>:
The types #<#<REFERENCE-TYPE INT> 32> and #<REFERENCE-TYPE INT> are not equivalent
[STACK]
((:IN SQUARE
(EXP CORD 2)
(CHECK (EXP CORD 2) (INT 32)))
(SQUARE (X PT))
(+ (SQUARE (X PT)) (SQUARE (Y PT)))
(SQUARE-ROOT (+ (SQUARE (X PT)) (SQUARE (Y PT)))))
```
Here we get the type error message saying that `(int 32)` and `int` are not compatable, and further the stack trace to the point.
It is saying that the expression `(EXP CORD 2)` caused the error as we stated that the type must be of `(int 32)` right before!
The stack trace just give the expression dump until the current point where the error occurs.
### Reporting Compiler Errors
If the system errors with a very baroque error message like
```lisp=
4 1 taichi@Gensokyo:~/Documents/Work/Repo/alu/alu git:main:*? % alu.image -i example.lisp -o example.vampir
> Debug: Undefined function ALU.PASS.DEPENDENCIES::TRACK-FUNCTION-DEPS called with arguments ((#<LET G10547 = #<#<REFERENCE *> #1=#<REFERENCE X10535> #1#>>
> #<LET G10548 = #<#<REFERENCE => #<REFERENCE P10517> #<REFERENCE G10547>>>)) .
> While executing: SIGNAL, in process toplevel(4).
> Type :GO to continue, :POP to abort, :R for a list of available restarts.
> If continued: Retry applying ALU.PASS.DEPENDENCIES::TRACK-FUNCTION-DEPS to ((#<LET G10547 = #<#<REFERENCE *> #1=#<REFERENCE X10535> #1#>>
#<LET G10548 = #<#<REFERENCE => #<REFERENCE P10517> #<REFERENCE G10547>>>)).
> Type :? for other options.
1 >
```
And spits you into a repl, please file an issue or message `mariari` directly. These are internal errors and they might show up!