Skip to content

Instantly share code, notes, and snippets.

@istupakov
Last active February 2, 2017 21:09
Show Gist options
  • Save istupakov/de87bdb33c1100d831007d201f67bd7e to your computer and use it in GitHub Desktop.
Save istupakov/de87bdb33c1100d831007d201f67bd7e to your computer and use it in GitHub Desktop.
Automatic differentiation (second order) on C# with Roslyn for parsing.
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); };
}
}
}
@JessicaLawson
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment