2009-07-23 3 views
1

Я ищу общий способ python для управления текстом в разрешимые уравнения.Переупорядочить уравнения для решателя

Например:

могут быть некоторые константы для инициализации

e1,e2=0.58,0.62 
ma1,ma2=0.85,1.15 
mw=0.8 
Cpa,Cpw=1.023,4.193 
dba,dbr=0.0,25.0 

и набор уравнений (здесь написано для удобства чтения, а не решателя)

Q=e1*ma1*Cpa*(tw1-dba) 
Q=ma1*Cpa*(dbs-dba) 
Q=mw*Cpw*(tw1-tw2) 
Q=e2*ma2*Cpa*(dbr-tw2) 
Q=ma2*Cpa*(dbr-dbo) 

Это оставляет 5 неизвестных, поэтому, по-видимому, система может быть решена.

Q, dbo, dbr, tw1, tw2 

Фактические системы являются нелинейными и сложнее.

Я уже решил этот простой пример с помощью Scipy, Delphi, Sage ... поэтому я не ищу решающую часть.

Уравнения напечатаны непосредственно в текстовом редакторе, и я хочу, чтобы программа Python давала мне массив неизвестных и массив функций ошибок.

y = mysolver.fsolve(f, x) 

Таким образом, для приведенного выше примера

x=[Q,dbo,dbr,tw1,tw2] 

f=[Q-e1*ma1*Cpa*(tw1-dba), Q-ma1*Cpa*(dbs-dba), Q-mw*Cpw*(tw1-tw2), 
    Q-e2*ma2*Cpa*(dbr-tw2), Q-ma2*Cpa*(dbr-dbo)] 

Я просто не знаю, как извлечь неизвестные и создать функции ошибок.

Я пробовал функцию compile.parse() и, похоже, давал структурированную разбивку.

Может кто-нибудь дать некоторые идеи по наилучшему подходу.

+0

Вам нужно разрешить синтаксис «списка»? (a, b = 1,2) Возможно, вам будет легче подойти, если вы не ... – Stobor

+0

Нет, я просто сделал это, чтобы сделать постоянное назначение более компактным. Как это может помочь присвоить значения индивидуально? – 2009-07-23 14:38:23

+0

Долгое время назад была программа Borland под названием Eureka, которая решает эту проблему. Тот же код был выпущен позднее автором как Меркурий. Спустя много лет вышла Windows-программа под названием EES (Engineering Equation Solver), но решатель никогда не был так хорош, как Eureka. В последнее время я нашел код в сети Clifford Wolf http://svn.clifford.at/tools/trunk/electrotools/eqsolver.html , но он есть в JavaScript и, честно говоря, я не следую его логике. Это в значительной степени то, что я хочу, но в Python. – 2009-07-24 02:34:52

ответ

1

Если вы не хотите писать парсер для своего языка выражения, вы действительно можете попытаться использовать синтаксис Python. Не используйте модуль компилятора; вместо этого используйте какой-то абстрактный синтаксис. Так как 2.5, вы можете использовать модуль _ast:

py> import _ast                  
py> tree = compile("e1,e2=0.58,0.62", "<string>", "exec", _ast.PyCF_ONLY_AST) 
py> tree 
<_ast.Module object at 0xb7cd5fac>          
py> tree.body[0] 
<_ast.Assign object at 0xb7cd5fcc> 
py> tree.body[0].targets[0] 
<_ast.Tuple object at 0xb7cd5fec> 
py> tree.body[0].targets[0].elts 
[<_ast.Name object at 0xb7cd5e4c>, <_ast.Name object at 0xb7cd5f6c>] 
py> tree.body[0].targets[0].elts[0].id 
'e1' 
py> tree.body[0].targets[0].elts[1].id 
'e2' 

В более ранних версиях, вы должны использовать parser.suite, который дает вам конкретно-синтаксическое дерево, которое является более трудным процессом.

+0

Я не уверен, что понимаю, как я получаю от этого к векторам x = [] и f = [] Я нашел здесь вызов (разбор уравнения с использованием re без использования eval). Некоторые из кода выглядят довольно многообещающими, поэтому я буду экспериментировать с этой идеей. – 2009-07-23 14:38:14

+0

его страница http://stackoverflow.com/questions/928563/code-golf-evaluating-mathematics-expressions – 2009-07-23 14:46:35

2

На самом деле, я реализовал точно то же самое в python. Я также знаком с Eureka и другими программами, которые вы упомянули. Вы можете увидеть мою реализацию на xyzsolve.appspot.com (Извините за бесстыдный плагин). Реализация выполняется во всех python. Я перечислил итерации кода, который прошел код:

Итерация # 0: Простой поиск замените для каждой переменной в уравнении и замените переменную на ее значение. Например, x * y станет 1.1 * 2.2, если значения x и y равны 1.1 и 2.2. После того, как вы получите преобразованную строку, вы можете просто использовать eval и поместить ее значение в остаточный (или f-вектор, в вашем случае). Функция fsolve/fmin Scipy позволяет передавать дополнительные аргументы в вашу остаточную функцию, поэтому используйте это. То есть передайте словарь, содержащий индекс каждой именованной переменной. Ваш dict должен содержать что-то вроде {'x': 0, 'y': 1}, а затем вы можете просто выполнить поиск и заменить для каждого уравнения. Это работает, но очень медленно, так как вы должны выполнять поиск-замену каждый раз, когда вызывается остаточная функция.

Итерация # 1: Выполнять то же самое, что итерация # 0, за исключением замены переменных элементом массива x непосредственно, поэтому 'y' станет «x [1]».Фактически вы можете сделать все это для создания строки функции; что-то похожее на «def f (x): return x [0] + x [1], x [0] - x [1]». Затем вы можете использовать функцию exec в python для создания функции для перехода к fsolve/fmin. Нет скорости, и вы можете остановиться в этой точке, если ваши уравнения находятся в форме действительного синтаксиса python. Вы не можете сделать больше с этим подходом, если хотите поддерживать более обширный формат ввода уравнений.

Итерация # 2: Внедрение пользовательского лексера и синтаксического анализатора. Это не так сложно сделать, как кажется. Я использовал http://www.evanfosmark.com/2009/02/sexy-lexing-with-python/ для лексера. Я создал рекурсивный синтаксический анализатор (это не сложно, всего 100 строк кода) для анализа каждого уравнения. Это дает вам полную гибкость с форматом уравнений. Я просто отслеживаю переменные, константы, которые возникают с каждой стороны уравнения в отдельных списках. Когда анализатор анализирует уравнение, он строит строку уравнений, которая выглядит как «var_000 + var_001 * var_002» и т. Д. Наконец, я просто заменяю «var_000» соответствующим индексом из x-вектора. Таким образом, «var_000» становится «x [0]» и т. Д. Если вы хотите, вы можете построить АСТ и сделать много более сложных преобразований, но я остановился здесь.

Наконец, вы также можете рассмотреть тип входных уравнений. Существует немало безобидных нелинейных уравнений, которые не будут решаться с помощью fsolve (он использует MINPACK hybrdj). Вероятно, вам также нужен способ ввода исходных догадок.

Мне было бы интересно услышать, есть ли другие альтернативные способы сделать это.