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

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

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
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.base.Preconditions;
import com.google.common.base.VerifyException;
import com.google.common.collect.ForwardingIterator;
import com.google.common.collect.ForwardingSet;
import com.google.common.graph.Graph;
import com.google.common.graph.GraphBuilder;
import com.google.common.graph.MutableGraph;

import io.github.oliviercailloux.j_voting.Alternative;
import io.github.oliviercailloux.j_voting.Voter;
import io.github.oliviercailloux.j_voting.graph.GraphView;
import io.github.oliviercailloux.j_voting.preferences.MutableLinearPreference;

public class MutableLinearPreferenceImpl implements MutableLinearPreference {

	private Voter voter;
	private MutableGraph graph;
	private Set alternatives;
	private List list;

	@SuppressWarnings("unused")
	private static final Logger LOGGER = LoggerFactory.getLogger(MutableLinearPreferenceImpl.class);

	private MutableLinearPreferenceImpl(Voter voter, List list) {

		this.voter = voter;
		this.list = new ArrayList<>(list);
		this.graph = GraphBuilder.directed().allowsSelfLoops(true).build();

		for (int i = 0; i < list.size(); i++) {
			for (int j = i; j < list.size(); j++) {
				graph.putEdge(list.get(i), list.get(j));
			}
		}
		this.alternatives = graph.nodes();
	}

	@Override
	public String toString() {
		return MoreObjects.toStringHelper(this).add("Voter", voter).add("Graph", graph).add("Set", alternatives)
				.add("List", list).toString();
	}

	/**
	 * @param list  is a List of alternatives representing the preference.
	 * @param voter is the Voter associated to the Preference.
	 * @return the mutable linear preference
	 */
	public static MutableLinearPreference given(Voter voter, List list) {
		LOGGER.debug("MutableLinearPreferenceImpl given");
		Preconditions.checkNotNull(voter);
		Preconditions.checkNotNull(list);

		return new MutableLinearPreferenceImpl(voter, list);
	}

	@Override
	public boolean changeOrder(Alternative alternative, int rank) {
		LOGGER.debug("MutableLinearPreferenceImpl tries to changeOrder of " + alternative + " at " + rank + " rank.");
		Preconditions.checkNotNull(alternative);
		Preconditions.checkNotNull(rank);

		if (list.indexOf(alternative) == rank || !(list.contains(alternative)) || rank < 1 || rank > list.size()) {
			return false;
		}

		int initRank = list.indexOf(alternative);
		Alternative temp;

		if (initRank > rank) {
			for (int i = initRank; i >= rank; i--) {
				temp = list.get(i - 1);
				swap(temp, alternative);
			}
		} else if (initRank < rank) {
			for (int i = initRank; i <= rank; i++) {
				temp = list.get(i - 1);
				swap(alternative, temp);
			}
		}
		return true;
	}

	@Override
	public boolean removeAlternative(Alternative a) {
		LOGGER.debug("MutableLinearPreferenceImpl deleteAlternative");
		Preconditions.checkNotNull(a);

		if (alternatives.contains(a)) {
			graph.removeNode(a);
			list.remove(a);
			return true;
		}
		return false;
	}

	@Override
	public boolean addAlternative(Alternative a) {
		LOGGER.debug("MutablePreferenceImpl addAlternative");
		Preconditions.checkNotNull(a);

		if (alternatives.contains(a)) {
			return false;
		}

		list.add(a);
		graph.addNode(a);

		for (Alternative element : list) {
			graph.putEdge(element, list.get(list.size() - 1));
		}
		return true;
	}

	/**
	 * Clears the MutableLinearPreference (list + set + graph)
	 */
	private void clear() {
		for (Alternative element : list) {
			graph.removeNode(element);
		}
		list.clear();
	}

	@Override
	public Set getAlternatives() {
		LOGGER.debug("MutableLinearPreferenceImpl getAlternatives");
		return new MutableLinearSetDecorator(this);
	}

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

