Skip to content

Commit 1aaa925

Browse files
authored
Add C to integration result, change integral node to support range instead of iterations, implement u-substitution and quadratic denominator integral, integration of abs(x), sgn(x) and ln(abs(x))^2 (#657)
* Implement constant of integration * u substitution and quadratic denominator * Integrate abs and sgn * Implement integration of ln(abs(x))^2 * Fix F# tests * Apply AI fixes
1 parent b44972d commit 1aaa925

33 files changed

Lines changed: 715 additions & 251 deletions

Sources/AngouriMath/Convenience/AngouriMathExtensions.cs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ public static FastExpression Compile(this string str, params Variable[] variable
298298
/// Finds the symbolical derivative of the given expression
299299
/// </summary>
300300
/// <param name="str">
301-
/// The expresion to be parsed and differentiated
301+
/// The expression to be parsed and differentiated
302302
/// </param>
303303
/// <param name="x">
304304
/// Over which variable to find the derivative
@@ -315,7 +315,7 @@ public static Entity Derive(this string str, Variable x)
315315
/// Finds the symbolical derivative of the given expression
316316
/// </summary>
317317
/// <param name="str">
318-
/// The expresion to be parsed and differentiated
318+
/// The expression to be parsed and differentiated
319319
/// </param>
320320
/// <param name="x">
321321
/// Over which variable to find the derivative
@@ -328,21 +328,35 @@ public static Entity Differentiate(this string str, Variable x)
328328
=> str.ToEntity().Differentiate(x);
329329

330330
/// <summary>
331-
/// Integrates the given expression over the `x` variable, if can.
331+
/// Integrates indefinitely the given expression over the `x` variable, if can.
332332
/// May return an unresolved <see cref="Integralf"/> node.
333333
/// </summary>
334334
/// <param name="str">
335-
/// The expression to be parsed and integrated over <paramref name="x"/>
335+
/// The expression to be parsed and integrated
336336
/// </param>
337-
/// <param name="x">Over which to integrate</param>
337+
/// <param name="x">Over which variable to integrate</param>
338338
/// <returns>
339-
/// An integrated expression. It might remain the same,
340-
/// it might have no integrals, and it might be transformed so that
341-
/// only a few nodes have unresolved integrals.
339+
/// An integrated expression. It might remain the same or be transformed into nodes with no integrals.
342340
/// </returns>
343341
public static Entity Integrate(this string str, Variable x)
344342
=> str.ToEntity().Integrate(x);
345343

344+
/// <summary>
345+
/// Integrates definitely the given expression over the `x` variable, if can.
346+
/// May return an unresolved <see cref="Integralf"/> node.
347+
/// </summary>
348+
/// <param name="str">
349+
/// The expression to be parsed and integrated
350+
/// </param>
351+
/// <param name="x">Over which variable to integrate</param>
352+
/// <param name="from">The lower bound for integrating</param>
353+
/// <param name="to">The upper bound for integrating</param>
354+
/// <returns>
355+
/// An integrated expression. It might remain the same or be transformed into nodes with no integrals.
356+
/// </returns>
357+
public static Entity Integrate(this string str, Variable x, Entity from, Entity to)
358+
=> str.ToEntity().Integrate(x, from, to);
359+
346360
/// <summary>
347361
/// Finds the limit of the given expression over the given variable
348362
/// </summary>

Sources/AngouriMath/Convenience/MathS.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6338,7 +6338,7 @@ public static Entity Integral(Entity expr, Variable x)
63386338
/// <param name="to">The complex upper bound for integrating</param>
63396339
[Obsolete("Now these functions are available as non-static methods at Entity")]
63406340
public static Complex DefiniteIntegral(Entity expr, Variable x, (EDecimal Re, EDecimal Im) from, (EDecimal Re, EDecimal Im) to) =>
6341-
Integration.Integrate(expr, x, from, to, 100);
6341+
DefiniteIntegral(expr, x, from, to, 100);
63426342

63436343
/// <summary>
63446344
/// Returns a value of a definite integral of a function. Only works for one-variable functions
@@ -6349,7 +6349,7 @@ public static Complex DefiniteIntegral(Entity expr, Variable x, (EDecimal Re, ED
63496349
/// <param name="to">The real upper bound for integrating</param>
63506350
[Obsolete("Now these functions are available as non-static methods at Entity")]
63516351
public static Complex DefiniteIntegral(Entity expr, Variable x, EDecimal from, EDecimal to) =>
6352-
Integration.Integrate(expr, x, (from, 0), (to, 0), 100);
6352+
DefiniteIntegral(expr, x, (from, 0), (to, 0), 100);
63536353

63546354
/// <summary>
63556355
/// Returns a value of a definite integral of a function. Only works for one-variable functions
@@ -6361,7 +6361,7 @@ public static Complex DefiniteIntegral(Entity expr, Variable x, EDecimal from, E
63616361
/// <param name="stepCount">Accuracy (initially, amount of iterations)</param>
63626362
[Obsolete("Now these functions are available as non-static methods at Entity")]
63636363
public static Complex DefiniteIntegral(Entity expr, Variable x, (EDecimal Re, EDecimal Im) from, (EDecimal Re, EDecimal Im) to, int stepCount) =>
6364-
Integration.Integrate(expr, x, from, to, stepCount);
6364+
Integration.IntegrateNumerically(expr, x, Complex.Create(from.Re, from.Im), Complex.Create(to.Re, to.Im), stepCount);
63656365

63666366

63676367
/// <summary>
@@ -6626,15 +6626,16 @@ public static Complex DefiniteIntegral(Entity expr, Variable x, (EDecimal Re, ED
66266626
/// a
66276627
/// </code>
66286628
/// </example>
6629-
public static Entity Integral(Entity expr, Entity var) => new Integralf(expr, var, 1);
6629+
public static Entity Integral(Entity expr, Entity var) => new Integralf(expr, var, null);
66306630

66316631
/// <summary>
66326632
/// Hangs your entity to an integral node
66336633
/// (to evaluate instead use <see cref="Compute.Integral(Entity, Variable)"/>)
66346634
/// </summary>
66356635
/// <param name="expr">Expression to be hung</param>
66366636
/// <param name="var">Variable over which integral is taken</param>
6637-
/// <param name="power">Number of times integral is taken. Only integers will be simplified or evaluated.</param>
6637+
/// <param name="from">The lower bound for integrating</param>
6638+
/// <param name="to">The upper bound for integrating</param>
66386639
/// <example>
66396640
/// <code>
66406641
/// using System;
@@ -6680,7 +6681,7 @@ public static Complex DefiniteIntegral(Entity expr, Variable x, (EDecimal Re, ED
66806681
/// a
66816682
/// </code>
66826683
/// </example>
6683-
public static Entity Integral(Entity expr, Entity var, int power) => new Integralf(expr, var, power);
6684+
public static Entity Integral(Entity expr, Entity var, Entity from, Entity to) => new Integralf(expr, var, (from, to));
66846685

66856686
/// <summary>
66866687
/// Hangs your entity to a limit node
@@ -6820,6 +6821,18 @@ public static class Boolean
68206821
/// </summary>
68216822
public static Entity.Boolean Create(bool b)
68226823
=> Entity.Boolean.Create(b);
6824+
6825+
/// <summary>
6826+
/// One of the Boolean's states, which also behaves as Entity
6827+
/// That is, hangable
6828+
/// </summary>
6829+
[ConstantField] public static readonly Entity.Boolean True = Entity.Boolean.True;
6830+
6831+
/// <summary>
6832+
/// One of the Boolean's states, which also behaves as Entity
6833+
/// That is, hangable
6834+
/// </summary>
6835+
[ConstantField] public static readonly Entity.Boolean False = Entity.Boolean.False;
68236836
}
68246837

68256838
/// <summary>

Sources/AngouriMath/Core/Antlr/AngouriMath.g

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/*
22

3-
Remember to run the "antlr_rerun.bat" file at the project root every time you modify this file so that other
4-
source files under the Antlr folder can update and be reflected in other parts of AngouriMath!
5-
It only consists of commands that are consistent across CMD and Bash so you should be able to run that file
6-
regardless of whether you are on Windows, Linux or Mac. You need to have an installed Java Runtime, however.
3+
Remember to run the "antlr_rerun.bat" file located at "Sources/Utils/antlr_rerun.bat" (relative to the repository root)
4+
every time you modify this file so that the generated source files under the Antlr folder are updated and changes are
5+
reflected in other parts of AngouriMath. The script only consists of commands that are consistent across CMD and Bash,
6+
so you should be able to run it on Windows, Linux, or Mac. You need to have an installed Java Runtime, however.
77

88
*/
99

@@ -362,12 +362,12 @@ atom returns[Entity value]
362362
}
363363
| 'integral(' args = function_arguments ')'
364364
{
365-
if (Assert("integral", (3, 2), $args.list.Count))
365+
if (Assert("integral", (4, 2), $args.list.Count))
366366
{
367-
if ($args.list[2] is Integer { EInteger: var asEInt })
368-
$value = MathS.Integral($args.list[0], $args.list[1], asEInt.ToInt32Checked());
367+
if ($args.list.Count == 4)
368+
$value = MathS.Integral($args.list[0], $args.list[1], $args.list[2], $args.list[3]);
369369
else
370-
throw new InvalidArgumentParseException("Expected number for the third argument of integral");
370+
$value = MathS.Integral($args.list[0], $args.list[1]);
371371
}
372372
else
373373
$value = MathS.Integral($args.list[0], $args.list[1]);

Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,12 +2968,12 @@ public AtomContext atom() {
29682968
State = 734;
29692969
Match(T__39);
29702970

2971-
if (Assert("integral", (3, 2), _localctx.args.list.Count))
2971+
if (Assert("integral", (4, 2), _localctx.args.list.Count))
29722972
{
2973-
if (_localctx.args.list[2] is Integer { EInteger: var asEInt })
2974-
_localctx.value = MathS.Integral(_localctx.args.list[0], _localctx.args.list[1], asEInt.ToInt32Checked());
2973+
if (_localctx.args.list.Count == 4)
2974+
_localctx.value = MathS.Integral(_localctx.args.list[0], _localctx.args.list[1], _localctx.args.list[2], _localctx.args.list[3]);
29752975
else
2976-
throw new InvalidArgumentParseException("Expected number for the third argument of integral");
2976+
_localctx.value = MathS.Integral(_localctx.args.list[0], _localctx.args.list[1]);
29772977
}
29782978
else
29792979
_localctx.value = MathS.Integral(_localctx.args.list[0], _localctx.args.list[1]);

Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Calculus.Classes.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ namespace AngouriMath
1212
partial record Entity
1313
{
1414
#pragma warning disable CS1591 // only while records' parameters cannot be documented
15-
// Iterations should be refactored? to be int instead of Entity
1615
/// <summary>
1716
/// A node of derivative
1817
/// </summary>
18+
/// <remarks>
19+
/// Negative iterations convert to integrals.
20+
/// </remarks>
1921
public sealed partial record Derivativef(Entity Expression, Entity Var, int Iterations) : CalculusOperator(Expression, Var)
2022
{
2123
/// <summary>Reuse the cache by returning the same object if possible</summary>
@@ -32,17 +34,19 @@ public override Entity Replace(Func<Entity, Entity> func) =>
3234
/// <summary>
3335
/// A node of integral
3436
/// </summary>
35-
public sealed partial record Integralf(Entity Expression, Entity Var, int Iterations) : CalculusOperator(Expression, Var)
37+
public sealed partial record Integralf(Entity Expression, Entity Var, (Entity from, Entity to)? Range) : CalculusOperator(Expression, Var)
3638
{
3739
/// <summary>Reuse the cache by returning the same object if possible</summary>
38-
private Integralf New(Entity expression, Entity var) =>
40+
private Integralf New(Entity expression, Entity var, (Entity from, Entity to)? range) =>
3941
ReferenceEquals(Expression, expression) && ReferenceEquals(Var, var)
40-
? this : new(expression, var, Iterations);
42+
&& (range is null && Range is null || range is var (newFrom, newTo) && Range is var (oldFrom, oldTo)
43+
&& ReferenceEquals(newFrom, oldFrom) && ReferenceEquals(newTo, oldTo))
44+
? this : new(expression, var, range);
4145
/// <inheritdoc/>
4246
public override Entity Replace(Func<Entity, Entity> func) =>
43-
func(New(Expression.Replace(func), Var.Replace(func)));
47+
func(New(Expression.Replace(func), Var, Range is var (from, to) ? (from.Replace(func), to.Replace(func)) : null));
4448
/// <inheritdoc/>
45-
protected override Entity[] InitDirectChildren() => new[] { Expression, Var, Iterations };
49+
protected override Entity[] InitDirectChildren() => Range is var (from, to) ? [Expression, Var, from, to] : [Expression, Var];
4650
}
4751

4852
/// <summary>

Sources/AngouriMath/Core/Entity/Discrete/Entity.Discrete.Classes.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ partial record Entity
2020
public sealed partial record Boolean(bool Value) : Statement
2121
{
2222
/// <summary>
23-
/// One of the Boolean's state, which also behaves as Entity
23+
/// One of the Boolean's states, which also behaves as Entity
2424
/// That is, hangable
2525
/// </summary>
2626
[ConstantField] public static readonly Boolean True = new Boolean(true);
2727

2828
/// <summary>
29-
/// One of the Boolean's state, which also behaves as Entity
29+
/// One of the Boolean's states, which also behaves as Entity
3030
/// That is, hangable
3131
/// </summary>
3232
[ConstantField] public static readonly Boolean False = new Boolean(false);

Sources/AngouriMath/Functions/Continuous/Differentiation.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,15 @@ partial record Matrix
8181
}
8282

8383
/// <summary>Derives over <paramref name="x"/> <paramref name="power"/> times</summary>
84-
public Entity Differentiate(Variable x, EInteger power)
84+
public Entity Differentiate(Variable x, int power)
8585
{
8686
var ent = this;
87-
for (var _ = 0; _ < power; _++)
88-
ent = ent.InnerDifferentiate(x);
87+
if (power < 0)
88+
for (var _ = 0; _ < -power; _++)
89+
ent = ent.Integrate(x);
90+
else
91+
for (var _ = 0; _ < power; _++)
92+
ent = ent.InnerDifferentiate(x);
8993
return ent;
9094
}
9195

@@ -276,7 +280,11 @@ partial record Integralf
276280
/// <inheritdoc/>
277281
protected override Entity InnerDifferentiate(Variable variable) =>
278282
Var == variable
279-
? this with { Iterations = Iterations - 1 }
283+
? Range is var (from, to)
284+
// https://math.stackexchange.com/a/139191/627798
285+
? to.InnerDifferentiate(variable) * Expression.Substitute(variable, to) -
286+
from.InnerDifferentiate(variable) * Expression.Substitute(variable, from)
287+
: Expression
280288
: MathS.Derivative(this, variable, 1);
281289
}
282290
#pragma warning restore IDE0054 // Use compound assignment
@@ -303,10 +311,9 @@ protected override Entity InnerDifferentiate(Variable variable)
303311

304312
partial record Absf
305313
{
306-
// TODO: derivative of the absolute function?
307314
/// <inheritdoc/>
308315
protected override Entity InnerDifferentiate(Variable variable)
309-
=> MathS.Signum(Argument) * Argument.InnerDifferentiate(variable);
316+
=> MathS.Signum(Argument).Provided(!Argument.Equalizes(Integer.Zero)) * Argument.InnerDifferentiate(variable);
310317
}
311318

312319
partial record Providedf

0 commit comments

Comments
 (0)