Package rinde.sim.core.model.communication

Source Code of rinde.sim.core.model.communication.CommunicationModel2$CanCommunicate

package rinde.sim.core.model.communication;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;

import org.apache.commons.math3.random.RandomGenerator;

import rinde.sim.core.TimeLapse;
import rinde.sim.core.graph.Point;

import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

/**
* A version optimized for broadcasting
*
* @author Bartosz Michalik <bartosz.michalik@cs.kuleuven.be>
* @since 2.0
*/
public class CommunicationModel2 extends CommunicationModel {

  private Multimap<CommunicationUser, SimpleEntry<Message, Class<? extends CommunicationUser>>> toBroadcast;

  private final Comparator<CommunicationUser> xComp = new Comparator<CommunicationUser>() {
    @Override
    public int compare(CommunicationUser o1, CommunicationUser o2) {
      double diff = o1.getPosition().x - o2.getPosition().x;
      if (diff != 0) {
        return diff > 0 ? 1 : -1;
      }

      return o1.hashCode() - o2.hashCode();
    }
  };

  private final Comparator<CommunicationUser> yComp = new Comparator<CommunicationUser>() {
    @Override
    public int compare(CommunicationUser o1, CommunicationUser o2) {
      double diff = o1.getPosition().y - o2.getPosition().y;
      if (diff != 0) {
        return diff > 0 ? 1 : -1;
      }

      return o1.hashCode() - o2.hashCode();
    }
  };

  public CommunicationModel2(RandomGenerator generator) {
    super(generator);
    toBroadcast = ArrayListMultimap.create();
  }

  @Override
  public void afterTick(TimeLapse timeLapse) {
    broadcast();
    super.afterTick(timeLapse);
  }

  private void broadcast() {

    final ArrayList<CommunicationUser> xSorted = new ArrayList<CommunicationUser>(
        users);

    Collections.sort(xSorted, xComp);
    Multimap<CommunicationUser, SimpleEntry<Message, Class<? extends CommunicationUser>>> cache = toBroadcast;
    toBroadcast = ArrayListMultimap.create();

    for (CommunicationUser sender : cache.keySet()) {
      ArrayList<CommunicationUser> toCheck = select(xSorted, sender, true);

      CanCommunicate predicate = new CanCommunicate(sender);
      broadcast2(sender, cache.get(sender), predicate, toCheck);
    }
  }

  private ArrayList<CommunicationUser> select(
      final ArrayList<CommunicationUser> from, CommunicationUser sender,
      final boolean isX) {
    ArrayList<CommunicationUser> toCheck = new ArrayList<CommunicationUser>(
        1024);
    Comparator<CommunicationUser> c = null;
    double distance;
    if (isX) {
      c = xComp;
      distance = sender.getPosition().x - sender.getRadius();
    } else {
      c = yComp;
      distance = sender.getPosition().y - sender.getRadius();
    }
    int idx = Collections.binarySearch(from, sender, c);
    for (int i = idx; i >= 0; --i) {
      CommunicationUser user = from.get(i);
      double pos = (isX ? user.getPosition().x : user.getPosition().y);

      if (pos >= distance) {
        toCheck.add(user);
      } else {
        break;
      }
    }
    if (isX) {
      distance = sender.getPosition().x - sender.getRadius();
    } else {
      distance = sender.getPosition().y - sender.getRadius();
    }
    for (int i = idx + 1; i < from.size(); ++i) {
      CommunicationUser user = from.get(i);
      double pos = (isX ? user.getPosition().x : user.getPosition().y);
      if (pos <= distance) {
        toCheck.add(user);
      } else {
        break;
      }
    }
    return toCheck;
  }

  @Override
  public void broadcast(Message message) {
    toBroadcast
        .put(message.sender, new SimpleEntry<Message, Class<? extends CommunicationUser>>(
            message, null));
  }

  @Override
  public void broadcast(Message message, Class<? extends CommunicationUser> type) {
    toBroadcast
        .put(message.sender, new SimpleEntry<Message, Class<? extends CommunicationUser>>(
            message, type));
  }

  private void broadcast2(
      CommunicationUser sender,
      Collection<SimpleEntry<Message, Class<? extends CommunicationUser>>> collection,
      Predicate<CommunicationUser> predicate,
      ArrayList<CommunicationUser> toCheck) {
    if (toCheck.isEmpty()) {
      return;
    }

    ArrayList<CommunicationUser> toCommunicate = toCheck;

    if (toCheck.size() > 100) {
      Collections.sort(toCheck, yComp);
      toCommunicate = select(toCheck, sender, false);
      if (users.isEmpty()) {
        return;
      }
    }
    toCommunicate.remove(sender);

    HashSet<CommunicationUser> uSet = new HashSet<CommunicationUser>(
        toCommunicate.size() / 2);

    for (CommunicationUser u : toCommunicate) {
      if (predicate.apply(u)) {
        uSet.add(u);
      }
    }

    for (CommunicationUser u : uSet) {
      try {
        for (SimpleEntry<Message, Class<? extends CommunicationUser>> p : collection) {
          if (p.getValue() != null && !p.getValue().equals(u.getClass())) {
            continue;
          }
          sendQueue.add(SimpleEntry.entry(u, p.getKey().clone()));
        }
      } catch (CloneNotSupportedException e) {
        LOGGER.error("clonning exception for message", e);
      }
    }
  }

  /**
   * Check if an message from a given sender can be deliver to recipient
   *
   * @see CanCommunicate#apply(CommunicationUser)
   * @author Bartosz Michalik <bartosz.michalik@cs.kuleuven.be>
   * @since 2.0
   */
  class CanCommunicate implements Predicate<CommunicationUser> {

    private final Class<? extends CommunicationUser> clazz;
    private final CommunicationUser sender;

    public CanCommunicate(CommunicationUser sender,
        Class<? extends CommunicationUser> clazz) {
      this.sender = sender;
      this.clazz = clazz;
    }

    public CanCommunicate(CommunicationUser sender) {
      this(sender, null);
    }

    @Override
    public boolean apply(CommunicationUser input) {
      if (input == null) {
        return false;
      }
      if (clazz != null && !clazz.equals(input.getClass())) {
        return false;
      }
      // if(input.equals(sender)) return false;
      final Point iPos = input.getPosition();

      double prob = input.getReliability() * sender.getReliability();
      double rand = generator.nextDouble();
      if (prob <= rand) {
        return false;
      }

      double minRadius = Math.min(input.getRadius(), sender.getRadius());
      Point sPos = sender.getPosition();
      return Point.distance(sPos, iPos) <= minRadius;

    }
  }
}
TOP

Related Classes of rinde.sim.core.model.communication.CommunicationModel2$CanCommunicate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.