agent-based-modeling - 吃饭 Java : scheduling agent and global behaviors in a structural way

标签 agent-based-modeling repast-simphony

我之前与 Netlogo 合作多年,并且非常习惯于基于一组过程开发基于代理的模型。供应链仿真模型结构示例如下:

;;the main simulation loop
@ScheduledMethod(start = 1, interval = 1)
public void step() {       
    place-order-to-suppliers() ;;procedures involving customer agent behaviors (a number of methods)
    receive-shipment-from-suppliers() ;;procedures involving both supplier and customer agents and their behaviors (methods)
    receive-order-from-customers()  ;;procedures involving supplier agent only 
    ship-order-to-customers() ;;procedures involving supplier agent only
    summarize()  ;;procedures involving global summary behaviors independent of any agents, as well as local summary behaviors per each type of agents (customer and supplier)
}

上述结构对于开发仿真模型非常有用且直观。我们首先将模拟世界划分为几个关键部分(程序),在其中我们进一步开发与相关代理和行为相关的特定方法。关键部分是建立一个更高级别的过程(如包),该过程可用于将不同类型的代理及其行为/交互集成(打包)到一个地方,并基于这些以所需的顺序执行模型程序。

是否有任何提示/示例可以在 Repast 中实现此类模块化建模策略?

