- 
                Notifications
    You must be signed in to change notification settings 
- Fork 15
Configuring objects comparison (ComparisonConfig)
As seen in the Diffing and the Hash wiki pages, the real power of object comparison is given by the options that you have when performing it. For this reason, we expose options to customise these operations via the ComparisonConfig object.
Here is an example of the ComparisonConfig object seen from Grasshopper:

There are also "Toolkit-specific" ComparisonConfig objects that extend the available options when dealing with certain objects, for example Revit's RevitComparisonConfig gives further options when dealing with Revit objects. More details on it in its dedicated page.
The "default"
comparisonConfigobject inherits from theBaseComparisonConfigabstract class, which defines all the "basic" options. This abstract class can be extended by the "Toolkit-specific"comparisonConfigs, so you can include additional options to deal with certain objects in your Toolkit, of whichRevitComparisonConfigis an example.
If you implement your own Toolkit-specificcomparisonConfigobject, you will need to implement the functions that deal with it too, which are a toolkit-specificDiffing()method (example in Revit), a toolkit-specificHashString()method (example in Revit), and any number ofComparisonInclusion()methods that you might need (example in Revit). More details can be found in the diffing guide for developers.
Let's see the ComparisonConfig options in detail.
Many of the following examples use the Bar class as a reference object.
- PropertyExceptions
- PropertiesToConsider
- CustomDataKeysExceptions
- CustomDataKeysToConsider
- TypeExceptions
- NamespaceExceptions
- MaxNesting
- MaxPropertyDifferences
- NumericTolerance
- PropertyNumericTolerance
- SignificantFigures
- PropertySignificantFigures
You can specify one or more names of properties that you want to ignore (not consider, take as exceptions) when comparing objects.
This allows to ignore properties and also sub-properties (i.e., properties of properties) of any object.
This also supports * wildcard within property names, so you can match multiple properties.
You can specify either the simple name of the property (e.g. StartNode), or the FullName of the property (e.g. BH.oM.Structure.Elements.Bar.StartNode) if you want to be more precise and avoid confusion in case you have properties/sub-properties with the same name.
To clarify the above, here are examples using the Bar class as a reference:
- Specifying the property name StartNodewould ignore theStartNodeproperty. It follows that any sub-property ofStartNodewill also be ignored.
- Specifying the property Full Name BH.oM.Structure.Element.Bar.StartNodewould achieve the same result, but it is safer than using only the simple nameStartNode(and may as well save computation time, like in the case of PropertiesToConsider when Hashing).
To explain why using the property Full Name is safer, consider the example where you are Diffing a mix of objects which include both Bars and also GraphLinks, both of which own a StartNode property. If you input StartNode in the PropertyExceptions, you must be aware that both properties BH.oM.Structure.Elements.Bar.StartNode and BH.oM.Data.Collections.GraphLink.StartNode will be treated as exceptions, hence ignored. Specifying the property full name is safer.
- Specifying StartNode.Position, would ignore any change in thePositionproperty of the start Node, but all the other properties ofStartNodewould still be considered.
- Specifying StartNode.Position.X, would ignore any change in theXproperty of the start Node's Position property, but all the other properties ofStartNode.Positionwould still be considered.
- Again, you can specify the Full Name even for sub-properties, like BH.oM.Structure.Elements.Bar.StartNode.Position.X, and as seen above, this is safer.
You can specify * wildcards within property names, so you can match multiple properties with a single text.
- 
Specifying BH.oM.Structure.Elements.Bar.*.Position.Ywould match:- BH.oM.Structure.Elements.Bar.StartNode.Position.Y
- BH.oM.Structure.Elements.Bar.EndNode.Position.Y
 so if this is specified in the PropertyExceptions, those 2 properties will be ignored.
