es.uam.eps.ir.relison.diffusion.propagation.PullPushStrategyPureRecommenderPropagationMechanism Maven / Gradle / Ivy
/*
* Copyright (C) 2020 Information Retrieval Group at Universidad Autónoma
* de Madrid, http://ir.ii.uam.es
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package es.uam.eps.ir.relison.diffusion.propagation;
import es.uam.eps.ir.relison.diffusion.data.Data;
import es.uam.eps.ir.relison.diffusion.data.PropagatedInformation;
import es.uam.eps.ir.relison.diffusion.simulation.SimulationEdgeTypes;
import es.uam.eps.ir.relison.diffusion.simulation.UserState;
import es.uam.eps.ir.relison.graph.edges.EdgeOrientation;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Propagation mechanism for the so-called rumour spreading propagation mechanism. Following this strategy, each user
* selects a user each iteration: he catches the information from such user, and shares with him the information he has.
* It is a combination of the pull and push propagation mechanisms. A certain amount of time has to pass before a
* neighbor is selected again.
*
* This variant only allows propagating information through recommended links.
*
*
* Reference: A. Demers, D. Greene, C. Hauser, W. Irish, J. Larson. Epidemic algorithms for replicated database maintenance. ACM PODC 1987, pp. 1-12 (1987)
*
*
* @author Javier Sanz-Cruzado ([email protected])
* @author Pablo Castells ([email protected])
*
* @param type of the users.
* @param type of the information pieces.
* @param type of the parameters.
*/
public class PullPushStrategyPureRecommenderPropagationMechanism implements PropagationMechanism
{
/**
* Number of iterations to wait until a profile can be revisited
*/
private final int waitTime;
/**
* For each user, the list of users that user will propagate the information to.
*/
private Map> propagationList;
/**
* The list of users in the last iterations
*/
private final Map> lastIterations;
/**
* The orientation for selecting the neighborhood.
*/
private final EdgeOrientation orientation;
/**
* Constructor.
* @param waitTime number of iterations to wait until a profile can be revisited.
* @param orientation the orientation for selecting the neighborhood.
*/
public PullPushStrategyPureRecommenderPropagationMechanism(int waitTime, EdgeOrientation orientation)
{
this.waitTime = waitTime;
this.lastIterations = new HashMap<>();
this.orientation = orientation;
}
@Override
public Stream getUsersToPropagate(PropagatedInformation information, UserState originUser, Data data)
{
if(propagationList.containsKey(originUser.getUserId()))
return propagationList.get(originUser.getUserId()).stream();
return Stream.empty();
}
@Override
public void resetSelections(Data data)
{
Random rng = new Random();
propagationList = new HashMap<>();
// For all the users in the system:
data.getAllUsers().forEach((u)->
{
// We first select a list of neighbors:
List neighbours = data.getGraph().getNeighbourhood(u, orientation).filter(v ->
{
if(orientation.equals(EdgeOrientation.IN))
{
return data.getGraph().getEdgeType(v, u) == SimulationEdgeTypes.RECOMMEND;
}
else if(orientation.equals(EdgeOrientation.OUT))
{
return data.getGraph().getEdgeType(u, v) == SimulationEdgeTypes.RECOMMEND;
}
else
{
return (data.getGraph().containsEdge(u, v) && data.getGraph().getEdgeType(u,v) == SimulationEdgeTypes.RECOMMEND) ||
(data.getGraph().containsEdge(v, u) && data.getGraph().getEdgeType(v,u) == SimulationEdgeTypes.RECOMMEND);
}
}).collect(Collectors.toCollection(ArrayList::new));
// Then, we obtain the already visited.
List alreadyVisited = lastIterations.containsKey(u) ? lastIterations.get(u) : new ArrayList<>();
U neigh;
// Select the neighbour
// First, we get which neighbors we can choose from:
List actualNeighs = new ArrayList<>();
for(U v : neighbours)
{
if(!alreadyVisited.contains(v)) actualNeighs.add(v);
}
if(actualNeighs.size() > 0) // if there are enough neighbors to choose from:
{
int index = rng.nextInt(neighbours.size());
neigh = neighbours.get(index);
}
else // otherwise, we do not choose a neighbor, and we exit the loop:
{
neigh = null;
}
if(neigh != null)
{
if(!propagationList.containsKey(neigh))
propagationList.put(neigh, new ArrayList<>());
if(!propagationList.get(neigh).contains(u))
propagationList.get(neigh).add(u);
if(!propagationList.containsKey(u))
propagationList.put(u, new ArrayList<>());
if(!propagationList.get(u).contains(neigh))
propagationList.get(u).add(neigh);
alreadyVisited.add(neigh);
}
else
{
alreadyVisited.add(null);
}
// Prune the list
if(alreadyVisited.size() > waitTime)
{
alreadyVisited.remove(0);
}
if(!this.lastIterations.containsKey(u))
{
this.lastIterations.put(u, alreadyVisited);
}
});
}
@Override
public boolean dependsOnInformationPiece()
{
return false;
}
}