fix: parse grRules into a tree; fix removeGenes, expandModel, findPotentialErrors - #673
Merged
Conversation
…lErrors Three functions each reasoned about grRules by searching the raw string, and each got it wrong in a different way. They now share one parse tree. New in utils/: parseGrRule (tokenise + recursive descent), isDnfGrRule, grRuleToDNF, grRuleToString. Operators are matched as whole words, so a gene called RAND1 is a gene, and "10" is never confused with "100". raven-toolbox gets this for free from cobra's Python AST (utils/gpr.py, manipulation/expand.py); MATLAB has no equivalent, so the tree is built here. isDnfGrRule mirrors _is_dnf_node/_contains_or and grRuleToDNF mirrors _node_to_dnf node for node. removeGenes (R2): removeGeneFromRule used an unanchored strfind over the ' or '-split rule, so removing gene "10" from "10 or 100" also matched "100" and left the reaction with no grRule at all while gene 100 stayed in the model -- the association was destroyed, silently, and standardizeGrRules then zeroed the rxnGeneMat row. Numeric Entrez/HGNC ids make this the norm rather than the exception in the tINIT/HPA human workflow, and findGeneDeletions and runSimpleOptKnock mispredict essentiality off the result. Both subfunctions now walk the tree, comparing gene ids with strcmp. This also retires the last eval-based grRule evaluation in the codebase. expandModel (EX1): stripped every parenthesis and split on ' or ', which destroys precedence. "g1 and (g2 or g3)" expanded to "g1 and g2" and "g3" -- the second isozyme silently lost its mandatory g1 subunit, so a g1 knockout was predicted viable when it is lethal. Isozymes are now the DNF clauses. The reaction count comes from the clauses too: "(g1 or g2) and (g3 or g4)" has two or:s but four isozymes, and the old preallocation sized for three. rxnToCheck now lists only rules that genuinely needed distributivity, not every rule containing ' and '. findPotentialErrors (S2): the one-level split flagged valid DNF such as "((G1 and G2) or G3)" and "(G1 or G2) or (G3 and G4)". That was worse than cosmetic: standardizeGrRules skips flagged rules, so a false positive meant the rule was never repaired and kept the brackets the function exists to remove. Unparseable rules are now reported as issues rather than skipped. Also fix a pre-existing crash in expandModel: cpyIndices was a row, and indexing a 1x1 field takes the orientation of the index, so every concatenation failed on a single-reaction model. Tests: nothing under testing/ exercised grRules at all. Adds parser coverage to tUtils and regression tests to tManipulation for each defect above, using the reproductions as the anchors.
Function test results259 tests 237 ✅ 1m 2s ⏱️ Results for commit 14e8e2c. |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Main improvements in this PR:
parseGrRule,grRuleToDNF,isDnfGrRule,grRuleToString.removeGenesremoved the wrong gene's association when one gene id was a substring of another.expandModeldropped mandatory subunits when expanding rules mixingandandor.findPotentialErrorsflagged valid DNF rules as errors, which also preventedstandardizeGrRulesfrom repairing them.tUtils.mandtManipulation.m.Instructions on merging this PR:
develop3as target branch, and will be resolved with a squash-merge.