{"id":400330,"date":"2024-06-29T15:12:01","date_gmt":"2024-06-29T15:12:01","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=400330"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T15:12:01","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=400330","title":{"rendered":"<span>What&#8217;s new in AngouriMath 1.2?<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Hi. The last 7 months I have been working on the greatest release of <a href=\"https:\/\/github.com\/asc-community\/AngouriMath\" rel=\"noopener noreferrer nofollow\">AngouriMath<\/a>. There is something I want to tell you.<\/p>\n<h3>Briefly about the project<\/h3>\n<p>In November of 2019 I realized that it would be nice to have a symbolic algebra library for .NET, which could simplify expressions, solve equations, build latex code, and many more. That is how I decided to create one.<\/p>\n<details class=\"spoiler\">\n<summary>But this already exists&#8230;<\/summary>\n<div class=\"spoiler__content\">\n<p>As long as I tell people about what I am working on, they suggest different solutions, be those to rewrite SymPy, make a wrapper over SageMath for .NET, pirate Wolfram|Alpha, use primitive mathnet.symbolics (about which they mention themselves).<\/p>\n<p>All of those have limitations or difficulties. In contrast, what I am working on is a very lightweight library, made and optimized for .NET specifically. It is open-source (under MIT).<\/p>\n<\/div>\n<\/details>\n<h3>Release 1.2<\/h3>\n<p>In August one of the main contributors, <a href=\"https:\/\/github.com\/Happypig375\" rel=\"noopener noreferrer nofollow\">@HappyPig375<\/a>, helped to rewrite a significant part of the library into a type hierarchy. Every operator\/function has its own node (type). Thanks to it, the library now has a more obvious API, improved performance and security. Now, let us go over what has been done within these 7 months.<\/p>\n<h4>An expression is a record<\/h4>\n<p>For example, that is what <code>Sumf <\/code>looks like<\/p>\n<pre><code class=\"cs\">public sealed partial record Sumf(Entity Augend, Entity Addend) : NumericNode<\/code><\/pre>\n<p>Thanks to it, now we can apply pattern matching:<\/p>\n<pre><code class=\"cs\">internal static Entity CommonRules(Entity x) => x switch {     \/\/ (a * f(x)) * g(x) = a * (f(x) * g(x))     Mulf(Mulf(Number const1, Function func1), Function func2) => func1 * func2 * const1,      \/\/ (a\/b) * (c\/d) = (a*c)\/(b*d)     Mulf(Divf(var any1, var any2), Divf(var any3, var any4)) => any1 * any3 \/ (any2 * any4),      \/\/ a \/ (b \/ c) = a * c \/ b     Divf(var any1, Divf(var any2, var any3)) => any1 * any3 \/ any2,<\/code><\/pre>\n<p>(it is a few examples of patterns used in the simplification algorithm)<\/p>\n<h3>Math<\/h3>\n<p>Here I am going to over over features related to math itself.<\/p>\n<h4>New functions<\/h4>\n<p><code>Secant<\/code>, <code>cosecant<\/code>, <code>arcsecant<\/code>, <code>arccosecant <\/code>were added as separate nodes.<\/p>\n<p>12 hyperbolic functions were added. They do not have their own nodes and return their symbolic expression (<code>sinh(x)<\/code>as<code>(e.Pow(x) - e.Pow(-x)) \/ 2<\/code>).<\/p>\n<p><code>Abs <\/code>and <code>Signum<\/code>. The syntax of <code>Abs <\/code>is the following: <code>(|x|)<\/code>. It looks similar to how we write in on a paper while at the same time allows to avoid ambiguouty (because | is symmetric, there might be problems with it).<\/p>\n<p>Euler&#8217;s totient function was added.<\/p>\n<pre><code>WriteLine(@\"phi(8)\".EvalNumerical()); WriteLine(@\"(|-3 + 4i|)\".EvalNumerical()); WriteLine(@\"sinh(3)\".Simplify()); WriteLine(@\"sec(0.5)\".Simplify());<\/code><\/pre>\n<p>Prints<\/p>\n<pre><code>4 5 (e ^ 3 - 1 \/ e ^ 3) \/ 2 sec(1\/2)<\/code><\/pre>\n<h4>Domains<\/h4>\n<p>They allow to limit every node&#8217;s range. If a node is out of its domain, it turns into a <code>NaN<\/code>, which makes the entire expression undefined. <code>SpecialSet<\/code>s are used as values of domains.<\/p>\n<h4>Booleans and logic<\/h4>\n<p>Logic operators were finally added. At the beginning, there was an idea to make those similar to what we use in programming; instead, it was decided to make them literal. That is why the syntax is: <code>not<\/code>, <code>or<\/code>, <code>xor<\/code>, <code>and<\/code>, <code>implies<\/code>.<\/p>\n<p>To check whether an expression is evaluable into a <code>Boolean<\/code>, you need to use <code>EvaluableBoolean<\/code>. Same way, we use <code>EvaluableNumerical <\/code>to check whether an expression is evaluable into a <code>Number<\/code>.<\/p>\n<pre><code class=\"cs\">WriteLine(@\"(true or b) implies c\".Simplify());<\/code><\/pre>\n<p>(prints<code>c<\/code>)<\/p>\n<h4>Equality and inequality signs<\/h4>\n<p>They might carry the <code>Boolean<\/code>type, if their operands are computed. Of course, the following were added: <code>=<\/code>, <code>&lt;<\/code>, <code>><\/code>, <code>&lt;=<\/code>, <code>>=<\/code>.<\/p>\n<p>You can also combine inequalities. For example, <code>a > b > c<\/code> is interpreted as<code>a > b and b > c<\/code>.<\/p>\n<pre><code class=\"cs\">WriteLine(@\"a &lt; b >= c\".Simplify());<\/code><\/pre>\n<p>(Prints<code>a &lt; b and b >= c<\/code>)<\/p>\n<h4>Sets<\/h4>\n<p>Sets were added. They are parsable and have their own nodes.<\/p>\n<p>The most naive type of set is <code>FiniteSet<\/code>. Its syntax: <code>{ 1, 2, 3 }<\/code>.<\/p>\n<p><code>Intervals <\/code>also have familiar syntax: <code>[1; 2]<\/code> for both points included, <code>(1; 2)<\/code> for both excluded, <code>[1; 2)<\/code> for the right one excluded, and <code>(1; 2]<\/code> for the left one excluded. Complex intervals were removed because of their clumsiness.<\/p>\n<p><code>SpecialSet <\/code>are preset sets. Now we have <code>CC<\/code>, <code>RR<\/code>, <code>QQ<\/code>, <code>ZZ<\/code>, <code>BB<\/code>\u00a0for complex, real, rational, integer and boolean values.<\/p>\n<p><code>ConditionalSet <\/code>is written in <a href=\"https:\/\/en.wikipedia.org\/wiki\/Set-builder_notation\" rel=\"noopener noreferrer nofollow\">set-builder notation<\/a>, for example: <code>{ x : x > 0 and x^2 = y }<\/code> (any  <code>x<\/code> such that greater than 0 and equals<code>y<\/code>).<\/p>\n<pre><code class=\"cs\">WriteLine(@\"({ 1, 2 } \\\/ { 5 }) \/\\ { x : x in [2; 3] and x > 0 } \".Simplify());<\/code><\/pre>\n<p>(Prints<code>{ 2 }<\/code>)<\/p>\n<h4>Limits improved<\/h4>\n<p>First remarkable, second remarkable limits transformation rules were added, as well as the l&#8217;Hopital&#8217;s rule.<\/p>\n<pre><code class=\"cs\">WriteLine(\"tan(a x) \/ (b x)\".Limit(\"x\", 0)); WriteLine(\"(sin(t) - t) \/ t3\".Limit(\"t\", 0));<\/code><\/pre>\n<p>(Prints<code>a \/ b<\/code> and <code>-1\/6<\/code> respectively)<\/p>\n<h4>&#171;Provided&#187; node<\/h4>\n<p>Allows to set constraints on an expression. For example, square root on real numbers we can define as <code>sqrt(x) provided x >= 0<\/code>. It will turn into <code>NaN <\/code>if you substitute negative <code>x<\/code>.<\/p>\n<p>If an expression being turned into <code>NaN <\/code>is an element of a finite set, it will be excluded, instead of turning the whole expression into <code>NaN<\/code>. It is the only exception for <code>NaN<\/code>.<\/p>\n<h4>Piecewise<\/h4>\n<p><code>Piecewise <\/code>is a sequence of<code>Provided<\/code>s. Unlike the classical piecewise-defined function, here the order of elements matters, and when computing<code>Piecewise<\/code>, the first<code>Provided<\/code>\u00a0is returned such that its predicate is true.<\/p>\n<p>That is an example of how we can define the absolute value function for real numbers via <code>Piecewise<\/code>:<\/p>\n<pre><code class=\"cs\">Entity abs = \"piecewise(x provided x > 0, -x provided x &lt;= 0)\"; WriteLine(abs.Substitute(\"x\", 3).EvalNumerical()); WriteLine(abs.Substitute(\"x\", -3).EvalNumerical());<\/code><\/pre>\n<p>(Prints 3 in both cases)<\/p>\n<h2>Ease and convenience of use<\/h2>\n<p>This part of the article about features making the use of AngouriMath more comfortable.<\/p>\n<h4>Exceptions were reconsidered and refactored<\/h4>\n<p>Now all exceptions thrown by the library are somehow inherited from <code>AngouriMathBaseException<\/code>. Because there is no<code>p\/invoke<\/code> or IO, you can be assured that any exception assignable to <code>AngouriMathBaseException\u00a0<\/code>does not bring any direct harm to the system or user&#8217;s data. In other words, when catching exceptions, now you can catch this exception in the last instance of <code>Catch<\/code>.<\/p>\n<h4>Performance improved<\/h4>\n<p>To be precise, the performance has been fluctuating throughout this all time. Nonetheless, it is still by far better than that of 1.1.0.5. <a href=\"https:\/\/github.com\/asc-community\/AngouriMath\/blob\/master\/Sources\/AngouriMath\/Docs\/WhatsNew\/version_performance_control.md\" rel=\"noopener noreferrer nofollow\">Here <\/a>you can find a performance report by every key commit.<\/p>\n<h4>F# is now supported<\/h4>\n<p>With this release, the API for AngouriMath is now supported natively for wonderful language F#. It might be not as functional as the main API, so in especially complicated cases, you still can call methods from the core library itself.<\/p>\n<h4>Interactive<\/h4>\n<p>I wrote an article some time ago about <a href=\"https:\/\/habr.com\/ru\/post\/528816\/\" rel=\"noopener noreferrer nofollow\">AngouriMath in Jupyter<\/a>. AngouriMath.Interactive itself simplify converts <code>ILatexiseable <\/code>into a LaTeX-code and renders it with MathJax (read more about it in the mentioned article).<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a77\/5de\/7d7\/a775de7d74bcb97915553d6f446a1e74.PNG\" alt=\"A simple example of using AngouriMath.Interactive in Jupyter\" title=\"A simple example of using AngouriMath.Interactive in Jupyter\" width=\"918\" height=\"181\"\/><figcaption>A simple example of using AngouriMath.Interactive in Jupyter<\/figcaption><\/figure>\n<h4>Multithreading<\/h4>\n<p>All computations happen strictly in one thread. The library is not responsible for your threading problems. Moreover, all methods are thread-safe. The settings are local for every thread(<code>[ThreadStatic]<\/code>).<\/p>\n<p>The main feature of this update is that you can interrupt computations of <code>Solve <\/code>or<code>Simplify<\/code>. <\/p>\n<h4>New settings<\/h4>\n<p>It is their third version. Even though I am not a big fan of the new solution, it is the best I could achieve. To set a new value of a setting, let us write<\/p>\n<pre><code class=\"cs\">using var _ = MaxExpansionTermCount.Set(10); \/\/ some code<\/code><\/pre>\n<p>Then this setting will be automatically rolled back to the previous value once the end of the scope is reached (the return type of <code>Set<\/code>\u00a0is<code>IDisposable<\/code>).<\/p>\n<h3>That is about it<\/h3>\n<p>Thank you for your attention. I will be pleased to answer your questions.<\/p>\n<p>Anybody willing to contribute is welcome (contact me or fork and make your changes directly).<\/p>\n<h3>References<\/h3>\n<ol>\n<li>\n<p><a href=\"https:\/\/github.com\/asc-community\/AngouriMath\" rel=\"noopener noreferrer nofollow\">GitHub<\/a> page of the project.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/am.angouri.org\" rel=\"noopener noreferrer nofollow\">Website<\/a> of the project.<\/p>\n<\/li>\n<li>\n<p>Detailed <a href=\"https:\/\/am.angouri.org\/#whatsnew\" rel=\"noopener noreferrer nofollow\">What&#8217;s new<\/a>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/asc-community\/AngouriMath\/milestones\" rel=\"noopener noreferrer nofollow\">Plans<\/a> for the future updates.<\/p>\n<\/li>\n<li>\n<p>My GitHub <a href=\"https:\/\/github.com\/WhiteBlackGoose\" rel=\"noopener noreferrer nofollow\">profile<\/a>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.sympy.org\" rel=\"noopener noreferrer nofollow\">SymPy <\/a>&#8212; those who inspire me.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/545436\/\"> https:\/\/habr.com\/ru\/articles\/545436\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Hi. The last 7 months I have been working on the greatest release of <a href=\"https:\/\/github.com\/asc-community\/AngouriMath\" rel=\"noopener noreferrer nofollow\">AngouriMath<\/a>. There is something I want to tell you.<\/p>\n<h3>Briefly about the project<\/h3>\n<p>In November of 2019 I realized that it would be nice to have a symbolic algebra library for .NET, which could simplify expressions, solve equations, build latex code, and many more. That is how I decided to create one.<\/p>\n<details class=\"spoiler\">\n<summary>But this already exists&#8230;<\/summary>\n<div class=\"spoiler__content\">\n<p>As long as I tell people about what I am working on, they suggest different solutions, be those to rewrite SymPy, make a wrapper over SageMath for .NET, pirate Wolfram|Alpha, use primitive mathnet.symbolics (about which they mention themselves).<\/p>\n<p>All of those have limitations or difficulties. In contrast, what I am working on is a very lightweight library, made and optimized for .NET specifically. It is open-source (under MIT).<\/p>\n<\/div>\n<\/details>\n<h3>Release 1.2<\/h3>\n<p>In August one of the main contributors, <a href=\"https:\/\/github.com\/Happypig375\" rel=\"noopener noreferrer nofollow\">@HappyPig375<\/a>, helped to rewrite a significant part of the library into a type hierarchy. Every operator\/function has its own node (type). Thanks to it, the library now has a more obvious API, improved performance and security. Now, let us go over what has been done within these 7 months.<\/p>\n<h4>An expression is a record<\/h4>\n<p>For example, that is what <code>Sumf <\/code>looks like<\/p>\n<pre><code class=\"cs\">public sealed partial record Sumf(Entity Augend, Entity Addend) : NumericNode<\/code><\/pre>\n<p>Thanks to it, now we can apply pattern matching:<\/p>\n<pre><code class=\"cs\">internal static Entity CommonRules(Entity x) => x switch {     \/\/ (a * f(x)) * g(x) = a * (f(x) * g(x))     Mulf(Mulf(Number const1, Function func1), Function func2) => func1 * func2 * const1,      \/\/ (a\/b) * (c\/d) = (a*c)\/(b*d)     Mulf(Divf(var any1, var any2), Divf(var any3, var any4)) => any1 * any3 \/ (any2 * any4),      \/\/ a \/ (b \/ c) = a * c \/ b     Divf(var any1, Divf(var any2, var any3)) => any1 * any3 \/ any2,<\/code><\/pre>\n<p>(it is a few examples of patterns used in the simplification algorithm)<\/p>\n<h3>Math<\/h3>\n<p>Here I am going to over over features related to math itself.<\/p>\n<h4>New functions<\/h4>\n<p><code>Secant<\/code>, <code>cosecant<\/code>, <code>arcsecant<\/code>, <code>arccosecant <\/code>were added as separate nodes.<\/p>\n<p>12 hyperbolic functions were added. They do not have their own nodes and return their symbolic expression (<code>sinh(x)<\/code>as<code>(e.Pow(x) - e.Pow(-x)) \/ 2<\/code>).<\/p>\n<p><code>Abs <\/code>and <code>Signum<\/code>. The syntax of <code>Abs <\/code>is the following: <code>(|x|)<\/code>. It looks similar to how we write in on a paper while at the same time allows to avoid ambiguouty (because | is symmetric, there might be problems with it).<\/p>\n<p>Euler&#8217;s totient function was added.<\/p>\n<pre><code>WriteLine(@\"phi(8)\".EvalNumerical()); WriteLine(@\"(|-3 + 4i|)\".EvalNumerical()); WriteLine(@\"sinh(3)\".Simplify()); WriteLine(@\"sec(0.5)\".Simplify());<\/code><\/pre>\n<p>Prints<\/p>\n<pre><code>4 5 (e ^ 3 - 1 \/ e ^ 3) \/ 2 sec(1\/2)<\/code><\/pre>\n<h4>Domains<\/h4>\n<p>They allow to limit every node&#8217;s range. If a node is out of its domain, it turns into a <code>NaN<\/code>, which makes the entire expression undefined. <code>SpecialSet<\/code>s are used as values of domains.<\/p>\n<h4>Booleans and logic<\/h4>\n<p>Logic operators were finally added. At the beginning, there was an idea to make those similar to what we use in programming; instead, it was decided to make them literal. That is why the syntax is: <code>not<\/code>, <code>or<\/code>, <code>xor<\/code>, <code>and<\/code>, <code>implies<\/code>.<\/p>\n<p>To check whether an expression is evaluable into a <code>Boolean<\/code>, you need to use <code>EvaluableBoolean<\/code>. Same way, we use <code>EvaluableNumerical <\/code>to check whether an expression is evaluable into a <code>Number<\/code>.<\/p>\n<pre><code class=\"cs\">WriteLine(@\"(true or b) implies c\".Simplify());<\/code><\/pre>\n<p>(prints<code>c<\/code>)<\/p>\n<h4>Equality and inequality signs<\/h4>\n<p>They might carry the <code>Boolean<\/code>type, if their operands are computed. Of course, the following were added: <code>=<\/code>, <code>&lt;<\/code>, <code>><\/code>, <code>&lt;=<\/code>, <code>>=<\/code>.<\/p>\n<p>You can also combine inequalities. For example, <code>a > b > c<\/code> is interpreted as<code>a > b and b > c<\/code>.<\/p>\n<pre><code class=\"cs\">WriteLine(@\"a &lt; b >= c\".Simplify());<\/code><\/pre>\n<p>(Prints<code>a &lt; b and b >= c<\/code>)<\/p>\n<h4>Sets<\/h4>\n<p>Sets were added. They are parsable and have their own nodes.<\/p>\n<p>The most naive type of set is <code>FiniteSet<\/code>. Its syntax: <code>{ 1, 2, 3 }<\/code>.<\/p>\n<p><code>Intervals <\/code>also have familiar syntax: <code>[1; 2]<\/code> for both points included, <code>(1; 2)<\/code> for both excluded, <code>[1; 2)<\/code> for the right one excluded, and <code>(1; 2]<\/code> for the left one excluded. Complex intervals were removed because of their clumsiness.<\/p>\n<p><code>SpecialSet <\/code>are preset sets. Now we have <code>CC<\/code>, <code>RR<\/code>, <code>QQ<\/code>, <code>ZZ<\/code>, <code>BB<\/code>\u00a0for complex, real, rational, integer and boolean values.<\/p>\n<p><code>ConditionalSet <\/code>is written in <a href=\"https:\/\/en.wikipedia.org\/wiki\/Set-builder_notation\" rel=\"noopener noreferrer nofollow\">set-builder notation<\/a>, for example: <code>{ x : x > 0 and x^2 = y }<\/code> (any  <code>x<\/code> such that greater than 0 and equals<code>y<\/code>).<\/p>\n<pre><code class=\"cs\">WriteLine(@\"({ 1, 2 } \\\/ { 5 }) \/\\ { x : x in [2; 3] and x > 0 } \".Simplify());<\/code><\/pre>\n<p>(Prints<code>{ 2 }<\/code>)<\/p>\n<h4>Limits improved<\/h4>\n<p>First remarkable, second remarkable limits transformation rules were added, as well as the l&#8217;Hopital&#8217;s rule.<\/p>\n<pre><code class=\"cs\">WriteLine(\"tan(a x) \/ (b x)\".Limit(\"x\", 0)); WriteLine(\"(sin(t) - t) \/ t3\".Limit(\"t\", 0));<\/code><\/pre>\n<p>(Prints<code>a \/ b<\/code> and <code>-1\/6<\/code> respectively)<\/p>\n<h4>&#171;Provided&#187; node<\/h4>\n<p>Allows to set constraints on an expression. For example, square root on real numbers we can define as <code>sqrt(x) provided x >= 0<\/code>. It will turn into <code>NaN <\/code>if you substitute negative <code>x<\/code>.<\/p>\n<p>If an expression being turned into <code>NaN <\/code>is an element of a finite set, it will be excluded, instead of turning the whole expression into <code>NaN<\/code>. It is the only exception for <code>NaN<\/code>.<\/p>\n<h4>Piecewise<\/h4>\n<p><code>Piecewise <\/code>is a sequence of<code>Provided<\/code>s. Unlike the classical piecewise-defined function, here the order of elements matters, and when computing<code>Piecewise<\/code>, the first<code>Provided<\/code>\u00a0is returned such that its predicate is true.<\/p>\n<p>That is an example of how we can define the absolute value function for real numbers via <code>Piecewise<\/code>:<\/p>\n<pre><code class=\"cs\">Entity abs = \"piecewise(x provided x > 0, -x provided x &lt;= 0)\"; WriteLine(abs.Substitute(\"x\", 3).EvalNumerical()); WriteLine(abs.Substitute(\"x\", -3).EvalNumerical());<\/code><\/pre>\n<p>(Prints 3 in both cases)<\/p>\n<h2>Ease and convenience of use<\/h2>\n<p>This part of the article about features making the use of AngouriMath more comfortable.<\/p>\n<h4>Exceptions were reconsidered and refactored<\/h4>\n<p>Now all exceptions thrown by the library are somehow inherited from <code>AngouriMathBaseException<\/code>. Because there is no<code>p\/invoke<\/code> or IO, you can be assured that any exception assignable to <code>AngouriMathBaseException\u00a0<\/code>does not bring any direct harm to the system or user&#8217;s data. In other words, when catching exceptions, now you can catch this exception in the last instance of <code>Catch<\/code>.<\/p>\n<h4>Performance improved<\/h4>\n<p>To be precise, the performance has been fluctuating throughout this all time. Nonetheless, it is still by far better than that of 1.1.0.5. <a href=\"https:\/\/github.com\/asc-community\/AngouriMath\/blob\/master\/Sources\/AngouriMath\/Docs\/WhatsNew\/version_performance_control.md\" rel=\"noopener noreferrer nofollow\">Here <\/a>you can find a performance report by every key commit.<\/p>\n<h4>F# is now supported<\/h4>\n<p>With this release, the API for AngouriMath is now supported natively for wonderful language F#. It might be not as functional as the main API, so in especially complicated cases, you still can call methods from the core library itself.<\/p>\n<h4>Interactive<\/h4>\n<p>I wrote an article some time ago about <a href=\"https:\/\/habr.com\/ru\/post\/528816\/\" rel=\"noopener noreferrer nofollow\">AngouriMath in Jupyter<\/a>. AngouriMath.Interactive itself simplify converts <code>ILatexiseable <\/code>into a LaTeX-code and renders it with MathJax (read more about it in the mentioned article).<\/p>\n<figure class=\"\"><figcaption>A simple example of using AngouriMath.Interactive in Jupyter<\/figcaption><\/figure>\n<h4>Multithreading<\/h4>\n<p>All computations happen strictly in one thread. The library is not responsible for your threading problems. Moreover, all methods are thread-safe. The settings are local for every thread(<code>[ThreadStatic]<\/code>).<\/p>\n<p>The main feature of this update is that you can interrupt computations of <code>Solve <\/code>or<code>Simplify<\/code>. <\/p>\n<h4>New settings<\/h4>\n<p>It is their third version. Even though I am not a big fan of the new solution, it is the best I could achieve. To set a new value of a setting, let us write<\/p>\n<pre><code class=\"cs\">using var _ = MaxExpansionTermCount.Set(10); \/\/ some code<\/code><\/pre>\n<p>Then this setting will be automatically rolled back to the previous value once the end of the scope is reached (the return type of <code>Set<\/code>\u00a0is<code>IDisposable<\/code>).<\/p>\n<h3>That is about it<\/h3>\n<p>Thank you for your attention. I will be pleased to answer your questions.<\/p>\n<p>Anybody willing to contribute is welcome (contact me or fork and make your changes directly).<\/p>\n<h3>References<\/h3>\n<ol>\n<li>\n<p><a href=\"https:\/\/github.com\/asc-community\/AngouriMath\" rel=\"noopener noreferrer nofollow\">GitHub<\/a> page of the project.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/am.angouri.org\" rel=\"noopener noreferrer nofollow\">Website<\/a> of the project.<\/p>\n<\/li>\n<li>\n<p>Detailed <a href=\"https:\/\/am.angouri.org\/#whatsnew\" rel=\"noopener noreferrer nofollow\">What&#8217;s new<\/a>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/asc-community\/AngouriMath\/milestones\" rel=\"noopener noreferrer nofollow\">Plans<\/a> for the future updates.<\/p>\n<\/li>\n<li>\n<p>My GitHub <a href=\"https:\/\/github.com\/WhiteBlackGoose\" rel=\"noopener noreferrer nofollow\">profile<\/a>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.sympy.org\" rel=\"noopener noreferrer nofollow\">SymPy <\/a>&#8212; those who inspire me.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/545436\/\"> https:\/\/habr.com\/ru\/articles\/545436\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-400330","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/400330","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=400330"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/400330\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=400330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=400330"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=400330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}