package esl.cuenet.algorithms.firstk.personal; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import esl.cuenet.algorithms.firstk.personal.accessor.Candidates; import esl.cuenet.algorithms.firstk.personal.accessor.Source; import org.apache.log4j.Logger; import java.util.*; public class Voter { private HashMap<Candidates.CandidateReference, Integer> voteTable = new HashMap<Candidates.CandidateReference, Integer>(); private Candidates candidates = Candidates.getInstance(); private final int K = 30 ; private Logger logger = Logger.getLogger(Voter.class); public Voter() { zeros(); } private HashSet<Candidates.CandidateReference> previouslyVotedEntities = Sets.newHashSet(); public List<Candidates.CandidateReference> vote(EventContextNetwork network, Source[] sources, Time time) { List<EventContextNetwork.ECNRef> _persons = network.getVotableEntities(); List<Candidates.CandidateReference> votableCandidates = Lists.newArrayList(); for (EventContextNetwork.ECNRef p: _persons) { Candidates.CandidateReference ref = network.getCandidateReference(p); if (previouslyVotedEntities.contains(ref)) continue; votableCandidates.add(ref); } List<Candidates.CandidateReference> references = Lists.newArrayList(); List<EventContextNetwork> secondaries = Lists.newArrayList(); for (Candidates.CandidateReference ref: votableCandidates) { logger.info("Discovering for " + candidates.get(ref).toStringKey(Candidates.NAME_KEY)); for (Source source: sources) { List<Candidates.CandidateReference> p = source.knows(ref); if (p != null) references.addAll(p); List<EventContextNetwork> e = source.knowsAtTime(ref, time); if (e != null) secondaries.addAll(e); } } logger.info("Found " + references.size() + " references"); logger.info("Found " + secondaries.size() + " secondaries."); zeros(); knows(references); HashMap<Candidates.CandidateReference, Double> knowsScores = normCopyScores(); zeros(); knowsAtTime(secondaries); HashMap<Candidates.CandidateReference, Double> knowsAtTimesScores = normCopyScores(); previouslyVotedEntities.addAll(votableCandidates); return combine(votableCandidates, knowsScores, knowsAtTimesScores); } List<Map.Entry<Candidates.CandidateReference, Double>> scores = null; private List<Candidates.CandidateReference> combine(List<Candidates.CandidateReference> votableCandidates, Map<Candidates.CandidateReference, Double> knowsScoresMap, Map<Candidates.CandidateReference, Double> knowsAtTimesMap) { final double emailWeight = 0.5; final double locationWeight = 0.5; HashMap<Candidates.CandidateReference, Double> scoresMap = Maps.newHashMap(); for (Candidates.CandidateReference key: knowsScoresMap.keySet()) { if (votableCandidates.contains(key)) continue; scoresMap.put(key, knowsScoresMap.get(key) * locationWeight + knowsAtTimesMap.get(key) * emailWeight); } List<Candidates.CandidateReference> topK = Lists.newArrayList(); if (scoresMap.size() == 0) return topK; PriorityQueue<Map.Entry<Candidates.CandidateReference, Double>> ballot = new PriorityQueue<Map.Entry<Candidates.CandidateReference, Double>>(scoresMap.size(), new Comparator<Map.Entry<Candidates.CandidateReference, Double>>() { @Override public int compare(Map.Entry<Candidates.CandidateReference, Double> o1, Map.Entry<Candidates.CandidateReference, Double> o2) { return o2.getValue().compareTo(o1.getValue()); } }); ballot.addAll(scoresMap.entrySet()); scores = Lists.newArrayList(); while ( !ballot.isEmpty() ) { Map.Entry<Candidates.CandidateReference, Double> entry = ballot.remove(); if (entry.getValue() > 0) scores.add(entry); } int i=0; while (topK.size() < K && i < scores.size()) { Candidates.CandidateReference ref = scores.get(i).getKey(); if ( !votableCandidates.contains(ref) && !previouslyVotedEntities.contains(ref)) { topK.add(ref); } i++; } print(scores); return topK; } public int getRankOf(Candidates.CandidateReference cRef) { if (scores == null) return -1; int ix = 0; for (Map.Entry<Candidates.CandidateReference, Double> score: scores) { ix++; if (score.getKey().equals(cRef)) return ix; } return -2; } private void print(List<Map.Entry<Candidates.CandidateReference, Double>> scores) { logger.info("----------------------------------------------------------"); logger.info(" VOTE TABLE "); logger.info("----------------------------------------------------------"); int ix = 0; for (Map.Entry<Candidates.CandidateReference, Double> entry: scores) { logger.info(entry.getValue() + " " + candidates.get(entry.getKey()).toStringKey(Candidates.NAME_KEY)); if (ix++ > K) break; } } private void increment(Candidates.CandidateReference reference) { if ( !voteTable.containsKey(reference) ) return; int score = voteTable.get(reference); voteTable.put(reference, score + 1); } public void knows(List<Candidates.CandidateReference> references) { for (Candidates.CandidateReference ref: references) increment(ref); } private void zeros() { Iterator<Candidates.CandidateReference> iter = candidates.candidateIterator(); while (iter.hasNext()) voteTable.put(iter.next(), 0); } public void knowsAtTime(List<EventContextNetwork> secondaries) { for (EventContextNetwork secondary: secondaries) visitAndUpdate(secondary); } private void visitAndUpdate(final EventContextNetwork secondary) { secondary.visit(new EventContextNetwork.Visitor() { @Override public void visit(EventContextNetwork.Event event) { } @Override public void visit(EventContextNetwork.Person person) { increment(secondary.getCandidateReference(person.reference)); } }); } private HashMap<Candidates.CandidateReference, Double> normCopyScores() { int max = Collections.max(voteTable.values()); HashMap<Candidates.CandidateReference, Double> t = Maps.newHashMap(); for ( Map.Entry<Candidates.CandidateReference, Integer> entry: voteTable.entrySet()) { if (max == 0) t.put(entry.getKey(), (double) 0); else t.put(entry.getKey(), (double) entry.getValue()/max); } return t; } public List<Map.Entry<Candidates.CandidateReference, Integer>> sortScores() { Set<Map.Entry<Candidates.CandidateReference, Integer>> entrySet = voteTable.entrySet(); PriorityQueue<Map.Entry<Candidates.CandidateReference, Integer>> ballot = new PriorityQueue<Map.Entry<Candidates.CandidateReference, Integer>>(entrySet.size(), new Comparator<Map.Entry<Candidates.CandidateReference, Integer>>() { @Override public int compare(Map.Entry<Candidates.CandidateReference, Integer> o1, Map.Entry<Candidates.CandidateReference, Integer> o2) { return o2.getValue() - o1.getValue(); } }); ballot.addAll(entrySet); List<Map.Entry<Candidates.CandidateReference, Integer>> sortedList = Lists.newArrayList(); while ( !ballot.isEmpty() ) { Map.Entry<Candidates.CandidateReference, Integer> entry = ballot.remove(); if (entry.getValue() > 0) sortedList.add(entry); } return sortedList; } }