-
Notifications
You must be signed in to change notification settings - Fork 196
[experimental] PInfer: learning specifications from event traces #862
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
Merged
Merged
Changes from 198 commits
Commits
Show all changes
199 commits
Select commit
Hold shift + click to select a range
aca014c
[init] PInfer backend
AD1024 7d51b72
save
AD1024 72dbbe2
[add] predicate enumeration
AD1024 729819f
[save] compilation to java src
AD1024 910c5df
[save] generating terms and predicates
AD1024 c74b1ec
[fix] predicates and term enumeration
AD1024 0f30ec3
[save] structural equality for AST nodes
AD1024 e6485b1
[add] serialize to string for types
AD1024 8a410ce
[save] Java codegen
AD1024 ef5daef
[refactor] predicate and function store
AD1024 45b8d3c
[refactor] tweak Java codegen backend to support PInfer codegen
AD1024 f9f562d
[wip] verification template generation
AD1024 079c157
[fix] unwrap alias
AD1024 ab0eeb7
[save] enum type conversion
AD1024 eff95b9
[save] finish trace parser codegen
AD1024 222d15a
[fix] event payload get for json objects
AD1024 fe5f162
[save] forall-only template wip
AD1024 6b03109
[add] forall template; term orders
AD1024 f42ec80
[save] populating contraditions for atomic predicates
AD1024 d0a0541
[add] include types
AD1024 0c5e4f4
[save] predicate check enumeratior
AD1024 966bfd7
[save] remove project-dependent code
AD1024 daa400a
[save] more automation on workflow
AD1024 bb44b64
[add] more java codegen
AD1024 1933d5f
[save] container types
AD1024 cb7c278
[save] more tweaks of templates
AD1024 2708d2b
[fix] more tweaks on infer infra
AD1024 706f6c2
[save] more fixes
AD1024 3f616b2
[save] isolate templates
AD1024 89b709c
[tweak] automatically generating enum comparisons
AD1024 1628f24
[save] generate boolean eq cmp
AD1024 23bac7e
[major refactor] switch to P Java runtime
AD1024 1c9a69d
[save] more fixes
AD1024 1488041
[tweak] use array sequences
AD1024 af958f1
[add] exist-only templates
AD1024 af2e469
[save] forall-exists
AD1024 c716d7a
[add] PInfer trace dump options for PChecker
AD1024 9106bb9
[save] better multi-processing
AD1024 1dc86e5
fix typo in path
AD1024 31026e4
[add] dependencies
AD1024 6dfb570
[save] changes
AD1024 6bf9e1e
[save] fix codegen for custom functions with sequence types
AD1024 95548cd
[major refactor] forall/exists template
AD1024 b30ca8d
[fix] forgot to call it!
AD1024 4fb5f15
[save] fix daikon output converter
AD1024 68ebb3c
[save] subst
AD1024 807c53f
[add] subst for headers
AD1024 3e2d8fe
[fix] check event name instead of event variable name
AD1024 8769923
[fix] daikon output header builder
AD1024 498b83b
[add] compliation phase
AD1024 908f539
[save] small fixes
AD1024 8f6aae6
[fix] template generation for events with the same names
AD1024 f021e4d
[add] todos
AD1024 d961176
[save] gt predicate
AD1024 bb9159f
[fix] template generator
AD1024 d8562b3
[fix] task pool monitors numFinished instead of ptr
AD1024 3ad68a3
[save] some tweaks
AD1024 cd30ac5
[fix] template names
AD1024 a16e661
Merge branch 'master' of github.com:AD1024/P
AD1024 513657f
Merge branch 'master' of github.com:AD1024/P
AD1024 5ac485b
some tweaks
AD1024 ca5d9bf
save
AD1024 8a56a05
[save] FromDaikon
AD1024 e55b17b
[add] cli
AD1024 cf132b9
[add] data type annotations
AD1024 dc357b1
save
AD1024 6733af0
[add] post-infer clean ups
AD1024 7976284
[save] some ui tweaks
AD1024 02fa1d3
[add] post-hoc pruning
AD1024 830dc10
[fix] upper case arg
AD1024 646d4f7
[try tweak] use static function instead of constructor
AD1024 57743e3
fix
AD1024 ceb4d37
[tweak] output to a text file
AD1024 ad3cab9
fix bug
AD1024 2091215
[add] interactive mode
AD1024 2aad986
tweaks!!
AD1024 96cef4d
[tweak] order
AD1024 992dbaf
[save] snapshot for hyperparameter search
AD1024 4c51135
[save] hints!!
AD1024 58ad832
[impl] run hints
AD1024 62fcc07
[tweak] hint search space exploration
AD1024 f8fffba
[save] begin `auto`
AD1024 099e5a5
[add] hint/hint exact
AD1024 88a921c
[save] search start!
AD1024 a88bf29
[save] some fixes
AD1024 f01c59d
[add] trace indexer; tweak PChecker infer mode
AD1024 d7ad637
fix bugs
AD1024 58b8f7c
[save] `indexof` metafunction
AD1024 f96dd1a
[init] CC-based pruning
AD1024 124b979
[save] contradictions
AD1024 bcd9b2a
[add] more pruning utilities
AD1024 d2883a9
[save] type-based pruning
AD1024 9c3b8e6
[save] refine pruning
AD1024 a1845cf
save
AD1024 66ab74b
[tweak] logic-based pruning
AD1024 0cb8cd6
save
AD1024 b12f0e1
save
AD1024 5861236
tweak
AD1024 6a9a76f
[near finalized] pruning
AD1024 791befd
[save] finish pruning. may have little bugs tho
AD1024 0939fa3
Merge pull request #1 from AD1024/pinfer-pruning
AD1024 143973e
save
AD1024 6105534
tweak utilities
AD1024 749d333
[add] lt generation for numeric types
AD1024 65c800f
[tweak] look at events sent in entry function alone
AD1024 e17c49f
[remove] logger
AD1024 5d2c327
[add] also run user-defind hints in auto mode
AD1024 367b989
[fix] bug of grid search
AD1024 e72b006
[fix] wrong arity
AD1024 e27442e
fix again
AD1024 0c5d613
yet another fix
AD1024 79febb7
[add] unary ops
AD1024 5989456
[add] AST comparer for SizeOfExpr
AD1024 6ebd51b
more fixes
AD1024 383bf56
[mark save] better support for custom predicates
AD1024 b800f45
[tweak] add contains expr support
AD1024 04a30fc
[save] add eq for same field types
AD1024 fe439b7
[save] several fixes to better support custom hints
AD1024 25501ef
[save] fix for nested arrays
AD1024 fdfdcb6
[add] trace indexing
AD1024 cef3fd2
[save] guide
AD1024 99a6bb8
save one more line
AD1024 c875adf
[save] add traces commandline args to docus
AD1024 7310c9d
fix typo
AD1024 7ffa0f1
[fix] checker extension
AD1024 0c2842b
tweaks
AD1024 5206a47
save
AD1024 da19922
[rollback] forall-exists pruning
AD1024 ddc2c4a
[add] chunk size limit
AD1024 f8af2a0
[add] transform back to P code
AD1024 06ed859
save
AD1024 8a78850
Merge branch 'master' of github.com:AD1024/P
AD1024 f0af7f7
[save] to P monitor
AD1024 0adde69
[fix] monitor generation for forall-only templates
AD1024 3dfe9d3
[save] fix bugs in monitor generation
AD1024 db8913e
save
AD1024 3c7a039
[fix] resolution using negations
AD1024 166dbe7
[save] do not generate new folders
AD1024 6755d30
[tweak] explorer
AD1024 6c9faa2
[save] checkpoint
AD1024 a6c8929
[save] tweak pruning
AD1024 82f7070
[fix] template gen: existentials should be falsified by us!
AD1024 75ee8a4
[save] parse for boolean constant comp
AD1024 5751315
[tweak] avoid generating predicates that may lead to symmetric invari…
AD1024 e8e5f28
[save] write stats
AD1024 01f935f
save
AD1024 4aa968c
[add] benchmark models
AD1024 3d2ac20
[add] trace parsing mode and smt solver integration
AD1024 108af36
save
AD1024 41fb8e3
[save] pruning mode
AD1024 17dc57f
add z3 checker switch
AD1024 52d6df5
optimize pruning
AD1024 fa81685
save
AD1024 97f7d96
[save] aggregating results
AD1024 0859e19
[add] pinfer tutorial
AD1024 a0ea2a5
add ring leader
AD1024 87e75d9
[save] benchmark results
AD1024 f35f69c
add pruned invs for clocks
AD1024 b0323d1
[save] readme
AD1024 128c20f
fix some issues with custom functions
AD1024 30d3e65
[tweak] trace generator
AD1024 661003b
remove files
AD1024 7bac4ca
save
AD1024 921f8d0
[save] more pruning
AD1024 f900017
[update] 2PC example
AD1024 e098e0e
save prepare traces
AD1024 d8310ac
save constants
AD1024 e790804
[update] invariants
AD1024 73989f8
save raft invariants
AD1024 3b19356
save clockbound invariants
AD1024 6189028
save all
AD1024 f3b8af5
save chain replication
AD1024 cca23eb
remove slurm job
AD1024 d89e402
subsumption: checks contra-positives
AD1024 bddca25
[add] statistics of number of activated guards
AD1024 c913914
save
AD1024 55308da
save
AD1024 774e10e
save
AD1024 6dd0244
save
AD1024 e2f494e
save new benchmarks and readme
AD1024 b666058
update
AD1024 b9f3b2e
hotfix
AD1024 d3eddd8
hotfix
AD1024 6d9f2cd
save
AD1024 969c0a4
fix
AD1024 ff653e0
save
AD1024 e2bbc35
sace
AD1024 955aa0e
save hotfix
AD1024 7e6c333
save hotfix
AD1024 794aea9
save
AD1024 83bbce9
save
AD1024 df01f5d
save
AD1024 6acf92d
save
AD1024 1a8b2a6
save invariant files
AD1024 8d2af94
remove duplicated benchmark code
AD1024 06bb44b
save merge
AD1024 7aca38b
remove tutorials
AD1024 9d4abab
restore tutorial from upstream
AD1024 46f2de4
remove dependency on Src
AD1024 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
# PInfer - Automatic Invariant Learning from Traces | ||
## Prerequisites | ||
> Note that PInfer has only been tested on Amazon Linux. | ||
|
||
### Installing Z3 (before building P) | ||
1. Clone the Z3 repository: https://github.com/Z3Prover/z3 by `git clone git@github.com:Z3Prover/z3.git` | ||
2. Run `python scripts/mk_make.py -x --dotnet` | ||
3. `cd build; make -j$(nproc)` | ||
4. `sudo make install` | ||
5. Add `export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/path-to-z3/build/"` to `.bashrc` (or `.zshrc` if using Zsh) where `path-to-z3` is the directory of the cloned Z3 repository in step 1. | ||
|
||
#### Environment setups | ||
- Follow the instruction of [P language here](https://p-org.github.io/P/getstarted/install/) and install dotnet. The version used for developing is 8.0.401. | ||
- Install Java 22 and maven | ||
+ For amazon linux, [follow the guide here](https://docs.aws.amazon.com/corretto/latest/corretto-22-ug/generic-linux-install.html#rpm-linux-install-instruct) | ||
+ Maven version: Apache Maven 3.5.2. Can be installed via `sudo yum install maven` | ||
- Install PJavaRuntime: go to [Src/Runtimes/PJavaRuntimes](./Src/PRuntimes/PJavaRuntime/) and run `mvn install` | ||
- Compile P: run `dotnet build -c Release` under the root of this repo. | ||
|
||
## Step 1: Getting traces | ||
### Using the python script for generating traces | ||
There is a `1_prepare_traces.py` under `Tutoiral/PInfer`. To use this script to generate traces, first add an entry to `configurations` dictionary in `Tutoiral/PInfer/constants.py`. | ||
The key should be the name of the folder under `Tutorial/PInfer` that contains the P source code of the benchmark, and the value is a list of names of test cases to run to obtain the traces. | ||
|
||
You may optionally set an environment variable called `PINFER_TRACE_DIR` (e.g. `export PINFER_TRACE_DIR=/home/PInferTraces) that specifies the path to store the generated traces. | ||
|
||
After making the changes, run with | ||
``` | ||
> python3 1_prepare_traces.py --benchmarks [names of benchmarks] --num_traces [a list of numbers representing number of traces to generate] [--trace_dir <path-to-store-traces>] | ||
``` | ||
|
||
For instance, to generate 10k traces for Paxos storing into `$PINFER_TRACE_DIR`, run the following | ||
> `python3 1_prepare_traces.py --benchmarks paxos --num_traces 10000` | ||
|
||
### Event filters | ||
By default, the generated traces have all Send and Announce events being recorded. | ||
For some benchmarks, we may want to only record events that are relevant to the protocol. | ||
To do so, add an entry in `event_combs` dictionary in `constants.py`, where the key is the name of directory of the benchmark and the value is in the form of `[(e1, e2, e3...)]` where `e1, e2, e3...` are events that are relevant to the protocol. | ||
|
||
**Removing traces:** If you want to remove certain traces, simply delete the files. You don't need to remove the metadata in the JSON file. | ||
|
||
**How are trace metadata being used?** When checking `n` events of type e1, e2, ..., en, PInfer will first look for any *exact* match on the index, i.e. a folder that have traces that contains events that are *exactly* of type e1, ..., en. If no such folder is found, PInfer looks for any folder that holds traces that is a superset of (e1, ..., en). | ||
|
||
> Alternatively, some of the codebase have `generateTrace.sh`. You can simply run `./generateTrace.sh <num schedules> <e1> <e2> ... <en>` and it will gather traces containing e1, e2,...,en using all test cases. | ||
|
||
## Step 2: Running PInfer | ||
For our benchmarks, simply execute `run.sh` under the benchmark folders. | ||
|
||
To setup your own experiments: | ||
### Fully-automated mode | ||
Simply run `p infer`, it will infer combinations of events that might yield interesting properties and then perform the search over the lattice. | ||
|
||
If traces are stored under some other paths, you can run it with `p infer -t <path-to-traces>`. Note that there must be a `metadata.json` under the provided path. | ||
|
||
If traces were generated using `1_prepare_traces.py`, then under `PINFER_TRACE_DIR`, traces are stored in folders that have the same name as the benchmark. For example `PINFER_TRACE_DIR/paxos/10000` stores 10k traces for paxos. This is the path you will need to pass to PInfer using `-t` commandline argument. For example, running PInfer under `paxos` with 10k traces is | ||
|
||
``` | ||
> p infer -t $PINFER_TRACE_DIR/paxos/10000 | ||
``` | ||
|
||
To enable SMT-based pruning, add a `-z3` flag, e.g., | ||
``` | ||
> p infer -t $PINFER_TRACE_DIR/paxos/10000 -z3 | ||
``` | ||
|
||
Default parameters (upper bounds): | ||
- `term_depth`: 2 | ||
- `num_guards`: 2 | ||
- `num_filters`: 2 | ||
- `exists`: 1 | ||
- `config_event`: null | ||
|
||
`arity` is determined by the maximum arity of prediates generated. | ||
|
||
These can be configured using command line argumets: | ||
> p infer -td <`max term depth`> -max-guards <`max conj in guards`> -max-filters <`max conj. in filters`> -ce <`event name`> | ||
|
||
### Hints | ||
Hints is a construct in P program that provides manual hints for PInfer. | ||
|
||
Hints can be defined as follows: | ||
``` | ||
hint <hint name> (e1: Event1 ... en: EventN) { | ||
term_depth = <int>; | ||
exists = <int>; | ||
num_guards = <int>; | ||
num_filters = <int>; | ||
arity = <int>; | ||
config_event = <event name>; | ||
include_guards = <bool expr>; // predicates that must be included in the guards, e.g. e0.key == e1.key; conjuntion only. | ||
include_filters = <bool expr>; // similar, but must be included in filters | ||
} | ||
``` | ||
|
||
If any of the field is not provided, the default values are: | ||
- `exists` = 0 | ||
- `num_guards` = 0 | ||
- `num_filters` = 0 | ||
- `arity` = 1 | ||
- `config_event` = null | ||
- `include_guards` = true | ||
- `include_filters` = true | ||
|
||
#### Generating SpecMiner for a hint | ||
> p infer --action compile --hint <`name of the hint`> | ||
|
||
PInfer will generate the SpecMiner specifically for the provided hint. | ||
|
||
#### Searching the space defined by a hint | ||
> p infer --action run --hint <`name of hint`> \[--traces <`folder`>\] | ||
|
||
PInfer will search the formula in the form of `forall* G -> exists* F /\ R` that holds for all traces. PInfer starts with the provided parameters in the hint and search till the upperbound. | ||
By default PInfer looks for traces under `traces` folder. Notice that the traces must be indexed, i.e. having a `metadata.json` mapping sets of events to folders containing corresponding traces. | ||
|
||
#### Searching a specific grid | ||
**exact hints:** Mainly used for debugging purposes. When declaring a hint with `exact` keyword, i.e. `hint exact ...` then running it, PInfer will only check the search space defined by the given parameters in the hint but will not go up the grid. | ||
|
||
#### List out predicates generated | ||
> p infer -lp | ||
#### List out terms generated | ||
> p infer -lt | ||
|
||
## Step 3: Outputs | ||
After PInfer finishes, invariants will be stored in `invariants.txt` in the folder PInfer was executed. Another file `inv_running.txt` will be updated as PInfer finds new invariants. Mined properties are pretty-printted. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
import java.util.stream.Collectors; | ||
|
||
public class FromDaikon { | ||
public int numExists; | ||
private Map<Set<Integer>, List<Main.RawPredicate>> termsToPredicates; | ||
private List<Main.RawTerm> terms; | ||
private String templateHeaderCar; | ||
private String templateHeaderCdr; | ||
private int pruningLevel; | ||
private static final String[] QUANTIFIERS = { %QUANTIFIERS% }; | ||
private static final String[] VARNAME = { %QUANTIFIED_VARS% }; | ||
private static final String[] FILTERED_INVS = { "!= null", ".getClass().getName()", "[] ==" }; | ||
private static final String[] COMP_OPS = { "!=", "<=", "<", ">=", ">" }; | ||
private static final Map<String, String> substs = new HashMap<>(); | ||
|
||
public FromDaikon(Map<Set<Integer>, List<Main.RawPredicate>> termsToPredicates, | ||
List<Main.RawTerm> terms, String templateFamily, int numExtQuantfiers, int pruningLevel) { | ||
this.termsToPredicates = termsToPredicates; | ||
this.terms = terms; | ||
this.templateHeaderCar = ""; | ||
this.templateHeaderCdr = ""; | ||
this.numExists = numExtQuantfiers; | ||
this.pruningLevel = pruningLevel; | ||
StringBuilder sb = new StringBuilder(); | ||
switch (templateFamily) { | ||
case "Forall": | ||
for (int i = 0; i < QUANTIFIERS.length; ++i) { | ||
sb.append("∀").append(VARNAME[i]) | ||
.append(": ").append(QUANTIFIERS[i]).append(i == QUANTIFIERS.length - 1 ? " :: " : " "); | ||
} | ||
templateHeaderCar = sb.toString(); | ||
break; | ||
case "Exists": | ||
for (int i = 0; i < QUANTIFIERS.length; ++i) { | ||
sb.append("∃").append(VARNAME[i]) | ||
.append(":").append(QUANTIFIERS[i]).append(i == QUANTIFIERS.length - 1 ? " :: " : " "); | ||
} | ||
templateHeaderCar = sb.toString(); | ||
break; | ||
case "ForallExists": | ||
for (int i = 0; i < QUANTIFIERS.length - numExtQuantfiers; ++i) { | ||
sb.append("∀").append(VARNAME[i]) | ||
.append(":").append(QUANTIFIERS[i]).append(i == QUANTIFIERS.length - numExtQuantfiers - 1 ? " :: " : " "); | ||
} | ||
templateHeaderCar = sb.toString(); | ||
sb = new StringBuilder(); | ||
for (int i = QUANTIFIERS.length - numExtQuantfiers; i < QUANTIFIERS.length; ++i) { | ||
sb.append("∃").append(VARNAME[i]) | ||
.append(":").append(QUANTIFIERS[i]).append(i == QUANTIFIERS.length - 1 ? " :: " : " "); | ||
} | ||
templateHeaderCdr = sb.toString(); | ||
break; | ||
default: | ||
throw new IllegalArgumentException("Unknown template family: " + templateFamily); | ||
} | ||
substs.put(".toString", ""); | ||
substs.put("one of", "∈"); | ||
substs.put(".getPayload()", ""); | ||
substs.put("[] elements", ""); | ||
substs.put("(elementwise)", ""); | ||
} | ||
|
||
public String getFormulaHeader(String guards, String filters) { | ||
String guardsStr = runSubst(guards); | ||
String arrow = guardsStr.length() == 0 ? " " : " -> "; | ||
return this.templateHeaderCar + guardsStr + arrow + this.templateHeaderCdr + runSubst(filters); | ||
} | ||
|
||
public String convertOutput(String line, List<Main.RawPredicate> guards, List<Main.RawPredicate> filters, | ||
List<Main.RawTerm> forallTerms, List<Main.RawTerm> existsTerms) { | ||
if (!checkValidity(line, guards, filters, forallTerms, existsTerms)) { | ||
return null; | ||
} | ||
List<Main.RawTerm> substTerms = new ArrayList<>(); | ||
for (int i = 0; i < forallTerms.size(); ++i) { | ||
if (line.contains("f" + i)) { | ||
substTerms.add(forallTerms.get(i)); | ||
line = line.replace("f" + i, forallTerms.get(i).shortRepr()); | ||
} | ||
} | ||
for (int i = 0; i < existsTerms.size(); ++i) { | ||
String fieldPHName = "f" + (i + forallTerms.size()); | ||
if (line.contains(fieldPHName)) { | ||
// do not check sorted by for aggregated array | ||
if (line.contains("sorted by")) return null; | ||
substTerms.add(existsTerms.get(i)); | ||
line = line.replace(fieldPHName, existsTerms.get(i).shortRepr()); | ||
} | ||
} | ||
boolean didSth = !substTerms.isEmpty(); | ||
if (!didSth && !line.contains("_num_e_exists_")) return null; | ||
if (line.contains("_num_e_exists_")) { | ||
// _num_e_exists_ should be on lhs | ||
if (!line.startsWith("_num_e_exists_")) return null; | ||
// check # exists is related not only existentially quantified events | ||
if (didSth) { | ||
Set<Integer> boundedEvents = substTerms.stream() | ||
.flatMap(x -> x.events().stream()) | ||
.collect(Collectors.toSet()); | ||
boolean containsForallEvent = false; | ||
for (int i = 0; i < QUANTIFIERS.length - numExists; ++i) { | ||
if (boundedEvents.contains(i)) { | ||
containsForallEvent = true; | ||
break; | ||
} | ||
} | ||
if (!containsForallEvent) return null; | ||
} | ||
} | ||
return runSubst(line); | ||
} | ||
|
||
private String runSubst(String line) { | ||
for (var subst : substs.entrySet()) { | ||
line = line.replace(subst.getKey(), subst.getValue()); | ||
} | ||
if (line.contains(" in ")) { | ||
line = line.replace(" in ", " == "); | ||
} | ||
line = line.replace("[]", ""); | ||
return line; | ||
} | ||
|
||
private boolean isNumber(String x) { | ||
if (x == null || x.isEmpty()) return false; | ||
try { | ||
Double.parseDouble(x); | ||
} catch (NumberFormatException e) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
private boolean containsTerm(String line, int forallTermCount, int existsTermCount) { | ||
for (int i = 0; i < forallTermCount + existsTermCount; ++i) { | ||
if (line.contains("f" + i)) return true; | ||
} | ||
return false; | ||
} | ||
|
||
private Main.RawTerm getTermByTemplateField(String f, List<Main.RawTerm> forallTerms, List<Main.RawTerm> existsTerms) { | ||
for (int i = 0; i < forallTerms.size(); ++i) { | ||
if (f.contains("f" + i)) return forallTerms.get(i); | ||
} | ||
for (int i = 0; i < existsTerms.size(); ++i) { | ||
if (f.contains("f" + (i + forallTerms.size()))) return existsTerms.get(i); | ||
} | ||
return null; | ||
} | ||
|
||
private Map.Entry<List<Main.RawTerm>, List<Main.RawTerm>> | ||
getTermSubsts(String line, List<Main.RawTerm> forallTerms, List<Main.RawTerm> existsTerms) { | ||
List<Main.RawTerm> forallSubsts = new ArrayList<>(); | ||
List<Main.RawTerm> existsSubsts = new ArrayList<>(); | ||
for (int i = 0; i < forallTerms.size(); ++i) { | ||
if (line.contains("f" + i)) forallSubsts.add(forallTerms.get(i)); | ||
} | ||
for (int i = 0; i < existsTerms.size(); ++i) { | ||
int j = i + forallTerms.size(); | ||
if (line.contains("f" + j)) existsSubsts.add(existsTerms.get(i)); | ||
} | ||
return new AbstractMap.SimpleEntry<>(forallSubsts, existsSubsts); | ||
} | ||
|
||
private boolean checkValidity(String line, List<Main.RawPredicate> guards, | ||
List<Main.RawPredicate> filters, | ||
List<Main.RawTerm> forallTerms, | ||
List<Main.RawTerm> existsTerms) { | ||
if (pruningLevel == 0) { | ||
return true; | ||
} | ||
if (pruningLevel >= 1) { | ||
// prune nullptr comparisons | ||
// and type name comparisons | ||
for (var stub : FILTERED_INVS) { | ||
if (line.contains(stub)) return false; | ||
} | ||
} | ||
if (pruningLevel >= 2) { | ||
// prune if the set of terms of the mined property | ||
// equals to some selected atomic predicates | ||
Set<Integer> minedPropertyBoundedTerms = new HashSet<>(); | ||
for (int i = 0; i < forallTerms.size(); ++i) { | ||
if (line.contains("f" + i)) { | ||
minedPropertyBoundedTerms.add(forallTerms.get(i).order()); | ||
} | ||
} | ||
for (int i = 0; i < existsTerms.size(); ++i) { | ||
if (line.contains("f" + (i + forallTerms.size()))) { | ||
minedPropertyBoundedTerms.add(existsTerms.get(i).order()); | ||
} | ||
} | ||
for (Main.RawPredicate p: guards) { | ||
if (p.terms().equals(minedPropertyBoundedTerms)) return false; | ||
} | ||
for (Main.RawPredicate p: filters) { | ||
if (p.terms().equals(minedPropertyBoundedTerms)) return false; | ||
} | ||
} | ||
if (pruningLevel >= 3) { | ||
// exclude comparisons with constants | ||
for (String op: COMP_OPS) { | ||
if (line.contains(op)) { | ||
String[] args = line.split(op); | ||
if (args.length < 2) continue; | ||
String lhs = args[0].trim(); | ||
String rhs = args[1].trim(); | ||
if (op.equals("!=")) { | ||
var lhsTerm = getTermByTemplateField(lhs, forallTerms, existsTerms); | ||
var rhsTerm = getTermByTemplateField(rhs, forallTerms, existsTerms); | ||
if (lhsTerm != null && rhsTerm != null) { | ||
if (lhsTerm.shortRepr().endsWith(".index()") | ||
&& rhsTerm.shortRepr().endsWith(".index()")) return false; | ||
} | ||
} | ||
boolean rhsIsConst = isNumber(rhs) || (rhs.startsWith("\"") && rhs.endsWith("\"")); | ||
if (!containsTerm(lhs, forallTerms.size(), existsTerms.size())) { | ||
if (!rhsIsConst && !rhs.startsWith("size") && containsTerm(rhs, forallTerms.size(), existsTerms.size())) { | ||
// if a comparison does not involve a term on lhs, | ||
// it should not involve a term on rhs either (avoid `_num_e_exists_ > [some term]`) | ||
// however, we do want to see size([some term]) / config constants on rhs. | ||
return false; | ||
} | ||
break; | ||
} | ||
// if (rhsIsConst) { | ||
// return false; | ||
// } | ||
break; | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.