Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Diffing_Engine: clarification of concept of Hash vs Diff; leverage persistentId #2105

Merged
merged 32 commits into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
75e0698
Adding feature to check for `PersistentId`
alelom Oct 21, 2020
f44db18
Update DiffRevisions.cs
alelom Oct 27, 2020
4c5e66d
First test with IDiffing leveraging PersistentId.
alelom Oct 27, 2020
29aeee4
Merge branch 'master' into Diffing_Engine-#2095-leveragePersistentId
alelom Nov 12, 2020
5d5b351
Merge branch 'master' into Diffing_Engine-#2095-leveragePersistentId
alelom Nov 12, 2020
78d5bdb
Refactored for consistency (Hash/Diff configs); add persistentId
alelom Nov 12, 2020
1e97b39
Alignment to latest changes. Simplification.
alelom Nov 13, 2020
a7ed1f8
Align to minor changes in oM; HashComparer generic again
alelom Nov 13, 2020
235b4f8
Align to ComparisonConfig rename from DistinctConfig. Fixes
alelom Nov 16, 2020
2409049
Update SetHashFragment.cs
alelom Nov 16, 2020
df91b28
Minor renaming.
alelom Nov 16, 2020
38930f3
Moved HashComparer in Base Engine; fixing ComparisonConfig not passed
alelom Nov 16, 2020
35d0b99
Moved SetHashFragment in Base. Add `hashFromFragment` to Hash()
alelom Nov 17, 2020
008db52
File renaming: ComparisonConfig
alelom Nov 17, 2020
79bbc49
Some renamings.
alelom Nov 19, 2020
206a0a7
Removed unused reference
alelom Nov 19, 2020
a7441d6
Update UniqueEntitiesReplacementMap.cs
alelom Nov 19, 2020
a941ae3
Update UniqueEntitiesReplacementMap.cs
alelom Nov 19, 2020
c13a002
Fixing bug in Query.Hash() for PropertyNamesToConsider
alelom Nov 19, 2020
4774384
Changes on propertiesToInclude/Exceptions
alelom Nov 19, 2020
9326473
Update Hash.cs
alelom Nov 19, 2020
b8664b6
Update BHoM_Engine/Create/IObject/RandomObject.cs
alelom Nov 23, 2020
41c4ba3
Update Diffing_Engine/Compute/_IDiffing.cs
alelom Nov 23, 2020
2fd402b
Update Physical_Engine/Query/UniqueConstructions.cs
alelom Nov 23, 2020
77c93e7
suggested changes
alelom Nov 23, 2020
e5fc607
Restoring version of UniqueEntities without HashComparer
alelom Nov 26, 2020
843acf5
Update Hash for performance reasons
alelom Nov 26, 2020
5dee50e
Merge branch 'master' into Diffing_Engine-#2095-leveragePersistentId
alelom Dec 1, 2020
37616a6
Other changes required for compliance
alelom Dec 1, 2020
6a6b160
Update SetHashFragment.cs
alelom Dec 1, 2020
0932595
Update SetHashFragment.cs
alelom Dec 1, 2020
dcbcca1
Merge branch 'master' into Diffing_Engine-#2095-leveragePersistentId
alelom Dec 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Analytical_Engine/Analytical_Engine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
<Compile Include="Convert\Graph\ToDataVizObjects.cs" />
<Compile Include="Convert\Graph\ToDotFormat.cs" />
<Compile Include="Convert\Graph\ToRelation.cs" />
<Compile Include="Create\Graph\DiffConfig.cs" />
<Compile Include="Create\Graph\ComparisonConfig.cs" />
<Compile Include="Create\Graph\Graph.cs" />
alelom marked this conversation as resolved.
Show resolved Hide resolved
<Compile Include="Create\Graph\Relation.cs" />
<Compile Include="Create\IElement2D\NewInternalElement2D.cs" />
Expand All @@ -95,12 +95,12 @@
<Compile Include="Query\ExternalPolycurve.cs" />
<Compile Include="Query\Geometry.cs" />
<Compile Include="Query\Graph\Adjacency.cs" />
<Compile Include="Query\Graph\DistinctEntities.cs" />
<Compile Include="Query\Graph\EntityNeighbourhood.cs" />
alelom marked this conversation as resolved.
Show resolved Hide resolved
<Compile Include="Query\Graph\AStarShortestPath.cs" />
<Compile Include="Query\Graph\ClosestIElement0D.cs" />
<Compile Include="Query\Graph\Depth.cs" />
<Compile Include="Query\Graph\Destinations.cs" />
<Compile Include="Query\Graph\DiffEntities.cs" />
<Compile Include="Query\Graph\DijkstraShortestPath.cs" />
<Compile Include="Query\Graph\Entities.cs" />
<Compile Include="Query\Graph\Entity.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BH.oM.Diffing;
using BH.oM.Base;
alelom marked this conversation as resolved.
Show resolved Hide resolved
using BH.oM.Diffing;
using BH.oM.Reflection.Attributes;
using System;
using System.Collections.Generic;
Expand All @@ -15,23 +16,21 @@ public static partial class Create
/**** Public Methods ****/
/***************************************************/

[Description("Create a simple DiffConfig.")]
[Description("Create a simple ComparisonConfig.")]
[Input("numericTolerance", "Tolerance used to determine numerical differences." +
"\nDefaults to Tolerance.Distance (1e-6).")]
[Input("propertiesToConsider", "By default, diffing considers all the properties of the objects." +
"\nHere you can specify a list of property names. Only the properties with a name matching any of this list will be considered for diffing." +
"\nE.g., if you input 'Name' only the differences in terms of name will be returned." +
"\nNOTE: these can be only top-level properties of the object (not the sub-properties).")]
[Output("diffConfig", "DiffConfig.")]
public static DiffConfig DiffConfig(double numericTolerance = oM.Geometry.Tolerance.Distance, List<string> propertiesToConsider = null)
[Input("propertyNamesToConsider", "By default, all the properties of the objects are considered in determining uniqueness." +
"\nHere you can specify a list of property names. Only the properties with a name matching any of this list will be considered." +
"\nE.g., if you input 'Name' only the differences in terms of name will be returned.")]
public static ComparisonConfig ComparisonConfig(double numericTolerance = oM.Geometry.Tolerance.Distance, List<string> propertyNamesToConsider = null)
{
DiffConfig diffConfig = new DiffConfig()
ComparisonConfig cc = new ComparisonConfig()
{
NumericTolerance = numericTolerance,
PropertiesToConsider = propertiesToConsider ?? new List<string>(),
PropertyNamesToConsider = propertyNamesToConsider ?? new List<string>(),
};

return diffConfig;
return cc;
}
}
}
18 changes: 9 additions & 9 deletions Analytical_Engine/Create/Graph/Graph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,32 @@ public static partial class Create

[Description("Create a graph from a collection of IBHoMObjects, property names and decimal places to determine unique graph entities.")]
[Input("entities", "A collection of IBHoMOBjects to use as Graph entities. Entities should include DependencyFragments to determine the Graph Relations.")]
[Input("diffConfig", "Configuration of diffing used when attempting to find unique entities.")]
[Input("comparisonConfig", "Settings to determine the uniqueness of entities.")]
[Output("graph", "Graph.")]
public static Graph Graph(List<IBHoMObject> entities, DiffConfig diffConfig = null)
public static Graph Graph(List<IBHoMObject> entities, ComparisonConfig comparisonConfig = null)
{
return Graph(entities, new List<IRelation>(), diffConfig);
return Graph(entities, new List<IRelation>(), comparisonConfig);
}

/***************************************************/

[Description("Create a graph from a collection of IRelations, property names and decimal places to determine unique graph entities.")]
[Input("relations", "A collection of IRelations to use as Graph Relations. Relations should include sub Graphs containing the entities to be used in the Graph.")]
[Input("diffConfig", "Configuration of diffing used when attempting to find unique entities.")]
[Input("comparisonConfig", "Settings to determine the uniqueness of entities.")]
[Output("graph", "Graph.")]
public static Graph Graph(List<IRelation> relations, DiffConfig diffConfig = null)
public static Graph Graph(List<IRelation> relations, ComparisonConfig comparisonConfig = null)
{
return Graph(new List<IBHoMObject>(), relations, diffConfig);
return Graph(new List<IBHoMObject>(), relations, comparisonConfig);
}

/***************************************************/

