1
1
import { cons } from "../lib/cons.ts" ;
2
2
import { I , K , S } from "../lib/ski/terminal.ts" ;
3
3
import type { SKIExpression } from "../lib/ski/expression.ts" ;
4
- import { initArenaEvaluator } from "../lib/evaluator/arenaEvaluator.ts" ;
5
- import { prettyPrint } from "../lib/ski/expression.ts" ;
4
+ import { initArenaEvaluator , hasEmbedding } from "../lib/evaluator/arenaEvaluator.ts" ;
6
5
import type { EvaluationStep , GlobalInfo } from "./types.ts" ;
7
6
8
7
const memo = new Map < number , SKIExpression [ ] > ( ) ;
9
8
const [ nRaw , outputPath ] = Deno . args ;
10
9
11
10
if ( ! nRaw ) {
12
11
console . error (
13
- "Usage: deno run -A scripts/generateforest .ts <symbolCount> [outputFile]" ,
12
+ "Usage: deno run -A scripts/genForest .ts <symbolCount> [outputFile]" ,
14
13
) ;
15
14
console . error ( "" ) ;
16
15
console . error (
@@ -62,21 +61,6 @@ function enumerateExpressions(leaves: number): SKIExpression[] {
62
61
return result ;
63
62
}
64
63
65
- async function generateLabel ( expr : SKIExpression ) : Promise < string > {
66
- let label = prettyPrint ( expr ) ;
67
- if ( label . length > 100 ) {
68
- const encoder = new TextEncoder ( ) ;
69
- const data = encoder . encode ( label ) ;
70
- const hashBuffer = await crypto . subtle . digest ( "SHA-256" , data ) ;
71
- const hashArray = Array . from ( new Uint8Array ( hashBuffer ) ) ;
72
- const hashHex = hashArray . map ( ( b ) => b . toString ( 16 ) . padStart ( 2 , "0" ) ) . join (
73
- "" ,
74
- ) ;
75
- label = `HASH:${ hashHex . substring ( 0 , 16 ) } ` ;
76
- }
77
- return label ;
78
- }
79
-
80
64
export async function * generateEvaluationForest (
81
65
symbolCount : number ,
82
66
wasmPath : string ,
@@ -90,7 +74,6 @@ export async function* generateEvaluationForest(
90
74
console . error (
91
75
`Processing ${ total } expressions with ${ symbolCount } symbols each...` ,
92
76
) ;
93
- const labels : Record < number , string > = { } ;
94
77
const sources = new Set < number > ( ) ;
95
78
const sinks = new Set < number > ( ) ;
96
79
@@ -105,79 +88,53 @@ export async function* generateEvaluationForest(
105
88
) ;
106
89
}
107
90
108
- let cur = expr ;
109
- let steps = 0 ;
110
- const MAX_STEPS = 10000 ;
111
- const curId = evaluator . toArena ( cur ) ;
112
- const label = await generateLabel ( expr ) ;
113
-
114
- labels [ curId ] = label ;
91
+ const curId = evaluator . toArena ( expr ) ;
115
92
sources . add ( curId ) ;
116
93
117
- const encounteredNodes = new Set < number > ( ) ;
118
- encounteredNodes . add ( curId ) ;
94
+ // Track evaluation history for cycle detection
95
+ const history : number [ ] = [ curId ] ;
119
96
const pathSteps : EvaluationStep [ ] = [ ] ;
97
+ let hasCycle = false ;
98
+ let currentId = curId ;
120
99
121
- while ( steps < MAX_STEPS ) {
122
- steps ++ ;
123
- const { altered, expr : next } = evaluator . stepOnce ( cur ) ;
124
- if ( ! altered ) break ;
100
+ // Manual evaluation with cycle detection
101
+ for ( let step = 0 ; ; step ++ ) {
102
+ const { altered, expr : nextExpr } = evaluator . stepOnce ( evaluator . fromArena ( currentId ) ) ;
125
103
126
- const currentId = evaluator . toArena ( cur ) ;
127
- const nextId = evaluator . toArena ( next ) ;
128
-
129
- if ( ! labels [ currentId ] ) {
130
- labels [ currentId ] = await generateLabel ( cur ) ;
131
- }
132
- if ( ! labels [ nextId ] ) {
133
- labels [ nextId ] = await generateLabel ( next ) ;
104
+ if ( ! altered ) {
105
+ break ; // No more reduction possible
134
106
}
135
107
136
- if ( encounteredNodes . has ( nextId ) ) {
137
- pathSteps . push ( { from : currentId , to : nextId } ) ;
138
- pathSteps . push ( { from : nextId , to : nextId } ) ;
108
+ const nextId = evaluator . toArena ( nextExpr ) ;
109
+
110
+ if ( hasEmbedding ( evaluator . dumpArena ( ) . nodes , history , nextId ) ) {
111
+ hasCycle = true ;
139
112
break ;
140
113
}
141
114
142
115
pathSteps . push ( { from : currentId , to : nextId } ) ;
143
- encounteredNodes . add ( nextId ) ;
144
- cur = next ;
116
+ currentId = nextId ;
117
+ history . push ( currentId ) ;
145
118
}
146
119
147
- if ( steps === MAX_STEPS ) {
148
- console . error (
149
- `Warning: reduction for term #${ count } hit step limit (${ MAX_STEPS } ): ${
150
- prettyPrint ( expr )
151
- } `,
152
- ) ;
153
- }
154
-
155
- const finalId = evaluator . toArena ( cur ) ;
156
- labels [ finalId ] = await generateLabel ( cur ) ;
120
+ const finalId = currentId ;
157
121
sinks . add ( finalId ) ;
158
122
159
123
yield JSON . stringify ( {
160
124
source : curId ,
161
125
sink : finalId ,
162
126
steps : pathSteps ,
127
+ hasCycle,
163
128
} ) ;
164
129
}
165
130
166
131
const { nodes } = evaluator . dumpArena ( ) ;
167
132
168
133
console . error ( `Arena contains ${ nodes . length } nodes` ) ;
169
134
170
- for ( const node of nodes ) {
171
- if ( ! labels [ node . id ] ) {
172
- const expr = evaluator . fromArena ( node . id ) ;
173
- labels [ node . id ] = await generateLabel ( expr ) ;
174
- }
175
- }
176
-
177
135
const globalInfo : GlobalInfo = {
178
136
type : "global" ,
179
137
nodes,
180
- labels,
181
138
sources : Array . from ( sources ) ,
182
139
sinks : Array . from ( sinks ) ,
183
140
} ;
@@ -186,7 +143,7 @@ export async function* generateEvaluationForest(
186
143
}
187
144
188
145
async function streamToFile ( symbolCount : number , outputPath : string ) {
189
- const wasmPath = "assembly/build/debug .wasm" ;
146
+ const wasmPath = "assembly/build/release .wasm" ;
190
147
const file = await Deno . open ( outputPath , {
191
148
write : true ,
192
149
create : true ,
@@ -205,7 +162,7 @@ async function streamToFile(symbolCount: number, outputPath: string) {
205
162
}
206
163
207
164
async function streamToStdout ( symbolCount : number ) {
208
- const wasmPath = "assembly/build/debug .wasm" ;
165
+ const wasmPath = "assembly/build/release .wasm" ;
209
166
210
167
for await ( const data of generateEvaluationForest ( symbolCount , wasmPath ) ) {
211
168
console . log ( data ) ;
0 commit comments