-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStencil.dyalog
152 lines (139 loc) · 6.16 KB
/
Stencil.dyalog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
res←{opts}(code Stencil specs)input;Try;Rank;rank;No;If;Axes;axes;Of;EMASK;VMASK;NMASK;SMASK;Template;Injected;Code;Post;Pre;Ⓔ;Pad;Cycle;Block;Twist;Ü;P;C;T;M;K;R;I;STATES;Collect;Expand;repeat;Repeat;World;Do;Add0s;Rem0s;⎕IO;DIM;FORE;AFT;Min1;i;w
⎕IO←1 ⋄ ⎕ML←1
:If 900⌶⍬
opts←⍬
:EndIf
Try←{
0::⍵
⍎⍵
}
specs input←Try¨specs input ⍝ evaluate if possible
Rank←≢⍴
rank←Rank input
No←0∊⍴
If←{
⍺←⊢
⍵⍵⊣⍵:⍺ ⍺⍺⊣⍵
⍵
}
specs←(rank⍴3)If No specs ⍝ default to 3 3 …
specs←⍉∘⍪If(1≥Rank)specs ⍝ make matrix if not
specs←2↑specs⍪1 ⍝ add step if missing
specs←rank/If(2 1≡⍴)specs ⍝ replicate to all dimensions if needed
Axes←⍳=∘⊂∘⌈÷∘2 ⍝ middle coordinates
DIM←1⌷specs
axes←Axes DIM
Of←{,⍺⍺/¨⍵}
EMASK←⍲Of axes ⍝ moorE without self
VMASK←∨Of axes ⍝ Von neumann with self
NMASK←≠Of axes ⍝ von neumanN without self
SMASK←∧Of axes ⍝ Self
Template←{
ⓇⒺⓈ←Ⓐ(Code Injected)Ⓦ;Count;M;m;E;e;V;v;N;n;S;s;P;p;code
Count←⊢+.≠Ⓔ ⍝ number of non-empties
m←Count⊢M←,Ⓦ ⍝ Moore with self
e←Count⊢E←EMASK/M ⍝ moorE without self
v←Count⊢V←VMASK/M ⍝ Von neumann with self
n←Count⊢N←NMASK/M ⍝ von neumanN without self
s←Count⊢S←SMASK/M ⍝ Self
S←⊃S ⍝ scalarise
p←Count⊢P←0≠Ⓐ ⍝ Padded
w←,W ⍝ raw input
y←,Y←input ⍝ preprocessed input
code←⎕NR'Code'
:If 1=≢code
Code←⍎⊃code
:Else
Code←⍎⎕FX ⎕NR'Code'
:EndIf
ⓇⒺⓈ←Ⓐ Code Ⓦ ⍝ call user code
}
⎕FX ¯1↓1↓⎕NR'Template' ⍝ create "Injected" tradop
Post←⊢ ⍝ no postprocessor
Pre←⊢ ⍝ no preprocessor
:If 3=⎕NC'code' ⍝ fn left operand → behave like ⌺
Code←code
:Else ⍝ text
code←'''.*?''' '⎕\w+' '\pL'⎕R'&' '&' ' & '⊆code ⍝ put spaces around letters which are neither ⎕NAMES nor quoted
:If 2≤≢code
Post←⍎3⌽' ⍵}{0::⍵ ⋄ ',⊃code ⍝ create postprocessor
code←1↓code
:EndIf
:If 2≤≢code
Pre←⍎3⌽' ⍵}{0::⍵ ⋄ ',⊃⌽code ⍝ create preprocessor
code←¯1↓code
:EndIf
⎕FX'Code←{' '⎕IO←0',code,'}' ⍝ create left operand
:EndIf
⍝ "Polyfills":
Ⓔ←⊃0⍴⊂
Ü←{ ⍝ Under (⍢)
⍵⍵⍣¯1 ⍺⍺ ⍵⍵ ⍵
}
FORE AFT←¯1 1×⌈¯1+⌈/DIM÷2 ⍝ max needed padding
Min1←{ ⍝ ensure matrix is minimum 1-by-1
No ⍵:⍵⍴⍨1⌈⍴⍵
⍵
}
Add0s←(⍉(FORE↑Ⓔ)⍪⊢⍪AFT↑Ⓔ)⍣2 Min1 ⍝ Add layers of prototype elements
Rem0s←{⍉⌽⍵↓⍨+/∧\∧/⍵=Ⓔ ⍵}⍣4 ⍝ Remove layers of prototype elements
Pad←{ ⍝ pad with result of given function
(AFT↓FORE↓∘⍺⍺(FORE↑⍵⍵)⍪⊢⍪AFT↑⍵⍵)Min1 ⍵
}
Cycle←Pad⊢ ⍝ ┌─→─┐
⍝ pad top and bottom with self
⍝ └─→─┘
Block←Pad Ⓔ ⍝ ┌───┐
⍝ pad top and bottom with prototype
⍝ └───┘ (manifold-with-boundary)
Twist←Pad⌽ ⍝ ┌─←─┐
⍝ pad top and bottom with reversed self
⍝ └─→─┘
P←{ ⍝ ┌───┐ Plane:
⍺⍺ Block Ü⍉Block ⍵ ⍝ │ │ left and right disconnected
} ⍝ └───┘ lower and upper disconnected
C←{ ⍝ ┌───┐ Cylinder:
⍺⍺ Cycle Ü⍉Block ⍵ ⍝ ⍋ ⍋ left and right joined
} ⍝ └───┘ lower and upper disconnected
T←{ ⍝ ┌─→─┐ Torus:
⍺⍺ Cycle Ü⍉Cycle ⍵ ⍝ ⍋ ⍋ left and right joined
} ⍝ └─→─┘ lower and upper joined
M←{ ⍝ ┌─→─┐ Möbius strip:
⍺⍺ Block Ü⍉Twist ⍵ ⍝ │ │ left and right disconnected
} ⍝ └─←─┘ lower and upper twist-joined
K←{ ⍝ ┌─→─┐ Klein bottle:
⍺⍺ Cycle Ü⍉Twist ⍵ ⍝ ⍋ ⍋ left and right joined
} ⍝ └─←─┘ lower and upper twist-joined
R←{ ⍝ ┌─→─┐ Real projective plane:
⍺⍺ Twist Ü⍉Twist ⍵ ⍝ ⍋ ⍒ left and right twist-joined
} ⍝ └─←─┘ lower and upper twist-joined
I←{ ⍝ ┌─→─┐ Infinite:
Rem0s ⍺⍺ Add0s ⍵ ⍝ ⍋ ⍒ left and right expand as needed
} ⍝ └─←─┘ lower and upper expand as needed
STATES←⊂{⎕←Post ⍵ ⋄ ⎕←⍬ ⋄ ⍵}If('≡'∊opts)⊢input
Collect←{
⍺⍺⊃STATES,←⊂⍵
}
Expand←{ ⍝ expand ⍣functions
body←'≡'⎕R'⍺≡⍵:1 ⋄ ⎕←Post ⍺ ⋄ ⎕←⍬ ⋄ 0'⊢⍵
body←'∊|≢'⎕R'STATES∊⍨⊂⍺'⊢body
'Repeat←{'body'}'
}
repeat←'∊'If No opts~⎕A ⍝ how many times
Repeat←⍎⎕FX∘Expand If(∨/'≡∊≢'∘∊)repeat
World←⍎'P'If No opts∩⎕A
⍝ This is where the actual work happens:
input←Pre W←input
STATES←⊂input
Do←Code Injected⌺specs World Collect⍣Repeat
STATES←∪STATES,⊂Do input
⍝ Now we choose what to return:
:If '≡'∊opts
res←⍬⊤⍬ ⍝ silence if already printed
:ElseIf '≢'∊opts
res←Post≢STATES ⍝ count generations until stable or already found
:ElseIf '∊'∊opts
res←Post¨STATES ⍝ list generations
:Else
res←Post⊃⌽STATES ⍝ return final generation
:EndIf