#esolang #programming-language #rotation #4d #esoteric #computation #stack

bin+lib spin4

spin4 是一种使用 4D 旋转进行计算的谜之编程语言

3 个版本

0.0.3 2024年2月24日
0.0.2 2024年2月17日
0.0.1 2024年2月17日

#348数学

Download history 24/week @ 2024-04-02

每月 105 次下载

MIT 许可证

50KB
1K SLoC

JavaScript 635 SLoC // 0.1% comments Rust 581 SLoC // 0.0% comments

spin4

spin4 是一种使用 4D 旋转进行计算的谜之编程语言。其主要哲学是通过旋转编码状态的 4D 空间来编写程序,然后使用此状态来递增或递减累加器向量。累加器组件可以放入堆栈中,堆栈也可以向一个方向旋转。

为什么?

是的。

spin4 解释器

当前的 spin4 解释器尚未优化,仅作为概念证明。安装

cargo install spin4
Usage: spin4 [OPTIONS] --file <FILE>

Options:
  -f, --file <FILE>  
  -d, --debug        
  -h, --help         Print help
  -V, --version      Print version

基本概述

最终,一个 spin4 程序具有

  • 一个包含 2 个组件的累加器向量:寄存器 X 和 Y
    • 我们通过执行加法、减法、乘法或整数除法来进行旋转以累积值
    • 我们可以对其组件 X 进行操作,
    • 当我们旋转 4D 空间时,堆栈的值会增加或减少
  • 一个堆栈
    • 我们可以逐个组件地将累加器的值推入,即推入 X 或 Y 的值
    • 我们可以使用标准输入执行推入
    • 我们可以从左或右旋转它
    • 我们可以将顶部元素弹出到一个寄存器中
    • 我们可以显示顶部元素

示例

Hello World

spin4 中的 Hello World 程序

{(+1>)x?y}(+0000>)*[<][<][y]y[>][>][x]x*[>][>][y]y[<][<][x]+[x]+[.c][x]x+[x]+[x]+[x]+[<][yx]y[>]-(+1054<5401>012111<)x(+0>)x[.c][<][<][<][<][yx]xy[>][>][>][>]+[xy]y+[.c][.c][x]x[<][<][<][y]y[>][>][>]+[.c][x]x+[>][>][x]x[<][y]x[<][<][<][<][<][<][.c][<][<][.c]y[.c][y][xy][yx][xy][y][.c][xy][.c][yx][.c]

斐波那契序列

作为传统,这里是在 spin4 中的斐波那契序列。此程序接收一个正整数 n 作为输入(stdin)并打印 n 个第一个斐波那契数的列表。

[,n](+00>)y*[y]*[x]*[>][x](-00<)(+0>)xxx[.n][<][.c][>][.n][xy]xy{[xy]+x[xy]xy[<][.c][>][.n][>][>][yx]y-[yx]yx[>][>][>]?y}

概念

旋转 < -π/2 和 > +π/2

在 4D 中,我们可以从基向量形成总共 6 个平面,旋转平面是 2D 中旋转中心的等效概念,即在 4D 旋转下始终有一个不变的平面。

  • xy 作为 0 (xy 平面是不变的)
  • xz 作为 1 (xz 平面是不变的)
  • xw 作为 2 (xw 平面是不变的)
  • yz 作为 3 (yz 平面是不变的)
  • yw 作为 4 (yw 平面是不变的)
  • zw 作为 5 (zw 平面保持不变)
  • 我们使用语法 (main_operator seq_of_rotation) 开始旋转或旋转序列

  • 旋转后累加器会发生什么?

    • 累加器向量状态改变:X 和 Y 增量/减少
    • 系统以某种方式变得有方向
    • 从概念上讲,为了计算累加器向量的下一个状态,spin4 采取两个仅能生成与 $\vec{u} = (1 \space 0 \space 0 \space 0)^T$ 和 $\vec{v} = (0 \space 1 \space 0 \space 0)^T$ 相同平面的基本向量。例如,如果我们有系统矩阵中的列 $(0 \space -1 \space 0 \space 0)^T$ 和 $(1 \space 0 \space 0 \space 0)^T$,则方向签名变为 [-1, 1],然后我们可以计算下一个累加器状态 acc <- acc + [-1, 1]

    计算签名的最简单实现是遍历满足投影 $\vec{u}.\vec{v}'=0$ 和 $\vec{u}'.\vec{v}=0$ 的每个列对组合 $(\vec{u}', \vec{v}')$,这基本上保证了生成的平面与初始平面相似。

    一个不错的技巧是注意到,在单位矩阵或其列的符号排列上应用 $\pm \pi / 2$ 旋转始终会产生一个 广义排列矩阵,其非零项为 -11,我们可以通过一些代数简单地提取相关项。

