|
8 | 8 | <ₑ(a::Symbolic, b::Number) = false |
9 | 9 | <ₑ(a::Number, b::Symbolic) = true |
10 | 10 |
|
11 | | -arglength(a) = length(arguments(a)) |
12 | | -function <ₑ(a, b) |
13 | | - if isterm(a) && (b isa Symbolic && !isterm(b)) |
14 | | - return false |
15 | | - elseif isterm(b) && (a isa Symbolic && !isterm(a)) |
16 | | - return true |
17 | | - elseif (isadd(a) || ismul(a)) && (isadd(b) || ismul(b)) |
18 | | - return cmp_mul_adds(a, b) |
19 | | - elseif issym(a) && issym(b) |
20 | | - nameof(a) < nameof(b) |
21 | | - elseif !istree(a) && !istree(b) |
22 | | - T = typeof(a) |
23 | | - S = typeof(b) |
24 | | - return T===S ? (T <: Number ? isless(a, b) : hash(a) < hash(b)) : nameof(T) < nameof(S) |
25 | | - elseif istree(b) && !istree(a) |
26 | | - return true |
27 | | - elseif istree(a) && istree(b) |
28 | | - return cmp_term_term(a,b) |
| 11 | +<ₑ(a::Function, b::Function) = nameof(a) <ₑ nameof(b) |
| 12 | + |
| 13 | +<ₑ(a::Type, b::Type) = nameof(a) <ₑ nameof(b) |
| 14 | +<ₑ(a::T, b::S) where{T,S} = T<S |
| 15 | +<ₑ(a::T, b::T) where{T} = a < b |
| 16 | + |
| 17 | + |
| 18 | +###### A variation on degree lexicographic order ######## |
| 19 | +# find symbols and their corresponding degrees |
| 20 | +function get_degrees(expr) |
| 21 | + if issym(expr) |
| 22 | + ((Symbol(expr),) => 1,) |
| 23 | + elseif istree(expr) |
| 24 | + op = operation(expr) |
| 25 | + args = arguments(expr) |
| 26 | + if operation(expr) == (^) && args[2] isa Number |
| 27 | + return map(get_degrees(args[1])) do (base, pow) |
| 28 | + (base => pow * args[2]) |
| 29 | + end |
| 30 | + elseif operation(expr) == (*) |
| 31 | + return mapreduce(get_degrees, |
| 32 | + (x,y)->(x...,y...,), args) |
| 33 | + elseif operation(expr) == (+) |
| 34 | + ds = map(get_degrees, args) |
| 35 | + _, idx = findmax(x->sum(last.(x), init=0), ds) |
| 36 | + return ds[idx] |
| 37 | + elseif operation(expr) == (getindex) |
| 38 | + args = arguments(expr) |
| 39 | + return ((Symbol.(args)...,) => 1,) |
| 40 | + else |
| 41 | + return ((Symbol("zzzzzzz", hash(expr)),) => 1,) |
| 42 | + end |
29 | 43 | else |
30 | | - return !(b <ₑ a) |
| 44 | + return () |
31 | 45 | end |
32 | 46 | end |
33 | 47 |
|
34 | | -function cmp_mul_adds(a, b) |
35 | | - (isadd(a) && ismul(b)) && return true |
36 | | - (ismul(a) && isadd(b)) && return false |
37 | | - a_args = unsorted_arguments(a) |
38 | | - b_args = unsorted_arguments(b) |
39 | | - length(a_args) < length(b_args) && return true |
40 | | - length(a_args) > length(b_args) && return false |
41 | | - a_args = arguments(a) |
42 | | - b_args = arguments(b) |
43 | | - for (x, y) in zip(a_args, b_args) |
44 | | - x <ₑ y && return true |
45 | | - end |
46 | | - return false |
| 48 | +function monomial_lt(degs1, degs2) |
| 49 | + d1 = sum(last, degs1, init=0) |
| 50 | + d2 = sum(last, degs2, init=0) |
| 51 | + d1 != d2 ? d1 < d2 : lexlt(degs1, degs2) |
47 | 52 | end |
48 | 53 |
|
49 | | -function <ₑ(a::Symbol, b::Symbol) |
50 | | - # Enforce the order [+,-,\,/,^,*] |
51 | | - if b === :* |
52 | | - a in (:^, :/, :\, :-, :+) |
53 | | - elseif b === :^ |
54 | | - a in (:/, :\, :-, :+) && return true |
55 | | - elseif b === :/ |
56 | | - a in (:\, :-, :+) && return true |
57 | | - elseif b === :\ |
58 | | - a in (:-, :+) && return true |
59 | | - elseif b === :- |
60 | | - a === :+ && return true |
61 | | - elseif a in (:*, :^, :/, :-, :+) |
62 | | - false |
63 | | - else |
64 | | - a < b |
| 54 | +function lexlt(degs1, degs2) |
| 55 | + for (a, b) in zip(degs1, degs2) |
| 56 | + if a[1] == b[1] && a[2] != b[2] |
| 57 | + return a[2] > b[2] |
| 58 | + elseif a[1] != b[1] |
| 59 | + return a < b |
| 60 | + end |
65 | 61 | end |
| 62 | + return false # they are equal |
66 | 63 | end |
67 | 64 |
|
68 | | -<ₑ(a::Function, b::Function) = nameof(a) <ₑ nameof(b) |
69 | | - |
70 | | -<ₑ(a::Type, b::Type) = nameof(a) <ₑ nameof(b) |
71 | | - |
72 | | -function cmp_term_term(a, b) |
73 | | - la = arglength(a) |
74 | | - lb = arglength(b) |
| 65 | +_arglen(a) = istree(a) ? length(unsorted_arguments(a)) : 0 |
75 | 66 |
|
76 | | - if la == 0 && lb == 0 |
77 | | - return operation(a) <ₑ operation(b) |
78 | | - elseif la === 0 |
79 | | - return operation(a) <ₑ b |
80 | | - elseif lb === 0 |
81 | | - return a <ₑ operation(b) |
82 | | - end |
83 | | - |
84 | | - na = operation(a) |
85 | | - nb = operation(b) |
86 | | - |
87 | | - if 0 < arglength(a) <= 2 && 0 < arglength(b) <= 2 |
88 | | - # e.g. a < sin(a) < b ^ 2 < b |
89 | | - @goto compare_args |
| 67 | +function <ₑ(a::Tuple, b::Tuple) |
| 68 | + for (x, y) in zip(a, b) |
| 69 | + if x <ₑ y |
| 70 | + return true |
| 71 | + elseif y <ₑ x |
| 72 | + return false |
| 73 | + end |
90 | 74 | end |
| 75 | + return length(a) < length(b) |
| 76 | +end |
91 | 77 |
|
92 | | - if na !== nb |
93 | | - return na <ₑ nb |
94 | | - elseif arglength(a) != arglength(b) |
95 | | - return arglength(a) < arglength(b) |
96 | | - else |
97 | | - @label compare_args |
98 | | - aa, ab = arguments(a), arguments(b) |
99 | | - if length(aa) !== length(ab) |
100 | | - return length(aa) < length(ab) |
| 78 | +function <ₑ(a::BasicSymbolic, b::BasicSymbolic) |
| 79 | + da, db = get_degrees(a), get_degrees(b) |
| 80 | + fw = monomial_lt(da, db) |
| 81 | + bw = monomial_lt(db, da) |
| 82 | + if fw === bw && !isequal(a, b) |
| 83 | + if _arglen(a) == _arglen(b) |
| 84 | + return (operation(a), arguments(a)...,) <ₑ (operation(b), arguments(b)...,) |
101 | 85 | else |
102 | | - terms = zip(Iterators.filter(!is_literal_number, aa), Iterators.filter(!is_literal_number, ab)) |
103 | | - |
104 | | - for (x,y) in terms |
105 | | - if x <ₑ y |
106 | | - return true |
107 | | - elseif y <ₑ x |
108 | | - return false |
109 | | - end |
110 | | - end |
111 | | - |
112 | | - # compare the numbers |
113 | | - nums = zip(Iterators.filter(is_literal_number, aa), |
114 | | - Iterators.filter(is_literal_number, ab)) |
115 | | - |
116 | | - for (x,y) in nums |
117 | | - if x <ₑ y |
118 | | - return true |
119 | | - elseif y <ₑ x |
120 | | - return false |
121 | | - end |
122 | | - end |
123 | | - |
| 86 | + return _arglen(a) < _arglen(b) |
124 | 87 | end |
125 | | - return na <ₑ nb # all args are equal, compare the name |
| 88 | + else |
| 89 | + return fw |
126 | 90 | end |
127 | 91 | end |
0 commit comments