fr.boreal.model.logicalElements.impl.SubstitutionImpl Maven / Gradle / Ivy
The newest version!
package fr.boreal.model.logicalElements.impl;
import fr.boreal.model.logicalElements.api.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.*;
/**
* Default implementation of Substitution using a map
*
* @author Florent Tornil
*
*/
public class SubstitutionImpl implements Substitution, Serializable {
@Serial
private static final long serialVersionUID = 8409744590170243850L;
private final Map map;
/////////////////////////////////////////////////
// Constructors
/////////////////////////////////////////////////
/**
* Default constructor using a HashMap
*/
public SubstitutionImpl() {
this.map = new HashMap<>();
}
/**
* Constructor using a user-given map
*
* @param associations a map representing a substitution
*/
public SubstitutionImpl(Map associations) {
this.map = associations;
}
/**
* Copy contructor
*
* @param s another substitution
*/
public SubstitutionImpl(Substitution s) {
this(new HashMap<>(s.keys().size()));
for (Variable v : s.keys()) {
this.add(v, s.createImageOf(v));
}
}
/////////////////////////////////////////////////
// Public methods
/////////////////////////////////////////////////
@Override
public Term createImageOf(Term term) {
Term substitut = null;
if (term instanceof FunctionalTerm f) {
substitut = f.eval(this);
}
if (term instanceof StoredFunctionalTerm f) {
substitut = f.eval(this);
}
if (substitut == null) {
substitut = this.map.get(term);
}
return (substitut == null) ? term : substitut;
}
@Override
public Atom createImageOf(Atom atom) {
Atom substitut = null;
if (atom instanceof ComputedAtom) {
substitut = ((ComputedAtom) atom).eval(this);
}
if (substitut == null) {
List res = new ArrayList<>();
for (int i = 0; i < atom.getPredicate().arity(); i++) {
Term t = atom.getTerm(i);
res.add(this.createImageOf(t));
}
substitut = new AtomImpl(atom.getPredicate(), res);
}
return substitut;
}
@Override
public Collection keys() {
return this.map.keySet();
}
@Override
public void add(Variable v, Term t) {
this.map.put(v, t);
}
@Override
public void remove(Variable v) {
this.map.remove(v);
}
@Override
public boolean isEmpty() {
return this.map.isEmpty();
}
@Override
public Optional merged(Substitution other) {
if (this.isEmpty()) {
return Optional.of(other);
}
if (other.isEmpty()) {
return Optional.of(this);
}
Substitution result = new SubstitutionImpl(this);
for (Variable current_variable : other.keys()) {
Term b_image = other.createImageOf(current_variable);
if (result.keys().contains(current_variable)) {
Term current_image = result.createImageOf(current_variable);
if (!current_image.equals(b_image)) {
return Optional.empty();
}
} else {
result.add(current_variable, b_image);
}
}
return Optional.of(result);
}
@Override
public Optional aggregated(Substitution s) {
SubstitutionImpl newSub = new SubstitutionImpl(this);
for (Variable term : s.keys()) {
if (!newSub.aggregate(term, s.createImageOf(term))) {
return Optional.empty();
}
}
return Optional.of(newSub);
}
private boolean aggregate(Variable term, Term substitut) {
Term termSubstitut = this.createImageOf(term);
Term substitutSubstitut = this.createImageOf(substitut);
if (!termSubstitut.equals(substitutSubstitut)) {
if (termSubstitut.isConstant()) {
if (substitutSubstitut.isConstant()) {
return substitutSubstitut.equals(termSubstitut);
} else {
Term tmp = termSubstitut;
termSubstitut = substitutSubstitut;
substitutSubstitut = tmp;
}
}
for (Variable t : this.keys()) {
Term image = this.createImageOf(t);
if (termSubstitut.equals(image) && !t.equals(substitutSubstitut)) {
this.add(t, substitutSubstitut);
}
}
this.add((Variable) termSubstitut, substitutSubstitut);
}
return true;
}
@Override
public Substitution limitedTo(Collection vars) {
Substitution result = new SubstitutionImpl();
for (Variable v : this.keys()) {
if (vars.contains(v)) {
result.add(v, this.createImageOf(v));
}
}
return result;
}
@Override
public boolean isExtensionOf(Substitution other) {
Substitution limited_copy = this.limitedTo(other.keys());
return limited_copy.equals(other);
}
@Override
public boolean isInjective() {
Set terms = new HashSet<>();
for (Term value : map.values()) {
if (terms.contains(value)) {
return false;
}
terms.add(value);
}
return true;
}
@Override
public boolean isInvertible() {
for (Term value : map.values()) {
if (value.isFrozen(null)) {
return false;
}
}
return isInjective();
}
@Override
public Set rangeTerms() {
Set imageTerms = new HashSet<>();
for (Variable key : map.keySet()) {
imageTerms.add(map.get(key));
}
return imageTerms;
}
@Override
public Map toMap() {
return this.map;
}
/////////////////////////////////////////////////
// Object methods
/////////////////////////////////////////////////
@Override
public int hashCode() {
return this.map.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null) {
return false;
} else if (o instanceof SubstitutionImpl) {
return this.map.equals(((SubstitutionImpl) o).map);
} else {
return false;
}
}
/**
* @return a string representation of this substitution of the form {v1:t1, ...,
* vn:tn}
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
boolean first = true;
for (Variable v : this.keys()) {
if (!first) {
sb.append(", ");
}
sb.append(v.toString());
sb.append(":");
sb.append(this.map.get(v));
first = false;
}
sb.append("}");
return sb.toString();
}
}