コード例 #1
0
ファイル: Circuit.cs プロジェクト: logisketchUCSD/Code
        /// <summary>
        /// Constructs a Circuit given a Dictionary of all the gates,
        /// List of all outputs, and List of all inputs
        /// </summary>
        public Circuit(Dictionary <Sketch.Shape, Dictionary <int, Tuple <Shape, int> > > shapesAndTheirInputs,
                       List <Shape> outputs, List <Shape> inputs,
                       Dictionary <Sketch.Shape, CircuitElement> subCircuits)
            : this()
        {
            // Build global inputs
            foreach (Shape inputShape in inputs)
            {
                INPUT input = new INPUT(inputShape.Name, inputShape.Bounds, inputShape.Orientation);
                shapesToElements.Add(inputShape, input);
                globalInputs.Add(input);
            }

            // Build global outputs
            foreach (Shape outputShape in outputs)
            {
                OUTPUT output = new OUTPUT(outputShape.Name, outputShape.Bounds);
                shapesToElements.Add(outputShape, output);
                globalOutputs.Add(output);
            }

            // Build logic gates within the circuit
            foreach (var shapeAndInputs in shapesAndTheirInputs)
            {
                Shape gateShape = shapeAndInputs.Key;
                Gate  gateElement;

                // If the shape is not a gate, or is already in the circuit, skip it.
                if (!LogicDomain.IsGate(gateShape.Type) || shapesToElements.ContainsKey(gateShape))
                {
                    continue;
                }

                // If it's a subcircuit, roll our own circuit element.
                else if (subCircuits.Keys.Contains(gateShape))
                {
                    SubCircuit associatedSub = (SubCircuit)subCircuits[gateShape];
                    associatedSub = new SubCircuit(gateShape.Name, gateShape.Bounds, gateShape, associatedSub.inputs, associatedSub.outputs,
                                                   associatedSub.behavior, gateShape.Orientation);
                    gateElement            = associatedSub;
                    subCircuits[gateShape] = associatedSub;
                }

                // Otherwise, create an element normally.
                else
                {
                    gateElement = createGate(gateShape.Name, gateShape.Bounds, gateShape.Orientation, gateShape.Type);
                }

                if (gateElement == null)
                {
                    throw new Exception("failed to create gate!");
                }

                shapesToElements.Add(gateShape, gateElement);
                gates.Add(gateElement);
            }

            connectEverything(shapesAndTheirInputs);
        }