更新: 下面是我编写的一个简单模型,它是关于男孩和女孩在聚会中如何互动的(完整引用可以在 https://ccl.northwestern.edu/netlogo/models/Party 找到)。下面是Boy类的代码(女孩也是一样的所以不再粘贴)。

package party;

import java.util.ArrayList;
import java.util.List;

import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.parameter.Parameters;
import repast.simphony.query.PropertyGreaterThan;
import repast.simphony.query.PropertyEquals;
import repast.simphony.query.Query;
import repast.simphony.random.RandomHelper;
import repast.simphony.space.continuous.ContinuousSpace;
import repast.simphony.space.grid.Grid;
import repast.simphony.space.grid.GridPoint;
import repast.simphony.util.ContextUtils;

public class Boy {
    private ContinuousSpace<Object> space;
    private Grid<Object> grid;
    private boolean happy;
    private int id, x, y,tolerance;
    private boolean over;

    Boy (Grid<Object> grid, int id, int x, int y) {
        this.grid = grid;
        this.id = id;
        this.x = x;
        this.y = y;
        Parameters p = RunEnvironment.getInstance().getParameters();
        int get_tolerance = (Integer) p.getValue("tolerance");
        this.tolerance = get_tolerance;
        }

//  @ScheduledMethod(start = 1, interval = 1,shuffle=true)
//  public void step() {
//      relocation();
//      update_happiness();
//      endRun();
//      
//  }

    public void endRun( ) {
        Context<Object> context = ContextUtils.getContext(this);
        Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
        int end_count = 0;
        for (Object o : query.query()) {
           if (o instanceof Boy) {
               end_count ++;               
           }
           if (o instanceof Girl) {
               end_count ++;               
           }
        }
        if (end_count == 70) {
            RunEnvironment.getInstance().endRun();
        }
    }



    public void update_happiness() {
        over = false;
        Context<Object> context = ContextUtils.getContext(this);
        Parameters p = RunEnvironment.getInstance().getParameters();
        int tolerance = (Integer) p.getValue("tolerance");
        GridPoint pt = grid.getLocation(this);
        int my_x = this.getX();
        int boy_count = 0;
        int girl_count = 0;
        Query<Object> query = new PropertyEquals<Object>(context, "x", my_x);
        for (Object o : query.query()) {
            if (o instanceof Boy) {
                boy_count++;
            }
            else {
                girl_count++;
            }
        }
        int total = boy_count + girl_count;
        double ratio = (girl_count / (double)total);
//      System.out.println((girl_count / (double)total));
        if (ratio <= (tolerance / (double)100)) {
            happy = true;
//          System.out.println("yes");
        }
        else {
            happy = false;
//          System.out.println("no");
        }
        over = true;
//      System.out.println(over);
    }

    public void relocation() {
        if (!happy) {
            List<Integer> x_list = new ArrayList<Integer>();
            for (int i = 5; i <= 50; i = i + 5) {
                x_list.add(i);
            }   
            int index = RandomHelper.nextIntFromTo(0, 9);
            int group_x = x_list.get(index);
            while(group_x == this.getX()){
                index = RandomHelper.nextIntFromTo(0, 9);
                group_x = x_list.get(index);
            }
            int group_y = 35;
            while (grid.getObjectAt(group_x,group_y) != null) {
                group_y = group_y + 1;
            }
            this.setX(group_x);
            grid.moveTo(this, group_x,group_y);
        }
    }

    public int getTolerance() {
        return tolerance;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public int getID() {
        return id;
    }

    public boolean getHappy() {
        return happy;
    }

    public boolean getOver() {
        return over;
    }


    public void setTolerance(int tolerance) {
        this.tolerance = tolerance;
    }
}

---------------------------------------------------------------------------------

上述代码的运行可以遵循标准的Repast Annotated调度方法。然而,由于我想对不同的代理及其方法进行一些集成,以允许创建更大的过程(方法),因此我设法创建一个全局调度程序代理类来管理此建模策略。下面是代码:

package party;

import java.util.ArrayList;
import java.util.List;

import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.engine.schedule.ScheduleParameters;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.engine.schedule.Schedule;
import repast.simphony.query.PropertyEquals;
import repast.simphony.query.Query;
import repast.simphony.util.ContextUtils;
import repast.simphony.util.collections.IndexedIterable;

public class Global_Scheduler {


    @ScheduledMethod(start = 1, interval = 1,shuffle=true)
    public void updateHappiness() {
        Context<Object> context = ContextUtils.getContext(this);
        IndexedIterable<Object> boy_agents = context.getObjects(Boy.class);
        IndexedIterable<Object> girl_agents = context.getObjects(Girl.class);

        for (Object b: boy_agents) {
            ((Boy) b).update_happiness();
        }
        for (Object g: girl_agents) {
            ((Girl) g).update_happiness();
        }
    }

    @ScheduledMethod(start = 1, interval = 1,shuffle=true)
    public void relocate() {
        Context<Object> context = ContextUtils.getContext(this);
        IndexedIterable<Object> boy_agents = context.getObjects(Boy.class);
        IndexedIterable<Object> girl_agents = context.getObjects(Girl.class);

        for (Object b: boy_agents) {
            ((Boy) b).relocation();
        }
        for (Object g: girl_agents) {
            ((Girl) g).relocation();
        }

    }


    @ScheduledMethod(start = 1, interval = 1,shuffle=true)
    public void summary() {
        Context<Object> context = ContextUtils.getContext(this);
        Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
        int total_count = 0;
        int boy_count = 0;
        int girl_count = 0;
        for (Object o : query.query()) {
           if (o instanceof Boy) {
               total_count ++;  
               boy_count++;
           }
           if (o instanceof Girl) {
               total_count ++;  
               girl_count++;
           }
        }
        System.out.println("Total happy person: " + total_count);
        System.out.println("Total happy boys: " + boy_count);
        System.out.println("Total happy girls: " + girl_count);     
    }

    @ScheduledMethod(start = 1, interval = 1,shuffle=true)
    public void endRun( ) {
        Context<Object> context = ContextUtils.getContext(this);
        Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
        int end_count = 0;
        for (Object o : query.query()) {
           if (o instanceof Boy) {
               end_count ++;               
           }
           if (o instanceof Girl) {
               end_count ++;               
           }
        }
        if (end_count == 70) {
            RunEnvironment.getInstance().endRun();
        }
    }
}

使用全局调度程序代理运行模型的上述代码工作正常,结果应该表现相同。但是,我不确定模型的执行是否真的遵循顺序(即 update_happiness() -> relocate() -> Summary() -> end_run())。我也想知道是否有更好和更简单的方法实现这样的建模策略?

最佳答案

您提供的代码示例几乎在就餐模型代理中完全按原样工作 - 您只需更改注释行前缀 ;;//并在代理类中实现 place-order-to-suppliers() 等方法。典型 ABM 中的代理行为结构遵循这个精确的结构。一种通用“步骤”方法,根据所需的执行顺序组合各个子步骤。

就餐常见问题解答中概述了多种行为安排方法:https://repast.github.io/docs/RepastReference/RepastReference.html#_scheduling 。如您在示例中提供的通过注释进行调度将定期或在单个时间步重复该行为。您还可以通过直接在 Repast 计划上放置操作来在模型中动态计划。这种类型的调度适用于基于事件的行为,例如调度由模型中的某些其他事件触发的一次性行为。您还可以使用 @Watch 注解进行调度,这些注解会根据注解中指定的一组条件触发行为。

关于agent-based-modeling - 吃饭 Java : scheduling agent and global behaviors in a structural way,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57655735/

相关文章:

netlogo - 限制代理可以建立的链接数量

repast-simphony - 吃饭 : plot the KPI of each single agent

geotools - Repast Simphony 上的最短距离?

java - Repast Simphony 项目自动生成时出错

java - Java 中基于代理的建模 - 动画问题

netlogo - 要求补丁评估后海龟的行为

social-networking - NetLogo:比较邻居的值

Netlogo,如何让海龟沿着小块之间的路径到达目的地

java - 我的循环出了什么问题?

java - 使用就餐模拟器时不断出现错误