public SolutionAgg() { atomIndices = new IndexList(); solEq = null; solArea = -1; solType = SolutionType.UNKNOWN; }
// // Create the actual equation and continue processing recursively. // private void ProcessShape(Region currOuterRegion, TreeNode <Figure> currShape, List <TreeNode <Figure> > currHierarchyRoots, ComplexRegionEquation currEquation, double currArea, KnownMeasurementsAggregator known) { // Acquire the sub-shape. Figure currentFigure = currShape.GetData(); // See what regions compose the subshape. ShapeRegion childShapeRegion = new ShapeRegion(currentFigure); // Make a copy of the current outer regions Region regionCopy = new Region(currOuterRegion); // Remove all regions from the outer region; if successful, recur on the new outer shape. if (regionCopy.Remove(childShapeRegion.atoms)) { // Update the equation: copy and modify ComplexRegionEquation eqCopy = new ComplexRegionEquation(currEquation); eqCopy.AppendSubtraction(childShapeRegion); // Compute new area double currAreaCopy = currArea; if (currAreaCopy > 0) { double currShapeArea = currentFigure.GetArea(known); currAreaCopy = currShapeArea < 0 ? -1 : currAreaCopy - currShapeArea; } // Recur. SolveHelper(regionCopy, currHierarchyRoots, eqCopy, currAreaCopy, known); } }
public ComplexRegionEquation(ComplexRegionEquation complex) : base() { target = complex.target; expr = complex.expr.Copy(); thisArea = -1; }
// // Catalyst routine to the recursive solver: returns solution equation and actual area. // public void SolveAll(KnownMeasurementsAggregator known, List <Figure> allFigures) { PreprocessAtomAreas(known); PreprocessShapeHierarchyAreas(known, allFigures); // // Using the atomic regions, explore all of the top-most shapes recursively. // for (int a = 0; a < figureAtoms.Count; a++) { IndexList atomIndexList = new IndexList(a); SolutionAgg agg = null; solutions.TryGetValue(atomIndexList, out agg); if (agg == null) { Figure topShape = figureAtoms[a].GetTopMostShape(); // Shape Region? ComplexRegionEquation startEq = new ComplexRegionEquation(null, new ShapeRegion(topShape)); double outerArea = topShape.GetArea(known); // Invoke the recursive solver using the outermost region and catalyst. //ProcessChildrenShapes(a, new ShapeRegion(topShape), topShape.Hierarchy(), // new List<TreeNode<Figure>>(), // startEq, outerArea, known); SolveHelper(new ShapeRegion(topShape), topShape.Hierarchy().Children(), startEq, outerArea, known); } else if (agg.solType == SolutionAgg.SolutionType.COMPUTABLE) { //solutions[atomIndexList] = agg; } else if (agg.solType == SolutionAgg.SolutionType.INCOMPUTABLE) { //solutions[atomIndexList] = agg; } else if (agg.solType == SolutionAgg.SolutionType.UNKNOWN) { //TBD } } // // Subtraction of shapes extracts as many atomic regions as possible of the strict atomic regions, now compose those together. // ComposeAllRegions(); }
// // Given a shape that owns the atomic region, recur through the resulting atomic region // // From // public void SolveHelper(Region currOuterRegion, List <TreeNode <Figure> > currHierarchyRoots, ComplexRegionEquation currEquation, double currArea, KnownMeasurementsAggregator known) { IndexList currOuterRegionIndices = IndexList.AcquireAtomicRegionIndices(figureAtoms, currOuterRegion.atoms); // There is no outer region if (currOuterRegionIndices.IsEmpty()) { return; } // // We have reached this point by subtracting shapes, therefore, we have an equation. // SolutionAgg agg = new SolutionAgg(); agg.solEq = new ComplexRegionEquation(currEquation); agg.solEq.SetTarget(currOuterRegion); agg.solType = currArea < 0 ? SolutionAgg.SolutionType.INCOMPUTABLE : SolutionAgg.SolutionType.COMPUTABLE; agg.solArea = currArea; agg.atomIndices = currOuterRegionIndices; // // Add this solution to the database. // solutions.AddSolution(agg); // Was this equation solving for a single atomic region? If so, leave. if (currOuterRegion.IsAtomic()) { return; } // // Recursively explore EACH sub-shape root inside of the outer region. // foreach (TreeNode <Figure> shapeNode in currHierarchyRoots) { // A list omitting this shape List <TreeNode <Figure> > updatedHierarchy = new List <TreeNode <Figure> >(currHierarchyRoots); updatedHierarchy.Remove(shapeNode); // Process this shape ProcessShape(currOuterRegion, shapeNode, updatedHierarchy, currEquation, currArea, known); // Process the children ProcessChildrenShapes(currOuterRegion, shapeNode, updatedHierarchy, currEquation, currArea, known); } }
public ComplexRegionEquation TraceRegionArea(Region thatRegion) { // Find this region in the hypergraph. int startIndex = graph.GetNodeIndex(thatRegion); if (startIndex == -1) throw new ArgumentException("Desired region not found in area hypergraph: " + thatRegion); // Modifiable region equation: region = region so that we substitute into the RHS. ComplexRegionEquation eq = new ComplexRegionEquation(thatRegion, thatRegion); // Traverse depth-first to construct all equations. bool success = SimpleVisit(startIndex, eq); return success ? memoizedSolutions[startIndex] : null; }
// // The graph nodes are the powerset of atomic nodes // private void PrecomputeShapes() { // Construct each element of the powerset for (int r = 0; r < graph.vertices.Count; r++) { // TODO collect atoms into a shape.... // Check if we can memoize this directly as a shape if (graph.vertices[r].data is ShapeRegion) { memoizedSolutions[r] = new ComplexRegionEquation(graph.vertices[r].data, graph.vertices[r].data); } } }
public ComplexRegionEquation TraceRegionArea(Region thatRegion) { // Find this region in the hypergraph. int startIndex = graph.GetNodeIndex(thatRegion); if (startIndex == -1) { throw new ArgumentException("Desired region not found in area hypergraph: " + thatRegion); } // Modifiable region equation: region = region so that we substitute into the RHS. ComplexRegionEquation eq = new ComplexRegionEquation(thatRegion, thatRegion); // Traverse depth-first to construct all equations. bool success = SimpleVisit(startIndex, eq); return(success ? memoizedSolutions[startIndex] : null); }
// // Depth-First // public ComplexRegionEquation TraceRegionArea(Region thatRegion) { // Find this region in the hypergraph. int startIndex = graph.GetNodeIndex(thatRegion); if (startIndex == -1) { throw new ArgumentException("Desired region not found in area hypergraph: " + thatRegion); } // Modifiable region equation: region = region so that we substitute into the RHS. ComplexRegionEquation eq = new ComplexRegionEquation(thatRegion, thatRegion); bool[] visited = new bool[graph.Size()]; // // Precompute any shapes in which we know we can compute the area; this is done in BuildNodes() // memoizedSolutions = new ComplexRegionEquation[graph.Size()]; // Traverse depth-first to construct all equations. bool success = SimpleVisit(startIndex, eq, visited); return(success ? memoizedSolutions[startIndex] : null); }
// // Given a shape that owns the atomic region, recur through the resulting atomic region // // From // public void SolveHelper(Region currOuterRegion, List<TreeNode<Figure>> currHierarchyRoots, ComplexRegionEquation currEquation, double currArea, KnownMeasurementsAggregator known) { IndexList currOuterRegionIndices = IndexList.AcquireAtomicRegionIndices(figureAtoms, currOuterRegion.atoms); // There is no outer region if (currOuterRegionIndices.IsEmpty()) return; // // We have reached this point by subtracting shapes, therefore, we have an equation. // SolutionAgg agg = new SolutionAgg(); agg.solEq = new ComplexRegionEquation(currEquation); agg.solEq.SetTarget(currOuterRegion); agg.solType = currArea < 0 ? SolutionAgg.SolutionType.INCOMPUTABLE : SolutionAgg.SolutionType.COMPUTABLE; agg.solArea = currArea; agg.atomIndices = currOuterRegionIndices; // // Add this solution to the database. // solutions.AddSolution(agg); // Was this equation solving for a single atomic region? If so, leave. if (currOuterRegion.IsAtomic()) return; // // Recursively explore EACH sub-shape root inside of the outer region. // foreach (TreeNode<Figure> shapeNode in currHierarchyRoots) { // A list omitting this shape List<TreeNode<Figure>> updatedHierarchy = new List<TreeNode<Figure>>(currHierarchyRoots); updatedHierarchy.Remove(shapeNode); // Process this shape ProcessShape(currOuterRegion, shapeNode, updatedHierarchy, currEquation, currArea, known); // Process the children ProcessChildrenShapes(currOuterRegion, shapeNode, updatedHierarchy, currEquation, currArea, known); } }
// // 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)); }
// // Depth-First // public ComplexRegionEquation TraceRegionArea(Region thatRegion) { // Find this region in the hypergraph. int startIndex = graph.GetNodeIndex(thatRegion); if (startIndex == -1) throw new ArgumentException("Desired region not found in area hypergraph: " + thatRegion); // Modifiable region equation: region = region so that we substitute into the RHS. ComplexRegionEquation eq = new ComplexRegionEquation(thatRegion, thatRegion); bool[] visited = new bool[graph.Size()]; // // Precompute any shapes in which we know we can compute the area; this is done in BuildNodes() // memoizedSolutions = new ComplexRegionEquation[graph.Size()]; // Traverse depth-first to construct all equations. bool success = SimpleVisit(startIndex, eq, visited); return success ? memoizedSolutions[startIndex] : null; }
// // Process the child's shapes. // private void ProcessChildrenShapes(Region currOuterRegion, TreeNode <Figure> currShape, List <TreeNode <Figure> > currHierarchyRoots, ComplexRegionEquation currEquation, double currArea, KnownMeasurementsAggregator known) { foreach (TreeNode <Figure> childNode in currShape.Children()) { // A copy of the children minus this shape. List <TreeNode <Figure> > childHierarchy = new List <TreeNode <Figure> >(currShape.Children()); childHierarchy.Remove(childNode); // Add the hierarchy to the list of topmost hierarchical shapes. childHierarchy.AddRange(currHierarchyRoots); ProcessShape(currOuterRegion, childNode, childHierarchy, currEquation, currArea, known); } }
// // 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; }
// // Create the actual equation and continue processing recursively. // private void ProcessShape(Region currOuterRegion, TreeNode<Figure> currShape, List<TreeNode<Figure>> currHierarchyRoots, ComplexRegionEquation currEquation, double currArea, KnownMeasurementsAggregator known) { // Acquire the sub-shape. Figure currentFigure = currShape.GetData(); // See what regions compose the subshape. ShapeRegion childShapeRegion = new ShapeRegion(currentFigure); // Make a copy of the current outer regions Region regionCopy = new Region(currOuterRegion); // Remove all regions from the outer region; if successful, recur on the new outer shape. if (regionCopy.Remove(childShapeRegion.atoms)) { // Update the equation: copy and modify ComplexRegionEquation eqCopy = new ComplexRegionEquation(currEquation); eqCopy.AppendSubtraction(childShapeRegion); // Compute new area double currAreaCopy = currArea; if (currAreaCopy > 0) { double currShapeArea = currentFigure.GetArea(known); currAreaCopy = currShapeArea < 0 ? -1 : currAreaCopy - currShapeArea; } // Recur. SolveHelper(regionCopy, currHierarchyRoots, eqCopy, currAreaCopy, known); } }
// // Catalyst routine to the recursive solver: returns solution equation and actual area. // public void SolveAll(KnownMeasurementsAggregator known, List<Figure> allFigures) { PreprocessAtomAreas(known); PreprocessShapeHierarchyAreas(known, allFigures); // // Using the atomic regions, explore all of the top-most shapes recursively. // for (int a = 0; a < figureAtoms.Count; a++) { IndexList atomIndexList = new IndexList(a); SolutionAgg agg = null; solutions.TryGetValue(atomIndexList, out agg); if (agg == null) { Figure topShape = figureAtoms[a].GetTopMostShape(); // Shape Region? ComplexRegionEquation startEq = new ComplexRegionEquation(null, new ShapeRegion(topShape)); double outerArea = topShape.GetArea(known); // Invoke the recursive solver using the outermost region and catalyst. //ProcessChildrenShapes(a, new ShapeRegion(topShape), topShape.Hierarchy(), // new List<TreeNode<Figure>>(), // startEq, outerArea, known); SolveHelper(new ShapeRegion(topShape), topShape.Hierarchy().Children(), startEq, outerArea, known); } else if (agg.solType == SolutionAgg.SolutionType.COMPUTABLE) { //solutions[atomIndexList] = agg; } else if (agg.solType == SolutionAgg.SolutionType.INCOMPUTABLE) { //solutions[atomIndexList] = agg; } else if (agg.solType == SolutionAgg.SolutionType.UNKNOWN) { //TBD } } // // Subtraction of shapes extracts as many atomic regions as possible of the strict atomic regions, now compose those together. // ComposeAllRegions(); }
// // 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); }
// // Process the child's shapes. // private void ProcessChildrenShapes(Region currOuterRegion, TreeNode<Figure> currShape, List<TreeNode<Figure>> currHierarchyRoots, ComplexRegionEquation currEquation, double currArea, KnownMeasurementsAggregator known) { foreach (TreeNode<Figure> childNode in currShape.Children()) { // A copy of the children minus this shape. List<TreeNode<Figure>> childHierarchy = new List<TreeNode<Figure>>(currShape.Children()); childHierarchy.Remove(childNode); // Add the hierarchy to the list of topmost hierarchical shapes. childHierarchy.AddRange(currHierarchyRoots); ProcessShape(currOuterRegion, childNode, childHierarchy, currEquation, currArea, known); } }