Input:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import edu.uky.cs.nil.sabre.Character;
import edu.uky.cs.nil.sabre.Settings;
import edu.uky.cs.nil.sabre.Signature;
import edu.uky.cs.nil.sabre.Utilities;
import edu.uky.cs.nil.sabre.comp.CompiledAction;
import edu.uky.cs.nil.sabre.comp.CompiledEvent;
import edu.uky.cs.nil.sabre.comp.CompiledFluent;
import edu.uky.cs.nil.sabre.comp.CompiledMapping;
import edu.uky.cs.nil.sabre.comp.CompiledProblem;
import edu.uky.cs.nil.sabre.logic.Clause;
import edu.uky.cs.nil.sabre.logic.Disjunction;
import edu.uky.cs.nil.sabre.logic.Effect;
import edu.uky.cs.nil.sabre.logic.False;
import edu.uky.cs.nil.sabre.logic.Parameter;
import edu.uky.cs.nil.sabre.logic.Precondition;
import edu.uky.cs.nil.sabre.logic.True;
import edu.uky.cs.nil.sabre.logic.Value;
import edu.uky.cs.nil.sabre.util.ImmutableSet;

Context:
src/edu/uky/cs/nil/sabre/ptree/EventList.java
package edu.uky.cs.nil.sabre.ptree;

/**
 * A list of {@link CompiledEvent compiled events} (including dummy belief
 * update actions) and their effect for use in a {@link ProgressionTree
 * progression tree}.
 *
 * @author Stephen G. Ware
 */
final class EventList implements Serializable {

	/**
	 * A key for storing a belief update dummy action in a {@link HashMap
	 * hashtable}.
	 *
	 * @author Stephen G. Ware
	 */
	private final class UpdateKey implements Serializable {

		/** Serial version ID */
		private static final long serialVersionUID = 1L;

		/** The character whose beliefs will be updated */
		public Character character;

		/** The fluent whose value will be set */
		public CompiledFluent fluent;

		/** The value to set the fluent to */
		public Value value;

		/**
		 * Constructs a new dummy belief update action key.
		 *
		 * @param character the character whose beliefs will be updated
		 * @param fluent the fluent whose value will be set
		 * @param value the value to set the fluent to
		 */
		public UpdateKey(Character character, CompiledFluent fluent, Value value) {
			this.character = character;
			this.fluent = fluent;
			this.value = value;
		}

		@Override
		public boolean equals(Object other) {
			if(other instanceof UpdateKey) {
				UpdateKey otherKey = (UpdateKey) other;
				return character.equals(otherKey.character) && fluent.equals(otherKey.fluent) && value.equals(otherKey.value);
			}
			return false;
		}

		@Override
		public int hashCode() {
			return Utilities.hashCode(character, fluent, value);
		}
	}

	/** Serial version ID */
	private static final long serialVersionUID = Settings.VERSION_UID;

	/** A list of all events by ID, including dummy belief update events */
	private final ArrayList<CompiledEvent> events;

	/** A map of dummy belief update actions */
	private final HashMap<UpdateKey, CompiledEvent> updates;

	/** A key used to look up dummy belief update actions in {@link #updates} */
	private final UpdateKey key = new UpdateKey(null, null, null);

	/**
	 * A table of each event's effect for each fluent; the first array is
	 * indexed by {@link CompiledEvent#getID() the event ID}, and the second
	 * array is indexed by {@link CompiledFluent#id the fluent ID}
	 */
	private final Clause<Effect>[][] effects;

	/**
	 * Constructs a new event list.
	 *
	 * @param problem the compiled problem whose events will be indexed
	 */
	@SuppressWarnings("unchecked")
	public EventList(CompiledProblem problem) {
		this.events = new ArrayList<>((int) (((double) problem.events.size()) * 1.2));
		for(CompiledEvent event : problem.events)
			this.events.add(event);
		this.updates = new HashMap<>(this.events.size() - problem.events.size());
		this.effects = new Clause[problem.events.size()][problem.fluents.size()];
		for(CompiledEvent event : problem.events)
			for(CompiledFluent fluent : problem.fluents)
				this.effects[event.getID()][fluent.id] = effect(event, fluent);
	}

	private static final Clause<Effect> effect(CompiledEvent event, CompiledFluent fluent) {
		Clause<Effect> effect = event.getEffect(fluent);
		return effect.equals(Clause.EMPTY) ? null : effect;
	}

	/**
	 * Returns the compiled event with the given {@link CompiledEvent#getID()
	 * ID number}, including any dummy belief update actions that have been
	 * {@link #getUpdate(Character, CompiledFluent, Value) created} by this list.
	 *
	 * @param id the ID number of the event
	 * @return the event with that ID number
	 */
	public CompiledEvent getEvent(int id) {
		return events.get(id);
	}

	/**
	 * Returns a compiled action defined like a {@link
	 * edu.uky.cs.nil.sabre.graph.DummyAction#update(Character, edu.uky.cs.nil.sabre.Event, edu.uky.cs.nil.sabre.State)
	 * dummy belief update action}. The action always has {@link False#FALSE
	 * false} as its precondition, a single effect setting a fluent to a value,
	 * no consenting characters, and a single observing character whose beliefs
	 * are being updated by the action. If no such action has been created by
	 * this list yet, this method will create one.
	 *
	 * @param character the character whose beliefs will be updated
	 * @param fluent the fluent whose value will change
	 * @param value the value the fluent will have
	 * @return a compiled dummy belief update action observed by the character
	 * which sets the fluent to that value
	 */
	public CompiledEvent getUpdate(Character character, CompiledFluent fluent, Value value) {
		key.character = character;
		key.fluent = fluent;
		key.value = value;
		CompiledEvent update = updates.get(key);
		if(update == null) {
			update = update(character, fluent, value);
			events.add(update);
			updates.put(new UpdateKey(character, fluent, value), update);
		}
		return update;
	}

