Solving a System of Two Differential Equations Numerically in Python
![]()
Let’s suppose we have the following set of differential equations:
Y and P could be two populations of animals in the same area. Therefore the growth of one population depends of the number of predator animals of the other species. For every calculation the initial populations should be given. In the first model both initial populations are set to 20.
The code
Now that we’ve determined our model it’s time to write a python program to calculate the size of the populations after a given period of time.
First, we need to import the Numpy and Matplotlib libraries. Then we can set the initial values. We have to determine a time step for the approximations, the values of Y and P at the beginning. We also need a start and end time to calculate the number of steps we have to calculate.
Then we can create empty arrays to store the calculated values at any time. We should fill in element 0 with the assigned initial values.
Now it’s time to create a for loop that will iterate every timestep and calculate the next values of P, Y and t given their differential equations. If you’d like to experiment with different differential equations you can do that here.
Finally, we can plot how P and Y change over time.
As you can see, an equilibrium is reached. We have now solved this system of differential equations. You can play around with this code and change some variables and look how the results change, or if the equilibrium point is reached, or maybe even a different equilibrium. You should still make sure to choose an appropriate dt time step.
Phase diagram
If we plot Y against P instead of against t, we get a so called phase diagram, which is quite useful for studying equilibria. In this case it’s not as exciting, but is can create a pretty image. In this case all three initial combinations converge to a single point. This one is called a spiral sink.
If you’ve understood this code and the theories supporting it, you have a great basis to numerically solve any system of differential equations.
Solvers¶
The solvers module in SymPy implements methods for solving equations.
It is recommended to use solveset() to solve univariate equations and sympy.solvers.solveset.linsolve() to solve system of linear equations instead of solve() , since sooner or later the solveset will take over solve either internally or externally.
Algebraic equations¶
Use solve() to solve algebraic equations. We suppose all equations are equaled to 0, so solving x**2 == 1 translates into the following code:
The first argument for solve() is an equation (equaled to zero) and the second argument is the symbol that we want to solve the equation for.
Algebraically solves equations and systems of equations.
- polynomial,
- transcendental
- piecewise combinations of the above
- systems of linear and polynomial equations
- sytems containing relational expressions.
Input is formed as:
- f
- a single Expr or Poly that must be zero,
- an Equality
- a Relational expression or boolean
- iterable of one or more of the above
- none given (other non-numeric objects will be used)
- single symbol
- denested list of symbols e.g. solve(f, x, y)
- ordered iterable of symbols e.g. solve(f, [x, y])
return list (perhaps empty) of solution mappings
‘set’=True (default is False)
return list of symbols and set of tuple(s) of solution(s)
don’t try to solve for any of the free symbols in exclude; if expressions are given, the free symbols in them will be extracted automatically.
If False, don’t do any testing of solutions. This can be useful if one wants to include solutions that make any denominator zero.
do a fast numerical check if f has only one symbol.
‘minimal=True (default is False)’
a very fast, minimal testing.
‘warn=True (default is False)’
show a warning if checksol() could not conclude.
simplify all but polynomials of order 3 or greater before returning them and (if check is not False) use the general simplify function on the solutions and the expression obtained when they are substituted into the function which should be zero
‘force=True (default is False)’
make positive all symbols without assumptions regarding sign.
recast Floats as Rational; if this option is not used, the system containing floats may fail to solve because of issues with polys. If rational=None, Floats will be recast as rationals but the answer will be recast as Floats. If the flag is False then nothing will be done to the Floats.
‘manual=True (default is False)’
do not use the polys/matrix method to solve a system of equations, solve them one at a time as you might “manually”
‘implicit=True (default is False)’
allows solve to return a solution for a pattern in terms of other functions that contain that pattern; this is only needed if the pattern is inside of some invertible function like cos, exp, .
‘particular=True (default is False)’
instructs solve to try to find a particular solution to a linear system with as many zeros as possible; this is very expensive
‘quick=True (default is False)’
when using particular=True, use a fast heuristic instead to find a solution with many zeros (instead of using the very slow method guaranteed to find the largest number of zeros possible)
return explicit solutions when cubic expressions are encountered
return explicit solutions when quartic expressions are encountered
return explicit solutions (if possible) when quintic expressions are encountered
solve() with check=True (default) will run through the symbol tags to elimate unwanted solutions. If no assumptions are included all possible solutions will be returned.
By using the positive tag only one solution will be returned:
Assumptions aren’t checked when \(solve()\) input involves relationals or bools.
When the solutions are checked, those that make any denominator zero are automatically excluded. If you do not want to exclude such solutions then use the check=False option:
If check=False then a solution to the numerator being zero is found: x = 0. In this case, this is a spurious solution since sin(x)/x has the well known limit (without dicontinuity) of 1 at x = 0:
In the following case, however, the limit exists and is equal to the the value of x = 0 that is excluded when check=True:
The output varies according to the input and can be seen by example:
boolean or univariate Relational
to always get a list of solution mappings, use flag dict=True
to get a list of symbols and set of solution(s) use flag set=True
single expression and single symbol that is in the expression
single expression with no symbol that is in the expression
single expression with no symbol given
In this case, all free symbols will be selected as potential symbols to solve for. If the equation is univariate then a list of solutions is returned; otherwise – as is the case when symbols are given as an iterable of length > 1 – a list of mappings will be returned.
when an object other than a Symbol is given as a symbol, it is isolated algebraically and an implicit solution may be obtained. This is mostly provided as a convenience to save one from replacing the object with a Symbol and solving for that Symbol. It will only work if the specified object can be replaced with a Symbol using the subs method.
-
To solve for a symbol implicitly, use ‘implicit=True’:
single expression and more than 1 symbol
-
when there is a linear solution
-
that are linear
if there is no linear solution then the first successful attempt for a nonlinear solution will be returned
iterable of one or more of the above
-
involving relationals or bools
-
with a solution
when the system is not linear
if no symbols are given, all free symbols will be selected and a list of mappings returned
if any equation doesn’t depend on the symbol(s) given it will be eliminated from the equation set and an answer may be given implicitly in terms of variables that were not of interest
Disabling High-order, Explicit Solutions
When solving polynomial expressions, one might not want explicit solutions (which can be quite long). If the expression is univariate, CRootOf instances will be returned instead:
If the expression is multivariate, no solution might be returned:
Sometimes solutions will be obtained even when a flag is False because the expression could be factored. In the following example, the equation can be factored as the product of a linear and a quadratic factor so explicit solutions (which did not require solving a cubic expression) are obtained:
Solving Equations Involving Radicals
Because of SymPy’s use of the principle root (issue #8789), some solutions to radical equations will be missed unless check=False:
In the above example there is only a single solution to the equation. Other expressions will yield spurious roots which must be checked manually; roots which give a negative argument to odd-powered radicals will also need special checking:
The first solution is negative so real_root must be used to see that it satisfies the expression:
If the roots of the equation are not real then more care will be necessary to find the roots, especially for higher order equations. Consider the following expression:
We will construct a known value for this expression at x = 3 by selecting the 1-th root for each radical:
The solve function is unable to find any exact roots to this equation:
The function unrad, however, can be used to get a form of the equation for which numerical roots can be found:
Although eq or eq1 could have been used to find xvals, the solution can only be verified with expr1:
Return a tuple derived from f = lhs — rhs that is one of the following:
(0, 1) meaning that f is independent of the symbols in symbols that aren’t in exclude , e.g:
(0, 0) meaning that there is no solution to the equation amongst the symbols given.
(symbol, solution) where symbol appears linearly in the numerator of f , is in symbols (if given) and is not in exclude (if given). No simplification is done to f other than a mul=True expansion, so the solution will correspond strictly to a unique solution.
(n, d) where n and d are the numerator and denominator of f when the numerator was not linear in any symbol of interest; n will never be a symbol unless a solution for that symbol was found (in which case the second element is the solution, not the denominator).
The variable x appears as a linear variable in each of the following:
When not linear in x or y then the numerator and denominator are returned.
If the numerator of the expression is a symbol then (0, 0) is returned if the solution for that symbol would have set any denominator to 0:
But automatic rewriting may cause a symbol in the denominator to appear in the numerator so a solution will be returned:
Use an unevaluated expression to avoid this:
If x is allowed to cancel in the following expression, then it appears to be linear in x , but this sort of cancellation is not done by solve_linear so the solution will always satisfy the original expression without causing a division by zero error.
A list of symbols for which a solution is desired may be given:
A list of symbols to ignore may also be given:
(A solution for y is obtained because it is the first variable from the canonically sorted list of symbols that had a linear solution.)
sympy.solvers.solvers. solve_linear_system ( system, *symbols, **flags ) [source] ¶
Solve system of N linear equations with M variables, which means both under- and overdetermined systems are supported. The possible number of solutions is zero, one or infinite. Respectively, this procedure will return None or a dictionary with solutions. In the case of underdetermined systems, all arbitrary parameters are skipped. This may cause a situation in which an empty dictionary is returned. In that case, all symbols can be assigned arbitrary values.
Input to this functions is a Nx(M+1) matrix, which means it has to be in augmented form. If you prefer to enter N equations and M unknowns then use \(solve(Neqs, *Msymbols)\) instead. Note: a local copy of the matrix is made by this routine so the matrix that is passed will not be modified.
The algorithm used here is fraction-free Gaussian elimination, which results, after elimination, in an upper-triangular matrix. Then solutions are found using back-substitution. This approach is more efficient and compact than the Gauss-Jordan method.
Как решать уравнения на пайтоне
Программа, позволяющая находить корни квадратного уравнения, – это один из примеров простых программ, которые можно написать на Python 3. Она хорошо подойдет для начинающих изучать этот язык программирования.
Постановка задачи
Уравнение, которое будем решать, выглядит следующим образом: a·x²+b·x+c=0. Пользователю предлагается ввести значения a, b и с в терминале. После этого программа посчитает дискриминант. На его основе найдем решения уравнения – значения x, для которых будет выполняться равенство.
Вот пример работы программы, которая будет написана.

Программа
Для решения квадратных уравнений на Python 3 напишем код, приведенный ниже. Разберем некоторые моменты, которые мы использовали в этой простой программе:
- print — эта функция выводит на экран информацию.
- input — выводит информацию и предлагает пользователю ввести данные.
- b**2 — это возведение в степень, в данном случае переменная b возводится в квадрат.
- str — эта функция приводит данные к строковому виду.
- if-elif-else — это условные операторы в языке Python. Исходя из значения discriminant мы определяем количество корней квадратного уравнения.
- discriminant ** 0.5 — с помощью такого способа извлекаем квадратный корень. В Python есть несколько способов извлечения корней, например, с помощью функции sqrt из библиотеки math. Про способы извлечения корней в Python описано в отдельной статье.
Запустим программу и введём нужные коэффициенты.
Все посчитано, найдены два корня, которые будут являться решением квадратного уравнения.
Дополнительно
Хотелось бы уделить внимание ещё одному моменту. Если дискриминант отрицательный, то действительных корней нет. Но будут комплексные корни. Если мы хотим их обрабатывать, то следует изменить конструкцию условных операторов следующим образом:
Тогда пример решения уравнения будет выглядеть следующим образом:
Как видим, получили два комплексных корня.
Этот простой код написанный на Python 3 можно для обучения программированию немного усложнить:
- Предлагать запрос в конце программы «Решить ещё одно уравнение (y/n): ». И если пользователь введет «y», то заново запросить коэффициенты. Это нужно делать в цикле. Подробнее о циклах в Python можно прочитать здесь.
- Сделать проверку корректности ввода. Ведь пользователь вместо числа может ввести какую-нибудь строку, которая не будет корректно обработана. Про проверку на число описано в отдельной статье.
Библиотека Sympy: символьные вычисления в Python
Что такое SymPy ? Это библиотека символьной математики языка Python. Она является реальной альтернативой таким математическим пакетам как Mathematica или Maple и обладает очень простым и легко расширяемым кодом. SymPy написана исключительно на языке Python и не требует никаких сторонних библиотек.
Документацию и исходный код этой библиотеки можно найти на ее официальной странице.
Первые шаги с SymPy
Используем SymPy как обычный калькулятор
В библиотеке SymPy есть три встроенных численных типа данных: Real , Rational и Integer . С Real и Integer все понятно, а класс Rational представляет рациональное число как пару чисел: числитель и знаменатель рациональной дроби. Таким образом, Rational(1, 2) представляет собой 1/2 , а, например, Rational(5, 2) — соответственно 5/2 .
Библиотека SymPy использует библиотеку mpmath , что позволяет производить вычисления с произвольной точностью. Таким образом, ряд констант (например, пи, e), которые в данной библиотеке рассматриваются как символы, могут быть вычислены с любой точностью.
Как можно заметить, функция evalf() дает на выходе число с плавающей точкой.
В SymPy есть также класс, представляющий такое понятие в математике, как бесконечность. Он обозначается следующим образом: oo .
Символы
В отличие от ряда других систем компьютерной алгебры, в SymPy можно в явном виде задавать символьные переменные. Это происходит следующим образом:
После их задания, с ними можно производить различные манипуляции.
С символами можно производить преобразования с использованием некоторых операторов языка Python. А именно, арифметических ( + , -` , «* , ** ) и логических ( & , | ,
Библиотека SymPy позволяет задавать форму вывода результатов на экран. Обычно мы используем формат такого вида:
Алгебраические преобразования
SymPy способна на сложные алгебраические преобразования. Здесь мы рассмотрим наиболее востребованные из них, а именно раскрытие скобок и упрощение выражений.
Раскрытие скобок
Чтобы раскрыть скобки в алгебраических выражениях, используйте следующий синтаксис:
При помощи ключевого слова можно добавить поддержку работы с комплексными переменными, а также раскрытие скобок в тригонометрических функциях.
Упрощение выражений
Если вы хотите привести выражение к более простому виду (возможно, сократить какие-то члены), то используйте функцию simplify .
Также надо сказать, что для определенных видов математических функций существуют альтернативные, более конкретные функции для упрощения выражений. Так, для упрощения степенных функций есть функция powsimp , для тригонометрических — trigsimp , а для логарифмических — logcombine , radsimp .
Вычисления
Вычисления пределов
Для вычисления пределов в SymPy предусмотрен очень простой синтаксис, а именно limit(function, variable, point) . Например, если вы хотите вычислить предел функции f(x) , где x -> 0 , то надо написать limit(f(x), x, 0) .
Также можно вычислять пределы, которые стремятся к бесконечности.
Дифференцирование
Для дифференцирования выражений в SymPy есть функция diff(func, var) . Ниже даны примеры ее работы.
Проверим результат последней функции при помощи определения производной через предел.
tan 2 (?)+1 Результат тот же.
Также при помощи этой же функции могут быть вычислены производные более высоких порядков. Синтаксис функции будет следующим: diff(func, var, n) . Ниже приведено несколько примеров.
Разложение в ряд
Для разложения выражения в ряд Тейлора используется следующий синтаксис: series(expr, var) .
Интегрирование
В SymPy реализована поддержка определенных и неопределенных интегралов при помощи функции integrate() . Интегрировать можно элементарные, трансцендентные и специальные функции. Интегрирование осуществляется с помощью расширенного алгоритма Риша-Нормана. Также используются различные эвристики и шаблоны. Вот примеры интегрирования элементарных функций:
Также несложно посчитать интеграл и от специальных функций. Возьмем, например, функцию Гаусса:
Результат вычисления можете посмотреть сами. Вот примеры вычисления определенных интегралов.
Также можно вычислять определенные интегралы с бесконечными пределами интегрирования (несобственные интегралы).
Решение уравнений
При помощи SymPy можно решать алгебраические уравнения с одной или несколькими переменными. Для этого используется функция solveset() .
Как можно заметить, первое выражение функции solveset() приравнивается к 0 и решается относительно х . Также возможно решать некоторые уравнения с трансцендентными функциями.
Системы линейных уравнений
SymPy способна решать широкий класс полиномиальных уравнений. Также при помощи данной библиотеки можно решать и системы уравнений. При этом переменные, относительно которых должна быть разрешена система, передаются в виде кортежа во втором аргументе функции solve() , которая используется для таких задач.
Факторизация
Другим мощным методом исследования полиномиальных уравнений является факторизация многочленов (то есть представление многочлена в виде произведения многочленов меньших степеней). Для этого в SymPy предусмотрена функция factor() , которая способна производить факторизацию очень широкого класса полиномов.
Булевы уравнения
Также в SymPy реализована возможность решения булевых уравнений, что по сути означает проверку булевого выражения на истинность. Для этого используется функция satisfiable() .
Данный результат говорит нам о том, что выражение (x & y) будет истинным тогда и только тогда, когда x и y истинны. Если выражение не может быть истинным ни при каких значениях переменных, то функция вернет результат False .
Линейная алгебра
Матрицы
Матрицы в SymPy создаются как экземпляры класса Matrix :
В отличие от NumPy , мы можем использовать в матрицах символьные переменные:
И производить с ними разные манипуляции:
Дифференциальные уравнения
При помощи библиотеки SymPy можно решать некоторые обыкновенные дифференциальные уравнения. Для этого используется функция dsolve() . Для начала нам надо задать неопределенную функцию. Это можно сделать, передав параметр cls=Function в функцию symbols() .
Теперь f и g заданы как неопределенные функции. мы можем в этом убедиться, просто вызвав f(x) .
Теперь решим следующее дифференциальное уравнение:
Чтобы улучшить решаемость и помочь этой функции в поиске решения, можно передавать в нее определенные ключевые аргументы. Например, если мы видим, что это уравнение с разделяемыми переменными, то мы можем передать в функцию аргумент hint=’separable’ .

Английский для программистов
Наш телеграм канал с тестами по английскому языку для программистов. Английский это часть карьеры программиста. Поэтому полезно заняться им уже сейчас
Математическая библиотека Python SymPy
SymPy — это библиотека Python для выполнения символьных вычислений. Это система компьютерной алгебры, которая может выступать как отдельное приложение, так и в качестве библиотеки для других приложений. Поработать с ней онлайн можно на https://live.sympy.org/. Поскольку это чистая библиотека Python, ее можно использовать даже в интерактивном режиме.
В SymPy есть разные функции, которые применяются в сфере символьных вычислений, математического анализа, алгебры, дискретной математики, квантовой физики и так далее. SymPy может представлять результат в разных форматах: LaTeX, MathML и так далее. Распространяется библиотека по лицензии New BSD. Первыми эту библиотеку выпустили разработчики Ondřej Čertík и Aaron Meurer в 2007 году. Текущая актуальная версия библиотеки — 1.6.2.
Вот где применяется SymPy:
- Многочлены
- Математический анализ
- Дискретная математика
- Матрицы
- Геометрия
- Построение графиков
- Физика
- Статистика
- Комбинаторика
Установка SymPy
Для работы SymPy требуется одна важная библиотека под названием mpmath . Она используется для вещественной и комплексной арифметики с числами с плавающей точкой произвольной точности. Однако pip установит ее автоматически при загрузке самой SymPy:
Такие дистрибутивы, как Anaconda, Enthough, Canopy и другие, заранее включают SymPy. Чтобы убедиться в этом, достаточно ввести в интерактивном режиме команду:
Исходный код можно найти на GitHub.
Символьные вычисления в SymPy
Символьные вычисления — это разработка алгоритмов для управления математическими выражениями и другими объектами. Такие вычисления объединяют математику и компьютерные науки для решения математических выражений с помощью математических символов.
Система компьютерной алгебры же, такая как SymPy, оценивает алгебраические выражения с помощью тех же символов, которые используются в традиционных ручных методах. Например, квадратный корень числа с помощью модуля math в Python вычисляется вот так:
Как можно увидеть, квадратный корень числа 7 вычисляется приблизительно. Но в SymPy квадратные корни чисел, которые не являются идеальными квадратами, просто не вычисляются:
Вот каким будет вывод этого кода: sqrt(7) .
Это можно упростить и показать результат выражения символически таким вот образом:
В случае с модулем math вернется число, а вот в SymPy — формула.
Для рендеринга математических символов в формате LaTeX код SymPy, используйте Jupyter notebook:
Если выполнить эту команду в IDLE, то получится следующий результат:

Квадратный корень неидеального корня также может быть представлен в формате LaTeX с помощью привычных символов:

Символьные вычисления с помощью таких систем, как SymPy, помогают выполнять вычисления самого разного рода (производные, интегралы, пределы, решение уравнений, работа с матрицами) в символьном виде.
В пакете SymPy есть разные модули, которые помогают строить графики, выводить результат (LaTeX), заниматься физикой, статистикой, комбинаторикой, числовой теорией, геометрией, логикой и так далее.
Числа
Основной модуль в SymPy включает класс Number , представляющий атомарные числа. У него есть пара подклассов: Float и Rational . В Rational также входит Integer .
Класс Float
Float представляет числа с плавающей точкой произвольной точности:
SymPy может конвертировать целое число или строку в число с плавающей точкой:
При конвертации к числу с плавающей точкой, также можно указать количество цифр для точности:
Представить число дробью можно с помощью объекта класса Rational , где знаменатель — не 0:

Если число с плавающей точкой передать в конструктор Rational() , то он вернет дробь:

Для упрощения можно указать ограничение знаменателя:
Выведется дробь 1/5 вместо 3602879701896397/18014398509481984.
Если же в конструктор передать строку, то вернется рациональное число произвольной точности:

Также рациональное число можно получить, если в качестве аргументов передать два числа. Числитель и знаменатель доступны в виде свойств:
Класс Integer
Класс Integer в SymPy представляет целое число любого размера. Конструктор принимает рациональные и числа с плавающей точкой. В результате он откидывает дробную часть:
Также есть класс RealNumber , который является алиасом для Float . В SymPy есть классы-одиночки Zero и One , доступные через S.Zero и S.One соответственно.
Другие числовые объекты-одиночки — Half , NaN , Infinity и ImaginaryUnit .
Бесконечность представлена в виде объекта-символа oo или как S.Infinity :

ImaginaryUnit можно импортировать как символ I , а получить к нему доступ — через S.ImaginaryUnit .

Символы
Symbol — самый важный класс в библиотеке SymPy. Как уже упоминалось ранее, символьные вычисления выполняются с помощью символов. И переменные SymPy являются объектами класса Symbol .
Аргумент функции Symbol() — это строка, содержащая символ, который можно присвоить переменной.
Код выше является эквивалентом этого выражения:

Символ может включать больше одной буквы:
Также в SymPy есть функция Symbols() , с помощью которой можно определить несколько символов за раз. Строка содержит названия переменных, разделенные запятыми или пробелами.
В модуле abc можно найти элементы латинского и греческого алфавитов в виде символов. Таким образом вместо создания экземпляра Symbol можно использовать метод:
Однако C, O, S, I, N, E и Q являются заранее определенными символами. Также символы с более чем одной буквы не определены в abc. Для них нужно использовать объект Symbol . Модуль abs определяет специальные имена, которые могут обнаружить определения в пространстве имен SymPy по умолчанию. сlash1 содержит однобуквенные символы, а clash2 — целые слова.
Индексированные символы (последовательность слов с цифрами) можно определить с помощью синтаксиса, напоминающего функцию range() . Диапазоны обозначаются двоеточием. Тип диапазона определяется символом справа от двоеточия. Если это цифра, то все смежные цифры слева воспринимаются как неотрицательное начальное значение.
Смежные цифры справа берутся на 1 больше конечного значения.
Подстановка параметров
Одна из базовых операций в математических выражениях — подстановка. Функция subs() заменяет все случаи первого параметра на второй.
Этот код даст вывод, эквивалентный такому выражению.

А кодом expr.subs(x,a) мы получим туже формулу, но с a вместо x .
Эта функция полезна, когда требуется вычислить определенное выражение. Например, нужно посчитать значения выражения, заменив a на 5 :

Также функция используется для замены подвыражения другим подвыражением. В следующем примере b заменяется на a+b .
Это дает такой вывод:

Функция simplify()
Функция simplify() используется для преобразования любого произвольного выражения, чтобы его можно было использовать как выражение SymPy. Обычные объекты Python, такие как целые числа, конвертируются в SymPy.Integer и так далее. Строки также конвертируются в выражения SymPy:
Любой объект Python можно конвертировать в объект SymPy. Однако учитывая то, что при преобразовании используется функция eval() , не стоит использовать некорректные выражения, иначе возникнет ошибка SimplifyError .
Функция simplify() принимает следующий аргумент: strict=False . Если установить True , то преобразованы будут только те типы, для которых определено явное преобразование. В противном случае также возникнет ошибка SimplifyError . Если же поставить False , то арифметические выражения и операторы будут конвертированы в их эквиваленты SumPy без вычисления выражения.

Функция evalf()
Функция вычисляет данное числовое выражение с точностью до 100 цифр после плавающей точки. Она также принимает параметр subs , как объект словаря с числовыми значениями для символов. Например такое выражение:
Даст такой результат: ?? 2
Вычислим выражение с помощью evalf() и заменим r на 5:
По умолчанию точность после плавающей точки — 15, но это значение можно перезаписать до 100. Следующее выражение вычисляет, используя вплоть до 20 цифр точности:
Функция lambdify()
Функция lambdify() переводит выражения SymPy в функции Python. Если выражение, которое нужно вычислить, затрагивает диапазон значений, то функция evalf() становится неэффективной. Функция lambdify действует как лямбда-функция с тем исключением, что она конвертирует SymPy в имена данной числовой библиотеки, обычно NumPy. По умолчанию же она реализована на основе стандартной библиотеки math.
У выражения может быть больше одной переменной. В таком случае первым аргументом функции является список переменных, а после него — само выражение:
Но чтобы использовать numpy в качестве основной библиотеки, ее нужно передать в качестве аргумента функции lambdify() .
В этой функции использовались два массива numpy: a и b . В случае с ними выполнение гораздо быстрее:
Логические выражения
Булевы функции расположены в модуле sympy.basic.booleanarg . Их можно создать и с помощью стандартных операторов Python: & (And), | (Or),
(Not), а также >> и . Булевы выражения наследуются от класса Basic .
BooleanTrue.
Эта функция является эквивалентом True из Python. Она возвращает объект-одиночку, доступ к которому можно получить и с помощью S.true .BooleanFalse.
А эта функция является эквивалентом False . Ее можно достать с помощью S.False .And.
Функция логического AND оценивает два аргумента и возвращает False , если хотя бы один из них является False . Эта функция заменяет оператор & .Or.
Оценивает два выражения и возвращает True , если хотя бы одно из них является True . Это же поведение можно получить с помощью оператора | .Not.
Результат этой функции — отрицание булево аргумента. True, если аргумент является False , и False в противном случае. В Python за это отвечает операторXor.
Логический XOR (исключающий OR) возвращает True, если нечетное количество аргументов равняется True , а остальные — False . False же вернется в том случае, если четное количество аргументов True , а остальные — False . То же поведение работает в случае оператора ^ .В предыдущем примере один(нечетное число) аргумент является True , поэтому Xor вернет True . Если же количество истинных аргументов будет четным, результатом будет False , как показано дальше.
Nand.
Выполняет логическую операцию NAND. Оценивает аргументы и возвращает True , если хотя бы один из них равен False , и False — если они истинные.Nor.
Выполняет логическую операцию NOR. Оценивает аргументы и возвращает False , если один из них True , или же True , если все — False .Хотя SymPy и предлагает операторы ^ для Xor ,
для Not , | для Or и & для And ради удобства, в Python они используются в качестве побитовых. Поэтому если операнды будут целыми числами, результаты будут отличаться.
Equivalent.
Эта функция возвращает отношение эквивалентности. Equivalent(A, B) будет равно True тогда и только тогда, когда A и B оба будут True или False . Функция вернет True , если все аргументы являются логически эквивалентными. В противном случае — False .Запросы
Модуль assumptions в SymPy включает инструменты для получения информации о выражениях. Для этого используется функция ask() .
Следующие свойства предоставляют полезную информацию о выражении:
algebraic(x)
Чтобы быть алгебраическим, число должно быть корнем ненулевого полиномиального уравнения с рациональными коэффициентами. √2, потому что √2 — это решение x2 − 2 = 0. Следовательно, это выражения является алгебраическим.complex(x)
Предикат комплексного числа. Является истиной тогда и только тогда, когда x принадлежит множеству комплексных чисел.composite(x)
Предикат составного числа, возвращаемый ask(Q.composite(x)) является истиной тогда и только тогда, когда x — это положительное число, имеющее как минимум один положительный делитель, кроме 1 и самого числа.even, odd
ask() возвращает True , если x находится в множестве четных и нечетных чисел соответственно.imaginary
Свойство представляет предикат мнимого числа. Является истиной, если x можно записать как действительное число, умноженное на мнимую единицу.integer
Это свойство, возвращаемое Q.integer(x) , будет истинным только в том случае, если x принадлежит множеству четных чисел.rational, irrational
Q.irrational(x) истинно тогда и только тогда, когда x — это любое реальное число, которое нельзя представить как отношение целых чисел. Например, pi — это иррациональное число.positive, negative
Предикаты для проверки того, является ли число положительным или отрицательным.zero, nonzero
Предикат для проверки того, является ли число нулем или нет.Решаем систему линейных алгебраических уравнений с Python-пакетом scipy.linalg (не путать с numpy.linalg)

Аппарат линейной алгебры применяют в самых разных областях — в линейном программировании, эконометрике, в естественных науках. Отдельно отмечу, что этот раздел математики востребован в машинном обучении. Если, например, вам нужно поработать с матрицами и векторами, то, вполне возможно, на каком-то шаге вам придётся решать систему линейных алгебраических уравнений (СЛАУ).
СЛАУ — мощный инструмент моделирования процессов. Если некая хорошо изученная модель на основе СЛАУ годится для формализации задачи, то с высокой вероятностью её можно будет решить. А вот насколько быстро — это зависит от вашего инструментария и вычислительных мощностей.
Я расскажу про один из таких инструментов — Python-пакет scipy.linalg из библиотеки SciPy, который позволяет быстро и эффективно решать многие задачи с использованием аппарата линейной алгебры.
В этом туториале вы узнаете:
- как установить scipy.linalg и подготовить среду выполнения кода;
- как работать с векторами и матрицами с помощью NumPy;
- почему scipy.linalg лучше, чем numpy.linalg;
- как формализовать задачи с использованием систем линейных алгебраических уравнений;
- как решать СЛАУ с помощью scipy.linalg (на реальном примере).
Когда речь идёт о математике, изложение материала должно быть последовательным — таким, чтобы одно следовало из другого. Эта статья не исключение: сначала будет много подготовительной информации и только потом мы перейдём непосредственно к делу.
Если готовы к этому — приглашаю под кат. Хотя, честно говоря, некоторые разделы можно пропускать — например, основы работы с векторами и матрицами в NumPy (если вы хорошо знакомы с ним).
Установка scipy.linalg
SciPy — это библиотека Python с открытым исходным кодом для научных вычислений: решение СЛАУ, оптимизация, интеграция, интерполяция и обработка сигналов. Помимо linalg, она содержит несколько других пакетов — например, NumPy, Matplotlib, SymPy, IPython и pandas.
Среди прочего, scipy.linalg содержит функции для с работы с матрицами — вычисление определителя, инверсия, вычисление собственных значений и векторов, а также сингулярное разложение.
Чтобы использовать scipy.linalg, вам необходимо установить и настроить библиотеку SciPy. Это можно сделать с помощью дистрибутива Anaconda, а также системы управления пакетами и инсталлятора Conda.
Для начала подготовьте среду выполнения для библиотеки:
Установите необходимые пакеты:
Эта команда может работать долго. Не пугайтесь!
Я предлагаю использовать Jupyter Notebook для запуска кода в интерактивной среде. Это не обязательно, но лично мне он облегчает работу.
Перед открытием Jupyter Notebook вам необходимо зарегистрировать экземпляр conda linalg, чтобы использовать его в качестве ядра при создании ноутбука. Для этого выполните следующую команду:
Теперь можно открыть Jupyter Notebook:
Когда он загрузится в вашем браузере, создайте новый notebook, нажав New → linalg:

Чтобы убедиться, что установка библиотеки SciPy прошла успешно, введите в ноутбуке:
NumPy для работы с векторами и матрицами (куда же без него)
Сложно переоценить роль векторов и матриц при решении технических задач и, в том числе, задач машинного обучения.
NumPy — это наиболее популярный пакет для работы с матрицами и векторами в Python. Часто его применяют в сочетании с scipy.linalg. Чтобы начать работу с матрицами и векторами, нужно импортировать пакет NumPy:
Для представления матриц и векторов NumPy использует специальный тип, называемый ndarray. Чтобы создать объект ndarray, вы можете использовать array ().
Например, вам нужно создать следующую матрицу:

Создадим матрицу как набор вложенных списков (векторов-строк):
Заметьте, что приведённый выше вывод (Outp[3]) достаточно наглядно показывает получившуюся матрицу.
И ещё: все элементы матрицы должны и будут иметь один тип. Это можно проверить с помощью dtype.
Здесь элементы являются целыми числами, поэтому их общий тип по умолчанию — int64. Если бы среди них было хотя бы одно число с плавающей точкой, все элементы получили бы тип float64:
Чтобы вывести на экран размерность матрицы, можно использовать метод shape:
Как и ожидалось, размерность матрицы A 3×2, то есть A имеет три строки и два столбца.
При работе с матрицами часто приходится использовать операцию транспонирования, которая столбцы превращает в строки и наоборот. Чтобы транспонировать вектор или матрицу (представленную объектом типа ndarray), вы можете использовать .transpose () или .T. Например:
Чтобы создать вектор, также можно использовать.array(), передав туда список значений в качестве аргумента:
По аналогии с матрицами, используем .shape(), чтобы вывести на экран размерность вектора:
Заметьте, что она выглядит как (3,), а не как (3, 1) или (1, 3). Разработчики NumPy решили сделать отображение размерности векторов так же, как в MATLAB.
Чтобы получить на выходе размерность (1, 3), нужно было бы создать вот такой массив:
Для (3, 1) — вот такой:
Как видите, они не идентичны.
Часто возникает задача из вектора-строки сделать вектор-столбец. Как вариант, можно сначала создать вектор-строку, а потом использовать .reshape() для его преобразования в столбец:
В приведённом выше примере мы использовали .reshape() для получения вектора-столбца с размерностью (3, 1) из вектора с размерностью(3,). Стоит отметить, что .reshape() делает преобразование с учётом того, что количество элементов (100% заполненных мест) в массиве с новой размерностью должно быть равно количеству элементов в исходном массиве.
В практических задачах часто требуется создавать матрицы, полностью состоящие из нулей, единиц или случайных чисел. Для этого NumPy предлагает несколько удобных функций, о которых я расскажу в следующем разделе.
Заполнение массивов данными
NumPy позволяет быстро создавать и заполнять массивы. Например, чтобы создать массив, заполненный нулями, можно использовать .zeros():
В качестве аргумента .zeros() нужно указать размерность массива, упакованную в кортеж (перечислить значения через запятую и обернуть это в круглые скобки). Элементы созданного массива получат тип float64.
Точно так же, для создания массивов из единиц можно использовать .ones ():
Элементы созданного массива также получат тип float64.
Создать массив, заполненный случайными числами, поможет .random.rand():
Говоря точнее, метод .random.rand() возвращает массив с псевдослучайными значениями (от 0 до 1) из множества, сгенерированного по закону равномерного распределения. Обратите внимание, что в отличие от .zeros() и .ones(), .random.rand () на вход принимает не кортеж, а просто два значения через запятую.
Чтобы получить массив с псевдослучайными значениями, взятыми из множества, сгенерированного по закону нормального распределения с нулевым средним и единичной дисперсией, вы можете использовать .random.randn():
Почему scipy.linalg лучше, чем numpy.linalg
NumPy имеет встроенный модуль numpy.linalg для решения некоторых задач, связанных с аппаратом линейной алгебры. Обычно scipy.linalg рекомендуют использовать по следующим причинам:
-
В официальной документации сказано, что scipy.linalg содержит все функции numpy.linalg, а также дополнительные функции, не входящие в numpy.linalg.
В следующем разделе мы применим scipy.linalg для работы с системами линейных алгебраических уравнений. Наконец-то практика!
Формализация и решение задач с scipy.linalg
Пакет scipy.linalg может стать полезным инструментом для решения транспортной задачи, балансировки химических уравнений и электрических нагрузок, полиномиальной интерполяции и так далее.
В этом разделе вы узнаете, как использовать scipy.linalg.solve() для решения СЛАУ. Но прежде чем приступить к работе с кодом, займёмся формализацией задачи и далее рассмотрим простой пример.
Система линейных алгебраических уравнений — это набор из m уравнений, n переменных и вектора свободных членов. Прилагательное «линейных» означает, что все переменные имеют первую степень. Для простоты рассмотрим СЛАУ, где m и n равны 3:

Есть ещё одно требование к «линейности»: коэффициенты K₁ … K₉ и вектор b₁ … b₃ должны быть константами (в математическом смысле этого слова).
В реальных задачах СЛАУ обычно содержат большое количество переменных, что делает невозможным решение систем вручную. К счастью, такие инструменты, как scipy.linalg, могут выполнить эту тяжелую работу.
Задача 1
Мы сначала разберёмся с основами scipy.linalg.solve() на простом примере, а в следующем разделе возьмём задачу посложнее.

Перейдём к матричной записи нашей системы и введём соответствующие обозначения — A, x и b:

Заметьте: левая часть в исходной записи системы — это обычное произведение матрицы A на вектор x.
Всё, теперь можно переходить к программированию.
Пишем код, используя scipy.linalg.solve()
Входными данными для scipy.linalg.solve() будут матрица A и вектор b. Их нужно представить в виде двух массивов: A — массив 2х2 и b — массив 2х1. В этом нам как раз поможет NumPy. Таким образом, мы можем решить систему так:
Разберём приведённый выше код:
- Строки 1 и 2: импортируем NumPy и функцию solve() из scipy.linalg.
- Строки с 4 по 9: создаём матрицу коэффициентов как двумерный массив с именем A.
- Строка 11: создаём вектор-строку b как массив с именем b. Чтобы сделать его вектор-столбцом, вызываем .reshape ((2, 1)).
- Строки 13 и 14: вызываем .solve() для нашей системы, результат сохраняем в х и выводим его. Обратите внимание, что .solve() возвращает вектор из чисел с плавающей запятой, даже если все элементы исходных массивов являются целыми числами.
Далее возьмём более сложный пример из реальной практики.
Задача 2: составление плана питания
Это одна из типовых задач, встречающихся на практике: найти пропорции компонентов для получения определенной смеси.
Ниже мы сформируем план питания, смешивая разные продукты, чтобы получить сбалансированную диету.
Нам даны нормы содержания витаминов в пище:
- 170 единиц витамина А;
- 180 единиц витамина B;
- 140 единиц витамина С;
- 180 единиц витамина D;
- 350 единиц витамина Е.
Продукт Витамин A Витамин B Витамин C Витамин D Витамин E 1 1 10 1 2 2 2 9 1 0 1 1 3 2 2 5 1 2 4 1 1 1 2 13 5 1 1 1 9 2 Необходимо скомбинировать продукты питания так, чтобы их концентрация была оптимальной и соответствовала нормам содержания витаминов в пище.
Обозначим оптимальную концентрацию (количество единиц) для продукта 1 как x1, для продукта 2 — как x2 и так далее. Так как мы будем смешивать продукты, то для каждого витамина (столбца таблицы) можно просто просуммировать значения, по всем продуктам. Учитывая, что сбалансированная диета должна включать 170 единиц витамина А, то, используя данные из столбца «Витамин А», составим уравнение:

Аналогичные уравнения можно составить и для витаминов B, C, D, E, объединив всё в систему:

Запишем полученную СЛАУ в матричной форме:

Теперь для решения системы можно использовать scipy.linalg.solve():
Мы получили результат. Давайте его расшифруем. Сбалансированная диета должна включать:
- 10 единиц продукта 1;
- 10 единиц продукта 2;
- 20 единиц продукта 3;
- 20 единиц продукта 4;
- 10 единиц продукта 5.
Облачные VPS-серверы с быстрыми NVMе-дисками и посуточной оплатой. Загрузка своего ISO.