- 
Specifying BH.oM.Structure.Elements.Bar.*.Ywould match:- BH.oM.Structure.Elements.Bar.StartNode.Position.Y
- BH.oM.Structure.Elements.Bar.EndNode.Position.Y
- BH.oM.Structure.Elements.Bar.StartNode.Orientation.Y
- BH.oM.Structure.Elements.Bar.EndNode.Orientation.Y
 so if this is specified in the PropertyExceptions, those 4 properties will be ignored.
- 
Again, you can specify only the name instead of the Full Name to obtain the same result, i.e. *.Position.Ywould achieve the same result asBH.oM.Structure.Elements.Bar.*.Position.Ywhen the input objects are onlyBars, but you incur in the same risks illustrated above if your input objects are of different types (see property name VS property Full Name).
- 
You can add as many *wildcards as you wish, which is especially handy when you have input objects of different types. SpecifyingBH.oM.Structure.*.Start*.*Ywith bothBars andBarReleases input objects would match all of the following properties:- BH.oM.Structure.Elements.Bar.StartNode.Position.Y
- BH.oM.Structure.Elements.Bar.StartNode.Orientation.Y
- BH.oM.Structure.Elements.Bar.StartNode.Offset.Start.Y
- BH.oM.Structure.Constraints.BarRelease.StartRelease.TranslationalStiffnessY
- BH.oM.Structure.Constraints.BarRelease.StartRelease.RotationalStiffnessY
- BH.oM.Structure.Constraints.BarRelease.StartRelease.TranslationY
- BH.oM.Structure.Constraints.BarRelease.StartRelease.RotationY
 so if this is specified in the PropertyExceptions, and bothBars andBarReleases are in the input objects, all those 7 properties will be ignored.
 If instead you only hadBars in the input objects, theBH.oM.Structure.*.Start*.*Ywould only match the first 3 properties in the list above.
