Skip to content

Commit 105030e

Browse files
Eric Prud'hommeauxclaude
andcommitted
+ evidence-dnf: abstracted DNF rule engine + compiler mode-toggle tests
An evidence-appraisal abstraction of a production rule engine (components -> evidence; component types -> observational/rnc study types; diameterInInches -> pValue; material -> effectMeasure with OddsRatio/AdjustedOddsRatio/HazardRatio values; study-sounding names throughout; the recommendation UNION arm and its data omitted): tests/Algae3/evidence-dnf.rq + data/evidence{,-groups,-rules}.ttl, structurally identical to the source (same selectors/disjuncts/conjuncts, polarities and olo:index ordering) - two rules fire with the same shape of per-level logs. Compiler mode-toggle coverage: - evidence-dnf.{topdown,bottomup}.a3: committed sparql-to-a3.js outputs (regen + self-check: tests/Algae3/regen-compiled.mjs, needs node). - test_Algae3 evaluates both against one golden and re-runs each under both engine modes (the workaround-style query is well-designed, so all four combinations agree). - sparql-to-a3.js: SPARQL query blank nodes now compile as ?_bn_* variables - they are BGP-scoped existentials (SPARQL 4.1.4) and a3 blank nodes do not join across '.' boundaries; this fixes a cross-join of every rule with every message. - engine load: pseudo-absolute file:/rel paths (from a bare BASE <file:>) retry relative to the script directory. All 22 suites pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 7b2c32c commit 105030e

11 files changed

Lines changed: 674 additions & 3 deletions

