001package conexp.fx.core.context;
002
003import java.util.Collection;
004import java.util.Collections;
005
006/*
007 * #%L
008 * Concept Explorer FX
009 * %%
010 * Copyright (C) 2010 - 2019 Francesco Kriegel
011 * %%
012 * This program is free software: you can redistribute it and/or modify
013 * it under the terms of the GNU General Public License as
014 * published by the Free Software Foundation, either version 3 of the
015 * License, or (at your option) any later version.
016 * 
017 * This program is distributed in the hope that it will be useful,
018 * but WITHOUT ANY WARRANTY; without even the implied warranty of
019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
020 * GNU General Public License for more details.
021 * 
022 * You should have received a copy of the GNU General Public
023 * License along with this program.  If not, see
024 * <http://www.gnu.org/licenses/gpl-3.0.html>.
025 * #L%
026 */
027
028import java.util.HashSet;
029import java.util.Iterator;
030import java.util.Set;
031import java.util.stream.Collectors;
032
033import com.google.common.collect.Sets;
034
035import conexp.fx.core.math.SetClosureOperator;
036import conexp.fx.core.util.UnicodeSymbols;
037import de.tudresden.inf.tcs.fcaapi.FCAImplication;
038
039public class Implication<G, M> extends de.tudresden.inf.tcs.fcalib.Implication<M> {
040
041  public static final <G, M> boolean equivalent(final Set<Implication<G, M>> x, final Set<Implication<G, M>> y) {
042    return entails(x, y) && entails(y, x);
043  }
044
045  public static final <G, M> boolean entails(final Set<Implication<G, M>> x, final Set<Implication<G, M>> y) {
046    return y.parallelStream().allMatch(z -> entails(x, z));
047  }
048
049  public static final <G, M> Set<Implication<G, M>>
050      diff(final Set<Implication<G, M>> x, final Set<Implication<G, M>> y) {
051    return y.parallelStream().filter(z -> !entails(x, z)).collect(Collectors.toSet());
052  }
053
054  public static final <G, M> boolean entails(final Set<Implication<G, M>> x, final Implication<G, M> y) {
055    return SetClosureOperator.fromImplications(x, false, false).closure(y.getPremise()).containsAll(y.getConclusion());
056  }
057
058  private final Set<G> support;
059  private final double confidence;
060
061  public Implication() {
062    this(new HashSet<M>(), new HashSet<M>(), new HashSet<G>());
063  }
064
065  public Implication(final Set<M> premise, final Set<M> conclusion) {
066    this(premise, conclusion, new HashSet<G>());
067  }
068
069  public Implication(final Set<M> premise, final Set<M> conclusion, final Set<G> support) {
070    this(premise, conclusion, support, 1d);
071  }
072
073  public Implication(final Set<M> premise, final Set<M> conclusion, final Set<G> support, final double confidence) {
074    super(premise, conclusion);
075    this.support = support;
076    if (confidence < 0d || confidence > 1d)
077      throw new IllegalArgumentException("Confidence must be in range [0,1]");
078    this.confidence = confidence;
079  }
080
081  public Implication(final Collection<M> premise, final Collection<M> conclusion) {
082    this(new HashSet<M>(premise), new HashSet<M>(conclusion));
083  }
084
085  public Implication(final Collection<M> premise, final Collection<M> conclusion, final Collection<G> support) {
086    this(
087        (Set<M>) (premise instanceof Set ? premise : new HashSet<M>(premise)),
088        (Set<M>) (conclusion instanceof Set ? conclusion : new HashSet<M>(conclusion)),
089        (Set<G>) (support instanceof Set ? support : new HashSet<G>(support)),
090        1d);
091  }
092
093  public Implication(final M premise, final Set<M> conclusion) {
094    this(Collections.singleton(premise), conclusion);
095  }
096
097  public Implication(final Set<M> premise, final M conclusion) {
098    this(premise, Collections.singleton(conclusion));
099  }
100
101  public Implication(final M premise, final M conclusion) {
102    this(Collections.singleton(premise), Collections.singleton(conclusion));
103  }
104
105  public final Set<G> getSupport() {
106    return support;
107  }
108
109  public final double getConfidence() {
110    return confidence;
111  }
112
113  public boolean isTrivial() {
114    return getPremise().containsAll(getConclusion());
115  }
116
117  @Override
118  public boolean equals(final Object obj) {
119    if (obj == null)
120      return false;
121    if (!(obj instanceof Implication)) {
122      if (obj instanceof FCAImplication)
123        return super.equals((FCAImplication<?>) obj);
124      return false;
125    }
126    final Implication<?, ?> other = (Implication<?, ?>) obj;
127    return this.getPremise().equals(other.getPremise()) && this.getConclusion().equals(other.getConclusion());
128//        && this.getSupport().equals(other.getSupport()) && this.getConfidence() == other.getConfidence();
129  }
130
131  @Override
132  public int hashCode() {
133    return getPremise().hashCode() + getConclusion().hashCode();
134//    return 2 * getPremise().hashCode() + 3 * getConclusion().hashCode() + 5 * getSupport().hashCode()
135//        + (int) (8191d * confidence);
136  }
137
138  @Override
139  public String toString() {
140    final StringBuilder s = new StringBuilder();
141    final Iterator<M> pit = getPremise().iterator();
142    if (pit.hasNext())
143      s.append(pit.next());
144    pit.forEachRemaining(m -> s.append(" " + UnicodeSymbols.WEDGE + " " + m));
145    s.append(" " + UnicodeSymbols.TO + " ");
146    final Iterator<M> cit = Sets.difference(getConclusion(), getPremise()).iterator();
147    if (cit.hasNext())
148      s.append(cit.next());
149    cit.forEachRemaining(m -> s.append(" " + UnicodeSymbols.WEDGE + " " + m));
150    if (confidence < 1d)
151      s.append(" (" + ((int) (100d * confidence)) + "%)");
152    return s.toString();
153  }
154
155}