001package conexp.fx.core.algorithm.exploration; 002 003/* 004 * #%L 005 * Concept Explorer FX 006 * %% 007 * Copyright (C) 2010 - 2019 Francesco Kriegel 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.util.Arrays; 026import java.util.Collections; 027import java.util.NoSuchElementException; 028import java.util.Set; 029import java.util.concurrent.Callable; 030import java.util.concurrent.ConcurrentHashMap; 031import java.util.concurrent.ExecutionException; 032import java.util.concurrent.ExecutorService; 033import java.util.stream.Collectors; 034 035import conexp.fx.core.context.Implication; 036import javafx.collections.FXCollections; 037import javafx.collections.MapChangeListener; 038import javafx.collections.ObservableMap; 039 040public class ExpertPool<G, M> implements Expert<G, M> { 041 042 enum Strategy { 043 ANSWER_FROM_FIRST_IDLE("Chooses a random idle expert and returns its/his/her answer."), 044 FIRST_ANSWER_FROM_IDLE("Use answer from fastest idle expert"), 045 FIRST_ANSWER("Use answer from fastest expert"), 046 SOME_CONFIRMS( 047 "Confirm all implications that are confirmed by at least one of the experts, i.e., reject all implications that are rejected by all experts."), 048 ALL_CONFIRM( 049 "Confirm all implications that confirmed by all experts, i.e., reject all implications that are rejected by at least one of the experts."); 050 051 private final String description; 052 053 private Strategy(final String description) { 054 this.description = description; 055 } 056 057 public String getDescription() { 058 return this.description; 059 } 060 061 } 062 063 private final ObservableMap<Expert<G, M>, Boolean> experts = FXCollections.observableMap(new ConcurrentHashMap<>()); 064 private final Strategy strategy; 065 private final ExecutorService exe; 066 067 public ExpertPool(final ExpertPool.Strategy strategy, final ExecutorService executor) { 068 this.strategy = strategy; 069 this.exe = executor; 070 this.experts.addListener((MapChangeListener<Expert<G, M>, Boolean>) change -> { 071 if (change.wasAdded() && change.wasRemoved()) { 072 System.out.println(change.getKey() + " IS NOW " + (change.getValueAdded() ? "IDLE" : "BUSY")); 073 } else if (change.wasAdded()) { 074 System.out.println(change.getKey() + " WAS ADDED AND IS " + (change.getValueAdded() ? "IDLE" : "BUSY")); 075 } else if (change.wasRemoved()) { 076 System.out.println(change.getKey() + " WAS REMOVED AND WAS " + (change.getValueRemoved() ? "IDLE" : "BUSY")); 077 } 078 }); 079 } 080 081 @Override 082 public Set<CounterExample<G, M>> getCounterExamples(Implication<G, M> implication) throws InterruptedException { 083 switch (strategy) { 084 case ANSWER_FROM_FIRST_IDLE: 085 return getIdleExpert().getCounterExamples(implication); 086 case FIRST_ANSWER_FROM_IDLE: 087 try { 088 return exe.invokeAny( 089 this.experts 090 .entrySet() 091 .parallelStream() 092 .filter(entry -> entry.getValue().equals(true)) 093 .map(entry -> entry.getKey()) 094 .map(expert -> (Callable<Set<CounterExample<G, M>>>) () -> { 095 try { 096 return expert.getCounterExamples(implication); 097 } catch (Exception e) { 098 return null; 099 } 100 }) 101 .collect(Collectors.toSet())); 102 } catch (ExecutionException e) { 103 return null; 104 } 105 case FIRST_ANSWER: 106 try { 107 return exe.invokeAny( 108 this.experts.keySet().parallelStream().map(expert -> (Callable<Set<CounterExample<G, M>>>) () -> { 109 try { 110 return expert.getCounterExamples(implication); 111 } catch (Exception e) { 112 return null; 113 } 114 }).collect(Collectors.toSet())); 115 } catch (ExecutionException e) { 116 return null; 117 } 118 case SOME_CONFIRMS: 119 if (experts.keySet().parallelStream().map(expert -> { 120 try { 121 return expert.getCounterExamples(implication); 122 } catch (Exception __) { 123 return null; 124 } 125 126 }).anyMatch(cex -> cex.isEmpty())) 127 return Collections.emptySet(); 128 case ALL_CONFIRM: 129 return experts.keySet().parallelStream().map(expert -> { 130 try { 131 return expert.getCounterExamples(implication); 132 } catch (Exception __) { 133 return null; 134 } 135 }).flatMap(Set::parallelStream).collect(Collectors.toSet()); 136 default: 137 return Collections.emptySet(); 138 } 139 140 } 141 142 @SafeVarargs 143 public final void add(final Expert<G, M>... experts) { 144 add(Arrays.asList(experts)); 145 } 146 147 public final void add(final Iterable<Expert<G, M>> experts) { 148 experts.forEach(expert -> this.experts.put(expert, true)); 149 } 150 151 @SafeVarargs 152 public final void remove(final Expert<G, M>... experts) { 153 remove(Arrays.asList(experts)); 154 } 155 156 public final void remove(final Iterable<Expert<G, M>> experts) { 157 experts.forEach(expert -> this.experts.remove(expert)); 158 } 159 160 public final boolean isIdle(final Expert<G, M> expert) { 161 return this.experts.get(expert); 162 } 163 164 public final boolean allIdle() { 165 return !this.experts.values().contains(false); 166 } 167 168 public final boolean someIdle() { 169 return this.experts.values().contains(true); 170 } 171 172 public final void setBusy(final Expert<G, M> expert) { 173 if (!this.experts.containsKey(expert)) 174 throw new IllegalArgumentException(); 175 this.experts.put(expert, false); 176 } 177 178 public final void setIdle(final Expert<G, M> expert) { 179 if (!this.experts.containsKey(expert)) 180 throw new IllegalArgumentException(); 181 this.experts.put(expert, true); 182 } 183 184 public final Expert<G, M> getIdleExpert() throws NoSuchElementException { 185 return this.experts 186 .entrySet() 187 .parallelStream() 188 .filter(entry -> entry.getValue().equals(true)) 189 .map(entry -> entry.getKey()) 190 .findAny() 191 .get(); 192 } 193 194 public final Strategy getStrategy() { 195 return this.strategy; 196 } 197 198}