/// <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); } } }
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); }
/// <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); } } }
/// <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); } } }
/// <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); }
/// <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); } } }
/// <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); }
public Color GetColor(string label) { return(GetColor(LogicDomain.getType(label))); }