eyeling 1.14.0 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HANDBOOK.md CHANGED
@@ -1551,6 +1551,12 @@ If `i` is out of range, `out` is the original string.
1551
1551
 
1552
1552
  Returns the number of differing positions between `a` and `b`. Fails if the two strings have different lengths.
1553
1553
 
1554
+ #### `string:mutateSelectBest`
1555
+
1556
+ **Shape:** `( samples current target mutProb seedState ) string:mutateSelectBest ( best bestScore seedState2 )`
1557
+
1558
+ Generates `samples` mutated variants of `current` (mutating each character with probability `mutProb` percent), scores each candidate against `target` (Hamming distance), and returns the best candidate (lowest score). RNG is a deterministic 31-bit LCG, threaded via `seedState` → `seedState2`, so runs are reproducible.
1559
+
1554
1560
  ### Containment and prefix/suffix tests
1555
1561
 
1556
1562
  - `string:contains`
@@ -1976,24 +1982,6 @@ References:
1976
1982
 
1977
1983
  If you are running untrusted inputs, consider `--super-restricted` to disable all builtins except implication.
1978
1984
 
1979
- ### Eyeling fast-path builtins
1980
-
1981
- Eyeling ships one optional fast-path builtins builtin e.g. used by the genetic-algorithm example:
1982
-
1983
- #### `urn:eyeling:ga:solveString`
1984
-
1985
- **Shape:** `( target mutationProbability samples seed traceEvery maxGenerations ) urn:eyeling:ga:solveString ( generation score value seed )`
1986
-
1987
- - `target` and `value` are `xsd:string` literals.
1988
- - `mutationProbability` is interpreted as a percentage per character (0–100).
1989
- - `traceEvery` controls debug tracing:
1990
- - `0` disables tracing,
1991
- - `1` traces every generation,
1992
- - `N` traces every `N` generations.
1993
- - `maxGenerations` is a safety cap:
1994
- - `0` means unlimited,
1995
- - otherwise the builtin stops once `generation >= maxGenerations` (even if not solved).
1996
-
1997
1985
  ### A.6 Skolemization and `log:skolem`
1998
1986
 
1999
1987
  When forward rule heads contain blank nodes (existentials), Eyeling replaces them with generated Skolem IRIs so derived facts are ground.
@@ -10,46 +10,158 @@
10
10
  # This is a simple hill-climbing GA (selection + mutation, no crossover), using a seeded RNG
11
11
  # so runs are reproducible.
12
12
  #
13
- # Uses Eyeling's builtin:
14
- # urn:eyeling:ga:solveString
13
+ # The GA is still expressed as backward rules (<=) for the outer evolution loop,
14
+ # but the expensive inner loop ("take N mutated samples and keep the best") is
15
+ # handled by a single string builtin to avoid huge proof trees and OOM.
15
16
  #
16
- # Configure:
17
- # :mutationProbability 5 # percent per character
18
- # :samples 80
19
- # :seed 100
20
- # :traceEvery 0 # 0=off, 1=every generation, 100=every 100 generations
21
- # :maxGenerations 0 # 0=unlimited
22
17
  # ==========================================================================================
23
18
 
24
- @prefix : <http://example.org/ga-solve#>.
25
- @prefix ega: <urn:eyeling:ga:>.
19
+ @prefix : <urn:ga:>.
26
20
  @prefix log: <http://www.w3.org/2000/10/swap/log#>.
21
+ @prefix math: <http://www.w3.org/2000/10/swap/math#>.
22
+ @prefix list: <http://www.w3.org/2000/10/swap/list#>.
27
23
  @prefix string: <http://www.w3.org/2000/10/swap/string#>.
28
24
 
29
25
  :cfg
30
26
  :mutationProbability 5;
31
27
  :samples 80;
32
28
  :seed 100;
33
- :traceEvery 1;
34
- :maxGenerations 0.
35
29
 