	private static final ImmutableSet<Character> NO_CONSENTING_CHARACTERS = new ImmutableSet<>();

	@SuppressWarnings("unchecked")

src/edu/uky/cs/nil/sabre/comp/CompiledEvent.java
public interface CompiledEvent extends Event, Unique {

	@Override
	public default boolean isGround() {
		return true;
	}

	@Override
	public default CompiledEvent simplify() {
		return this;
	}

	@Override
	public Disjunction<Clause<Precondition>> getPrecondition();

	@Override
	public Clause<Effect> getEffect();

	/**
	 * Returns the event's unique ID number, which should correspond to this
	 * event's index in its {@link CompiledProblem#events compiled problem's
	 * set of events}.
	 *
	 * @return the event's unique ID number
	 */
	public int getID();

	/**
	 * Returns a {@link Clause clause} composed of every {@link Effect effect}
	 * in {@link #getEffect() this event's effect} that has the given fluent
	 * {@link edu.uky.cs.nil.sabre.logic.Assignment#fluent as its fluent}. The
	 * returned clause may be empty if this event does not affect the given
	 * fluent, or it may have several atoms if this event has several
	 * conditional effects which might affect the given fluent.
	 *
	 * @param fluent the fluent which this event may affect
	 * @return a clause of all ways this event could affect the given fluent
	 */
	public default Clause<Effect> getEffect(Fluent fluent) {
		Clause<Effect> clause = Clause.EMPTY.toEffect();
		for(Effect effect : getEffect())
			if(effect.fluent.equals(fluent))
				clause = clause.add(effect);
		return clause;
	}
}

src/edu/uky/cs/nil/sabre/comp/CompiledMapping.java
public class CompiledMapping<E extends Expression> implements Mapping<E> {

	/** Serial version ID */
	private static final long serialVersionUID = Settings.VERSION_UID;

	/**
	 * An {@link ImmutableArray array} that stores the expressions in this
	 * mapping, where the expression for each {@link Character character} is in
	 * the index corresponding to the {@link edu.uky.cs.nil.sabre.Entity#id ID
	 * number} for that character
	 */
	public final ImmutableArray<E> table;

	/**
	 * Constructs a new compiled mapping.
	 *
	 * @param table an array of {@link Expression logical expressions} where
	 * the expression for each {@link Character character} is in the index
	 * corresponding to the {@link edu.uky.cs.nil.sabre.Entity#id ID number}
	 * of the character
	 */
	public CompiledMapping(ImmutableArray<E> table) {
		this.table = table;
	}

	/**
	 * Constructs a new compiled mapping.
	 *
	 * @param table an array of {@link Expression logical expressions} where
	 * the expression for each {@link Character character} is in the index
	 * corresponding to the {@link edu.uky.cs.nil.sabre.Entity#id ID number}
	 * of the character
	 */
	@SuppressWarnings("unchecked")
	public CompiledMapping(E...table) {
		this(new ImmutableArray<>(table));
	}

	@Override
	public int hashCode() {
		return Utilities.hashCode(getClass(), table);
	}

	@Override
	public String toString() {
		String string = "";
		if(table.size() > 0)
			string = "0 -> " + table.get(0);
		for(int i=1; i<table.size(); i++)
			string += "\n" + i + " -> " + table.get(i);
		return string;
	}

	@Override
	public int compareTo(Logical other) {
		if(getClass().equals(other.getClass()))
			return Utilities.compare(table, ((CompiledMapping<?>) other).table);
		else
			return Mapping.super.compareTo(other);
	}

	@Override
	public boolean isBoolean() {
		for(int i=0; i<table.size(); i++)
			if(!table.get(i).isBoolean())
				return false;
		return true;
	}

	@Override
	public boolean isNumber() {
		for(int i=0; i<table.size(); i++)
			if(!table.get(i).isNumber())
				return false;
		return true;
	}

	@Override
	public boolean isEntity() {
		for(int i=0; i<table.size(); i++)
			if(!table.get(i).isEntity())
				return false;
		return true;
	}

	@Override
	public boolean isCharacter() {
		for(int i=0; i<table.size(); i++)
			if(!table.get(i).isCharacter())
				return false;
		return true;
	}

	@Override
	public boolean is(Type type) {
		for(int i=0; i<table.size(); i++)
			if(!table.get(i).is(type))
				return false;
		return true;
	}

	@Override
	public boolean isGround() {
		return true;
	}

	@Override
	@SuppressWarnings("unchecked")
	public CompiledMapping<?> apply(java.util.function.Function<Object, Object> function) {
		ImmutableArray<Expression> table = (ImmutableArray<Expression>) this.table.apply(function);
		if(table != this.table)
			return new CompiledMapping<>(table);
		else
			return this;
	}

