diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..e9db78e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "AngouriMath"]
+ path = AngouriMath
+ url = git@github.com:asc-community/AngouriMath.git
diff --git a/AngouriMath b/AngouriMath
new file mode 160000
index 0000000..18c127d
--- /dev/null
+++ b/AngouriMath
@@ -0,0 +1 @@
+Subproject commit 18c127d7c576624d063aee7df95a86c1995c1432
diff --git a/CLI.csproj b/CLI.csproj
index 14e8666..0fcae01 100644
--- a/CLI.csproj
+++ b/CLI.csproj
@@ -5,7 +5,6 @@
net7.0
enable
enable
-
true
true
true
@@ -17,8 +16,9 @@
-
+
+
diff --git a/Program.cs b/Program.cs
index fad6b77..a9c55fa 100644
--- a/Program.cs
+++ b/Program.cs
@@ -16,13 +16,15 @@
using AngouriMath;
using AngouriMath.Extensions;
-using HonkSharp;
using HonkSharp.Functional;
+using HonkSharp.Fluency;
+using PeterO.Numbers;
var cliArgs = System.Environment.GetCommandLineArgs();
-var reader = new ArgReader(cliArgs);
-
-
+IArgReader reader = new ArgReader(cliArgs);
+// IArgReader reader = new ArgReader(new [] { "", "info", "-66 x_1 2 - 6 x_1 x_2 + 24 x_1 x_3 - 12 x_1 x_4 + 270 x_1 - 74 x_2 2 - 8 x_2 x_3 + 4 x_2 x_4 - 440 x_2 - 59 x_3 2 - 16 x_3 x_4 - 190 x_3 - 71 x_4 2 + 20 x_4" });
+var prec = GetEnv("AMCLI_PRECISION", 20);
+MathS.Settings.DecimalPrecisionContext.Set(new EContext(prec, ERounding.HalfUp, -prec, 10 * prec, false));
Entity expr;
Entity.Variable v;
string res;
@@ -170,6 +172,13 @@ is equivalent to
Here the result of `echo` is substituted instead of the second argument
of `amcli sub`, not the last one.
+ SETTINGS
+
+ All settings are set using environment variables.
+
+ AMCLI_PRECISION - precision/number of digits in decimal numbers.
+ Default - 100.
+
OTHER
You can bind amcli to @ using aliases. On Unix-like operating systems,
@@ -228,12 +237,141 @@ Here the result of `echo` is substituted instead of the second argument
Console.WriteLine(expr.Substitute(v, withWhat));
break;
+ case "info":
+ expr = reader.Next();
+ var splitter = new string('-', 20);
+ Console.WriteLine($"expr: {expr}");
+ Console.WriteLine(splitter);
+ Console.WriteLine($"vars: {expr.Vars.ToLList()}");
+ Console.WriteLine(splitter);
+ var vars = expr.Vars.ToArray();
+ foreach (var vx in vars)
+ {
+ Console.Write($"diff over {vx}: ");
+ Console.WriteLine(expr.Differentiate(vx).InnerSimplified);
+ Console.WriteLine(splitter);
+ }
+ foreach (var vx in vars)
+ {
+ Console.Write($"roots over {vx}: ");
+ Console.WriteLine(expr.Equalizes(0).Solve(vx).InnerSimplified);
+ Console.WriteLine(splitter);
+ }
+ if (vars.Length is 1)
+ {
+ var fx = expr.Differentiate(vars[0]);
+ var crit = fx.Equalizes(0).Solve(vars[0]);
+ if (crit is not Entity.Set.FiniteSet fins)
+ goto notOneVar;
+ var fxx = fx.Differentiate(vars[0]);
+ foreach (var (i, sol) in fins.Enumerate())
+ {
+ Console.WriteLine($"Extremum #{i}");
+ Console.WriteLine($"Point: {sol}");
+ Console.WriteLine($"Value: {expr.Substitute(vars[0], sol).Evaled}");
+ var fxxValue = fxx.Substitute(vars[0], sol).EvalNumerical();
+ Console.WriteLine($"2nd derivative value: {fxxValue}");
+ Console.Write("Type of extremum: ");
+ if (fxxValue is not Entity.Number.Real rVal)
+ continue;
+ if (rVal == 0)
+ Console.WriteLine("Saddle");
+ if ((double)rVal > 0.0)
+ Console.WriteLine("Minimum");
+ if ((double)rVal < 0.0)
+ Console.WriteLine("Maximum");
+ Console.WriteLine();
+ }
+ }
+ notOneVar:
+ if (vars.Length is > 1)
+ {
+ var diffs = new List();
+ foreach (var vx in vars)
+ diffs.Add(expr.Differentiate(vx).InnerSimplified);
+
+ var system = MathS.Equations((IEnumerable)diffs);
+ Console.WriteLine("First order condition:");
+ Console.WriteLine(system);
+ var sols2 = system.Solve(vars);
+ if (sols2 is null)
+ {
+ Console.WriteLine("amcli wasn't able to find any extremas");
+ break;
+ }
+
+ var hessian = new Entity.Matrix(dims =>
+ expr
+ .Differentiate(vars[dims[0]])
+ .Differentiate(vars[dims[1]])
+ .InnerSimplified,
+ vars.Length,
+ vars.Length);
+
+ foreach (var (i, sol) in sols2.Enumerate())
+ {
+ var exprToSub = expr;
+ Entity hessianToSub = hessian;
+ var msol = ((Entity.Matrix)sol).T;
+ foreach (var (val, vr) in msol.Zip(vars))
+ {
+ exprToSub = exprToSub.Substitute(vr, val);
+ hessianToSub = hessianToSub.Substitute(vr, val);
+ }
+ var fValue = exprToSub.Evaled;
+ var hessienEvaled = (Entity.Matrix)hessianToSub.Evaled;
+ var det = hessienEvaled.Determinant!.EvalNumerical();
+ Console.WriteLine($"Extrema #{i}:");
+ Console.WriteLine($"Point: {msol.T}");
+ Console.WriteLine($"Value: {fValue}");
+ Console.WriteLine($"Hessien:");
+ Console.WriteLine(hessienEvaled.ToString(multilineFormat: true));
+
+ var uniqueVar = MathS.Var("lambda_quackfrog");
+ var eigenMatrix = (Entity.Matrix)(hessianToSub - MathS.IdentityMatrix(hessian.RowCount) * uniqueVar).InnerSimplified;
+ var eigenDet = eigenMatrix.Determinant!;
+ var eigenValues = eigenDet.InnerSimplified.Equalizes(0).Solve(uniqueVar).Evaled;
+ if (eigenValues is Entity.Set.FiniteSet eigens)
+ {
+ if (eigens.Count is 0)
+ Console.WriteLine("amcli wasn't able to find eigen values and the type of extremum");
+ else
+ {
+ Console.WriteLine($"Eigen values of hessian: {eigens}");
+ if (eigens.All(val => val.EvalNumerical() is Entity.Number.Real r1 && r1.IsPositive))
+ Console.WriteLine("Type of extremum: Minimum");
+ else if (eigens.All(val => val.EvalNumerical() is Entity.Number.Real r2 && r2.IsNegative))
+ Console.WriteLine("Type of extremum: Negative");
+ else if (eigens.All(val => val.EvalNumerical() is Entity.Number.Real r3 && r3.IsNegative || val.EvalNumerical() is Entity.Number.Real r4 && r4.IsPositive))
+ Console.WriteLine("Type of extremum: Saddle");
+ else
+ Console.WriteLine("Cannot detect type of extremum");
+ }
+ }
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+ }
+
+ break;
+
default:
Console.WriteLine($"Unrecognized command `{cmd}`");
break;
}
-public sealed class ArgReader
+static T GetEnv(string name, T def)
+{
+ if (Environment.GetEnvironmentVariable(name) is not string value)
+ return def;
+ if (typeof(T) == typeof(int))
+ return (T)(object)int.Parse(value);
+ if (typeof(T) == typeof(string))
+ return (T)(object)value;
+ throw new();
+}
+
+public sealed class ArgReader : IArgReader
{
private readonly string[] args;
private int curr = 1;
@@ -252,3 +390,8 @@ public string Next()
return Console.ReadLine()!;
}
}
+
+public interface IArgReader
+{
+ public string Next();
+}