static void Main(string[] args) { var random = new Random(3_14159265); Func <double> vertexAttributeGenerator = () => { return(random.NextDouble()); }; Func <double> edgeAttributeGenerator = () => { return(random.NextDouble()); }; double vertexBound = 2; double edgeBound = 3; double vertexDecay = 1; double edgeDecay = 1; Func <double, double, double, double> boundMetric = (a, bound, decay) => bound * a / (1 / decay + a); Func <double, double, double> vertexRelabel = (a1, a2) => { return(boundMetric(Math.Abs(a1 - a2), vertexBound, vertexDecay)); }; Func <double, double> vertexAdd = a => boundMetric(Math.Abs(a), vertexBound, vertexDecay); Func <double, double> vertexRemove = vertexAdd; Func <double, double, double> edgeRelabel = (a1, a2) => { return(boundMetric(Math.Abs(a1 - a2), edgeBound, edgeDecay)); }; Func <double, double> edgeAdd = a => boundMetric(Math.Abs(a), edgeBound, edgeDecay); Func <double, double> edgeRemove = edgeAdd; // Func<double, double, double> vertexRelabel = (a1, a2) => // { // return Math.Abs(a1 - a2); // }; // Func<double, double> vertexAdd = a => Math.Abs(a); // Func<double, double> vertexRemove = vertexAdd; // Func<double, double, double> edgeRelabel = (a1, a2) => // { // return Math.Abs(a1 - a2); // }; // Func<double, double> edgeAdd = a => Math.Abs(a); // Func<double, double> edgeRemove = edgeAdd; var a = new List <double>() { 0, 1, .5, 1d / 3, 2d / 3, -1, 2, 10, -10, 100, -100, 1000, -1000 }; var b = new List <double>() { 0, 1, .5, 1d / 3, 2d / 3, -1, 2, 10, -10, 100, -100, 1000, -1000 }; var RiesenBunke2009AB = (1, 1); for (int gVertices = 8; gVertices < 12; gVertices++) { var hVertices = gVertices; // for (int hVertices = gVertices; hVertices > 0; hVertices-=1) { var measurements = 0; var results = new Dictionary <(double, double), double>(); foreach (var aElement in a) { foreach (var bElement in b) { results.Add((aElement, bElement), 0); } } for (double gDensity = 1.0; gDensity > 0; gDensity -= 0.1) { for (double hDensity = gDensity; hDensity > 0; hDensity -= 0.1) { for (int iter = 0; iter < 5; iter++) { var G = RandomGraphFactory.GenerateRandomInstance( vertices: gVertices, density: gDensity, directed: true, vertexAttributeGenerator: vertexAttributeGenerator, edgeAttributeGenerator: edgeAttributeGenerator ); var H = RandomGraphFactory.GenerateRandomInstance( vertices: hVertices, density: hDensity, directed: true, vertexAttributeGenerator: vertexAttributeGenerator, edgeAttributeGenerator: edgeAttributeGenerator ); var matchingParameters = new GraphMatchingParameters <int, double, double> { aCollection = a, bCollection = b, edgeAdd = edgeAdd, vertexAdd = vertexAdd, edgeRelabel = edgeRelabel, edgeRemove = edgeRemove, vertexRemove = vertexRemove, vertexRelabel = vertexRelabel, encodingMethod = GraphEncodingMethod.Wojciechowski }; var matching = new VertexPartialMatchingNode <int, double, double>( G, H, matchingParameters ); var myRelativeError = (matching.BestUpperBound - matching.BestLowerBound) / matching.BestLowerBound; var theirRelativeError = (matching.BestUpperBound - matching.abLowerBounds[RiesenBunke2009AB]) / matching.abLowerBounds[RiesenBunke2009AB]; var eps = 1e-12; // if (theirRelativeError > eps) // { // System.Console.WriteLine($"|Vg|={gVertices}, |Eg|={gDensity:f2}, |Vh|={hVertices}, |Eh|={hDensity:f2}. My estimate / theirs {matching.LowerBound / matching.abLowerBounds[RiesenBunke2009AB]:f2}."); // } // var theirLowerBound = matching.abLowerBounds[(2d/3, .5)]; // if (theirLowerBound > eps) { measurements += 1; foreach (var kvp in matching.abLowerBounds) { // var score = (matching.UpperBound - kvp.Value) / matching.UpperBound; var score = kvp.Value > Math.Max(Math.Max( matching.abLowerBounds[(.5, .5)],
static void Main(string[] args) { using var context = new EnronContext(); Console.WriteLine($"{context.Emails.Count()} emails in total."); // var resultsFilePath = "./results.txt"; var topResultsFilePath = "./top_results.txt"; var topTopResultsFilePath = "./top_top_results.txt"; var matchingFeatureSelectors = new List <(string, Func <VertexPartialMatchingNode <string, double, double>, double>)>() { ("Upper bound", matching => matching.BestUpperBound), ("Lower bound", matching => matching.BestLowerBound) }; var edgeCostTypes = new List <(string, CostType, List <double>, List <double>)>() { // ("Unit cost Wojciechowski .5", CostType.UnitCost, new List<double>(){.5}, new List<double>(){.5}), // ("Unit cost Wojciechowski (1.) .5", CostType.UnitCost, new List<double>(){1}, new List<double>(){.5}), // ("Unit cost Wojciechowski .5 Riesen Bunke 1.", CostType.UnitCost, new List<double>(){.5, 1}, new List<double>(){1, .5}), // ("Unit cost Riesen Bunke 1.", CostType.UnitCost, new List<double>(){1}, new List<double>(){1}), ("Absolute value Wojciechowski .5", CostType.AbsoluteValue, new List <double>() { .5 }, new List <double>() { .5 }), // ("Absolute value Wojciechowski (1.) .5", CostType.AbsoluteValue, new List<double>(){1}, new List<double>(){.5}), // ("Absolute value Wojciechowski .5 Riesen Bunke 1.", CostType.AbsoluteValue, new List<double>(){.5, 1}, new List<double>(){1, .5}), ("Absolute value Riesen Bunke 1.", CostType.AbsoluteValue, new List <double>() { 1 }, new List <double>() { 1 }), // ("Absolute value bounded Wojciechowski .5", CostType.AbsoluteValueBounded, new List<double>(){.5}, new List<double>(){.5}), // ("Absolute value bounded Wojciechowski (1.) .5", CostType.AbsoluteValueBounded, new List<double>(){1}, new List<double>(){.5}), // ("Absolute value bounded Wojciechowski .5 Riesen Bunke 1.", CostType.AbsoluteValueBounded, new List<double>(){.5, 1}, new List<double>(){1, .5}), // ("Absolute value bounded Riesen Bunke 1.", CostType.AbsoluteValueBounded, new List<double>(){1}, new List<double>(){1}), }; var results = new Dictionary <(int vertexUpperBound, int k, string distanceScorerName, string edgeCostType, string matchingFeatureSelectorName), (double testAccuracy, double validationAccuracy)>(); var topResults = new Dictionary <(int vertexUpperBound, int k, string distanceScorerName, string edgeCostType, string matchingFeatureSelectorName), (double testAccuracy, double validationAccuracy)>(); for (int iteration = 0; iteration < 10; iteration++) { for (int vertexUpperBound = 3; vertexUpperBound < 8; vertexUpperBound++) { var dataset = GenerateDataSet( context, trainingProportion: 8, validatingProportion: 1, testingProportion: 1, vertexUpperBound: vertexUpperBound, randomSeed: iteration ); foreach (var(matchingFeatureSelectorName, matchingFeatureSelector) in matchingFeatureSelectors) { foreach (var(edgeCostTypeName, edgeCostType, aCollection, bCollection) in edgeCostTypes) { var matchingParameters = GraphMatchingParameters <string, double, double> .DoubleCostComposer( CostType.UnitCost, edgeCostType ); matchingParameters.aCollection = aCollection; matchingParameters.bCollection = bCollection; // determine closest neighbours for each test and validation graph var testMatchingClassPairsList = new List <(List <(VertexPartialMatchingNode <string, double, double>, bool)>, bool)>(); var validationMatchingClassPairsList = new List <(List <(VertexPartialMatchingNode <string, double, double>, bool)>, bool)>(); foreach (var(pair, i) in dataset.testSet.Zip(Enumerable.Range(0, int.MaxValue))) { var pairToAdd = ( KNNClassifier.KNNClassifier.FindClosest(pair.Item1, dataset.trainingSet, matchingParameters, matchingFeatureSelector), pair.Item2 ); testMatchingClassPairsList.Add(pairToAdd); // System.Console.WriteLine($"Test set: computed distance: {i * 100d / dataset.testSet.Count:f2}%."); } foreach (var(pair, i) in dataset.validationSet.Zip(Enumerable.Range(0, int.MaxValue))) { var pairToAdd = ( KNNClassifier.KNNClassifier.FindClosest(pair.Item1, dataset.trainingSet, matchingParameters, matchingFeatureSelector), pair.Item2 ); validationMatchingClassPairsList.Add(pairToAdd); // System.Console.WriteLine($"Validation set: computed distance: {i * 100d / dataset.validationSet.Count:f2}%."); } Func <int, Func <int, VertexPartialMatchingNode <string, double, double>, double>, List <(List <(VertexPartialMatchingNode <string, double, double>, bool)>, bool)>, double> getAccuracy = (k, distanceScorer, matchingClassPairsList) => { var truePositives = 0; var falsePositives = 0; var trueNegatives = 0; var falseNegatives = 0; foreach (var(matchingClassPairs, testGraphLabel) in matchingClassPairsList) { var classificationResult = KNNClassifier.KNNClassifier.Classify <string, double, double, bool>( matchingClassPairs, distanceScorer, k: k ); var result = (expected : testGraphLabel, received : classificationResult.graphClass); if (result.expected) { if (result.received) { truePositives += 1; } else { falseNegatives += 1; } } else { if (result.received) { falsePositives += 1; } else { trueNegatives += 1; } } } return((truePositives + trueNegatives) * 1d / matchingClassPairsList.Count); }; var ks = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1 }; var distanceScorers = new (string, Func <int, VertexPartialMatchingNode <string, double, double>, double>)[]