TTK
Loading...
Searching...
No Matches
AssignmentAuction.h
Go to the documentation of this file.
1
13
14#pragma once
15
16#include <AssignmentSolver.h>
17
18#include <limits>
19#include <queue>
20
21namespace ttk {
22
23 template <class dataType>
24 class AssignmentAuction : virtual public Debug,
25 public AssignmentSolver<dataType> {
26
27 public:
28 AssignmentAuction() = default;
29
30 ~AssignmentAuction() override = default;
31
32 int run(std::vector<MatchingType> &matchings) override;
33 void runAuctionRound(std::vector<std::vector<dataType>> &cMatrix);
34
35 void initFirstRound();
37 void initEpsilon();
38 void epsilonScaling();
39 void makeBalancedMatrix(std::vector<std::vector<dataType>> &matrix);
40
41 bool stoppingCriterion(std::vector<std::vector<dataType>> &cMatrix);
42 dataType getRelativePrecision(std::vector<std::vector<dataType>> &cMatrix);
43 dataType getMatchingDistance(std::vector<std::vector<dataType>> &cMatrix);
44
45 inline void setBalanced(bool balanced) override {
47 if(this->balancedAssignment)
48 goodPrices.resize(this->colSize, 0);
49 else
50 goodPrices.resize((this->colSize - 1) + (this->rowSize - 1), 0);
51 }
52
53 inline void setNumberOfRounds(int noRounds) {
54 numberOfRounds = noRounds;
55 }
56
57 inline int getIter() {
58 return iter;
59 }
60
61 inline void setEpsilon(double eps) {
62 epsilon = eps;
63 }
64
65 inline void setDeltaLim(double delta) {
66 delta_lim = delta;
67 }
68
69 inline void setEpsilonDiviserMultiplier(double div) {
70 epsilonDiviserMultiplier = div;
71 }
72
73 inline void setPrices(std::vector<double> prices) {
74 goodPrices.resize(prices.size(), 0);
75 for(unsigned int i = 0; i < prices.size(); ++i)
76 goodPrices[i] = prices[i];
77 }
78
79 inline std::vector<double> &getPrices() {
80 return goodPrices;
81 }
82
83 private:
84 int numberOfRounds = -1;
85 int iter = 0;
86 double epsilon = -1;
87 double epsilonDiviserMultiplier = 0;
88 double delta_lim = 0.01;
89
90 dataType lowerBoundCostWeight = 1 + delta_lim;
91
92 // Filled
93 std::vector<int> bidderAssignments{1, -1}, bestBidderAssignments;
94 std::vector<int> goodAssignments{};
95 std::vector<double> goodPrices{};
96 dataType lowerBoundCost;
97 }; // AssignmentAuction Class
98
99 template <typename type>
100 static type abs(const type var) {
101 return (var >= 0) ? var : -var;
102 }
103
104 template <class dataType>
105 dataType getMaxValue(std::vector<std::vector<dataType>> &matrix,
106 bool balancedAsgn) {
107 unsigned int const nRows = matrix.size();
108 unsigned int const nCols = matrix[0].size();
109 dataType maxValue = std::numeric_limits<dataType>::lowest();
110 for(unsigned int i = 0; i < nRows; ++i) {
111 for(unsigned int j = 0; j < nCols; ++j) {
112 if(not balancedAsgn and i == nRows - 1 and j == nCols - 1)
113 continue;
114 maxValue = (matrix[i][j] > maxValue) ? matrix[i][j] : maxValue;
115 }
116 }
117 return maxValue;
118 }
119
120 template <typename dataType>
122 if(epsilon == -1.0) {
123 dataType maxValue
125 epsilon = maxValue / 4.0;
126 if(epsilon == 0.0)
127 epsilon = 1.0;
128 epsilon
129 /= ((epsilonDiviserMultiplier == 0) ? 1 : epsilonDiviserMultiplier * 5);
130 }
131 }
132
133 template <typename dataType>
135 epsilon /= 5;
136 /*if(epsilon < 1e-6)
137 epsilon = 1e-6;*/
138 }
139
140 template <typename dataType>
142 bidderAssignments.clear();
143 goodAssignments.clear();
144 if(this->balancedAssignment) {
145 bidderAssignments.resize(this->rowSize, -1);
146 goodAssignments.resize(this->colSize, -1);
147 } else {
148 bidderAssignments.resize((this->rowSize - 1) + (this->colSize - 1), -1);
149 goodAssignments.resize((this->colSize - 1) + (this->rowSize - 1), -1);
150 }
151 }
152
153 template <typename dataType>
155 iter = 0;
156 bidderAssignments[0] = -1;
157 }
158
159 template <typename dataType>
161 std::vector<std::vector<dataType>> &matrix) {
162 unsigned int const nRows = matrix.size();
163 unsigned int const nCols = matrix[0].size();
164 matrix[nRows - 1][nCols - 1] = 0;
165
166 // Add rows
167 for(unsigned int i = 0; i < nCols - 2; ++i) {
168 std::vector<dataType> const newLine(matrix[nRows - 1]);
169 matrix.push_back(newLine);
170 }
171 // Add columns
172 for(unsigned int i = 0; i < (nRows - 1) + (nCols - 1); ++i) {
173 for(unsigned int j = 0; j < nRows - 2; ++j) {
174 matrix[i].push_back(matrix[i][nCols - 1]);
175 }
176 }
177 }
178
179 // ----------------------------------------
180 // Main Functions
181 // ----------------------------------------
182 template <typename dataType>
184 std::vector<std::vector<dataType>> &cMatrix) {
185 std::queue<int> unassignedBidders{};
186 for(unsigned int i = 0; i < bidderAssignments.size(); ++i)
187 unassignedBidders.push(i);
188
189 while(!unassignedBidders.empty()) {
190 int const bidderId = unassignedBidders.front();
191 unassignedBidders.pop();
192
193 // Get good with highest value
194 dataType bestValue = std::numeric_limits<dataType>::lowest();
195 dataType bestSecondValue = std::numeric_limits<dataType>::lowest();
196 int bestGoodId = -1;
197 for(unsigned int goodId = 0; goodId < goodPrices.size(); ++goodId) {
198 if(cMatrix[bidderId][goodId] == static_cast<dataType>(-1))
199 continue;
200 dataType goodPrice = goodPrices[goodId];
201 dataType value = -cMatrix[bidderId][goodId] - goodPrice;
202 if(value > bestValue) {
203 bestSecondValue = bestValue;
204 bestValue = value;
205 bestGoodId = goodId;
206 } else if(value > bestSecondValue)
207 bestSecondValue = value;
208 }
209
210 // Update assignments
211 bidderAssignments[bidderId] = bestGoodId;
212 if(goodAssignments[bestGoodId] != -1)
213 unassignedBidders.push(goodAssignments[bestGoodId]);
214 goodAssignments[bestGoodId] = bidderId;
215
216 // If there is only one acceptable good for the bidder
217 if(bestSecondValue == std::numeric_limits<dataType>::lowest())
218 bestSecondValue = bestValue;
219
220 // Update price
221 double const delta = abs<dataType>(bestValue - bestSecondValue) + epsilon;
222 double newPrice = goodPrices[bestGoodId] + delta;
223 if(newPrice > std::numeric_limits<double>::max() / 2) {
224 // Avoid price explosion
225 newPrice = goodPrices[bestGoodId] + epsilon;
226 }
227 goodPrices[bestGoodId] = newPrice;
228 }
229 }
230
231 template <typename dataType>
232 dataType getLowerBoundCost(std::vector<std::vector<dataType>> &costMatrix) {
233 std::vector<dataType> minCol(
234 costMatrix[0].size(), std::numeric_limits<dataType>::max()),
235 minRow(costMatrix.size(), std::numeric_limits<dataType>::max());
236 for(unsigned int i = 0; i < costMatrix.size(); ++i) {
237 for(unsigned int j = 0; j < costMatrix[i].size(); ++j) {
238 if(costMatrix[i][j] < minCol[j])
239 minCol[j] = costMatrix[i][j];
240 if(costMatrix[i][j] < minRow[i])
241 minRow[i] = costMatrix[i][j];
242 }
243 }
244 dataType minColCost = 0, minRowCost = 0;
245 for(unsigned int i = 0; i < minCol.size(); ++i)
246 minColCost += minCol[i];
247 for(unsigned int i = 0; i < minRow.size(); ++i)
248 minRowCost += minRow[i];
249 dataType lowerBoundCost = std::max(minColCost, minRowCost);
250
251 return lowerBoundCost;
252 }
253
254 template <typename dataType>
255 int AssignmentAuction<dataType>::run(std::vector<MatchingType> &matchings) {
256 initEpsilon();
257 dataType bestCost = std::numeric_limits<dataType>::max();
258
259 // Try to avoid price war
260 double const tempPrice
261 = *std::max_element(goodPrices.begin(), goodPrices.end());
262 std::vector<double> savedPrices;
263 for(unsigned int i = 0; i < goodPrices.size(); ++i) {
264 auto old = goodPrices[i];
265 goodPrices[i]
266 = goodPrices[i] * epsilon / ((tempPrice == 0) ? 1 : tempPrice);
267 auto t = old - goodPrices[i];
268 savedPrices.push_back(t);
269 }
270
271 // Make balanced cost matrix
272 if(not this->balancedAssignment)
273 this->makeBalancedMatrix(this->costMatrix);
274
275 // Get lower bound cost
276 lowerBoundCost = getLowerBoundCost(this->costMatrix);
277
278 // Run auction
280 while(not stoppingCriterion(this->costMatrix)) {
282
284
285 dataType cost = getMatchingDistance(this->costMatrix);
286 if(cost < bestCost) {
287 bestCost = cost;
288 bestBidderAssignments = bidderAssignments;
289 }
290
292 iter++;
293
294 if(numberOfRounds != -1 and iter >= numberOfRounds)
295 break;
296 }
297 bidderAssignments = bestBidderAssignments;
298
299 // Create output matching
300 for(unsigned int bidderId = 0; bidderId < bidderAssignments.size();
301 ++bidderId) {
302 int const i = bidderId;
303 int const j = bidderAssignments[bidderId];
304 if(this->balancedAssignment
305 or (not this->balancedAssignment
306 and not(i >= this->rowSize - 1 and j >= this->colSize - 1))) {
307 matchings.push_back(std::make_tuple(i, j, this->costMatrix[i][j]));
308 }
309 }
310
311 // Set prices as before
312 for(unsigned int i = 0; i < goodPrices.size(); ++i)
313 goodPrices[i] += savedPrices[i];
314
315 return 0;
316 }
317
318 // ----------------------------------------
319 // Stopping Criterion Functions
320 // ----------------------------------------
321 // Adapted from Persistence Diagrams Auction
322 template <typename dataType>
324 std::vector<std::vector<dataType>> &cMatrix) {
325 if(bidderAssignments[0] == -1) // Auction not started
326 return false;
327 dataType delta = 5;
328 delta = getRelativePrecision(cMatrix);
329 return not(delta > delta_lim);
330 }
331
332 // Adapted from Persistence Diagrams Auction
333 template <typename dataType>
335 std::vector<std::vector<dataType>> &cMatrix) {
336 dataType d = this->getMatchingDistance(cMatrix);
337 if(d < 1e-6 or d <= (lowerBoundCost * lowerBoundCostWeight)) {
338 return 0;
339 }
340 dataType denominator = d - bidderAssignments.size() * epsilon;
341 if(denominator <= 0) {
342 return 1;
343 } else {
344 return d / denominator - 1;
345 }
346 }
347
348 // Adapted from Persistence Diagrams Auction
349 template <typename dataType>
351 std::vector<std::vector<dataType>> &cMatrix) {
352 dataType d = 0;
353 for(unsigned int bidderId = 0; bidderId < bidderAssignments.size();
354 ++bidderId) {
355 int const i = bidderId;
356 int const j = bidderAssignments[bidderId];
357 d += cMatrix[i][j];
358 }
359 return d;
360 }
361
362} // namespace ttk
void setEpsilon(double eps)
void runAuctionRound(std::vector< std::vector< dataType > > &cMatrix)
~AssignmentAuction() override=default
void setPrices(std::vector< double > prices)
bool stoppingCriterion(std::vector< std::vector< dataType > > &cMatrix)
void makeBalancedMatrix(std::vector< std::vector< dataType > > &matrix)
void setEpsilonDiviserMultiplier(double div)
dataType getRelativePrecision(std::vector< std::vector< dataType > > &cMatrix)
void setBalanced(bool balanced) override
int run(std::vector< MatchingType > &matchings) override
std::vector< double > & getPrices()
void setNumberOfRounds(int noRounds)
void setDeltaLim(double delta)
dataType getMatchingDistance(std::vector< std::vector< dataType > > &cMatrix)
std::vector< std::vector< dataType > > costMatrix
AssignmentSolver()=default
virtual void setBalanced(bool balanced)
T var(const T *v, const int &dimension=3)
TTK base package defining the standard types.
dataType getLowerBoundCost(std::vector< std::vector< dataType > > &costMatrix)
dataType getMaxValue(std::vector< std::vector< dataType > > &matrix, bool balancedAsgn)