	/**
	 * Returns a {@link edu.uky.cs.nil.sabre.logic.Logical#isGround() ground}
	 * {@link Expression expression} relevant to the given ground character.
	 *
	 * @param character the character
	 * @return the ground expression
	 * @throws edu.uky.cs.nil.sabre.FormatException if the character is not
	 * ground or not of type {@code character}
	 */
	@Override
	public E get(Parameter character) {
		character.mustBeGround();
		character.mustBeCharacter();
		return get((Character) character);
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T extends Expression> Mapping<T> cast(Class<T> type) {
		for(int i=0; i<table.size(); i++)
			type.cast(table.get(i));
		return (CompiledMapping<T>) this;
	}

	/**
	 * Returns a {@link edu.uky.cs.nil.sabre.logic.Logical#isGround() ground}
	 * {@link Expression expression} relevant to the given ground character.
	 *
	 * @param character the character
	 * @return the ground expression
	 */
	public E get(Character character) {
		return table.get(character.id);
	}
}

src/edu/uky/cs/nil/sabre/comp/CompiledFluent.java
public class CompiledFluent extends Fluent implements Unique {

	/** Serial version ID */
	private static final long serialVersionUID = Settings.VERSION_UID;

	/**
	 * A unique ID number that corresponds to this fluent's index in {@link
	 * CompiledProblem#fluents its compiled problem's set of fluents}
	 */
	public final int id;

	/**
	 * An ordered list of {@link Character characters} specifying whose beliefs
	 * this fluent represents
	 */
	public final ImmutableArray<Character> characters;

	/**
	 * The compiled fluent whose signature is identical but whose list of
	 * characters is the same except that the first character has been removed
	 */
	private final CompiledFluent parent;

	/**
	 * Compiled fluents whose signatures are identical but with one additional
	 * character added to the start of the list of characters
	 */
	private final CompiledFluent[] children;

	/**
	 * Constructs a new compiled fluent by prepending a character onto a parent.
	 *
	 * @param id a unique ID number
	 * @param character the first character in this fluent's list of characters
	 * @param parent the fluent's parent; its signature will be copied and the
	 * character will be prepended to the start of its parent's list of
	 * characters
	 */
	protected CompiledFluent(int id, Character character, CompiledFluent parent) {
		super(prepend(character, parent.characters), parent.signature, parent.type, parent.comment);
		this.id = id;
		this.characters = super.characters.cast(Character.class);
		this.parent = parent;
		this.children = new CompiledFluent[type.universe.characters.size()];
		parent.children[character.id] = this;
	}

	private static final ImmutableArray<Parameter> prepend(Character character, ImmutableArray<Character> characters) {
		Character[] array = new Character[characters.size() + 1];
		array[0] = character;
		for(int i=0; i<characters.size(); i++)
			array[i + 1] = characters.get(i);
		return new ImmutableArray<Parameter>(array);
	}

	/**
	 * Constructs a new compiled fluent with an empty list of characters.
	 *
	 * @param id a unique ID number
	 * @param signature the fluent's signature, which must be ground
	 * @param type the fluent's type
	 * @param comment the comment
	 * @throws FormatException if the signature is not ground
	 */
	protected CompiledFluent(int id, Signature signature, Type type, String comment) {
		super(signature, type, comment);
		signature.mustBeGround();
		this.id = id;
		this.characters = super.characters.cast(Character.class);
		this.parent = this;
		this.children = new CompiledFluent[type.universe.characters.size()];
	}

	@Override
	public boolean equals(Object other) {
		return this == other;
	}

	@Override
	public int hashCode() {
		return id;
	}

	@Override
	public boolean isGround() {
		return true;
	}

	@Override
	public CompiledFluent apply(Function<Object, Object> function) {
		return this;
	}

	@Override
	public CompiledFluent simplify() {
		return this;
	}

	@Override
	public Fluent prepend(Parameter character) {
		if(character instanceof Character) {
			CompiledFluent child = children[((Character) character).id];
			if(child != null)
				return child;
		}
		return new PrefixFluent(character, this);
	}

	@Override
	public CompiledFluent removeFirstCharacter() {
		return parent;
	}
}

src/edu/uky/cs/nil/sabre/logic/Parameter.java
public interface Parameter extends Expression {

	@Override
	public Parameter apply(Function<Object, Object> function);

	@Override
	public default Parameter simplify() {
		return this;
	}

	@Override
	public default boolean isValued() {
		return true;
	}

	@Override
	public default Parameter prepend(Parameter character) {
		return this;
	}

	@Override
	public default Conditional<Disjunction<Clause<Precondition>>> toValued() {
		return new Conditional<>(this);
	}
}

src/edu/uky/cs/nil/sabre/logic/Clause.java
public class Clause<A extends Atom> extends Conjunction<A> {

	/** Serial version ID */
	private static final long serialVersionUID = Settings.VERSION_UID;

