Repository navigation
Description
Update (after #673): the feature-matrix mismatch in follow-up 9 is fixed and merged. All numbers in this body were measured before the fix. A full rerun after the fix gives the same conclusions (F1 about +0.004 for every config;
pruned_full_lgeo length 21 vs 38, retrieval faster on 18/20 problems), see the comment below. Raw rows:e_fixed_matrix_all.jsonl.gzon the research branch. Follow-up 9 is done.
TL;DR
Pruning the rules of TDL's decision tree gives class expressions that are about half as long and that retrieve their instances roughly 40% as fast on average (5–10× faster on Mutagenesis), with no measurable loss in F1 on the 20 problems tested. This is a simplification of TDL's hypotheses, not an accuracy improvement.
Nothing here supports "strictly better than TDL". Equal F1 was shown as "not significantly different", not as non-inferior within a margin (see Caveats). I'm writing this up so somebody else can continue; the follow-up experiments are at the end.
Along the way I also tried several random-forest-style variants of TDL. None beat a single tuned tree (details and numbers below), which is a useful negative result.
Code: branch feat/tdl-hypothesis-pool (on top of feat/tdl-forest, from develop; both pushed, no PR open), new class TDLForest, files ontolearn/learners/tree_learner_forest.py, ontolearn/learners/tdl_forest_utils.py, tests/test_tdl_forest.py, examples/benchmark_tdl_forest.py. TDL itself is untouched.
Motivation
TDL fits one decision tree on binary class-expression features and reads a class expression back from it. The question was whether a random forest could improve it. A forest's vote has no compact class expression, so the problem becomes: either keep a single hypothesis, or keep a pool of final hypotheses and refine / derefine them. The experiments below start with derefinement (step 1 of the plan: derefine, then refine, then combine).
The approach
Features
As in TDL: every example is a row of binary features; a column is one OWL class expression and is 1 iff the example is an instance of it. The rows are put in a canonical order (positives first, then by IRI) because TDL lists them in set iteration order, which changes with PYTHONHASHSEED, and bagging indexes rows by position.
Rules
A rule is a conjunction of literals (column, holds): the column's expression, or its complement if holds is false. The hypothesis is the union of the rules of a decision tree's positive leaves (root-to-leaf paths ending in a leaf that predicts the positive class).
Derefinement (prune_rules)
Reduced-error pruning on class expressions. Given rules R and rows (X, y):
floor = F1(R) - tolerance # measured against the UNPRUNED rules, so edits cannot drift
repeat:
candidate edits = for each rule: drop the whole rule (if more than one rule is left)
drop one literal of it (if it has more than one literal)
take the edit with the best F1 on (X, y) (the first one among equal edits: deterministic)
stop if that F1 < floor, else apply it
Dropping a literal generalizes a conjunction, dropping a rule specializes the union; both shorten the expression. With tolerance = 0 ties are resolved in favour of the simpler hypothesis, which removes redundancy without changing F1 (lossless on the rows used). The implementation keeps a per-row cover count so one round is cheap.
Which rows decide what is pruned gives the variants:
| mode | tree | pruning rows | purpose |
|---|---|---|---|
full_rules |
one tree on all rows | none | control |
pruned_full |
one tree on all rows | the training rows, prune_tolerance tuned by inner CV |
the approach that worked |
best_tree |
best of 25 bagged trees (out-of-bag F1) | none | control |
pruned |
best of 25 bagged trees | that tree's own out-of-bag rows | derefinement on held-out rows |
tree, feature_selection, rules, vote, forest_predictor |
see TDLForest docstring |
forest variants (negative results) |
pruned_full configurations in the tables: pruned_full0 (tolerance=0, lossless), pruned_full_t (tolerance in {0, .01, .02, .05, .1} tuned for inner-CV F1), pruned_full_l (same grid, tuned for F1 - 0.01 * log2(length)).
Evaluation protocol
- 20 problems: 18 synthetic Family tasks (
LPs/Family/lps.json), Mutagenesis, Carcinogenesis. - Repeated stratified 5-fold CV, 4 repeats: 20 outer folds per problem. Features are extracted from the training fold only.
- Nested tuning: hyperparameters are chosen by an inner stratified 3-fold CV on the training fold; the test fold is never seen. Tree grid:
max_depthin {None, 3, 5} xmin_samples_leafin {1, 2, 5}. - Scoring by reasoner semantics: the hypothesis is retrieved from the KB (
kb.individuals(h)) and compared with the test labels. (TDL's own feature matrix is not used for scoring, see the last follow-up.) - Statistics at the problem level: the problem is the independent unit. Paired Wilcoxon on per-problem mean differences, Holm correction within a family of comparisons, bootstrap CI over problems, Friedman test over problems, and the Nadeau-Bengio corrected resampled t-test within a problem.
- Length = characters of the DL rendering of the hypothesis. Retrieval time = time for
kb.individuals(h)after one warm-up (the structural reasoner's per-class/per-property caches are warm), minimum of 3 runs, measured inside the same fold and process for all configurations (8 workers on 22 cores).
Results
All configurations (mean over the 20 problems of the per-problem mean over 20 folds)
| config | F1 | accuracy | geo-mean length (chars) | mean fit time (s) |
|---|---|---|---|---|
| tree | 0.9393 | 0.9329 | 37 | 0.03 |
| tree_t | 0.9448 | 0.9326 | 38 | 0.67 |
| tree_l | 0.9450 | 0.9317 | 35 | 0.57 |
| full_rules | 0.9393 | 0.9329 | 37 | 0.02 |
| pruned_full0 | 0.9386 | 0.9319 | 31 | 0.03 |
| pruned_full_t | 0.9386 | 0.9317 | 26 | 0.33 |
| pruned_full_l | 0.9399 | 0.9323 | 20 | 0.32 |
| fs | 0.9310 | 0.9228 | 45 | 0.08 |
| fs_t | 0.9392 | 0.9304 | 46 | 0.86 |
| rules | 0.9076 | 0.9042 | 54 | 0.12 |
| rules_t | 0.9169 | 0.9164 | 43 | 1.20 |
| vote5 | 0.9009 | 0.8952 | n/a (vote) | 0.03 |
| forest_tree | 0.8988 | 0.8818 | 222 | 0.14 |
| forest_vote | 0.9218 | 0.9142 | n/a (vote) | 0.14 |
| forest_vote_t | 0.9415 | 0.9370 | n/a (vote) | 7.55 |
| best_tree | 0.8982 | 0.8917 | 216 | 0.10 |
| best_tree_t | 0.9033 | 0.8925 | 120 | 2.62 |
| pruned | 0.8897 | 0.8774 | 27 | 0.34 |
| pruned_t | 0.9005 | 0.8874 | 23 | 2.99 |
tree is the default TDL; tree_t is the tree with the grid above tuned by inner CV; tree_l the same tuned for F1 - 0.01 * log2(length); _t = tuned; _l = tuned with the length term. Lengths are geometric means over folds then over problems (arithmetic means are dominated by Mutagenesis/Carcinogenesis).
Per-problem F1
20 problems x 10 configurations
| problem | tree | tree_t | pruned_full0 | pruned_full_t | pruned_full_l | fs_t | rules_t | forest_vote_t | best_tree_t | pruned_t |
|---|---|---|---|---|---|---|---|---|---|---|
| Carcinogenesis | 0.649 | 0.682 | 0.649 | 0.645 | 0.645 | 0.676 | 0.628 | 0.632 | 0.657 | 0.702 |
| Family-Aunt | 0.926 | 0.929 | 0.920 | 0.920 | 0.908 | 0.926 | 0.824 | 0.918 | 0.824 | 0.831 |
| Family-Brother | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.996 | 1.000 | 0.958 | 0.937 |
| Family-Cousin | 0.830 | 0.861 | 0.827 | 0.835 | 0.836 | 0.788 | 0.761 | 0.821 | 0.668 | 0.698 |
| Family-Daughter | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.987 | 0.982 |
| Family-Father | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.956 | 0.980 |
| Family-Granddaughter | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.994 | 1.000 | 0.973 | 0.937 |
| Family-Grandfather | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.989 | 0.986 |
| Family-Grandgranddaughter | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.988 | 0.938 | 1.000 | 0.951 | 0.951 |
| Family-Grandgrandfather | 0.948 | 0.948 | 0.948 | 0.948 | 0.948 | 0.931 | 0.921 | 0.941 | 0.935 | 0.924 |
| Family-Grandgrandmother | 0.921 | 0.921 | 0.921 | 0.921 | 0.948 | 0.944 | 0.903 | 0.922 | 0.888 | 0.830 |
| Family-Grandgrandson | 0.880 | 0.900 | 0.880 | 0.887 | 0.895 | 0.875 | 0.870 | 0.902 | 0.818 | 0.777 |
| Family-Grandmother | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.962 | 0.990 |
| Family-Grandson | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.997 | 0.992 | 0.967 | 0.983 |
| Family-Mother | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.994 | 1.000 | 0.954 | 0.960 |
| Family-PersonWithASibling | 0.931 | 0.931 | 0.931 | 0.931 | 0.931 | 0.935 | 0.906 | 0.997 | 0.936 | 0.900 |
| Family-Sister | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.967 | 0.977 |
| Family-Son | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 | 0.978 | 0.985 |
| Family-Uncle | 0.848 | 0.879 | 0.840 | 0.829 | 0.830 | 0.893 | 0.762 | 0.865 | 0.878 | 0.866 |
| Mutagenesis | 0.853 | 0.848 | 0.858 | 0.856 | 0.857 | 0.830 | 0.843 | 0.842 | 0.819 | 0.813 |
Per-problem median length (chars) / median retrieval time (ms)
20 problems x 5 configurations
| problem | tree len / ms | tree_t len / ms | pruned_full0 len / ms | pruned_full_t len / ms | pruned_full_l len / ms |
|---|---|---|---|---|---|
| Carcinogenesis | 1382 / 3595.29 | 379 / 860.95 | 576 / 1460.90 | 512 / 1137.07 | 396 / 968.08 |
| Family-Aunt | 251 / 10.48 | 416 / 11.98 | 152 / 5.26 | 150 / 5.01 | 93 / 2.98 |
| Family-Brother | 7 / 0.28 | 7 / 0.25 | 7 / 0.13 | 7 / 0.24 | 7 / 0.26 |
| Family-Cousin | 1360 / 38.96 | 1278 / 33.58 | 606 / 15.52 | 296 / 3.97 | 274 / 3.76 |
| Family-Daughter | 8 / 0.25 | 8 / 0.22 | 8 / 0.13 | 8 / 0.26 | 8 / 0.26 |
| Family-Father | 6 / 0.26 | 6 / 0.26 | 6 / 0.13 | 6 / 0.24 | 6 / 0.22 |
| Family-Granddaughter | 13 / 0.25 | 13 / 0.27 | 13 / 0.12 | 13 / 0.24 | 13 / 0.24 |
| Family-Grandfather | 11 / 0.27 | 11 / 0.27 | 11 / 0.13 | 11 / 0.24 | 11 / 0.25 |
| Family-Grandgranddaughter | 13 / 0.27 | 13 / 0.20 | 13 / 0.12 | 13 / 0.24 | 13 / 0.19 |
| Family-Grandgrandfather | 72 / 2.84 | 78 / 1.99 | 72 / 2.46 | 67 / 2.23 | 21 / 0.26 |
| Family-Grandgrandmother | 65 / 2.76 | 66 / 2.66 | 65 / 2.56 | 56 / 1.74 | 11 / 0.26 |
| Family-Grandgrandson | 94 / 3.14 | 131 / 3.90 | 90 / 2.79 | 48 / 2.26 | 8 / 0.29 |
| Family-Grandmother | 11 / 0.28 | 11 / 0.26 | 11 / 0.14 | 11 / 0.27 | 11 / 0.28 |
| Family-Grandson | 8 / 0.26 | 8 / 0.27 | 8 / 0.14 | 8 / 0.27 | 8 / 0.26 |
| Family-Mother | 16 / 0.27 | 16 / 0.28 | 16 / 0.16 | 16 / 0.28 | 16 / 0.26 |
| Family-PersonWithASibling | 15 / 0.33 | 15 / 0.31 | 15 / 0.19 | 15 / 0.31 | 15 / 0.35 |
| Family-Sister | 6 / 0.29 | 6 / 0.24 | 6 / 0.12 | 6 / 0.24 | 6 / 0.25 |
| Family-Son | 3 / 0.26 | 3 / 0.25 | 3 / 0.12 | 3 / 0.25 | 3 / 0.24 |
| Family-Uncle | 250 / 9.30 | 438 / 12.29 | 207 / 7.53 | 174 / 5.70 | 56 / 2.83 |
| Mutagenesis | 1961 / 3441.56 | 1830 / 3204.30 | 710 / 1083.75 | 517 / 546.53 | 188 / 311.08 |
Paired comparisons (problem level, F1)
| comparison | mean dF1 | 95% CI (bootstrap over problems) | Holm p | notes |
|---|---|---|---|---|
pruned_full0 vs full_rules |
-0.0006 | [-0.0019, +0.0004] | 0.35 | lossless pruning, F1 w/t/l 2/15/3 |
pruned_full0 vs tree |
-0.0006 | [-0.0019, +0.0004] | p=0.35 (Wilcoxon) | length -0.25 doublings |
pruned_full_t vs tree |
-0.0007 | [-0.0032, +0.0012] | p=0.75 (Wilcoxon) | length -0.51 doublings |
pruned_full_l vs tree |
+0.0006 | [-0.0033, +0.0047] | p=0.74 (Wilcoxon) | length -0.90 doublings (CI [-1.42, -0.41], p=0.012) |
tree_t vs tree |
+0.0055 | [+0.0010, +0.0110] | p=0.075 (Wilcoxon) | tuning only, not significant |
pruned_full_t vs tree_t |
-0.0062 | [-0.0130, -0.0006] | 0.23 | |
pruned_full_l vs tree_t |
-0.0049 | [-0.0122, +0.0015] | 0.61 | |
fs_t vs tree_t |
-0.0056 | [-0.0147, +0.0014] | 0.61 | |
forest_vote_t vs tree_t |
-0.0033 | [-0.0121, +0.0065] | 0.56 | forest vote, no compact expression |
rules_t vs tree_t |
-0.0279 | [-0.0454, -0.0124] | 0.006 | falls back to a single tree in 24% of folds |
best_tree_t vs tree_t |
-0.0415 | [-0.0621, -0.0256] | <0.0001 | bagged tree |
pruned_t vs best_tree_t |
-0.0028 | [-0.0142, +0.0084] | 0.81 | pruning on out-of-bag rows keeps F1 |
Friedman test over the 14 configurations of the first two runs: chi2 = 127.4, p < 0.0001.
Retrieval time against default TDL (tree), problem level
Difference of log2 retrieval time per problem (negative = faster), paired:
| config | dlog2 time (95% CI) | Wilcoxon p | faster on | dlog2 length |
|---|---|---|---|---|
pruned_full0 |
-0.84 [-1.02, -0.67] | <0.001 | 20/20 | -0.25 |
pruned_full_t |
-0.69 [-1.11, -0.33] | <0.001 | 17/20 | -0.51 |
pruned_full_l |
-1.20 [-1.82, -0.61] | <0.001 | 16/20 | -0.90 |
tree_t |
-0.10 [-0.32, +0.06] | 0.31 | 12/20 | +0.04 |
tree_l |
-0.18 [-0.42, -0.02] | 0.048 | 13/20 | -0.06 |
- Length predicts retrieval time: Spearman 0.78 over all folds, 0.94 on Mutagenesis and Carcinogenesis.
- Time falls faster than length:
pruned_full0is 0.25 doublings shorter but 0.84 doublings faster. The redundant sub-expressions that are removed seem to be the expensive ones. pruned_full_lwas faster thantreein all 156 folds in which it was shorter.- On the 18 Family problems retrieval takes well under a millisecond either way: the gain matters for the two large KBs.
- Reproducibility: the lengths of the re-run (2,800 rows) match the original run exactly.
Length-aware views
S = F1 - lambda * log2(length) (a doubling of the length costs lambda F1). Mean score at lambda = 0.01: pruned_full_l 0.8969, tree_l 0.8937, tree_t 0.8925, pruned_full_t 0.8917, tree 0.8873. By average rank over problems the untuned tree is best at every lambda (rank 3.5 at 0.01 against 5.5 for pruned_full_l): the shorter configurations win on a few large problems, tree wins on more problems. The conclusion depends on the aggregator. The Pareto front on (F1, length) among the configurations in the table above is {tree_l, pruned_full_l}. Break-even lambda of pruned_full_t against tree_t is 0.011 (CI [0.002, 0.027]); of pruned_full_l it is 0.005 (CI [-0.002, 0.015]).
Negative results (forest variants)
Nothing beat a single tuned tree:
- Majority-vote forests (
forest_vote_t) are statistically indistinguishable fromtree_t(-0.003, CI [-0.012, +0.007]) but fit about 10x slower (7.6 s vs 0.7 s) and have no compact class expression; the exact vote as a class expression grows combinatorially. - Selecting high-precision rules from the bagged trees by out-of-bag precision and greedy set cover (
rules_t) loses 2.8 F1 points. - Feature selection by forest importance (
fs_t) loses 0.6 points (n.s.). - A single bagged tree loses about 4 F1 points against a tree on all rows (
best_tree_tvstree_t): it sees about 63% of the distinct rows. Pruning it on its out-of-bag rows (pruned_t) makes it about 5x shorter at no extra F1 loss, but does not recover the gap. - Tuning the tree (depth, leaf size) is the only thing that raised F1 (0.939 to 0.945, n.s. with Holm, p=0.075 uncorrected).
TDL.fitalready has its own grid search; I did not compare the two.
Caveats (read before building on this)
- Equality of F1 is not proven. The F1 differences between
pruned_full*andtreeare not significant, which is not the same as non-inferior. A real test needs a margin fixed in advance (e.g. 0.01 F1) and an equivalence test (TOST). - The metric choices were made after seeing results: lambda in
F1 - lambda * log2(length), the use of characters as length, geometric means. The_lconfigurations were tuned with the same lambda they are scored with at 0.01. - Small and skewed sample: 18 of the 20 problems are synthetic Family tasks over one KB (not independent, tiny trees; pruning changes nothing on most of them). Only Mutagenesis and Carcinogenesis resemble real data, and Carcinogenesis often reverses the ranking (e.g.
pruned_tis best there and worst on Family). - Extraction difference:
TDLForestmodes read the union of predicted-positive leaf conjunctions,TDLdefault (positive_paths) uses leaves holding positive training rows. Their mean F1/length agree (tree=full_rules= 0.9393) but I did not prove the hypotheses are equivalent per fold. - About 25 configurations were tried; only comparisons inside a stated family have a Holm correction.
- Timing was done with 8 parallel workers. Within-fold pairing cancels most of the load, but absolute numbers are not clean. Cold-start retrieval is not measured.
- The raw result rows (about 8,400 JSONL lines from three runs plus the timing run) are in the repository, gzipped, in
examples/benchmark_results/tdl_forest/on the branch (see its README); the tables above are the problem-level aggregates of them.
Follow-up experiments (suggested order)
- Pre-registered non-inferiority test. Fix, before running anything: margin (0.01 F1), the length measure, lambda or none, the aggregator, the statistic (TOST at the problem level, or a mixed model over folds nested in problems). Then test
pruned_full0(lossless, no tuning, simplest to defend) andpruned_full_lagainstTDLdefault and against the tuned tree. Use more repeats to tighten the CI. - More and more realistic problems. Add the other KGs/LPs shipped with Ontolearn, noisy labels, larger and deeper trees, and a SPARQL triplestore backend (
TripleStore) where the retrieval time of a long expression is a network round trip and the gain should be largest. The two real KBs are where the whole effect lives. - A structural length measure and a clean timing harness. Use
concept_len/ the library's expression-length metric instead of characters; time with no parallel workers, cold and warm caches, and report the number of reasoner calls too. - Put the lossless step inside TDL.
pruned_full0removes redundancy without changing training F1. If it is equivalent to TDL's output apart from redundancy, it could be an extraction option (likehypothesis_extraction) rather than a new class. Check the extraction difference of caveat 4 first. - Better simplification than literal/rule dropping.
- Ontology-aware simplification: drop a conjunct entailed by another (e.g.
exists r.Tnext toexists r.C), merge disjuncts that subsume each other (reasoner subsumption checks). - Minimal DNF over the feature columns (Quine-McCluskey / Espresso) on the training rows.
- Put the length into the pruning criterion itself (
F1 - lambda * size) instead of tuning a tolerance. - Cross-fitted pruning: prune the full-data tree using held-out predictions of K fold-trees.
- Ontology-aware simplification: drop a conjunct entailed by another (e.g.
- The original plan, not done yet: refine (local search from the pruned expressions with a refinement operator such as CELOE's or EvoLearner's mutations, scored by out-of-bag quality plus a length penalty) and combine (union/intersection of a pool chosen by out-of-bag score). The negative results suggest this must beat the regularization from tuning, which a plain tuned tree already provides.
- Why does a bagged tree lose 4 points? Try subsampling at 90%, no bootstrap with feature subsampling, and stability selection of rules that appear in many fold-trees, so that the gap to the full-data tree can be closed before pruning.
- Tuning fairness. Compare against
TDL's built-in grid search, not only my grid, and give all methods the same tuning budget. - Fix a related TDL issue and re-run everything. TDL trains on a feature matrix that disagrees with the reasoner for a few columns. On the Family
Uncleproblem, 4 of 352 columns (123 of 26,752 cells, 0.46%) sayFalsein the matrix where the reasoner saysTrue; all four areforall r^-.T(hasChild,hasParent,hasSibling,married). Reproduction:I do not know the cause or whether fixing it changes accuracy.import json from owlapy.owl_individual import OWLNamedIndividual as I from ontolearn.knowledge_base import KnowledgeBase from ontolearn.learners import TDL from ontolearn.learning_problem import PosNegLPStandard s = json.load(open('examples/synthetic_problems.json')); e = s['problems']['Uncle'] lp = PosNegLPStandard(pos={I(i) for i in e['positive_examples']}, neg={I(i) for i in e['negative_examples']}) kb = KnowledgeBase(path=s['data_path'][3:]) m = TDL(knowledge_base=kb, verbose=0, report_classification=False).fit(lp) for c in m.X.columns: retrieved = set(kb.individuals(c)) n = sum((i in retrieved) != bool(m.X.loc[i, c]) for i in m.X.index) if n: print(c, n)
Reproduction
# tests
pytest tests/test_tdl_forest.py -p no:warnings # 33 tests
# the three result sets (results are resumable), new configs go to a new file
PYTHONPATH=$PWD python examples/benchmark_tdl_forest.py run --repeats 4 --workers 16 --out a.jsonl
PYTHONPATH=$PWD python examples/benchmark_tdl_forest.py run --repeats 4 --workers 16 --configs best_tree,pruned,best_tree_t,pruned_t --out b.jsonl
PYTHONPATH=$PWD python examples/benchmark_tdl_forest.py run --repeats 4 --workers 16 --configs full_rules,pruned_full0,pruned_full_t,tree_l,pruned_full_l --out c.jsonl
# the retrieval-time run
PYTHONPATH=$PWD python examples/benchmark_tdl_forest.py run --repeats 4 --workers 8 --configs tree,tree_t,tree_l,full_rules,pruned_full0,pruned_full_t,pruned_full_l --out d.jsonl
# the report (merges several files; includes the length-aware section)
PYTHONPATH=$PWD python examples/benchmark_tdl_forest.py report --out a.jsonl --out b.jsonl --out c.jsonlData (KGs/, LPs/) must be downloaded as described in the README. LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 was needed for pytest in my environment.
Activity
LckyLke commentedon Nov 5, 2026
Regarding 9:
forall r^-.Tis equivalent toT-> so it should be always true. And TDL should not check tautologies anway(?), cause they are always true...Either way the reasoner is right, and TDL is wrong :v
Demirrr commentedon Nov 5, 2026
Update: rerun on the fixed feature matrix
Follow-up 9 (the TDL feature matrix disagreeing with the reasoner) is fixed in #673, which is merged. It was the tautological
∀ r⁻.⊤column. The numbers in the issue body predate that fix. I mergeddevelopintofeat/tdl-forestandfeat/tdl-hypothesis-pooland reran the full nested-CV benchmark (20 problems, 4×5-fold, same configs and seeds).Conclusions are unchanged.
treetreetree_tpruned_full0pruned_full_tpruned_full_lbest_tree_tpruned_tpruned_full0vsfull_rules: −0.0006 F1 (Holm p=0.35), 2/15/3 wins/ties/losses.pruned_full_lvstree_t: −0.0053 F1 (CI [−0.0135, +0.0015], Holm p=0.35). Non-inferiority is still not tested.tree_t, as before.Retrieval time vs
tree(problem-level mean Δlog2 time; problems faster):pruned_full0: −0.67 (20/20)pruned_full_t: −0.47 (11/20)pruned_full_l: −1.12 (18/20)The efficiency gain holds on the fixed matrix and is slightly smaller for
pruned_full_t.Caveats that remain: 18 of 20 problems are one synthetic Family KB, the metrics were chosen post hoc, and about 25 configurations were tried. So this is a measurable efficiency gain, not a proven strictly better TDL.