using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
namespace FormulaEditor
{
/// <summary>
/// Elementary binary operation
/// </summary>
public class ElementaryBinaryOperation : IObjectOperation, ICloneable, IDerivationOperation,
IFormulaCreatorOperation
{
/// <summary>
/// Object of char type
/// </summary>
public const Char CharType = (char)0;
/// <summary>
/// Object of sbyte type
/// </summary>
public const SByte SbyteType = (sbyte)0;
/// <summary>
/// Object of short type
/// </summary>
public const Int16 Int16Type = (short)0;
/// <summary>
/// Object of int type
/// </summary>
public const Int32 Int32Type = (int)0;
/// <summary>
/// Object of long type
/// </summary>
public const Int64 Int64Type = (long)0;
/// <summary>
/// Object of byte type
/// </summary>
public const Byte ByteType = (byte)0;
/// <summary>
/// Object of ushort type
/// </summary>
public const UInt16 Uint16Type = (ushort)0;
/// <summary>
/// Object of uint type
/// </summary>
public const UInt32 Uint32Type = (uint)0;
/// <summary>
/// Object of ulong type
/// </summary>
public const UInt64 Uint64Type = (ulong)0;
/// <summary>
/// Object of bool type
/// </summary>
public const Boolean BooleanType = false;
/// <summary>
/// Object of double type
/// </summary>
public const Double DoubleType = 0;
/// <summary>
/// Object of string type
/// </summary>
public const string StringType = "";
/// <summary>
/// Types of objects
/// </summary>
public static readonly object[] Types = new object[]{DoubleType, BooleanType, ByteType, Uint16Type, Uint32Type, Uint64Type,
SbyteType, Int16Type, Int32Type, Int64Type, StringType};
/// <summary>
/// Type of operation
/// </summary>
private object type;
/// <summary>
/// Type of operation
/// </summary>
private const Double a = 0;
/// <summary>
/// Operation symbol
/// </summary>
private char symbol;
/// <summary>
/// Constructor
/// </summary>
/// <param name="symbol">Operation symbol</param>
/// <param name="type">Type of operation</param>
public ElementaryBinaryOperation(char symbol, object type)
{
this.symbol = symbol;
this.type = type;
}
/// <summary>
/// Creates formula
/// </summary>
/// <param name="tree">Operation tree</param>
/// <param name="level">Formula level</param>
/// <param name="sizes">Sizes of symbols</param>
/// <returns>The formula</returns>
public MathFormula CreateFormula(ObjectFormulaTree tree, byte level, int[] sizes)
{
MathFormula form = new MathFormula(level, sizes);
for (int i = 0; i < 2; i++)
{
IFormulaCreatorOperation op = tree[i].Operation as IFormulaCreatorOperation;
MathFormula f = op.CreateFormula(tree[i], level, sizes);
MathFormula fp = null;
if (op.OperationPriority < OperationPriority)
{
fp = new MathFormula(level, sizes);
MathSymbol s = new BracketsSymbol();
s.Append(fp);
fp.First[0] = f;
}
else
{
fp = f;
}
form.Add(fp);
if (i == 0)
{
MathSymbol s = new BinarySymbol(symbol);
s.Append(form);
}
}
return form;
}
/// <summary>
/// Operation priority
/// </summary>
public int OperationPriority
{
get
{
if (symbol == '*')
{
return (int)ElementaryOperationPriorities.Multiply;
}
return (int)ElementaryOperationPriorities.PlusMinus;
}
}
/// <summary>
/// Clones itself
/// </summary>
/// <returns>A clone</returns>
public object Clone()
{
return new ElementaryBinaryOperation(symbol, type);
}
/// <summary>
/// Calculates derivation
/// </summary>
/// <param name="tree">The function for derivation calculation</param>
/// <param name="s">Derivation string</param>
/// <returns>The derivation</returns>
public ObjectFormulaTree Derivation(ObjectFormulaTree tree, string s)
{
Double a = 0;
if ((symbol == '+') | (symbol == '-'))
{
IObjectOperation op = new ElementaryBinaryOperation(symbol, a);
List<ObjectFormulaTree> l = new List<ObjectFormulaTree>();
for (int i = 0; i < tree.Count; i++)
{
l.Add(DerivationPerformer.Derivation(tree[i], s));
}
return new ObjectFormulaTree(op, l);
}
ObjectFormulaTree[] der = new ObjectFormulaTree[2];
for (int i = 0; i < 2; i++)
{
der[i] = DerivationPerformer.Derivation(tree[i], s);
}
if (symbol == '*')
{
List<ObjectFormulaTree> list = new List<ObjectFormulaTree>();
for (int i = 0; i < 2; i++)
{
ElementaryBinaryOperation o = new ElementaryBinaryOperation('*', a);
List<ObjectFormulaTree> l = new List<ObjectFormulaTree>();
l.Add(tree[i].Clone() as ObjectFormulaTree);
l.Add(der[1 - i]);
list.Add(new ObjectFormulaTree(o, l));
}
ElementaryBinaryOperation op = new ElementaryBinaryOperation('+', a);
return new ObjectFormulaTree(op, list);
}
return null;
}
/// <summary>
/// Arity of this operation
/// </summary>
public int Arity
{
get
{
return 2;
}
}
/// <summary>
/// Calculates result of this operation
/// </summary>
public object this[object[] x]
{
get
{
return calculate(x);
}
}
/// <summary>
/// Return type
/// </summary>
public object ReturnType
{
get
{
return type;
}
}
/// <summary>
/// The "is powered" sign
/// </summary>
public bool IsPowered
{
get
{
return false;
}
}
#region Specific Members
/// <summary>
/// Detects whether object type is integer
/// </summary>
/// <param name="o">The object</param>
/// <returns>True if type is integer and false otherwise</returns>
public static bool IsInteger(object o)
{
return (o is SByte) | (o is Byte) | (o is Int16) | (o is UInt16)
| (o is Int32) | (o is UInt32) | (o is Int64) | (o is UInt64);
}
/// <summary>
/// Detects whether object type is unsigned
/// </summary>
/// <param name="o">The object</param>
/// <returns>True if type is unsigned and false otherwise</returns>
public static bool IsUnsigned(object o)
{
return (o is Byte) | (o is UInt16) | (o is UInt32) | (o is UInt64);
}
/// <summary>
/// Detects whether object type is double
/// </summary>
/// <param name="o">The object</param>
/// <returns>True if type is double and false otherwise</returns>
public static bool IsReal(object o)
{
return o is Double;
}
/// <summary>
/// Detects whether object type is numercial
/// </summary>
/// <param name="o">The object</param>
/// <returns>True if type is numercial and false otherwise</returns>
public static bool IsNumber(object o)
{
return IsReal(o) | IsInteger(o);
}
/// <summary>
/// Detects whether object is 64 bit integer
/// </summary>
/// <param name="o">The object</param>
/// <returns>True if object is 64 bit integer and false otherwise</returns>
public static bool IsInteger64(object o)
{
return (o is UInt64) | (o is Int64);
}
/// <summary>
/// Detects whether object is negative
/// </summary>
/// <param name="o">The object</param>
/// <returns>True if object is negative and false otherwise</returns>
public static bool IsNegative(object o)
{
return ElementaryIntegerOperation.ToDouble(o) < 0;
}
/// <summary>
/// Calculates number of object bits
/// </summary>
/// <param name="o">The object</param>
/// <returns>Number of bits</returns>
public static int NBits(object o)
{
if ((o is Byte) | (o is SByte))
{
return 8;
}
if ((o is Int16) | (o is UInt16))
{
return 16;
}
if ((o is Int32) | (o is UInt32))
{
return 32;
}
if ((o is Int64) | (o is UInt64))
{
return 64;
}
return 0;
}
public char Symbol
{
get
{
return symbol;
}
}
public static object DetectType(object typeA, object typeB)
{
if (!IsNumber(typeA) | !IsNumber(typeB))
{
return null;
}
if (IsReal(typeA) | IsReal(typeB))
{
return a;
}
int nA = NBits(typeA);
int nB = NBits(typeB);
if (nA > nB)
{
return typeA;
}
if (nB > nA)
{
return typeB;
}
if (IsUnsigned(typeA) & IsUnsigned(typeB))
{
return typeA;
}
if (!IsUnsigned(typeA))
{
return typeA;
}
if (!IsUnsigned(typeB))
{
return typeB;
}
return null;
}
/// <summary>
/// Calculates itself
/// </summary>
/// <param name="x">Arguments</param>
/// <returns>Result of calculation</returns>
private object calculate(object[] x)
{
if (IsReal(type))
{
double a = ElementaryIntegerOperation.ToDouble(x[0]);
double b = ElementaryIntegerOperation.ToDouble(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is SByte)
{
sbyte a = ElementaryIntegerOperation.ToSByte(x[0]);
sbyte b = ElementaryIntegerOperation.ToSByte(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is Int16)
{
short a = ElementaryIntegerOperation.ToInt16(x[0]);
short b = ElementaryIntegerOperation.ToInt16(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is Int32)
{
int a = ElementaryIntegerOperation.ToInt32(x[0]);
int b = ElementaryIntegerOperation.ToInt32(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is Int64)
{
long a = ElementaryIntegerOperation.ToInt64(x[0]);
long b = ElementaryIntegerOperation.ToInt64(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is Byte)
{
byte a = ElementaryIntegerOperation.ToByte(x[0]);
byte b = ElementaryIntegerOperation.ToByte(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is UInt16)
{
ushort a = ElementaryIntegerOperation.ToUInt16(x[0]);
ushort b = ElementaryIntegerOperation.ToUInt16(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is UInt32)
{
uint a = ElementaryIntegerOperation.ToUInt32(x[0]);
uint b = ElementaryIntegerOperation.ToUInt32(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
if (type is UInt64)
{
ulong a = ElementaryIntegerOperation.ToUInt64(x[0]);
ulong b = ElementaryIntegerOperation.ToUInt64(x[1]);
switch (symbol)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
}
}
return 0;
}
/// <summary>
/// Converts double variale
/// </summary>
/// <param name="type">Return type</param>
/// <param name="x">The variable</param>
/// <returns>Coversion result</returns>
static public object Convert(object type, double x)
{
if (type.Equals(DoubleType))
{
return x;
}
if (type.Equals(BooleanType))
{
if (x == 0)
{
return false;
}
if (x == 1)
{
return true;
}
throw new Exception("Can not convert double parameter value to boolean");
}
if (type.Equals(SbyteType))
{
return (sbyte)x;
}
if (type.Equals(Int16Type))
{
return (short)x;
}
if (type.Equals(Int32Type))
{
return (int)x;
}
if (type.Equals(Int64Type))
{
return (long)x;
}
if (type.Equals(ByteType))
{
return (byte)x;
}
if (type.Equals(Uint16Type))
{
return (ushort)x;
}
if (type.Equals(Uint32Type))
{
return (uint)x;
}
if (type.Equals(Uint64Type))
{
return (ulong)x;
}
throw new Exception("Type cannot be converted from double");
}
#endregion
}
}