	/**
	 * The null clause is a empty clause which is logically equivalent to
	 * {@link False#FALSE false}. Though an empty conjunction would normally be
	 * logically equivalent to {@link True#TRUE true} (see {@link #EMPTY the
	 * empty clause}), this object exists for situations where a clause object
	 * is needed that is trivially false, such as when an {@link
	 * edu.uky.cs.nil.sabre.Event event} has a contradictory effect. Atoms
	 * cannot be added or removed from the null clause (that is, adding atoms
	 * to or removing atoms from the null clause always results in the null
	 * clause itself).
	 */
	public static final Clause<Atom> NULL = new Clause<Atom>(new ImmutableArray<>()) {

		/** Serial version ID */
		private static final long serialVersionUID = 1;

		@Override
		public boolean equals(Object other) {
			return this == other;
		}

		@Override
		public int hashCode() {
			return super.hashCode() * -1;
		}

		@Override
		public String toString() {
			return DefaultParser.NULL_CLAUSE_KEYWORD;
		}

		@Override
		public int compareTo(Logical other) {
			if(getClass().equals(other.getClass())) {
				if(other.equals(this))
					return 0;
				else
					return -1;
			}
			else
				return super.compareTo(other);
		}

		/**
		 * Returns {@link False#FALSE false}.
		 *
		 * @returns {@link False#FALSE false}
		 */
		@Override
		public False simplify() {
			return False.FALSE;
		}

		/**
		 * Returns {@link False#FALSE false}.
		 *
		 * @returns {@link False#FALSE false}
		 */
		@Override
		public Value evaluate(State state) {
			return False.FALSE;
		}

		/**
		 * Returns {@link True#TRUE true}.
		 *
		 * @returns {@link True#TRUE true}
		 */
		@Override
		public True negate() {
			return True.TRUE;
		}

		/**
		 * Returns {@link False#FALSE false}.
		 *
		 * @returns {@link False#FALSE false}
		 */
		@Override
		public Disjunction<Clause<Precondition>> toPrecondition() {
			return False.FALSE.toPrecondition();
		}

		/**
		 * Returns {@link #NULL the null clause}.
		 *
		 * @returns {@link #NULL the null clause}
		 */
		@Override
		@SuppressWarnings("unchecked")
		public Clause<Effect> toEffect() {
			return (Clause<Effect>) (Clause<?>) this;
		}

		/**
		 * Returns {@link #NULL the null clause}.
		 *
		 * @returns {@link #NULL the null clause}
		 */
		@Override
		public Clause<Atom> add(Clause<Atom> clause) {
			return this;
		}

		/**
		 * Returns {@link #NULL the null clause}.
		 *
		 * @returns {@link #NULL the null clause}
		 */
		@Override
		public Clause<Atom> remove(Clause<Atom> clause) {
			return this;
		}

		private Object readResolve() throws ObjectStreamException {
			return NULL;
		}
	};

	/**
	 * The empty clause is clause with zero atoms which is logically equivalent
	 * to {@link True#TRUE true}.
	 */
	public static final Clause<Atom> EMPTY = new Clause<Atom>(new ImmutableArray<>()) {

		/** Serial version ID */
		private static final long serialVersionUID = 1;

		@Override
		public boolean equals(Object other) {
			return this == other;
		}

		@Override
		public int compareTo(Logical other) {
			if(getClass().equals(other.getClass())) {
				if(other.equals(NULL))
					return 1;
				else if(other.equals(this))
					return 0;
				else
					return -1;
			}
			else
				return super.compareTo(other);
		}

		/**
		 * Returns {@link True#TRUE true}.
		 *
		 * @returns {@link True#TRUE true}
		 */
		@Override
		public True simplify() {
			return True.TRUE;
		}

		/**
		 * Returns {@link False#FALSE false}.
		 *
		 * @returns {@link False#FALSE false}
		 */
		@Override
		public False negate() {
			return False.FALSE;
		}

		/**
		 * Returns {@link True#TRUE true}.
		 *
		 * @returns {@link True#TRUE true}
		 */
		@Override
		public Disjunction<Clause<Precondition>> toPrecondition() {
			return True.TRUE.toPrecondition();
		}

		/**
		 * Returns {@link #EMPTY the empty clause}.
		 *
		 * @returns {@link #EMPTY the empty clause}
		 */
		@Override
		@SuppressWarnings("unchecked")
		public Clause<Effect> toEffect() {
			return (Clause<Effect>) (Clause<?>) this;
		}

		private Object readResolve() throws ObjectStreamException {
			return EMPTY;
		}
	};

	private Clause(ImmutableArray<A> arguments) {
		super(arguments);
	}

	/**
	 * Constructs a clause from a single atom.
	 *
	 * @param atom the atom
	 */
	public Clause(A atom) {
		this(new ImmutableArray<>(atom));
	}

	/**
	 * Clauses are simplified incrementally as atoms are added or removed, so
	 * this method always returns this object itself with no changes.
	 *
	 * @return this clause
	 */
	@Override
	public Expression simplify() {
		return this;
	}

	@Override
	public Clause<A> prepend(Parameter character) {
		return new Clause<A>(arguments.apply(atom -> ((Atom) atom).prepend(character)));
	}

	@Override
	@SuppressWarnings("unchecked")
	public Clause<Effect> toEffect() {
		if(isEffect())
			return (Clause<Effect>) this;
		else
			return super.toEffect();
	}

	/**
	 * Tests whether every atom in this clause is a {@link Precondition
	 * precondition}.
	 *
	 * @return true if every atom is a precondition or if there are no atoms,
	 * false otherwise
	 */
	public boolean isPrecondition() {
		for(int i=0; i<arguments.size(); i++)
			if(!(arguments.get(i) instanceof Precondition))
				return false;
		return true;
	}

	/**
	 * Tests whether every atom is an {@link Effect effect}.
	 *
	 * @return true if every atom is an effect or if there are no atoms, false
	 * otherwise
	 */
	public boolean isEffect() {
		for(int i=0; i<arguments.size(); i++)
			if(!(arguments.get(i) instanceof Effect))
				return false;
		return true;
	}

	/**
	 * Adds an atom to this clause and simplifies the clause. See {@link
	 * #add(Clause)} for details on adding to clauses.
	 *
	 * @param atom the atom to be added
	 * @return the new clause that results from adding the atom
	 */
	public Clause<A> add(A atom) {
		return add(new Clause<A>(new ImmutableArray<>(atom)));
	}

