| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- import math
- from .utils import dividers, is_prime
- from ..node import ExpressionLeaf as Leaf, Scope, OP_SQRT, OP_MUL, sqrt
- from ..possibilities import Possibility as P, MESSAGES
- from ..translate import _
- def is_eliminateable_sqrt(n):
- """
- Check if the square root of n can be evaluated so that the square root
- disappears (is eliminated).
- """
- if isinstance(n, int):
- return n > 3 and int(math.sqrt(n)) ** 2 == n
- if n.negated:
- return False
- if n.is_numeric():
- return is_eliminateable_sqrt(n.value)
- return n.is_power(2)
- def match_reduce_sqrt(node):
- """
- sqrt(a ^ 2) -> a
- sqrt(a) and eval(sqrt(a)) in Z -> eval(sqrt(a))
- sqrt(a) and a == b ^ 2 * c with a,b,c in Z -> sqrt(eval(b ^ 2) * c)
- sqrt(ab) -> sqrt(a)sqrt(b)
- """
- assert node.is_op(OP_SQRT)
- exp = node[0]
- if exp.negated:
- return []
- if exp.is_power(2):
- return [P(node, quadrant_sqrt)]
- if exp.is_numeric():
- reduced = int(math.sqrt(exp.value))
- if reduced ** 2 == exp.value:
- return [P(node, constant_sqrt, (reduced,))]
- div = filter(is_eliminateable_sqrt, dividers(exp.value))
- div.sort(lambda a, b: cmp(is_prime(b), is_prime(a)))
- return [P(node, split_dividers, (m, exp.value / m)) for m in div]
- if exp.is_op(OP_MUL):
- scope = Scope(exp)
- p = []
- for n in scope:
- if is_eliminateable_sqrt(n):
- p.append(P(node, extract_sqrt_mult_priority, (scope, n)))
- else:
- p.append(P(node, extract_sqrt_multiplicant, (scope, n)))
- return p
- return []
- def quadrant_sqrt(root, args):
- """
- sqrt(a ^ 2) -> a
- """
- return root[0][0].negate(root.negated)
- MESSAGES[quadrant_sqrt] = \
- _('The square root of a quadrant reduces to the raised root.')
- def constant_sqrt(root, args):
- """
- sqrt(a) and eval(sqrt(a)) in Z -> eval(sqrt(a))
- """
- return Leaf(args[0]).negate(root.negated)
- MESSAGES[constant_sqrt] = \
- _('The square root of {0[0]} is {1}.')
- def split_dividers(root, args):
- """
- sqrt(a) and b * c = a with a,b,c in Z -> sqrt(a * b)
- """
- b, c = args
- return sqrt(Leaf(b) * c)
- MESSAGES[split_dividers] = _('Write {0[0]} as {1} * {2} to so that {1} can ' \
- 'be brought outside of the square root.')
- def extract_sqrt_multiplicant(root, args):
- """
- sqrt(ab) -> sqrt(a)sqrt(b)
- """
- scope, a = args
- scope.remove(a)
- return (sqrt(a) * sqrt(scope.as_nary_node())).negate(root.negated)
- MESSAGES[extract_sqrt_multiplicant] = _('Extract {2} from {0}.')
- def extract_sqrt_mult_priority(root, args):
- """
- sqrt(ab) and sqrt(a) in Z -> sqrt(a)sqrt(b)
- """
- return extract_sqrt_multiplicant(root, args)
- MESSAGES[extract_sqrt_mult_priority] = MESSAGES[extract_sqrt_multiplicant]
|