***CONTrOL*** *is an agent-based model developed for the purpose of studying behavioral mechanisms influencing social learning and performance within and across business organisations. CONTrOL stands for Complex Organisational and Network-driven Transmissions resulting in Organisation Learning.* # Control package This section contains the description of Control package. This consists of the MCS code objects clustered in one python code file (`mcs.py`). ## control.mcs module ```{eval-rst} .. automodule:: control.mcs :members: :undoc-members: :show-inheritance: ``` ### Belief System instance creation The `BeliefSystem` class serves to create instances of belief systems and initialises them with random weights. Also, it provides a method, `get`, to retrieve the weight associated with a particular layer within the belief system. * The `__init__` method is the constructor for the `BeliefSystem` class, and it is responsible for initializing instances of the class. * It takes one parameter, `numLayers`, which represents the number of landscape layers which are to be included in the belief system. * It generates a set of random weights for the belief system. The weights are created using a [Dirichlet distribution](https://numpy.org/doc/stable/reference/random/generated/numpy.random.dirichlet.html) and are stored in the `self.weights` attribute. These weights represent the significance of different landscape layers in the belief system. * The `get` method is used to retrieve the weight associated with a specific layer in the belief system. * It takes one parameter, `layer`, which represents the index of the layer for which the weight is to be retrieved. * The method returns the weight associated with the specified layer. It does this by indexing the `self.weights` attribute using the `layer` parameter. ```python class BeliefSystem: def __init__(self, numLayers): self.weights = np.random.dirichlet(np.ones(numLayers),size=1)[0] def get(self, layer): return self.weights[layer] ``` ### Boundary System instance creation The `__init__` method of the `BoundarySystem` class initializes a boundary system with a random resource margin within a specified range of 0 and the `maxAvailableMargin` as set in the [main module](#main.py). This margin is stored in the `self.resourceMargin` attribute for later use in the ABM. ```python class BoundarySystem: def __init__(self, maxAvailableMargin): self.resourceMargin = np.random.uniform(0,maxAvailableMargin) ``` ### Diagnostic Control System class definition elaborate #### Department Policy instance creation The `DepartmentPolicy` class is designed to store various policy-related attributes and preferences for a department within an organisation, including goal term importances, learning mode preferences, and personal skill preferences, along with lists to store data related to rewards and fitness improvements. This `DepartmentPolicy` is used to guide the department's actions and decision-making within the organization. The `__init__` method initialises such `DepartmentPolicy` instances. * It generates a set of goal term importances for the department. The `goalTermImportances` attribute is created and assigned random values using a [Dirichlet distribution](https://numpy.org/doc/stable/reference/random/generated/numpy.random.dirichlet.html). There here are two goal terms, as indicated by `np.random.dirichlet(np.ones(2), size=1)[0]`, and these values represent the manager's priorities or importance attached to these goals. These terms are a pair of importance weights summing up to 1. * [0] The first weight represent a preference towards achieving short-term goals which translates to a performance evaluation period that compares against previous month. * [1] The second weight represent a preference towards achieving long-term goals which translates to spending more energy on learning to invest in future performance improvement * It generates learning mode preferences for the department. The `learningModePreferences` attribute is created and assigned random values using a [Dirichlet distribution](#https://numpy.org/doc/stable/reference/random/generated/numpy.random.dirichlet.html). There are three learning modes, as indicated by `np.random.dirichlet(np.ones(3), size=1)[0]`. These learning preferences are expressed as weights summing up to 1 which represent the manager's preferences for three given types of learning: * [0] social learning (sharing among people); * [1] improving personal skills; * [2] exploring unknown edges (experimenting, without knowing the outcome). * It generates personal skill improvement preferences for the department. The `personalSkillPreferences` attribute is created and assigned random values using a [Dirichlet distribution](https://numpy.org/doc/stable/reference/random/generated/numpy.random.dirichlet.html). There are two personal skills or attributes, as indicated by `np.random.dirichlet(np.ones(2), size=1)[0]`, and these values represent the manager's preferences over two types of personal skills for employees to develop and improve: * [0] innovativeness * [1] prediction * The `rewards`, `fitness_improvements`, and `organisation_fitness_improvements` attributes are initialized as empty lists. These lists serve to store data related to rewards, fitness improvements, and organizational fitness improvements which serve as performance measurement systems for the department. These lists are initially empty and will be updated during the operation of the department. * Additionally, three functions are defined to calculate the department's average performance in terms of `rewards`, `fitness_improvements`, and `organisation_fitness_improvements`. Essentially the totals of these values are calculated for the department and divided by the number of employees. These are the following functions: * `getAverageReward` * `getAverageFitnessImprovement` * `getAverageOrganisationFitnessImprovement` ```python class DepartmentPolicy: def __init__(self): self.goalTermImportances = np.random.dirichlet(np.ones(2),size=1)[0] self.learningModePreferences = np.random.dirichlet(np.ones(3),size=1)[0] self.personalSkillPreferences = np.random.dirichlet(np.ones(2),size=1)[0] self.rewards = [] self.fitness_improvements = [] self.organisation_fitness_improvements = [] def getAverageReward(self): result = 0 for r in self.rewards: result += r return result/len(self.rewards) if len(self.rewards) > 0 else 0 def getAverageFitnessImprovement(self): result = 0 for r in self.fitness_improvements: result += r return result/len(self.fitness_improvements) if len(self.fitness_improvements) > 0 else 0 def getAverageOrganisationFitnessImprovement(self): result = 0 for r in self.organisation_fitness_improvements: result += r return result/len(self.organisation_fitness_improvements) if len(self.organisation_fitness_improvements) > 0 else 0 ``` Separately, a class object `DepartmentPolicyChange` is initialised to store and process changes made by the managers in department policies. The `__init__` The method simply initialises all values to 0. ```python class DepartmentPolicyChange: def __init__(self): self.goalTermImportances = [0,0] self.learningModePreferences = [0,0,0] self.personalSkillPreferences = [0,0] ``` #### Diagnostic Control System instance creation The `DiagnosticControlSystem` class is used to manage and record department policies, rewards, and fitness improvements. It can also apply policy changes and keeps a history of policy states and changes. * It initializes the `DiagnosticControlSystem` class. * It creates an initial department policy using the `DepartmentPolicy` class. * It initializes two lists: `policyHistory` to store a history of department policies, and `policyChangelog` to store policy changes using the `DepartmentPolicyChange()` function. * The `recordReward` function records rewards received by the department. * The `recordFitnessImprovement` function records fitness improvements achieved by the department. * The `recordOrganisationalFitnessImprovement` records organizational fitness improvements. * The `applyPolicyChange` function takes a `change` object as a parameter. * It creates a new policy by copying the current policy. * It adjusts the new policy based on the values in the `change` object, effectively applying the policy changes. * It ensures that policy values (e.g., goal term importances, learning mode preferences, personal skill preferences) are not allowed to go below zero. * It appends the current policy to the `policyHistory` list, records the policy change in the `policyChangelog` list, and sets the current policy to the new policy (`new_policy`). ```python class DiagnosticControlSystem: def __init__(self): self.policy = DepartmentPolicy() self.policyHistory = [self.policy] self.policyChangelog = [DepartmentPolicyChange()] def recordReward(self, reward): self.policy.rewards.append(reward) def recordFitnessImprovement(self, improvement): self.policy.fitness_improvements.append(improvement) def recordOrganisationFitnessImprovement(self, improvement): self.policy.organisation_fitness_improvements.append(improvement) def applyPolicyChange(self, change): new_policy = copy.deepcopy(self.policy) new_policy.goalTermImportances[0] += change.goalTermImportances[0] new_policy.goalTermImportances[1] += change.goalTermImportances[1] new_policy.learningModePreferences[0] += change.learningModePreferences[0] new_policy.learningModePreferences[1] += change.learningModePreferences[1] new_policy.learningModePreferences[2] += change.learningModePreferences[2] new_policy.personalSkillPreferences[0] += change.personalSkillPreferences[0] new_policy.personalSkillPreferences[1] += change.personalSkillPreferences[1] if new_policy.goalTermImportances[0] < 0: new_policy.goalTermImportances[0] == 0 if new_policy.goalTermImportances[1] < 0: new_policy.goalTermImportances[1] == 0 if new_policy.learningModePreferences[0] < 0: new_policy.learningModePreferences[0] == 0 if new_policy.learningModePreferences[1] < 0: new_policy.learningModePreferences[1] == 0 if new_policy.learningModePreferences[2] < 0: new_policy.learningModePreferences[2] == 0 if new_policy.personalSkillPreferences[0] < 0: new_policy.personalSkillPreferences[0] == 0 if new_policy.personalSkillPreferences[1] < 0: new_policy.personalSkillPreferences[1] == 0 self.policyHistory.append(self.policy) self.policyChangelog.append(change) self.policy = new_policy ``` ## Module contents ```{eval-rst} .. automodule:: control :members: :undoc-members: :show-inheritance: ```