/******************************************************************************* * Copyright (c) 2009, 2010 SAP AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * SAP AG - initial API and implementation ******************************************************************************/ package org.eclipse.ocl.examples.impactanalyzer.benchmark.preparation.model; import java.util.ArrayList; import java.util.Collection; import java.util.List; import modelmanagement.Package; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; /** * The {@link IncrementalResourceShrinker} class is responsible for cutting down * the size of emf models in one emf resource by removing packages and its model * elements bit by bit according to a dependency graph * * This class may be used for varying the size of models for benchmarking. * * @author Manuel Holzleitner (D049667) */ public class IncrementalResourceShrinker { public Collection<Resource> shrinkIncrementally(Resource fullSizeResource){ ArrayList<Resource> result = new ArrayList<Resource>(); int cloneId = 0; Resource nextResourceToShrink = ModelCloner.cloneResource(fullSizeResource, String.valueOf(cloneId)); while(deletePackageWithFewestDependencies(nextResourceToShrink) >= 1){ cloneId++; result.add(nextResourceToShrink); nextResourceToShrink = ModelCloner.cloneResource(nextResourceToShrink, String.valueOf(cloneId)); } return result; } //FIXME: Needs refactoring. Extract combinational shrinking public void shrinkCombinational(Resource parent, ArrayList<Resource> result, ArrayList<Integer> visitedSizes){ PackageDependencyGraph dependencyGraph = new PackageDependencyGraph(parent); List<Package> packageToDeleteList = calculatePossiblePackagesToDelete(dependencyGraph); List<Resource> cloneList = new ArrayList<Resource>(); List<PackageDependencyGraph> dependencyGraphList = new ArrayList<PackageDependencyGraph>(); for(int i=0; i < packageToDeleteList.size(); i++){ Resource clone = ModelCloner.cloneResource(parent, String.valueOf(i)); cloneList.add(clone); //List of packages which should be deleted of parent is not applicable for cloned resources //Therefore recalculate packages to delete on clones and pick one alternative PackageDependencyGraph cloneDependencyGraph = new PackageDependencyGraph(clone); dependencyGraphList.add(cloneDependencyGraph); List<Package> clonePackageToDeleteList = calculatePossiblePackagesToDelete(cloneDependencyGraph); if(cloneDependencyGraph.getNumberOfPackages() > 1){ deletePackage(clonePackageToDeleteList.get(i), cloneDependencyGraph); int numberOfElementsInChild = getNumberOfElements(clone); if(!visitedSizes.contains(new Integer(numberOfElementsInChild))){ result.add(clone); visitedSizes.add(numberOfElementsInChild); } System.out.println(visitedSizes.size()); } } for(int i=0; i < packageToDeleteList.size(); i++){ if(dependencyGraphList.get(i).getNumberOfPackages() > 1 && visitedSizes.size() < 108){ shrinkCombinational(cloneList.get(i), result, visitedSizes); } } } private int getNumberOfElements(Resource resource){ int resourceSize = 0; TreeIterator<EObject> iterator = resource.getAllContents(); while (iterator.hasNext()) { iterator.next(); resourceSize++; } return resourceSize; } private int deletePackageWithFewestDependencies(Resource resourceToShrink){ //TODO: Actually, rebuilding the dependency graph should not be required for deleting the next package. Therefore, ensure // that after deleting a package the dependency graph is updated accordingly. PackageDependencyGraph dependencyGraph = new PackageDependencyGraph(resourceToShrink); ArrayList<Package> packagesToDeleteList = calculatePossiblePackagesToDelete(dependencyGraph); deletePackage(getPackageWithFewestDependencies(packagesToDeleteList, dependencyGraph), dependencyGraph); return dependencyGraph.getNumberOfPackages(); } private ArrayList<Package> calculatePossiblePackagesToDelete(PackageDependencyGraph dependencyGraph) { int smallestAmountOfReferences = Integer.MAX_VALUE; for (Package pack : dependencyGraph.getAllPackages()) { if (getListWithoutDuplicates(dependencyGraph.getDependencies().get(pack)).size() < smallestAmountOfReferences) { smallestAmountOfReferences = getListWithoutDuplicates(dependencyGraph.getDependencies().get(pack)).size(); } } ArrayList<Package> packagesToDeleteList = new ArrayList<Package>(); for (Package pack : dependencyGraph.getAllPackages()) { if (getListWithoutDuplicates(dependencyGraph.getDependencies().get(pack)).size() == smallestAmountOfReferences) { packagesToDeleteList.add(pack); } } return packagesToDeleteList; } private Package getPackageWithFewestDependencies(ArrayList<Package> packagesToDeleteList, PackageDependencyGraph dependencyGraph){ Package packageToDelete = null; if(packagesToDeleteList.size() == 1){ //System.out.println("match"); packageToDelete = packagesToDeleteList.get(0); }else if(packagesToDeleteList.size() > 1){ //System.out.println("choose"); packageToDelete = chooseBestPackageToDelete(packagesToDeleteList, dependencyGraph); } return packageToDelete; } private Package chooseBestPackageToDelete(ArrayList<Package> packagesToDeleteList, PackageDependencyGraph dependencyGraph) { Package packageToDelete = packagesToDeleteList.get(0); for(Package deletionCandidate : packagesToDeleteList){ if(dependencyGraph.getDependencies().get(deletionCandidate).size() < dependencyGraph.getDependencies().get(packageToDelete).size()){ packageToDelete = deletionCandidate; } } //System.out.println(dependencyGraph.getDependencies().get(packageToDelete).size()); return packageToDelete; } private Package deletePackage(Package packageToDelete, PackageDependencyGraph dependencyGraph) { Package deletedPackage = null; System.out.println("\t\t\tDelete package: " + packageToDelete); //EcoreUtil.delete(packageToDelete, true); //packageWasDeleted = true; //deletedPackage = packageToDelete; for (Package key : dependencyGraph.getAllPackages()) { if (key != null && key.equals(packageToDelete)) { /*System.out.println("Elements: " + aggregatedElements.get(key).size()); for (EObject elementToDelete : aggregatedElements.get(key)) { if(!(elementToDelete instanceof Package)) { EcoreUtil.delete(elementToDelete); } // System.out.println("\t\t\t\t\tdeleted:" + elementToDelete); }*/ EcoreUtil.delete(key, true); deletedPackage = key; } } dependencyGraph.removePackage(packageToDelete); return deletedPackage; } /* TODO: Delete this commented debug code in final implementation for (Package key : dependencies.keySet()) { System.out.println("P: " + key + " Number:" + dependencies.get(key).size() + " Elements:" + aggregatedElements.get(key).size()); for (Package subPackage : dependencies.get(key)) { System.out.println("\t\t" + subPackage); } } System.out.println(aggregatedElements.size() + "/" + modelElementList.size() + "/" + dependencies.size()); */ private <T> ArrayList<T> getListWithoutDuplicates(List<T> arlList) { ArrayList<T> result = new ArrayList<T>(arlList.size()); java.util.HashSet<T> h = new java.util.HashSet<T>(arlList); result.addAll(h); return result; } }