lib/Algae3.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,9 +630,17 @@ namespace a3 {
630630
if (!path.empty() && path[0] != '/' && !e.baseDir.empty())
631631
path = e.baseDir + "/" + path;
632632
std::ifstream check(path.c_str());
633-
if (!check.good())
633+
if (!check.good() && path[0] == '/' && !e.baseDir.empty()) {
634+
/* a bare `file:` base yields pseudo-absolute /rel paths;
635+
* retry relative to the script directory */
636+
std::string rel = e.baseDir + path;
637+
std::ifstream retry(rel.c_str());
638+
if (retry.good())
639+
path = rel;
640+
}
641+
std::ifstream check2(path.c_str());
642+
if (!check2.good())
634643
throw std::string("load: cannot open \"") + path + "\"";
635-
check.close();
636644
IStreamContext istr(path, IStreamContext::FILE);
637645
/* a fresh driver per load: its private bnode map standardizes
638646
* blank nodes apart, making load a graph MERGE; `as` leaves the

sparql-to-a3.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ function term(t) {
2525
switch (t.termType) {
2626
case "NamedNode": return "<" + t.value + ">";
2727
case "Variable": return "?" + t.value;
28-
case "BlankNode": return "_:" + t.value.replace(/[^A-Za-z0-9_]/g, "_");
28+
case "BlankNode": /* query blank nodes are existential variables scoped to
29+
the BGP (SPARQL 4.1.4); Algae 3 blank nodes do not join across `.`
30+
boundaries, so compile them as variables with a reserved prefix */
31+
return "?_bn_" + t.value.replace(/[^A-Za-z0-9_]/g, "_");
2932
case "Literal": {
3033
const lex = '"' + t.value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
3134
const dt = t.datatype?.value;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Evidence groups (abstracted from component groups).
2+
PREFIX ex: <http://a.example/ns#>
3+
PREFIX ev: <http://a.example/evidence#>
4+
PREFIX evgrp: <http://a.example/evgrp/>
5+
6+
evgrp:MetaAnalyses1 a ex:Group ;
7+
ex:name "MetaAnalyses1(?)" ;
8+
ex:member [ ex:evidence ev:MA-1 ] .
9+
10+
evgrp:RecentCohorts a ex:Group ;
11+
ex:name "cohorts started within 2y" ;
12+
ex:member
13+
<#RecentCohorts_OBS-2214> ,
14+
<#RecentCohorts_DOES_NOT_EXIST> .
15+
<#RecentCohorts_OBS-2214> ex:evidence ev:OBS-2214 .
16+
<#RecentCohorts_DOES_NOT_EXIST> ex:evidence ev:DOES_NOT_EXIST .
17+
18+
evgrp:PeerReviewedCohorts a ex:Group ;
19+
ex:name "peer-reviewed cohorts" ;
20+
ex:member
21+
[ ex:evidence ev:OBS-0999 ] ,
22+
[ ex:evidence ev:OBS-2214 ] .
23+
24+
evgrp:ConfoundedStudies a ex:Group ;
25+
ex:name "confounding-prone studies" ;
26+
ex:member
27+
[ ex:evidence ev:OBS-2214 ] ,
28+
[ ex:evidence ev:OBS-0990 ] .
29+
30+
evgrp:PreregisteredStudies a ex:Group ;
31+
ex:name "preregistered studies" ;
32+
# does NOT include ev:OBS-2214
33+
ex:member [ ex:evidence ev:OBS-0990 ] .
34+
35+
evgrp:PeerReviewedCohortsEXCLUDED a ex:Group ;
36+
ex:name "peer-reviewed cohorts" ;
37+
ex:member
38+
[ ex:evidence ev:OBS-0999EXCLUDED ] ,
39+
[ ex:evidence ev:OBS-2214EXCLUDED ] .
40+
41+
evgrp:ConfoundedStudiesEXCLUDED a ex:Group ;
42+
ex:name "confounded studies" ;
43+
ex:member
44+
[ ex:evidence ev:OBS-2214EXCLUDED ] ,
45+
[ ex:evidence ev:OBS-0990EXCLUDED ] .
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Evidence-appraisal rules in DNF (abstracted from a production rule set;
2+
# same selectors/disjuncts/conjuncts, polarities and olo:index ordering).
3+
@prefix evgrp: <http://a.example/evgrp/> .
4+
@prefix ex: <http://a.example/ns#> .
5+
@prefix olo: <http://purl.org/ontology/olo/core#> .
6+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
7+
8+
<#pubbias> a ex:CorroborationRule,
9+
ex:Rule ;
10+
ex:action <#pubbias_action0> ;
11+
ex:label "publication-bias" ;
12+
ex:selector <#pubbias_selector0>,
13+
<#pubbias_selector1> .
14+
15+
<#confound> a ex:Rule,
16+
ex:SingleEvidenceRule ;
17+
ex:action <#confound_action0> ;
18+
ex:label "confound-sensitive" ;
19+
ex:selector <#confound_selector0> .
20+
21+
<#underpow> a ex:CorroborationRule,
22+
ex:Rule ;
23+
ex:action <#underpow_action0> ;
24+
ex:label "underpowered" ;
25+
ex:selector <#underpow_selector0>,
26+
<#underpow_selector1> .
27+
28+
<#pubbias_action0> ex:message "publication-bias" ;
29+
ex:severity ex:Critical .
30+
31+
<#pubbias_selector0> ex:or <#pubbias_selector0_or0>,
32+
<#pubbias_selector0_or1> ;
33+
olo:index 0 .
34+
35+
<#pubbias_selector0_or0> ex:and <#pubbias_selector0_or0_and0>,
36+
<#pubbias_selector0_or0_and2>,
37+
<#pubbias_selector0_or0_and3> ;
38+
olo:index 0 .
39+
40+
<#pubbias_selector0_or0_and0> ex:evidenceGroup evgrp:RecentCohorts ;
41+
ex:polarity ex:pos ;
42+
olo:index 0 .
43+
44+
<#pubbias_selector0_or0_and2> ex:attribute ex:effectMeasure ;
45+
ex:eq ex:OddsRatio ;
46+
ex:polarity ex:pos ;
47+
olo:index 2 .
48+
49+
<#pubbias_selector0_or0_and3> ex:attribute ex:effectMeasure ;
50+
ex:eq ex:AdjustedOddsRatio ;
51+
ex:polarity ex:neg ;
52+
olo:index 3 .
53+
54+
<#pubbias_selector0_or1> ex:and <#pubbias_selector0_or1_and0>,
55+
<#pubbias_selector0_or1_and2> ;
56+
olo:index 1 .
57+
58+
<#pubbias_selector0_or1_and0> ex:evidenceGroup evgrp:PeerReviewedCohorts ;
59+
ex:polarity ex:pos ;
60+
olo:index 0 .
61+
62+
<#pubbias_selector0_or1_and2> ex:attribute ex:effectMeasure ;
63+
ex:eq ex:OddsRatio ;
64+
ex:polarity ex:pos ;
65+
olo:index 2 .
66+
67+
<#pubbias_selector1> ex:or <#pubbias_selector1_or0> ;
68+
olo:index 1 .
69+
70+
<#pubbias_selector1_or0> ex:and <#pubbias_selector1_or0_and0> ;
71+
olo:index 0 .
72+
73+
<#pubbias_selector1_or0_and0> ex:attribute ex:pValue ;
74+
ex:ge 0.5 ;
75+
ex:polarity ex:pos ;
76+
olo:index 0 .
77+
78+
<#confound_action0> ex:message "confound-sensitive" ;
79+
ex:severity ex:Critical .
80+
81+
<#confound_selector0> ex:or <#confound_selector0_or0>,
82+
<#confound_selector0_or1> ;
83+
olo:index 0 .
84+
85+
<#confound_selector0_or0> ex:and <#confound_selector0_or0_and0>,
86+
<#confound_selector0_or0_and1>,
87+
<#confound_selector0_or0_and2>,
88+
<#confound_selector0_or0_and3> ;
89+
ex:description """
90+
RecentCohorts
91+
∧ in ConfoundedStudies
92+
∧ effectMeasure=OddsRatio
93+
∧ ¬effectMeasure=HazardRatio
94+
""" ;
95+
olo:index 0 .
96+
97+
<#confound_selector0_or0_and0> ex:evidenceGroup evgrp:RecentCohorts ;
98+
ex:polarity ex:pos ;
99+
olo:index 0 .
100+
101+
<#confound_selector0_or0_and1> ex:evidenceGroup evgrp:ConfoundedStudies ;
102+
ex:polarity ex:pos ;
103+
olo:index 1 .
104+
105+
<#confound_selector0_or0_and2> ex:attribute ex:effectMeasure ;
106+
ex:eq ex:OddsRatio ;
107+
ex:polarity ex:pos ;
108+
olo:index 2 .
109+
110+
<#confound_selector0_or0_and3> ex:attribute ex:effectMeasure ;
111+
ex:eq ex:HazardRatio ;
112+
ex:polarity ex:neg ;
113+
olo:index 3 .
114+
115+
<#confound_selector0_or1> ex:and <#confound_selector0_or1_and0>,
116+
<#confound_selector0_or1_and1>,
117+
<#confound_selector0_or1_and2> ;
118+
ex:description """
119+
PeerReviewedCohorts
120+
∧ in ConfoundedStudies
121+
∧ effectMeasure=OddsRatio
122+
""" ;
123+
olo:index 1 .
124+
125+
<#confound_selector0_or1_and0> ex:evidenceGroup evgrp:PeerReviewedCohorts ;
126+
ex:polarity ex:pos ;
127+
olo:index 0 .
128+
129+
<#confound_selector0_or1_and1> ex:evidenceGroup evgrp:ConfoundedStudies ;
130+
ex:polarity ex:pos ;
131+
olo:index 1 .
132+
133+
<#confound_selector0_or1_and2> ex:attribute ex:effectMeasure ;
134+
ex:eq ex:OddsRatio ;
135+
ex:polarity ex:pos ;
136+
olo:index 2 .
137+
138+
<#underpow_action0> ex:message "underpowered" ;
139+
ex:severity ex:Critical .
140+
141+
<#underpow_selector0> ex:or <#underpow_selector0_or0>,
142+
<#underpow_selector0_or1> ;
143+
olo:index 0 .
144+
145+
<#underpow_selector0_or0> ex:and <#underpow_selector0_or0_and0>,
146+
<#underpow_selector0_or0_and1>,
147+
<#underpow_selector0_or0_and2>,
148+
<#underpow_selector0_or0_and3> ;
149+
olo:index 0 .
150+
151+
<#underpow_selector0_or0_and0> ex:evidenceGroup evgrp:RecentCohorts ;
152+
ex:polarity ex:pos ;
153+
olo:index 0 .
154+
155+
<#underpow_selector0_or0_and1> ex:evidenceGroup evgrp:ConfoundedStudies ;
156+
ex:polarity ex:pos ;
157+
olo:index 1 .
158+
159+
<#underpow_selector0_or0_and2> ex:attribute ex:effectMeasure ;
160+
ex:eq ex:OddsRatio ;
161+
ex:polarity ex:pos ;
162+
olo:index 2 .
163+
164+
<#underpow_selector0_or0_and3> ex:attribute ex:effectMeasure ;
165+
ex:eq ex:HazardRatio ;
166+
ex:polarity ex:neg ;
167+
olo:index 3 .
168+
169+
<#underpow_selector0_or1> ex:and <#underpow_selector0_or1_and0>,
170+
<#underpow_selector0_or1_and1>,
171+
<#underpow_selector0_or1_and2>,
172+
<#underpow_selector0_or1_and3> ;
173+
olo:index 1 .
174+
175+
<#underpow_selector0_or1_and0> ex:evidenceGroup evgrp:PeerReviewedCohorts ;
176+
ex:polarity ex:pos ;
177+
olo:index 0 .
178+
179+
<#underpow_selector0_or1_and1> ex:evidenceGroup evgrp:ConfoundedStudies ;
180+
ex:polarity ex:pos ;
181+
olo:index 1 .
182+
183+
<#underpow_selector0_or1_and2> ex:attribute ex:effectMeasure ;
184+
ex:eq ex:OddsRatio ;
185+
ex:polarity ex:pos ;
186+
olo:index 2 .
187+
188+
<#underpow_selector0_or1_and3> ex:evidenceGroup evgrp:PreregisteredStudies ;
189+
ex:polarity ex:neg ;
190+
olo:index 3 .
191+
192+
<#underpow_selector1> ex:or <#underpow_selector1_or0> ;
193+
olo:index 1 .
194+
195+
<#underpow_selector1_or0> ex:and <#underpow_selector1_or0_and0> ;
196+
olo:index 0 .
197+
198+
<#underpow_selector1_or0_and0> ex:attribute ex:pValue ;
199+
ex:lt 0.25 ;
200+
ex:polarity ex:pos ;
201+
olo:index 0 .
202+

tests/Algae3/data/evidence.ttl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Evidence-appraisal instance data (abstracted from a production component
2+
# catalog: components -> evidence, Film -> Observational, Port -> Rnc,
3+
# diameterInInches -> pValue, material -> effectMeasure).
4+
PREFIX ex: <http://a.example/ns#>
5+
PREFIX ev: <http://a.example/evidence#>
6+
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
7+
8+
ex:Observational rdfs:subClassOf ex:Evidence .
9+
ex:Rnc rdfs:subClassOf ex:Evidence .
10+
11+
## Pooled analyses
12+
ev:MA-1 a ex:PooledAnalysis ;
13+
ex:onObservational ev:OBS-2214 ;
14+
ex:onRnc ev:RNC-0859.1 .
15+
16+
## Observational studies
17+
ev:OBS-2214 a ex:Observational ;
18+
ex:registryId "OBS-2214" ;
19+
ex:name "Cohort of 2214 adults" ;
20+
ex:effectMeasure ex:OddsRatio .
21+
22+
## Randomized controlled trials (one family, four arms)
23+
ev:RNC-0859.1 a ex:Rnc ;
24+
ex:trialFamily "RNC-0859" ;
25+
ex:pValue .15625 ;
26+
ex:name "multi-arm trial (arm 1)" .
27+
28+
ev:RNC-0859.2 a ex:Rnc ;
29+
ex:trialFamily "RNC-0859" ;
30+
ex:pValue .25 ;
31+
ex:name "multi-arm trial (arm 2)" .
32+
33+
ev:RNC-0859.3 a ex:Rnc ;
34+
ex:trialFamily "RNC-0859" ;
35+
ex:pValue .375 ;
36+
ex:name "multi-arm trial (arm 3)" .
37+
38+
ev:RNC-0859.4 a ex:Rnc ;
39+
ex:trialFamily "RNC-0859" ;
40+
ex:pValue .5 ;
41+
ex:name "multi-arm trial (arm 4)" .

0 commit comments

Comments
 (0)