All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openlca.util.ProviderChainRemoval Maven / Gradle / Ivy

The newest version!
package org.openlca.util;

import org.openlca.core.model.ProcessLink;
import org.openlca.core.model.ProductSystem;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ProviderChainRemoval {

	private final ProductSystem system;
	private final long ref;
	private final Map> inLinks;
	private final Map> outLinks;

	private ProviderChainRemoval(ProductSystem system) {
		this.system = system;
		this.ref = system.referenceProcess != null
				? system.referenceProcess.id
				: 0L;
		this.inLinks = new HashMap<>();
		this.outLinks = new HashMap<>();
		for (var link : system.processLinks) {
			inLinks.computeIfAbsent(
							link.processId, $ -> new ArrayList<>())
					.add(link);
			outLinks.computeIfAbsent(
							link.providerId, $ -> new ArrayList<>())
					.add(link);
		}
	}

	public static ProviderChainRemoval on(ProductSystem system) {
		return new ProviderChainRemoval(system);
	}

	/**
	 * Removes the given link from the product system and the subgraph G with
	 * the provider of the link as root if G is not connected to the reference
	 * process anymore.
	 * Returns the set of process links that were deleted.
	 */
	public Set remove(ProcessLink link) {
		if (link == null)
			return Collections.emptySet();
		removeLink(link);

		if (link.providerId == ref)
			return Set.of(link);

		var clusterLinks = removeCluster(link.providerId);
		var allLinks =  new HashSet();
		allLinks.add(link);
		allLinks.addAll(clusterLinks);
		return allLinks;
	}

	private List removeCluster(long root) {
		var links = new ArrayList();
		var queue = new ArrayDeque();
		var handled = new HashSet();
		queue.add(root);
		while (!queue.isEmpty()) {
			var next = queue.poll();
			handled.add(next);

			// check outgoing links first because a
			// possible link to the reference process
			// could be found faster this way
			var outList = outLinks.get(next);
			if (outList != null) {
				for (var link : outList) {
					if (link.processId == ref)
						return Collections.emptyList();
					links.add(link);
					Long process = link.processId;
					if (!handled.contains(process)
							&& !queue.contains(process)) {
						queue.add(process);
					}
				}
			}

			var inList = inLinks.get(next);
			if (inList != null) {
				for (var link : inList) {
					if (link.providerId == ref)
						return Collections.emptyList();
					links.add(link);
					Long provider = link.providerId;
					if (!handled.contains(provider)
							&& !queue.contains(provider)) {
						queue.add(provider);
					}
				}
			}
		}

		system.processes.removeAll(handled);
		for (var link : links) {
			removeLink(link);
		}
		return links;
	}

	private void removeLink(ProcessLink link) {
		system.processLinks.remove(link);
		var inList = inLinks.get(link.processId);
		if (inList != null) {
			inList.remove(link);
		}
		var outList = outLinks.get(link.providerId);
		if (outList != null) {
			outList.remove(link);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy