Return expression as numer-denom pair.
(obj)
| 1113 | |
| 1114 | |
| 1115 | def as_numer_denom(obj): |
| 1116 | """Return expression as numer-denom pair. |
| 1117 | """ |
| 1118 | if isinstance(obj, Expr): |
| 1119 | obj = normalize(obj) |
| 1120 | if obj.op in (Op.INTEGER, Op.REAL, Op.COMPLEX, Op.SYMBOL, |
| 1121 | Op.INDEXING, Op.TERNARY): |
| 1122 | return obj, as_number(1) |
| 1123 | elif obj.op is Op.APPLY: |
| 1124 | if obj.data[0] is ArithOp.DIV and not obj.data[2]: |
| 1125 | numers, denoms = map(as_numer_denom, obj.data[1]) |
| 1126 | return numers[0] * denoms[1], numers[1] * denoms[0] |
| 1127 | return obj, as_number(1) |
| 1128 | elif obj.op is Op.TERMS: |
| 1129 | numers, denoms = [], [] |
| 1130 | for term, coeff in obj.data.items(): |
| 1131 | n, d = as_numer_denom(term) |
| 1132 | n = n * coeff |
| 1133 | numers.append(n) |
| 1134 | denoms.append(d) |
| 1135 | numer, denom = as_number(0), as_number(1) |
| 1136 | for i in range(len(numers)): |
| 1137 | n = numers[i] |
| 1138 | for j in range(len(numers)): |
| 1139 | if i != j: |
| 1140 | n *= denoms[j] |
| 1141 | numer += n |
| 1142 | denom *= denoms[i] |
| 1143 | if denom.op in (Op.INTEGER, Op.REAL) and denom.data[0] < 0: |
| 1144 | numer, denom = -numer, -denom |
| 1145 | return numer, denom |
| 1146 | elif obj.op is Op.FACTORS: |
| 1147 | numer, denom = as_number(1), as_number(1) |
| 1148 | for b, e in obj.data.items(): |
| 1149 | bnumer, bdenom = as_numer_denom(b) |
| 1150 | if e > 0: |
| 1151 | numer *= bnumer ** e |
| 1152 | denom *= bdenom ** e |
| 1153 | elif e < 0: |
| 1154 | numer *= bdenom ** (-e) |
| 1155 | denom *= bnumer ** (-e) |
| 1156 | return numer, denom |
| 1157 | raise OpError(f'cannot convert {type(obj)} to numer and denom') |
| 1158 | |
| 1159 | |
| 1160 | def _counter(): |
searching dependent graphs…