	/**
	 * Adds all atoms from this clause and the given clause together to form a
	 * new clause. The resulting clause will not necessarily have as many atoms
	 * as both clauses combined because the clause is simplified as it is
	 * built. For example, if merging the clauses would create a contradiction,
	 * perhaps because an atom from this clause {@link Atom#negates(Atom)
	 * negates} an atom in the given clause, {@link #NULL the null clause} will
	 * be returned. If atoms from the two clauses can be {@link
	 * Atom#combine(Atom) combined}, they will be.
	 *
	 * @param clause the clause to combine with this clause
	 * @return a simplified clause resulting from combining this clause and the
	 * given clause
	 */
	@SuppressWarnings("unchecked")
	public Clause<A> add(Clause<A> clause) {
		if(clause.equals(NULL))
			return (Clause<A>) NULL;
		A[] atoms = add(null, this, 0, clause, 0, 0);
		if(atoms == null)
			return (Clause<A>) NULL;
		else if(atoms.length == 0)
			return (Clause<A>) EMPTY;
		else
			return new Clause<>(new ImmutableArray<>(atoms));
	}

	@SuppressWarnings("unchecked")
	private static final <A extends Atom> A[] add(A atom, Clause<A> c1, int i1, Clause<A> c2, int i2, int size) {
		A a1 = i1 == c1.size() ? null : c1.get(i1);
		A a2 = i2 == c2.size() ? null : c2.get(i2);
		if(atom == null && a1 == null && a2 == null)
			return (A[]) new Atom[size];
		else if(atom == null) {
			if(a1 == null)
				return add(a2, c1, i1, c2, i2 + 1, size);
			else if(a2 == null || a1.compareTo(a2) <= 0)
				return add(a1, c1, i1 + 1, c2, i2, size);
			else
				return add(a2, c1, i1, c2, i2 + 1, size);
		}
		if(a1 != null && atom.negates(a1))
			return null;
		else if(a2 != null && atom.negates(a2))
			return null;
		A a1c = a1 == null ? null : (A) atom.combine(a1);
		if(a1c != null)
			return add(a1c, c1, i1 + 1, c2, i2, size);
		A a2c = a2 == null ? null : (A) atom.combine(a2);
		if(a2c != null)
			return add(a2c, c1, i1, c2, i2 + 1, size);
		else {
			A[] atoms = add(null, c1, i1, c2, i2, size + 1);
			if(atoms == null)
				return null;
			atoms[size] = atom;
			return atoms;
		}
	}

	/**
	 * Removes an atom from this clause. See {@link #remove(Clause)} for
	 * details on removing from clauses.
	 *
	 * @param atom the atom to be removed
	 * @return a simplified clause resulting from removing the atom
	 */
	public Clause<A> remove(A atom) {
		return remove(new Clause<A>(new ImmutableArray<>(atom)));
	}

	/**
	 * Removes atoms from this clause if they appear, or if a more specific
	 * version appears, in the given clause, or returns {@link #NULL the null
	 * clause} if an atom in the given clause contradict this clause.
	 * Let {@code a} be some atom in this clause and {@code b} be an atom in
	 * the given clause. If {@code a} and {@code b} are the same, {@code a}
	 * will be removed. If {@code a} and {@code b} can be {@link
	 * Atom#combine(Atom) combined}, and the result is {@code b}, this means
	 * {@code b} was more specific than {@code a}, and {@code a} will be
	 * removed. If they can be combined and the result is something other than
	 * {@code b}, then {@code a} will not removed. If {@code a} {@link
	 * Atom#negates(Atom) negates} {@code b}, this method returns the {@link
	 * #NULL null clause}.
	 * <p>
	 * This method can be used to regress this clause over the given clause.
	 * This clause can be viewed as a condition (such as the {@link
	 * edu.uky.cs.nil.sabre.Event#getPrecondition() precondition of an event},
	 * though this clause does not need to have {@link Precondition
	 * precondition atoms}) and the given clause can be viewed as changes made
	 * (such as the {@link edu.uky.cs.nil.sabre.Event#getEffect() effect of an
	 * event}, though the given clause does not need to have {@link Effect
	 * effect atoms}). Regressing this clause means removing the conditions
	 * from this clause which the given clause could have caused. So if this
	 * clause has the condition that {@code f > 3} and we regress the effect
	 * {@code f = 4} (which is more specific and satisfied the condition), the
	 * condition would be removed. However, if we regress the effect
	 * {@code f = 2} (which contradicts the condition), than there is no way
	 * that effect could have led to a condition where {@code f > 3}, so this
	 * method returns the null clause.
	 *
	 * @param clause the clause whose atoms will be removed from this clause
	 * @return this clause, with atoms removed if they (or more specific
	 * versions) appear in the given clause, or {@link #NULL the null clause}
	 * if some atom in the given clause contradicts an atom in this clause
	 */
	@SuppressWarnings("unchecked")
	public Clause<A> remove(Clause<A> clause) {
		if(clause.equals(NULL))
			return (Clause<A>) NULL;
		A[] atoms = remove(this, 0, clause, 0, 0);
		if(atoms == null)
			return (Clause<A>) NULL;
		else if(atoms.length == 0)
			return (Clause<A>) EMPTY;
		else
			return new Clause<>(new ImmutableArray<>(atoms));
	}

