Skip to content

Commit

Permalink
Add Projector classes from P2
Browse files Browse the repository at this point in the history
  • Loading branch information
laeubi committed Jan 22, 2024
1 parent 9cd0883 commit da6ff7d
Show file tree
Hide file tree
Showing 4 changed files with 1,614 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2006, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.p2tools.copiedfromp2;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ProgressMonitorWrapper;

/**
* This class provides a simulation of progress. This is useful for situations where computing the
* amount of work to do in advance is too costly. The monitor will accept any number of calls to
* {@link #worked(int)}, and will scale the actual reported work appropriately so that the progress
* never quite completes.
*/
class InfiniteProgress extends ProgressMonitorWrapper {
/*
* Fields for progress monitoring algorithm. Initially, give progress for every 4 resources,
* double this value at halfway point, then reset halfway point to be half of remaining work.
* (this gives an infinite series that converges at total work after an infinite number of
* resources).
*/
private int totalWork;
private int currentIncrement = 4;
private int halfWay;
private int nextProgress = currentIncrement;
private int worked = 0;

protected InfiniteProgress(IProgressMonitor monitor) {
super(monitor);
}

@Override
public void beginTask(String name, int work) {
super.beginTask(name, work);
this.totalWork = work;
this.halfWay = totalWork / 2;
}

@Override
public void worked(int work) {
if (--nextProgress <= 0) {
//we have exhausted the current increment, so report progress
super.worked(1);
worked++;
if (worked >= halfWay) {
//we have passed the current halfway point, so double the
//increment and reset the halfway point.
currentIncrement *= 2;
halfWay += (totalWork - halfWay) / 2;
}
//reset the progress counter to another full increment
nextProgress = currentIncrement;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*******************************************************************************
* Copyright (c) 2013, 2018 Rapicorp Inc. and others.
*
* This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License 2.0 which accompanies this distribution, and is
* available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Rapicorp, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.tycho.p2tools.copiedfromp2;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IInstallableUnitPatch;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.query.Collector;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.IQueryable;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.tycho.p2tools.copiedfromp2.Projector.AbstractVariable;
import org.sat4j.pb.tools.WeightedObject;

public class OptimizationFunction {

private IQueryable<IInstallableUnit> picker;
private IInstallableUnit selectionContext;
protected Map<String, Map<Version, IInstallableUnit>> slice; //The IUs that have been considered to be part of the problem
private IQueryable<IInstallableUnit> lastState;
private List<AbstractVariable> optionalRequirementVariable;

public OptimizationFunction(IQueryable<IInstallableUnit> lastState, List<AbstractVariable> abstractVariables,
List<AbstractVariable> optionalRequirementVariable, IQueryable<IInstallableUnit> picker,
IInstallableUnit selectionContext, Map<String, Map<Version, IInstallableUnit>> slice) {
this.lastState = lastState;
this.optionalRequirementVariable = optionalRequirementVariable;
this.picker = picker;
this.selectionContext = selectionContext;
this.slice = slice;
}

//Create an optimization function favoring the highest version of each IU
public List<WeightedObject<? extends Object>> createOptimizationFunction(IInstallableUnit metaIu,
Collection<IInstallableUnit> newRoots) {
int numberOfInstalledIUs = sizeOf(lastState);
List<WeightedObject<? extends Object>> weightedObjects = new ArrayList<>();

Set<IInstallableUnit> transitiveClosure; //The transitive closure of the IUs we are adding (this also means updating)
if (newRoots.isEmpty()) {
transitiveClosure = Collections.emptySet();
} else {
IQueryable<IInstallableUnit> queryable = new Slicer(picker, selectionContext, false).slice(newRoots, null);
if (queryable == null) {
transitiveClosure = Collections.emptySet();
} else {
transitiveClosure = queryable.query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).toSet();
}
}

Set<Entry<String, Map<Version, IInstallableUnit>>> s = slice.entrySet();
final BigInteger POWER = BigInteger.valueOf(numberOfInstalledIUs > 0 ? numberOfInstalledIUs + 1 : 2);

BigInteger maxWeight = POWER;
for (Entry<String, Map<Version, IInstallableUnit>> entry : s) {
List<IInstallableUnit> conflictingEntries = new ArrayList<>(entry.getValue().values());
if (conflictingEntries.size() == 1) {
//Only one IU exists with the namespace.
IInstallableUnit iu = conflictingEntries.get(0);
if (iu != metaIu) {
weightedObjects.add(WeightedObject.newWO(iu, POWER));
}
continue;
}

// Set the weight such that things that are already installed are not updated
conflictingEntries.sort(Collections.reverseOrder());
BigInteger weight = POWER;
// have we already found a version that is already installed?
boolean foundInstalled = false;
// have we already found a version that is in the new roots?
boolean foundRoot = false;
for (IInstallableUnit iu : conflictingEntries) {
if (!foundRoot && isInstalled(iu) && !transitiveClosure.contains(iu)) {
foundInstalled = true;
weightedObjects.add(WeightedObject.newWO(iu, BigInteger.ONE));
} else if (!foundInstalled && !foundRoot && isRoot(iu, newRoots)) {
foundRoot = true;
weightedObjects.add(WeightedObject.newWO(iu, BigInteger.ONE));
} else {
weightedObjects.add(WeightedObject.newWO(iu, weight));
}
weight = weight.multiply(POWER);
}
if (weight.compareTo(maxWeight) > 0)
maxWeight = weight;
}

// no need to add one here, since maxWeight is strictly greater than the
// maximal weight used so far.
maxWeight = maxWeight.multiply(POWER).multiply(BigInteger.valueOf(s.size()));

// Add the optional variables
BigInteger optionalVarWeight = maxWeight.negate();
for (AbstractVariable var : optionalRequirementVariable) {
weightedObjects.add(WeightedObject.newWO(var, optionalVarWeight));
}

maxWeight = maxWeight.multiply(POWER).add(BigInteger.ONE);

//Now we deal the optional IUs,
long countOptional = 1;
List<IInstallableUnit> requestedPatches = new ArrayList<>();
for (IRequirement req : metaIu.getRequirements()) {
if (req.getMin() > 0 || !req.isGreedy())
continue;
for (IInstallableUnit match : picker.query(QueryUtil.createMatchQuery(req.getMatches()), null)) {
if (match instanceof IInstallableUnitPatch) {
requestedPatches.add(match);
countOptional = countOptional + 1;
}
}
}

// and we make sure that patches are always favored
BigInteger patchWeight = maxWeight.multiply(POWER).multiply(BigInteger.valueOf(countOptional)).negate();
for (IInstallableUnit iu : requestedPatches) {
weightedObjects.add(WeightedObject.newWO(iu, patchWeight));
}
return weightedObjects;
}

protected boolean isInstalled(IInstallableUnit iu) {
return !lastState.query(QueryUtil.createIUQuery(iu), null).isEmpty();
}

private boolean isRoot(IInstallableUnit iu, Collection<IInstallableUnit> newRoots) {
return newRoots.contains(iu);
}

/**
* Efficiently compute the size of a queryable
*/
private int sizeOf(IQueryable<IInstallableUnit> installedIUs) {
IQueryResult<IInstallableUnit> qr = installedIUs.query(QueryUtil.createIUAnyQuery(), null);
if (qr instanceof Collector<?>)
return ((Collector<?>) qr).size();
return qr.toUnmodifiableSet().size();
}

}
Loading

0 comments on commit da6ff7d

Please sign in to comment.