$darkmode
DENOPTIM
APMapFinder.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2022 Marco Foscato <marco.foscato@uib.no>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package denoptim.fragspace;
20
21import java.util.ArrayList;
22import java.util.HashSet;
23import java.util.LinkedHashMap;
24import java.util.List;
25import java.util.Set;
26
27import denoptim.graph.APClass;
28import denoptim.graph.APMapping;
29import denoptim.graph.AttachmentPoint;
30import denoptim.graph.DGraph;
31import denoptim.graph.Vertex;
32import denoptim.graph.Vertex.BBType;
33
41public class APMapFinder
42{
50
56 private List<APMapping> allAPMappings = new ArrayList<APMapping>();
57
65 private static int maxCombs = 250;
66
70 private FragmentSpace fragSpace = null;
71
72//------------------------------------------------------------------------------
73
95 Vertex vA, Vertex vB, boolean screenAll)
96 {
97 this(fragSpace, vA, vB, null, screenAll, false, true);
98 }
99
100//------------------------------------------------------------------------------
101
126 Vertex vA, Vertex vB,
127 APMapping fixedRootAPs, boolean screenAll,
128 boolean onlyCompleteMappings, boolean compatibleIfFree)
129 {
130 this.fragSpace = fragSpace;
131 List<AttachmentPoint> needyAPsA = new ArrayList<AttachmentPoint>();
132 if (vA.getGraphOwner()!=null)
133 {
134 List<Vertex> subgraph = new ArrayList<Vertex>();
135 subgraph.add(vA);
136 needyAPsA = vA.getGraphOwner().getInterfaceAPs(subgraph);
137 }
138 List<AttachmentPoint> needyAPsB =
139 new ArrayList<AttachmentPoint>();
140 if (vB.getGraphOwner()!=null)
141 {
142 List<Vertex> subgraph = new ArrayList<Vertex>();
143 subgraph.add(vB);
144 needyAPsB = vB.getGraphOwner().getInterfaceAPs(subgraph);
145 }
146 findAllMappings(vA.getAttachmentPoints(), needyAPsA,
147 vB.getAttachmentPoints(), needyAPsB,
148 fixedRootAPs, screenAll, onlyCompleteMappings, compatibleIfFree);
149 }
150
151//------------------------------------------------------------------------------
152
175 List<AttachmentPoint> lstA,
176 List<AttachmentPoint> needyAPsA,
177 List<AttachmentPoint> lstB,
178 List<AttachmentPoint> needyAPsB,
179 APMapping fixedRootAPs, boolean screenAll,
180 boolean onlyCompleteMappings, boolean compatibleIfFree)
181 {
182 this.fragSpace = fragSpace;
183 findAllMappings(lstA, needyAPsA, lstB, needyAPsB,
184 fixedRootAPs, screenAll, onlyCompleteMappings, compatibleIfFree);
185 }
186
187//------------------------------------------------------------------------------
188
206 private void findAllMappings(List<AttachmentPoint> lstA,
207 List<AttachmentPoint> needyAPsA,
208 List<AttachmentPoint> lstB,
209 List<AttachmentPoint> needyAPsB,
210 APMapping fixedRootAPs, boolean screenAll,
211 boolean onlyCompleteMappings, boolean compatibleIfFree)
212 {
213 // Remove from the lists those APs that have already a mapping
214 List<AttachmentPoint> purgedLstA = new ArrayList<AttachmentPoint>(lstA);
215 if (fixedRootAPs!=null)
216 {
217 purgedLstA.removeAll(fixedRootAPs.keySet());
218 }
219 List<AttachmentPoint> purgedLstB = new ArrayList<AttachmentPoint>(lstB);
220 if (fixedRootAPs!=null)
221 {
222 purgedLstB.removeAll(fixedRootAPs.values());
223 }
224
225 // Map all the compatibilities before choosing a specific mapping
226 LinkedHashMap<AttachmentPoint,List<AttachmentPoint>> apCompatilities =
227 findMappingCompatibileAPs(purgedLstA, purgedLstB,
228 compatibleIfFree, fragSpace);
229
230 // The 'keys' is used just to keep the map keys sorted in a separate list
231 // so that the order is randomized only once, then it is retained.
232 List<AttachmentPoint> keys = new ArrayList<AttachmentPoint>(
233 apCompatilities.keySet());
234 if (fixedRootAPs!=null)
235 {
236 // Since these are constrained we do not need them among the keys
237 // when looking over the combinations of keys
238 keys.removeAll(fixedRootAPs.keySet());
239 }
240
241 // Test if we have enough AP compatibilities to satisfy the constraints
242 Set<AttachmentPoint> doableAPsA = new HashSet<AttachmentPoint>(keys);
243 if (fixedRootAPs!=null)
244 doableAPsA.addAll(fixedRootAPs.keySet());
245 Set<AttachmentPoint> doableAPsB = new HashSet<AttachmentPoint>();
246 apCompatilities.values().stream().forEach(l -> doableAPsB.addAll(l));
247 if (onlyCompleteMappings)
248 {
249 for (AttachmentPoint oldAp : lstA)
250 {
251 if (!needyAPsA.contains(oldAp))
252 needyAPsA.add(oldAp);
253 }
254 for (AttachmentPoint oldAp : lstB)
255 {
256 if (!needyAPsB.contains(oldAp))
257 needyAPsB.add(oldAp);
258 }
259 }
260 Set<AttachmentPoint> mustBeDoableA = new HashSet<AttachmentPoint>(
261 needyAPsA);
262 Set<AttachmentPoint> mustBeDoableB = new HashSet<AttachmentPoint>(
263 needyAPsB);
264 if (fixedRootAPs!=null)
265 {
266 mustBeDoableA.removeAll(fixedRootAPs.keySet());
267 mustBeDoableB.removeAll(fixedRootAPs.values());
268 }
269 if (!doableAPsA.containsAll(mustBeDoableA)
270 || !doableAPsB.containsAll(mustBeDoableB))
271 {
272 return;
273 }
274
275 if (!onlyCompleteMappings)
276 {
277 for (AttachmentPoint oldAp : lstA)
278 {
279 if (oldAp.isAvailableThroughout())
280 {
281 // NB: adding 'null' will allow the presence of AP mappings
282 // where oldAP is intentionally left out of the mapping thus
283 // allowing to let it stay free.
284 if (apCompatilities.containsKey(oldAp))
285 {
286 apCompatilities.get(oldAp).add(null);
287 }
288 }
289 }
290 }
291
292 // Get all possible combinations of compatible AP pairs
293 int currentKey = 0;
294 APMapping currentMapping = new APMapping();
295 if (fixedRootAPs!=null)
296 {
297 currentMapping = fixedRootAPs.clone(); //shallow
298 }
299 // We try the comprehensive approach, but if that is too demanding
300 // and gets stopped, then we run a series of simplified attempts
301 // to hit a decent combination with "lucky shots".
302 Boolean stopped = false;
303 if (keys.size()>0)
304 {
306 currentKey, apCompatilities, currentMapping, allAPMappings,
307 screenAll, maxCombs);
308 } else {
309 // This would have been done by the recursive combiner
310 allAPMappings.add(currentMapping);
311 }
312
313 // Purge according to lists of APs that needs a mapping
314 List<APMapping> toRemove = new ArrayList<APMapping>();
315 for (APMapping c : allAPMappings)
316 {
317 if (!c.containsAllKeys(needyAPsA))
318 {
319 toRemove.add(c);
320 }
321 if (!c.containsAllValues(needyAPsB))
322 {
323 toRemove.add(c);
324 }
325 }
326 allAPMappings.removeAll(toRemove);
327
328 // If we where interrupted, we try to get a proper mapping again.
329 // This time we ignore all the possibilities and try a more direct
330 // approach, which, however, cannot account for all possible combs.
331 if (stopped && allAPMappings.isEmpty())
332 {
333 for (int iTry = 0; iTry < maxCombs; iTry++)
334 {
335 APMapping apMap = new APMapping();
336 List<AttachmentPoint> used =
337 new ArrayList<AttachmentPoint>();
338 List<AttachmentPoint> availKeys =
339 new ArrayList<AttachmentPoint>();
340 availKeys.addAll(needyAPsA);
341 boolean abandon = false;
342 for (int jj=0; jj<needyAPsA.size(); jj++)
343 {
344 AttachmentPoint ap =
346 availKeys);
347 availKeys.remove(ap);
348 List<AttachmentPoint> availPartners =
349 new ArrayList<AttachmentPoint>();
350 availPartners.addAll(apCompatilities.get(ap));
351 boolean done = false;
352 for (int j=0; j<apCompatilities.get(ap).size(); j++)
353 {
354 AttachmentPoint chosenAvail =
356 availPartners);
357 availPartners.remove(chosenAvail);
358 if (used.contains(chosenAvail))
359 {
360 continue;
361 }
362 used.add(chosenAvail);
363 apMap.put(ap,chosenAvail);
364 done = true;
365 break;
366 }
367 if (!done)
368 {
369 abandon = true;
370 break;
371 }
372 }
373
374 if (!abandon)
375 {
376 allAPMappings.add(apMap);
377 break;
378 }
379 }
380 }
381 if (allAPMappings.size() > 0)
384 }
385
386//------------------------------------------------------------------------------
387
403 public static LinkedHashMap<AttachmentPoint,List<AttachmentPoint>>
404 findMappingCompatibileAPs(List<AttachmentPoint> lstA,
405 List<AttachmentPoint> lstB, boolean compatibleIfFree,
407 {
408 LinkedHashMap<AttachmentPoint,List<AttachmentPoint>>
409 apCompatilities = new LinkedHashMap<AttachmentPoint,
410 List<AttachmentPoint>>();
411
412 for (AttachmentPoint oAP : lstA)
413 {
414 for (AttachmentPoint cAP : lstB)
415 {
416 boolean compatible = false;
418 {
419 // Addressing the cases where the APs are used/free
420 // and have src/trg role
421
422 boolean oAPInUse = !oAP.isAvailableThroughout();
423 boolean oAPIsSrc = oAP.isSrcInUserThroughout();
424 boolean oAPIsTrg = oAPInUse && !oAP.isSrcInUserThroughout();
425
426 boolean cAPInUse = !cAP.isAvailableThroughout();
427 boolean cAPIsSrc = cAP.isSrcInUserThroughout();
428 boolean cAPIsTrg = cAPInUse && !cAP.isSrcInUserThroughout();
429
430 // These can be null if AP is not in use!
433
434 APClass oAPcl = oAP.getAPClass();
435 APClass cAPcl = cAP.getAPClass();
436 APClass loAPcl = null;
437 if (loAP!=null)
438 loAPcl = loAP.getAPClass();
439 APClass lcAPcl = null;
440 if (lcAP!=null)
441 lcAPcl = lcAP.getAPClass();
442
443 // TODO: if the vertex is a template, we should
444 // consider the required APs.
445
446 if (oAP.getAPClass().equals(cAP.getAPClass()))
447 {
448 compatible = true;
449 } else {
450 if (!oAPInUse && !cAPInUse && compatibleIfFree)
451 {
452 compatible = true;
453 } else if (!oAPInUse && cAPInUse && compatibleIfFree)
454 {
455 if (cAPIsSrc && oAPcl.isCPMapCompatibleWith(lcAPcl,
456 fragSpace))
457 {
458 compatible = true;
459 } else if (cAPIsTrg && lcAPcl.isCPMapCompatibleWith(
460 oAPcl, fragSpace))
461 {
462 compatible = true;
463 }
464 } else if (oAPInUse && !cAPInUse && compatibleIfFree)
465 {
466 if (oAPIsSrc && cAPcl.isCPMapCompatibleWith(loAPcl,
467 fragSpace))
468 {
469 compatible = true;
470 } else if (oAPIsTrg && loAPcl.isCPMapCompatibleWith(
471 cAPcl, fragSpace))
472 {
473 compatible = true;
474 }
475 } else if (oAPInUse && cAPInUse)
476 {
477 if (oAPIsSrc && cAPIsSrc)
478 {
479 // both are SRC
480 if (oAPcl.isCPMapCompatibleWith(lcAPcl,
481 fragSpace)
482 && cAPcl.isCPMapCompatibleWith(loAPcl,
483 fragSpace))
484 {
485 compatible = true;
486 }
487 } else if ((!oAPIsSrc && cAPIsSrc)
488 || (oAPIsSrc && !cAPIsSrc))
489 {
490 // Since directions will have to be inverted, we
491 // want the APClass compatibility to exists in
492 // both directions on each connection.
493 if (oAPcl.isCPMapCompatibleWith(lcAPcl,
494 fragSpace)
495 && lcAPcl.isCPMapCompatibleWith(oAPcl,
496 fragSpace)
497 && cAPcl.isCPMapCompatibleWith(loAPcl,
498 fragSpace)
499 && loAPcl.isCPMapCompatibleWith(cAPcl,
500 fragSpace))
501 {
502 compatible = true;
503 }
504 } else {
505 // both oAP and cAP are TRG
506 if (lcAPcl.isCPMapCompatibleWith(oAPcl,
507 fragSpace)
508 && loAPcl.isCPMapCompatibleWith(cAPcl,
509 fragSpace))
510 {
511 compatible = true;
512 }
513 }
514 }
515 }
516 } else {
517 compatible = true;
518 }
519 if (compatible)
520 {
521 if (apCompatilities.containsKey(oAP))
522 {
523 apCompatilities.get(oAP).add(cAP);
524 } else {
525 List<AttachmentPoint> lst =
526 new ArrayList<AttachmentPoint>();
527 lst.add(cAP);
528 apCompatilities.put(oAP,lst);
529 }
530 }
531 }
532 }
533 return apCompatilities;
534 }
535
536//------------------------------------------------------------------------------
537
542 public boolean foundMapping()
543 {
544 return !allAPMappings.isEmpty();
545 }
546
547//------------------------------------------------------------------------------
548
558 {
559 return chosenAPMap;
560 }
561
562//------------------------------------------------------------------------------
563
572 public List<APMapping> getAllAPMappings()
573 {
574 return allAPMappings;
575 }
576
577//------------------------------------------------------------------------------
578
579}
An utility class to encapsulate the search for an AttachmentPoint-AttachmentPoint mapping.
APMapping getChosenAPMapping()
Returns the AttachmentPoint-AttachmentPoint mapping chosen among the possible mappings.
APMapping chosenAPMap
The chosen AttachmentPoint-AttachmentPoint mapping.
List< APMapping > allAPMappings
The collection of all AttachmentPoint-AttachmentPoint mappings that have been found.
APMapFinder(FragmentSpace fragSpace, List< AttachmentPoint > lstA, List< AttachmentPoint > needyAPsA, List< AttachmentPoint > lstB, List< AttachmentPoint > needyAPsB, APMapping fixedRootAPs, boolean screenAll, boolean onlyCompleteMappings, boolean compatibleIfFree)
Constructor that launches the search for a mapping between the AttachmentPoints on two lists.
static LinkedHashMap< AttachmentPoint, List< AttachmentPoint > > findMappingCompatibileAPs(List< AttachmentPoint > lstA, List< AttachmentPoint > lstB, boolean compatibleIfFree, FragmentSpace fragSpace)
Compares the AttachmentPoint of two lists searching for all the APs of the second list that are "comp...
boolean foundMapping()
Returns true if any mapping has been found.
List< APMapping > getAllAPMappings()
Returns all AttachmentPoint-AttachmentPoint mapping found.
static int maxCombs
Maximum number of combinations.
FragmentSpace fragSpace
Program-specific fragment space.
APMapFinder(FragmentSpace fragSpace, Vertex vA, Vertex vB, APMapping fixedRootAPs, boolean screenAll, boolean onlyCompleteMappings, boolean compatibleIfFree)
Constructor that launches the search for a mapping between the AttachmentPoints on the first vertex t...
void findAllMappings(List< AttachmentPoint > lstA, List< AttachmentPoint > needyAPsA, List< AttachmentPoint > lstB, List< AttachmentPoint > needyAPsB, APMapping fixedRootAPs, boolean screenAll, boolean onlyCompleteMappings, boolean compatibleIfFree)
Searches for mappings between the AttachmentPoints on the two lists.
APMapFinder(FragmentSpace fragSpace, Vertex vA, Vertex vB, boolean screenAll)
Constructor that launches the search for a mapping between the AttachmentPoints on the first vertex t...
Class defining a space of building blocks.
Randomizer getRandomizer()
Returns the program-specific randomizer that is associated with this program-specific fragment space.
boolean useAPclassBasedApproach()
Check usage of APClass-based approach, i.e., uses attachment points with annotated data (i....
Utility class for the fragment space.
static boolean recursiveCombiner(List< AttachmentPoint > keys, int currentKey, Map< AttachmentPoint, List< AttachmentPoint > > possibilities, APMapping combination, List< APMapping > completeCombinations, boolean screenAll, int maxCombs)
Search for all possible combinations of compatible APs.
boolean isCPMapCompatibleWith(APClass other, FragmentSpace fragSpace)
Check compatibility as defined in the compatibility matrix considering this AP as source and the othe...
Definition: APClass.java:455
Class representing a mapping between attachment points (APs).
Definition: APMapping.java:42
APMapping clone()
Shallow cloning.
Definition: APMapping.java:140
An attachment point (AP) is a possibility to attach a Vertex onto the vertex holding the AP (i....
APClass getAPClass()
Returns the Attachment Point class.
boolean isAvailableThroughout()
Check availability of this attachment point throughout the graph level, i.e., check also across the i...
AttachmentPoint getLinkedAPThroughout()
Gets the attachment point (AP) that is connected to this AP via the edge user or in any edge user tha...
List< AttachmentPoint > getInterfaceAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that represent the interface between a subgraph,...
Definition: DGraph.java:7113
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:61
DGraph getGraphOwner()
Returns the graph this vertex belongs to or null.
Definition: Vertex.java:779
abstract List< AttachmentPoint > getAttachmentPoints()
public< T > T randomlyChooseOne(Collection< T > c)
Chooses one member among the given collection.