コード例 #2
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sketch">SketchPanel to add a label to</param>
        /// <param name="inkStrokes">InkOverlay strokes</param>
        /// <param name="inkStrokes">A StrokeCollection strokes</param>
        /// <param name="label">Label to apply</param>
        public ApplyLabelCmd(SketchPanel sketch, StrokeCollection inkStrokes,
                             string label, bool userSpecifiedGroup = true, bool userSpecifiedLabel = true)
        {
            isUndoable = false;

            this.sketchPanel        = sketch;
            this.label              = label;
            this.inkStrokes         = inkStrokes;
            this.userSpecifiedGroup = userSpecifiedGroup;
            this.userSpecifiedLabel = userSpecifiedLabel;
            labelColor              = LogicDomain.getType(label).Color;

            // Save the original labels of the substrokes
            origLabels       = new Dictionary <string, Data.Pair <ShapeType, StrokeCollection> >();
            unlabeledStrokes = new StrokeCollection();

            foreach (Stroke stroke in inkStrokes)
            {
                Sketch.Substroke sub = sketchPanel.InkSketch.GetSketchSubstrokeByInk(stroke);

                if (sub.ParentShape != null)
                {
                    if (!origLabels.ContainsKey(sub.ParentShape.Name))
                    {
                        origLabels[sub.ParentShape.Name] = new Data.Pair <ShapeType, StrokeCollection>(sub.ParentShape.Type, new StrokeCollection());
                    }
                    origLabels[sub.ParentShape.Name].B.Add(stroke);
                }
                else
                {
                    unlabeledStrokes.Add(stroke);
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Figures out everything a given logic gate should be
        /// connected to, and connects them appropriately.
        ///
        /// Assumption: Every wire-mesh has a unique name.
        ///
        /// Note: this currently only deals with connections to wires.
        /// Hence, it does not make any connections for notbubbles yet.
        /// </summary>
        /// <param name="gate">The gate to connect</param>
        private void connectWiresTo(LogicGate gate)
        {
            // We keep track of what wire-meshes are inputs and outputs
            // so we can do sanity checks before actually connecting
            // them to the logic gate.
            List <string> inputWires  = new List <string>();
            List <string> outputWires = new List <string>();

            int maxOutputs = LogicDomain.MaxOutputs(gate.Type);

            // Cycle through everything connected to the gate's associated
            // shape and categorize their connection type accordingly
            foreach (Sketch.Shape connectedShape in gate.Shape.ConnectedShapes)
            {
                if (!Domain.LogicDomain.IsWire(connectedShape.Type))
                {
                    throw new Exception("Gate " + gate + " was connected to non-wire shape " + connectedShape);
                }

                Sketch.EndPoint connectingEndpoint =
                    gate.Shape.ClosestEndpointFrom(connectedShape);

                if (gate.ShouldBeInput(connectingEndpoint))
                {
                    inputWires.Add(connectedShape.Name);
                }
                else
                {
                    outputWires.Add(connectedShape.Name);
                }
            }

            // If it looks like we mixed up the output and input wires,
            // swap them so they're more correct (this can happen if the
            // gate's orientation was recognized in the wrong direction)
            if ((outputWires.Count > maxOutputs) && (inputWires.Count <= maxOutputs))
            {
                swap(ref outputWires, ref inputWires);
            }

            // Make the connections.
            foreach (string wireName in inputWires)
            {
                WireMesh inputWire = _wireMeshes[wireName];
                gate.ConnectInput(inputWire);
            }
            foreach (string wireName in outputWires)
            {
                WireMesh outputWire = _wireMeshes[wireName];
                gate.ConnectOutput(outputWire);
            }
            gate.ConnectAllInputs();
            gate.ConnectAllOutputs();
        }
コード例 #4
0
        private Rect centerDrawing()
        {
            removeGate();
            Rect bounds;

            if (gateChooser.SelectedItem == defaultChoice || (string)((ComboBoxItem)gateChooser.SelectedItem).Content == freehandString)
            {
                gate = null;
                return(new Rect());
            }

            gate = LogicDomain.getType((string)((ComboBoxItem)(gateChooser.SelectedItem)).Content);

            // Bounds are currently arbitrary, place shape template in the middle of canvas
            if (gate != LogicDomain.NOTBUBBLE)
            {
                bounds = new Rect(inkCanvas.Width / 2 - GATE_WIDTH / 2, inkCanvas.Height / 2 - GATE_HEIGHT / 2, GATE_WIDTH, GATE_HEIGHT);
            }
            else
            {
                bounds = new Rect(inkCanvas.Width / 2 - NOTBUBBLE_DIAMETER / 2, inkCanvas.Height / 2 - NOTBUBBLE_DIAMETER / 2, NOTBUBBLE_DIAMETER, NOTBUBBLE_DIAMETER);
            }


            // This is so NANDs look like ANDs with NOTBUBBLEs
            // Same goes for all gates in the OR family
            if (gate == LogicDomain.AND)
            {
                bounds.Width = bounds.Width - bounds.Width / 4;
            }
            else if (gate == LogicDomain.OR)
            {
                bounds.Width = bounds.Width - bounds.Width / 6 - bounds.Width / 4;
            }
            else if (gate == LogicDomain.NOR)
            {
                bounds.Width = bounds.Width - bounds.Width / 6;
            }
            else if (gate == LogicDomain.XOR)
            {
                bounds.Width = bounds.Width - bounds.Width / 4;
            }

            DrawingImage drawingImage = new DrawingImage(gateDrawer.DrawGate(gate, bounds, false, true));

            gateImage        = new Image();
            gateImage.Source = drawingImage;

            InkCanvas.SetLeft(gateImage, bounds.Left);
            InkCanvas.SetTop(gateImage, bounds.Top);

            inkCanvas.Children.Add(gateImage);
            return(bounds);
        }
コード例 #5
0
 /// <summary>
 /// Returns a pair of the minimum (first) and maximum (second) number of outputs that this shape can have.
 /// </summary>
 /// <param name="shape"></param>
 /// <returns></returns>
 public IntRange NumberOutputs(ShapeType shape)
 {
     if (shape == LogicDomain.SUBCIRCUIT)
     {
         return(new IntRange(1, int.MaxValue)); // we check validity in checkSubcircuits()
     }
     else if (LogicDomain.IsGate(shape))
     {
         return(new IntRange(1, 1));
     }
     return(new IntRange(1, int.MaxValue));
 }
コード例 #6
0
        /// <summary>
        /// Compute the probability that a given set of substrokes has the given type.
        /// </summary>
        /// <param name="substrokes"></param>
        /// <param name="type"></param>
        /// <param name="featureSketch"></param>
        /// <returns>a pair containing the recognition probability and the orientation</returns>
        private RecognitionResult computeRecognitionProbabilityForTextOrWire(SubstrokeCollection substrokes, ShapeType type, FeatureSketch featureSketch)
        {
            double probability = 0;
            double orientation = 0;

            PhantomShape shape = new PhantomShape();

            shape.AddSubstrokes(substrokes);

            if (LogicDomain.IsWire(type))
            {
                // the probability it is a wire is defined as
                // (# substrokes classified as wires) / (total # substrokes)

                int numSubstrokes     = substrokes.Count;
                int numWireSubstrokes = 0;

                foreach (Substroke substroke in substrokes)
                {
                    if (_classifications[substroke] == LogicDomain.WIRE_CLASS)
                    {
                        numWireSubstrokes++;
                    }
                }

                probability = (double)numWireSubstrokes / numSubstrokes;
                return(new RecognitionResult(LogicDomain.WIRE, probability, orientation));
            }
            else if (LogicDomain.IsText(type))
            {
                // the probability it is text is defined as
                // (# substrokes classified as text) / (total # substrokes)

                int numSubstrokes     = substrokes.Count;
                int numTextSubstrokes = 0;

                foreach (Substroke substroke in substrokes)
                {
                    if (_classifications[substroke] == LogicDomain.TEXT_CLASS)
                    {
                        numTextSubstrokes++;
                    }
                }

                probability = (double)numTextSubstrokes / numSubstrokes;
                return(new TextRecognitionResult(probability, _textRecognizer.read(shape)));
            }

            return(null);
        }
コード例 #7
0
        /// <summary>
        /// Convert a sketch from
        /// </summary>
        /// <param name="originalSketch"></param>
        public void translateSketch(ref Sketch.Sketch originalSketch)
        {
            foreach (Shape shape in originalSketch.Shapes)
            {
                ShapeType type = shape.Type;

                if (labelMap.ContainsKey(type.Name)) // Convert it if it's in our map
                {
                    shape.Type = LogicDomain.getType(labelMap[type.Name]);
                }
                else if (this.verbose)
                {
                    System.Console.Error.WriteLine("Type {0} not specified in label map", type);
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Creates new EndpointPainters whenever
        /// a circuit is created
        /// </summary>
        public void UpdateEndpoints()
        {
            if (!subscribed)
            {
                return;
            }
            // Reinit

            // Highlight endpoints
            foreach (Shape shape in sketchPanel.InkSketch.Sketch.Shapes)
            {
                if (LogicDomain.IsWire(shape.Type))
                {
                    highlightEndpoints(shape);
                }
            }
        }
コード例 #9
0
        /// <summary>
        /// Constructor
        /// </summary>
        public RemoveLabelCmd(SketchPanel sketch, StrokeCollection inkStrokes, string label)
        {
            isUndoable = true;

            sketchPanel     = sketch;
            this.inkStrokes = inkStrokes;
            this.label      = Domain.LogicDomain.getType(label);

            labelColor = LogicDomain.getType(label).Color;

            labeledStrokes = new StrokeCollection();
            foreach (Stroke stroke in inkStrokes)
            {
                if (stroke.DrawingAttributes.Color == labelColor)
                {
                    labeledStrokes.Add(stroke);
                }
            }
        }
コード例 #10
0
        /// <summary>
        /// Loads the given domain file.
        /// <seealso cref="Labeler.MainForm.LoadDomain"/>
        /// </summary>
        /// <param name="domainFilePath">the file path to load</param>
        /// <returns>the DomainInfo loaded</returns>
        public static DomainInfo LoadDomainInfo(string domainFilePath)
        {
            // Check to see if there is a domain file to load for this feedback mechanism
            if (domainFilePath == null)
            {
                return(null);
            }

            // Make sure file exists
            if (!System.IO.File.Exists(domainFilePath))
            {
                return(null);
            }

            // Load domain file
            System.IO.StreamReader sr = new System.IO.StreamReader(domainFilePath);

            DomainInfo domain = new DomainInfo();
            string     line   = sr.ReadLine();

            string[] words = line.Split(null);

            // The first two lines are useless
            line = sr.ReadLine();
            line = sr.ReadLine();

            // Then the rest are labels
            while (line != null && line != "")
            {
                words = line.Split(null);

                string label = words[0];
                string color = words[1];

                domain.AddLabel(LogicDomain.getType(label), (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(color));
                line = sr.ReadLine();
            }

            sr.Close();

            return(domain);
        }
コード例 #11
0
        /// <summary>
        /// Runs the tests!
        /// </summary>
        /// <param name="sketch"></param>
        /// <param name="filename"></param>
        public override void run(Sketch.Sketch sketch, string filename)
        {
            // store the first filename as a way to tell what user we're working on.
            if (_filename == null)
            {
                _filename = filename;
            }

            Dictionary <ShapeType, MutablePair <int, int> > sketchResults = new Dictionary <ShapeType, MutablePair <int, int> >();

            foreach (ShapeType type in LogicDomain.Gates)
            {
                sketchResults.Add(type, MutablePair.Create(0, 0));
            }

            Sketch.Sketch handLabeled = sketch.Clone();

            _pipeline.process(sketch);

            foreach (Sketch.Shape correctShape in handLabeled.Shapes)
            {
                if (!LogicDomain.IsGate(correctShape.Type))
                {
                    continue;
                }

                Sketch.Shape resultShape = sketch.ShapesL.Find(delegate(Sketch.Shape s) { return(s.GeometricEquals(correctShape)); });

                if (resultShape == null)
                {
                    throw new Exception("Could not find shape.");
                }

                sketchResults[correctShape.Type].Item1++;
                if (resultShape.Type == correctShape.Type)
                {
                    sketchResults[correctShape.Type].Item2++;
                }
            }

            _results.Add(sketchResults);
        }
コード例 #12
0
        /// <summary>
        /// Highlights the endpoints of a single Wire by
        /// creating EndPointPainters for all endpoints.
        ///
        /// Main function for endpoint highlighting.
        ///
        /// Wire must have "AlreadyLabeled" set to true.
        /// </summary>
        /// <param name="wire">The Wire to highlight</param>
        /// <param name="g">The graphics handle to use while creating painters</param>
        private void highlightEndpoints(Shape wire)
        {
            // If this hasn't been recognized or isn't a wire, don not highlight.
            if (!wire.AlreadyLabeled || !LogicDomain.IsWire(wire.Type))
            {
                return;
            }

            List <int>      newEppIds = new List <int>();
            EndPointPainter epp;
            int             eppId;

            foreach (Sketch.EndPoint endpoint in wire.Endpoints)
            {
                epp    = createEndpointPainter(endpoint);
                eppId  = endPointPainterMap.Keys.Count + 1;
                epp.Id = eppId;
                newEppIds.Add(eppId);
                endPointPainterMap.Add(eppId, epp);
            }

            // Update stroke map to point to endpoint painters
            foreach (Sketch.Substroke substroke in wire.Substrokes)
            {
                String iStrokeId = sketchPanel.InkSketch.GetInkStrokeIdBySubstrokeId(substroke.XmlAttrs.Id);
                System.Windows.Ink.Stroke iStroke = sketchPanel.InkSketch.GetInkStrokeById(iStrokeId);

                if (iStrokeId2EndPtPainterId.ContainsKey(iStroke))
                {
                    throw new ApplicationException("Error: encountered one stroke " +
                                                   "that is part of two or more unique meshes");
                }

                if (iStrokeId != null)
                {
                    iStrokeId2EndPtPainterId[iStroke] = newEppIds;
                }
            }

            PaintAllEndpoints();
        }
コード例 #13
0
        /// <summary>
        /// Connects not bubbles to gates and wires
        /// </summary>
        /// <param name="gate"></param>
        private void connectNotBubble(LogicGate bubble)
        {
            LogicGate parentGate = null;
            WireMesh  wire       = null;

            // Get the components this not bubble is connected to
            foreach (Shape connected in bubble.Shape.ConnectedShapes)
            {
                if (LogicDomain.IsGate(connected.Type) && parentGate == null)
                {
                    parentGate = _logicGates[connected];
                }
                else if (LogicDomain.IsWire(connected.Type))
                {
                    wire = _wireMeshes[connected];
                }
            }

            // If this is not connected to a gate, connect it like a normal logic gate
            if (parentGate == null)
            {
                connectWiresTo(bubble);
                return;
            }

            // Is this bubble on the output or the input?
            Sketch.EndPoint connectingEndpoint =
                parentGate.Shape.ClosestEndpointFrom(bubble.Shape);
            bool isInput = parentGate.ShouldBeInput(connectingEndpoint);

            if (isInput)
            {
                wire.ConnectDependent(bubble);
                parentGate.ConnectInput(bubble, 0);
            }
            else
            {
                wire.ConnectSource(bubble, 0);
                parentGate.ConnectOutput(bubble, 0);
            }
        }
コード例 #14
0
        /// <summary>
        /// Uses the cached result if it is available, or makes a call to the inner
        /// recognizer otherwise. This method is thread-safe provided that
        ///    1. the underlying recognizer's "recognize" method is thread-safe
        ///    2. this method will not be called concurrently on the same shape
        /// </summary>
        /// <param name="shape">the shape to recognize</param>
        /// <param name="featureSketch">the featureSketch to work on</param>
        public override void recognize(Sketch.Shape shape, Featurefy.FeatureSketch featureSketch)
        {
            int hash = shape.GetHashCode();

            // Safely determine if the value is already cached. We never remove cached
            // results, so it is safe to release the lock afterward.
            bool isCached;

            lock (_typeResults)
                isCached = _typeResults.ContainsKey(hash);

            if (isCached)
            {
                // Write the cached results to the shape. Since we can assume that
                // we don't need to lock the shape, all we need to synchronize on is
                // the dictionary when we retreive results.
                ShapeType type;
                float     prob;
                lock (_typeResults)
                {
                    type = LogicDomain.getType(_typeResults[hash]);
                    prob = _probabilityResults[hash];
                }
                shape.setRecognitionResults(type, prob);
            }
            else
            {
                // We only need a lock here when we write results to the dictionary.
                _innerRecognizer.recognize(shape, featureSketch);
                lock (_typeResults)
                {
                    _typeResults.Add(hash, shape.Type.Name);
                    _probabilityResults.Add(hash, shape.Probability);
                }
            }
        }
コード例 #15
0
        /// <summary>
        /// Recalculate the connectedShapes of every shape in a given list,
        /// and correctly update all related shapes.
        /// </summary>
        /// <param name="shapeList">the list of shapes to reconnect</param>
        /// <param name="featureSketch">the sketch the shapes belong to</param>
        public void recomputeConnectedShapes(IEnumerable <Sketch.Shape> shapeList, Sketch.Sketch sketch)
        {
            // Keep a unique list of shapes
            HashSet <Sketch.Shape> allRelevantShapes = new HashSet <Sketch.Shape>(shapeList);

            // Add connected shapes to the list that needs to change
            foreach (Sketch.Shape shape in shapeList)
            {
                foreach (Sketch.Shape connected in shape.ConnectedShapes)
                {
                    allRelevantShapes.Add(connected);
                }
            }

            // clear ALL connections first
            foreach (Sketch.Shape shape in allRelevantShapes)
            {
                shape.ClearConnections();
            }

            sketch.CheckConsistency();

            // connect every shape
            foreach (Sketch.Shape shape in allRelevantShapes)
            {
                connect(shape, sketch);
            }


            // Make sure connected wires are the same shape
            Tuple <Sketch.Shape, Sketch.Shape> pair = null;

            while ((pair = wiresToMerge(allRelevantShapes)) != null)
            {
                sketch.mergeShapes(pair.Item1, pair.Item2);
                allRelevantShapes.Remove(pair.Item2);
                sketch.connectShapes(pair.Item1, pair.Item1);;
            }

            sketch.CheckConsistency();

#if DEBUG
            foreach (Shape wire in sketch.Shapes)
            {
                if (!LogicDomain.IsWire(wire.Type))
                {
                    continue;
                }
                foreach (Shape shape in wire.ConnectedShapes)
                {
                    if (LogicDomain.IsWire(shape.Type) && shape != wire)
                    {
                        throw new Exception("Found two connected wires (" + wire + " and " + shape + ") that were not merged!");
                    }
                    bool found = false;
                    foreach (EndPoint endpoint in wire.Endpoints)
                    {
                        if (endpoint.ConnectedShape == shape)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        throw new Exception("The wire " + wire + " is connected to " + shape + " as a connected shape, but not by an endpoint!");
                    }
                }
            }
#endif
        }
コード例 #16
0
        /// <summary>
        /// Connects the given shape to the other shapes in the sketch.
        ///
        /// Postcondition:
        ///     If the shape is a wire, the following things are true:
        ///       - For every substroke in the wire, both endpoints are connected to the closest shape
        ///       - The shapes the endpoints are connected to are also in the list of connected shapes
        ///       - The shapes that the wire is  connected to also know they are connected to the wire
        ///     If the shape is a NOTBUBBLE
        ///       - It is connected to the two closest shapes??
        /// </summary>
        /// <param name="shape">The shape to check.</param>
        /// <param name="sketch">The sketch containing the shape.</param>
        public override void ConnectShape(Sketch.Shape shape, Sketch.Sketch sketch)
        {
            if (!sketch.ShapesL.Contains(shape))
            {
                throw new ArgumentException("The given shape " + shape + " is not in the given sketch!");
            }

            // Connect wires to adjacent shapes
            if (shape.Type == LogicDomain.WIRE)
            {
                foreach (Sketch.Substroke substroke in shape.Substrokes)
                {
                    // Find the shape closest to the start point of the wire
                    Shape shape2 = findClosest(true, substroke, sketch);
                    if (shape2 != null)
                    {
                        EndPoint start = substroke.Endpoints[0];
                        if (!start.IsConnected)
                        {
                            sketch.connectShapes(shape, shape2);
                            start.ConnectedShape = shape2;
                        }
                    }

                    // Find the shape closest to the end point of the wire
                    Shape shape3 = findClosest(false, substroke, sketch);
                    if (shape3 != null)
                    {
                        EndPoint end = substroke.Endpoints[1];
                        if (!end.IsConnected)
                        {
                            sketch.connectShapes(shape, shape3);
                            end.ConnectedShape = shape3;
                        }
                    }
                }
            }

            // Connect NotBubbles to its two closest shapes.
            // FIXME: This could potentially cause problems. For instance,
            // on the off chance that one of the closest shapes was a wire
            // whose connections were already figured out, this could leave
            // the wire in an inconsistent state.
            else if (shape.Type == LogicDomain.NOTBUBBLE)
            {
                List <Sketch.Shape> shapes = twoClosest(shape, sketch);

                foreach (Shape closeShape in shapes)
                {
                    if (closeShape == null)
                    {
                        continue;
                    }

                    // FIXME: For now, we're only connecting this notbubble to a wire if that wire's closest endpoint is free.
                    if (closeShape.Type == LogicDomain.WIRE)
                    {
                        EndPoint endpoint = shape.ClosestEndpointFrom(closeShape);
                        if (!endpoint.IsConnected)
                        {
                            closeShape.ConnectNearestEndpointTo(shape);
                        }
                    }
                    else
                    {
                        sketch.connectShapes(closeShape, shape);
                    }
                }
            }

#if DEBUG
            foreach (Shape wire in sketch.Shapes)
            {
                if (!LogicDomain.IsWire(wire.Type))
                {
                    continue;
                }
                foreach (Shape connected in wire.ConnectedShapes)
                {
                    bool found = false;

                    // If a wire is connected to something, then either the wire is
                    // connected by an endpoint to the other shape...
                    foreach (EndPoint endpoint in wire.Endpoints)
                    {
                        if (endpoint.ConnectedShape == connected)
                        {
                            found = true;
                            break;
                        }
                    }

                    // ...or the other shape is connected by an endpoint to the wire
                    foreach (EndPoint endpoint in connected.Endpoints)
                    {
                        if (endpoint.ConnectedShape == wire)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        throw new Exception("The wire " + wire + " is connected to " + connected +
                                            " as a connected shape, but neither has an endpoint connection to the other!");
                    }
                }
            }
#endif
        }
コード例 #17
0
        /// <summary>
        /// Determines whether or not a given shape is a circuit
        /// input, and creates and connects it accordingly.
        /// Will ignore any text that is not connected to anything.
        ///
        /// Assumptions:
        ///   * The names of wire-meshes correspond directly to
        ///     their associated shapes.
        ///   * Wire-meshes all have unique names.
        ///   * The given shape is not a label connected to two wires.
        /// </summary>
        /// <param name="shape">The shape to analyze</param>
        /// <returns>True if loading was successful, false
        /// if the given shape cannot be recognized as an input
        /// or output</returns>
        private void loadInputOrOutput(Sketch.Shape shape)
        {
            // Make sure we're actually dealing with something sensical.
            // Note: If there are no connected shapes, we don't make an input or output, it is just ignored in the circuit.
            if (shape.Type != LogicDomain.TEXT || shape.ConnectedShapes.Count == 0)
            {
                return;
            }

            // Retreive the wire connected to this label shape, while
            // also checking that the shape has the correct number and
            // kinds of connections.
            List <WireMesh> connectedWires = new List <WireMesh>();

            // Assume that we have an input until we are told otherwise.
            bool input = true;

            foreach (Sketch.Shape connectedShape in shape.ConnectedShapes)
            {
                // Is this a wire?
                if (!LogicDomain.IsWire(connectedShape.Type))
                {
                    continue;
                }

                // Get the connected wire
                WireMesh connected = _wireMeshes[connectedShape.Name];

                // Have we already seen this?
                if (connectedWires.Contains(connected))
                {
                    continue;
                }
                connectedWires.Add(connected);

                // If we're dealing with any wire that already has a source, this will not be an input
                if (connected.HasSource)
                {
                    input = false;
                }
            }

            if (input)
            {
                CircuitInput newInput = new CircuitInput(shape);
                foreach (WireMesh wire in connectedWires)
                {
                    newInput.Connect(wire);
                }
                _circuitInputs.Add(newInput.Name, newInput);
            }
            else
            {
                CircuitOutput newOutput = new CircuitOutput(shape);
                foreach (WireMesh wire in connectedWires)
                {
                    newOutput.Connect(wire);
                }
                _circuitOutputs.Add(newOutput.Name, newOutput);
            }
        }
コード例 #18
0
        /// <summary>
        /// Checks whether the sketch is valid, and returns a bool indicating this.
        /// Adds any errors it comes across to the _parseErrors list.
        ///
        /// Looks for:
        ///    * Basic consistency via sketch.CheckConsistency
        ///    * Gates connected to only wires
        ///    * Wires not connected to wires
        ///    * Text connected to at most one wire
        /// </summary>
        /// <param name="sketch">The sketch to check the validity of</param>
        /// <returns>A bool, which is true if the sketch is valid</returns>
        private bool CheckSketch(Sketch.Sketch sketch)
        {
            bool valid = true;

            // Check basic sketch consistency, will (rightly) throw an exception if it finds something wrong.
            // Eventually we should not need this, for the sketch should always pass this, but it's a useful check for now.
            sketch.CheckConsistency();

            foreach (Sketch.Shape shape in sketch.Shapes)
            {
                #region Gate Checks
                if (LogicDomain.IsGate(shape.Type))
                {
                    // Each gate should be connected to only wires
                    foreach (Sketch.Shape connected in shape.ConnectedShapes)
                    {
                        if (!LogicDomain.IsWire(connected.Type))
                        {
                            valid = false;
                            _parseErrors.Add(new ParseError("Gate " + shape.Name + " is connected to something that is not a wire, " + connected.Name + "of type " + connected.Type.Name,
                                                            "This gate is connected to something that is not a wire.  Draw wires between them or group them together.", shape));
                        }
                    }
                }
                #endregion

                #region Wire Checks
                else if (LogicDomain.IsWire(shape.Type))
                {
                    // Wires shouldn't be connected to other wires
                    foreach (Sketch.Shape connected in shape.ConnectedShapes)
                    {
                        if (shape != connected && LogicDomain.IsWire(connected.Type))
                        {
                            valid = false;
                            _parseErrors.Add(new ParseError("Wire " + shape.Name + " is connected to another wire, " + connected.Name,
                                                            "This wire is connected to another wire.  Try grouping these wires together.", shape));
                        }
                    }
                }
                #endregion

                #region Input/Output Checks
                else if (LogicDomain.IsText(shape.Type))
                {
                    // Text should only be connected to wires, if anything.
                    foreach (Sketch.Shape wire in shape.ConnectedShapes)
                    {
                        if (!LogicDomain.IsWire(wire.Type))
                        {
                            valid = false;
                            _parseErrors.Add(new ParseError("Text " + shape.Name + " should only be connected to a wire, but is connected to a " + wire.Type.Name + ".",
                                                            shape.Name + " should only be connected to a wire, but is connected to a " + wire.Type.Name + ".", shape));
                        }
                    }
                }
                #endregion
            }

            return(valid);
        }
コード例 #19
0
        /// <summary>
        /// Essentially re-trains the classifier using the stored instances
        /// </summary>
        public void UpdateClassifier()
        {
            // List of each class - go through all examples once to get complete list of classes
            List <ShapeType> classes = new List <ShapeType>();

            foreach (KeyValuePair <string, Dictionary <string, object> > example in _examples)
            {
                if (!classes.Contains(LogicDomain.getType(example.Key)))
                {
                    classes.Add(LogicDomain.getType(example.Key));
                }
            }


            #region Initialize Probability stuff
            //////////////////////////////////////////////////
            //////////////////////////////////////////////////
            // 4 Pieces of information needed to calculate all
            // feature likelyhoods given class

            // needed for priors and feature value likelyhood
            int numExamples = _examples.Count;
            if (numExamples == 0)
            {
                return;
            }

            // Prior probabilities of a class
            // Initialize them all to have 0.0 prior probability
            Dictionary <ShapeType, double> Priors = new Dictionary <ShapeType, double>();
            foreach (ShapeType cls in classes)
            {
                Priors.Add(cls, 0.0);
            }

            // Likelyhood of a feature value
            // Initialize all top level dictionary entries
            Dictionary <string, Dictionary <object, double> > FeatureValue_Likelyhood =
                new Dictionary <string, Dictionary <object, double> >();
            foreach (string feature in _featureNames)
            {
                FeatureValue_Likelyhood.Add(feature, new Dictionary <object, double>());
            }

            // Likelyhood of a class given a feature value
            // Initialize all top and 2nd level dictionary entries
            Dictionary <string, Dictionary <object, Dictionary <ShapeType, double> > > Class_Given_FeatureValue_Likelyhood =
                new Dictionary <string, Dictionary <object, Dictionary <ShapeType, double> > >();
            foreach (string feature in _featureNames)
            {
                Class_Given_FeatureValue_Likelyhood.Add(feature, new Dictionary <object, Dictionary <ShapeType, double> >());
            }
            //////////////////////////////////////////////////
            //////////////////////////////////////////////////
            #endregion


            #region Initialize Counting Stuff
            //////////////////////////////////////////////////
            //////////////////////////////////////////////////
            // Counts necessary to calculate likelyhoods

            // How many occurances there are of each class - for prior probabilities
            // Initialize all the class counts to 0
            Dictionary <string, int> Count_Class = new Dictionary <string, int>();
            foreach (ShapeType cls in classes)
            {
                Count_Class.Add(cls.Name, 0);
            }

            // For FeatureValueLikelyhood
            //   - Count of the number of times Feature_i = f
            // Initialize all top level dictionary entries
            Dictionary <string, Dictionary <object, int> > Count_Feature_Eq_f =
                new Dictionary <string, Dictionary <object, int> >(_featureNames.Count);
            foreach (string feature in _featureNames)
            {
                Count_Feature_Eq_f.Add(feature, new Dictionary <object, int>());
            }

            // Given a class, how many times was this value observed
            // For ClassGivenFeatureLikelyhood
            //   - Count of the number of times Class_j = c AND Feature_i = f
            // Initialize all top and 2nd level dictionary entries
            // First dictionary = feature name to 2nd dictionary
            // Second dictionary = feature value to 3rd dictionary
            // Third dictionary = class name to occurance count
            Dictionary <string, Dictionary <object, Dictionary <string, int> > > Count_Class_Eq_c_given_Feature_Eq_f =
                new Dictionary <string, Dictionary <object, Dictionary <string, int> > >();
            foreach (string feature in _featureNames)
            {
                Count_Class_Eq_c_given_Feature_Eq_f.Add(feature, new Dictionary <object, Dictionary <string, int> >());
            }
            //////////////////////////////////////////////////
            //////////////////////////////////////////////////
            #endregion


            #region Go through every single example and count feature occurances and class occurances
            foreach (KeyValuePair <string, Dictionary <string, object> > example in _examples)
            {
                string className = example.Key;
                Count_Class[className]++;

                Dictionary <string, object> features = example.Value;

                // Count the number of occurances of each feature value.
                foreach (string fName in _featureNames)
                {
                    // feature value
                    object value;

                    if (features.TryGetValue(fName, out value))
                    {
                        // count of instances of this value across all classes
                        Dictionary <object, int> count;
                        if (Count_Feature_Eq_f.TryGetValue(fName, out count))
                        {
                            if (count.ContainsKey(value))
                            {
                                count[value]++;
                            }
                            else
                            {
                                count.Add(value, 1);
                            }
                        }

                        // count of instances of this value in this class ONLY
                        Dictionary <string, int> countPerClass;
                        if (Count_Class_Eq_c_given_Feature_Eq_f[fName].TryGetValue(value, out countPerClass))
                        {
                            if (countPerClass.ContainsKey(className))
                            {
                                countPerClass[className]++;
                            }
                            else
                            {
                                countPerClass.Add(className, 1);
                            }
                        }
                        else
                        {
                            Dictionary <string, int> clsCount = new Dictionary <string, int>();
                            clsCount.Add(className, 1);
                            Count_Class_Eq_c_given_Feature_Eq_f[fName].Add(value, clsCount);
                        }
                    }
                }
            }
            #endregion


            #region Calculate all the probabilities

            // Get the prior probabilities for each class
            foreach (ShapeType cls in classes)
            {
                int count;
                if (Count_Class.TryGetValue(cls.Name, out count))
                {
                    double prior = (double)count / numExamples;
                    Priors[cls] = prior;
                }
            }

            // Likelyhood for feature value throughout all classes
            foreach (string fName in _featureNames)
            {
                Dictionary <object, int> count_for_Feature_i;
                if (Count_Feature_Eq_f.TryGetValue(fName, out count_for_Feature_i))
                {
                    foreach (KeyValuePair <object, int> pair in count_for_Feature_i)
                    {
                        double p_F = (double)pair.Value / numExamples;
                        p_F = Math.Min(Math.Max(p_F, MIN_PROBABILITY), 1.0 - MIN_PROBABILITY);
                        if (FeatureValue_Likelyhood[fName].ContainsKey(pair.Key))
                        {
                            FeatureValue_Likelyhood[fName][pair.Key] = p_F;
                        }
                        else
                        {
                            FeatureValue_Likelyhood[fName].Add(pair.Key, p_F);
                        }
                    }
                }
            }

            // Likelyhood for feature value per class
            foreach (string fName in _featureNames)
            {
                foreach (KeyValuePair <object, Dictionary <string, int> > pair in Count_Class_Eq_c_given_Feature_Eq_f[fName])
                {
                    object value = pair.Key;
                    Class_Given_FeatureValue_Likelyhood[fName].Add(value, new Dictionary <ShapeType, double>());
                    double p_F = FeatureValue_Likelyhood[fName][value];


                    int sum = 0;
                    foreach (KeyValuePair <string, int> clsCount in pair.Value)
                    {
                        sum += clsCount.Value;
                    }

                    foreach (ShapeType cls in classes)
                    {
                        if (pair.Value.ContainsKey(cls.Name))
                        {
                            double p_C         = Priors[cls];
                            double v           = (double)pair.Value[cls.Name] / sum;
                            double p_C_given_F = Math.Min(Math.Max(v, MIN_PROBABILITY), 1.0 - MIN_PROBABILITY);
                            double p_F_given_C = p_C_given_F * p_F / p_C;
                            Class_Given_FeatureValue_Likelyhood[fName][value].Add(cls, p_F_given_C);
                        }
                        else
                        {
                            Class_Given_FeatureValue_Likelyhood[fName][value].Add(cls, MIN_PROBABILITY);
                        }
                    }
                }
            }


            #endregion

            // Sort the dictionaries...for fun and ease of reading when debugging
            Dictionary <string, Dictionary <object, double> > fvl = new Dictionary <string, Dictionary <object, double> >();
            foreach (KeyValuePair <string, Dictionary <object, double> > pair in FeatureValue_Likelyhood)
            {
                List <object> v_keys = new List <object>(pair.Value.Keys);
                v_keys.Sort();
                Dictionary <object, double> v = new Dictionary <object, double>();
                foreach (object value in v_keys)
                {
                    v.Add(value, pair.Value[value]);
                }

                fvl.Add(pair.Key, v);
            }

            List <ShapeType> p_keys = new List <ShapeType>(Priors.Keys);
            p_keys.Sort();
            Dictionary <ShapeType, double> p = new Dictionary <ShapeType, double>();
            foreach (ShapeType key in p_keys)
            {
                p.Add(key, Priors[key]);
            }


            Dictionary <string, Dictionary <object, Dictionary <ShapeType, double> > > cgfvl = new Dictionary <string, Dictionary <object, Dictionary <ShapeType, double> > >();
            foreach (KeyValuePair <string, Dictionary <object, Dictionary <ShapeType, double> > > pair in Class_Given_FeatureValue_Likelyhood)
            {
                List <object> v_keys = new List <object>(pair.Value.Keys);
                v_keys.Sort();
                Dictionary <object, Dictionary <ShapeType, double> > v = new Dictionary <object, Dictionary <ShapeType, double> >();
                foreach (object value in v_keys)
                {
                    v.Add(value, pair.Value[value]);
                }

                cgfvl.Add(pair.Key, v);
            }


            // Update the Classifier
            _classifier = new NaiveBayes(classes, _featureNames, p, fvl, cgfvl);
        }
コード例 #20
0
 public Color GetColor(string label)
 {
     return(GetColor(LogicDomain.getType(label)));
 }
コード例 #21
0
        /// <summary>
        /// Compute the energy function that we are trying to maximize.
        /// </summary>
        /// <param name="sketch"></param>
        /// <returns>an unbounded double representing the energy of the sketch</returns>
        private double computeEnergy(FeatureSketch featureSketch)
        {
            Sketch.Sketch sketch = featureSketch.Sketch;
            featureSketch.hasConsistentSubstrokes();
            sketch.CheckConsistency();
            double energy    = 0;
            var    shapes    = sketch.ShapesL;
            int    numShapes = shapes.Count;
            int    numGates  = shapes.FindAll(s => LogicDomain.IsGate(s.Type)).Count;

            foreach (Shape shape in shapes)
            {
                // Add energy for every connection
#if false
                // This is a bad idea. It favors interpretations with more connections, which basically means
                // that everything should alternate wire-text-wire-text-wire-...
                foreach (Shape connected in shape.ConnectedShapes)
                {
                    if (connected == shape)
                    {
                        continue;
                    }
                    if (connected.Type != LogicDomain.WIRE)
                    {
                        continue;
                    }
                    double connectionDistance = double.PositiveInfinity;
                    foreach (EndPoint endpoint in connected.Endpoints)
                    {
                        connectionDistance = Math.Min(shape.minDistanceTo(endpoint.X, endpoint.Y), connectionDistance);
                    }
                    connectionDistance = Math.Max(connectionDistance, 0.001); // avoid problems when connection distance is close to zero
                    energy            += 1 + 1 / connectionDistance;
                }
#endif

                // Add the context match score
                energy += (double)_domain.ClosestContext(shape).Item1 / numShapes;

                // Get recognition results
                RecognitionResult result     = RecognizeAsType(shape, shape.Type, featureSketch);
                double            confidence = result.Confidence;

                // Add the recognition score
                energy += confidence / numShapes;

#if false
                // Gate orientation also contributes
                if (LogicDomain.IsGate(shape.Type))
                {
                    // Determine the recognizer's and the connector's orientation values,
                    // in the range [0, 2Pi]
                    double orientation      = result.Orientation;
                    double otherOrientation = _domain.OrientShape(shape, sketch);

                    // Orientation might be off by PI...
                    double dist1 = Math.Abs(otherOrientation - orientation);
                    double dist2 = Math.Abs(otherOrientation - Math.PI - orientation);
                    double dist  = Math.Min(dist1, dist2);

                    // Add orientation score
                    double twoPI = 2 * Math.PI;
                    energy += (1 - (dist / twoPI)) / numGates;
                }
#endif
            }
            return(energy);
        }