All Downloads are FREE. Search and download functionalities are using the official Maven repository.

es.uam.eps.ir.relison.diffusion.simulation.Simulator Maven / Gradle / Ivy

The newest version!
/* 
 *  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.simulation;

import es.uam.eps.ir.relison.diffusion.data.Data;
import es.uam.eps.ir.relison.diffusion.data.Information;
import es.uam.eps.ir.relison.diffusion.data.PropagatedInformation;
import es.uam.eps.ir.relison.diffusion.io.backup.BinarySimulationWriter;
import es.uam.eps.ir.relison.diffusion.protocols.Protocol;
import es.uam.eps.ir.relison.diffusion.selections.Selection;
import es.uam.eps.ir.relison.diffusion.stop.StopCondition;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Class for the execution of information propagation simulations.
 *
 * @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 Simulator implements Serializable { /** * Stop condition for the simulation. */ private final StopCondition stop; /** * Communication protocol. */ private final Protocol protocol; /** * The data to use in the simulation. */ private Data data; /** * The current iteration. */ private int numIter; /** * Number of items that have propagated information in an iteration. */ private int currentPropagated; /** * Number of users that have propagated information in an iteration. */ private int currentPropagatingUsers; /** * Number of newly propagated information in an iteration. */ private long newlyPropagatedInfo; /** * Current state of the simulation. */ private SimulationState state; /** * For time-based simulations, the current timestamp. */ private Long currentTimestamp; /** * Full constructor. * @param protocol the communication protocol to apply. * @param stop the stop condition of the simulation. */ public Simulator(Protocol protocol, StopCondition stop) { this.protocol = protocol; this.stop = stop; this.state = new SimulationState<>(); } /** * Initializes and prepares the data. * @param data the complete data for the simulation. */ public void initialize(Data data) { this.data = data; this.state.initialize(this.data); System.out.println("Filtering done"); System.out.println(this.data.dataSummary()); this.numIter = 0; this.currentTimestamp = data.getTimestamps().first(); } /** * Initializes and prepares the data. * @param data the complete data for the simulation. * @param simulation the current state of the simulation. */ public void initialize(Data data, Simulation simulation) { this.data = data; this.state = simulation.getFinalState(this.protocol.getUpdate()); System.out.println("Filtering done"); System.out.println(this.data.dataSummary()); this.numIter = simulation.getInitialNumber() + simulation.getNumIterations(); long timestamp = data.getTimestamps().first(); for(int i = 0; i < simulation.getInitialNumber() + simulation.getNumIterations(); ++i) { timestamp = data.getTimestamps().higher(timestamp); } this.currentTimestamp = timestamp; } /** * Executes the simulation and stores the results in a file. This method does not backup the simulation. * @return the simulation evolution. */ public Simulation simulate() { return this.simulate(null); } /** * Executes the simulation and stores the results in a file. * @param backup file where we want to backup the simulation, to prevent errors. * @return the simulation evolution. */ public Simulation simulate(String backup) { Simulation simulation = new Simulation<>(this.data, this.numIter); long initTime = System.currentTimeMillis(); long alarmTime = 0L; long totalpropagated = 0L; Map receivedCount = new HashMap<>(); this.state.getAllUsers().forEach(u -> { long count = u.getReceivedInformation().count(); if(count > 0) receivedCount.put(u.getUserId(), count); }); // Start propagation do { /* Each iteration, we store the state of the simulation in an Iteration object. For instance, we store the newly received pieces of information by the different users. */ Iteration iteration = new SimpleIteration<>(this.numIter); long initialTime = System.currentTimeMillis(); // As a first step, we indicate that no user has propagated information during the current iteration. this.currentPropagated = 0; this.currentPropagatingUsers = 0; // Then, for each user in the network, we select the users towards whom they might propagate their information // pieces. // We reset the selections, i.e. if the propagation model has to select, for each user, a fixed set of users // towards whom propagate information, this method does it. this.protocol.getProp().resetSelections(data); // Map containing the information propagated by each user: Map allPropInfo = new HashMap<>(); // We first select the set of users in the system that will propagate information: this.protocol.getSelection().getSelectableUsers(data, state, numIter, this.currentTimestamp).forEach(u -> { // We get the current state of the user. UserState user = state.getUser(u); // Select which information pieces that the user will propagat. Selection sel = this.protocol.getSelection().select(user, data, state, numIter, this.currentTimestamp); // If any... int numProp = sel.numPropagated(); if(numProp > 0) { // a) we add it to the list ++this.currentPropagatingUsers; this.currentPropagated += sel.numPropagated(); allPropInfo.put(user.getUserId(), sel); // b) we move the given pieces to the propagated list. user.updateReceivedToPropagated(sel.getPropagateSelection().map(Information::getInfoId)); user.updateOwnToPropagated(sel.getOwnSelection().map(Information::getInfoId)); // c) we update the list of users who have information which can expire long propCount = sel.getPropagateSelection().count(); if(propCount > 0) { long c = receivedCount.getOrDefault(u, 0L) - propCount; if(c <= 0) receivedCount.remove(u); else receivedCount.put(u, c); } } }); List toRemove = new ArrayList<>(); // Once we have selected the information pieces that are going to be propagated, we can then select which // of them shall not be propagated in the future. // We run over the set of users who have information in the received list. receivedCount.keySet().forEach(u -> { // We get the actual state of the user. UserState user = state.getUser(u); // Expire the information // Apply the expiration of the received information pieces. List deleted = this.protocol.getExpiration().expire(user, data, numIter, this.currentTimestamp) .collect(Collectors.toCollection(ArrayList::new)); // Store the information about the discarded pieces this iteration. List discardedInfo = new ArrayList<>(); deleted.forEach(i -> discardedInfo.add(this.data.getInformationPiecesIndex().idx2object(i))); // If we can discard information: if(!discardedInfo.isEmpty()) { iteration.addDiscardingUser(user.getUserId(), discardedInfo); long c = receivedCount.get(u) - discardedInfo.size(); if(c <= 0) toRemove.add(u); receivedCount.put(u, receivedCount.get(u) - discardedInfo.size()); } user.discardReceivedInformation(deleted.stream()); }); toRemove.forEach(receivedCount::remove); this.newlyPropagatedInfo = 0; // If users can only observe information pieces from some users, then, we update these values. this.protocol.getSight().resetSelections(data); Set receivedUsers = new HashSet<>(); Map> receivedInfo = new HashMap<>(); // First, we identify the propagated information that reaches each user. allPropInfo.keySet().forEach(u -> { Selection sel = allPropInfo.get(u); List propInfo = new ArrayList<>(); if(!this.protocol.getProp().dependsOnInformationPiece()) { sel.getAll().forEach(piece -> propInfo.add(this.data.getInformationPiecesIndex().idx2object(piece.getInfoId()))); PropagatedInformation auxpp = new PropagatedInformation(-1,0,0); this.protocol.getProp().getUsersToPropagate(auxpp, state.getUser(u), data).forEach(v -> { if(!receivedInfo.containsKey(v)) receivedInfo.put(v, new ArrayList<>()); sel.getAll().forEach(piece -> receivedInfo.get(v).add(piece)); }); } else { sel.getAll().forEach(info -> { this.protocol.getProp().getUsersToPropagate(info, state.getUser(u), data).forEach(v -> { if(!receivedInfo.containsKey(v)) receivedInfo.put(v, new ArrayList<>()); receivedInfo.get(v).add(info); }); propInfo.add(this.data.getInformationPiecesIndex().idx2object(info.getInfoId())); }); } if(!propInfo.isEmpty()) { iteration.addPropagatingUser(u, propInfo); } }); // As a second step, for each receiving user, we determine which information is seen and which is not receivedInfo.keySet().forEach(u -> { UserState uState = this.state.getUser(u); List prop = this.protocol.getSight().seesInformation(uState, data, receivedInfo.get(u)); if(!prop.isEmpty()) { this.newlyPropagatedInfo += prop.size(); receivedUsers.add(u); prop.forEach(uState::updateSeen); } }); // Then, for each received users... receivedUsers.forEach(user -> { // We identify which information Map> seenInfo = new HashMap<>(); Map> rereceivedInfo = new HashMap<>(); UserState uState = state.getUser(user); // Now: int numRec = uState.getSeenInformation().mapToInt(propInfo -> { int numRereceived = 0; int info = propInfo.getInfoId(); Set authors = new HashSet<>(); propInfo.getCreators().forEach(cidx -> authors.add(data.getUserIndex().idx2object(cidx))); // We check whether the information is new or it has been re-received. if(!uState.containsDiscardedInformation(info) && !uState.containsOwnInformation(info) && !uState.containsPropagatedInformation(info) && !uState.containsReceivedInformation(info)) { // The information is new: numRereceived++; seenInfo.put(data.getInformationPiecesIndex().idx2object(info), authors); } else { if(!uState.containsReceivedInformation(info)) numRereceived++; rereceivedInfo.put(data.getInformationPiecesIndex().idx2object(info), authors); } // We move from seen to received the information piece, using the update mechanism. uState.updateSeenToReceived(info, this.protocol.getUpdate()); return numRereceived; }).sum(); uState.clearSeenInformation(); // We add to the iteration the set of information pieces that the user has seen: if(!seenInfo.isEmpty()) { iteration.addReceivingUser(user, seenInfo); } if(!rereceivedInfo.isEmpty()) { iteration.addReReceivingUser(user, rereceivedInfo); } if(receivedCount.containsKey(user)) { receivedCount.put(user, numRec + receivedCount.get(user)); } else { receivedCount.put(user, (long) numRec); } }); totalpropagated += this.currentPropagated; simulation.addIteration(iteration); // Move all the newly observed pieces to the received set. alarmTime += (System.currentTimeMillis() - initialTime); if(numIter%100 == 0) { System.out.println("Iteration " + numIter + " finished (" + alarmTime + " ms.)"); } numIter++; this.currentTimestamp = this.data.getTimestamps().higher(this.currentTimestamp); long endTime = System.currentTimeMillis(); if(backup != null && (endTime - initTime) > 3600 * 1000) // Each hour of simulation, store a backup { BinarySimulationWriter bsw = new BinarySimulationWriter<>(); bsw.initialize(backup); bsw.writeSimulation(simulation); initTime = System.currentTimeMillis(); } } // Checks whether the simulation has finished. while(!this.stop.stop(numIter, currentPropagated, currentPropagatingUsers, this.newlyPropagatedInfo, totalpropagated, data, currentTimestamp)); return simulation; } }