Parallel#

The model used here is similar to the one in the serial use case, except that the simulation will be run for 100 steps and there will be 1000 agents. This is to show the difference between the runtimes of the two versions.

Note

For more details about the model, please refer to the serial use case.

In a python file, import the module:

import cuda_hybrid as ch

The model can be built using generate_model:

hm = ch.generate_model(1000, 'insurgency_simple.txt', 'watts')

After that, create interaction function. There can be multiple helper functions, but everything should be wrapped in one function only to passed as an argument. For this tutorial, the interaction is serial, while the FCMs will be run in parallel. These functions are exactly the same as the ones in Serial

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

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

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
        )

The insurgency_interact can then be passed to run_parallel, along with other arguments, which includes the hybridmodel object, a list of focus nodes, a list of thresholds for the focus nodes, the maximum number of iterations for the FCMs, and, optionally, number of steps.

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

The function run_parallel will return an average values across all agents for all the focus nodes. The results of the above simulation is shown below:

{'Rebelliousness': 0.9723588069677352}

The recorded time of the parallel version was 5.16 s, while that of the serial version was 2min 44s.