package org.egonet.graph.wholenet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import net.sf.functionalj.Function2;
import net.sf.functionalj.tuple.Pair;
import org.egonet.exceptions.MissingPairException;
import org.egonet.graph.wholenet.WholeNetworkTie.DiscrepancyStrategy;
import org.egonet.gui.wholenet.NameMapperFrame.NameMapping;
import org.egonet.model.Interview;
import org.egonet.model.Study;
import org.egonet.model.question.AlterPairQuestion;
import org.egonet.model.question.Question;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
/**
* This class encapsulates everything necessary to compile and retain data from
* a set of Egonet interviews into a whole network, including alter mappings.
*
* @author Martin
*
*/
public class WholeNetwork {
final private static Logger logger = LoggerFactory.getLogger(WholeNetwork.class);
final private Study study;
final private List<Interview> interviews;
final private List<NameMapping> nameMap;
// maps for fast access
private Map<Integer,WholeNetworkAlter> wholeNetworkAlters;
private Map<Pair<WholeNetworkAlter,WholeNetworkAlter>,WholeNetworkTie> wholeNetworkTies;
private Settings settings;
public WholeNetwork(Study study, List<Interview> interviews,
List<NameMapping> nameMap, Settings settings,
Function2<Map<String,String>,Interview,Integer> getAlterAttributes)
{
super();
this.study = study;
this.interviews = interviews;
this.nameMap = nameMap;
this.settings = settings;
build(getAlterAttributes);
}
public static class Settings {
public Integer inclusionThreshold = 1;
public Boolean alwaysIncludeEgo = true;
public Boolean egoAlwaysTiedToOwnAlters = true;
public DiscrepancyStrategy discrepancyStrategy = DiscrepancyStrategy.Majority;
}
public void build(Function2<Map<String,String>,Interview,Integer> getAlterAttributes) {
wholeNetworkAlters = new HashMap<Integer,WholeNetworkAlter>();
wholeNetworkTies = new HashMap<Pair<WholeNetworkAlter,WholeNetworkAlter>,WholeNetworkTie>();
// add all alters
for(NameMapping mapping : nameMap) {
int group = mapping.getGroup();
if(!wholeNetworkAlters.containsKey(group)) {
wholeNetworkAlters.put(group, new WholeNetworkAlter(group));
}
WholeNetworkAlter alter = wholeNetworkAlters.get(group);
alter.addOccurence(mapping);
}
// remove WholeNetworkAlters that are not mentioned in enough interviews
Map<Integer,WholeNetworkAlter> remainingAlters = new HashMap<Integer,WholeNetworkAlter>();
for(Entry<Integer,WholeNetworkAlter> entry : wholeNetworkAlters.entrySet()) {
if(entry.getValue().getOccurences().size() < settings.inclusionThreshold) {
if(settings.alwaysIncludeEgo) {
boolean isEgo = false;
for(NameMapping occurrence : entry.getValue().getOccurences()) {
if(occurrence.getAlterNumber().equals(-1)) {
isEgo = true;
}
}
if(isEgo) {
remainingAlters.put(entry.getKey(), entry.getValue());
}
}
} else {
// Include alter only if mentioned in enough interviews.
remainingAlters.put(entry.getKey(), entry.getValue());
}
}
wholeNetworkAlters = remainingAlters;
// Set attributes for remaining alters
for(WholeNetworkAlter wholeNetworkAlter : wholeNetworkAlters.values()) {
for(NameMapping mapping : wholeNetworkAlter.getOccurences()) {
wholeNetworkAlter.addAttributes(
getAlterAttributes.call(
mapping.getInterview(),
mapping.getAlterNumber()));
}
}
for(Interview interview : interviews) {
String [] thisInterviewAlterlist = interview.getAlterList();
// tie the ego to all alters
Pair<WholeNetworkAlter,NameMapping> ego = findAlter(interview, -1);
if(ego != null) {
for(int i = 0; i < interview.getAlterList().length; i++) {
Pair<WholeNetworkAlter,NameMapping> alter = findAlter(interview, i);
if(alter != null) {
tie(ego, alter, ego.getFirst().getId(), true, true);
}
}
}
// tie adjacent alters together
Iterator<Long> questions = study.getQuestionOrder(AlterPairQuestion.class).iterator();
while (questions.hasNext()) {
Question q = study.getQuestion((Long) questions.next());
if(q.determinesAdjacency()) {
try {
int [][] adj = interview.generateAdjacencyMatrix(q, false);
//int [][] adjWeight = interview.generateAdjacencyMatrix(q, true);
// loop through adj
// if adj[i][j] == 1, thisInterviewAlters[i] && thisInterviewAlters[j] are adjacent in final matrix
int alters = Math.min(adj.length,thisInterviewAlterlist.length);
for(int i = 0; i < alters; i++) {
for(int j = i+1; j < alters; j++) {
boolean adjacent = adj[i][j] == 1;
String alter1 = thisInterviewAlterlist[i];
String alter2 = thisInterviewAlterlist[j];
logger.debug(alter1 + "("+i+") and " + alter2 + "("+j+") are" +
(adjacent ? " " : " not ")+"adjacent");
// find whole network alters
Pair<WholeNetworkAlter,NameMapping> wholeAlter1 = findAlter(interview, i);
Pair<WholeNetworkAlter,NameMapping> wholeAlter2 = findAlter(interview, j);
if(wholeAlter1 != null && wholeAlter2 != null) {
if(wholeAlter1.getFirst().compareTo(wholeAlter2.getFirst()) > 0) {
Pair<WholeNetworkAlter,NameMapping> swap = wholeAlter1;
wholeAlter1 = wholeAlter2;
wholeAlter2 = swap;
}
// TODO: strength of tie, even if not adjacent
tie(wholeAlter1, wholeAlter2,
ego == null ? null : ego.getFirst().getId(),
adjacent,false);
}
}
}
} catch (MissingPairException ex) {
logger.error("Couldn't create adjacency matrix for question " + q, ex);
}
}
}
}
logger.info("# Alters: " + wholeNetworkAlters.size() + ", # Ties: " + wholeNetworkTies.size());
}
private Pair<WholeNetworkAlter,NameMapping> findAlter(Interview interview, Integer alterNumber) {
for(WholeNetworkAlter alter : wholeNetworkAlters.values()) {
for(NameMapping mapping : alter.getOccurences()) {
if(mapping.getInterview().equals(interview) && mapping.getAlterNumber().equals(alterNumber))
return new Pair<WholeNetworkAlter,NameMapping>(alter,mapping);
}
}
return null;
//throw new IllegalArgumentException("Alter did not exist -- it must have been derived from somewhere, so we *must* find it");
}
public Map<Integer, WholeNetworkAlter> getWholeNetworkAlters() {
return wholeNetworkAlters;
}
public Set<WholeNetworkTie> getWholeNetworkTies() {
Set<WholeNetworkTie> ties = Sets.newHashSet();
for(WholeNetworkTie tie : wholeNetworkTies.values()) {
if(tie.isTied(settings.discrepancyStrategy,settings.egoAlwaysTiedToOwnAlters)) {
ties.add(tie);
}
}
return ties;
}
public WholeNetworkTie getTie(WholeNetworkAlter alter1, WholeNetworkAlter alter2) {
WholeNetworkTie tie1 =
wholeNetworkTies.get(new Pair<WholeNetworkAlter,WholeNetworkAlter>(alter1,alter2));
if(tie1 != null) {
return tie1;
}
WholeNetworkTie tie2 =
wholeNetworkTies.get(new Pair<WholeNetworkAlter,WholeNetworkAlter>(alter2,alter1));
if(tie2 != null) {
return tie2;
}
return null;
}
private void tie(Pair<WholeNetworkAlter,NameMapping> wholeAlter1, Pair<WholeNetworkAlter,NameMapping> wholeAlter2,
Integer reporterMappingId, boolean isTied, boolean egoReportingOnSelf)
{
Pair<WholeNetworkAlter, WholeNetworkAlter> tieKey = new Pair<WholeNetworkAlter,WholeNetworkAlter>(wholeAlter1.getFirst(), wholeAlter2.getFirst());
if(!wholeNetworkTies.containsKey(tieKey)) {
wholeNetworkTies.put(tieKey, new WholeNetworkTie(tieKey));
logger.info("Saw new tie for first time: " + tieKey);
}
WholeNetworkTie tieEntry = wholeNetworkTies.get(tieKey);
if(isTied && egoReportingOnSelf) {
tieEntry.addEvidenceEgoSaysTied(reporterMappingId);
} else {
tieEntry.addEvidence(reporterMappingId, isTied);
}
}
public Pair<String[],int[][]> getAdjacencyMatrix() {
List<WholeNetworkAlter> alterList =
new ArrayList<WholeNetworkAlter>(wholeNetworkAlters.values());
int size = alterList.size();
String [] names = new String[size];
for(int i = 0; i < names.length; i++) {
names[i] = alterList.get(i).getId()+"";
}
int [][] adj = new int[size][size];
for(int x = 0; x < size; x++) {
for(int y = 0; y < size; y++) {
WholeNetworkAlter wholeAlter1 = alterList.get(x);
WholeNetworkAlter wholeAlter2 = alterList.get(y);
if(wholeAlter1.compareTo(wholeAlter2) > 0) {
WholeNetworkAlter swap = wholeAlter1;
wholeAlter1 = wholeAlter2;
wholeAlter2 = swap;
}
Pair<WholeNetworkAlter, WholeNetworkAlter> tieKey = new Pair<WholeNetworkAlter,WholeNetworkAlter>(wholeAlter1, wholeAlter2);
if(wholeNetworkTies.containsKey(tieKey)) {
WholeNetworkTie tie = wholeNetworkTies.get(tieKey);
adj[x][y] =
tie.isTied(
settings.discrepancyStrategy,
settings.egoAlwaysTiedToOwnAlters)
? 1 : 0;
}
else {
adj[x][y] = 0;
}
}
}
return new Pair<String[],int[][]>(names,adj);
}
}