Select Git revision
FunctionFact.cs
FunctionFact.cs 10.26 KiB
using Newtonsoft.Json;
using REST_JSON_API;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using UnityEngine;
/// <summary>
/// Binds a domain mapper (<see cref="FunctionFact"/>) opperating on time t in seconds to a <see cref="FunctionFact"/>.
/// Uses <see cref="FunctionFact"/> Function_args to map from a linear scale to the domain of <see cref="FunctionFact"/> Function to execute it.
/// </summary>
public class FunctionCallFact : FactWrappedCRTP<FunctionCallFact>
{
protected override object GetCompiledValue()
=> Tuple.Create(Domain, Function_args.CompiledValue, Function.CompiledValue);
/// <summary>
/// <see cref="Fact.Id"/> of <see cref="Function"/>
/// </summary>
public string func_id
{
get => Function?.Id ?? _func_id;
private set
{
_func_id = value;
FactRecorder.AllFacts.TryGetValue(value, out Fact func);
Function = (FunctionFact)func;
}
}
private string _func_id;
/// <summary>
/// <see cref="Fact.Id"/> of <see cref="Function_args"/>
/// </summary>
public string arg_func_id
{
get => Function_args?.Id ?? _arg_func_id;
private set
{
_arg_func_id = value;
FactRecorder.AllFacts.TryGetValue(value, out Fact func);
Function_args = (FunctionFact)func;
}
}
private string _arg_func_id;
/// <summary>
/// Linear domain on R this Fact is valid on;
/// Intervall is defined as [t_0, t_n]
/// </summary>
public (float t_0, float t_n) Domain;
/// <summary>
/// The function to be called with <see cref="Call(float)"/>
/// </summary>
[JsonIgnore]
public FunctionFact Function;
/// <summary>
/// Mapps from linear <see cref="Domain"/> to arguments from <see cref="Function"/>. (may be multidimensional)
/// </summary>
[JsonIgnore]
public FunctionFact Function_args;
[JsonConstructor]
public FunctionCallFact(string func_id, string arg_func_id, (float t_0, float t_n) Domain) : base()
{
this.func_id = func_id;
this.arg_func_id = arg_func_id;
this.Domain = Domain;
if (Function_args != null // is case when reading in Json
&& (Function_args.Signature[0] != typeof(float) // takes in |R
|| (Function_args.Signature[1..].SequenceEqual(Function.Signature[..^0]) // output equals input
&& Function_args.Signature[^1] != typeof(object[])))) // if output is object array => types are concieled
throw new ArgumentException(
$"Signatures must match: Func<float, D> {nameof(arg_func_id)} and Func<D,R> {nameof(func_id)}!\n" +
$"But where {Function_args.Signature} and {Function.Signature}.");
}
public FunctionCallFact(FunctionFact Function, FunctionFact Function_args, (float t_0, float t_n) Domain) : base()
{
this.Function = Function;
this.Function_args = Function_args;
this.Domain = Domain;
if (Function_args.Signature[0] != typeof(float) // takes in |R
|| (Function_args.Signature[1..].SequenceEqual(Function.Signature[..^0]) // output equals input
&& Function_args.Signature[^1] != typeof(object[]))) // if output is object array => types are concieled
throw new ArgumentException(
$"Signatures must match: Func<float, D> {nameof(arg_func_id)} and Func<D,R> {nameof(func_id)}!\n" +
$"But where {Function_args.Signature} and {Function.Signature}.");
}
/// <summary>
/// Mapps <paramref name="t"/> with <see cref="Function_args"/> to domain of <see cref="Function"/> and calls it.
/// </summary>
/// <param name="t">to be used as argument for <see cref="Function_args"/>. Semantical use is time in seconds.</param>
/// <returns><see cref="Function"/>(<see cref="Function_args"/>(<paramref name="t"/>)) iff <paramref name="t"/> is within <see cref="Domain"/></returns>
public object[] Call(float t)
{
if (t < Domain.t_0 || t > Domain.t_n)
return null;
object[] path = Function_args.Function(new object[] { t });
return Function.Function(path);
}
public override bool HasDependentFacts
=> true;
protected override string[] GetDependentFactIds()
=> new[] { func_id, arg_func_id };
protected override bool EquivalentWrapped(FunctionCallFact f1, FunctionCallFact f2)
{
if (Mathf.Approximately(f1.Domain.t_0, f2.Domain.t_0)
&& Mathf.Approximately(f1.Domain.t_n, f2.Domain.t_n)
&& DependentFactsEquivalent(f1, f2)
)
return true;
if (f1.Function.Signature[^1] != f2.Function.Signature[^1])
return false;
return false;
int samplenumber = 3;
float stepsizef1 = (f1.Domain.t_n - f1.Domain.t_0) / (samplenumber - 1);
float stepsizef2 = (f2.Domain.t_n - f2.Domain.t_0) / (samplenumber - 1);
for ((int i, float f1step, float f2step) = (0, f1.Domain.t_0, f2.Domain.t_0);
i < samplenumber;
i++, f1step += stepsizef1, f2step += stepsizef2)
{
object[] c1 = f1.Call(f1step);
object[] c2 = f2.Call(f2step);
if (c1 == null || c2 == null
|| !c1.SequenceEqual(c2, new ApproximationComparer(1e-3d)))
return false;
}
return true;
}
public override MMTFact MakeMMTDeclaration()
{
MMTGeneralFact mmt_arg = (MMTGeneralFact)Function_args.MakeMMTDeclaration();
MMTGeneralFact mmt_in = (MMTGeneralFact)Function.MakeMMTDeclaration();
SOMDoc type = new OMA(
new OMS(MMTConstants.Product),
new[]{
new OMA(
new OMS(MMTConstants.Product),
new []{
new OMS(MMTConstants.RealLit),
new OMS(MMTConstants.RealLit)
}),
mmt_arg.type,
mmt_in.type,
});
return new MMTGeneralFact(_LastLabel, type, Defines());
}
public override SOMDoc Defines()
=> new OMA(
new OMS(MMTConstants.Tuple),
new[] {
new OMA(
new OMS(MMTConstants.Tuple),
new[]{
new OMLIT<float>(Domain.t_0),
new OMLIT<float>(Domain.t_n)
}),
Function_args?.ServerDefinition ?? OMNONE.Instance,
Function?.ServerDefinition ?? OMNONE.Instance,
});
protected override void RecalculateTransform()
{
Position = Function.Position;
Rotation = Function.Rotation;
LocalScale = Function.LocalScale;
}
protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new)
=> new FunctionCallFact(old_to_new[this.func_id], old_to_new[this.arg_func_id], this.Domain);
}
/// <summary>
/// A function <c>Func<object[], object[]></c> as Fact.
/// </summary>
public class FunctionFact : FactWrappedCRTP<FunctionFact>
{
protected override object GetCompiledValue()
=> Expression.Lambda(CompileBase).Compile().DynamicInvoke();
/// <summary>
/// MMT AST representing the function
/// </summary>
public SOMDoc Function_SOMDoc;
/// <summary>
/// The signature of this function.
/// </summary>
[JsonIgnore]
public Type[] Signature;
/// <summary>
/// Encapsulated function.
/// </summary>
[JsonIgnore]
public Func<object[], object[]> Function;
/// <summary> \copydoc Fact.Fact </summary>
public FunctionFact() : base() { }
/// <summary>
/// Standard Constructor:
/// Initiates members and creates MMT %Fact Server-Side
/// </summary>
/// <param name="Function_SOMDoc">sets <see cref="Function_SOMDoc"/> and contains the Abstract Syntax Tree</param>
public FunctionFact(SOMDoc Function_SOMDoc) : base()
{
this.Function_SOMDoc = Function_SOMDoc;
this.Function = this.Function_SOMDoc.PartialInvokeCastingLambdaExpression(out Expression CompileBase, out Signature);
this.CompileBase = CompileBase;
}
/// <summary>
/// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
/// </summary>
/// <param name="function_expression">sets <see cref="Function_expression"/> and contains the Abstract Syntax Tree</param>
/// <param name="uri">MMT URI</param>
public FunctionFact(SOMDoc Function_SOMDoc, SOMDoc _ServerDefinition) : base()
{
this.Function_SOMDoc = Function_SOMDoc;
this.Function = Function_SOMDoc.PartialInvokeCastingLambdaExpression(out Expression CompileBase, out Signature);
this.CompileBase = CompileBase;
this.ServerDefinition = _ServerDefinition;
}
protected override void RecalculateTransform() { }
/// \copydoc Fact.parseFact(ScrollFact)
public new static IEnumerator parseFact(List<Fact> ret, MMTFact fact)
{// TODO Correctness
if (((MMTGeneralFact)fact).defines is not FUN fun
&& (((MMTGeneralFact)fact).defines is not FallbackWrapper SFW
|| (fun = SFW.Wrapper as FUN) == null)
)
yield break;
ParsingDictionary.parseTermsToId.TryAdd(fun.ToString(), fact.@ref.uri);
ret.Add(new FunctionFact(fun, fact.@ref));
}
/// \copydoc Fact.hasDependentFacts
public override bool HasDependentFacts
=> false;
/// \copydoc Fact.getDependentFactIds
protected override string[] GetDependentFactIds()
=> new string[] { };
/// \copydoc Fact.GetHashCode
public override int GetHashCode()
=> Function.GetHashCode();
/// \copydoc Fact.EquivalentWrapped
protected override bool EquivalentWrapped(FunctionFact f1, FunctionFact f2)
=> f1.Function_SOMDoc.Equivalent(f2.Function_SOMDoc);
protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new)
=> new FunctionFact(this.Function_SOMDoc.MapURIs(old_to_new));
public override MMTFact MakeMMTDeclaration()
=> new MMTGeneralFact(
_LastLabel,
SOMDoc.SOMDocType(FuncExtensions.CreateFuncType(Signature)),
Defines());
public override SOMDoc Defines()
=> Function_SOMDoc;
}