36
- # solveResult(TargetString) = (generation score value seed)
37
- { ?TargetString :solveResult ( ?Gen ?Score ?Value ?Seed ) } <= {
30
+ # Debug knobs:
31
+ :traceEvery 1; # 0 disables; 1 traces every generation
32
+ :maxGenerations 0; # 0 means unlimited
33
+
34
+ :alphabet (" " "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M"
35
+ "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z").
36
+
37
+ # ------------------------
38
+ # Small arithmetic helpers
39
+ # ------------------------
40
+
41
+ { ( ?N 1 ) :dec ?N1 } <= { ( ?N 1 ) math:difference ?N1 }.
42
+ { ( ?N 1 ) :inc ?N1 } <= { ( ?N 1 ) math:sum ?N1 }.
43
+
44
+ # ----------------------------------------------
45
+ # Seeded RNG (LCG) and JS Math.round(rnd() * N)
46
+ # (Used only for the initial random chromosome.)
47
+ # ----------------------------------------------
48
+
49
+ { ?S0 :lcgNext ?S1 } <= {
50
+ ( ?S0 1103515245 ) math:product ?P .
51
+ ( ?P 12345 ) math:sum ?T .
52
+ ( ?T 2147483648 ) math:remainder ?S1
53
+ }.
54
+
55
+ { ( ?S0 ?N ) :randRound ( ?R ?S1 ) } <= {
56
+ ?S0 :lcgNext ?S1 .
57
+ ( ?S1 ?N ) math:product ?A .
58
+ ( ?A ?A ) math:sum ?TwoA .
59
+ ( ?TwoA 2147483648 ) math:sum ?Num .
60
+ ( 2147483648 2 ) math:product ?Den .
61
+ ( ?Num ?Den ) math:integerQuotient ?R
62
+ }.
63
+
64
+ { ?S0 :randomAlpha ( ?Ch ?S1 ) } <= {
65
+ :cfg :alphabet ?Alphabet .
66
+ ( ?S0 26 ) :randRound ( ?Idx ?S1 ) .
67
+ ( ?Alphabet ?Idx ) list:memberAt ?Ch
68
+ }.
69
+
70
+ { ( 0 ?S0 ) :randomText ( "" ?S0 ) } <= true.
71
+
72
+ { ( ?Len ?S0 ) :randomText ( ?Out ?S2 ) } <= {
73
+ ?Len math:greaterThan 0 .
74
+ ( ?Len 1 ) :dec ?Len1 .
75
+ ?S0 :randomAlpha ( ?Ch ?S1 ) .
76
+ ( ?Len1 ?S1 ) :randomText ( ?Rest ?S2 ) .
77
+ ( "%s%s" ?Ch ?Rest ) string:format ?Out
78
+ }.
79
+
80
+ # -------------------------
81
+ # tracing helper (optional)
82
+ # -------------------------
83
+
84
+ { ( 0 ?Gen ?Score ?Value ) :traceMaybe true } <= true.
85
+
86
+ { ( ?Every ?Gen ?Score ?Value ) :traceMaybe true } <= {
87
+ ?Every math:greaterThan 0 .
88
+ ( ?Gen ?Every ) math:remainder ?R .
89
+ ?R math:equalTo 0 .
90
+ ?Gen log:trace ( ?Score ?Value )
91
+ }.
92
+
93
+ # --------------
94
+ # evolution loop
95
+ # --------------
96
+
97
+ # Stop when score == 0
98
+ { ( ?Current 0 ?Target ?MutProb ?Samples ?Gen ?S0 ?MaxGen ?TraceEvery )
99
+ :evolve ( ?Current ?Gen ?S0 ) } <= true.
100
+
101
+ # Stop when generation cap is reached (only if MaxGen > 0)
102
+ { ( ?Current ?Score ?Target ?MutProb ?Samples ?Gen ?S0 ?MaxGen ?TraceEvery )
103
+ :evolve ( ?Current ?Gen ?S0 ) } <= {
104
+ ?Score math:notEqualTo 0 .
105
+ ?MaxGen math:greaterThan 0 .
106
+ ?Gen math:equalTo ?MaxGen
107
+ }.
108
+
109
+ # Unlimited run (MaxGen == 0): keep evolving
110
+ { ( ?Current ?Score ?Target ?MutProb ?Samples ?Gen ?S0 0 ?TraceEvery )
111
+ :evolve ( ?Final ?FinalGen ?S2 ) } <= {
112
+ ?Score math:notEqualTo 0 .
113
+ ( ?Samples ?Current ?Target ?MutProb ?S0 )
114
+ string:mutateSelectBest
115
+ ( ?Best ?BestScore ?S1 ) .
116
+ ( ?Gen 1 ) :inc ?Gen1 .
117
+ ( ?TraceEvery ?Gen1 ?BestScore ?Best ) :traceMaybe true .
118
+ ( ?Best ?BestScore ?Target ?MutProb ?Samples ?Gen1 ?S1 0 ?TraceEvery )
119
+ :evolve ( ?Final ?FinalGen ?S2 )
120
+ }.
121
+
122
+ # Bounded run (MaxGen > 0): keep evolving while Gen < MaxGen
123
+ { ( ?Current ?Score ?Target ?MutProb ?Samples ?Gen ?S0 ?MaxGen ?TraceEvery )
124
+ :evolve ( ?Final ?FinalGen ?S2 ) } <= {
125
+ ?Score math:notEqualTo 0 .
126
+ ?MaxGen math:greaterThan 0 .
127
+ ?Gen math:lessThan ?MaxGen .
128
+ ( ?Samples ?Current ?Target ?MutProb ?S0 )
129
+ string:mutateSelectBest
130
+ ( ?Best ?BestScore ?S1 ) .
131
+ ( ?Gen 1 ) :inc ?Gen1 .
132
+ ( ?TraceEvery ?Gen1 ?BestScore ?Best ) :traceMaybe true .
133
+ ( ?Best ?BestScore ?Target ?MutProb ?Samples ?Gen1 ?S1 ?MaxGen ?TraceEvery )
134
+ :evolve ( ?Final ?FinalGen ?S2 )
135
+ }.
136
+
137
+ # ----------------------------------
138
+ # Public solver wrapper (string API)
139
+ # ----------------------------------
140
+
141
+ { ?TargetString :solveResult ( ?Gen 0 ?Value ?Seed ) } <= {
38
142
  :cfg :mutationProbability ?MutProb;
39
143
  :samples ?Samples;
40
144
  :seed ?Seed;
41
145
  :traceEvery ?TraceEvery;
42
- :maxGenerations ?MaxG.
146
+ :maxGenerations ?MaxGen.
147
+
148
+ ?TargetString string:length ?Len .
149
+
150
+ ( ?Len ?Seed ) :randomText ( ?Current0 ?S1 ) .
151
+
152
+ # initial score using string:hammingDistance
153
+ ( ?Current0 ?TargetString ) string:hammingDistance ?Score0 .
43
154
 
44
- ( ?TargetString ?MutProb ?Samples ?Seed ?TraceEvery ?MaxG )
45
- ega:solveString
46
- ( ?Gen ?Score ?Value ?SeedOut ) .
155
+ ( ?Current0 ?Score0 ?TargetString ?MutProb ?Samples 0 ?S1 ?MaxGen ?TraceEvery )
156
+ :evolve
157
+ ( ?Value ?Gen ?S2 ) .
47
158
 
48
- # By design, the 4th output is the (input) seed.
49
- ?SeedOut log:equalTo ?Seed
159
+ # Succeeds only when solved:
160
+ ( ?Value ?TargetString ) string:hammingDistance 0 .
161
+ ?Value log:equalTo ?TargetString .
162
+ ?S2 log:equalTo ?_FinalSeedState
50
163
  }.
51
164
 
52
- # Boolean-ish API for querying success
53
165
  { ?TargetString :solved true } <= {
54
166
  ?TargetString :solveResult ( ?Gen 0 ?TargetString ?Seed )
55
167
  }.
@@ -60,4 +172,6 @@
60
172
 
61
173
  { "METHINKS IT IS LIKE A WEASEL" :solved true .
62
174
  ( "solve('%s').\n" "METHINKS IT IS LIKE A WEASEL" ) string:format ?Line
63
- } => { 1 log:outputString ?Line }.
175
+ }
176
+ log:query
177
+ { 1 log:outputString ?Line }.
@@ -346,7 +346,5 @@ string:setCharAt a ex:Builtin ; ex:kind ex:Function ;
346
346
  string:hammingDistance a ex:Builtin ; ex:kind ex:Function ;
