-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trace Reconstruction #2
Changes from 80 commits
ab9c4b6
11938f0
005b519
efbef7c
11e73be
f3be6d8
f4efe32
7afbec6
ebbfd64
2986a42
a453727
189b11d
64843d4
13feca4
de7f272
2f27b15
c01aa06
f026007
2ea9437
d560d23
bf14157
925c59d
329465c
17834a0
ef7b2d9
be6a50b
6978483
908a9a8
8ad939a
a2443b1
0acdf0a
187b552
77ef808
024ba64
78ad347
ac4adb3
cb98432
995cfd3
d66cc9f
0960332
d3d7f40
2e73b75
58a3a05
01b6535
b930eec
b551486
a625ecb
48e52ce
b8c27fb
5743440
68fd13b
1aae322
1ee3c05
4d71937
b405617
8db3222
1efab9d
bea05c8
4e3790b
72591ea
4fab32f
f9ded11
6225f62
8b10a44
1de85ce
8ae39b6
39eb100
255a7f7
894bec8
0d812c3
f757995
425ec6d
124de22
f5d733e
6f16433
669ce54
7fbdb36
86a1be7
e892cc1
52b96fb
b5e93fc
822249f
28ab87e
43a92a7
2705f6b
eac52a9
323233e
19359d4
0a10520
7a7f372
47d0914
adfc803
8d61cc6
4ac2338
e9ac6c5
b3b635b
04b3a71
7dd1cb0
8b3d786
ae4da38
55c5b56
abc81b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
# Compiled C# code | ||
*.dll | ||
# Test outputs | ||
*.trace | ||
*.thm | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
## Project Overview | ||
|
||
The Veri-Datalog project is a verified Datalog+ engine. It proves the correctness of Datalog+ programs by constructing proof trees from their trace output. Datalog+ is a research defined language that is similar to Datalog but with more feature support; both are subsets of Prolog. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: wrap paragraphs to some reasonable width, 100 or 120 characters perhaps? |
||
|
||
## Contributions by Rory Brennan-Jones | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps remove this heading? We know it was your work, but I don't think the README needs to say that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
||
### Test Suite | ||
|
||
In the lcf directory, running `make test` will verify the go predicate of every Datalog+ file in the tests directory. The results are saved as .thm files with names matching the original code files. Using the Python script in the tools directory, it is possible to randomly generate example Datalog+ programs involving edge connectivity problems. | ||
|
||
### Trace Reconstruction | ||
|
||
The trace output of a Prolog program shows an exploration of many possible paths before settling on one that allows the query to be true | ||
or resolves some unification. The new trace reconstruction algorithm attempts to discard all the failed paths and look at just the successful path, which greatly simplifies the process of constructing a proof tree for that query. The algorithm does this by only looking at trace events that use the exit port, since these events result from successes and contain full variable assignments. However, failed paths can have zero or more temporary successes, potentially leading to the presence of "junk" events with exit ports in the trace output. | ||
|
||
Since exit ports always follow successes, the first exit ports in the trace happen after finding succesful base cases (builtin operations, facts, etc.), and later exit ports show the successes of predicates that depended on other rules and facts. As a result, the algorithm reads from the trace backwards in order to go from the root to the leaves instead of vice versa. The algorithm uses a mix of recursion and iteration, where the recursion helps the algorithm move "up" and "down" the tree, and the iteration helps algorithm move between siblings in the tree and skip junk events. A trace event with a prop such as a fact, equality, or builtin becomes a leaf in the proof tree, whereas other trace events become regular theorems that have proofs using other theorems and leaves from lower down in the tree as arguments. | ||
|
||
### Types and Builtins | ||
|
||
Unlike Datalog, Datalog+ supports constants other than atoms, including numbers, strings, and lists. These types are not complete yet. It has not been decided yet if the numbers should be natural numbers or integers (or if both should be supported). Furthermore, strings do not support all characters that could be found in a legal Datalog+ string, including escaped characters such as double quotes. Also, lists currently only support constant terms and cannot use the pipe operator. In addition to these types, there is also support for certain builtin operations, such as equality operators and string and list builtins. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ trace | |
; | ||
|
||
traceevent | ||
: port level=integer id=integer goal=clause ';' | ||
: port level=integer id=integer goal=clause';' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: keep the space after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
; | ||
|
||
port | ||
|
@@ -37,26 +37,63 @@ rule | |
; | ||
|
||
clause | ||
: name=Identifier '(' term_list ')' | ||
: builtin | ||
| app | ||
| expression | ||
; | ||
|
||
builtin | ||
: name=Builtin '(' term_list ')' | ||
; | ||
|
||
app | ||
: name=Identifier ( '(' term_list ')' )? | ||
; | ||
|
||
expression | ||
: left=term name=Operator right=term | ||
; | ||
|
||
term | ||
: atom | ||
: constant | ||
| variable | ||
; | ||
|
||
constant | ||
: atom | ||
| natural | ||
| string | ||
| list | ||
; | ||
|
||
clause_list | ||
: clause ( ',' clause)* | ||
; | ||
|
||
term_list | ||
: term( ',' term)* | ||
: term ( ',' term)* | ||
; | ||
|
||
atom | ||
: val=Identifier | ||
; | ||
|
||
natural | ||
: numeral=Int // TODO: make natural use the Nat rule, or switch support from natural numbers to integers | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason we can't do this TODO now? It's odd to have a rule called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I mentioned in person, this may have to stay unresolved for now. To summarize, the kernel only supports natural numbers right now, but the Nat lexer rule in the parser doesn't seem to work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed that the naming issue is worth resolving now, if we can. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have resolved the naming issue. The Int lexer rule has been commented out, and the rest of the Antlr uses the Nat rule. |
||
; | ||
|
||
string | ||
: s=Str | ||
; | ||
|
||
list | ||
: '[' constant_list ']' | ||
; | ||
|
||
constant_list | ||
: constant ( ',' constant)* | ||
; | ||
|
||
variable | ||
: name=VarName | ||
; | ||
|
@@ -65,6 +102,15 @@ variable | |
* Lexer Rules | ||
*/ | ||
|
||
fragment CHARACTER | ||
: ALPHANUMERIC // TODO: expand to all characters that are permitted by Prolog strings | ||
| '.' | ',' | ';' | '!' | '?' | ' ' | ||
| '\t' | '\\t' | ||
| '\n' | '\\n' | ||
| '\r' | '\\r' | ||
| '"' | '\\"' | ||
| '\\' | ||
; | ||
fragment ALPHANUMERIC: ALPHA | DIGIT ; | ||
fragment ALPHA: '_' | SMALL_LETTER | CAPITAL_LETTER ; | ||
fragment LEADER: '_' | CAPITAL_LETTER; | ||
|
@@ -76,10 +122,25 @@ Port | |
: 'call' | 'redo' | 'unify' | 'exit' | 'fail' | ||
; | ||
|
||
Builtin | ||
: 'split_string' | ||
| 'sub_string' | ||
| 'string_lower' | ||
| 'string_chars' | ||
| 'length' | ||
| 'lists:member' | 'member' | ||
| 'lists:reverse' | 'reverse' | ||
| 'lists:nth1' | 'nth1' | ||
Comment on lines
+131
to
+133
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do both forms appear? That is, do you see both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the trace, I see "lists:member", but in the .pl file, I see "member". |
||
; | ||
|
||
Identifier | ||
: SMALL_LETTER (Nondigit | Digit)* | ||
; | ||
|
||
Operator | ||
: '=' | '=<' | '>=' | '\\=' | '=\\=' | '<' | '>' | '==' | ||
; | ||
|
||
VarName | ||
: LEADER (Nondigit | Digit)* | ||
; | ||
|
@@ -88,8 +149,16 @@ Int | |
: ('-')? Digit+ | ||
; | ||
|
||
Nat | ||
: Digit+ | ||
; | ||
|
||
Str | ||
: '"' CHARACTER* '"' | ||
; | ||
|
||
fragment Nondigit | ||
: [a-zA-Z] | ||
: [a-zA-Z] | '_' | ||
; | ||
|
||
fragment Digit | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,16 +70,88 @@ private static int RuleID(ParserRuleContext context) { | |
return context.Start.Line; | ||
} | ||
|
||
public override object VisitClause(datalogParser.ClauseContext context) { | ||
var name = Sequence<char>.FromString(context.name.Text); | ||
public override object VisitBuiltin(datalogParser.BuiltinContext context) { | ||
var terms = (Dafny.ISequence<_ITerm>) VisitTerm_list(context.term_list()); | ||
return new _module.Prop_App(name, terms); | ||
switch (context.name.Text) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All of these cases have the same form:
Can we refactor this to use function that returns the builtin type from the builtin name?
Then each case doesn't need to have the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
case "split_string": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_SplitString(), terms); | ||
case "sub_string": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_SubString(), terms); | ||
case "string_lower": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_StringLower(), terms); | ||
case "string_chars": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_StringChars(), terms); | ||
case "length": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_Length(), terms); | ||
case "lists:member": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_Member(), terms); | ||
case "member": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_Member(), terms); | ||
case "lists:reverse": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_Reverse(), terms); | ||
case "reverse": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_Reverse(), terms); | ||
case "lists:nth1": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_Nth1(), terms); | ||
case "nth1": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_Nth1(), terms); | ||
default: | ||
return null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be best to have this throw an exception instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
} | ||
} | ||
|
||
public override object VisitExpression(datalogParser.ExpressionContext context) { | ||
var left = (_module.Term)VisitTerm(context.left); | ||
var right = (_module.Term)VisitTerm(context.right); | ||
var terms = new List<_module.Term> { left, right }; | ||
var terms2 = (Dafny.ISequence<_ITerm>) Sequence<_module.Term>.Create(terms.Count, i => terms[(int) i]); | ||
switch(context.name.Text) { | ||
case "=<": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_NatLeq(), terms2); | ||
case ">=": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_NatGeq(), terms2); | ||
case "\\=": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_NatNeq(), terms2); | ||
case "=\\=": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_NatNeq(), terms2); | ||
case "<": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_NatLt(), terms2); | ||
case ">": | ||
return new _module.Prop_BuiltinOp(new _module.Builtin_NatGt(), terms2); | ||
default: | ||
return new _module.Prop_Eq(left, right); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better to have an explicit case for equals. The default case should error out. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
} | ||
} | ||
|
||
public override object VisitApp(datalogParser.AppContext context) { | ||
var name = Sequence<char>.FromString(context.name.Text); | ||
if (context.term_list() == null ) { | ||
var terms = new List<_module.Term>(); | ||
var terms2 = Sequence<_module.Term>.Create(terms.Count, i => terms[(int) i]); | ||
return new _module.Prop_App(name, (Dafny.ISequence<_ITerm>) terms2); | ||
} else { | ||
var terms = (Dafny.ISequence<_ITerm>) VisitTerm_list(context.term_list()); | ||
return new _module.Prop_App(name, terms); | ||
} | ||
} | ||
|
||
public override object VisitAtom(datalogParser.AtomContext context) { | ||
return new Term_Const(new Const_Atom(Sequence<char>.FromString(context.val.Text))); | ||
} | ||
|
||
public override object VisitNatural(datalogParser.NaturalContext context) { | ||
return new Term_Const(new Const_Nat(BigInteger.Parse(context.numeral.Text))); | ||
} | ||
|
||
public override object VisitString(datalogParser.StringContext context) { | ||
return new Term_Const(new Const_Str(Sequence<char>.FromString(context.s.Text.Substring(1, context.s.Text.Length - 2)))); | ||
// A substring of the text is taken in order to remove the double quotes. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you say you had supported escaping now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I fixed it to replace escaped characters with the actual characters. However, I discovered that adding support for escaped double quotes broke the parser, so I had to stop supporting them for now (although other escaped characters are now fully supported). |
||
} | ||
|
||
public override object VisitList(datalogParser.ListContext context) { | ||
return new Term_Const(new Const_List( (Dafny.ISequence<_IConst>) VisitConstant_list(context.constant_list()) )); | ||
} | ||
|
||
public override object VisitVariable(datalogParser.VariableContext context) { | ||
return new Term_Var(Sequence<char>.FromString(context.name.Text)); | ||
} | ||
|
@@ -101,6 +173,15 @@ public override object VisitTerm_list(datalogParser.Term_listContext context) { | |
} | ||
return Sequence<_module.Term>.Create(terms.Count, i => terms[(int) i]); | ||
} | ||
|
||
public override object VisitConstant_list(datalogParser.Constant_listContext context) { | ||
var consts = new List<_module.Const>(); | ||
foreach (var constant in context.constant()) { | ||
var dafny_const = (_module.Const) ((_module.Term_Const) VisitConstant(constant))._val; | ||
consts.Add(dafny_const); | ||
} | ||
return Sequence<_module.Const>.Create(consts.Count, i => consts[(int) i]); | ||
} | ||
} | ||
|
||
public partial class __default | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please could we fix the missing newlines at the end of files? I think there's a few examples of it in this PR.
I think there's a vscode setting for this: https://stackoverflow.com/a/44704969
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed