Last active
February 2, 2017 21:09
-
-
Save istupakov/de87bdb33c1100d831007d201f67bd7e to your computer and use it in GitHub Desktop.
Automatic differentiation (second order) on C# with Roslyn for parsing.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using System.Threading.Tasks; | |
using Microsoft.CodeAnalysis.CSharp.Scripting; | |
using Microsoft.CodeAnalysis.Scripting; | |
namespace AutomaticDifferentiation | |
{ | |
public struct DualNumber | |
{ | |
public double Value { get; } | |
public double Eps { get; } | |
public double Eps2 { get; } | |
public DualNumber(double value, double eps = 0, double eps2 = 0) | |
{ | |
Value = value; | |
Eps = eps; | |
Eps2 = eps2; | |
} | |
public static implicit operator DualNumber(double v) => new DualNumber(v); | |
#region Arithmetic Operators | |
public static DualNumber operator +(DualNumber a) => a; | |
public static DualNumber operator -(DualNumber a) => new DualNumber(-a.Value, -a.Eps, -a.Eps2); | |
public static DualNumber operator +(DualNumber a, DualNumber b) => new DualNumber(a.Value + b.Value, a.Eps + b.Eps, a.Eps2 + b.Eps2); | |
public static DualNumber operator +(double a, DualNumber b) => new DualNumber(a + b.Value, b.Eps, b.Eps2); | |
public static DualNumber operator +(DualNumber a, double b) => new DualNumber(a.Value + b, a.Eps, a.Eps2); | |
public static DualNumber operator -(DualNumber a, DualNumber b) => new DualNumber(a.Value - b.Value, a.Eps - b.Eps, a.Eps2 - b.Eps2); | |
public static DualNumber operator -(double a, DualNumber b) => new DualNumber(a - b.Value, -b.Eps, -b.Eps2); | |
public static DualNumber operator -(DualNumber a, double b) => new DualNumber(a.Value - b, a.Eps, a.Eps2); | |
public static DualNumber operator *(DualNumber a, DualNumber b) | |
=> new DualNumber(a.Value * b.Value, a.Eps * b.Value + b.Eps * a.Value, a.Value * b.Eps2 + a.Eps * b.Eps + a.Eps2 * b.Value); | |
public static DualNumber operator *(double a, DualNumber b) => new DualNumber(a * b.Value, a * b.Eps, a * b.Eps2); | |
public static DualNumber operator *(DualNumber a, double b) => new DualNumber(a.Value * b, a.Eps * b, a.Eps2 * b); | |
public static DualNumber operator /(DualNumber a, DualNumber b) => a * Inverse(b); | |
public static DualNumber operator /(double a, DualNumber b) => a * Inverse(b); | |
public static DualNumber operator /(DualNumber a, double b) => a * (1 / b); | |
#endregion | |
#region Power Functions | |
public static DualNumber Inverse(DualNumber a) | |
{ | |
return new DualNumber(1 / a.Value, -a.Eps / (a.Value * a.Value), (a.Eps * a.Eps / a.Value - a.Eps2) / (a.Value * a.Value)); | |
} | |
public static DualNumber Sqrt(DualNumber a) | |
{ | |
var r = Math.Sqrt(a.Value); | |
return new DualNumber(r, 0.5 * a.Eps / r, 0.5 * a.Eps2 / r - 0.125 * a.Eps * a.Eps / (a.Value * r)); | |
} | |
public static DualNumber Exp(DualNumber a) | |
{ | |
var exp = Math.Exp(a.Value); | |
return new DualNumber(exp, exp * a.Eps, exp * (a.Eps2 + 0.5 * a.Eps * a.Eps)); | |
} | |
public static DualNumber Log(DualNumber a) | |
{ | |
return new DualNumber(Math.Log(a.Value), a.Eps / a.Value, (a.Eps2 - 0.5 * a.Eps * a.Eps / a.Value) / a.Value); | |
} | |
public static DualNumber Pow(DualNumber a, DualNumber b) => Exp(b * Log(a)); | |
public static DualNumber Pow(DualNumber a, double b) | |
{ | |
var pow = Math.Pow(a.Value, b); | |
var frac = a.Eps / a.Value; | |
return new DualNumber(pow, b * pow * frac, b * pow * (a.Eps2 / a.Value + 0.5 * (b - 1) * frac * frac)); | |
} | |
#endregion | |
#region Trigonometric Functions | |
public static DualNumber Sin(DualNumber a) | |
{ | |
var sin = Math.Sin(a.Value); | |
var cos = Math.Cos(a.Value); | |
return new DualNumber(sin, cos * a.Eps, cos * a.Eps2 - 0.5 * sin * a.Eps * a.Eps); | |
} | |
public static DualNumber Cos(DualNumber a) | |
{ | |
var sin = Math.Sin(a.Value); | |
var cos = Math.Cos(a.Value); | |
return new DualNumber(cos, -sin * a.Eps, -sin * a.Eps2 - 0.5 * cos * a.Eps * a.Eps); | |
} | |
public static DualNumber Tan(DualNumber a) | |
{ | |
var tan = Math.Tan(a.Value); | |
return new DualNumber(tan, (1 + tan * tan) * a.Eps, (1 + tan * tan) * (a.Eps2 + tan * a.Eps * a.Eps)); | |
} | |
public static DualNumber Asin(DualNumber a) | |
{ | |
var tmp = 1 / Math.Sqrt(1 - a.Value * a.Value); | |
var tmpEps = a.Eps * tmp; | |
return new DualNumber(Math.Asin(a.Value), tmpEps, (a.Eps2 + 0.5 * a.Value * tmpEps * tmpEps) * tmp); | |
} | |
public static DualNumber Acos(DualNumber a) | |
{ | |
var tmp = 1 / Math.Sqrt(1 - a.Value * a.Value); | |
var tmpEps = a.Eps * tmp; | |
return new DualNumber(Math.Acos(a.Value), -tmpEps, -(a.Eps2 + 0.5 * a.Value * tmpEps * tmpEps) * tmp); | |
} | |
public static DualNumber Atan(DualNumber a) | |
{ | |
var tmp = 1 / (1 + a.Value * a.Value); | |
var tmpEps = a.Eps * tmp; | |
return new DualNumber(Math.Atan(a.Value), tmpEps, a.Eps2 * tmp - a.Value * tmpEps * tmpEps); | |
} | |
#endregion | |
#region Hyperbolic Functions | |
public static DualNumber Sinh(DualNumber a) | |
{ | |
var sin = Math.Sinh(a.Value); | |
var cos = Math.Cosh(a.Value); | |
return new DualNumber(sin, cos * a.Eps, cos * a.Eps2 + 0.5 * sin * a.Eps * a.Eps); | |
} | |
public static DualNumber Cosh(DualNumber a) | |
{ | |
var sin = Math.Sinh(a.Value); | |
var cos = Math.Cosh(a.Value); | |
return new DualNumber(cos, sin * a.Eps, sin * a.Eps2 + 0.5 * cos * a.Eps * a.Eps); | |
} | |
public static DualNumber Tanh(DualNumber a) | |
{ | |
var tan = Math.Tanh(a.Value); | |
return new DualNumber(tan, (1 - tan * tan) * a.Eps, (1 - tan * tan) * (a.Eps2 - tan * a.Eps * a.Eps)); | |
} | |
#endregion | |
} | |
public class Parser | |
{ | |
public static async Task<Func<double, double>> Compile(string text) | |
{ | |
var options = ScriptOptions.Default.WithReferences(typeof(Expression).GetTypeInfo().Assembly); | |
var expr = await CSharpScript.EvaluateAsync<Expression<Func<double, double>>>(text, options); | |
return expr.Compile(); | |
} | |
public static async Task<Func<double, (double value, double diff, double diff2)>> CompileDiff(string text) | |
{ | |
var options = ScriptOptions.Default.WithReferences(typeof(Expression).GetTypeInfo().Assembly, typeof(DualNumber).GetTypeInfo().Assembly).WithImports(typeof(DualNumber).FullName); | |
var expr = await CSharpScript.EvaluateAsync<Expression<Func<DualNumber, DualNumber>>>(text, options); | |
var f = expr.Compile(); | |
return t => { var r = f(new DualNumber(t, 1)); return (r.Value, r.Eps, 2 * r.Eps2); }; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello
Happy to meet you, my name is Miss Jessica Lawson, it is my pressure to meet you here today through this site, i will like you to write to me so that i can be able to tell you more about me and the reason of my contact with you. here is my private email address, please write to me here so that i can tell you more anout me and also to send my picture to you ( jesicalawson91@gmail.com ) thanks
Yours Miss Jessica Lawson