package it.univr.di.labeledvalue; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.AbstractObject2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArraySet; import it.unimi.dsi.fastutil.objects.ObjectSet; import it.univr.di.Debug; /** * Simple implementation of {@link it.univr.di.labeledvalue.LabeledIntMap} interface. *
* An experimental result on 2016-01-13 showed that using base there is a small improvement in the performance. *
l
* An experiment result on 2016-01-13 showed that using base there is a small improvement in the performance. * * @param l * @return true if l is a component of the base, false otherwise. */ private boolean checkValidityOfTheBaseAfterRemoving(final Label l) { if ((this.base.length == 0) || (l.size() == 0) || (l.size() != this.base.length) || l.containsUnknown()) return false; // l and base have same length. for (char c : this.base) { if (!l.contains(c)) return false; } // l is a component of the base and it was removed. this.base = emptyBase; return true; } /** * Tries to add all given labeled values into the current map: *
inputValue
inputLabel
(l,v)
v
* An experiment result on 2016-01-13 showed that using base there is a small improvement in the performance. * * @param inputLabel * @param inputValue * @return true if inputValue is greater or equal than a base component value that is subsumed by inputLabel. False otherwise. */ private boolean isBaseAbleToRepresent(final Label inputLabel, final int inputValue) { if (this.base == emptyBase) return false; final Object2IntMap map1 = this.mainInt2SetMap.get(this.base.length); for (final Label baseLabel : Label.allComponentsOfBaseGenerator(this.base)) { final int baseValue = map1.getInt(baseLabel); if (baseValue == Constants.INT_NULL) { if (Debug.ON) if (LOG.isLoggable(Level.SEVERE)) { LabeledIntTreeMap.LOG.severe("The base is not sound: base=" + Arrays.toString(this.base) + ". Map1=" + map1); } this.base = emptyBase; return false; // throw new IllegalStateException("A base component has a null value. It is not possible."); } if (inputLabel.subsumes(baseLabel)) { if (inputLabel.size() == baseLabel.size()) { // inputLabel subsumes all the literals of baseLabel and it has no more literals. // so, they are equal or unknown. return true; } if (inputValue >= baseValue) { // entry.setValue(baseValue);// case 6 return true; } return false; } if (inputLabel.isConsistentWith(baseLabel)) { if (inputValue < baseValue) { return false; } } } return true; } /** * If entry (label, value) determines a new (better) base, the base is updated. * An experiment result on 2016-01-13 showed that using base there is a small improvement in the performance. * * @param entry * @return true if (label, value) determine a new (better) base. If true, the base is update. False otherwise. */ private boolean makeABetterBase(final Entry entry) { if (entry.getIntValue() == Constants.INT_NULL) return false; final int n = entry.getKey().size(); if (n == 0) { // The new labeled value (l,v) has universal label, the base is not more necessary! this.base = emptyBase; return true; } final Object2IntMap map1 = this.mainInt2SetMap.get(n); if (map1.size() < Math.pow(2.0, n)) // there are no sufficient elements! return false; final char[] baseCandidateColl = entry.getKey().getPropositions(); for (final Label label1 : Label.allComponentsOfBaseGenerator(baseCandidateColl)) { int value = map1.getInt(label1); if (value == Constants.INT_NULL) return false; } this.base = baseCandidateColl; return true; } /** * Remove all labeled values that subsume l and have values greater or equal to i. * * @param inputLabel * @param inputValue * @return true if one element at least has been removed, false otherwise. */ private boolean removeAllValuesGreaterThan(final Label inputLabel, final int inputValue) { if (inputLabel == null || inputValue == Constants.INT_NULL) return false; boolean removed = false; final int inputLabelSize = inputLabel.size(); for (int labelLenght : this.mainInt2SetMap.keySet()) { if (labelLenght < inputLabelSize) continue; final Object2IntMap internalMap = this.mainInt2SetMap.get(labelLenght); // BE CAREFUL! Since it is necessary to remove, it is not possible to use internalMap.keySet() directly // because removing an element in the map changes the keyset and it is possible to loose the checking of some label (the following // one a deleted element). // Iterator are not rightly implemented as 2019-03-30! // The last resource is to copy the labeled value set ObjectSet labels = new ObjectArraySet<>(internalMap.keySet()); for (Label currentLabel : labels) { final int currentValue = internalMap.getInt(currentLabel); if ((currentValue >= inputValue) && currentLabel.subsumes(inputLabel)) { if (Debug.ON) { if (LOG.isLoggable(Level.FINEST)) { LOG.log(Level.FINEST, "New label " + inputLabel + " induces a remove of (" + currentLabel + ", " + currentValue + ")"); } } internalMap.removeInt(currentLabel); this.count--; this.checkValidityOfTheBaseAfterRemoving(currentLabel); removed = true; } } } return removed; } /** * Remove all labeled values having each value greater than all values of base components consistent with it. * An experiment result on 2016-01-13 showed that using base there is a small improvement in the performance. * * @return true if one element at least has been removed, false otherwise. */ private boolean removeAllValuesGreaterThanBase() { if ((this.base == null) || (this.base.length == 0)) return false; final LabeledIntTreeMap newMap = new LabeledIntTreeMap(); // build the list of labeled values that form the base final ObjectArrayList> baseComponent = new ObjectArrayList<>((int) Math.pow(2, this.base.length)); for (final Label l : Label.allComponentsOfBaseGenerator(this.base)) { baseComponent.add(new AbstractObject2IntMap.BasicEntry<>(l, this.get(l))); } Label l1, lb; int v1, vb; boolean toInsert = true; for (final Object2IntMap map1 : this.mainInt2SetMap.values()) { for (final Entry entry : map1.object2IntEntrySet()) { l1 = entry.getKey(); v1 = entry.getIntValue(); toInsert = false; for (final Entry baseEntry : baseComponent) { lb = baseEntry.getKey(); vb = baseEntry.getIntValue(); if (l1.equals(lb)) { toInsert = true; // a base component has to be always insert! break; } if (l1.isConsistentWith(lb) && v1 < vb) {// isConsistent is necessary to manage cases like base = {(b,3)(¬b,4)} l1={(a,1)} toInsert = true; break; } } if (toInsert) { newMap.putForcibly(l1, v1); } } } if (!newMap.equals(this)) { if (Debug.ON) { if (LOG.isLoggable(Level.FINEST)) { LOG.finest("Base changed: the old map " + this.toString() + " is subsituted by " + newMap.toString()); } } this.mainInt2SetMap = newMap.mainInt2SetMap; this.count = newMap.count; return true; } return false; } }
i