1

I want to achieve a logic like this:

while (count loading_docks with [status == "free"] > 0 and trucks with [status == "free" and type == "20'" and capacity < 1000] > 0) {
   match a truck satisfying above 3 condidtions to a free dock for unloading cargo;
}

as can be seen, the query needs to be repetively called and updated in the while loop, and the second query is composed of 3 conditions (Which is not easy with AndQuery() method).

This is very easy to implement in Netlogo. What is the suitable and shorter way to achieve in repast?

UPDATE - the initial attempt

    public void match_dock() {


        for (Truck t: this.getTruck_queue()) {
            if (this.Count_freeDock() > 0) {
                Query<Object> fit_dock = new AndQuery(
                                            new PropertyEquals(context, "status", 1), 
                                            new PropertyGreaterThanEquals(context, "max_veh", t.getTruck_type()));
                double min = 10000; 
                Dock match = null;
                for(Object o: fit_dock.query()) {
                    if (((Dock)o).getMax_veh() < min) {
                        match = (Dock)o;
                    }
                }
                match.setStatus(2);
                match.getServe_list().add(t.getReq_id());
                t.setServe_dock(match.getId());
//              if (t.getServe_dock() != -1) {
//                  this.getTruck_queue().remove(t);
//              }
            }
        }
    }



    public int Count_freeDock() {
        List<Dock> free_list = new ArrayList<Dock>();
        Query<Object> free_dock = new PropertyEquals<Object>(context, "status", 1);
        for (Object o : free_dock.query()) {
            if (o instanceof Dock) {
                free_list.add((Dock)o);
            }
        }
        return free_list.size();
    } 

There are three issues to fix:

1) The query of a particular agent set has to consider three conditions; AndQuery only composes two conditions. is there a Query method which allows more than two conditions to be considered at the same time?

current problem:

Query<Object> pre_fit = new AndQuery(
                            new PropertyEquals(context, "status", 1), 
                            new PropertyGreaterThanEquals(context, "max_veh", t.getTruck_type()));

Query<Object> fit_dock = new AndQuery(pre_fit, new PropertyEquals(context, "ops_type", 3));

The initial composition of two conditions works fine and queries fast. However, when I add the third condition "ops_type", the query speed becomes hugely slow. What's the reason behind? Or is this a correct way to compose three conditions?

2) Is there simpler way to query the size (count) of a particular agent set, other than writing a custom count function (as shown in example)?

3) what is the shortest way to add(or copy) the queried agent set into a list for related list operations?

update entire code block:

    public void match_dock() {

        Iterator<Truck> truck_list = this.getTruck_queue().iterator();
        while(truck_list.hasNext() && this.Count_freeDock() > 0) {
            Truck t = truck_list.next();
//              Query<Object> pre_fit = new AndQuery(
//                                          new PropertyEquals(context, "status", 1), 
//                                          new PropertyGreaterThanEquals(context, "max_veh", t.getTruck_type()));
//              Query<Object> ops_fit = new OrQuery<>(
//                                          new PropertyEquals(context, "ops_type", 3), 
//                                          new PropertyEquals(context, "ops_type", this.getOps_type(t.getOps_type())));
//              Query<Object> fit_dock = new AndQuery(pre_fit, new PropertyEquals(context, "ops_type", 3));
//              Query<Object> fit_dock = new AndQuery(pre_fit, ops_fit);

                Query<Object> pre_fit = new AndQuery(
                        new PropertyEquals(context, "status", 1), 
                        new PropertyGreaterThanEquals(context, "max_veh", t.getTruck_type()));

                Query<Object> q = new PropertyEquals(context, "ops_type", 3);


                double min = 10000; 
                Dock match = null;
                for (Object o : q.query(pre_fit.query())) {
//              for(Object o: fit_dock.query()) {
                    if (((Dock)o).getMax_veh() < min) {
                        match = (Dock)o;
                    }
                }
                try {
                    match.setStatus(2);
                    match.getServe_list().add(t.getReq_id());
                    t.setServe_dock(match.getId());
                    if (t.getServe_dock() != -1) {
                        System.out.println("truck id " + t.getReq_id() + "serve dock: " + t.getServe_dock());
                        t.setIndock_tm(this.getTick());
                        truck_list.remove();
                    }
                }
                catch (Exception e){
//                  System.out.println("No fit dock found");
                }           
        }
    }



    public int Count_freeDock() {

        List<Dock> free_list = new ArrayList<Dock>();
        Query<Object> free_dock = new PropertyEquals<Object>(context, "status", 1);
        for (Object o : free_dock.query()) {
            if (o instanceof Dock) {
                free_list.add((Dock)o);
            }
        }
//      System.out.println("free trucks: " + free_list.size());
        return free_list.size();
    }

