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

io.github.oliviercailloux.j_voting.preferences.classes.ImmutableCompletePreferenceImpl Maven / Gradle / Ivy

The newest version!
package io.github.oliviercailloux.j_voting.preferences.classes;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.graph.GraphBuilder;
import com.google.common.graph.ImmutableGraph;

import io.github.oliviercailloux.j_voting.Alternative;
import io.github.oliviercailloux.j_voting.Voter;
import io.github.oliviercailloux.j_voting.preferences.ImmutableCompletePreference;

/**
 * private ImmutableMap
 * asRanks(@SuppressWarnings("hiding") Graph graph) {
 *
 * From
 * https://github.com/jgrapht/jgrapht/blob/master/jgrapht-core/src/main/java/org/jgrapht/alg/connectivity/AbstractStrongConnectivityInspector.java:
 * find strongly connected components; map each alternative to its component;
 * then for each edge in the original graph, link the two components in the
 * output graph. Compute the transitive closure of the resulting graph. The rank
 * of each component is given by the number of components it reaches. Should
 * also check that the resulting component graph is linear.
 */
public class ImmutableCompletePreferenceImpl implements ImmutableCompletePreference {

	@SuppressWarnings("unused")
	private static final Logger LOGGER = LoggerFactory.getLogger(ImmutableCompletePreferenceImpl.class);
	private final Voter voter;
	private final ImmutableList> equivalenceClasses;
	private final ImmutableGraph graph;

	private final ImmutableMap ranks;

	/**
	 *
	 * @param equivalenceClasses  not null  the best equivalence class
	 *                           must be in first position. An alternative must be
	 *                           unique
	 */
	public static ImmutableCompletePreference given(Voter voter, List> equivalenceClasses) {
		checkNotNull(voter);
		checkNotNull(equivalenceClasses);
		return new ImmutableCompletePreferenceImpl(voter, equivalenceClasses);
	}

	protected ImmutableCompletePreferenceImpl(Voter voter, List> equivalenceClasses) {
		this.voter = checkNotNull(voter);
		this.equivalenceClasses = equivalenceClasses.stream().map(ImmutableSet::copyOf)
				.collect(ImmutableList.toImmutableList());
		this.graph = asGraph(equivalenceClasses);
		this.ranks = asRanks(equivalenceClasses);
	}

	private ImmutableGraph asGraph(
			@SuppressWarnings("hiding") List> equivalenceClasses) {
		final ImmutableGraph.Builder builder = GraphBuilder.directed().allowsSelfLoops(true).immutable();
		final Set alternativesSoFar = new LinkedHashSet<>();
		for (Set equivalenceClass : equivalenceClasses) {
			checkArgument(!equivalenceClass.isEmpty());
			for (Alternative current : equivalenceClass) {
				checkArgument(!alternativesSoFar.contains(current), "Duplicate: " + current + ".");

				for (Alternative previous : alternativesSoFar) {
					builder.putEdge(previous, current);
				}
				for (Alternative equivalent : equivalenceClass) {
					builder.putEdge(equivalent, current);
				}
			}
			alternativesSoFar.addAll(equivalenceClass);
		}
		return builder.build();
	}

	private ImmutableMap asRanks(
			@SuppressWarnings("hiding") List> equivalenceClasses) {
		int rank = 1;
		final ImmutableMap.Builder builder = ImmutableMap.builder();
		for (Set equivalenceClass : equivalenceClasses) {
			for (Alternative alternative : equivalenceClass) {
				builder.put(alternative, rank);
			}
			++rank;
		}
		return builder.build();
	}

	@Override
	public Voter getVoter() {
		return this.voter;
	}

	@Override
	public ImmutableSet getAlternatives() {
		return ranks.keySet();
	}

	@Override
	public int getRank(Alternative a) {
		final Integer rank = ranks.get(a);
		if (rank == null) {
			throw new NoSuchElementException(a.toString());
		}
		return rank;
	}

	@Override
	public ImmutableSet getAlternatives(int rank) {
		return equivalenceClasses.get(rank - 1);
	}

	@Override
	public ImmutableList> asEquivalenceClasses() {
		return equivalenceClasses;
	}

	@Override
	public ImmutableGraph asGraph() {
		return graph;
	}

	public boolean isAntiSymmetric() {
		return (equivalenceClasses.size() == ranks.size());
	}

	@Override
	public boolean equals(Object o2) {
		if (!(o2 instanceof ImmutableCompletePreferenceImpl)) {
			return false;
		}
		ImmutableCompletePreferenceImpl other = (ImmutableCompletePreferenceImpl) o2;
		return Objects.equals(voter, other.voter) && Objects.equals(equivalenceClasses, other.equivalenceClasses);
	}

	@Override
	public int hashCode() {
		return Objects.hash(voter, equivalenceClasses);
	}

	@Override
	public String toString() {
		return MoreObjects.toStringHelper(this).add("Voter", voter).add("Equivalence classes", equivalenceClasses)
				.toString();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy