/// <summary> /// Returns an instance of the default SimilarityMeasure for /// the provided attribute. This method does not check the /// cache because the cache contains the currently associated /// Similarity Measure, which is not neccessairly the default. /// </summary> /// <param name="attributeName">The name of the targetAttribute</param> /// <returns>the default ISimilarityMeasure that should be used for the provided attribute</returns> public ISimilarityMeasure GetDefaultSimilarityMeasure(string attributeName) { // Validate parameter if (string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("AttributeName", "No valid attribute name was provided"); } ISimilarityMeasure defaultMeasure = null; // Attempt to get the default similairy measure using the assigned // preffered similarity measure defaultMeasure = GetPrefferedSimilarityMeasure(attributeName); // If we have a good measure, we can return it if (defaultMeasure != null) { return(defaultMeasure); } // No preffered similarity measure is set so we will determine // the default by analyzing the type of data stored in the attribute string firstValue = GlobalAttributeCollection.GetInstance(this.scope).GetAttributeValues(attributeName).FirstOrDefault(); string secondValue = GlobalAttributeCollection.GetInstance(this.scope).GetAttributeValues(attributeName).LastOrDefault(); if (string.IsNullOrEmpty(firstValue) || string.IsNullOrEmpty(secondValue)) { return(GetSimilarityMeasureInstance(typeof(LevenshteinDistanceStringSimilarityMeasure).FullName)); } // Determine the default by analyzing data stored in the specified // attribute defaultMeasure = DetermineSimilarityMeasure(attributeName, firstValue, secondValue); return(defaultMeasure); }
/// <summary> /// Returns a list of tuples that contain the calculated distances /// and the frequency of those distances /// </summary> /// <param name="attributeName">The name of the attribute that /// distances are being calculated for</param> /// <param name="measure">The similarity measure to be used</param> /// <returns>a collection of distances and the number of times /// that those distances occur</returns> private List <Tuple <double, int> > CalculateDistances(string attributeName, ISimilarityMeasure measure) { if (!GlobalAttributeCollection.GetInstance(this.scope).ContainsAttribute(attributeName)) { return(null); } List <Tuple <double, int> > distances = new List <Tuple <double, int> >(); double frequencyTotal = 0; int nodeCount = 0; // Get the values for the attribute List <string> attributeValues = new List <string>(GlobalAttributeCollection.GetInstance(this.scope).GetAttributeValues(attributeName)); // Loop over all the attribute values for (int i = 0; i <= attributeValues.Count - 1; i++) { // Get the frequency at which the source attribute value occurrs int sourceFrequency = GlobalAttributeCollection.GetInstance(this.scope).GetFrequency(attributeName, attributeValues[i]); nodeCount += sourceFrequency; // Compare the current attribute value to all other // attribute values for (int j = 0; j < i; j++) { // Compute the distance for the two values double?distance = measure.CalculateDistance(attributeValues[i], attributeValues[j]); if (distance != null) { // Get the frequency at which the target attribute value occurrs int targetFrequency = GlobalAttributeCollection.GetInstance(this.scope).GetFrequency(attributeName, attributeValues[j]); distances.Add(Tuple.Create <double, int>(distance.Value, sourceFrequency * targetFrequency)); // Keep a running total of the frequencies frequencyTotal += sourceFrequency * targetFrequency; } } } // Since we only loop over unique attribute values we never make // the comparisons against nodes where the values would be the // same. We need to determine if this case has occurred and insert // the appropriate number of zero distance items. // Use binomial function to determine the number of possible combinations //double combinations = (MathUtils.LogFactorial(nodeCount) / (2 * (MathUtils.LogFactorial(nodeCount - 2)))); double combinations = Math.Exp(MathUtils.LogFactorial(nodeCount) - MathUtils.LogFactorial(2) - MathUtils.LogFactorial(nodeCount - 2)); // Add in all the zero distance items that we need for (int i = 1; i <= combinations - frequencyTotal; i++) { distances.Add(Tuple.Create <double, int>(0, 1)); } //foreach (Tuple<double, int> distanceCount in distances) //{ // System.Diagnostics.Debug.WriteLine("[{0},{1}]", distanceCount.Item1, distanceCount.Item2); //} return(distances); }
/// <summary> /// Adds the specificed node /// </summary> /// <param name="graphComponents">The Graph that data is being imported into</param> /// <param name="creationType">The specified CreationType</param> /// <param name="objNode">Node to be added</param> public static void AddNode(GraphComponents graphComponents, CreationType creationType, NodeMapData objNode) { // Create new node Node uiNode = new Node(objNode.Id); uiNode.SourceMechanism = creationType; // TODO as NodeMapData types expands, this needs to be adjusted NodeTypes uiNodeType = NodeTypes.Simple; if (objNode is IconNodeMapData) { uiNodeType = NodeTypes.Icon; } else if (objNode is TextNodeMapData) { uiNodeType = NodeTypes.Text; } NodeViewModelBase uiNodeVM = NodeViewModelBase.GetNodeViewModel(uiNodeType, uiNode, graphComponents.Scope); // Properties if (uiNodeType == NodeTypes.Icon) { IconNodeMapData objIconNode = (IconNodeMapData)objNode; if (objIconNode.ImageSource != null) { ((IconNodeViewModel)uiNodeVM).ImageSource = objIconNode.ImageSource.ToString(); } } uiNodeVM.Description = objNode.Description; uiNodeVM.DisplayValue = objNode.Label; uiNodeVM.Width = objNode.Dimension.Width; uiNodeVM.Height = objNode.Dimension.Height; uiNodeVM.Position = objNode.Position; uiNodeVM.IsHidden = objNode.IsHidden; SolidColorBrush uiBackgroundColorBrush = new SolidColorBrush(objNode.BackgroundColor); uiNodeVM.BackgroundColor = uiBackgroundColorBrush; SolidColorBrush uiSelectionColorBrush = new SolidColorBrush(objNode.SelectionColor); uiNodeVM.SelectionColor = uiSelectionColorBrush; if (uiNodeVM.Height == 0) { uiNodeVM.Height = 45; } if (uiNodeVM.Width == 0) { uiNodeVM.Width = 45; } // Add the node to the graph graphComponents.AddNodeViewModel(uiNodeVM); // Attributes foreach (KeyValuePair <string, AttributeMapData> objNodeAttrKVP in objNode.Attributes) { Attributes.Attribute uiNodeAttribute = new Attributes.Attribute(objNodeAttrKVP.Value.Name); AttributeValue uiNodeAttributeValue = new AttributeValue(objNodeAttrKVP.Value.Value); uiNode.Attributes.Add(uiNodeAttribute.Name, uiNodeAttributeValue); GlobalAttributeCollection.GetInstance(graphComponents.Scope).Add(uiNodeAttribute, uiNodeAttributeValue); uiNodeAttribute.SemanticType = objNodeAttrKVP.Value.SemanticType; uiNodeAttribute.PreferredSimilarityMeasure = objNodeAttrKVP.Value.SimilarityMeasure; uiNodeAttribute.Visible = !objNodeAttrKVP.Value.IsHidden; } }
/// <summary> /// Imports GraphML into SnagL on a new graph /// </summary> /// <param name="data">The graph data to place on the graph</param> /// <param name="scope">Specifies the graphs scope</param> /// <param name="format">Specifies the graph data format</param> public void ImportData(string data, string scope, GraphDataFormatBase format) { SnaglEventAggregator.DefaultInstance.GetEvent <UI.TimeConsumingTaskExecutingEvent>().Publish(new UI.TimeConsumingTaskEventArgs()); GraphComponents components = null; // Check if the provided scope is null or empty if (string.IsNullOrEmpty(scope)) { // This is a new graph so we will generate new GraphComponents // for it components = new GraphComponents(); } else { // Attempt to get the graph components instance for // the given scope components = GetGraphComponents(scope); // If we were unable to get an instance, create a // new one if (components == null) { components = new GraphComponents(); } } components.Clear(); GlobalAttributeCollection.GetInstance(scope).Clear(); // Import the data into the provided components format.Import(data, components, CreationType.Imported); // Check if the default instance (which is the first instance // created) has been initialized yet if (this.defaultComponentInstanceScope == string.Empty) { // TODO: ENSURE THIS IS VALID IN THE FUTURE AS THE MAIN GRAPH MAY NOT ALWAYS POPULATE FIRST (BUT SHOULD BE) // Save the newly created components as the default this.defaultComponentInstanceScope = components.Scope; } // Now we need to update or add the components to the collection of components // Check if the collection has never been initialized if (this.graphComponentsInstances == null) { // Initialize the collection this.graphComponentsInstances = new Dictionary <string, GraphComponents>(); } // Check if we have no items if (this.graphComponentsInstances.Count == 0) { // Add the components instance to the collection this.graphComponentsInstances.Add(components.Scope, components); } else { // Ensure that the scope doesn't already exist if (this.graphComponentsInstances.ContainsKey(components.Scope)) { // Update the components instance for the specified scope this.graphComponentsInstances[components.Scope] = components; } else { // Add the new instance for the specified scope this.graphComponentsInstances.Add(components.Scope, components); } } //TODO MAKE SURE THAT WE HAVE DATA // Fire the DataLoaded event DispatcherHelper.UIDispatcher.BeginInvoke(() => SnaglEventAggregator.DefaultInstance.GetEvent <DataLoadedEvent>().Publish(new DataLoadedEventArgs(components.Scope, CreationType.Imported)) ); SnaglEventAggregator.DefaultInstance.GetEvent <TimeConsumingTaskCompletedEvent>().Publish(new TimeConsumingTaskEventArgs()); }