The PropertiesToConsider input allows you to add property names that should be considered in the comparison.
If you add a property name in this field, only the value held in that property will be considered.
If the property name that you specified is not found on the object, then no properties will be considered. Therefore, make sure you input property names that exist on the object.
Like for the PropertyExceptions option, you can specify the property names as just the Name (e.g. StartNode), as a Full Name (e.g. BH.oM.Structure.Elements.Bar.StartNode) and/or using wildcards (e.g. BH.oM.Structure.Elements.*.StartNode) to get different matching results. See the section on PropertyExceptions for more details on Full Names and using wildcards.
Using
PropertiesToConsidercan be a resource-intensive operation when calculating an object's Hash (Diffing instead is only slightly affected). To speed up the Hash computation:
- use only property Full Names as an input to
PropertiesToConsider;- do not use Wildcards in
PropertiesToConsider;- limit the amount of property names in
PropertiesToConsider.Technical explanation in the details below.
The Hash of an object is calculated by recursively navigating all properties of the object and taking their value. If you specify some
PropertiesToConsider, the property value is only considered if its name matches a property name in there. Then, the recursion continues, and if the current property has some sub-property, the algorithm checks the sub-property, and so on. When checking a certain property, the algorithm doesn't know the names of all its sub-properties until it gets there.If the property names include Wildcards or are not specified as Full Names, there can be situations where some nested sub-property needs to be considered, but then its parent's siblings must be ignored. When computing the
Hash(), we are traversing the property tree of the object, but we do not know all the properties during the traversal. For example, say that your input object is aBar, and you want to consider exclusively properties that match*.Name. The situation is:
One way of solving this could be to "consider" all the properties of the object while doing the Hash, and, at the end, cull away those that do not match any
PropertiesToConsider. This basically is like saying that we build our knowledge of the object while computing its Hash. However, this can be wasteful for two reasons:
- speed: many other operations may be done to the object values being considered when computing the Hash (e.g. numerical approximations);
- space: we would need to store in RAM many values that we may never use.
For this reason, we instead build the knowledge of the property tree before computing the hash; in other words, we traverse the entire object once and look at the property names, and get the "consequent" PropertiesToConsider, i.e. all the properties of the object that match your wildcard or partial property name, translated to their Full Name form. By using Full Names, it the becomes easy for the Hash algorithm to consider or not a property: just check if the property full name matches any of the
PropertiesToConsider.The cost of this can be cut by specifying Full Names instead of just the name (i.e.
BH.oM.Structure.Elements.Bar.StartNodeinstead ofStartNode) and avoiding wildcards*when usingPropertiesToConsider.
This works similarly to PropertyExceptions, but is used only for BHoMObjects CustomData dictionary keys.
Setting a key name in CustomDataKeysExceptions means that if that key is found on in the CustomData dictionary of an object, it will not be considered.
This option does not support wildcard, unlike PropertyExceptions.
Setting a key name in CustomDataKeysToConsider means that only that dictionary key will be considered amongst any BHoMObject's CustomData. If no matching CustomData key is found on the object, no CustomData entry will be considered.
This option does not support wildcard.
You can input any Type here. Any object or property of corresponding types will not be considered.
You can input the name of any namespace here. An example of a namespace is BH.oM.Structure.Elements.
Any object or property that belong to the corresponding namespace will not be considered.
This option does not support wildcard.
This option limits the depth of property discovery when computing Diffing or an object's Hash.
Properties whose Nesting Level is equal to or larger than MaxNesting will not be considered.
The nesting level of a property defines how deep we are in the object property tree.
For example:
Top-level properties are at level 1. Setting MaxNesting to 1 will make the Hash or Diffing consider only top-level properties. Setting MaxNesting to 0 will disregard any object property (only the class name will end up in the Hash, and Diffing will not find any differences).
This option is better used as a safety measure to avoid excessive computation time when diffing or computing the hash for objects that may occasionally have one or more deeply nested properties of which we do not care about.
When Diffing, this indicates the maximum number of Property Differences that will be collected and returned. This setting does not affect the Hash calculation (in fact, this option should be moved in DiffingConfig instead).
You can not control what properties are returned and what remain excluded due to this numeric limit. Hence, this option is better used as a safety measure to avoid excessive computation time when:
- we care about finding different objects, but do not care about what properties did change between them, although a better and faster option for this would be to use DiffingConfig.EnablePropertyDiffingset tofalse;
- we are okay with finding only the first n differences between objects, whatever those may be.
This option sets the Numeric tolerance applied when considering any numerical property of objects.
For example, a Bar's StartNode.Position.X property is a numerical property.
When a numerical property is encountered, the function BH.Engine.Base.RoundWithTolerance() is applied to its value, which becomes approximated with the given NumericTolerance.
Therefore, when Hashing, the property's approximate value will be recorded in the Hash. When Diffing, the property approximate value will be used for the comparison.
If both NumericTolerance and SignificantFigures are provided in the ComparisonConfig, both approximations are executed, and the largest approximation among all (the least precise number) is registered.
The function
BH.Engine.Base.RoundWithTolerance()will approximate the input value with the given tolerance, which is done by rounding (to floor) to the nearest tolerance multiplier.Some examples of
RoundWithTolerance()are:
Input number Input Tolerance Result (approximated number) 12 20 0 121 2 120 1.2345 1.1 1.1 0.014 0.01 0.01 0.014 0.02 0 
This option applies a given Numeric Tolerance to a specific property, therefore considering its value approximated using the given tolerance.
In order to use it, you have to create and input in PropertyNumericTolerance one or more NamedNumericTolerance objects, where you set:
- the Nameof the property you want to target; this supports*wildcard usage;
- the Tolerancethat you want to apply to the given property.
The approximation will work exactly as per the NumericTolerance option, only it will target exclusively the properties with the name specified via the NamedNumericTolerance objects.
If a match is found, this takes precedence over the NumericTolerance option.
If conflicting values/multiple matches are found among the ComparisonConfig's numerical precision options, the largest approximation among all (least precise number) is registered.
The Name field supports wildcard usage. Some examples:
- 
BH.oM.Geometry.Vector: applies the corresponding tolerance to all numerical properties of Vectors, i.e. X, Y, Z
- 
BH.oM.Structure.Elements.*.Position: applies the corresponding tolerance to all numerical properties of properties namedPositionunder any Structural Element, e.g.Bar.Position.X,Bar.Position.Y,Bar.Position.Zand at the same time alsoNode.Position.X,Node.Position.Y,Node.Position.Z.
This option sets the Significant Figures considered for any numerical property of objects.
For example, a Bar's StartNode.Position.X property is a numerical property.
When a numerical property is encountered, the function BH.Engine.Base.RoundToSignificantFigures() is applied to its value, which becomes approximated with the given SignificantFigures.
Therefore, when Hashing, the property's approximate value will be recorded in the Hash. When Diffing, the property approximate value will be used for the comparison.
If both SignificantFigures and NumericTolerance are provided in the ComparisonConfig, both approximations are executed, and the largest approximation among all (the least precise number) is registered.
The function
BH.Engine.Base.RoundToSignificantFigures()will approximate the input value with the given Significant Figures. Some examples:
Input number Input Significant Figures Result (approximated number) 1050.67 1 1000 1050.67 2 1100 1050.67 3 1050 1050.67 4 1051 1050.67 5 1050.7 123456.123 7 123456.1 123456.123 1 100000 0.0000000000000000000123456789 5 1.2346E-20 0.0000000000000000000123456789 99 1.23456789E-20 
This option applies the approximation with given Significant Figures to a specific property.
In order to use it, you have to create and input in PropertyNumericTolerance one or more NamedSignificantFigures objects, where you set:
- the Nameof the property you want to target; this supports*wildcard usage;
- the SignificantFiguresthat you want to consider when evaluating the given property.
The approximation will work exactly as per the SignificantFigures option, only it will target exclusively the properties with the name specified via the NamedSignificantFigures objects.
If a match is found, this takes precedence over the SignificantFigures option.
If conflicting values/multiple matches are found among the ComparisonConfig's numerical precision options, the largest approximation among all (least precise number) is registered.
The Name field supports wildcard usage. Some examples:
- 
BH.oM.Geometry.Vector: applies the corresponding tolerance to all numerical properties of Vectors, i.e. X, Y, Z
- 
BH.oM.Structure.Elements.*.Position: applies the corresponding tolerance to all numerical properties of properties namedPositionunder any Structural Element, e.g.Bar.Position.X,Bar.Position.Y,Bar.Position.Zand at the same time alsoNode.Position.X,Node.Position.Y,Node.Position.Z.
- 
Introduction to the BHoM: 
 What is the BHoM for?
 Structure of the BHoM
 Technical Philosophy of the BHoM
- 
Getting Started: 
 Installing the BHoM
 Using the BHoM
 Submitting an Issue
 Getting started for developers
- 
Use GitHub & Visual Studio: 
 Using the SCRUM Board
 Resolving an Issue
 Avoiding Conflicts
 Creating a new Repository
 Using Visual Studio
 Using Visual Studio Code
- 
Contribute: 
 The oM
 The Engine
 The Adapter
 The Toolkit
 The UI
 The Tests
- 
Guidelines: 
 Unit convention
 Geometry
 BHoM_Engine Classes
 The IImmutable Interface
 Handling Exceptional Events
 BHoM Structural Conventions
 BHoM View Quality Conventions
 Code Versioning
 Wiki Style
 Coding Style
 Null Handling
 Code Attributes
 Creating Icons
 Changelog
 Releases and Versioning
 Open Sourcing Procedure
 Dataset guidelines
- 
Foundational Interfaces: 
 IElement Required Extension Methods
- 
Continuous Integration: 
 Introduction
 Check-PR-Builds
 Check-Core
 Check-Installer
- 
Code Compliance: 
 Compliance
- 
Further Reading: 
 FAQ
 Structural Adapters
 Mongo_Toolkit
 Socket_Toolkit