UPDATE on 5/5

I have moved the query outside the while loop for better detection. I found the slow speed could be largely due to the use of "PropertyGreaterThanEquals". regardless whether the queried field is int or double.

  1. when you query using "PropertyGreaterThanEquals", the query runs very slow regardless wether the queried field is int or double. However, it returns correct result.
  2. when you query using "PropertyEquals", the query runs in less than one second regardless wether the queried field is int or double. however, it returns result which is not correct since it needs to consider ">=".

    public void match_dock() {
        System.out.println("current tick is: " + this.getTick());
        Iterator<Truck> truck_list = this.getTruck_queue().iterator();
    
        Query<Object> pre_fit = new AndQuery(
                new PropertyEquals(context, "status", 1), 
                new PropertyGreaterThanEquals(context, "max_veh", 30));
                //new PropertyEquals(context, "max_veh", 30));
    
        Query<Object> q = new PropertyEquals(context, "hv_spd", 240);
    
    
        for (Object o : q.query(pre_fit.query())) {
            if (o instanceof Dock) {
            System.out.println("this object is: " + ((Dock)o).getId());
            }
        }
    

    }

Jack
  • 1,339
  • 1
  • 12
  • 31

1 Answers1

2

For 1, you could try chaining the queries like so:

Query<Object> pre_fit = new AndQuery(
                        new PropertyEquals(context, "status", 1), 
                        new PropertyGreaterThanEquals(context, "max_veh", t.getTruck_type()));

Query<Object> q = new PropertyEquals(context, "ops_type", 3);
for (Object o : q.query(pre_fit.query())) { ...

I think this can be faster than the embedding the AndQuery, but I'm not entirely sure.

For 2, I think some of the Iterables produced by a Query are in fact Java Sets. You could try to cast to one of those and then call size(). If its not a set then you do in fact have to iterate as the query filter conditions are actually applied as part of the iteration.

For 3, I think there are some Java methods for this. new ArrayList(Iterable), and some methods in Collections.

Nick Collier
  • 1,786
  • 9
  • 10
  • the channing query is as slow as my method. It's really weird! The model can finish run in less than one second with only two conditions. but when an additional condition is added, it costs more than two minutes to run and the tick is gettting slower and slower gradually. I doubt there is an underlying problem. Please see my updated entire code block. – Jack May 04 '20 at 14:27
  • would it be something wrong with the context? I have made the context a variable of the agent and initialize it in the context builder. (i.e. private Context context; then setContext(context) in context builder; so that i dont have to put Context context = ContextUtils.getContext(this) in every function. I have tried to remove context as the variable and use the latter one but the speed is as slow as the previous one. – Jack May 04 '20 at 14:38
  • Will the results of the "ops_type" query change within the outer while loop? If not, you could run that query outside the loop to create a Set. Then as part of looping over the AndQuery check if the object is in that set. – Nick Collier May 04 '20 at 14:44
  • I am not sure I am understanding. could you make a code example? Ideally I want one query that can return me an agent set (docks) meeting all three conditions. – Jack May 04 '20 at 14:59
  • I don't know why it would be slow. You could try replacing the queries with a loop through the context that checks for the right status and max_veh values. There is some dynamic compilation involved here to make the query relatively fast, so it shouldn't be that slow. – Nick Collier May 04 '20 at 19:17
  • I found it’s not something to do with the data type, but with the method “PropertyGreaterThanEquals” . the " >= " query runs much much slower than “PropertyEquals” regardless whether the queried field is int or double – Jack May 04 '20 at 19:22
  • since this problem is largely related to the method “PropertyGreaterThanEquals” , I have opened a new question for further discussion: https://stackoverflow.com/questions/61606900/repast-propertygreaterthanequals-propertylessthanequals-cause-slow-running-spe – Jack May 05 '20 at 06:21