/// <summary> /// Provides the value of the function /// </summary> /// <param name="context"></param> /// <param name="actuals"></param> /// <param name="explain"></param> /// <returns>The value for the function application</returns> public virtual IValue Evaluate(InterpretationContext context, Dictionary<Actual, IValue> actuals, ExplanationPart explain) { IValue retVal = null; bool useCache = EFSSystem.CacheFunctions; ExplainedValue explainedValue = null; // Only use the cached value when the EFSSystem indicates that caches should be used // This condition has been added to handle the fact that the user changes the status // of EFSSystem.CacheFunctions within a test session if (useCache) { if (_cachedResult == null) { _cachedResult = new CurryCache(this); } explainedValue = _cachedResult.GetValue(actuals); } if (explainedValue == null) { int token = context.LocalScope.PushContext(); AssignParameters(context, actuals); if (Cases.Count > 0) { bool preConditionSatisfied = false; // Statically defined function foreach (Case aCase in Cases) { // Evaluate the function ExplanationPart subExplanation = ExplanationPart.CreateSubExplanation(explain, aCase); preConditionSatisfied = aCase.EvaluatePreConditions(context, subExplanation); ExplanationPart.SetNamable(subExplanation, preConditionSatisfied ? EFSSystem.BoolType.True : EFSSystem.BoolType.False); if (preConditionSatisfied) { retVal = aCase.Expression.GetValue(context, subExplanation); break; } } if (!preConditionSatisfied) { ExplanationPart.CreateSubExplanation(explain, "Partial function called outside its domain"); AddError("Partial function called outside its domain"); } } else if (Surface != null && FormalParameters.Count == 2) { double x = 0.0; double y = 0.0; Parameter formal1 = (Parameter) FormalParameters[0]; Parameter formal2 = (Parameter) FormalParameters[1]; foreach (KeyValuePair<Actual, IValue> pair in actuals) { if (pair.Key.Parameter == formal1) { x = GetDoubleValue(pair.Value); } if (pair.Key.Parameter == formal2) { y = GetDoubleValue(pair.Value); } } retVal = new DoubleValue(EFSSystem.DoubleType, Surface.Val(x, y)); } else if (Graph != null && FormalParameters.Count < 2) { if (FormalParameters.Count == 0) { retVal = new DoubleValue(EFSSystem.DoubleType, Graph.Evaluate(0)); } else if (FormalParameters.Count == 1) { double x = 0.0; Parameter formal = (Parameter) FormalParameters[0]; foreach (KeyValuePair<Actual, IValue> pair in actuals) { if (pair.Key.Parameter == formal) { x = GetDoubleValue(pair.Value); } } retVal = new DoubleValue(EFSSystem.DoubleType, Graph.Evaluate(x)); } } context.LocalScope.PopContext(token); ExplanationPart.SetNamable(explain, retVal); if (useCache) { _cachedResult.SetValue(actuals, retVal, explain); } } else { retVal = explainedValue.Value; ExplanationPart subExplain = ExplanationPart.CreateSubExplanation(explain, "Cached result = "); ExplanationPart.SetNamable(subExplain, retVal); // Reuse the explanation of the return value computation // Topmost entry is the function call, useless, so don't provide it if (explainedValue.Explanation != null) { foreach (ExplanationPart part in explainedValue.Explanation.SubExplanations) { ExplanationPart.AddSubExplanation(subExplain, part); } } } return retVal; }
/// <summary> /// Clears the caches for this function /// </summary> public override void ClearCache() { base.ClearCache(); _cachedResult = null; Graph = null; Surface = null; }