	@SuppressWarnings("unchecked")
	private static final <A extends Atom> A[] remove(Clause<A> c1, int i1, Clause<A> c2, int i2, int size) {
		if(i1 == c1.size())
			return (A[]) new Atom[size];
		else if(i2 == c2.size()) {
			A[] atoms = remove(c1, i1 + 1, c2, i2, size + 1);
			atoms[size] = c1.get(i1);
			return atoms;
		}
		A a1 = c1.get(i1);
		A a2 = c2.get(i2);
		if(a1.negates(a2))
			return null;
		Atom combined = a1.combine(a2);
		if(combined != null && combined.equals(a2))
			return remove(c1, i1 + 1, c2, i2, size);
		else if(a1.compareTo(a2) < 0) {
			A[] atoms = remove(c1, i1 + 1, c2, i2, size + 1);
			if(atoms == null)
				return null;
			atoms[size] = a1;
			return atoms;
		}
		else
			return remove(c1, i1, c2, i2 + 1, size);
	}
}

src/edu/uky/cs/nil/sabre/Utilities.java
public class Utilities {

	/**
	 * A default {@link edu.uky.cs.nil.sabre.io.Printer printer} generally used
	 * for converting objects to strings
	 */
	public static final DefaultPrinter DEFAULT_PRINTER = new DefaultPrinter();

	/**
	 * Checks whether two objects are {@link Object#equals(Object) equal to}
	 * one another without causing a {@link NullPointerException} if one or
	 * both of them is null.
	 *
	 * @param o1 the first object
	 * @param o2 the second object
	 * @return true if they are equal or both null, false otherwise
	 */
	public static final boolean equals(Object o1, Object o2) {
		if(o1 == null)
			return o2 == null;
		else if(o2 == null)
			return false;
		else
			return o1.equals(o2);
	}

	/**
	 * Returns an object's {@link Object#hashCode() hash code} or 0 if the
	 * object is null.
	 *
	 * @param object the object or null
	 * @return the object's hash code or 0 if the object was null
	 */
	public static final int hashCode(Object object) {
		if(object == null)
			return 0;
		else
			return object.hashCode();
	}

	/**
	 * Combines two {@link #hashCode(Object) hash code} values.
	 *
	 * @param hc1 the first hash code
	 * @param hc2 the second hash code
	 * @return the combined hash code
	 */
	public static final int hashCode(int hc1, int hc2) {
		return hc1 * 31 + hc2;
	}

	/**
	 * Combines a {@link #hashCode(Object) hash code} value with the {@link
	 * #hashCode(Object) hash code} of an object.
	 *
	 * @param hc the hash code value
	 * @param o1 the object
	 * @return the combined hash code
	 */
	public static final int hashCode(int hc, Object o1) {
		return hashCode(hc, hashCode(o1));
	}

	/**
	 * Combines the {@link #hashCode(Object) hash code} values of two objects.
	 *
	 * @param o1 the first object
	 * @param o2 the second object
	 * @return the combined hash code
	 */
	public static final int hashCode(Object o1, Object o2) {
		return hashCode(hashCode(o1), hashCode(o2));
	}

	/**
	 * Combines a {@link #hashCode(Object) hash code} value with the {@link
	 * #hashCode(Object) hash code} of two objects.
	 *
	 * @param hc the hash code value
	 * @param o1 the first object
	 * @param o2 the second object
	 * @return the combined hash code
	 */
	public static final int hashCode(int hc, Object o1, Object o2) {
		return hashCode(hashCode(hc, o1), hashCode(o2));
	}

	/**
	 * Combines the {@link #hashCode(Object) hash code} values of three
	 * objects.
	 *
	 * @param o1 the first object
	 * @param o2 the second object
	 * @param o3 the third object
	 * @return the combined hash code
	 */
	public static final int hashCode(Object o1, Object o2, Object o3) {
		return hashCode(hashCode(o1, o2), hashCode(o3));
	}

	/**
	 * Combines a {@link #hashCode(Object) hash code} value with the {@link
	 * #hashCode(Object) hash code} of three objects.
	 *
	 * @param hc the hash code value
	 * @param o1 the first object
	 * @param o2 the second object
	 * @param o3 the third object
	 * @return the combined hash code
	 */
	public static final int hashCode(int hc, Object o1, Object o2, Object o3) {
		return hashCode(hashCode(hc, o1, o2), hashCode(o3));
	}

	/**
	 * Combines the {@link #hashCode(Object) hash code} values of four objects.
	 *
	 * @param o1 the first object
	 * @param o2 the second object
	 * @param o3 the third object
	 * @param o4 the fourth object
	 * @return the combined hash code
	 */
	public static final int hashCode(Object o1, Object o2, Object o3, Object o4) {
		return hashCode(hashCode(o1, o2, o3), hashCode(o4));
	}

	/**
	 * Combines a {@link #hashCode(Object) hash code} value with the {@link
	 * #hashCode(Object) hash code} of four objects.
	 *
	 * @param hc the hash code value
	 * @param o1 the first object
	 * @param o2 the second object
	 * @param o3 the third object
	 * @param o4 the fourth object
	 * @return the combined hash code
	 */
	public static final int hashCode(int hc, Object o1, Object o2, Object o3, Object o4) {
		return hashCode(hashCode(hc, o1, o2, o3), hashCode(o4));
	}

