-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimp.c
377 lines (335 loc) · 10.6 KB
/
simp.c
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
/***************************************************************************************
* The Patterns of Resemblance Arithmetic Library *
* *
* (By Samuel Alexander) *
* (Department of Mathematics) *
* (The Ohio State University) *
***************************************************************************************
* As seen in the Online Patterns of Resemblance Ordinal Calculator *
* For documentation, see http://www.semitrivial.com/patterns *
***************************************************************************************
* This library implements basic arithmetic for Timothy J. Carlson's Patterns of *
* Resemblance ordinal notation system. Patterns of resemblance are a combinatorial *
* way of notating very large ordinals (up to the ordinal of Pi^1_1-CA_0, to be *
* precise). The PORAL (Patterns of Resemblance Arithmetic Library) is a patterns *
* implementation in C. *
***************************************************************************************
* simp.c *
***************************************************************************************
* Implementation of an algorithm to simplify a pattern. *
* *
* Simplifies a pointed pattern into its normal form, as defined in: *
* Carlson & Wilken, 2013, "Normal forms for elementary patterns", J. Symb. Logic *
* *
* Programmed mainly May 2--3, 2013. *
**************************************************************************************/
#include "patterns.h"
#include "por.h"
/*
* Local function prototypes
*/
static pattern *simplify_recurse( pattern *p, node *start );
static pattern *remove_end_clumps( pattern *p );
static int mark_for_removal( pattern *p, node *x, node *start );
static pattern *execute_removal(pattern *p);
/*
* Local definitions
*/
typedef enum
{
SIMPL_UNCHECKED=0, SIMPL_MARKED=1
} simple_data_types;
/*
* The simplify function itself is just a wrapper function
* to do some minor preparation and launch a recursive simplify
* function that takes an additional argument
*/
pattern *simplify( pattern *p )
{
if ( !p->first_node->next )
return p;
p = remove_end_clumps(p);
if ( !p->first_node->next )
return p;
return simplify_recurse( p, p->first_node->next );
}
/*
* We simplify the pattern recursively, using node "start" as a
* "zipper" to zip the pattern up ("start" moves from left to
* right as the recursion proceeds, and the recusion ends when
* "start" reaches the end of the pattern).
*
* Overall strategy: We "check" whether we can remove "start" without
* changing what ordinal the pointed pattern notates. But if we remove
* "start", we have to remove anything connected to it (via less1,
* or via decompositions), so we have to ask the same question about
* all those nodes as well, which in turn requires asking the same
* question about any node THEY'RE connected to, and so on.
*/
static pattern *simplify_recurse( pattern *p, node *start )
{
node *n;
pattern *q;
/*
* Mark all nodes in the pattern as being unchecked during this iteration
*/
for ( n = p->first_node; n; n = n->next )
n->simplify_data = SIMPL_UNCHECKED;
/*
* Under no circumstances would we remove the pattern's designated point
*/
if ( start == p->point )
{
start = start->next;
if ( !start )
return p;
}
/*
* Attempt to mark "start" for removal.
* If the attempt fails (because it would
* require removing p->point) then move on
* to the next start.
*/
if ( ! mark_for_removal(p,start,start) )
{
if ( !start->next )
return p;
return simplify_recurse( p, start->next );
}
/*
* If "start" was successfully marked for
* removal, then remove it, along with anything
* else that was marked as collateral damage.
* Actually, do all this in a copy q of p.
*/
q = execute_removal(p);
/*
* Check whether the copy q, with "start" removed,
* still notates the same ordinal that p does.
* If so, continue trying to further simplify q.
* If not, revert back to p and increment "start".
*/
if ( same_point(q,p) )
{
start = isom(start,q);
if ( start )
return simplify_recurse( q, start );
else
return q;
}
else
{
if ( start->next )
return simplify_recurse( p, start->next );
else
return p;
}
}
/*
* Attempt to mark a node x for removal, along with (recursively)
* all nodes that would also have to be removed if that node were.
* Returns 0 if the pattern's designated point would have to be
* removed. The node *start input keeps track of which node we
* were originally wanting to remove (before getting lost in the
* mazes of recursion).
*/
static int mark_for_removal( pattern *p, node *x, node *start )
{
node *n, **d, *L;
if ( x == p->point )
return 0;
/*
* Black-magic shortcut:
* if the point we're recursively trying to mark is further left
* than the original point we care about marking, then marking
* x would force us to mark p->point. Why? Because if we could
* have marked x, then we would have done so already, in simplify_recurse,
* before even considering "start".
*/
if ( x->position < start->position )
return 0;
/*
* If x is the left endpoint of a circle and p->point lies within that
* circle, then we cannot mark x for removal without marking p->point
*/
if ( x->position <= p->point->position
&& p->point->position <= x->less1->position )
return 0;
/*
* If we've already marked x for removal, there's nothing left to do.
*/
if ( x->simplify_data == SIMPL_MARKED )
return 1;
/*
* Mark x for removal.
*/
x->simplify_data = SIMPL_MARKED;
/*
* Now recursively mark for removal all things which would have to
* be removed if we remove x.
*/
for ( n = x->next; n; n = n->next )
{
/*
* Anything which is a decomposition involving doomed nodes, is doomed.
*/
if ( n->decomposition )
{
for ( d = n->decomposition; *d; d++ )
{
if ( (*d)->simplify_data == SIMPL_MARKED )
break;
}
if ( *d )
{
if ( !mark_for_removal( p, n, start ) )
return 0;
}
else
{
/*
* Suppose n=x_1+...+x_n (a descending sum of indecomposables), and none
* of the x_i have been marked for removal. It will still be necessary
* to mark n for removal if any of x_1+...+x_(n-i) are marked.
*/
node *d_bak; // backup of *d
node *acl; // "arithmetical closure"
for ( d = n->decomposition; *d; d++ )
{
d_bak = *d;
*d = NULL;
acl = get_node_by_decomposition( p, n->decomposition );
*d = d_bak;
if ( acl == n )
continue;
if ( acl->simplify_data == SIMPL_MARKED )
break;
}
if ( *d )
{
if ( !mark_for_removal( p, n, start ) )
return 0;
}
}
}
}
/*
* If x is the left endpoint of a less1-circle, then to remove x,
* we must remove everything within that circle.
*/
if ( x->less1 != x )
{
for ( n = x->next; n->position <= x->less1->position; n = n->next )
{
if ( !mark_for_removal( p, n, start ) )
return 0;
}
}
else
{
/*
* Otherwise, consider the case whether x is the right endpoint of
* a less1-circle. We search for the leftmost (if any) node L such
* that L is the left-endpoint of a circle whose right endpoint is x.
*/
for ( L = p->first_node; L; L = L->next )
{
if ( L == x )
break;
if ( L->less1 == x )
break;
if ( L->less1->position < x->position )
L = L->less1;
}
/*
* If we found a circle with left endpoint L and right endpoint x,
* we are obliged to remove that circle and everything inside it.
*/
if ( L && L != x )
{
for ( n = L; L->position < x->position; L++ )
{
if ( !mark_for_removal( p, n, start ) )
return 0;
}
}
}
return 1;
}
/*
* Having successfully marked some points for removal ("successfully" here
* means that doing so did not force us to mark p->point), make a copy of
* the pattern, and remove the marked points from it.
*/
static pattern *execute_removal(pattern *p)
{
node *n, *m, *m_next;
pattern *q;
int i;
q = copy_pattern(p);
for ( i=0, n=p->first_node, m=q->first_node; n; n = n->next, m = m_next )
{
m_next = m->next;
if ( n->simplify_data == SIMPL_MARKED )
{
UNLINK( m, q->first_node, q->last_node, next, prev );
kill_node( m );
}
else
{
/*
* Maintain a running count of how many nodes we DON'T remove,
* so we can fix the nodecount after the dust settles.
*/
i++;
}
}
q->nodes = i;
for ( i = 0, m = q->first_node; m; m = m->next )
m->position = i++;
return q;
}
/*
* Remove less1-connected-components located to the right of
* the less1-connected-component containing p->point.
*
* Undefined behavior if p is the pattern with only one node.
*/
static pattern *remove_end_clumps( pattern *p )
{
node *n, *n_next;
pattern *q;
/*
* Search for the first node (if any) that lies further right
* than every circle containing p->point.
*/
n = p->first_node->next;
while ( n->position <= p->point->position )
{
n = n->less1->next;
if ( !n )
return p;
}
/*
* Having found such a node, n, we make a copy of p,
* and in the copy, kill everything from n onward.
*/
q = copy_pattern(p);
q->nodes = n->position;
for ( n = isom(n,q); n; n = n_next )
{
n_next = n->next;
UNLINK( n, q->first_node, q->last_node, next, prev );
kill_node( n );
}
return q;
}
/*
* Check whether pointed patterns p and q notate the same ordinal.
* Assumes working in scratch-space (see core.c)
*/
int same_point( pattern *p, pattern *q )
{
amal *a = amalgamate( copy_pattern(p), copy_pattern(q) );
return ( a->p1_in_p->position == a->p2_in_p->position );
}