//
        // Graph traversal to find shapes and thus the resulting equation (solution).
        //
        // Depth first: construct along the way
        // Find only the SHORTEST equation (based on the number of regions involved in the equation).
        //
        private bool SimpleVisit(int regionIndex, ComplexRegionEquation currentEq)
        {
            //
            // Deal with memoizing: keep the shortest equation for this particular region (@ regionIndex)
            //
            if (visited[regionIndex])
            {
                return(true);
            }

            // We have now visited this node.
            visited[regionIndex] = true;

            // Is this partitcular region a shape?
            // If so, save the basis equation in memozied.
            if (graph.vertices[regionIndex].data is ShapeRegion)
            {
                return(true);
            }

            // For all hyperedges leaving this node, follow the edge sources
            foreach (Hypergraph.HyperEdge <SimpleRegionEquation> edge in graph.vertices[regionIndex].targetEdges)
            {
                // Will contain two equations representing expressions for the source node
                ComplexRegionEquation[] edgeEqs = new ComplexRegionEquation[edge.sourceNodes.Count];

                // For actively substituting into.
                ComplexRegionEquation currentEqCopy = new ComplexRegionEquation(currentEq);

                // Area can be calcualted either directly or using the GeoTutor deductive engine.
                bool canCalcArea = true;
                for (int e = 0; e < edge.sourceNodes.Count; e++)
                {
                    // If we have already visited this node, we already have an equation for it; use it.
                    if (visited[edge.sourceNodes[e]])
                    {
                        // Check if we cannot calculate the region area.
                        if (memoizedSolutions[edge.sourceNodes[e]] == null)
                        {
                            canCalcArea = false;
                            break;
                        }

                        // Otherwise, we use the memoized version of this region equation for this source node.
                        edgeEqs[e] = memoizedSolutions[edge.sourceNodes[e]];
                    }
                    // We don't have a memoized version; calculate it.
                    else
                    {
                        // Create an equation: region = region so that we substitute into the RHS.
                        Region srcRegion = graph.vertices[edge.sourceNodes[e]].data;
                        edgeEqs[e] = new ComplexRegionEquation(srcRegion, srcRegion);

                        // This source node is not a shape: we can't directly calculate its area.
                        if (!SimpleVisit(edge.sourceNodes[e], edgeEqs[e]))
                        {
                            canCalcArea = false;
                            break;
                        }
                    }
                }

                //
                // If we have a successful search from this edge, create the corresponding region equation.
                //
                if (canCalcArea)
                {
                    // We can substitute the annotation along the edge into the edge's target region (expression).

                    // to find (val)
                    currentEqCopy.Substitute(graph.vertices[edge.targetNode].data,
                                             // to sub (for val)
                                             new ComplexRegionEquation.Binary(edgeEqs[0].expr,
                                                                              edge.annotation.op,
                                                                              edgeEqs[0].expr));
                    // Choose the shortest solution for this region
                    if (currentEq.Length > currentEqCopy.Length)
                    {
                        currentEq = currentEqCopy;
                    }
                }
            }

            // Did we find a solution?
            if (currentEq.Length == int.MaxValue)
            {
                return(false);
            }

            // Success; save the solution.
            memoizedSolutions[regionIndex] = currentEq;

            return(true);
        }
        //
        // Graph traversal to find shapes and thus the resulting equation (solution).
        //
        // Dynamic Programming: return the first solution found (which will be the shortest)
        //
        private KeyValuePair<ComplexRegionEquation, double> DynamicVisit(int startIndex, bool[] visited, KnownMeasurementsAggregator known)
        {
            // The actual Region object for this node.
            Region thisRegion = graph.vertices[startIndex].data;

            // Cut off search if we've been here before.
            if (visited[startIndex]) return new KeyValuePair<ComplexRegionEquation,double>(memoizedSolutions[startIndex], thisRegion.GetKnownArea());

            // We've been here now.
            visited[startIndex] = true;

            //
            // Can we compute the area of this node directly?
            //
            double area = thisRegion.GetArea(known);
            if (area > 0)
            {
                thisRegion.SetKnownArea(area);
                memoizedSolutions[startIndex] = new ComplexRegionEquation(thisRegion, thisRegion);
                return new KeyValuePair<ComplexRegionEquation,double>(memoizedSolutions[startIndex], thisRegion.GetKnownArea());
            }

            //
            // Does any of the edges satisfy this equation? Investigate dynamically.
            //
            // Complex equation resulting from each outgoing edge.
            ComplexRegionEquation shortestEq = null;
            area = 0;
            foreach (Hypergraph.HyperEdge<SimpleRegionEquation> edge in graph.vertices[startIndex].targetEdges)
            {
                KeyValuePair<ComplexRegionEquation, double> src1Eq = DynamicVisit(edge.sourceNodes[0], visited, known);
                KeyValuePair<ComplexRegionEquation, double> src2Eq = DynamicVisit(edge.sourceNodes[1], visited, known);

                // Success, we found a valid area expression for edge.
                if (src1Eq.Key != null && src2Eq.Key != null)
                {
                    // Create a copy of the anootation for a simple region equation for this edge.
                    SimpleRegionEquation simpleEdgeEq = new SimpleRegionEquation(edge.annotation);

                    //
                    // Make one complex equation performing substitutions.
                    //
                    ComplexRegionEquation complexEdgeEq = new ComplexRegionEquation(simpleEdgeEq);
                    complexEdgeEq.Substitute(src1Eq.Key.target, src1Eq.Key.expr);
                    complexEdgeEq.Substitute(src2Eq.Key.target, src2Eq.Key.expr);

                    // Pick the shortest equation possible.
                    if (shortestEq == null) shortestEq = complexEdgeEq;
                    else if (shortestEq.Length > complexEdgeEq.Length) shortestEq = complexEdgeEq;

                    if (edge.annotation.op == OperationT.ADDITION)
                    {
                        area = src1Eq.Value + src2Eq.Value;
                    }
                    else if (edge.annotation.op == OperationT.SUBTRACTION)
                    {
                        area = src1Eq.Value - src2Eq.Value;
                    }
                }
            }

            //if (shortestEq != null)
            //{
            //    thisRegion.SetKnownArea(area);
            //    memoizedSolutions[startIndex] = new ComplexRegionEquation(thisRegion, thisRegion);
            //    return new KeyValuePair<ComplexRegionEquation, double>(memoizedSolutions[startIndex], area);
            //}

            memoizedSolutions[startIndex] = shortestEq;

            return new KeyValuePair<ComplexRegionEquation, double>(memoizedSolutions[startIndex], area);
        }
        //
        // Graph traversal to find shapes and thus the resulting equation (solution).
        //
        // Depth first: construct along the way
        // Find only the SHORTEST equation (based on the number of regions involved in the equation).
        //
        private bool SimpleVisit(int regionIndex, ComplexRegionEquation currentEq, bool[] visited)
        {
            //
            // Deal with memoizing: keep the shortest equation for this particular region (@ regionIndex)
            //
            if (visited[regionIndex]) return true;

            // We have now visited this node.
            visited[regionIndex] = true;

            // Is this partitcular region a shape?
            // If so, save the basis equation in memozied.
            if (graph.vertices[regionIndex].data is ShapeRegion) return true;

            // For all hyperedges leaving this node, follow the edge sources
            foreach (Hypergraph.HyperEdge<SimpleRegionEquation> edge in graph.vertices[regionIndex].targetEdges)
            {
                // Will contain two equations representing expressions for the source node
                ComplexRegionEquation[] edgeEqs = new ComplexRegionEquation[edge.sourceNodes.Count];

                // For actively substituting into.
                ComplexRegionEquation currentEqCopy = new ComplexRegionEquation(currentEq);

                // Area can be calcualted either directly or using the GeoTutor deductive engine.
                bool canCalcArea = true;
                for (int e = 0; e < edge.sourceNodes.Count; e++)
                {
                    // If we have already visited this node, we already have an equation for it; use it.
                    if (visited[edge.sourceNodes[e]])
                    {
                        // Check if we cannot calculate the region area.
                        if (memoizedSolutions[edge.sourceNodes[e]] == null)
                        {
                            canCalcArea = false;
                            break;
                        }

                        // Otherwise, we use the memoized version of this region equation for this source node.
                        edgeEqs[e] = memoizedSolutions[edge.sourceNodes[e]];
                    }
                    // We don't have a memoized version; calculate it.
                    else
                    {
                        // Create an equation: region = region so that we substitute into the RHS.
                        Region srcRegion = graph.vertices[edge.sourceNodes[e]].data;
                        edgeEqs[e] = new ComplexRegionEquation(srcRegion, srcRegion);

                        // This source node is not a shape: we can't directly calculate its area.
                        if (!SimpleVisit(edge.sourceNodes[e], edgeEqs[e], visited))
                        {
                            canCalcArea = false;
                            break;
                        }
                    }
                }

                //
                // If we have a successful search from this edge, create the corresponding region equation.
                //
                if (canCalcArea)
                {
                    // We can substitute the annotation along the edge into the edge's target region (expression).

                                             // to find (val)
                    currentEqCopy.Substitute(graph.vertices[edge.targetNode].data,
                                             // to sub (for val)
                                             new ComplexRegionEquation.Binary(edgeEqs[0].expr,
                                                                              edge.annotation.op,
                                                                              edgeEqs[0].expr));
                    // Choose the shortest solution for this region
                    if (currentEq.Length > currentEqCopy.Length)
                    {
                        currentEq = currentEqCopy;
                    }
                }
            }

            // Did we find a solution?
            if (currentEq.Length == int.MaxValue) return false;

            // Success; save the solution.
            memoizedSolutions[regionIndex] = currentEq;

            return true;
        }
        //
        // Graph traversal to find shapes and thus the resulting equation (solution).
        //
        // Dynamic Programming: return the first solution found (which will be the shortest)
        //
        private KeyValuePair <ComplexRegionEquation, double> DynamicVisit(int startIndex, bool[] visited, KnownMeasurementsAggregator known)
        {
            // The actual Region object for this node.
            Region thisRegion = graph.vertices[startIndex].data;

            // Cut off search if we've been here before.
            if (visited[startIndex])
            {
                return(new KeyValuePair <ComplexRegionEquation, double>(memoizedSolutions[startIndex], thisRegion.GetKnownArea()));
            }

            // We've been here now.
            visited[startIndex] = true;

            //
            // Can we compute the area of this node directly?
            //
            double area = thisRegion.GetArea(known);

            if (area > 0)
            {
                thisRegion.SetKnownArea(area);
                memoizedSolutions[startIndex] = new ComplexRegionEquation(thisRegion, thisRegion);
                return(new KeyValuePair <ComplexRegionEquation, double>(memoizedSolutions[startIndex], thisRegion.GetKnownArea()));
            }

            //
            // Does any of the edges satisfy this equation? Investigate dynamically.
            //
            // Complex equation resulting from each outgoing edge.
            ComplexRegionEquation shortestEq = null;

            area = 0;
            foreach (Hypergraph.HyperEdge <SimpleRegionEquation> edge in graph.vertices[startIndex].targetEdges)
            {
                KeyValuePair <ComplexRegionEquation, double> src1Eq = DynamicVisit(edge.sourceNodes[0], visited, known);
                KeyValuePair <ComplexRegionEquation, double> src2Eq = DynamicVisit(edge.sourceNodes[1], visited, known);

                // Success, we found a valid area expression for edge.
                if (src1Eq.Key != null && src2Eq.Key != null)
                {
                    // Create a copy of the anootation for a simple region equation for this edge.
                    SimpleRegionEquation simpleEdgeEq = new SimpleRegionEquation(edge.annotation);

                    //
                    // Make one complex equation performing substitutions.
                    //
                    ComplexRegionEquation complexEdgeEq = new ComplexRegionEquation(simpleEdgeEq);
                    complexEdgeEq.Substitute(src1Eq.Key.target, src1Eq.Key.expr);
                    complexEdgeEq.Substitute(src2Eq.Key.target, src2Eq.Key.expr);

                    // Pick the shortest equation possible.
                    if (shortestEq == null)
                    {
                        shortestEq = complexEdgeEq;
                    }
                    else if (shortestEq.Length > complexEdgeEq.Length)
                    {
                        shortestEq = complexEdgeEq;
                    }

                    if (edge.annotation.op == OperationT.ADDITION)
                    {
                        area = src1Eq.Value + src2Eq.Value;
                    }
                    else if (edge.annotation.op == OperationT.SUBTRACTION)
                    {
                        area = src1Eq.Value - src2Eq.Value;
                    }
                }
            }

            //if (shortestEq != null)
            //{
            //    thisRegion.SetKnownArea(area);
            //    memoizedSolutions[startIndex] = new ComplexRegionEquation(thisRegion, thisRegion);
            //    return new KeyValuePair<ComplexRegionEquation, double>(memoizedSolutions[startIndex], area);
            //}

            memoizedSolutions[startIndex] = shortestEq;

            return(new KeyValuePair <ComplexRegionEquation, double>(memoizedSolutions[startIndex], area));
        }