private static bool HandleSimpleSegmentEquation(KnownMeasurementsAggregator known, SegmentEquation theEq) { if (theEq.GetAtomicity() != Equation.BOTH_ATOMIC) { return(false); } Segment unknownSegment = null; double segmentValue = -1; if (theEq.lhs is NumericValue) { unknownSegment = theEq.rhs as Segment; segmentValue = (theEq.lhs as NumericValue).DoubleValue; } else if (theEq.rhs is NumericValue) { unknownSegment = theEq.lhs as Segment; segmentValue = (theEq.rhs as NumericValue).DoubleValue; } else { return(false); } // // (7) Add to the list of knowns // return(known.AddSegmentLength(unknownSegment, segmentValue)); }
// // Get the numeric value of this area. // public virtual double GetArea(KnownMeasurementsAggregator known) { // Did we memoize this area? if (thisArea > 0) { return(thisArea); } // Calculate the area if not memoized. double area = 0; foreach (Atomizer.AtomicRegion atom in atoms) { double currArea = atom.GetArea(known); if (currArea <= 0) { return(-1); } area += currArea; } return(area); }
private static bool HandleSimpleArcEquation(KnownMeasurementsAggregator known, ArcEquation theEq) { if (theEq.GetAtomicity() != Equation.BOTH_ATOMIC) { return(false); } Arc unknownArc = null; double measure = -1; if (theEq.lhs is NumericValue) { unknownArc = theEq.rhs as Arc; measure = (theEq.lhs as NumericValue).DoubleValue; } else if (theEq.rhs is NumericValue) { unknownArc = theEq.lhs as Arc; measure = (theEq.rhs as NumericValue).DoubleValue; } else { return(false); } // // (7) Add to the list of knowns // return(known.AddArcMeasureDegree(unknownArc, measure)); }
// // 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); } }
// // Recur through all of the shapes to pre-calculate their areas. // private void PreprocessShapeHierarchyAreas(KnownMeasurementsAggregator known, List <Figure> allFigures) { foreach (Figure theFigure in allFigures) { // Acquire the indices of the shape. IndexList figIndices = IndexList.AcquireAtomicRegionIndices(figureAtoms, theFigure.atoms); figureIndexMap[figIndices] = theFigure; double area = theFigure.GetArea(known); if (area > 0) { ShapeRegion atomRegion = new ShapeRegion(theFigure); SolutionAgg agg = new SolutionAgg(); // The equation is the identity equation. agg.solEq = new ComplexRegionEquation(atomRegion, atomRegion); agg.solType = SolutionAgg.SolutionType.COMPUTABLE; agg.solArea = area; agg.atomIndices = IndexList.AcquireAtomicRegionIndices(figureAtoms, theFigure.atoms); // Add this solution to the database. solutions.AddSolution(agg); } } }
private void PreprocessAtomAreas(KnownMeasurementsAggregator known) { // // Preprocess any of the shape atoms to see if the area is computable. // for (int a = 0; a < figureAtoms.Count; a++) { ShapeAtomicRegion shapeAtom = figureAtoms[a] as ShapeAtomicRegion; if (shapeAtom != null) { double area = shapeAtom.GetArea(known); if (area > 0) { ShapeRegion atomRegion = new ShapeRegion(shapeAtom.shape); SolutionAgg agg = new SolutionAgg(); // The equation is the identity equation. agg.solEq = new ComplexRegionEquation(atomRegion, atomRegion); agg.solType = SolutionAgg.SolutionType.COMPUTABLE; agg.solArea = area; agg.atomIndices = new IndexList(a); // Add this solution to the database. solutions.AddSolution(agg); } } } }
private static bool AcquireViaFigures(KnownMeasurementsAggregator known, List<Figure> figures) { // // Split into the types of figures. // List<Triangle> triangles = new List<Triangle>(); List<IsoscelesTrapezoid> isoTraps = new List<IsoscelesTrapezoid>(); foreach (Figure fig in figures) { if (fig is Triangle) triangles.Add(fig as Triangle); if (fig is IsoscelesTrapezoid) isoTraps.Add(fig as IsoscelesTrapezoid); } // // Process each type of figure. // bool addedKnown = false; foreach (Triangle tri in triangles) { addedKnown = KnownValueAcquisition.HandleTriangle(known, tri) || addedKnown; } foreach (IsoscelesTrapezoid isoTrap in isoTraps) { HandleIsoscelesTrapezoid(known, isoTrap); } return addedKnown; }
public static KnownMeasurementsAggregator Propogate(KnownMeasurementsAggregator known, List<Constraint> constraints) { List<GroundedClause> congruences = new List<GroundedClause>(); List<GroundedClause> equations = new List<GroundedClause>(); List<Figure> figures = new List<Figure>(); foreach (Constraint constraint in constraints) { if (constraint is CongruenceConstraint) congruences.Add((constraint as CongruenceConstraint).conConstraint); if (constraint is EquationConstraint) equations.Add((constraint as EquationConstraint).eqConstraint); if (constraint is FigureConstraint) figures.Add((constraint as FigureConstraint).figConstraint); } // // Fixed-point acquisition of values using congruences and equations. // bool change = true; while(change) { change = KnownValueAcquisition.AcquireCongruences(known, congruences); // Right Triangles, Isosceles Triangles, Isosceles Trapezoids change = AcquireViaFigures(known, figures) || change; change = KnownValueAcquisition.AcquireViaEquations(known, equations) || change; } return known; }
public override double EvaluateArea(KnownMeasurementsAggregator known) { double leftArea = leftProblem.EvaluateArea(known); double rightArea = rightProblem.EvaluateArea(known); if (leftArea < 0 || rightArea < 0) return -1; return leftArea + rightArea; }
public static bool AcquireCongruences(KnownMeasurementsAggregator known, List <GroundedClause> clauses) { bool addedKnown = false; foreach (GeometryTutorLib.ConcreteAST.GroundedClause clause in clauses) { GeometryTutorLib.ConcreteAST.CongruentSegments cs = clause as GeometryTutorLib.ConcreteAST.CongruentSegments; if (cs != null && !cs.IsReflexive()) { double length1 = known.GetSegmentLength(cs.cs1); double length2 = known.GetSegmentLength(cs.cs2); if (length1 >= 0 && length2 < 0) { if (known.AddSegmentLength(cs.cs2, length1)) { addedKnown = true; } } if (length1 <= 0 && length2 > 0) { if (known.AddSegmentLength(cs.cs1, length2)) { addedKnown = true; } } // else: both known } GeometryTutorLib.ConcreteAST.CongruentAngles cas = clause as GeometryTutorLib.ConcreteAST.CongruentAngles; if (cas != null && !cas.IsReflexive()) { double measure1 = known.GetAngleMeasure(cas.ca1); double measure2 = known.GetAngleMeasure(cas.ca2); if (measure1 >= 0 && measure2 < 0) { if (known.AddAngleMeasureDegree(cas.ca2, measure1)) { addedKnown = true; } } if (measure1 <= 0 && measure2 > 0) { if (known.AddAngleMeasureDegree(cas.ca1, measure2)) { addedKnown = true; } } // else: both known } } return(addedKnown); }
private static bool HandleRatioEquation(KnownMeasurementsAggregator known, SegmentRatioEquation theEq) { double topLeft = known.GetSegmentLength(theEq.lhs.smallerSegment); double bottomLeft = known.GetSegmentLength(theEq.lhs.largerSegment); double topRight = known.GetSegmentLength(theEq.rhs.smallerSegment); double bottomRight = known.GetSegmentLength(theEq.rhs.largerSegment); int unknown = 0; if (topLeft <= 0) { unknown++; } if (bottomLeft <= 0) { unknown++; } if (topRight <= 0) { unknown++; } if (bottomRight <= 0) { unknown++; } if (unknown != 1) { return(false); } if (topLeft <= 0) { return(known.AddSegmentLength(theEq.lhs.smallerSegment, (topRight / bottomRight) * bottomLeft)); } else if (bottomLeft <= 0) { return(known.AddSegmentLength(theEq.lhs.largerSegment, topLeft * (bottomRight / topRight))); } else if (topRight <= 0) { return(known.AddSegmentLength(theEq.rhs.smallerSegment, (topLeft / bottomLeft) * bottomRight)); } else if (bottomRight <= 0) { return(known.AddSegmentLength(theEq.rhs.largerSegment, topRight * (bottomLeft / topLeft))); } else { return(false); } }
// // 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); } }
// // 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); } }
// // (1) Make a copy // (2) Collect the equation terms. // (3) Are all but one known? // (4) Substitute // (5) Simplify // (6) Acquire the unknown and its value. // (7) Add to the list of knowns. // public static bool HandleEquation(KnownMeasurementsAggregator known, List <GroundedClause> clauses, Equation theEq) { if (theEq is AngleEquation) { return(HandleAngleEquation(known, clauses, theEq as AngleEquation)); } if (theEq is SegmentEquation) { return(HandleSegmentEquation(known, clauses, theEq as SegmentEquation)); } if (theEq is ArcEquation) { return(HandleArcEquation(known, clauses, theEq as ArcEquation)); } return(false); }
// // Check all equations to see if we can substitute into any. // public static bool AcquireViaEquations(KnownMeasurementsAggregator known, List<GroundedClause> clauses) { bool addedKnown = false; foreach (GeometryTutorLib.ConcreteAST.GroundedClause clause in clauses) { if (clause is GeometryTutorLib.ConcreteAST.Equation) { if (HandleEquation(known, clauses, clause as Equation)) addedKnown = true; } else if (clause is GeometryTutorLib.ConcreteAST.SegmentRatioEquation) { if (HandleRatioEquation(known, clause as SegmentRatioEquation)) addedKnown = true; } } return addedKnown; }
public static KnownMeasurementsAggregator AcquireAllKnownValues(KnownMeasurementsAggregator known, List<GroundedClause> congsEqs, List<GroundedClause> triangles) { // // Fixed-point acquisition of values using congruences and equations. // bool change = true; while(change) { change = AcquireCongruences(known, congsEqs); // Pythagorean Theorem change = AcquireViaTriangles(known, triangles) || change; change = AcquireViaEquations(known, congsEqs) || change; } return known; }
public static KnownMeasurementsAggregator AcquireAllKnownValues(KnownMeasurementsAggregator known, List <GroundedClause> congsEqs, List <GroundedClause> triangles) { // // Fixed-point acquisition of values using congruences and equations. // bool change = true; while (change) { change = AcquireCongruences(known, congsEqs); // Pythagorean Theorem change = AcquireViaTriangles(known, triangles) || change; change = AcquireViaEquations(known, congsEqs) || change; } return(known); }
// // Get the numeric value of this area. // public virtual double GetArea(KnownMeasurementsAggregator known) { // Did we memoize this area? if (thisArea > 0) return thisArea; // Calculate the area if not memoized. double area = 0; foreach (Atomizer.AtomicRegion atom in atoms) { double currArea = atom.GetArea(known); if (currArea <= 0) return -1; area += currArea; } return area; }
public static bool AcquireCongruences(KnownMeasurementsAggregator known, List<GroundedClause> clauses) { bool addedKnown = false; foreach (GeometryTutorLib.ConcreteAST.GroundedClause clause in clauses) { GeometryTutorLib.ConcreteAST.CongruentSegments cs = clause as GeometryTutorLib.ConcreteAST.CongruentSegments; if (cs != null && !cs.IsReflexive()) { double length1 = known.GetSegmentLength(cs.cs1); double length2 = known.GetSegmentLength(cs.cs2); if (length1 >= 0 && length2 < 0) { if (known.AddSegmentLength(cs.cs2, length1)) addedKnown = true; } if (length1 <= 0 && length2 > 0) { if (known.AddSegmentLength(cs.cs1, length2)) addedKnown = true; } // else: both known } GeometryTutorLib.ConcreteAST.CongruentAngles cas = clause as GeometryTutorLib.ConcreteAST.CongruentAngles; if (cas != null && !cas.IsReflexive()) { double measure1 = known.GetAngleMeasure(cas.ca1); double measure2 = known.GetAngleMeasure(cas.ca2); if (measure1 >= 0 && measure2 < 0) { if (known.AddAngleMeasureDegree(cas.ca2, measure1)) addedKnown = true; } if (measure1 <= 0 && measure2 > 0) { if (known.AddAngleMeasureDegree(cas.ca1, measure2)) addedKnown = true; } // else: both known } } return addedKnown; }
private static bool AddKnowns(KnownMeasurementsAggregator known, List <KeyValuePair <Segment, double> > pairs) { if (!pairs.Any()) { return(false); } bool change = false; foreach (KeyValuePair <Segment, double> rightPair in pairs) { // Do we know this already? if (known.GetSegmentLength(rightPair.Key) < 0) { change = true; known.AddSegmentLength(rightPair.Key, rightPair.Value); } } return(change); }
private static bool AcquireViaTriangles(KnownMeasurementsAggregator known, List <GroundedClause> triangles) { bool addedKnown = false; foreach (GroundedClause clause in triangles) { if (clause is Triangle) { addedKnown = HandleTriangle(known, clause as Triangle) || addedKnown; } else if (clause is Strengthened) { Strengthened streng = clause as Strengthened; if (streng.strengthened is Triangle) { addedKnown = HandleTriangle(known, streng.strengthened as Triangle) || addedKnown; } } } return(addedKnown); }
public static KnownMeasurementsAggregator Propogate(KnownMeasurementsAggregator known, List <Constraint> constraints) { List <GroundedClause> congruences = new List <GroundedClause>(); List <GroundedClause> equations = new List <GroundedClause>(); List <Figure> figures = new List <Figure>(); foreach (Constraint constraint in constraints) { if (constraint is CongruenceConstraint) { congruences.Add((constraint as CongruenceConstraint).conConstraint); } if (constraint is EquationConstraint) { equations.Add((constraint as EquationConstraint).eqConstraint); } if (constraint is FigureConstraint) { figures.Add((constraint as FigureConstraint).figConstraint); } } // // Fixed-point acquisition of values using congruences and equations. // bool change = true; while (change) { change = KnownValueAcquisition.AcquireCongruences(known, congruences); // Right Triangles, Isosceles Triangles, Isosceles Trapezoids change = AcquireViaFigures(known, figures) || change; change = KnownValueAcquisition.AcquireViaEquations(known, equations) || change; } return(known); }
// // A right triangle means we can apply the pythagorean theorem to acquire an unknown. // public static bool HandleTriangle(KnownMeasurementsAggregator known, Triangle tri) { if (tri == null) { return(false); } KeyValuePair <Segment, double> pair = tri.PythagoreanTheoremApplies(known); if (pair.Value > 0) { // Do we know this already? if (known.GetSegmentLength(pair.Key) > 0) { return(false); } // We don't know it, we add it. known.AddSegmentLength(pair.Key, pair.Value); return(true); } else { if (AddKnowns(known, tri.IsoscelesRightApplies(known))) { return(true); } if (AddKnowns(known, tri.CalculateBaseOfIsosceles(known))) { return(true); } if (AddKnowns(known, tri.RightTriangleTrigApplies(known))) { return(true); } } return(false); }
private static bool AcquireViaFigures(KnownMeasurementsAggregator known, List <Figure> figures) { // // Split into the types of figures. // List <Triangle> triangles = new List <Triangle>(); List <IsoscelesTrapezoid> isoTraps = new List <IsoscelesTrapezoid>(); foreach (Figure fig in figures) { if (fig is Triangle) { triangles.Add(fig as Triangle); } if (fig is IsoscelesTrapezoid) { isoTraps.Add(fig as IsoscelesTrapezoid); } } // // Process each type of figure. // bool addedKnown = false; foreach (Triangle tri in triangles) { addedKnown = KnownValueAcquisition.HandleTriangle(known, tri) || addedKnown; } foreach (IsoscelesTrapezoid isoTrap in isoTraps) { HandleIsoscelesTrapezoid(known, isoTrap); } return(addedKnown); }
// // Check all equations to see if we can substitute into any. // public static bool AcquireViaEquations(KnownMeasurementsAggregator known, List <GroundedClause> clauses) { bool addedKnown = false; foreach (GeometryTutorLib.ConcreteAST.GroundedClause clause in clauses) { if (clause is GeometryTutorLib.ConcreteAST.Equation) { if (HandleEquation(known, clauses, clause as Equation)) { addedKnown = true; } } else if (clause is GeometryTutorLib.ConcreteAST.SegmentRatioEquation) { if (HandleRatioEquation(known, clause as SegmentRatioEquation)) { addedKnown = true; } } } return(addedKnown); }
// // An isosceles trapezoid can use an equation to find the height based on the bases and the side lengths. // public static void HandleIsoscelesTrapezoid(KnownMeasurementsAggregator known, IsoscelesTrapezoid isoTrap) { isoTrap.CalculateHeight(known); }
// // We have a set of constraints associated with the figure. // Also associated is a set of variables in which constraints are defined. // 1) Randomly choose one of the variables that defines the area formula, define it by its coordinate-based value. // 2) Push it through the constant propagator. // 3) From the list of variables, remove which of them that are now known. // 4) Repeat until the list of variables is empty. // public KnownMeasurementsAggregator AcquireKnowns() { // Acquire all unknown variables required to calculate the area. List<Segment> unknownAreaVars = this.GetAreaVariables(); // The constraints for this problem. List<Constraint> constraints = this.GetConstraints(); // The values we must state to the user in order to solve the problem. List<Segment> assumptions = new List<Segment>(); // // Loop until all variables are known. // KnownMeasurementsAggregator known = new KnownMeasurementsAggregator(); while (unknownAreaVars.Any()) { // Acquire a new assumption. Segment newAssumption = unknownAreaVars[0]; // remove that assumption since it is now known; add as an assumption. unknownAreaVars.RemoveAt(0); assumptions.Add(newAssumption); // Set this value as known with its intrinsic (corrdinate-based) length. known.AddSegmentLength(newAssumption, newAssumption.Length); // Propagate the new information through the constraints. ConstantPropagator.Propogate(known, constraints); // Check if any of the unknown variables are now known through constant propagation. unknownAreaVars = AcquireCurrentUnknowns(known, unknownAreaVars); } // // Create the known object. // KnownMeasurementsAggregator trueAssumptions = new KnownMeasurementsAggregator(); foreach (Segment seg in assumptions) { trueAssumptions.AddSegmentLength(seg, seg.Length); } return trueAssumptions; }
public abstract double EvaluateArea(KnownMeasurementsAggregator known);
// // 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); } }
private static bool HandleSimpleSegmentEquation(KnownMeasurementsAggregator known, SegmentEquation theEq) { if (theEq.GetAtomicity() != Equation.BOTH_ATOMIC) return false; Segment unknownSegment = null; double segmentValue = -1; if (theEq.lhs is NumericValue) { unknownSegment = theEq.rhs as Segment; segmentValue = (theEq.lhs as NumericValue).DoubleValue; } else if (theEq.rhs is NumericValue) { unknownSegment = theEq.lhs as Segment; segmentValue = (theEq.rhs as NumericValue).DoubleValue; } else return false; // // (7) Add to the list of knowns // return known.AddSegmentLength(unknownSegment, segmentValue); }
// // (1) Make a copy // (2) Collect the equation terms. // (3) Are all but one known? // (4) Substitute // (5) Simplify // (6) Acquire the unknown and its value. // (7) Add to the list of knowns. // private static bool HandleSegmentEquation(KnownMeasurementsAggregator known, List <GroundedClause> clauses, SegmentEquation theEq) { if (theEq.GetAtomicity() == Equation.BOTH_ATOMIC) { return(HandleSimpleSegmentEquation(known, theEq)); } // CTA: Verify this calls the correct Equation deep copy mechanism. // (1) Make a copy SegmentEquation copy = (SegmentEquation)theEq.DeepCopy(); // (2) Collect the equation terms. List <GroundedClause> left = copy.lhs.CollectTerms(); double[] leftVal = new double[left.Count]; List <GroundedClause> right = copy.rhs.CollectTerms(); double[] rightVal = new double[right.Count]; // (3) Are all but one term known? int unknownCount = 0; for (int ell = 0; ell < left.Count; ell++) { if (left[ell] is NumericValue) { leftVal[ell] = (left[ell] as NumericValue).DoubleValue; } else { leftVal[ell] = known.GetSegmentLength(left[ell] as Segment); if (leftVal[ell] <= 0) { unknownCount++; } } } for (int r = 0; r < right.Count; r++) { if (right[r] is NumericValue) { rightVal[r] = (right[r] as NumericValue).DoubleValue; } else { rightVal[r] = known.GetSegmentLength(right[r] as Segment); if (rightVal[r] <= 0) { unknownCount++; } } } // We can't solve for more or less than one unknown. if (unknownCount != 1) { return(false); } // // (4) Substitute // for (int ell = 0; ell < left.Count; ell++) { if (leftVal[ell] > 0) { copy.Substitute(left[ell], new NumericValue(leftVal[ell])); } } for (int r = 0; r < right.Count; r++) { if (rightVal[r] > 0) { copy.Substitute(right[r], new NumericValue(rightVal[r])); } } // // (5) Simplify // SegmentEquation simplified = (SegmentEquation)GenericInstantiator.Simplification.Simplify(copy); return(HandleSimpleSegmentEquation(known, simplified)); }
private static bool HandleRatioEquation(KnownMeasurementsAggregator known, SegmentRatioEquation theEq) { double topLeft = known.GetSegmentLength(theEq.lhs.smallerSegment); double bottomLeft = known.GetSegmentLength(theEq.lhs.largerSegment); double topRight = known.GetSegmentLength(theEq.rhs.smallerSegment); double bottomRight = known.GetSegmentLength(theEq.rhs.largerSegment); int unknown = 0; if (topLeft <= 0) unknown++; if (bottomLeft <= 0) unknown++; if (topRight <= 0) unknown++; if (bottomRight <= 0) unknown++; if (unknown != 1) return false; if (topLeft <= 0) { return known.AddSegmentLength(theEq.lhs.smallerSegment, (topRight / bottomRight) * bottomLeft); } else if (bottomLeft <= 0) { return known.AddSegmentLength(theEq.lhs.largerSegment, topLeft * (bottomRight / topRight)); } else if (topRight <= 0) { return known.AddSegmentLength(theEq.rhs.smallerSegment, (topLeft / bottomLeft) * bottomRight); } else if (bottomRight <= 0) { return known.AddSegmentLength(theEq.rhs.largerSegment, topRight * (bottomLeft / topLeft)); } else return false; }
// // Dynamic Programming Style Solution Construction; equation and actual area. // public KeyValuePair <ComplexRegionEquation, double> Solve(List <Atomizer.AtomicRegion> atoms, KnownMeasurementsAggregator known) { // Construct the memoization data structure. if (memoizedSolutions == null) { memoizedSolutions = new ComplexRegionEquation[graph.Size()]; } // The region for which we will construct an equation. Region desired = new Region(atoms); // Determine if this region is actually in the hypergraph. int startIndex = graph.GetNodeIndex(desired); if (startIndex == -1) { throw new ArgumentException("Desired region not found in area hypergraph: " + desired); } // For marking if we have visited the given node already bool[] visited = new bool[graph.Size()]; // Traverse dymanically to construct all equations. return(DynamicVisit(startIndex, visited, known)); }
// // A right triangle means we can apply the pythagorean theorem to acquire an unknown. // public static bool HandleTriangle(KnownMeasurementsAggregator known, Triangle tri) { if (tri == null) return false; KeyValuePair<Segment, double> pair = tri.PythagoreanTheoremApplies(known); if (pair.Value > 0) { // Do we know this already? if (known.GetSegmentLength(pair.Key) > 0) return false; // We don't know it, we add it. known.AddSegmentLength(pair.Key, pair.Value); return true; } else { if (AddKnowns(known, tri.IsoscelesRightApplies(known))) return true; if (AddKnowns(known, tri.CalculateBaseOfIsosceles(known))) return true; if (AddKnowns(known, tri.RightTriangleTrigApplies(known))) return true; } return false; }
public override double GetArea(KnownMeasurementsAggregator known) { return shape.GetArea(known); }
// // An isosceles trapezoid can use an equation to find the height based on the bases and the side lengths. // public static void HandleIsoscelesTrapezoid(KnownMeasurementsAggregator known, IsoscelesTrapezoid isoTrap) { isoTrap.CalculateHeight(known); }
// // Filter the list of unknowns by any new information. // private List<Segment> AcquireCurrentUnknowns(KnownMeasurementsAggregator known, List<Segment> unknowns) { List<Segment> newUnknowns = new List<Segment>(); foreach (Segment unknown in unknowns) { if (known.GetSegmentLength(unknown) < 0) newUnknowns.Add(unknown); } return newUnknowns; }
// // (1) Make a copy // (2) Collect the equation terms. // (3) Are all but one known? // (4) Substitute // (5) Simplify // (6) Acquire the unknown and its value. // (7) Add to the list of knowns. // private static bool HandleSegmentEquation(KnownMeasurementsAggregator known, List<GroundedClause> clauses, SegmentEquation theEq) { if (theEq.GetAtomicity() == Equation.BOTH_ATOMIC) return HandleSimpleSegmentEquation(known, theEq); // CTA: Verify this calls the correct Equation deep copy mechanism. // (1) Make a copy SegmentEquation copy = (SegmentEquation)theEq.DeepCopy(); // (2) Collect the equation terms. List<GroundedClause> left = copy.lhs.CollectTerms(); double[] leftVal = new double[left.Count]; List<GroundedClause> right = copy.rhs.CollectTerms(); double[] rightVal = new double[right.Count]; // (3) Are all but one term known? int unknownCount = 0; for (int ell = 0; ell < left.Count; ell++) { if (left[ell] is NumericValue) leftVal[ell] = (left[ell] as NumericValue).DoubleValue; else { leftVal[ell] = known.GetSegmentLength(left[ell] as Segment); if (leftVal[ell] <= 0) unknownCount++; } } for (int r = 0; r < right.Count; r++) { if (right[r] is NumericValue) rightVal[r] = (right[r] as NumericValue).DoubleValue; else { rightVal[r] = known.GetSegmentLength(right[r] as Segment); if (rightVal[r] <= 0) unknownCount++; } } // We can't solve for more or less than one unknown. if (unknownCount != 1) return false; // // (4) Substitute // for (int ell = 0; ell < left.Count; ell++) { if (leftVal[ell] > 0) copy.Substitute(left[ell], new NumericValue(leftVal[ell])); } for (int r = 0; r < right.Count; r++) { if (rightVal[r] > 0) copy.Substitute(right[r], new NumericValue(rightVal[r])); } // // (5) Simplify // SegmentEquation simplified = (SegmentEquation)GenericInstantiator.Simplification.Simplify(copy); return HandleSimpleSegmentEquation(known, simplified); }
// // 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); }
public override double EvaluateArea(KnownMeasurementsAggregator known) { return figure.GetArea(known); }
// // (1) Make a copy // (2) Collect the equation terms. // (3) Are all but one known? // (4) Substitute // (5) Simplify // (6) Acquire the unknown and its value. // (7) Add to the list of knowns. // public static bool HandleEquation(KnownMeasurementsAggregator known, List<GroundedClause> clauses, Equation theEq) { if (theEq is AngleEquation) return HandleAngleEquation(known, clauses, theEq as AngleEquation); if (theEq is SegmentEquation) return HandleSegmentEquation(known, clauses, theEq as SegmentEquation); if (theEq is ArcEquation) return HandleArcEquation(known, clauses, theEq as ArcEquation); return false; }
// // Dynamic Programming Style Solution Construction; equation and actual area. // public KeyValuePair<ComplexRegionEquation, double> Solve(List<Atomizer.AtomicRegion> atoms, KnownMeasurementsAggregator known) { // Construct the memoization data structure. if (memoizedSolutions == null) memoizedSolutions = new ComplexRegionEquation[graph.Size()]; // The region for which we will construct an equation. Region desired = new Region(atoms); // Determine if this region is actually in the hypergraph. int startIndex = graph.GetNodeIndex(desired); if (startIndex == -1) { throw new ArgumentException("Desired region not found in area hypergraph: " + desired); } // For marking if we have visited the given node already bool[] visited = new bool[graph.Size()]; // Traverse dymanically to construct all equations. return DynamicVisit(startIndex, visited, known); }
private static bool AcquireViaTriangles(KnownMeasurementsAggregator known, List<GroundedClause> triangles) { bool addedKnown = false; foreach (GroundedClause clause in triangles) { if (clause is Triangle) { addedKnown = HandleTriangle(known, clause as Triangle) || addedKnown; } else if (clause is Strengthened) { Strengthened streng = clause as Strengthened; if (streng.strengthened is Triangle) { addedKnown = HandleTriangle(known, streng.strengthened as Triangle) || addedKnown; } } } return addedKnown; }
// // 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(); }
private static bool AddKnowns(KnownMeasurementsAggregator known, List<KeyValuePair<Segment, double>> pairs) { if (!pairs.Any()) return false; bool change = false; foreach (KeyValuePair<Segment, double> rightPair in pairs) { // Do we know this already? if (known.GetSegmentLength(rightPair.Key) < 0) { change = true; known.AddSegmentLength(rightPair.Key, rightPair.Value); } } return change; }
// // 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); } }
private void PreprocessAtomAreas(KnownMeasurementsAggregator known) { // // Preprocess any of the shape atoms to see if the area is computable. // for (int a = 0; a < figureAtoms.Count; a++) { ShapeAtomicRegion shapeAtom = figureAtoms[a] as ShapeAtomicRegion; if (shapeAtom != null) { double area = shapeAtom.GetArea(known); if (area > 0) { ShapeRegion atomRegion = new ShapeRegion(shapeAtom.shape); SolutionAgg agg = new SolutionAgg(); // The equation is the identity equation. agg.solEq = new ComplexRegionEquation(atomRegion, atomRegion); agg.solType = SolutionAgg.SolutionType.COMPUTABLE; agg.solArea = area; agg.atomIndices = new IndexList(a); // Add this solution to the database. solutions.AddSolution(agg); } } } }
// // Recur through all of the shapes to pre-calculate their areas. // private void PreprocessShapeHierarchyAreas(KnownMeasurementsAggregator known, List<Figure> allFigures) { foreach (Figure theFigure in allFigures) { // Acquire the indices of the shape. IndexList figIndices = IndexList.AcquireAtomicRegionIndices(figureAtoms, theFigure.atoms); figureIndexMap[figIndices] = theFigure; double area = theFigure.GetArea(known); if (area > 0) { ShapeRegion atomRegion = new ShapeRegion(theFigure); SolutionAgg agg = new SolutionAgg(); // The equation is the identity equation. agg.solEq = new ComplexRegionEquation(atomRegion, atomRegion); agg.solType = SolutionAgg.SolutionType.COMPUTABLE; agg.solArea = area; agg.atomIndices = IndexList.AcquireAtomicRegionIndices(figureAtoms, theFigure.atoms); // Add this solution to the database. solutions.AddSolution(agg); } } }
private static bool HandleSimpleArcEquation(KnownMeasurementsAggregator known, ArcEquation theEq) { if (theEq.GetAtomicity() != Equation.BOTH_ATOMIC) return false; Arc unknownArc = null; double measure = -1; if (theEq.lhs is NumericValue) { unknownArc = theEq.rhs as Arc; measure = (theEq.lhs as NumericValue).DoubleValue; } else if (theEq.rhs is NumericValue) { unknownArc = theEq.lhs as Arc; measure = (theEq.rhs as NumericValue).DoubleValue; } else return false; // // (7) Add to the list of knowns // return known.AddArcMeasureDegree(unknownArc, measure); }
// // 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); } }
public override double GetArea(KnownMeasurementsAggregator known) { return(shape.GetArea(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)); }