| 2379 | } |
| 2380 | if (u.operator === 'Multiply' && u.ops) return u.ops.every(niceSqrtAux); |
| 2381 | return !fracPowerFactorQ(rtExpr(u, 2)); |
| 2382 | } |
| 2383 | |
| 2384 | /** Rubi SimplerSqrtQ[u,v] — is √u simpler than √v */ |
| 2385 | function simplerSqrtQ(u: Expression, v: Expression): boolean { |
| 2386 | const ltZero = (e: Expression): boolean => { |
| 2387 | const r = realNum(e) ?? realNum(safeSimplify(e)); |
| 2388 | return r !== null && r < 0; |
| 2389 | }; |
| 2390 | if (ltZero(v) && !ltZero(u)) return true; |
| 2391 | if (ltZero(u) && !ltZero(v)) return false; |
| 2392 | const su = rtExpr(u, 2); |
| 2393 | const sv = rtExpr(v, 2); |
| 2394 | if (isLiteralInteger(su)) |
| 2395 | return isLiteralInteger(sv) ? realNum(su)! < realNum(sv)! : true; |
| 2396 | if (isLiteralInteger(sv)) return false; |
| 2397 | if (isLiteralRational(su)) |
| 2398 | return isLiteralRational(sv) ? realNum(su)! < realNum(sv)! : true; |
| 2399 | if (isLiteralRational(sv)) return false; |
| 2400 | if (posQ(u)) return posQ(v) ? leafCount(su) < leafCount(sv) : true; |
| 2401 | if (posQ(v)) return false; |
| 2402 | if (leafCount(su) < leafCount(sv)) return true; |
| 2403 | if (leafCount(sv) < leafCount(su)) return false; |
| 2404 | // ~ Not[OrderedQ[{v,u}]] — canonical-order tiebreak |
| 2405 | return u.toString() < v.toString(); |
| 2406 | } |
| 2407 | |
| 2408 | /** Rubi RationalFunctionQ — u is a rational function of x */ |
| 2409 | export function rationalFnQ(u: Expression, x: string): boolean { |
| 2410 | if (!u.ops || !u.has(x)) return true; |
| 2411 | switch (u.operator) { |
| 2412 | case 'Power': |
| 2413 | return isLiteralInteger(u.ops[1]) && rationalFnQ(u.ops[0], x); |
| 2414 | case 'Add': |
| 2415 | case 'Subtract': |
| 2416 | case 'Negate': |
| 2417 | case 'Multiply': |
| 2418 | case 'Divide': |
| 2419 | return u.ops.every((o) => rationalFnQ(o, x)); |
| 2420 | } |
| 2421 | return false; |
| 2422 | } |
| 2423 | |
| 2424 | /** Rubi AlgebraicFunctionQ — u is an algebraic function of x */ |