From f157bb0b31fc424856c48b62f24f46a498a362a9 Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 4 Dec 2024 09:34:00 +0100 Subject: [PATCH 01/13] Allow for calmar var_number counting positive value --- openfisca_survey_manager/calibration.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/openfisca_survey_manager/calibration.py b/openfisca_survey_manager/calibration.py index ddf8be6f..42e09398 100644 --- a/openfisca_survey_manager/calibration.py +++ b/openfisca_survey_manager/calibration.py @@ -52,8 +52,9 @@ def __init__(self, simulation, target_margins, period, target_entity_count = Non variable_instance_by_variable_name = simulation.tax_benefit_system.variables entities = set( variable_instance_by_variable_name[variable].entity.key - for variable in margin_variables + for variable in margin_variables if not variable.endswith("_number") ) + assert all([(len(variable.split("_number")) < 3) for variable in margin_variables]), "invalid name of a variable for calibration, with '_number' not only in last position" if entity is not None: entities.add(entity) self.entities = list(entities) @@ -131,8 +132,13 @@ def _build_calmar_data(self) -> dict: data[self.target_entity][self._initial_weight_name] = self.initial_weight * self.filter_by period = self.period for variable in self.margins_by_variable: - assert variable in self.simulation.tax_benefit_system.variables - data[self.simulation.tax_benefit_system.variables[variable].entity.key][variable] = self.simulation.adaptative_calculate_variable(variable, period = period) + assert variable in self.simulation.tax_benefit_system.variables or variable.split("_number")[0] in self.simulation.tax_benefit_system.variables + if variable.endswith("_number"): + assert self.simulation.tax_benefit_system.variables[variable.split("_number")[0]].value_type in [int, float], "variable with suffix 'number' should be float-like so we can separate the positive values" + value = (self.simulation.adaptative_calculate_variable(variable.split("_number")[0], period = period) > 0).astype(int) + else: + value = self.simulation.adaptative_calculate_variable(variable, period = period) + data[self.simulation.tax_benefit_system.variables[variable].entity.key][variable] = value if len(self.entities) == 2: for entity in self.entities: @@ -209,8 +215,8 @@ def set_target_margin(self, variable, target): """ simulation = self.simulation period = self.period - assert variable in simulation.tax_benefit_system.variables - variable_instance = simulation.tax_benefit_system.variables[variable] + assert variable in simulation.tax_benefit_system.variables or variable.split("_number")[0] in simulation.tax_benefit_system.variables + variable_instance = simulation.tax_benefit_system.variables[variable.split("_number")[0]] filter_by = self.filter_by target_by_category = None @@ -275,10 +281,13 @@ def _update_margins(self): filter_by = self.filter_by initial_weight = self.initial_weight - value = simulation.adaptative_calculate_variable(variable, period = period) + if variable.endswith("_number"): + value = (simulation.adaptative_calculate_variable(variable.split("_number")[0], period = period) < 0).astype(int) + else: + value = simulation.adaptative_calculate_variable(variable, period = period) weight_variable = simulation.weight_variable_by_entity[target_entity] - if len(self.entities) == 2 and simulation.tax_benefit_system.variables[variable].entity.key != self.target_entity: + if len(self.entities) == 2 and simulation.tax_benefit_system.variables[variable.split("_number")[0]].entity.key != self.target_entity: value_df = pd.DataFrame(value) id_variable = self.parameters["id_variable_link"] value_df[id_variable] = simulation.adaptative_calculate_variable(id_variable, period = period) @@ -297,7 +306,7 @@ def _update_margins(self): ('initial', initial_weight), ] - variable_instance = simulation.tax_benefit_system.get_variable(variable) + variable_instance = simulation.tax_benefit_system.get_variable(variable.split("_number")[0]) assert variable_instance is not None if variable_instance.value_type in [bool, Enum]: margin_items.append(('category', value)) From b3b21abf0486c3252a72de13e6162c9ac2487b60 Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 4 Dec 2024 09:44:50 +0100 Subject: [PATCH 02/13] Update test --- openfisca_survey_manager/tests/test_calmar.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openfisca_survey_manager/tests/test_calmar.py b/openfisca_survey_manager/tests/test_calmar.py index 90851750..92774fa7 100644 --- a/openfisca_survey_manager/tests/test_calmar.py +++ b/openfisca_survey_manager/tests/test_calmar.py @@ -106,7 +106,8 @@ def create_margins(entities = 1): 1: 30, 2: 50, }, - 'Z': 140.0 + 'Z': 140.0, + 'Z_number': 80, } if entities == 2: margins_by_variable['C'] = 85 From b514ff2e97028aa4321c5742c059ec9b87040c39 Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 4 Dec 2024 09:50:48 +0100 Subject: [PATCH 03/13] Bump --- CHANGELOG.md | 6 +++++- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b769325b..af71cbec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog +### 3.0.2 [#324](https://github.com/openfisca/openfisca-survey-manager/pull/324) -# 3.0.1 [#322](https://github.com/openfisca/openfisca-survey-manager/pull/322) +* New feature + - Introduce the possibility to use calmar on variables with a suffix "_number", with target the weighted sum of the number of positive value of the variable. Only the variable without "_number" should be in the tax benefit system. + +### 3.0.1 [#322](https://github.com/openfisca/openfisca-survey-manager/pull/322) * Technical changes - Fix build. diff --git a/pyproject.toml b/pyproject.toml index cab4f1b7..4f3fd520 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "OpenFisca-Survey-Manager" -version = "3.0.1" +version = "3.0.2" description = "A tool for managing survey/administrative data and import them in OpenFisca" readme = "README.md" keywords = ["microsimulation", "tax", "benefit", "rac", "rules-as-code", "survey", "data"] From e15e885e52a69bfce3370875deb6b4679c9b8685 Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 4 Dec 2024 16:34:23 +0100 Subject: [PATCH 04/13] Use expressions instead of _number --- openfisca_survey_manager/calibration.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openfisca_survey_manager/calibration.py b/openfisca_survey_manager/calibration.py index 42e09398..aca75fb4 100644 --- a/openfisca_survey_manager/calibration.py +++ b/openfisca_survey_manager/calibration.py @@ -52,9 +52,8 @@ def __init__(self, simulation, target_margins, period, target_entity_count = Non variable_instance_by_variable_name = simulation.tax_benefit_system.variables entities = set( variable_instance_by_variable_name[variable].entity.key - for variable in margin_variables if not variable.endswith("_number") + for variable in margin_variables if not len(variable.split(" ")) > 1 ) - assert all([(len(variable.split("_number")) < 3) for variable in margin_variables]), "invalid name of a variable for calibration, with '_number' not only in last position" if entity is not None: entities.add(entity) self.entities = list(entities) @@ -132,10 +131,10 @@ def _build_calmar_data(self) -> dict: data[self.target_entity][self._initial_weight_name] = self.initial_weight * self.filter_by period = self.period for variable in self.margins_by_variable: - assert variable in self.simulation.tax_benefit_system.variables or variable.split("_number")[0] in self.simulation.tax_benefit_system.variables - if variable.endswith("_number"): - assert self.simulation.tax_benefit_system.variables[variable.split("_number")[0]].value_type in [int, float], "variable with suffix 'number' should be float-like so we can separate the positive values" - value = (self.simulation.adaptative_calculate_variable(variable.split("_number")[0], period = period) > 0).astype(int) + assert variable in self.simulation.tax_benefit_system.variables or variable.split(" ")[0] in self.simulation.tax_benefit_system.variables + if len(variable.split(" ")) > 1: + var_to_eval = simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) + value = eval('var_to_eval' + ''.join(variable.split(" ")[1: ])).astype(float) else: value = self.simulation.adaptative_calculate_variable(variable, period = period) data[self.simulation.tax_benefit_system.variables[variable].entity.key][variable] = value @@ -215,8 +214,8 @@ def set_target_margin(self, variable, target): """ simulation = self.simulation period = self.period - assert variable in simulation.tax_benefit_system.variables or variable.split("_number")[0] in simulation.tax_benefit_system.variables - variable_instance = simulation.tax_benefit_system.variables[variable.split("_number")[0]] + assert variable in simulation.tax_benefit_system.variables or variable.split(" ")[0] in simulation.tax_benefit_system.variables + variable_instance = simulation.tax_benefit_system.variables[variable.split(" ")[0]] filter_by = self.filter_by target_by_category = None @@ -281,13 +280,14 @@ def _update_margins(self): filter_by = self.filter_by initial_weight = self.initial_weight - if variable.endswith("_number"): - value = (simulation.adaptative_calculate_variable(variable.split("_number")[0], period = period) < 0).astype(int) + if len(variable.split(" ")) > 1: + var_to_eval = simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) + value = eval( 'var_to_eval' + ''.join(variable.split(" ")[1: ])).astype(float) else: value = simulation.adaptative_calculate_variable(variable, period = period) weight_variable = simulation.weight_variable_by_entity[target_entity] - if len(self.entities) == 2 and simulation.tax_benefit_system.variables[variable.split("_number")[0]].entity.key != self.target_entity: + if len(self.entities) == 2 and simulation.tax_benefit_system.variables[variable.split(" ")[0]].entity.key != self.target_entity: value_df = pd.DataFrame(value) id_variable = self.parameters["id_variable_link"] value_df[id_variable] = simulation.adaptative_calculate_variable(id_variable, period = period) @@ -306,7 +306,7 @@ def _update_margins(self): ('initial', initial_weight), ] - variable_instance = simulation.tax_benefit_system.get_variable(variable.split("_number")[0]) + variable_instance = simulation.tax_benefit_system.get_variable(variable.split(" ")[0]) assert variable_instance is not None if variable_instance.value_type in [bool, Enum]: margin_items.append(('category', value)) From c6fff04942494635bfc7359057ab536a87a1a175 Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 4 Dec 2024 16:41:59 +0100 Subject: [PATCH 05/13] Lint --- openfisca_survey_manager/calibration.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/openfisca_survey_manager/calibration.py b/openfisca_survey_manager/calibration.py index aca75fb4..c01e92e7 100644 --- a/openfisca_survey_manager/calibration.py +++ b/openfisca_survey_manager/calibration.py @@ -132,11 +132,9 @@ def _build_calmar_data(self) -> dict: period = self.period for variable in self.margins_by_variable: assert variable in self.simulation.tax_benefit_system.variables or variable.split(" ")[0] in self.simulation.tax_benefit_system.variables + value = self.simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) if len(variable.split(" ")) > 1: - var_to_eval = simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) - value = eval('var_to_eval' + ''.join(variable.split(" ")[1: ])).astype(float) - else: - value = self.simulation.adaptative_calculate_variable(variable, period = period) + value = eval('value' + ''.join(variable.split(" ")[1:])).astype(float) data[self.simulation.tax_benefit_system.variables[variable].entity.key][variable] = value if len(self.entities) == 2: @@ -280,11 +278,9 @@ def _update_margins(self): filter_by = self.filter_by initial_weight = self.initial_weight + value = simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) if len(variable.split(" ")) > 1: - var_to_eval = simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) - value = eval( 'var_to_eval' + ''.join(variable.split(" ")[1: ])).astype(float) - else: - value = simulation.adaptative_calculate_variable(variable, period = period) + value = eval('value' + ''.join(variable.split(" ")[1:])).astype(float) weight_variable = simulation.weight_variable_by_entity[target_entity] if len(self.entities) == 2 and simulation.tax_benefit_system.variables[variable.split(" ")[0]].entity.key != self.target_entity: From 3686d5c6e64088dd7c5d299043a8dd149d478051 Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 4 Dec 2024 16:42:54 +0100 Subject: [PATCH 06/13] Adapt test --- openfisca_survey_manager/tests/test_calmar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfisca_survey_manager/tests/test_calmar.py b/openfisca_survey_manager/tests/test_calmar.py index 92774fa7..63c6002b 100644 --- a/openfisca_survey_manager/tests/test_calmar.py +++ b/openfisca_survey_manager/tests/test_calmar.py @@ -107,7 +107,7 @@ def create_margins(entities = 1): 2: 50, }, 'Z': 140.0, - 'Z_number': 80, + 'Z > 0': 80, } if entities == 2: margins_by_variable['C'] = 85 From 14fae5f406437fd06a06567bcb24696b15246eec Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Thu, 5 Dec 2024 08:47:56 +0100 Subject: [PATCH 07/13] Adapt CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af71cbec..76d8bb7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### 3.0.2 [#324](https://github.com/openfisca/openfisca-survey-manager/pull/324) * New feature - - Introduce the possibility to use calmar on variables with a suffix "_number", with target the weighted sum of the number of positive value of the variable. Only the variable without "_number" should be in the tax benefit system. + - Introduce the possibility to use calmar on variables changed with expressions starting with a space, with a target associated, for instance 'wage > 0' to have the number of positive wage in population. ### 3.0.1 [#322](https://github.com/openfisca/openfisca-survey-manager/pull/322) From 2d893395ad39fccf5e3caa73d3f2855242df635d Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Thu, 5 Dec 2024 14:16:00 +0100 Subject: [PATCH 08/13] Allow for several variables in expression --- openfisca_survey_manager/calibration.py | 36 ++++++++++++++++--------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/openfisca_survey_manager/calibration.py b/openfisca_survey_manager/calibration.py index c01e92e7..6aa0c4bc 100644 --- a/openfisca_survey_manager/calibration.py +++ b/openfisca_survey_manager/calibration.py @@ -3,6 +3,7 @@ import numpy from numpy import logical_not import pandas as pd +import re from openfisca_core.model_api import Enum from openfisca_survey_manager.calmar import calmar @@ -52,8 +53,11 @@ def __init__(self, simulation, target_margins, period, target_entity_count = Non variable_instance_by_variable_name = simulation.tax_benefit_system.variables entities = set( variable_instance_by_variable_name[variable].entity.key - for variable in margin_variables if not len(variable.split(" ")) > 1 + for var in margin_variables for variable in re.findall('[A-Za-z_]+', var) ) + for var in margin_variables : + assert len(set([variable_instance_by_variable_name[variable].entity.key + for variable in re.findall('[A-Za-z_]+', var)])) == 1, "An expression use variables that are not based on the same entity" if entity is not None: entities.add(entity) self.entities = list(entities) @@ -131,11 +135,13 @@ def _build_calmar_data(self) -> dict: data[self.target_entity][self._initial_weight_name] = self.initial_weight * self.filter_by period = self.period for variable in self.margins_by_variable: - assert variable in self.simulation.tax_benefit_system.variables or variable.split(" ")[0] in self.simulation.tax_benefit_system.variables - value = self.simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) - if len(variable.split(" ")) > 1: - value = eval('value' + ''.join(variable.split(" ")[1:])).astype(float) - data[self.simulation.tax_benefit_system.variables[variable].entity.key][variable] = value + list_var = re.findall('[A-Za-z_]+', variable) + assert all([var in self.simulation.tax_benefit_system.variables for var in list_var]) + dic_eval = {} + for var in list_var: + dic_eval[var] = self.simulation.adaptative_calculate_variable(var, period = period) + value = eval(variable, {}, dic_eval) + data[self.simulation.tax_benefit_system.variables[list_var[0]].entity.key][variable] = value if len(self.entities) == 2: for entity in self.entities: @@ -212,8 +218,9 @@ def set_target_margin(self, variable, target): """ simulation = self.simulation period = self.period - assert variable in simulation.tax_benefit_system.variables or variable.split(" ")[0] in simulation.tax_benefit_system.variables - variable_instance = simulation.tax_benefit_system.variables[variable.split(" ")[0]] + list_var = re.findall('[A-Za-z_]+', variable) + assert all([var in simulation.tax_benefit_system.variables for var in list_var]) + variable_instance = simulation.tax_benefit_system.variables[list_var[0]] filter_by = self.filter_by target_by_category = None @@ -278,12 +285,15 @@ def _update_margins(self): filter_by = self.filter_by initial_weight = self.initial_weight - value = simulation.adaptative_calculate_variable(variable.split(" ")[0], period = period) - if len(variable.split(" ")) > 1: - value = eval('value' + ''.join(variable.split(" ")[1:])).astype(float) + list_var = re.findall('[A-Za-z_]+', variable) + dic_eval = {} + for var in list_var: + dic_eval[var] = simulation.adaptative_calculate_variable(var, period = period) + value = eval(variable, {}, dic_eval) + weight_variable = simulation.weight_variable_by_entity[target_entity] - if len(self.entities) == 2 and simulation.tax_benefit_system.variables[variable.split(" ")[0]].entity.key != self.target_entity: + if len(self.entities) == 2 and simulation.tax_benefit_system.variables[list_var[0]].entity.key != self.target_entity: value_df = pd.DataFrame(value) id_variable = self.parameters["id_variable_link"] value_df[id_variable] = simulation.adaptative_calculate_variable(id_variable, period = period) @@ -302,7 +312,7 @@ def _update_margins(self): ('initial', initial_weight), ] - variable_instance = simulation.tax_benefit_system.get_variable(variable.split(" ")[0]) + variable_instance = simulation.tax_benefit_system.get_variable(list_var[0]) assert variable_instance is not None if variable_instance.value_type in [bool, Enum]: margin_items.append(('category', value)) From 5752cafdcdf79efcb332123bdc8f5bee7715e41c Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Thu, 5 Dec 2024 14:17:32 +0100 Subject: [PATCH 09/13] Test several variables --- openfisca_survey_manager/tests/test_calmar.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openfisca_survey_manager/tests/test_calmar.py b/openfisca_survey_manager/tests/test_calmar.py index 63c6002b..b6b168eb 100644 --- a/openfisca_survey_manager/tests/test_calmar.py +++ b/openfisca_survey_manager/tests/test_calmar.py @@ -108,6 +108,7 @@ def create_margins(entities = 1): }, 'Z': 140.0, 'Z > 0': 80, + '(Z > 0) * (X > 0)': 80 } if entities == 2: margins_by_variable['C'] = 85 From ccc5c4a905cb157893eccedc0084a65c2e74e8a8 Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Thu, 5 Dec 2024 14:30:12 +0100 Subject: [PATCH 10/13] Lint --- openfisca_survey_manager/calibration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfisca_survey_manager/calibration.py b/openfisca_survey_manager/calibration.py index 6aa0c4bc..99ab8413 100644 --- a/openfisca_survey_manager/calibration.py +++ b/openfisca_survey_manager/calibration.py @@ -55,7 +55,7 @@ def __init__(self, simulation, target_margins, period, target_entity_count = Non variable_instance_by_variable_name[variable].entity.key for var in margin_variables for variable in re.findall('[A-Za-z_]+', var) ) - for var in margin_variables : + for var in margin_variables: assert len(set([variable_instance_by_variable_name[variable].entity.key for variable in re.findall('[A-Za-z_]+', var)])) == 1, "An expression use variables that are not based on the same entity" if entity is not None: From 70b6d36db099a70ccffc8607c7ffd8bff1bc062a Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Tue, 10 Dec 2024 15:16:42 +0100 Subject: [PATCH 11/13] Avoid problems in case of reforms --- openfisca_survey_manager/calibration.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openfisca_survey_manager/calibration.py b/openfisca_survey_manager/calibration.py index 99ab8413..ceb0def4 100644 --- a/openfisca_survey_manager/calibration.py +++ b/openfisca_survey_manager/calibration.py @@ -257,8 +257,6 @@ def set_calibrated_weights(self): weight_variable = simulation.tax_benefit_system.variables[weight_name] if weight_name == self.weight_name: weight_variable.unit = "base_weight" # The weight variable is flagged as the one that have changed - if weight_variable.formulas: - weight_variable.formulas = [] # The weight variable becomes an input variable after it changes with calibration # Delete other entites already computed weigths # to ensure that this weights a recomputed if they derive from # the calibrated weight variable From 686dd5523dc299e3ba8cae0bba889d2597257bdf Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 11 Dec 2024 14:31:49 +0100 Subject: [PATCH 12/13] Allow weight update in reforms --- openfisca_survey_manager/calibration.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfisca_survey_manager/calibration.py b/openfisca_survey_manager/calibration.py index ceb0def4..f8978990 100644 --- a/openfisca_survey_manager/calibration.py +++ b/openfisca_survey_manager/calibration.py @@ -104,6 +104,8 @@ def __init__(self, simulation, target_margins, period, target_entity_count = Non self.filter_by = numpy.array(1.0) assert weight_name is not None, "A calibration needs a weight variable name to act on" + weight_variable = simulation.tax_benefit_system.variables[weight_name] + weight_variable.unit = "" self._initial_weight_name = weight_name + "_ini" self.initial_weight = initial_weight = simulation.calculate(weight_name, period = period) From f86251f969ac49ac0d87f974ce59fa3935c3aacd Mon Sep 17 00:00:00 2001 From: Duchesne Sylvain Date: Wed, 11 Dec 2024 15:16:31 +0100 Subject: [PATCH 13/13] Avoid multiple frame.insert warning --- openfisca_survey_manager/calmar.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openfisca_survey_manager/calmar.py b/openfisca_survey_manager/calmar.py index 3c4d664f..98408bff 100644 --- a/openfisca_survey_manager/calmar.py +++ b/openfisca_survey_manager/calmar.py @@ -253,9 +253,10 @@ def F_prime(x): if isinstance(val, dict): dummies_dict = build_dummies_dict(data[entity][var]) k, pop = 0, 0 + list_col_to_add = [data[entity]] for cat, nb in val.items(): cat_varname = var + '_' + str(cat) - data[entity][cat_varname] = dummies_dict[cat] + list_col_to_add.append(pd.Series(dummies_dict[cat], name = cat_varname)) margins_new[cat_varname] = nb if var not in margins_new_dict: margins_new_dict[var] = {} @@ -263,6 +264,7 @@ def F_prime(x): pop += nb k += 1 nj += 1 + data[entity] = pd.concat(list_col_to_add, axis = 1) # Check total popualtion population = (entity == target_entity) * total_population + (entity != target_entity) * total_population_smaller_entity if pop != population: