Skip to main content
added 143 characters in body
Source Link
Lukas Lang
  • 34.4k
  • 1
  • 56
  • 99

Third times's the charm, isn't it? ;)

Similar in spirit to my other answer using GeneralUtilities`PatternSort, but fully documented and more robust:

robustRuleSort[rules_] := Module[
  {ruleSorter},
  (ruleSorter[# _.]dummyPat_] := {{#2}}) & @@@ rules;
  DownValues[ruleSorter][[All, All, 1, 1]]
  /. p_ Verbatim[dummyPat_] :> p
]

n2/n3/n4/n5 + n1*n2/n3/n4/n5 /. robustRuleSort@{n2/n3/n4/n5 -> a2, n1*n2/n3/n4/n5 -> e}
(* 2 a2 + e *)

###How it works The basic idea is to (ab)use the rule ordering mechanism of downvalues to order the rules for us. This has the advantage that we use the best available specificity tester available, rather that something that tries to emulate it (like GeneralUtilities`PatternSort or Internal`ComparePatterns). This requires a few things:

  • A dummy symbol to attach our rules to (ruleSorter). We will attach our rules as downvalues, which are then ordered by specificity (see here).
  • We need to make sure the rules are not literal downvalues (ordering doesn't work for them). Hence the _dummyPat factor we add. We later remove it using ReplaceAll (/. that should always be matched by nothing) (note the use of Verbatim)
  • The right-hand-side of the downvalues is wrapped in {{…}} to make extraction easier: DownValues[sym] are always of the form {HoldPattern[sym[lhs]]:>rhs}. This means we need to strip off two layers on the lhs, so we add two on the rhs to even it out.

This results in a rule sorter that should be as good as possible

Third times's the charm, isn't it? ;)

Similar in spirit to my other answer using GeneralUtilities`PatternSort, but fully documented and more robust:

robustRuleSort[rules_] := Module[
  {ruleSorter},
  (ruleSorter[# _.] := {{#2}}) & @@@ rules;
  DownValues[ruleSorter][[All, All, 1, 1]]
   ]

n2/n3/n4/n5 + n1*n2/n3/n4/n5 /. robustRuleSort@{n2/n3/n4/n5 -> a2, n1*n2/n3/n4/n5 -> e}
(* 2 a2 *)

###How it works The basic idea is to (ab)use the rule ordering mechanism of downvalues to order the rules for us. This has the advantage that we use the best available specificity tester available, rather that something that tries to emulate it (like GeneralUtilities`PatternSort or Internal`ComparePatterns). This requires a few things:

  • A dummy symbol to attach our rules to (ruleSorter). We will attach our rules as downvalues, which are then ordered by specificity (see here).
  • We need to make sure the rules are not literal downvalues (ordering doesn't work for them). Hence the _. that should always be matched by nothing
  • The right-hand-side of the downvalues is wrapped in {{…}} to make extraction easier: DownValues[sym] are always of the form {HoldPattern[sym[lhs]]:>rhs}. This means we need to strip off two layers on the lhs, so we add two on the rhs to even it out.

This results in a rule sorter that should be as good as possible

Third times's the charm, isn't it? ;)

Similar in spirit to my other answer using GeneralUtilities`PatternSort, but fully documented and more robust:

robustRuleSort[rules_] := Module[{ruleSorter},
  (ruleSorter[# dummyPat_] := {{#2}}) & @@@ rules;
  DownValues[ruleSorter][[All, All, 1, 1]] /. p_ Verbatim[dummyPat_] :> p
]

n2/n3/n4/n5 + n1*n2/n3/n4/n5 /. robustRuleSort@{n2/n3/n4/n5 -> a2, n1*n2/n3/n4/n5 -> e}
(* a2 + e *)

###How it works The basic idea is to (ab)use the rule ordering mechanism of downvalues to order the rules for us. This has the advantage that we use the best available specificity tester available, rather that something that tries to emulate it (like GeneralUtilities`PatternSort or Internal`ComparePatterns). This requires a few things:

  • A dummy symbol to attach our rules to (ruleSorter). We will attach our rules as downvalues, which are then ordered by specificity (see here).
  • We need to make sure the rules are not literal downvalues (ordering doesn't work for them). Hence the dummyPat factor we add. We later remove it using ReplaceAll (/.) (note the use of Verbatim)
  • The right-hand-side of the downvalues is wrapped in {{…}} to make extraction easier: DownValues[sym] are always of the form {HoldPattern[sym[lhs]]:>rhs}. This means we need to strip off two layers on the lhs, so we add two on the rhs to even it out.

This results in a rule sorter that should be as good as possible

Source Link
Lukas Lang
  • 34.4k
  • 1
  • 56
  • 99

Third times's the charm, isn't it? ;)

Similar in spirit to my other answer using GeneralUtilities`PatternSort, but fully documented and more robust:

robustRuleSort[rules_] := Module[
  {ruleSorter},
  (ruleSorter[# _.] := {{#2}}) & @@@ rules;
  DownValues[ruleSorter][[All, All, 1, 1]]
  ]

n2/n3/n4/n5 + n1*n2/n3/n4/n5 /. robustRuleSort@{n2/n3/n4/n5 -> a2, n1*n2/n3/n4/n5 -> e}
(* 2 a2 *)

###How it works The basic idea is to (ab)use the rule ordering mechanism of downvalues to order the rules for us. This has the advantage that we use the best available specificity tester available, rather that something that tries to emulate it (like GeneralUtilities`PatternSort or Internal`ComparePatterns). This requires a few things:

  • A dummy symbol to attach our rules to (ruleSorter). We will attach our rules as downvalues, which are then ordered by specificity (see here).
  • We need to make sure the rules are not literal downvalues (ordering doesn't work for them). Hence the _. that should always be matched by nothing
  • The right-hand-side of the downvalues is wrapped in {{…}} to make extraction easier: DownValues[sym] are always of the form {HoldPattern[sym[lhs]]:>rhs}. This means we need to strip off two layers on the lhs, so we add two on the rhs to even it out.

This results in a rule sorter that should be as good as possible