347
347
  rdfs:comment "Function: subject is a 2-item list (a b). Binds/unifies object with the number of differing positions (Hamming distance). Fails if lengths differ." .
348
348
 
349
- # --- eyeling fast path builtins ------------------------------
350
-
351
- ega:solveString a ex:Builtin ; ex:kind ex:Function ;
352
- rdfs:comment "Eyeling extension: GA solver on strings. Subject list: (target mutationProbability samples seed traceEvery maxGenerations). Object list: (generation score value seed). traceEvery=0 disables tracing; maxGenerations=0 means unlimited." .
349
+ string:mutateSelectBest a ex:Builtin ; ex:kind ex:Function ;
350
+ rdfs:comment "Shape: (samples current target mutProb seedState) string:mutateSelectBest (best bestScore seedState2). Generates samples mutated variants of current (mutating each character with probability mutProb percent), scores each candidate against target (Hamming distance), and returns the best candidate (lowest score). RNG is a deterministic 31-bit LCG, threaded via seedState → seedState2, so runs are reproducible." .
package/eyeling.js CHANGED
@@ -3547,34 +3547,35 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3547
3547
  return s2 !== null ? [s2] : [];
3548
3548
  }
3549
3549
 
3550
- // -----------------------------------------------------------------
3551
- // 4.6.2 urn:eyeling:ga: builtins (fast GA on *strings*)
3552
- // -----------------------------------------------------------------
3553
-
3554
- // urn:eyeling:ga:solveString
3555
- // Schema: ( $target $mutProb $samples $seed $traceEvery $maxGenerations ) :solveString ( $gen $score $value $seed )
3556
- // Side effect: if traceEvery > 0, prints: <gen> TRACE (<score> "<value>")
3557
- if (pv === 'urn:eyeling:ga:solveString') {
3558
- if (!(g.s instanceof ListTerm) || g.s.elems.length != 6) return [];
3559
-
3560
- const target = termToJsXsdStringNoLang(g.s.elems[0]);
3561
- const mutProbNum = parseNum(g.s.elems[1]);
3562
- const samplesNum = parseNum(g.s.elems[2]);
3563
- const seedNum = parseNum(g.s.elems[3]);
3564
- const traceEveryNum = parseNum(g.s.elems[4]);
3565
- const maxGenNum = parseNum(g.s.elems[5]);
3566
-
3567
- if (target === null || mutProbNum === null || samplesNum === null || seedNum === null) return [];
3568
- if (traceEveryNum === null || maxGenNum === null) return [];
3550
+ // string:mutateSelectBest
3551
+ // Schema:
3552
+ // ( $samples $current $target $mutProb $seedState )
3553
+ // string:mutateSelectBest
3554
+ // ( $best $bestScore $seedState2 )
3555
+ //
3556
+ // Deterministic 31-bit LCG (same as the GA demo):
3557
+ // state = (1103515245 * state + 12345) % 2^31
3558
+ // and randRound(N) = Math.round((state/2^31) * N) with state advanced once per draw.
3559
+ //
3560
+ // This builtin exists to keep GA-style "many samples × many characters" loops out of
3561
+ // the proof search (dramatically reducing memory use).
3562
+ if (pv === STRING_NS + 'mutateSelectBest') {
3563
+ if (!(g.s instanceof ListTerm) || g.s.elems.length !== 5) return [];
3564
+
3565
+ const samplesNum = parseNum(g.s.elems[0]);
3566
+ const current = termToJsXsdStringNoLang(g.s.elems[1]);
3567
+ const target = termToJsXsdStringNoLang(g.s.elems[2]);
3568
+ const mutProbNum = parseNum(g.s.elems[3]);
3569
+ const seedNum = parseNum(g.s.elems[4]);
3570
+
3571
+ if (samplesNum === null || current === null || target === null || mutProbNum === null || seedNum === null)
3572
+ return [];
3573
+ if (current.length !== target.length) return [];
3569
3574
 
3570
- const mutProb = Math.max(0, Math.trunc(mutProbNum));
3571
3575
  const samples = Math.max(1, Math.trunc(samplesNum));
3576
+ const mutProb = Math.max(0, Math.trunc(mutProbNum));
3572
3577
  const seed0 = Math.trunc(seedNum);
3573
3578
 
3574
- const traceEvery = Math.max(0, Math.trunc(traceEveryNum));
3575
- const maxGenerations = Math.max(0, Math.trunc(maxGenNum));
3576
-
3577
- // Deterministic 31-bit LCG using BigInt arithmetic (matches the N3 version)
3578
3579
  let state = BigInt(seed0);
3579
3580
  const MOD = 2147483648n; // 2^31
3580
3581
  const A = 1103515245n;
@@ -3594,12 +3595,6 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3594
3595
  return p === 0 ? ' ' : String.fromCharCode(64 + p);
3595
3596
  }
3596
3597
 
3597
- function randomText(len) {
3598
- let out = '';
3599
- for (let i = 0; i < len; i++) out += randomAlpha();
3600
- return out;
3601
- }
3602
-
3603
3598
  function mutate(str) {
3604
3599
  let out = '';
3605
3600
  for (let i = 0; i < str.length; i++) {
@@ -3616,50 +3611,22 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3616
3611
  return diffs;
3617
3612
  }
3618
3613
 
3619
- const pref = trace.getTracePrefixes() || PrefixEnv.newDefault();
3620
- function doTrace(gen, sc, val) {
3621
- const genLit = internLiteral(String(gen));
3622
- const scLit = internLiteral(String(sc));
3623
- const valLit = makeStringLiteral(val);
3624
- const obj = new ListTerm([scLit, valLit]);
3625
- const xStr = termToN3(genLit, pref);
3626
- const yStr = termToN3(obj, pref);
3627
- trace.writeTraceLine(`${xStr} TRACE ${yStr}`);
3628
- }
3629
-
3630
- let generation = 0;
3631
- let current = randomText(target.length);
3632
- let currentScore = score(current);
3633
-
3634
- if (traceEvery > 0 && generation % traceEvery === 0) doTrace(generation, currentScore, current);
3635
-
3636
- while (currentScore !== 0) {
3637
- if (maxGenerations > 0 && generation >= maxGenerations) break;
3638
-
3639
- let best = '';
3640
- let bestScore = Infinity;
3641
-
3642
- for (let i = 0; i < samples; i++) {
3643
- const cand = mutate(current);
3644
- const candScore = score(cand);
3645
- if (candScore < bestScore) {
3646
- best = cand;
3647
- bestScore = candScore;
3648
- }
3649
- }
3614
+ let best = '';
3615
+ let bestScore = Infinity;
3650
3616
 
3651
- generation += 1;
3652
- current = best;
3653
- currentScore = bestScore;
3654
-
3655
- if (traceEvery > 0 && generation % traceEvery === 0) doTrace(generation, currentScore, current);
3617
+ for (let i = 0; i < samples; i++) {
3618
+ const cand = mutate(current);
3619
+ const candScore = score(cand);
3620
+ if (candScore < bestScore) {
3621
+ best = cand;
3622
+ bestScore = candScore;
3623
+ }
3656
3624
  }
3657
3625
 
3658
3626
  const outList = new ListTerm([
3659
- internLiteral(String(generation)),
3660
- internLiteral(String(currentScore)),
3661
- makeStringLiteral(current),
3662
- internLiteral(String(seed0)),
3627
+ makeStringLiteral(best),
3628
+ internLiteral(String(bestScore)),
3629
+ internLiteral(state.toString()),
3663
3630
  ]);
3664
3631
 
3665
3632
  const s2 = unifyTerm(g.o, outList, subst);
@@ -3686,11 +3653,6 @@ function isBuiltinPred(p) {
3686
3653
  return true;
3687
3654
  }
3688
3655
 
3689
- // Eyeling extension: GA demo builtins
3690
- if (v === 'urn:eyeling:ga:solveString') {
3691
- return true;
3692
- }
3693
-
3694
3656
  return (
3695
3657
  v.startsWith(CRYPTO_NS) ||
3696
3658
  v.startsWith(MATH_NS) ||
package/lib/builtins.js CHANGED
@@ -3535,34 +3535,32 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3535
3535
  return s2 !== null ? [s2] : [];
3536
3536
  }
3537
3537
 
3538
- // -----------------------------------------------------------------
3539
- // 4.6.2 urn:eyeling:ga: builtins (fast GA on *strings*)
3540
- // -----------------------------------------------------------------
3541
-
3542
- // urn:eyeling:ga:solveString
3543
- // Schema: ( $target $mutProb $samples $seed $traceEvery $maxGenerations ) :solveString ( $gen $score $value $seed )
3544
- // Side effect: if traceEvery > 0, prints: <gen> TRACE (<score> "<value>")
3545
- if (pv === 'urn:eyeling:ga:solveString') {
3546
- if (!(g.s instanceof ListTerm) || g.s.elems.length != 6) return [];
3547
-
3548
- const target = termToJsXsdStringNoLang(g.s.elems[0]);
3549
- const mutProbNum = parseNum(g.s.elems[1]);
3550
- const samplesNum = parseNum(g.s.elems[2]);
3551
- const seedNum = parseNum(g.s.elems[3]);
3552
- const traceEveryNum = parseNum(g.s.elems[4]);
3553
- const maxGenNum = parseNum(g.s.elems[5]);
3554
-
3555
- if (target === null || mutProbNum === null || samplesNum === null || seedNum === null) return [];
3556
- if (traceEveryNum === null || maxGenNum === null) return [];
3538
+ // string:mutateSelectBest
3539
+ // Schema:
3540
+ // ( $samples $current $target $mutProb $seedState )
3541
+ // string:mutateSelectBest
3542
+ // ( $best $bestScore $seedState2 )
3543
+ //
3544
+ // Deterministic 31-bit LCG (same as the GA demo):
3545
+ // state = (1103515245 * state + 12345) % 2^31
3546
+ // and randRound(N) = Math.round((state/2^31) * N) with state advanced once per draw.
3547
+ if (pv === STRING_NS + 'mutateSelectBest') {
3548
+ if (!(g.s instanceof ListTerm) || g.s.elems.length !== 5) return [];
3549
+
3550
+ const samplesNum = parseNum(g.s.elems[0]);
3551
+ const current = termToJsXsdStringNoLang(g.s.elems[1]);
3552
+ const target = termToJsXsdStringNoLang(g.s.elems[2]);
3553
+ const mutProbNum = parseNum(g.s.elems[3]);
3554
+ const seedNum = parseNum(g.s.elems[4]);
3555
+
3556
+ if (samplesNum === null || current === null || target === null || mutProbNum === null || seedNum === null)
3557
+ return [];
3558
+ if (current.length !== target.length) return [];
3557
3559
 
3558
- const mutProb = Math.max(0, Math.trunc(mutProbNum));
3559
3560
  const samples = Math.max(1, Math.trunc(samplesNum));
3561
+ const mutProb = Math.max(0, Math.trunc(mutProbNum));
3560
3562
  const seed0 = Math.trunc(seedNum);
3561
3563
 
3562
- const traceEvery = Math.max(0, Math.trunc(traceEveryNum));
3563
- const maxGenerations = Math.max(0, Math.trunc(maxGenNum));
3564
-
3565
- // Deterministic 31-bit LCG using BigInt arithmetic (matches the N3 version)
3566
3564
  let state = BigInt(seed0);
3567
3565
  const MOD = 2147483648n; // 2^31
3568
3566
  const A = 1103515245n;
@@ -3582,12 +3580,6 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3582
3580
  return p === 0 ? ' ' : String.fromCharCode(64 + p);
3583
3581
  }
3584
3582
 
3585
- function randomText(len) {
3586
- let out = '';
3587
- for (let i = 0; i < len; i++) out += randomAlpha();
3588
- return out;
3589
- }
3590
-
3591
3583
  function mutate(str) {
3592
3584
  let out = '';
3593
3585
  for (let i = 0; i < str.length; i++) {
@@ -3604,50 +3596,22 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3604
3596
  return diffs;
3605
3597
  }
3606
3598
 
3607
- const pref = trace.getTracePrefixes() || PrefixEnv.newDefault();
3608
- function doTrace(gen, sc, val) {
3609
- const genLit = internLiteral(String(gen));
3610
- const scLit = internLiteral(String(sc));
3611
- const valLit = makeStringLiteral(val);
3612
- const obj = new ListTerm([scLit, valLit]);
3613
- const xStr = termToN3(genLit, pref);
3614
- const yStr = termToN3(obj, pref);
3615
- trace.writeTraceLine(`${xStr} TRACE ${yStr}`);
3616
- }
3617
-
3618
- let generation = 0;
3619
- let current = randomText(target.length);
3620
- let currentScore = score(current);
3621
-
3622
- if (traceEvery > 0 && generation % traceEvery === 0) doTrace(generation, currentScore, current);
3623
-
3624
- while (currentScore !== 0) {
3625
- if (maxGenerations > 0 && generation >= maxGenerations) break;
3626
-
3627
- let best = '';
3628
- let bestScore = Infinity;
3629
-
3630
- for (let i = 0; i < samples; i++) {
3631
- const cand = mutate(current);
3632
- const candScore = score(cand);
3633
- if (candScore < bestScore) {
3634
- best = cand;
3635
- bestScore = candScore;
3636
- }
3637
- }
3599
+ let best = '';
3600
+ let bestScore = Infinity;
3638
3601
 
3639
- generation += 1;
3640
- current = best;
3641
- currentScore = bestScore;
3642
-
3643
- if (traceEvery > 0 && generation % traceEvery === 0) doTrace(generation, currentScore, current);
3602
+ for (let i = 0; i < samples; i++) {
3603
+ const cand = mutate(current);
3604
+ const candScore = score(cand);
3605
+ if (candScore < bestScore) {
3606
+ best = cand;
3607
+ bestScore = candScore;
3608
+ }
3644
3609
  }
3645
3610
 
3646
3611
  const outList = new ListTerm([
3647
- internLiteral(String(generation)),
3648
- internLiteral(String(currentScore)),
3649
- makeStringLiteral(current),
3650
- internLiteral(String(seed0)),
3612
+ makeStringLiteral(best),
3613
+ internLiteral(String(bestScore)),
3614
+ internLiteral(state.toString()),
3651
3615
  ]);
3652
3616
 
3653
3617
  const s2 = unifyTerm(g.o, outList, subst);
@@ -3674,11 +3638,6 @@ function isBuiltinPred(p) {
3674
3638
  return true;
3675
3639
  }
3676
3640
 
3677
- // Eyeling extension: GA demo builtins
3678
- if (v === 'urn:eyeling:ga:solveString') {
3679
- return true;
3680
- }
3681
-
3682
3641
  return (
3683
3642
  v.startsWith(CRYPTO_NS) ||
3684
3643
  v.startsWith(MATH_NS) ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [