Serial#

The two-agent model used in this tutorial is described below:

../_images/insurgency_simple.svg

Each agent has three nodes: Economic Development(ED), Rebelliousness(R), Ability of Insurgents to Control Population(AICP).

The two agents will interact with each other, and their final values for Rebelliousness will be recorded.

By default, the simulation will run 100 times.

In a python file, import the cuda_hybrid module:

import cuda-hybrid as md

Next, create a model using generate_model:

hm = md.generate_model(2, "newman", "insurgency_simple.txt")

The text file can be found here: insurgency_simple.txt

Now create a function that simulates the interactions between the agents:

Note

The interactions can be broken up into different methods, but these methods need to be wrapped into one function only in order to be passed to the run_serial method.

The two rules for agent interactions for this model are:

#. If the sum of ED values of an agent’s neighbors is larger than 110% of the agent’s ED, the agent’s ED will increase by 5%. If the sum is smaller than 90% of the agent’s ED, the agent’s ED will decrease by 5%. The code for this is illustrated below:

def econ_influence(val, influencing):
    threshold = 10
    impact = 5
    avg = 0.0
    for num in influencing:
        avg += num
    lowerThresh = 1 - threshold / 100.0
    upperThresh = 1 + threshold / 100.0
    result = val
    if avg > val * upperThresh:
        result += val * impact / 100.0
    elif avg < val * lowerThresh:
        result -= val * impact / 100.0
    return result

#. The agent’s new ED value from the previous step will be influenced by its neighbors’ AICP values. Deduct 10% of the total AICPs of its neighbors from its new ED value:

def insurgency_influence(influencedVal, influencing):
    rate = 0.1
    avg = 0.0
    result = influencedVal
    for num in influencing:
        result -= rate * num
    avg /= len(influencing)
    return result

The two above methods can be put into one function as follows:

def insurgency_interact(hm):
    if hm.ABM_adj.shape[0] <= 1:
        return
    # loop through each agent
    for agent in range(hm.ABM_adj.shape[0]):
        # grab the neighbors
        friends = hm.get_neighbors(agent)
        # get the numeric index for EconomicDevelopment and AbilityOfInsurgentsToControlThePopulation
        econIdx = hm.fcm_labels["EconomicDevelopment"]
        insurgeIdx = hm.fcm_labels["AbilityOfInsurgentsToControlThePopulation"]
        econList = []
        insurgeList = []
        # get the list of values for all the neighbors for the two concepts
        for friend in friends:
            econList.append(hm.node_val[friend][econIdx])
            insurgeList.append(hm.node_val[friend][insurgeIdx])
        # agents now influence each other
        hm.node_future_val[agent][econIdx] = econ_influence(
                hm.node_val[agent][econIdx],
                econList
        )
        hm.node_future_val[agent][econIdx] = insurgency_influence(
                hm.node_future_val[agent][econIdx],
                insurgeList
        )

Note

The above method takes the HybridModel object as the only argument. This can be changed depending on the use case

To run the simulation, call the run_serial. The last argument, which is the number of steps is set to 20 by default. The arguments for the interaction function must be put into an array:

hm.run_serial(["Rebelliousness"], [0.05], 10, insurgency_interact, [hm], 100)

Runtime can be recorded by using timeit:

from timeit import Timer

def run():
    hm = generate_model(2, "newman", "insurgency_simple.txt")
    hm.run_serial(["Rebelliousness"], [0.05], 10, insurgency_interact, [hm], 100)
t = Timer('run()','from test_insurgency import run')
# run the function a total of 20 times and measure the time
print(t.timeit(20))

Another way to record time is to use %timeit and %run via ipython package. After everything has been set up, %timeit can be used as:

In [75]: %timeit hm.run_serial(["Rebelliousness"], [0.05], 10, insurgency_interact, [hm], 100)

If the model is in a python file, the following code will run the file from within ipython and measure the time:

In [10]: %timeit %run ./test_insurgency.py

The average values of all the focus nodes across all agents are displayed below:


The recorded time using the second method was 1.35 ms seconds.