aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java
blob: d4c48b9ec049c21d10d9be1c8a4261bcc14ec544 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package edu.brown.cs.student.term.hub;

import edu.brown.cs.student.term.DatabaseQuerier;
import edu.brown.cs.student.term.repl.commands.SetupCommand;

import java.time.Instant;
import java.util.*;

public class HubSearch {

  LinkMapper mapper;
  Map<Holder, Set<Holder>> followerToLeaderMap = new HashMap<>();

  public HubSearch(LinkMapper mapper){
    this.mapper = mapper;
  }

  public Map<Holder, Double> runHubSearch(Instant start, Instant end){
    followerToLeaderMap = mapper.makeFollowerLinks(start, end);
    int numHolders = followerToLeaderMap.size();
    List<Holder> holders = new ArrayList<>(followerToLeaderMap.keySet());
    double[] weights = new double[numHolders];
    double[] rank = new double[numHolders];
    double[] rankPrime = new double[numHolders];
    System.err.println(numHolders + "\t" + getDigits(numHolders));
    Arrays.fill(rankPrime, 1.0 / numHolders);

    double thresh = Math.pow(.1, getDigits(numHolders));
    while(!withinDistance(rank, rankPrime, thresh)){
      rank = Arrays.copyOf(rankPrime, rankPrime.length);
      //calculating hub rank for ith holder
      for(int i = 0; i < numHolders; i++){
        rankPrime[i] = 0;
        //iterating through all holders to calculate hub rank
        for(int j = 0; j < numHolders; j++){
          double weightIJ = getWeight(holders.get(i), holders.get(j), numHolders);
          rankPrime[i] += (weightIJ * rank[j]);
        }
      }
    }

    //potentially should change this to be a map from holder id => double?
    Map<Holder, Double> hubRankMap = new HashMap<>();

    for(int i = 0; i < rankPrime.length; i++){
      hubRankMap.put(holders.get(i), rankPrime[i]);
    }

    return hubRankMap;
  }

  private double getWeight(Holder leader, Holder follower, int numHolders){

    //dampening factor
    double damp = 0.15;
    /*

     In Hub Search
     we have the leader and follower if follower links to (follows) leader,
     then we want to add some weight from follower to leader,
     but should that weight be diluted by the number of people
     who followed leader or the number of people who follower followed
     --- probably the second option ;( */
    Set<Holder> peopleFollowed = followerToLeaderMap.get(follower);

    int numberFollowed = peopleFollowed.size();

    if(peopleFollowed.contains(leader)){
      //constructs the leader to follower links as we go for use later on
      leader.addFollower(new Holder(follower.getId(), follower.getName()));
      return ((damp / numHolders) + (1 - damp) * (1.0 / numberFollowed));
    } else if(numberFollowed == 0){
      return ((damp / numHolders) + (1 - damp) * (1.0 / numHolders));
    } else {
      return (damp / numHolders);
    }
  }

  private boolean withinDistance(double[] r, double[] rPrime, double threshold){
    double sum = 0.0;
    for(int i = 0; i < r.length; i++){
      sum += Math.pow((r[i] - rPrime[i]), 2);
    }

    System.err.println(sum + "\t" + !(sum <= 0.0000001));

    return sum <= 0.001*threshold;
  }

  private int getDigits(int numFollowers) {
    int count = 1;
    int temp = numFollowers;
    while(temp >= 10) {
      count++;
      temp /= 10;
      System.out.println(temp);
    }
    return count;
  }
}