[Description("Create a graph from a collection of IBHoMObjects, a collection of IRelations, property names and decimal places to determine unique graph entities.")]
[Input("entities", "Optional collection of IBHoMOBjects to use as Graph entities. Entities can include DependencyFragments to determine the Graph Relations.")]
[Input("relations", "Optional collection of IRelations to use as Graph Relations. Relations can include sub Graphs containing the entities to be used in the Graph.")]
[Input("diffConfig", "Configuration of diffing used when attempting to find unique entities.")]
[Input("comparisonConfig", "Settings to determine the uniqueness of entities.")]
[Output("graph", "Graph.")]
public static Graph Graph(List<IBHoMObject> entities = null, List<IRelation> relations = null, DiffConfig diffConfig = null)
public static Graph Graph(List<IBHoMObject> entities = null, List<IRelation> relations = null, ComparisonConfig comparisonConfig = null)
{
Graph graph = new Graph();

Expand All @@ -88,7 +88,7 @@ public static Graph Graph(List<IBHoMObject> entities = null, List<IRelation> rel
return graph;
}

m_MatchedObjects = Query.DiffEntities(clonedEntities, diffConfig);
m_MatchedObjects = Query.DistinctEntities(clonedEntities, comparisonConfig);

//convert dependency fragments attached to entities and add to relations
clonedEntities.ForEach(ent => clonedRelations.AddRange(ent.ToRelation()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,27 @@ public static partial class Query

[Description("Identifies unique objects from a collection IBHoMObjects using hash comparison.")]
[Input("entities", "A collection of IBHoMObjects from which unique instances are identified.")]
[Input("diffConfig", "Configuration of diffing used to find unique entities.")]
[Input("comparisonConfig", "Configuration of diffing used to find unique entities.")]
[Output("unique entities", "A Dictionary replacement map of the entities where the keys are the Guid of the original entity and the Values the matching IBHoMObject entity.")]
public static Dictionary<Guid, IBHoMObject> DiffEntities(this List<IBHoMObject> entities, DiffConfig diffConfig = null)
public static Dictionary<Guid, IBHoMObject> DistinctEntities(this List<IBHoMObject> entities, ComparisonConfig comparisonConfig = null) // this is not a diff, it's finding unique entities
{
alelom marked this conversation as resolved.
Show resolved Hide resolved
if (diffConfig == null)
diffConfig = new DiffConfig();
ComparisonConfig cc = comparisonConfig ?? new ComparisonConfig();

Dictionary<Guid, IBHoMObject> replaceMap = new Dictionary<Guid, IBHoMObject>();
Dictionary<IBHoMObject, string> objectHash = new Dictionary<IBHoMObject, string>();

//remove old hashes if any
RemoveExistingHashes(entities);

//find decimal places from numeric tolerance
int decimalPlaces = DecimalPlaces(diffConfig.NumericTolerance);

//generate hashes
entities.ForEach(ent => objectHash.Add(ent, ent.HashEntity(diffConfig, decimalPlaces)));
HashComparer<object> hashComparer = new HashComparer<object>(cc);

foreach (KeyValuePair<IBHoMObject, string> entityA in objectHash)
{
alelom marked this conversation as resolved.
Show resolved Hide resolved
foreach (KeyValuePair<IBHoMObject, string> entityB in objectHash)
{
//only if same object type
if(entityA.Key.GetType() == entityB.Key.GetType())
if (entityA.Key.GetType() == entityB.Key.GetType())
{
//compare hashes
if (entityA.Value == entityB.Value)
if (hashComparer.Equals(entityA.Value, entityB.Value))
{

//store in map dictionary where key is original Guid and Value is replacement object
replaceMap[entityA.Key.BHoM_Guid] = entityB.Key;

Expand All @@ -84,47 +75,5 @@ public static Dictionary<Guid, IBHoMObject> DiffEntities(this List<IBHoMObject>
}
return replaceMap;
}

/***************************************************/
/**** Private Methods ****/
/***************************************************/

private static string HashEntity(this IBHoMObject entity, DiffConfig diffConfig, int decimalPlaces)
{
if (diffConfig == null)
diffConfig = new DiffConfig();

List<string> propertiesToIgnore = BH.Engine.Reflection.Query.PropertyNames(entity).Except(diffConfig.PropertiesToConsider).ToList();

return Base.Query.Hash(entity, propertyNameExceptions: propertiesToIgnore, fractionalDigits: decimalPlaces);
}

/***************************************************/

private static int DecimalPlaces(double numericTolerance)
{
//horrible conversion from numeric tolerance to precision needed for Hashing
int precision = 0;

while ((decimal)numericTolerance * (decimal)Math.Pow(10, precision) !=
Math.Round((decimal)numericTolerance * (decimal)Math.Pow(10, precision)))
precision++;

return precision;
}

/***************************************************/

private static void RemoveExistingHashes(List<IBHoMObject> entities)
{
foreach(IBHoMObject entity in entities)
{
if (entity.Fragments.Contains(typeof(HashFragment)))
{
entity.Fragments.Remove(typeof(HashFragment));
}
}
}
}

}
2 changes: 2 additions & 0 deletions BHoM_Engine/BHoM_Engine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Modify\SetHashFragment.cs" />
<Compile Include="Objects\EqualityComparers\HashComparer.cs" />
<Compile Include="Query\Hash.cs" />
<Compile Include="Create\BHoMGroup.cs" />
<Compile Include="Create\IObject\RandomObject.cs" />
Expand Down
6 changes: 5 additions & 1 deletion BHoM_Engine/Create/IObject/RandomObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,11 @@ private static object GetValue(Type type, Random rnd, int depth)
else if (type.IsInterface || type.IsAbstract)
{
if (depth > 50) return null;
return GetValue(m_ImplementingTypes[type], rnd, depth + 1);

Type obj = null;
if (!m_ImplementingTypes.TryGetValue(type, out obj)) return null;
alelom marked this conversation as resolved.
Show resolved Hide resolved

return GetValue(obj, rnd, depth + 1);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion BHoM_Engine/Modify/RemoveFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static partial class Modify
[Input("fragmentType", "The type of fragment that should be removed from the object.")]
[Output("iBHoMObject", "The BHoM object with the added fragment.")]
public static IBHoMObject RemoveFragment(this IBHoMObject iBHoMObject, Type fragmentType = null)
{
{
if (fragmentType == null) return iBHoMObject;
if (iBHoMObject == null) return null;
IBHoMObject o = iBHoMObject.DeepClone();
Expand Down
76 changes: 76 additions & 0 deletions BHoM_Engine/Modify/SetHashFragment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* This file is part of the Buildings and Habitats object Model (BHoM)
* Copyright (c) 2015 - 2020, the respective contributors. All rights reserved.
*
* Each contributor holds copyright over their respective contributions.
* The project versioning (Git) records all such contribution source information.
*
*
* The BHoM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* The BHoM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Reflection;
using BH.oM.Base;
using BH.oM.Reflection.Attributes;
using BH.Engine.Serialiser;

namespace BH.Engine.Base
{
public static partial class Modify
{
[Description("Computes the hash of the input BHoMObjects and stores it in a HashFragment for each of them." +
"\nIf the hashFragment already existed, it is replaced.")]
public static List<T> SetHashFragment<T>(this IEnumerable<T> objs, ComparisonConfig comparisonConfig = null) where T : IBHoMObject
{
// Each object will be cloned to avoid modification by reference.
List<T> objs_cloned = new List<T>();

// Calculate and set the object hashes
foreach (var obj in objs)
objs_cloned.Add(SetHashFragment(obj, comparisonConfig));

return objs_cloned;
}

[Description("Computes the hash of the BHoMObject and stores it in a HashFragment." +
"\nIf the hashFragment already existed, it is replaced.")]
public static T SetHashFragment<T>(T obj, ComparisonConfig comparisonConfig = null) where T : IBHoMObject
{
// Calculate and set the object hashes
string hash = obj.Hash(comparisonConfig);

return SetHashFragment<T>(obj, hash);
}

[Description("Clones the IBHoMObject, computes its hash and stores it in a HashFragment." +
"\nIf the hashFragment already existed, it is replaced.")]
public static T SetHashFragment<T>(T obj, string hash) where T : IBHoMObject
{
// Clone the current object to avoid modification by reference.
T obj_cloned = BH.Engine.Base.Query.DeepClone(obj);

obj_cloned.Fragments.AddOrReplace(new HashFragment() { Hash = hash });

return obj_cloned;
}
}
}

Loading