| /******************************************************************************* |
| * Copyright (c) 2009, 2011 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; |
| } |
| } |