	/**
	 * Combines the {@link #hashCode(Object) hash code} values of five objects.
	 *
	 * @param o1 the first object
	 * @param o2 the second object
	 * @param o3 the third object
	 * @param o4 the fourth object
	 * @param o5 the fifth object
	 * @return the combined hash code
	 */
	public static final int hashCode(Object o1, Object o2, Object o3, Object o4, Object o5) {
		return hashCode(hashCode(o1, o2, o3, o4), hashCode(o5));
	}

	/**
	 * Combines a {@link #hashCode(Object) hash code} value with the {@link
	 * #hashCode(Object) hash code} of five objects.
	 *
	 * @param hc the hash code value
	 * @param o1 the first object
	 * @param o2 the second object
	 * @param o3 the third object
	 * @param o4 the fourth object
	 * @param o5 the fifth object
	 * @return the combined hash code
	 */
	public static final int hashCode(int hc, Object o1, Object o2, Object o3, Object o4, Object o5) {
		return hashCode(hashCode(hc, o1, o2, o3, o4), hashCode(o5));
	}

	/**
	 * Combines the {@link #hashCode(Object) hash code} values of six objects.
	 *
	 * @param o1 the first object
	 * @param o2 the second object
	 * @param o3 the third object
	 * @param o4 the fourth object
	 * @param o5 the fifth object
	 * @param o6 the sixth object
	 * @return the combined hash code
	 */
	public static final int hashCode(Object o1, Object o2, Object o3, Object o4, Object o5, Object o6) {
		return hashCode(hashCode(o1, o2, o3, o4, o5), hashCode(o6));
	}

	/**
	 * Rounds a {@code double} up to the nearest whole number.
	 *
	 * @param value the value to round up
	 * @return the nearest whole number that is greater than or equal to the
	 * value
	 */
	public static final double roundUp(double value) {
		return new BigDecimal(value).setScale(0, RoundingMode.UP).doubleValue();
	}

	/**
	 * Compares a pair of {@link Comparable comparable} objects.
	 *
	 * @param <C1> the type of the objects
	 * @param o1 the first object
	 * @param o2 the second object
	 * @return a negative integer, zero, or a positive integer as the first
	 * object is less than, equal to, or greater than the second object
	 */
	public static final <C1 extends Comparable<C1>> int compare(C1 o1, C1 o2) {
		return o1.compareTo(o2);
	}

	/**
	 * Compares two pairs of {@link Comparable comparable} objects. The first
	 * pair (that is, the first two arguments) is compared. If the result is
	 * not 0, it is returned, otherwise the second pair (that is, the third and
	 * fourth arguments) is compared, and so on.
	 *
	 * @param <C1> the type of the first pair of objects
	 * @param <C2> the type of the second pair of objects
	 * @param o1 the first object in the first pair
	 * @param o2 the second object in the first pair
	 * @param o3 the first object in the second pair
	 * @param o4 the second object in the second pair
	 * @return a negative integer, zero, or a positive integer as the earlier
	 * pairs are less than, equal to, or greater than the later pairs
	 */
	public static final <C1 extends Comparable<C1>, C2 extends Comparable<C2>> int compare(C1 o1, C1 o2, C2 o3, C2 o4) {
		int comparison = compare(o1, o2);
		if(comparison == 0)
			comparison = compare(o3, o4);
		return comparison;
	}

	/**
	 * Compares three pairs of {@link Comparable comparable} objects. The first
	 * pair (that is, the first two arguments) is compared. If the result is not
	 * 0, it is returned, otherwise the second pair (that is, the third and
	 * fourth arguments) is compared, and so on.
	 *
	 * @param <C1> the type of the first pair of objects
	 * @param <C2> the type of the second pair of objects
	 * @param <C3> the type of the third pair of objects
	 * @param o1 the first object in the first pair
	 * @param o2 the second object in the first pair
	 * @param o3 the first object in the second pair
	 * @param o4 the second object in the second pair
	 * @param o5 the first object in the third pair
	 * @param o6 the second object in the third pair
	 * @return a negative integer, zero, or a positive integer as the earlier
	 * pairs are less than, equal to, or greater than the later pairs
	 */
	public static final <C1 extends Comparable<C1>, C2 extends Comparable<C2>, C3 extends Comparable<C3>> int compare(C1 o1, C1 o2, C2 o3, C2 o4, C3 o5, C3 o6) {
		int comparison = compare(o1, o2, o3, o4);
		if(comparison == 0)
			comparison = compare(o5, o6);
		return comparison;
	}

	/**
	 * Compares four pairs of {@link Comparable comparable} objects. The first
	 * pair (that is, the first two arguments) is compared. If the result is
	 * not 0, it is returned, otherwise the second pair (that is, the third and
	 * fourth arguments) is compared, and so on.
	 *
	 * @param <C1> the type of the first pair of objects
	 * @param <C2> the type of the second pair of objects
	 * @param <C3> the type of the third pair of objects
	 * @param <C4> the type of the fourth pair of objects
	 * @param o1 the first object in the first pair
	 * @param o2 the second object in the first pair
	 * @param o3 the first object in the second pair
	 * @param o4 the second object in the second pair
	 * @param o5 the first object in the third pair
	 * @param o6 the second object in the third pair
	 * @param o7 the first object in the fourth pair
	 * @param o8 the second object in the fourth pair
	 * @return a negative integer, zero, or a positive integer as the earlier
	 * pairs are less than, equal to, or greater than the later pairs
	 */
	public static final <C1 extends Comparable<C1>, C2 extends Comparable<C2>, C3 extends Comparable<C3>, C4 extends Comparable<C4>> int compare(C1 o1, C1 o2, C2 o3, C2 o4, C3 o5, C3 o6, C4 o7, C4 o8) {
		int comparison = compare(o1, o2, o3, o4, o5, o6);
		if(comparison == 0)
			comparison = compare(o7, o8);
		return comparison;
	}

