2016-07-08 5 views
3

У меня есть функция SymPy lambdify d с dot продукта в нем, например,SymPy: lambdified точка() с (3, п) -array

import numpy as np 
import sympy 


class dot(sympy.Function): 
    pass 


x = sympy.Symbol('x') 
a = sympy.Matrix([1, 1, 1]) 
f = dot(x, a) 

ff = sympy.lambdify((x), f, modules='numpy') 

x = np.random.rand(3) 
print(ff(x)) # okay 

(Жутко, декларация работы пользовательских dot . не знаю, почему именно, но это не важно. Если есть лучшее решение, дайте мне знать.)

Я бы сейчас хотел бы назвать ff с кучей векторов сразу, поэтому я пошел

x = np.random.rand(3, 10) 
print(ff(x)) 

Неплохо!

ValueError: shapes (3,10) and (3,1) not aligned: 10 (dim 1) != 3 (dim 0) 

Хорошо, так что я как-то перенести первый аргумент dot. Использование старого старого .T на sympy.Symbol('x') не является законным.

Любые подсказки о том, как делать массовые точечные продукты из выражения ягненка sympy?

+1

О, эй, я не понимал, что вы автор matlab2tikz. Удивительная работа! :) –

+1

Спасибо! Проверьте https://github.com/nschloe/matplotlib2tikz, если вы хотите активировать свою сюжетную игру. –

ответ

3

Вы делаете несколько странных вещей, но я не могу сказать, насколько это связано с упрощенным MCVE.

Во-первых, немного более элегантное определение вашей функции:

import sympy as sym  

x = sym.Symbol('x') 
a = sym.Matrix([1, 1, 1]) 
dot = sym.Function('dot') 
f = dot(x, a) 

ff = sym.lambdify(x, f, modules='numpy') 

Причина этого и ваш оригинальный ляп работает, потому что все, что вы должны добиться того, чтобы иметь что-то , который говорит «dot». После этого lambdify заменит np.dot той части вашего символа.

Теперь, просто для полноты картины, вот как я бы сделал это вместо:

import numpy as np 

a = np.array([[1],[1],[1]]) 
ff = lambda x,a=a: np.dot(x,a) 

Я знаю, что это не может быть вариантом в вашей конкретной проблеме, но мой опыт показывает, что если что-то может быть сделано без символической математике, тогда это стоит делать так.

Теперь для вашей ошибки. Ошибка довольно ясна, и математика тоже. Вы определили функцию, которая для любого входа x вычисляет x*a с вектором 3d-столбца a. Как показывает ошибка, это имеет смысл в очень ограниченном числе случаев. Было бы разумно, если бы оба операнда были 3-элементными 1d-массивами, в этом случае скалярное произведение было бы возвращено. Однако, поскольку один из ваших операндов фиксирован до формы (3,1), np.dot выполняет только умножение матрицы (и для векторного ввода возвращает 1-элементный 1-й массив вместо скаляра). Благодаря вашему определению он работает только с матрицами, которые могут быть умножены справа на a, то есть матрицы формы (N,3). Ясно, что это не так для вашего ввода.

Что вы должны сделать, транспонировать x на числовой стороне:

x = np.random.rand(3,10) 
print(ff(x.T)) 

Это ввести массив формы (10,3) в функцию, которая затем умножает его одним из формы (3,1), в результате чего 2d-массив формы (10,1): вектор-столбец, каждая строка содержит скалярное произведение, если данный входной вектор равен a.

Другой вариант поменять определение вашей функции:

f = dot(a.T,x) 
ff = sym.lambdify(x, f, modules='numpy') 
# or 
a = np.array(1,1,1) # transpose of previous a 
ff = lambda x,a=a: np.dot(a,x) 

Оба создать функцию, которая умножать массив формы (1,3) с правой стороны с входом. Тогда ваш ввод x формы (3,10) непосредственно совместим; выход будет 1d массивом из 10 скалярных продуктов. В этой формулировке

Смежные вопросы