# -*- coding: utf-8 -*-
"""
Sympy helpers
"""
from __future__ import absolute_import, division, print_function
import numpy as np
import six
import utool as ut
import ubelt as ub
[docs]def custom_sympy_attrs(mat):
import sympy
def matmul(other, hold=True):
if hold:
new = sympy.MatMul(mat, other)
else:
new = mat.multiply(other)
custom_sympy_attrs(new)
return new
def inv_():
new = mat.inv()
custom_sympy_attrs(new)
return new
setattr(mat, 'matmul', matmul)
setattr(mat, 'inv_', inv_)
return mat
[docs]def sympy_mat(arr):
import sympy
mat = sympy.Matrix(arr)
mat = custom_sympy_attrs(mat)
return mat
[docs]def evalprint(str_, globals_=None, locals_=None, simplify=False):
import sympy
if globals_ is None:
globals_ = ut.get_parent_frame().f_globals
if locals_ is None:
locals_ = ut.get_parent_frame().f_locals
if isinstance(str_, six.string_types):
var = eval(str_, globals_, locals_)
else:
var = str_
str_ = ut.get_varname_from_stack(var, N=1)
if simplify is True:
var = sympy.simplify(var)
print(ub.hzcat(str_ + ' = ', repr(var)))
[docs]def check_expr_eq(expr1, expr2, verbose=True):
"""
Does not work in general. Problem is not decidable.
Thanks Richard.
Args:
expr1 (?):
expr2 (?):
CommandLine:
python -m vtool.symbolic --test-check_expr_eq
SeeALso:
vt.symbolic_randcheck
Example:
>>> # DISABLE_DOCTEST
>>> from vtool.symbolic import * # NOQA
>>> expr1 = sympy.Matrix([ [sx*x + 1.0*tx + w1*y], [sy*y + 1.0*ty + w2*x], [1.0]])
>>> expr2 = sympy.Matrix([ [sx*x + tx + w1*y], [sy*y + ty + w2*x], [1]])
>>> result = check_expr_eq(expr1, expr2)
>>> print(result)
"""
import sympy
if isinstance(expr1, six.string_types):
expr1 = sympy.simplify(expr1)
if isinstance(expr2, six.string_types):
expr2 = sympy.simplify(expr2)
print(ub.hzcat('Checking if ', repr(expr1), ' == ', repr(expr2)))
random_point_check = expr1.equals(expr2)
if random_point_check is None:
failexpr = expr1.equals(expr2, failing_expression=True)
print('failexpr = %r' % (failexpr,))
random_point_check = False
print('... seems %r' % (random_point_check,))
# return random_point_check
expr3 = expr1 - expr2
if not random_point_check and True:
common_symbols = expr1.free_symbols.intersection(expr2.free_symbols)
if len(common_symbols):
y = sympy.symbols('y') # Hack, should be a new symbol
symbol = common_symbols.pop()
soln1 = sympy.solve(sympy.Eq(sympy.simplify(expr1), y), symbol)
soln2 = sympy.solve(sympy.Eq(sympy.simplify(expr2), y), symbol)
print('Solving expr1 for common symbol: ' + str(soln1))
print('Solving expr2 for common symbol: ' + str(soln2))
if soln1 == soln2:
print('This seems True')
else:
print('This seems False')
sympy.solve(sympy.Eq(sympy.simplify(expr2), y), 'd')
print(ub.hzcat('... checking 0 ', repr(expr3)))
# Does not always work.
print('(not gaurenteed to work) expr3.is_zero = %r' % (expr3.is_zero,))
return expr3.is_zero
[docs]def symbolic_randcheck(expr1, expr2, domain={}, n=10):
def get_domain(key, domain={}, rng=np.random):
min_, max_ = domain.get(key, (-100, 100))
range_ = max_ - min_
return (rng.rand() * (range_)) + min_
num_checks = n
input_list = []
results_list = []
for num in range(num_checks):
expr1_subs = {key: get_domain(key, domain) for key in expr1.free_symbols}
expr2_subs = {
key: expr1_subs[key] if key in expr1_subs else get_domain(key, domain)
for key in expr2.free_symbols
}
expr1_value = expr1.evalf(subs=expr1_subs)
expr2_value = expr2.evalf(subs=expr2_subs)
input_list.append((expr1_subs, expr2_subs))
results_list.append((expr1_value, expr2_value))
results_list = np.array(results_list)
# truth_list = np.allclose(results_list.T[0], results_list.T[1])
truth_list = results_list.T[0] == results_list.T[1]
return truth_list, results_list, input_list
[docs]def sympy_latex_repr(expr1):
import sympy
expr1_repr = sympy.latex(expr1)
expr1_repr = expr1_repr.replace('\\\\', '\\\\\n')
expr1_repr = expr1_repr.replace(r'\left[\begin{smallmatrix}{}', '\\MAT{\n')
expr1_repr = expr1_repr.replace(r'\end{smallmatrix}\right]', '\n}')
expr1_repr = expr1_repr.replace(r'\left[\begin{matrix}', '\\BIGMAT{\n')
expr1_repr = expr1_repr.replace(r'\end{matrix}\right]', '\n}')
expr1_repr = expr1_repr.replace(r'\left (', '(')
expr1_repr = expr1_repr.replace(r'\right )', ')')
expr1_repr = expr1_repr.replace(r'\left(', '(')
expr1_repr = expr1_repr.replace(r'\right)', ')')
# hack of align
expr1_repr = ut.align(expr1_repr, '&', pos=None)
return expr1_repr
# print(expr1_repr)
[docs]def sympy_numpy_repr(expr1):
import re
expr1_repr = repr(expr1)
expr1_repr = expr1_repr.replace('Matrix', 'np.array')
expr1_repr = re.sub('\\bsin\\b', 'np.sin', expr1_repr)
expr1_repr = re.sub('\\bcos\\b', 'np.cos', expr1_repr)
expr1_repr = ut.autoformat_pep8(expr1_repr)
print(expr1_repr)
# import autopep8
# autopep8.fix_code(expr1_repr)
"""
Symbolic Scrap Work:
The number of negative reviews needed is usually much larger than the number of
positive reviews.
import sympy
from sympy.abc import theta
import sympy.stats
from sympy.stats import E as mean
items = sympy.symbols('a, b, c, d')
from sympy.stats import FiniteRV, P, E
density = {0: .1, 1: .2, 2: .3, 3: .4}
X = FiniteRV('X', density)
cs = sympy.stats.FiniteRV(str('X'), {0: .5, 1: .5})
cs = [[None] * np.random.randint(10) for _ in range(1)]
print(sum(len(c) - 1 for c in cs))
print(np.mean([len(c) for c in cs]) * len(cs) - len(cs))
ori = theta
x, y, iv11, iv21, iv22, patch_size = sympy.symbols('x y iv11 iv21 iv22 S')
"""
if __name__ == '__main__':
"""
CommandLine:
xdoctest -m vtool.symbolic
"""
import xdoctest
xdoctest.doctest_module(__file__)