package happy.research.utils;
import happy.research.cf.TrustRating;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class TidalTrust
{
/**
* TidalTrust algorithm to infer trust
*
* @param userTNsMap
* {user, {trustors}} map
* @param userTrustorsMap
* @param userRatingsMap
* {user, {trust ratings}} map
* @param source
* source user
* @param sink
* target user
* @param maxDepth
* maximum length of the searching path
* @return
*/
@SuppressWarnings({ "unchecked" })
public static Map<String, Double> runAlgorithm(Map<String, Map<String, Double>> userTrusteesMap,
Map<String, Map<String, Double>> userTrustorsMap, Map<String, List<TrustRating>> userRatingsMap,
String source, int maxDepth)
{
Map<String, Double> trustees = userTrusteesMap.get(source);
if (trustees == null) return null; // no out-link from source node
LinkedList<String> toVisitNodes = new LinkedList<>();
for (String tee : trustees.keySet())
toVisitNodes.push(tee);
List<String> visitedNodes = new ArrayList<>();
visitedNodes.add(source);
List<String> tempNodes = new ArrayList<>();
List<String>[] data = new ArrayList[maxDepth + 1];
for (int i = 0; i < data.length; i++)
data[i] = new ArrayList<>();
int currentDepth = 1;
data[0].add(source);
Map<String, Double> pathFlowMap = new HashMap<>();
pathFlowMap.put(source, Double.MAX_VALUE);
Map<String, List<String>> nodesChildren = new HashMap<>();
Map<String, Double> trustors = null;
List<TrustRating> ratings = null;
while (!toVisitNodes.isEmpty() && currentDepth <= maxDepth)
{
String node = toVisitNodes.pop();
data[currentDepth].add(node);
if (visitedNodes.contains(node)) continue;
else visitedNodes.add(node);
trustees = userTrusteesMap.get(node);
if (trustees != null)
{
for (String tee : trustees.keySet())
{
if (!tempNodes.contains(tee) && !visitedNodes.contains(tee)) tempNodes.add(tee);
}
}
trustors = userTrustorsMap.get(node);
ratings = userRatingsMap.get(node);
for (String tor : trustors.keySet())
{
if (!visitedNodes.contains(tor)) continue;
double flow = Math.min(pathFlowMap.get(tor), getTrustRating(ratings, tor, node));
Double flow2 = pathFlowMap.get(node);
double pathflow = Math.max(flow, flow2 == null ? 0 : flow2);
pathFlowMap.put(node, pathflow);
List<String> children = null;
if (nodesChildren.containsKey(tor)) children = nodesChildren.get(tor);
else children = new ArrayList<>();
children.add(node);
nodesChildren.put(tor, children);
}
if (toVisitNodes.isEmpty() && !tempNodes.isEmpty())
{
toVisitNodes.addAll(tempNodes);
currentDepth++;
tempNodes.clear();
}
}
currentDepth = 1;
visitedNodes.clear();
visitedNodes.add(source);
Map<String, Double> trustScores = new HashMap<>();
trustScores.put(source, 1.0);
while (currentDepth <= maxDepth)
{
for (String sink : data[currentDepth])
{
Double threshold = pathFlowMap.get(sink);
if (threshold == null) continue;
trustors = userTrustorsMap.get(sink);
double numerator = 0;
double denominator = 0;
for (String tor : trustors.keySet())
{
if (!visitedNodes.contains(tor)) continue;
double rating = getTrustRating(userRatingsMap, tor, sink);
if (pathFlowMap.get(tor) >= threshold && rating >= 0)
{
numerator += trustScores.get(tor) * rating;
denominator += trustScores.get(tor);
}
}
if (denominator > 0)
{
trustScores.put(sink, numerator / denominator);
visitedNodes.add(sink);
}
}
currentDepth++;
}
trustScores.remove(source);
return trustScores;
}
private static double getTrustRating(List<TrustRating> ratings, String source, String sink)
{
if (ratings != null)
{
for (TrustRating r : ratings)
{
if (r.getTrustor().equals(source) && r.getTrustee().equals(sink)) return r.getRating();
}
}
return Double.NaN;
}
private static double getTrustRating(Map<String, List<TrustRating>> userRatingsMap, String source, String sink)
{
return getTrustRating(userRatingsMap.get(sink), source, sink);
}
}