$$T \leftarrow R_{Index, Dir} T$$

$$ (Acc_X \space Acc_Y) \leftarrow (Acc_X \space Acc_Y) + \begin{pmatrix}1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0\end{pmatrix} T \begin{pmatrix}1 \\ 1 \\ 1 \\ 1\end{pmatrix} $$

指令

  • 算术运算符 +-/*_(无操作)。

  • 旋转序列 (Op Seq)

    • Op 可以是上述任何二元运算符
    • Seq 是一系列有序旋转
      例如,(+1>1<01>) 等价于 (+01>)
  • xy:将累加器的特定组件推送到堆栈中。
    示例

    • (+03<5>)x => 将 -1 推送到堆栈,累加器 [-1, 1]
      • 堆栈 := ... -1
    • (+03<5>)yx => 将 1 和 -1 压入栈中,累加器 [-1, 1]
      • 栈 := ... 1 -1
    • (+03<5>)* => 将 -1(或 x=-1 * y=1)压入栈中,累加器 [-1, 1]
      • 堆栈 := ... -1
    • (+03<5>)x+y => 将 -1、0、1 压入栈中,累加器向量是 [-1, 1]
      • 栈 := ... -1 0 1
    • (+03<5>)yx/+x => 将 1, -1, -1, 0, 然后是 -1 压入栈中,累加器 [-1, 1]
      • 栈 := ... 1 -1 -1 0 -1
  • [>]/[<] : 右/左旋转栈

  • [x], [y], [xy][yx] : 弹出栈中的值,按顺序放入相应的累加器组件

  • [.n] : 打印栈顶元素作为数字

  • [.c] : 打印栈顶元素作为字符

  • [,n] : 数字输入(int32)

  • [,c] : 字符输入

  • 循环 { .. ?t}:t 是 x 或 y,它检查单个累加器组件,如果值为 0 则中断循环。

    示例

    • {(+50>)?x}y 当累加器 x 的分量是 0 时停止,然后将 y 分量值推送到堆栈

更多示例...

  • 示例 1:操作符 no op _

    在某些情况下,我们只想执行一系列旋转,而在这个过程中不执行任何操作。在表达式 (_03>5<) 中,累加器向量保持为 [0, 0]

  • 示例 2:在旋转时执行加法/减法...

    考虑以下程序 (+03<5>)

    • 旋转 0(90 度),根据与初始 xy 对应的平面方向执行加法
      • acc = [0, 0] + [+1, +1] = [1, 1]
    • 旋转 3(90 度),根据与初始 xy 对应的平面方向执行加法
      • acc = [1, 1] + [-1, +1] = [0, 2]
    • 旋转 5(-90 度),根据与初始 xy 对应的平面方向执行加法
      • acc = [0, 2] + [-1, -1] = [-1, 1] 因此,累加器向量变为 [-1, 1]
  • 示例 3

    acc = [2, 4]

    程序中的 + .. + .. 计算 2 + 4,结果存储在堆栈中。

  • 示例 4

    表达式 (-01>3<)x 中的 x 提取累加器的 x 分量并将其存储在堆栈中。

依赖项

~4.5MB
~92K SLoC