	/**
	 * Compares two {@link ImmutableArray arrays} of {@link Logical logical}
	 * objects. The first elements of both arrays are compared. If the result
	 * is not 0, it is returned, otherwise the second elements of both arrays
	 * are compared, and so on.
	 *
	 * @param array1 the first array
	 * @param array2 the second array
	 * @return a negative integer, zero, or a positive integer as the earlier
	 * elements are less than, equal to, or greater than the later elements
	 */
	public static final int compare(ImmutableArray<? extends Logical> array1, ImmutableArray<? extends Logical> array2) {
		int comparison = 0;
		int size = Math.min(array1.size(), array2.size());
		for(int i=0; i<size && comparison==0; i++)
			comparison = array1.get(i).compareTo(array2.get(i));
		if(comparison == 0) {
			if(array1.size() > array2.size())
				return 1;
			else if(array2.size() > array1.size())
				return -1;
		}
		return comparison;
	}

	/**
	 * Iterates through all elements of an {@link Iterable iterable} and places
	 * them into an array of a given type.
	 *
	 * @param <T> the component type of the array
	 * @param iterable the iterable
	 * @param type the class of the component type of the array
	 * @return an array containing all the elements in the iterable
	 */
	public static final <T> T[] toArray(Iterable<? extends T> iterable, Class<T> type) {
		return toArray(iterable.iterator(), 0, type);
	}

	@SuppressWarnings("unchecked")
	private static final <T> T[] toArray(Iterator<? extends T> iterator, int index, Class<T> type) {
		if(iterator.hasNext()) {
			T element = iterator.next();
			T[] array = toArray(iterator, index + 1, type);
			array[index] = element;
			return array;
		}
		else
			return (T[]) Array.newInstance(type, index);
	}

	/**
	 * Iterates through all elements of an {@link Iterable iterable} and places
	 * into a {@link ImmutableSet set} only those items which are of a given
	 * type.
	 *
	 * @param <T> the type of elements to collect
	 * @param type the class object of the type
	 * @param iterable the iterable to iterate through
	 * @return a set of elements from the iterable of the given type
	 */
	@SuppressWarnings("unchecked")
	public static final <T> ImmutableSet<T> collect(Class<T> type, Iterable<?> iterable) {
		LinkedHashSet<T> set = new LinkedHashSet<>();
		for(Object element : iterable)
			if(type.isAssignableFrom(element.getClass()))
				set.add((T) element);
		return new ImmutableSet<>(set);
	}

	/**
	 * Wrap a string in parentheses, unless it is already so wrapped.
	 *
	 * @param string the second
	 * @return the string, wrapped in parentheses
	 */
	public static final String wrap(String string) {
		if(string.startsWith("(") && string.endsWith(")"))
			return string;
		else
			return "(" + string + ")";
	}

	/**
	 * Converts a number of milliseconds into a short string representation
	 * that gives the numbers of days, hours, minutes, seconds, and
	 * milliseconds. For example, {@code "2d1h3m45s20ms"} represents two days,
	 * 1 hour, 3 minutes, fourty-five seconds, and twenty milliseconds.
	 *
	 * @param ms the number of milliseconds
	 * @return a string representation of that amount of time
	 */
	public static final String time(long ms) {
		long days = TimeUnit.MILLISECONDS.toDays(ms);
		ms -= TimeUnit.DAYS.toMillis(days);
		long hours = TimeUnit.MILLISECONDS.toHours(ms);
		ms -= TimeUnit.HOURS.toMillis(hours);
		long minutes = TimeUnit.MILLISECONDS.toMinutes(ms);
		ms -= TimeUnit.MINUTES.toMillis(minutes);
		long seconds = TimeUnit.MILLISECONDS.toSeconds(ms);
		ms -= TimeUnit.SECONDS.toMillis(seconds);
		String string = "";
		if(days > 0)
			string += days + "d";
		if(hours > 0)
			string += hours + "h";
		if(minutes > 0)
			string += minutes + "m";
		if(seconds > 0)
			string += seconds + "s";
		if(ms > 0)
			string += ms + "ms";
		if(string.isEmpty())
			return "0ms";
		return string;
	}
}

src/edu/uky/cs/nil/sabre/logic/Value.java
public interface Value extends Parameter {

	@Override
	public default boolean isGround() {
		return true;
	}

	@Override
	public default Value apply(Function<Object, Object> function) {
		return this;
	}

	@Override
	public default Value simplify() {
		return this;
	}

	@Override
	public default boolean isValued() {
		return true;
	}

	@Override
	public default Value evaluate(State state) {
		return this;
	}

	@Override
	public default Value prepend(Parameter character) {
		return this;
	}

	@Override
	public default Conditional<Disjunction<Clause<Precondition>>> toValued() {
		return new Conditional<>(this);
	}
}

Answer: private final CompiledAction update(Character character, CompiledFluent fluent, Value value) {

<think>
In EventList, after the static field NO_CONSENTING_CHARACTERS the code has a @SuppressWarnings annotation, indicating the next line defines the method used earlier (update) that creates a dummy belief update event. The method is static, returns CompiledEvent, and takes Character, CompiledFluent, Value parameters. Hence the next line is the method signature.
</think>
private static final CompiledEvent update(Character character, CompiledFluent fluent, Value value) {