/*
* Created by SharpDevelop.
* User: Davide
* Date: 08/09/2012
* Time: 20:28
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using SMath.Manager;
using SMath.Math;
namespace NonlinearSolvers.Primitives
{
///
/// Bisected Direct Quadratic Regula Falsi root-finding method.
///
public class BDQRF
{
static public string SMathPrimitiveName = "BDQRF";
static public TermInfo GetTermInfos_3()
{
return
new TermInfo
(
SMathPrimitiveName,
TermType.Function,
string.Format(Translator.GetString("RFM_BDQRF_dialog_3"), GlobalParams.DecimalPlaces),
FunctionSections.Unknown,
true,
new ArgumentInfo(ArgumentSections.Function),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition)
);
}
static public TermInfo GetTermInfos_4()
{
return
new TermInfo
(
SMathPrimitiveName,
TermType.Function,
Translator.GetString("RFM_BDQRF_dialog_4"),
FunctionSections.Unknown,
true,
new ArgumentInfo(ArgumentSections.Function),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition)
);
}
static public TermInfo GetTermInfos_5()
{
return
new TermInfo
(
SMathPrimitiveName,
TermType.Function,
Translator.GetString("RFM_BDQRF_dialog_5"),
FunctionSections.Unknown,
true,
new ArgumentInfo(ArgumentSections.Function),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition)
);
}
static public TermInfo GetTermInfos_9()
{
return
new TermInfo
(
SMathPrimitiveName,
TermType.Function,
Translator.GetString("RFM_BDQRF_dialog_9"),
FunctionSections.Unknown,
true,
new ArgumentInfo(ArgumentSections.Function),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.Condition),
new ArgumentInfo(ArgumentSections.RealNumber),
new ArgumentInfo(ArgumentSections.Variable),
new ArgumentInfo(ArgumentSections.Variable),
new ArgumentInfo(ArgumentSections.Variable)
);
}
static public bool IsSupport(Term root)
{
if (root.Text == SMathPrimitiveName && ((root.ArgsCount >= 3 && root.ArgsCount <= 5) || root.ArgsCount == 9)) return true;
return false;
}
static public bool LowLevelEvaluation( Term root, Term[][] args, ref Store context, ref Term[] result )
{
Term[]
arg1 = Computation.Preprocessing(args[0], ref context),
arg2 = Computation.Preprocessing(args[1], ref context),
arg3 = Computation.Preprocessing(args[2], ref context),
// optional arguments
arg4 = (root.ArgsCount >= 4) ? Computation.Preprocessing(args[3], ref context) : TermsConverter.ToTerms("0"),
arg5 = (root.ArgsCount >= 5) ? Computation.Preprocessing(args[4], ref context) : TermsConverter.ToTerms("0");
// preprocessing the output pattern, clear LHS defined variables.
Term[] outputPattern = SharedFunctions.pattern2std(args[1], ref context);
// initialize an empty store
Store store = context.Scope.CreateStore();
store.FileName = context.FileName;
store.Optimization = context.Optimization;
store.FractionsTypeNumeric = context.FractionsTypeNumeric;
// preprocessing functions and starting values
arg1 = SharedFunctions.equations2std(context.Scope, arg1, arg2);
arg2 = SharedFunctions.variables2std(context.Scope, arg2);
arg3 = SharedFunctions.variables2std(context.Scope, arg3);
// get the variable units
List myBuffer = new List();
myBuffer.AddRange(arg2);
myBuffer.Add(new Term(Functions.Abs, TermType.Function, 1));
myBuffer.AddRange(arg3);
myBuffer.Add(new Term(Functions.Abs, TermType.Function, 1));
myBuffer.Add(new Term(Operators.Composition, TermType.Operator, 2));
Term[] units = UoM.getUnits(context.Scope, myBuffer.ToArray());
// make anything dimensionless
arg1 = UoM.remUnits(context.Scope, arg1);
arg2 = UoM.remUnits(context.Scope, arg2);
arg3 = UoM.remUnits(context.Scope, arg3);
arg4 = UoM.remUnits(context.Scope, arg4);
arg5 = UoM.remUnits(context.Scope, arg5);
// set the target precision of the function
if (root.ArgsCount == 3)
{
myBuffer.Clear();
myBuffer.Add(new Term("10", TermType.Operand, 0));
myBuffer.Add(new Term(GlobalParams.DecimalPlaces.ToString(), TermType.Operand, 0));
myBuffer.Add(new Term(Operators.Subtraction, TermType.Operator, 1));
myBuffer.Add(new Term(Operators.Exponentiation, TermType.Operator, 2));
arg4 = Computation.Preprocessing(myBuffer.ToArray(), ref store);
}
// number of iterations (default)
int arg6 = 100;
// show the number of iterations (default)
bool arg7 = false;
// show the step-by-step summary (default)
bool arg8 = false;
// save the step-by-step summary (default)
bool arg9 = false;
if (root.ArgsCount == 9)
{
int a6 = Int32.Parse(TermsConverter.ToString(Computation.SymbolicCalculation(args[5], ref context)));
arg6 = (a6 > 0) ? a6 : arg6;
arg7 = (TermsConverter.ToString(Computation.Preprocessing(args[6], ref context)) != "0") ? true : arg7;
arg8 = (TermsConverter.ToString(Computation.Preprocessing(args[7], ref context)) != "0") ? true : arg8;
arg9 = (TermsConverter.ToString(Computation.Preprocessing(args[8], ref context)) != "0") ? true : arg9;
}
// main alghoritm
Term[][] solution = trySolve(arg1, arg2, arg3, arg4, arg5, arg6, arg8, arg9, ref store);
List myResult = new List();
// add the result
myResult.AddRange(SharedFunctions.PostProcessing(context.Scope, solution[0], units, outputPattern, ref context));
int i = 1;
// add the number of iterations
if (arg7)
{
myResult.AddRange(solution[1]);
myResult.Add(new Term("1", TermType.Operand, 0));
myResult.Add(new Term("1", TermType.Operand, 0));
myResult.Add(new Term(Functions.Mat, TermType.Function, 3));
i++;
}
// add the summary
if (arg8)
{
myResult.AddRange(solution[2]);
i++;
}
// output vector
if (i > 1)
{
myResult.Add(new Term(i.ToString(), TermType.Operand, 0));
myResult.Add(new Term("1", TermType.Operand, 0));
myResult.Add(new Term(Functions.Mat, TermType.Function, 2 + i));
}
// output the result
result = myResult.ToArray();
return true;
}
static public Term[][] trySolve(Term[] function, Term[] bound_P1, Term[] bound_P2, Term[] epsilon_fx, Term[] epsilon_Δx, int maxIterations, bool showSummary, bool saveSummary, ref Store context)
{
List
myBuffer = new List(), // Buffer to use for chunks of code
myResult = new List(); // Result Term List
// initialize the step-by-step summary
Summary summary = new Summary("BDQRF", context.FileName);
if (showSummary || saveSummary)
{
summary.AddLine(new string[]{"i","Xdn","Xup","X","f(Xdn)","f(Xup)","f(X)"}, saveSummary);
}
int i = 0;
Term[]
num_0 = TermsConverter.ToTerms("0"),
num_1 = TermsConverter.ToTerms("1"),
num_2 = TermsConverter.ToTerms("2"),
num_4 = TermsConverter.ToTerms("4"),
var_X = bound_P1,
var_Xdn = null,
var_Xup = null,
var_Xm = null,
var_Y = SharedFunctions.setValues(context.Scope, function, var_X),
var_Ydn = null,
var_Yup = null,
var_Ym = null,
var_Xlast = TermsConverter.ToTerms("10^300"),
var_D = null,
var_a = null,
var_b = null;
// if/else #1, condition: [y<0]
myBuffer.Clear();
myBuffer.AddRange(var_Y);
myBuffer.AddRange(num_0);
myBuffer.Add(new Term(Operators.BooleanLess, TermType.Operator, 2));
myBuffer.Add(new Term(Functions.Eval, TermType.Function, 1));
string myFlag = Computation.Preprocessing(myBuffer.ToArray(), ref context)[0].Text;
if (myFlag == "1")
{
var_Xdn = bound_P1;
var_Xup = bound_P2;
}
else
{
var_Xdn = bound_P2;
var_Xup = bound_P1;
}
// [y.dn:f(x.dn)]
var_Ydn = SharedFunctions.setValues(context.Scope, function, var_Xdn);
// [y.up:f(x.up)]
var_Yup = SharedFunctions.setValues(context.Scope, function, var_Xup);
// check that [sign(f(x.dn))*sign(f(x.up))<=0]
myBuffer.Clear();
myBuffer.AddRange(var_Ydn);
myBuffer.Add(new Term(Functions.Sign, TermType.Function, 1));
myBuffer.AddRange(var_Yup);
myBuffer.Add(new Term(Functions.Sign, TermType.Function, 1));
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.AddRange(num_0);
myBuffer.Add(new Term(Operators.BooleanMore, TermType.Operator, 2));
myBuffer.Add(new Term(Functions.Eval, TermType.Function, 1));
myFlag = Computation.Preprocessing(myBuffer.ToArray(), ref context)[0].Text;
// wrong delimiters
if (myFlag == "1")
{
throw new Exception(Translator.GetString("error_delimiters"));
}
// // HACK: set an unit of measurement for X.last
// // UoM(abs(X.dn)+abs(X.up)) to have a non zero value (zero values in SMath have no units)
// myBuffer.Clear();
// myBuffer.AddRange(var_Xdn);
// myBuffer.Add(new Term(Functions.Abs, TermType.Function, 1));
// myBuffer.AddRange(var_Xup);
// myBuffer.Add(new Term(Functions.Abs, TermType.Function, 1));
// myBuffer.Add(new Term(Operators.Composition, TermType.Operator, 2));
// Term[] var_UoM = Computation.Preprocessing(myBuffer.ToArray(), ref context);
// // d*UoM(abs(a)+abs(b))
// myBuffer.Clear();
// myBuffer.AddRange(var_Xlast);
// myBuffer.AddRange(UoM.getUnits(var_UoM, context));
// myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
// var_Xlast = Computation.Preprocessing(myBuffer.ToArray(), ref context);
bool solved = false;
while (i <= maxIterations)
{
// [D:{x.up-x.dn}/2]
myBuffer.Clear();
myBuffer.AddRange(var_Xup);
myBuffer.AddRange(var_Xdn);
myBuffer.Add(new Term(Operators.Subtraction, TermType.Operator, 2));
myBuffer.AddRange(num_2);
myBuffer.Add(new Term(Operators.Division, TermType.Operator, 2));
var_D = Computation.Preprocessing(myBuffer.ToArray(), ref context);
// [x.m:{x.up+x.dn}/2]
myBuffer.Clear();
myBuffer.AddRange(var_Xup);
myBuffer.AddRange(var_Xdn);
myBuffer.Add(new Term(Operators.Composition, TermType.Operator, 2));
myBuffer.AddRange(num_2);
myBuffer.Add(new Term(Operators.Division, TermType.Operator, 2));
var_Xm = Computation.Preprocessing(myBuffer.ToArray(), ref context);
// [y.m:f(x.m)]
var_Ym = SharedFunctions.setValues(context.Scope, function, var_Xm);
// [a:{y.up+y.dn-2*y.m}/{2*D^2}]
myBuffer.Clear();
myBuffer.AddRange(var_Yup);
myBuffer.AddRange(var_Ydn);
myBuffer.Add(new Term(Operators.Composition, TermType.Operator, 2));
myBuffer.AddRange(num_2);
myBuffer.AddRange(var_Ym);
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Subtraction, TermType.Operator, 2));
myBuffer.AddRange(num_2);
myBuffer.AddRange(var_D);
myBuffer.AddRange(num_2);
myBuffer.Add(new Term(Operators.Exponentiation, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Division, TermType.Operator, 2));
var_a = Computation.Preprocessing(myBuffer.ToArray(), ref context);
// [b:{y.up-y.dn}/{2*D}]
myBuffer.Clear();
myBuffer.AddRange(var_Yup);
myBuffer.AddRange(var_Ydn);
myBuffer.Add(new Term(Operators.Subtraction, TermType.Operator, 2));
myBuffer.AddRange(num_2);
myBuffer.AddRange(var_D);
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Division, TermType.Operator, 2));
var_b = Computation.Preprocessing(myBuffer.ToArray(), ref context);
// [x:x.m-{2*y.m}/{b*(1+sqrt(1-{4*a*y.m}/{b^2}))}]
myBuffer.Clear();
myBuffer.AddRange(var_Xm);
myBuffer.AddRange(num_2);
myBuffer.AddRange(var_Ym);
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.AddRange(var_b);
myBuffer.AddRange(num_1);
myBuffer.AddRange(num_1);
myBuffer.AddRange(num_4);
myBuffer.AddRange(var_a);
myBuffer.AddRange(var_Ym);
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.AddRange(var_b);
myBuffer.AddRange(num_2);
myBuffer.Add(new Term(Operators.Exponentiation, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Division, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Subtraction, TermType.Operator, 2));
myBuffer.Add(new Term(Functions.Sqrt, TermType.Function, 1));
myBuffer.Add(new Term(Operators.Composition, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Multiplication, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Division, TermType.Operator, 2));
myBuffer.Add(new Term(Operators.Subtraction, TermType.Operator, 2));
myBuffer.Add(new Term(Functions.Eval, TermType.Function, 1));
var_X = Computation.Preprocessing(myBuffer.ToArray(), ref context);
// [y:f(x)]
var_Y = SharedFunctions.setValues(context.Scope, function, var_X);
// thresholds check: [[abs(y) 0 && !solved)
{
myBuffer.Clear();
myBuffer.AddRange(var_X);
myBuffer.AddRange(var_Xlast);
myBuffer.Add(new Term(Operators.Subtraction, TermType.Operator, 2));
solved = SharedFunctions.isTargetBelowThreshold(context.Scope, myBuffer.ToArray(), epsilon_Δx);
}
// record this step
if (showSummary || saveSummary)
{
summary.AddLine(context.Scope, new Term[][]{
TermsConverter.ToTerms(i.ToString()),
var_Xdn,
var_Xup,
var_X,
var_Ydn,
var_Yup,
var_Y
}, saveSummary);
}
// required precision reached
if (solved)
{
break;
}
// [x.last:x]
var_Xlast = var_X;
// if/else #4, condition: [y>0]
myBuffer.Clear();
myBuffer.AddRange(var_Y);
myBuffer.AddRange(num_0);
myBuffer.Add(new Term(Operators.BooleanMore, TermType.Operator, 2));
myBuffer.Add(new Term(Functions.Eval, TermType.Function, 1));
myFlag = Computation.Preprocessing(myBuffer.ToArray(), ref context)[0].Text;
if (myFlag == "1")
{
var_Xup = var_X;
var_Yup = var_Y;
// if/else #5, condition: [y.m<0]
myBuffer.Clear();
myBuffer.AddRange(var_Ym);
myBuffer.AddRange(num_0);
myBuffer.Add(new Term(Operators.BooleanLess, TermType.Operator, 2));
myBuffer.Add(new Term(Functions.Eval, TermType.Function, 1));
myFlag = Computation.Preprocessing(myBuffer.ToArray(), ref context)[0].Text;
if (myFlag == "1")
{
var_Xdn = var_Xm;
var_Ydn = var_Ym;
}
}
else
{
var_Xdn = var_X;
var_Ydn = var_Y;
// if/else #6, condition: [y.m>0]
myBuffer.Clear();
myBuffer.AddRange(var_Ym);
myBuffer.AddRange(num_0);
myBuffer.Add(new Term(Operators.BooleanMore, TermType.Operator, 2));
myBuffer.Add(new Term(Functions.Eval, TermType.Function, 1));
myFlag = Computation.Preprocessing(myBuffer.ToArray(), ref context)[0].Text;
if (myFlag == "1")
{
var_Xup = var_Xm;
var_Yup = var_Ym;
}
}
i++;
}
if (solved)
{
// Output results and iterations
return new Term[][]
{
var_X,
TermsConverter.ToTerms(i.ToString()),
summary.GetMatrix()
};
}
else
{
// No solutions using the assigned iteration limit
throw new Exception(string.Format(Translator.GetString("error_iterations"), --i));
}
}
}
}