	@Override
	public Graph asGraph() {
		return GraphView.decorate(this.graph);
	}

	@Override
	public boolean swap(Alternative alternative1, Alternative alternative2) {
		LOGGER.debug("MutablePreferenceImpl Swap");
		Preconditions.checkNotNull(alternative1);
		Preconditions.checkNotNull(alternative2);

		if (alternative1.equals(alternative2) || !(alternatives.contains(alternative1))
				|| !(alternatives.contains(alternative2))) {
			return false;
		}

		boolean op1, op2, op3, op4;

		Alternative best = alternative1;
		Alternative worst = alternative2;

		if (list.indexOf(alternative1) > list.indexOf(alternative2)) {
			best = alternative2;
			worst = alternative1;
		}

		List subList = list.subList(list.indexOf(best) + 1, list.indexOf(worst));

		for (Alternative a : subList) {

			op1 = graph.removeEdge(best, a);
			op2 = graph.putEdge(a, best);
			op3 = graph.removeEdge(a, worst);
			op4 = graph.putEdge(worst, a);

			if (!(op1 && op2 && op3 && op4)) {
				throw new VerifyException("There might be a bug in the stucture.");
			}
		}

		op1 = graph.removeEdge(best, worst);
		op2 = graph.putEdge(worst, best);

		if (!(op1 && op2)) {
			throw new VerifyException("There might be a bug in the stucture.");
		}

		Collections.swap(list, list.indexOf(alternative1), list.indexOf(alternative2));

		return true;
	}

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

	@Override
	public boolean equals(Object o2) {
		if (!(o2 instanceof MutableLinearPreferenceImpl)) {
			return false;
		}
		if (this == o2) {
			return true;
		}
		MutableLinearPreferenceImpl mlp2 = (MutableLinearPreferenceImpl) o2;
		return voter.equals(mlp2.voter) && list.equals(mlp2.list);
	}

	/**
	 * In the future, ideally, sets returned via this decorator should be protected
	 * from alteration.
	 */
	public static class MutableLinearSetDecorator extends ForwardingSet {
		private MutableLinearPreferenceImpl delegate;

		private MutableLinearSetDecorator(MutableLinearPreferenceImpl delegate) {
			this.delegate = delegate;
		}

		@Override
		protected Set delegate() {
			return delegate.alternatives;
		}

		@Override
		public boolean add(Alternative a) {
			LOGGER.debug("MutableLinearSetDecorator add");
			return delegate.addAlternative(a);
		}

		@Override
		public boolean addAll(Collection c) {
			LOGGER.debug("MutableLinearSetDecorator delegate addAll");
			return standardAddAll(c);
		}

		@Override
		public boolean remove(Object o) {
			LOGGER.debug("MutableLinearSetDecorator delegate remove");

			if (o instanceof Alternative) {
				Alternative a = (Alternative) o;
				if (delegate.getAlternatives().contains(a)) {
					return delegate.removeAlternative(a);
				}
			}
			return false;
		}

		@Override
		public boolean removeAll(Collection c) {
			LOGGER.debug("MutableLinearSetDecorator delegate removeAll");
			return standardRemoveAll(c);
		}

		@Override
		public void clear() {
			LOGGER.debug("MutableLinearSetDecorator delegate clear");
			delegate.clear();
		}

		@Override
		public boolean retainAll(Collection c) {
			LOGGER.debug("MutableLinearSetDecorator delegate retainAll");
			return standardRetainAll(c);
		}

		@Override
		public Iterator iterator() {
			LOGGER.debug("MutableLinearSetDecorator delegate iterator");
			return new MutableLinearIteratorDecorator(delegate.list.iterator());
		}
	}

	public static class MutableLinearIteratorDecorator extends ForwardingIterator {

		private Iterator iteratorDelegate;

		@Override
		protected Iterator delegate() {
			return iteratorDelegate;
		}

		private MutableLinearIteratorDecorator(Iterator iteratorDelegate) {
			this.iteratorDelegate = iteratorDelegate;
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy