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}