Skip to content

Commit d11c553

Browse files
author
ctjoreilly
committed
- fixed a defect in the FOLOTTERLikeTheorem prover, whereby its lightest clause heuristic was not cleaning down its SOS between calls to ask().
- put a hard coded learned Hypothesis into the CurrentBestLearning algorithm implementation in order to ensure supporting infrastructure in place. - Made the underlying translation from a DataSetSpecification to FOL more robust to non java identifiers (i.e. affects the FOLLexer).
1 parent 900ebc9 commit d11c553

File tree

9 files changed

+166
-32
lines changed

9 files changed

+166
-32
lines changed

src/aima/learning/knowledge/CurrentBestLearning.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import java.util.List;
44

5+
import aima.logic.fol.kb.FOLKnowledgeBase;
6+
import aima.logic.fol.kb.data.Clause;
7+
58
/**
69
* Artificial Intelligence A Modern Approach (2nd Edition): Figure 19.2, page 681.
710
*
@@ -28,20 +31,27 @@
2831
*/
2932
public class CurrentBestLearning {
3033
private FOLDataSetDomain folDSDomain = null;
34+
private FOLKnowledgeBase kbForLearning = null;
3135

3236
//
3337
// PUBLIC METHODS
3438
//
35-
public CurrentBestLearning(FOLDataSetDomain folDSDomain) {
39+
public CurrentBestLearning(FOLDataSetDomain folDSDomain, FOLKnowledgeBase kbForLearning) {
3640
this.folDSDomain = folDSDomain;
41+
this.kbForLearning = kbForLearning;
3742
}
3843

3944
// * function CURRENT-BEST-LEARNING(examples) returns a hypothesis
4045
public Hypothesis currentBestLearning(List<FOLExample> examples) {
41-
// TODO-remove this test behavior code
42-
// for (FOLExample fe : examples) {
43-
// System.out.println(fe.toString());
44-
// }
46+
47+
// TODO-use the default from pg 679 for now.
48+
String c1 = "patrons(v,Some)";
49+
String c2 = "patrons(v,Full) AND (hungry(v) AND type(v,French))";
50+
String c3 = "patrons(v,Full) AND (hungry(v) AND (type(v,Thai) AND fri_sat(v)))";
51+
String c4 = "patrons(v,Full) AND (hungry(v) AND type(v,Burger))";
52+
String sh = "FORALL v (will_wait(v) <=> ("+c1+" OR ("+c2+" OR ("+c3+" OR ("+c4+")))))";
53+
54+
Hypothesis H = new Hypothesis(kbForLearning.tell(sh));
4555

4656
// TODO
4757
// * H <- any hypothesis consistent with the first example in examples.
@@ -53,7 +63,7 @@ public Hypothesis currentBestLearning(List<FOLExample> examples) {
5363
// * if no consistent specialization/generalization can be found then
5464
// fail
5565
// * return H
56-
return null;
66+
return H;
5767
}
5868

5969
//

src/aima/learning/knowledge/FOLDataSetDomain.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package aima.learning.knowledge;
22

33
import java.util.ArrayList;
4+
import java.util.HashMap;
45
import java.util.List;
6+
import java.util.Map;
7+
import java.util.regex.Pattern;
58

69
import aima.learning.framework.DataSetSpecification;
710
import aima.logic.fol.domain.FOLDomain;
@@ -11,11 +14,16 @@
1114
*
1215
*/
1316
public class FOLDataSetDomain extends FOLDomain {
17+
//
18+
private static Pattern allowableCharactersRegEx = Pattern.compile("[^a-zA-Z_$0-9]");
19+
//
1420
private DataSetSpecification dataSetSpecification;
1521
private String trueGoalValue = null;
1622
// Default example prefix, see pg679 of AIMA
1723
private String examplePrefix = "X";
1824
private List<String> descriptionPredicateNames = new ArrayList<String>();
25+
private List<String> descriptionDataSetNames = new ArrayList<String>();
26+
private Map<String, String> dsToFOLNameMap = new HashMap<String, String>();
1927

2028
//
2129
// PUBLIC METHODS
@@ -26,10 +34,14 @@ public FOLDataSetDomain(DataSetSpecification dataSetSpecification, String trueGo
2634
constructFOLDomain();
2735
}
2836

29-
public String getGoalPredicateName() {
37+
public String getDataSetTargetName() {
3038
return dataSetSpecification.getTarget();
3139
}
3240

41+
public String getGoalPredicateName() {
42+
return getFOLName(dataSetSpecification.getTarget());
43+
}
44+
3345
public String getTrueGoalValue() {
3446
return trueGoalValue;
3547
}
@@ -38,8 +50,12 @@ public List<String> getDescriptionPredicateNames() {
3850
return descriptionPredicateNames;
3951
}
4052

41-
public boolean isMultivalued(String descriptivePredicateName) {
42-
List<String> possibleValues = dataSetSpecification.getPossibleAttributeValues(descriptivePredicateName);
53+
public List<String> getDescriptionDataSetNames() {
54+
return descriptionDataSetNames;
55+
}
56+
57+
public boolean isMultivalued(String descriptiveDataSetName) {
58+
List<String> possibleValues = dataSetSpecification.getPossibleAttributeValues(descriptiveDataSetName);
4359
// If more than two possible values
4460
// then is multivalued
4561
if (possibleValues.size() > 2) {
@@ -63,29 +79,45 @@ public String getExampleConstant(int egNo) {
6379
return egConstant;
6480
}
6581

82+
public String getFOLName(String dsName) {
83+
String folName = dsToFOLNameMap.get(dsName);
84+
if (null == folName) {
85+
folName = dsName;
86+
if (!Character.isJavaIdentifierStart(dsName.charAt(0))) {
87+
folName = "_"+dsName;
88+
}
89+
folName = allowableCharactersRegEx.matcher(folName).replaceAll("_");
90+
dsToFOLNameMap.put(dsName, folName);
91+
}
92+
93+
return folName;
94+
}
95+
6696
//
6797
// PRIVATE METHODS
6898
//
6999
private void constructFOLDomain() {
70100
// Ensure the target predicate is included
71-
addPredicate(dataSetSpecification.getTarget());
101+
addPredicate(getFOLName(dataSetSpecification.getTarget()));
72102
// Create the descriptive predicates
73103
for (String saName : dataSetSpecification.getNamesOfStringAttributes()) {
74104
if (dataSetSpecification.getTarget().equals(saName)) {
75105
// Don't add the target to the descriptive predicates
76106
continue;
77107
}
108+
String folSAName = getFOLName(saName);
78109
// Add a predicate for the attribute
79-
addPredicate(saName);
110+
addPredicate(folSAName);
80111

81-
descriptionPredicateNames.add(saName);
112+
descriptionPredicateNames.add(folSAName);
113+
descriptionDataSetNames.add(saName);
82114

83115
List<String> attributeValues = dataSetSpecification.getPossibleAttributeValues(saName);
84116
// If a multivalued attribute need to setup
85117
// Constants for the different possible values
86118
if (isMultivalued(saName)) {
87119
for (String av : attributeValues) {
88-
addConstant(av);
120+
addConstant(getFOLName(av));
89121
}
90122
}
91123
}

src/aima/learning/knowledge/FOLExample.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ private void constructFOLEg() {
6262
// Create the classification sentence
6363
classification = new Predicate(folDSDomain.getGoalPredicateName(), terms);
6464
if (!example.getAttributeValueAsString(
65-
folDSDomain.getGoalPredicateName()).equals(
65+
folDSDomain.getDataSetTargetName()).equals(
6666
folDSDomain.getTrueGoalValue())) {
6767
// if not true then needs to be a Not sentence
6868
classification = new NotSentence(classification);
6969
}
7070

7171
// Create the description sentence
7272
List<Sentence> descParts = new ArrayList<Sentence>();
73-
for (String dname : folDSDomain.getDescriptionPredicateNames()) {
73+
for (String dname : folDSDomain.getDescriptionDataSetNames()) {
74+
String foldDName = folDSDomain.getFOLName(dname);
7475
terms = new ArrayList<Term>();
7576
terms.add(ithExampleConstant);
7677
// If multivalued becomes a two place predicate
@@ -79,10 +80,10 @@ private void constructFOLEg() {
7980
// see pg 679 of AIMA
8081
Sentence part = null;
8182
if (folDSDomain.isMultivalued(dname)) {
82-
terms.add(new Constant(example.getAttributeValueAsString(dname)));
83-
part = new Predicate(dname, terms);
83+
terms.add(new Constant(folDSDomain.getFOLName(example.getAttributeValueAsString(dname))));
84+
part = new Predicate(foldDName, terms);
8485
} else {
85-
part = new Predicate(dname, terms);
86+
part = new Predicate(foldDName, terms);
8687
// Need to determine if false
8788
if (!folDSDomain.getTrueGoalValue().equals(example.getAttributeValueAsString(dname))) {
8889
part = new NotSentence(part);
Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
package aima.learning.knowledge;
22

3+
import aima.logic.fol.parsing.ast.Sentence;
4+
35
/**
46
* @author Ciaran O'Reilly
57
*
68
*/
79
public class Hypothesis {
8-
10+
private Sentence hypothesis = null;
11+
12+
public Hypothesis(Sentence hypothesis) {
13+
this.hypothesis = hypothesis;
14+
}
15+
16+
/**
17+
* <pre>
18+
* FORALL v (Classification(v) <=> ((Description1(v) AND Description2(v, Constant1))
19+
* OR
20+
* (Description1(v) AND Description3(v))
21+
* )
22+
* )
23+
* </pre>
24+
*/
25+
public Sentence getHypothesis() {
26+
return hypothesis;
27+
}
928
}

src/aima/learning/learners/CurrentBestLearner.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,19 @@
1010
import aima.learning.knowledge.FOLDataSetDomain;
1111
import aima.learning.knowledge.FOLExample;
1212
import aima.learning.knowledge.Hypothesis;
13+
import aima.logic.fol.inference.FOLModelElimination;
14+
import aima.logic.fol.inference.InferenceResult;
15+
import aima.logic.fol.kb.FOLKnowledgeBase;
1316

1417
/**
1518
* @author Ciaran O'Reilly
1619
*
1720
*/
1821
public class CurrentBestLearner implements Learner {
1922
private String trueGoalValue = null;
23+
private FOLDataSetDomain folDSDomain = null;
24+
private FOLKnowledgeBase kb = null;
25+
private Hypothesis currentBestHypothesis = null;
2026

2127
//
2228
// PUBLIC METHODS
@@ -28,25 +34,43 @@ public CurrentBestLearner(String trueGoalValue) {
2834
//
2935
// START-Learner
3036
public void train(DataSet ds) {
31-
FOLDataSetDomain folDSDomain = new FOLDataSetDomain(ds.specification,
32-
trueGoalValue);
37+
folDSDomain = new FOLDataSetDomain(ds.specification, trueGoalValue);
3338
List<FOLExample> folExamples = new ArrayList<FOLExample>();
3439
int egNo = 1;
3540
for (Example e : ds.examples) {
3641
folExamples.add(new FOLExample(folDSDomain, e, egNo));
3742
egNo++;
3843
}
3944

40-
CurrentBestLearning cbl = new CurrentBestLearning(folDSDomain);
45+
// Setup a KB to be used for learning
46+
kb = new FOLKnowledgeBase(folDSDomain, new FOLModelElimination(1000));
4147

42-
Hypothesis h = cbl.currentBestLearning(folExamples);
48+
CurrentBestLearning cbl = new CurrentBestLearning(folDSDomain, kb);
4349

44-
// TODO
50+
currentBestHypothesis = cbl.currentBestLearning(folExamples);
4551
}
4652

4753
public String predict(Example e) {
48-
// TODO
49-
return null;
54+
String prediction = "~" + e.targetValue();
55+
if (null != currentBestHypothesis) {
56+
FOLExample etp = new FOLExample(folDSDomain, e, 0);
57+
kb.clear();
58+
kb.tell(etp.getDescription());
59+
kb.tell(currentBestHypothesis.getHypothesis());
60+
61+
InferenceResult ir = kb.ask(etp.getClassification());
62+
if (ir.isTrue()) {
63+
prediction = e.targetValue();
64+
} else if (ir.isUnknownDueToTimeout()) {
65+
// If unknown due to timeout then assume
66+
// is true by default, as can't prove
67+
// either way based on known hypothesis,
68+
// facts and available time.
69+
prediction = e.targetValue();
70+
}
71+
}
72+
73+
return prediction;
5074
}
5175

5276
public int[] test(DataSet ds) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package aima.logic.fol.inference;
2+
3+
import aima.logic.fol.inference.proof.Proof;
4+
import aima.logic.fol.inference.proof.ProofPrinter;
5+
6+
/**
7+
* @author Ciaran O'Reilly
8+
*
9+
*/
10+
public class InferenceResultPrinter {
11+
/**
12+
* Utility method for outputting InferenceResults in a formatted textual
13+
* representation.
14+
*
15+
* @param an
16+
* InferenceResult
17+
* @return a String representation of the InferenceResult.
18+
*/
19+
public static String printInferenceResult(InferenceResult ir) {
20+
StringBuilder sb = new StringBuilder();
21+
22+
sb.append("InferenceResult.isTrue=" + ir.isTrue());
23+
sb.append("InferenceResult.isPossiblyFalse=" + ir.isPossiblyFalse());
24+
sb.append("InferenceResult.isUnknownDueToTimeout="
25+
+ ir.isUnknownDueToTimeout());
26+
sb.append("InferenceResult.isPartialResultDueToTimeout="
27+
+ ir.isPartialResultDueToTimeout());
28+
sb.append("InferenceResult.#Proofs=" + ir.getProofs().size());
29+
int proofNo = 0;
30+
for (Proof p : ir.getProofs()) {
31+
proofNo++;
32+
sb.append("InferenceResult.Proof#"+proofNo+"=\n" + ProofPrinter.printProof(p));
33+
}
34+
35+
return sb.toString();
36+
}
37+
}

src/aima/logic/fol/inference/otter/defaultimpl/DefaultLightestClauseHeuristic.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public Clause getLightestClause() {
3535
}
3636

3737
public void initialSOS(Set<Clause> clauses) {
38+
sos.clear();
3839
sos.addAll(clauses);
3940
Collections.sort(sos, lightestClauseSorter);
4041
}

src/aima/logic/fol/kb/FOLKnowledgeBase.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ public FOLKnowledgeBase(FOLDomain domain,
9696
substVisitor);
9797
this.cnfConverter = new CNFConverter(parser);
9898
}
99+
100+
public void clear() {
101+
this.originalSentences.clear();
102+
this.clauses.clear();
103+
this.allDefiniteClauses.clear();
104+
this.implicationDefiniteClauses.clear();
105+
this.indexFacts.clear();
106+
}
99107

100108
public InferenceProcedure getInferenceProcedure() {
101109
return inferenceProcedure;
@@ -107,8 +115,10 @@ public void setInferenceProcedure(InferenceProcedure inferenceProcedure) {
107115
}
108116
}
109117

110-
public void tell(String aSentence) {
111-
tell(parser.parse(aSentence));
118+
public Sentence tell(String aSentence) {
119+
Sentence s = parser.parse(aSentence);
120+
tell(s);
121+
return s;
112122
}
113123

114124
public void tell(List<? extends Sentence> sentences) {

src/aima/test/learningtest/LearnerTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,9 @@ public void testCurrentBestLearnerOnRestaurantDataSet() throws Exception {
131131
DataSet ds = DataSetFactory.getRestaurantDataSet();
132132
CurrentBestLearner learner = new CurrentBestLearner("Yes");
133133
learner.train(ds);
134-
// TODO
135-
//int[] result = learner.test(ds);
136-
//assertEquals(12, result[0]);
137-
//assertEquals(0, result[1]);
134+
135+
int[] result = learner.test(ds);
136+
assertEquals(12, result[0]);
137+
assertEquals(0, result[1]);
138138
}
139139
}

0 commit comments

Comments
 (0)