/release 0.1.1/HAB/Expressions/BoolExpression.cs
C# | 340 lines | 234 code | 20 blank | 86 comment | 79 complexity | b9b16834c5c540ff6ae23555651f2b24 MD5 | raw file
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace NeuralNetworkDesigne.HAB
- {
- /// <summary>
- /// A result expression that can be evaluated to a boolean.
- /// </summary>
- /// <remarks>
- /// If there is only a left part, this evaluates to true if non of the items in the left part are <see cref="PredefinedNeurons.False"/>.
- /// </remarks>
- [NeuronID((ulong)PredefinedNeurons.BoolExpression, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.And, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.Or, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.Contains, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.Different, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.Equal, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.BiggerOrEqual, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.Smaller, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.SmallerOrEqual, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.Bigger, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.False, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.True, typeof(Neuron))]
- [NeuronID((ulong)PredefinedNeurons.Clusters, typeof(Neuron))]
- public class BoolExpression : ResultExpression
- {
- #region ctor
- /// <summary>
- /// Default constructor.
- /// </summary>
- public BoolExpression()
- {
- }
- /// <summary>
- /// Creates a new bool expression, with the proper links already made.
- /// </summary>
- /// <param name="left">The left part of the expression.</param>
- /// <param name="op">The operator to execute.</param>
- /// <param name="right">The right part of the expression.</param>
- public BoolExpression(Neuron left, Neuron op, Neuron right)
- {
- Link iNew = new Link(left, this, (ulong)PredefinedNeurons.LeftPart);
- iNew = new Link(op, this, (ulong)PredefinedNeurons.Operator);
- iNew = new Link(right, this, (ulong)PredefinedNeurons.RightPart);
- }
- #endregion ctor
- #region Prop
- /// <summary>
- /// Gets/sets the operator that should be used.
- /// </summary>
- /// <remarks>
- /// This is 'Equal' by defualt. Other values could be 'Bigger', 'Smaller', 'Different, 'BiggerOrEqual', 'SmallerOrEqual' or 'Contains'.
- /// <para>
- /// If this is an expression, it is first executed before the compare is done (so multiple operators are allowed?).
- /// </para>
- /// </remarks>
- public Neuron Operator
- {
- get
- {
- return FindFirstOut((ulong)PredefinedNeurons.Operator);
- }
- set
- {
- SetFirstOutgoingLinkTo((ulong)PredefinedNeurons.Operator, value);
- }
- }
- /// <summary>
- /// Gets/sets the Neuronlist that should be searched in a 'Contains' expression. This value should only be supplied if this operator
- /// is used.
- /// </summary>
- /// <remarks>
- /// If this is an expression, it is first solved, so multiple lists on the same neuron are allowed.
- /// </remarks>
- public Neuron ListToSearch
- {
- get
- {
- return FindFirstOut((ulong)PredefinedNeurons.ListToSearch);
- }
- set
- {
- SetFirstOutgoingLinkTo((ulong)PredefinedNeurons.ListToSearch, value);
- }
- }
- /// <summary>
- /// Gets/sets the left part of the expression.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The left part is compared to the <see cref="BoolExpression.RightPart"/> using the <see cref="BoolExpresssion.Operator"/> (which
- /// must be of a known type) to produce a result.
- /// </para>
- /// <para>
- /// If this is an expression, it is first executed before the compare is done.
- /// </para>
- /// </remarks>
- public Neuron LeftPart
- {
- get
- {
- return FindFirstOut((ulong)PredefinedNeurons.LeftPart);
- }
- set
- {
- SetFirstOutgoingLinkTo((ulong)PredefinedNeurons.LeftPart, value);
- }
- }
- /// <summary>
- /// Gets/sets the right part of the expression.
- /// </summary>
- /// <remarks>
- /// The right part is compared to the <see cref="BoolExpression.LeftPart"/> using the <see cref="BoolExpresssion.Operator"/> (which
- /// must be of a known type) to produce a result.
- /// <para>
- /// If this is an expression, it is first executed before the compare is done.
- /// </para>
- /// </remarks>
- public Neuron RightPart
- {
- get
- {
- return FindFirstOut((ulong)PredefinedNeurons.RightPart);
- }
- set
- {
- SetFirstOutgoingLinkTo((ulong)PredefinedNeurons.RightPart, value);
- }
- }
- #region TypeOfNeuron
- /// <summary>
- /// Gets the type of this neuron expressed as a Neuron.
- /// </summary>
- /// <value><see cref="PredefinedNeurons.BoolExpression"/>.</value>
- public override Neuron TypeOfNeuron
- {
- get
- {
- return Brain.Current[(ulong)PredefinedNeurons.BoolExpression];
- }
- }
- #endregion TypeOfNeuron
- #endregion Prop
- /// <summary>
- /// We push the result of the expression on the stack, this is normally a <see cref="PredefinedNeuron.True"/> or
- /// <see cref="PredefinedNeuron.False"/>
- /// </summary>
- /// <param name="handler"></param>
- protected internal override void Execute(Processor handler)
- {
- if (Evaluate(handler) == true)
- handler.Push(Brain.Current[(ulong)PredefinedNeurons.True]);
- else
- handler.Push(Brain.Current[(ulong)PredefinedNeurons.False]);
- }
- /// <summary>
- /// Returns the value of the compare as a list containing a true or false node.
- /// provided to solve general purpose result expressions.
- /// </summary>
- /// <returns></returns>
- public override IEnumerable<Neuron> GetValue(Processor processor)
- {
- List<Neuron> iRes = new List<Neuron>();
- if (Evaluate(processor) == true)
- iRes.Add(Brain.Current[(ulong)PredefinedNeurons.True]);
- else
- iRes.Add(Brain.Current[(ulong)PredefinedNeurons.False]);
- return iRes;
- }
- /// <summary>
- /// Evaluates the boolean expression and returns the result. True if the evaluation
- /// was true, otherwise false.
- /// </summary>
- /// <returns>True if the bool expression evaluated to true.</returns>
- public bool Evaluate(Processor processor)
- {
- IEnumerable<Neuron> iRight = null;
- IEnumerable<Neuron> iLeft = SolveResultExp(LeftPart, processor);
- IEnumerable<Neuron> iOp = SolveResultExp(Operator, processor);
- IEnumerable<Neuron> iListsToSearch = SolveResultExp(ListToSearch, processor);
- if (iLeft != null) //there were no left parts to evaluate, this is a state of error, so log and return that the condition failed.
- {
- if (iLeft.Count() == 0)
- return iOp.All(i => i.ID == (ulong)PredefinedNeurons.Different) == true; //if we have no result, but are trying to do a '!=' we need to return true.
- if (iOp != null)
- {
- foreach (Neuron iL in iLeft) //check every possible combination, if non is false, it's true.
- {
- foreach (Neuron iO in iOp) //we need to check the operator in a loop cause an expression can always return multiple items, so also an operator in theory, although this will probably not often be used.
- {
- if (iO.ID == (ulong)PredefinedNeurons.Contains) //we treat the contains seperatly, cause this needs a different check type.
- {
- iRight = GetRightPart(iRight, processor);
- if (iRight == null || EvaluateContains(iL, iRight, iListsToSearch) == false)
- return false;
- }
- else if (iO.ID == (ulong)PredefinedNeurons.And)
- {
- if (iL.ID != (ulong)PredefinedNeurons.True)
- return false;
- iRight = GetRightPart(iRight, processor);
- foreach (Neuron iR in iRight)
- if (iL.CompareWith(iR, iO) == false)
- return false;
- }
- else if (iO.ID == (ulong)PredefinedNeurons.Or)
- {
- if (iL.ID != (ulong)PredefinedNeurons.True)
- {
- iRight = GetRightPart(iRight, processor);
- foreach (Neuron iR in iRight)
- if (iL.CompareWith(iR, iO) == false)
- return false;
- }
- }
- else
- {
- iRight = GetRightPart(iRight, processor);
- foreach (Neuron iR in iRight)
- if (iL.CompareWith(iR, iO) == false)
- return false;
- }
- }
- }
- return true;
- }
- else
- Log.LogError("BoolExpression.Evaluate", string.Format("No valid operator part found during evaluation of: {0}", this));
- }
- else
- Log.LogError("BoolExpression.Evaluate", string.Format("No valid left part to evaluate for: {0}", this));
- return false;
- }
- /// <summary>
- /// Small helper function that checks if the right part has already been solved, if not, we try to solve it.
- /// </summary>
- /// <param name="list">The list.</param>
- /// <param name="processor">The processor.</param>
- /// <returns></returns>
- private IEnumerable<Neuron> GetRightPart(IEnumerable<Neuron> list, Processor processor)
- {
- if (list == null) //if the right part has not yet been build, do it now.
- {
- list = SolveResultExp(RightPart, processor);
- if (list == null)
- Log.LogError("BoolExpression.Evaluate", string.Format("No valid right part found during evaluation of: {0}", this));
- }
- return list;
- }
- /// <summary>
- /// Performs the evaluation for a contains operator. All lists in left as defined by lists, should contain all the items
- /// defined in right
- /// </summary>
- /// <param name="left">The item who's list(s) to check.</param>
- /// <param name="right">The items that need to be found in the list(s)</param>
- /// <param name="lists">The list(s) to check, should not be null.</param>
- /// <returns>True if all the items were contained in the lists, otherwise false.</returns>
- private bool EvaluateContains(Neuron left, IEnumerable<Neuron> right, IEnumerable<Neuron> lists)
- {
- NeuronCluster iLeft = left as NeuronCluster;
- foreach (Neuron iRight in right)
- {
- foreach (Neuron iList in lists)
- {
- if (iList.ID == (ulong)PredefinedNeurons.Children)
- {
- using (ChildrenAccessor iLeftList = iLeft.Children)
- if (iLeft == null || iLeftList.Contains(iRight) == false)
- return false;
- }
- else if (iList.ID == (ulong)PredefinedNeurons.Clusters)
- {
- using (NeuronsAccessor iClusteredBy = left.ClusteredBy)
- if (iClusteredBy.Items.Contains(iRight.ID) == false)
- return false;
- }
- }
- }
- return true;
- }
- public override string ToString()
- {
- StringBuilder iStr = new StringBuilder();
- Neuron iToWrite = LeftPart;
- if (iToWrite != null)
- iStr.Append(iToWrite.ToString());
- else
- iStr.Append("??");
- iStr.Append(" ");
- iToWrite = Operator;
- if (iToWrite == null)
- iStr.Append("?");
- else if (iToWrite.ID == (ulong)PredefinedNeurons.Equal)
- iStr.Append("==");
- else if (iToWrite.ID == (ulong)PredefinedNeurons.Smaller)
- iStr.Append("<");
- else if (iToWrite.ID == (ulong)PredefinedNeurons.Bigger)
- iStr.Append(">");
- else if (iToWrite.ID == (ulong)PredefinedNeurons.SmallerOrEqual)
- iStr.Append("<=");
- else if (iToWrite.ID == (ulong)PredefinedNeurons.BiggerOrEqual)
- iStr.Append(">=");
- else if (iToWrite.ID == (ulong)PredefinedNeurons.Different)
- iStr.Append("!=");
- else if (iToWrite.ID == (ulong)PredefinedNeurons.Contains)
- iStr.Append("contains");
- else if (iToWrite != null)
- iStr.Append(iToWrite.ToString());
- else
- iStr.Append("?");
- iStr.Append(" ");
- iToWrite = RightPart;
- if (iToWrite != null)
- iStr.Append(iToWrite.ToString());
- else
- iStr.Append("??");
- return iStr.ToString();
- }
- }
- }