2

我在使用网络投影的 Repast Simphony 时遇到问题。我有一系列代理在连续空间上排列成一个环,每个代理都使用网络投影连接到它的后继者。在实践中,每个代理都有一个从自身开始并指向其后继者的 Edge,然后它又被另一个 Edge 指向。代理来来去去,在执行模拟器时,我有以下堆栈跟踪:

repast.simphony.ui.GUIScheduleRunner - RunTimeException when running the schedule
Current tick (20.0)
java.lang.NullPointerException
    at saf.v3d.scene.VEdge2D.update(VEdge2D.java:90)
    at repast.simphony.visualizationOGL2D.NetworkLayerOGL2D.update(NetworkLayerOGL2D.java:96)
    at repast.simphony.visualizationOGL2D.DisplayOGL2D.update(DisplayOGL2D.java:410)
    at repast.simphony.visualization.engine.DisplayComponentControllerAction$DisplayUpdater.execute(DisplayComponentControllerAction.java:48)
    at repast.simphony.engine.schedule.DefaultAction.execute(DefaultAction.java:38)
    at repast.simphony.engine.schedule.ScheduleGroup.executeList(ScheduleGroup.java:205)
    at repast.simphony.engine.schedule.ScheduleGroup.execute(ScheduleGroup.java:238)
    at repast.simphony.engine.schedule.Schedule.execute(Schedule.java:352)
    at repast.simphony.ui.GUIScheduleRunner$ScheduleLoopRunnable.run(GUIScheduleRunner.java:52)
    at java.lang.Thread.run(Thread.java:745)

有趣的事实:如果我从显示器上移除网络投影,什么都不会失败。

这是我在构建器中初始化网络和连续空间的方式:

NetworkBuilder<Object> netBuilder = new NetworkBuilder<Object>(
                "chord network", context, true);
        netBuilder.buildNetwork();

        ContinuousSpaceFactory spaceFactory = ContinuousSpaceFactoryFinder
                .createContinuousSpaceFactory(null);
        ContinuousSpace<Object> space = spaceFactory.createContinuousSpace(
                "space", context, new RandomCartesianAdder<Object>(),
                new repast.simphony.space.continuous.WrapAroundBorders(), 50,
                50);

在代码中我以这种方式访问​​网络

Network<Object> net = (Network<Object>)context.getProjection("chord network");

最后,在代理的代码中,我以这种方式更改边缘:

// removing the edge
if (this.edge != null)
    net.removeEdge(this.edge);

// adding a new edge
net.addEdge(this, this.successor);

关于发生了什么的任何想法?

编辑:我模拟的是Chord,一种分布式哈希表协议。我的代理称为节点,每个节点都有一个指向其前任和后继的指针,并且它还处理指向其后继的边缘。

在任何滴答声中,都会选择并移除 3 个随机节点。此移除旨在作为节点的自愿离开,因此每个节点都会通过以下方式通知其后继者和前任者离开:

if (this.edge != null)
        this.net.removeEdge(this.edge);
this.successor.predecessor = this.predecessor;
if (this.predecessor != null) {
    this.predecessor.successor = this.successor;
    this.predecessor.successors = this.successors;
    if (this.predecessor.edge != null)
        this.net.removeEdge(this.predecessor.edge);
    this.predecessor.edge = this.net.addEdge(this.predecessor, this.successor);
}

之后,每个被移除的节点都会从上下文中移除。

以类似的方式,每个滴答都会创建 3 个新节点。选择一个随机位置后,将节点添加到上下文中,并添加一条从自身指向其后继节点的边,以这种方式

// this.edge is an attribute of Node, that is a pointer to the network
this.edge = this.net.addEdge(this, this.successor);

最后,每个节点都有一系列计划的方法,这些方法在每次迭代时执行。他们检查是否有新的后继者,在这种情况下,删除当前边,并添加新边

// in case a new successor is identified
if (this.edge != null)
    this.net.removeEdge(this.edge);
this.edge = this.net.addEdge(this, this.successor);

这些都是在网络上执行的所有操作。当然,协议是在稳定状态下模拟的,所以在开始时,构建器会创建一个包含N个节点和所有已校正边的上下文。

错误发生的时刻是不确定的:有时在 150 个滴答声之后,有时在第 5 个。

4

0 回答 0