1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | 3x 3x 3x 3x 676x 676x 7078x 7078x 676x 676x 3x 816x 816x 1959x 1959x 256x 1703x 1703x 560x 3x 167x 167x 684x 167x 3x 165x 674x 165x 165x 674x 3x 163x 163x 163x 163x 163x 163x 163x 670x 163x 3x 165x 1527x 1527x 165x 674x 674x 12x 662x 662x 6989x 6989x 1460x 1460x 662x 237x 237x 237x 425x 425x 165x 3x 6915x 6915x 16041x 16041x 16041x 5305x 1610x 3x 3x 14017x 14017x 7160x 6857x 3x 10764x | /*! GPII Canopy Matchmaker Copyright 2012 OCAD University Copyright 2012 Antranig Basman Licensed under the New BSD license. You may not use this file except in compliance with this License. The research leading to these results has received funding from the European Union's Seventh Framework Programme (FP7/2007-2013) under grant agreement no. 289016. You may obtain a copy of the License at https://github.com/GPII/universal/blob/master/LICENSE.txt */ "use strict"; var fluid = fluid || require("infusion"); var gpii = gpii || fluid.registerNamespace("gpii"); fluid.registerNamespace("gpii.canopyMatchMaker.utils"); gpii.canopyMatchMaker.utils.computeFitness = function (leaves, solution, ontologicalMetricFunction) { var vector = []; for (var i = 0; i < leaves.length; ++i) { var leaf = leaves[i]; vector[i] = ontologicalMetricFunction(leaf, solution); } vector = vector.sort(gpii.canopyMatchMaker.utils.sortDescending); return vector; }; gpii.canopyMatchMaker.utils.compareFitness = function (solA, solB) { var i = 0, fitA = solA.fitness, fitB = solB.fitness; for (; ; ++i) { var endA = i === fitA.length, endB = i === fitB.length; if (endA || endB) { return endA && endB ? 0 : (endB ? -1 : 1); } var diff = fitB[i] - fitA[i]; if (diff !== 0) { return diff; } } }; /* * @leaves {object} * @solrecs {object} map of solutions keyed by solution id. */ gpii.canopyMatchMaker.utils.sortSolutions = function (solutions) { var solArr = []; for (var i in solutions) { solArr.push(solutions[i]); } return solArr.sort(gpii.canopyMatchMaker.utils.compareFitness); }; /* * @leaves {object} * @solrecs {object} map of solutions keyed by solution id. */ gpii.canopyMatchMaker.utils.rankSolutions = function (leaves, solrecs, ontologicalMetricFunction) { fluid.each(solrecs, function (solrec) { solrec.fitness = gpii.canopyMatchMaker.utils.computeFitness(leaves, solrec.skeleton, ontologicalMetricFunction); }); var solArr = gpii.canopyMatchMaker.utils.sortSolutions(solrecs); return fluid.transform(solArr, function (value) { return value.index; }); }; /* * @leaves {object} * @solrecs {object} map of solutions keyed by solution id. */ gpii.canopyMatchMaker.utils.disposeStrategy = function (leaves, solrecs, data, ontologyMetadata) { var ontologicalMetricName = fluid.get(ontologyMetadata, "ontologicalMetricFunction") || "gpii.canopyMatchMaker.utils.prefixLength"; var ontologicalMetricFunction = fluid.getGlobalValue(ontologicalMetricName); // if we already have priority for some solutions, accept these and reject any applications // of same type. gpii.matchMakerFramework.utils.disposeFromPriority(solrecs, data); // rank remaining solutions based on fit to preferences var ranked = gpii.canopyMatchMaker.utils.rankSolutions(leaves, solrecs, ontologicalMetricFunction); // dispose based on canopy var disposed = gpii.canopyMatchMaker.utils.disposeFromCanopy(leaves, ranked, solrecs, data, ontologicalMetricFunction); // re-key by solution id: var togo = {}; fluid.each(disposed, function (val) { togo[val.index] = val; }); return togo; }; gpii.canopyMatchMaker.utils.disposeFromCanopy = function (leaves, ranked, solrecs, data, ontologicalMetricFunction) { // Set default canopy to negative leaf depth. To raise the canopy, a preference needs to // match at least one level into the leaf. var canopy = fluid.transform(leaves, function (leaf) { var leafDepth = fluid.pathUtil.parseEL(leaf).length; return -leafDepth; }); for (var i = 0; i < ranked.length; ++i) { var sol = solrecs[ranked[i]]; if (sol.disposition === "reject") { continue; } var inCanopy = false; for (var j = 0; j < leaves.length; ++j) { var depth = ontologicalMetricFunction(leaves[j], sol.skeleton); if (depth > canopy[j]) { inCanopy = true; canopy[j] = depth; } } if (inCanopy) { sol.disposition = "accept"; sol.dispositionReason = "Was the solution of this type that best fit user preferences"; gpii.matchMakerFramework.utils.rejectFromTypes(data.solutionTypes[sol.index], data.solutionTypeMapping, solrecs, "Another solution (" + sol.index + ") covering more preferences was found found."); } else { sol.disposition = "reject"; sol.dispositionReason = "Was not in canopy."; } } return solrecs; }; /** Returns a non-positive number indicating by how many path segments the supplied * path fails to index correctly into the supplied model. A return value of 0 * indicates that the path indexes fully */ gpii.canopyMatchMaker.utils.prefixLength = function (path, model) { var segs = fluid.pathUtil.parseEL(path); for (var i = 0; i < segs.length; ++i) { var seg = segs[i]; model = model[seg]; if (model === undefined) { return i - segs.length; } } return 0; }; fluid.registerNamespace("gpii.canopyMatchMaker.utils.ISO24751"); gpii.canopyMatchMaker.utils.ISO24751.ontologicalMetric = function (path, model) { var segs = fluid.pathUtil.parseEL(path); // if it's an application setting and the application is not matching, consider worst fit if (segs[0] === "applications" && fluid.get(model, ["applications", segs[1]]) === undefined) { return -Infinity; } else { // else do fitting as usual return gpii.canopyMatchMaker.utils.prefixLength(path, model); } }; // only used by canopyMatchMaker - moved from MatchMakerFramework gpii.canopyMatchMaker.utils.sortDescending = function (numA, numB) { return numB - numA; }; |