From db746bfbd1f6059df50ae8946a0bd96ba7f8b7d6 Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 16:54:04 +0000 Subject: [PATCH 01/11] fix: apply the cap after normalising the distribution --- app/grants/clr.py | 57 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index a1ec5ae4a59..5bb8c452a8c 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -200,7 +200,7 @@ def get_totals_by_pair(contrib_dict): return pair_totals -def calculate_clr(curr_agg, trust_dict, pair_totals, v_threshold, total_pot, match_cap_per_grant): +def calculate_clr(curr_agg, trust_dict, pair_totals, v_threshold, total_pot): ''' calculates the clr amount at the given threshold and total pot args: @@ -245,17 +245,13 @@ def calculate_clr(curr_agg, trust_dict, pair_totals, v_threshold, total_pot, mat if type(tot) == complex: tot = float(tot.real) - # ensure CLR match for a grant in CLR round does not exceed 2.5 of the total pot - if total_pot != match_cap_per_grant and tot > match_cap_per_grant: - tot = match_cap_per_grant - bigtot += tot totals[proj] = {'number_contributions': _num, 'contribution_amount': _sum, 'clr_amount': tot} return bigtot, totals -def calculate_clr_for_prediction(bigtot, totals, curr_agg, trust_dict, v_threshold, total_pot, grant_id, amount): +def calculate_clr_for_prediction(bigtot, totals, curr_agg, trust_dict, v_threshold, total_pot, grant_id, amount, match_cap_per_grant): ''' clubbed function that runs all calculation functions and returns the result for a single grant_id @@ -322,7 +318,7 @@ def calculate_clr_for_prediction(bigtot, totals, curr_agg, trust_dict, v_thresho totals[grant_id] = {'number_contributions': _num, 'contribution_amount': _sum, 'clr_amount': tot} # normalise the result - grants_clr = normalise(bigtot + tot, totals, total_pot) + grants_clr = normalise(bigtot + tot, totals, total_pot, match_cap_per_grant) # find grant we added the contribution to and get the new clr amount grant_clr = grants_clr.get(grant_id) @@ -339,7 +335,7 @@ def calculate_clr_for_prediction(bigtot, totals, curr_agg, trust_dict, v_thresho return (grants_clr, 0.0, 0, 0.0) -def normalise(bigtot, totals, total_pot): +def normalise(bigtot, totals, total_pot, match_cap_per_grant): ''' given the total amount distributed (bigtot) and the total_pot size normalise the distribution args: @@ -363,6 +359,43 @@ def normalise(bigtot, totals, total_pot): for key, t in totals.items(): t['clr_amount'] = t['clr_amount'] * (1 + percentage_increase) + totals = apply_cap(totals, match_cap_per_grant) + + return totals + + +def apply_cap(totals, match_cap_per_grant): + # work out how much of the pool is remaining after capping each grant + remainder = 0 + uncapped = 0 + + # cap each of the clr_amounts + for key, t in totals.items(): + if t['clr_amount'] >= match_cap_per_grant: + remainder += t['clr_amount'] - match_cap_per_grant + t['clr_amount'] = match_cap_per_grant + else: + uncapped += t['clr_amount'] + + if remainder > 0 and uncapped > 0: + # div so we can spread the remainder proportionally + per_remainder = remainder / uncapped + + # reset remainder to check if any grants enter the cap region after spreading the remainder + remainder = 0 + + # spread the remainder + for key, t in totals.items(): + if t['clr_amount'] < match_cap_per_grant: + t['clr_amount'] += per_remainder * t['clr_amount'] + # check if the cap is hit after spreading the remainder + if t['clr_amount'] >= match_cap_per_grant: + remainder += t['clr_amount'] - match_cap_per_grant + + # apply the cap again (recursively) + if remainder > 0: + apply_cap(totals, match_cap_per_grant) + return totals @@ -404,11 +437,13 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn pair_totals = get_totals_by_pair(curr_agg) grant_clr_percentage_cap = clr_round.grant_clr_percentage_cap if clr_round.grant_clr_percentage_cap else 100 + bigtot, totals = calculate_clr(curr_agg, trust_dict, pair_totals, v_threshold, total_pot) + + # $ value of the percentage cap match_cap_per_grant = total_pot * (float(grant_clr_percentage_cap) / 100) - bigtot, totals = calculate_clr(curr_agg, trust_dict, pair_totals, v_threshold, total_pot, match_cap_per_grant) # normalise against a deepcopy of the totals to avoid mutations - curr_grants_clr = normalise(bigtot, copy.deepcopy(totals), total_pot) + curr_grants_clr = normalise(bigtot, copy.deepcopy(totals), total_pot, match_cap_per_grant) # for slim calc - only update the current distribution and skip calculating predictions if what == 'slim': @@ -474,7 +509,7 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn else: # calculate clr with additional donation amount grants_clr, predicted_clr, _, _ = calculate_clr_for_prediction( - bigtot, totals, curr_agg, trust_dict, v_threshold, total_pot, grant.id, amount + bigtot, totals, curr_agg, trust_dict, v_threshold, total_pot, grant.id, amount, match_cap_per_grant ) # record each point of the prediction From 16f36d6885b545d433da8c767bd98e9036f72eaa Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 17:05:35 +0000 Subject: [PATCH 02/11] fix: adds flag to estimate_clr so that we can skip saving the results --- app/grants/management/commands/estimate_clr.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/grants/management/commands/estimate_clr.py b/app/grants/management/commands/estimate_clr.py index 26857a9871d..c37b11ff5b3 100644 --- a/app/grants/management/commands/estimate_clr.py +++ b/app/grants/management/commands/estimate_clr.py @@ -38,6 +38,7 @@ def add_arguments(self, parser): parser.add_argument('what', type=str, default="full") parser.add_argument('sync', type=str, default="false") parser.add_argument('--use-sql', type=bool, default=False) + parser.add_argument('--skip-save', type=bool, default=False) # slim = just run 0 contribution match upcate calcs # full, run [0, 1, 10, 100, calcs across all grants] @@ -48,6 +49,7 @@ def handle(self, *args, **options): what = options['what'] sync = options['sync'] use_sql = options['use_sql'] + skip_save = options['skip_save'] print (network, clr_pk, what, sync, use_sql) if clr_pk and clr_pk.isdigit(): @@ -60,7 +62,7 @@ def handle(self, *args, **options): if sync == 'true': # run it sync -> useful for payout / debugging predict_clr( - save_to_db=True, + save_to_db=True if not skip_save else False, from_date=timezone.now(), clr_round=clr_round, network=network, @@ -70,7 +72,7 @@ def handle(self, *args, **options): else: # runs it as celery task. process_predict_clr( - save_to_db=True, + save_to_db=True if not skip_save else False, from_date=timezone.now(), clr_round=clr_round, network=network, From 8a28af27797513a3fd94bf79805e2a49791668a8 Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 17:31:50 +0000 Subject: [PATCH 03/11] fix: expose id and title to make it easier to compare results --- app/grants/clr.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/grants/clr.py b/app/grants/clr.py index 5bb8c452a8c..6b11be84854 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -529,6 +529,8 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn else: clr_prediction_curve = [[0.0, 0.0, 0.0] for x in range(0, 6)] + print(grant.id) + print(grant.title) print(clr_prediction_curve) clr_round.record_clr_prediction_curve(grant, clr_prediction_curve) From 0440c278111b3781641ae319bed7b6d9ec17b58c Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 17:36:38 +0000 Subject: [PATCH 04/11] fix: apply Adityas comments --- app/grants/clr.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index 6b11be84854..7e38946efbc 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -366,18 +366,23 @@ def normalise(bigtot, totals, total_pot, match_cap_per_grant): def apply_cap(totals, match_cap_per_grant): # work out how much of the pool is remaining after capping each grant - remainder = 0 - uncapped = 0 + remainder = 0 # amount left to be redistributed after cap + uncapped = 0 # total amount matched for grants which haven't capped # cap each of the clr_amounts for key, t in totals.items(): if t['clr_amount'] >= match_cap_per_grant: + # grant has exceeded the cap + # - so cap the clr_amount + # - add the extra funds to remainder remainder += t['clr_amount'] - match_cap_per_grant t['clr_amount'] = match_cap_per_grant else: uncapped += t['clr_amount'] + # check that we have both capped and uncapped grants if remainder > 0 and uncapped > 0: + # div so we can spread the remainder proportionally per_remainder = remainder / uncapped From 8f2cccb08d677b6fd60b37724869dfda439a769c Mon Sep 17 00:00:00 2001 From: Aditya Anand M C Date: Tue, 7 Dec 2021 22:59:30 +0530 Subject: [PATCH 05/11] add logging --- app/grants/clr.py | 4 +++- app/grants/management/commands/estimate_clr.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index 7e38946efbc..a62aa29c887 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -372,16 +372,18 @@ def apply_cap(totals, match_cap_per_grant): # cap each of the clr_amounts for key, t in totals.items(): if t['clr_amount'] >= match_cap_per_grant: - # grant has exceeded the cap + # grant has exceeed the cap # - so cap the clr_amount # - add the extra funds to remainder remainder += t['clr_amount'] - match_cap_per_grant t['clr_amount'] = match_cap_per_grant else: + # grant has not exceed cap so add amount to uncapped uncapped += t['clr_amount'] # check that we have both capped and uncapped grants if remainder > 0 and uncapped > 0: + # there are grants which have capped and not capped # div so we can spread the remainder proportionally per_remainder = remainder / uncapped diff --git a/app/grants/management/commands/estimate_clr.py b/app/grants/management/commands/estimate_clr.py index c37b11ff5b3..3108fa064ee 100644 --- a/app/grants/management/commands/estimate_clr.py +++ b/app/grants/management/commands/estimate_clr.py @@ -61,7 +61,7 @@ def handle(self, *args, **options): for clr_round in active_clr_rounds: if sync == 'true': # run it sync -> useful for payout / debugging - predict_clr( + clr = predict_clr( save_to_db=True if not skip_save else False, from_date=timezone.now(), clr_round=clr_round, @@ -69,6 +69,10 @@ def handle(self, *args, **options): what=what, use_sql=use_sql, ) + + if skip_save: + # print output while running in sync and no save to DB + print(clr) else: # runs it as celery task. process_predict_clr( From 1ded414d873a99a2f3108f2ac7f3105bda2220d8 Mon Sep 17 00:00:00 2001 From: Aditya Anand M C Date: Tue, 7 Dec 2021 23:04:58 +0530 Subject: [PATCH 06/11] add more logs --- app/grants/clr.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/grants/clr.py b/app/grants/clr.py index a62aa29c887..1a7f1dd527d 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -375,8 +375,15 @@ def apply_cap(totals, match_cap_per_grant): # grant has exceeed the cap # - so cap the clr_amount # - add the extra funds to remainder + print("=======") + print(f"{t['id']} has exceeded cap cause amount {t['clr_amount']}") + remainder += t['clr_amount'] - match_cap_per_grant t['clr_amount'] = match_cap_per_grant + + print(f"remainer: {remainder}") + print("=======") + else: # grant has not exceed cap so add amount to uncapped uncapped += t['clr_amount'] @@ -397,7 +404,10 @@ def apply_cap(totals, match_cap_per_grant): t['clr_amount'] += per_remainder * t['clr_amount'] # check if the cap is hit after spreading the remainder if t['clr_amount'] >= match_cap_per_grant: + print("***********") + print(f"uncapped grant {t['id']} has exceeded cap cause amount {t['clr_amount']}") remainder += t['clr_amount'] - match_cap_per_grant + print("***********") # apply the cap again (recursively) if remainder > 0: From 85067febed9cfca1b189a3a389f388b3516f1bf4 Mon Sep 17 00:00:00 2001 From: Aditya Anand M C Date: Tue, 7 Dec 2021 23:49:18 +0530 Subject: [PATCH 07/11] add logging --- app/grants/clr.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index 1a7f1dd527d..1cd077457b1 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -381,7 +381,7 @@ def apply_cap(totals, match_cap_per_grant): remainder += t['clr_amount'] - match_cap_per_grant t['clr_amount'] = match_cap_per_grant - print(f"remainer: {remainder}") + print(f"remainder: {remainder}") print("=======") else: @@ -550,12 +550,12 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn print(grant.title) print(clr_prediction_curve) - clr_round.record_clr_prediction_curve(grant, clr_prediction_curve) + # clr_round.record_clr_prediction_curve(grant, clr_prediction_curve) - if from_date > (clr_calc_start_time - timezone.timedelta(hours=1)): - grant.save() + # if from_date > (clr_calc_start_time - timezone.timedelta(hours=1)): + # grant.save() - debug_output.append({'grant': grant.id, "clr_prediction_curve": (potential_donations, potential_clr), "grants_clr": grants_clr}) + debug_output.append({'grant': grant.id, "title": grant.title, "clr_prediction_curve": (potential_donations, potential_clr), "grants_clr": grants_clr}) print(f"\nTotal execution time: {(timezone.now() - clr_calc_start_time)}\n") From c7c02ff7bc13d54441b91d2fda11caa4131488a0 Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 18:33:50 +0000 Subject: [PATCH 08/11] fix: adds id to totals --- app/grants/clr.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index 1cd077457b1..26f3b1a0bc9 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -246,7 +246,7 @@ def calculate_clr(curr_agg, trust_dict, pair_totals, v_threshold, total_pot): tot = float(tot.real) bigtot += tot - totals[proj] = {'number_contributions': _num, 'contribution_amount': _sum, 'clr_amount': tot} + totals[proj] = {'id': proj, 'number_contributions': _num, 'contribution_amount': _sum, 'clr_amount': tot} return bigtot, totals @@ -315,7 +315,7 @@ def calculate_clr_for_prediction(bigtot, totals, curr_agg, trust_dict, v_thresho if type(tot) == complex: tot = float(tot.real) - totals[grant_id] = {'number_contributions': _num, 'contribution_amount': _sum, 'clr_amount': tot} + totals[grant_id] = {'id': grant_id, 'number_contributions': _num, 'contribution_amount': _sum, 'clr_amount': tot} # normalise the result grants_clr = normalise(bigtot + tot, totals, total_pot, match_cap_per_grant) @@ -533,29 +533,29 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn potential_clr.append(predicted_clr) # save the result of the prediction - if save_to_db: - clr_prediction_curve = list(zip(potential_donations, potential_clr)) - base = clr_prediction_curve[0][1] - grant.last_clr_calc_date = timezone.now() - grant.next_clr_calc_date = timezone.now() + timezone.timedelta(minutes=60) - - # check that we have enough data to set the curve - can_estimate = True if base or clr_prediction_curve[1][1] or clr_prediction_curve[2][1] or clr_prediction_curve[3][1] else False - if can_estimate: - clr_prediction_curve = [[ele[0], ele[1], ele[1] - base if ele[1] != 0 else 0.0] for ele in clr_prediction_curve ] - else: - clr_prediction_curve = [[0.0, 0.0, 0.0] for x in range(0, 6)] - - print(grant.id) - print(grant.title) - print(clr_prediction_curve) + # if save_to_db: + clr_prediction_curve = list(zip(potential_donations, potential_clr)) + base = clr_prediction_curve[0][1] + grant.last_clr_calc_date = timezone.now() + grant.next_clr_calc_date = timezone.now() + timezone.timedelta(minutes=60) + + # check that we have enough data to set the curve + can_estimate = True if base or clr_prediction_curve[1][1] or clr_prediction_curve[2][1] or clr_prediction_curve[3][1] else False + if can_estimate: + clr_prediction_curve = [[ele[0], ele[1], ele[1] - base if ele[1] != 0 else 0.0] for ele in clr_prediction_curve ] + else: + clr_prediction_curve = [[0.0, 0.0, 0.0] for x in range(0, 6)] + + print(grant.id) + print(grant.title) + print(clr_prediction_curve) # clr_round.record_clr_prediction_curve(grant, clr_prediction_curve) # if from_date > (clr_calc_start_time - timezone.timedelta(hours=1)): # grant.save() - debug_output.append({'grant': grant.id, "title": grant.title, "clr_prediction_curve": (potential_donations, potential_clr), "grants_clr": grants_clr}) + debug_output.append({'grant': grant.id, "title": grant.title, "clr_prediction_curve": clr_prediction_curve, "grants_clr": grants_clr}) print(f"\nTotal execution time: {(timezone.now() - clr_calc_start_time)}\n") From 981b30c1a53eaa013965b1f50355820a3958059b Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 20:02:23 +0000 Subject: [PATCH 09/11] fix: clean up logs --- app/grants/clr.py | 47 +++++++------------ .../management/commands/estimate_clr.py | 6 +-- 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index 26f3b1a0bc9..3703876e884 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -372,18 +372,12 @@ def apply_cap(totals, match_cap_per_grant): # cap each of the clr_amounts for key, t in totals.items(): if t['clr_amount'] >= match_cap_per_grant: - # grant has exceeed the cap + # grant has exceeded the cap # - so cap the clr_amount # - add the extra funds to remainder - print("=======") - print(f"{t['id']} has exceeded cap cause amount {t['clr_amount']}") - remainder += t['clr_amount'] - match_cap_per_grant t['clr_amount'] = match_cap_per_grant - print(f"remainder: {remainder}") - print("=======") - else: # grant has not exceed cap so add amount to uncapped uncapped += t['clr_amount'] @@ -404,10 +398,7 @@ def apply_cap(totals, match_cap_per_grant): t['clr_amount'] += per_remainder * t['clr_amount'] # check if the cap is hit after spreading the remainder if t['clr_amount'] >= match_cap_per_grant: - print("***********") - print(f"uncapped grant {t['id']} has exceeded cap cause amount {t['clr_amount']}") remainder += t['clr_amount'] - match_cap_per_grant - print("***********") # apply the cap again (recursively) if remainder > 0: @@ -533,29 +524,27 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn potential_clr.append(predicted_clr) # save the result of the prediction - # if save_to_db: - clr_prediction_curve = list(zip(potential_donations, potential_clr)) - base = clr_prediction_curve[0][1] - grant.last_clr_calc_date = timezone.now() - grant.next_clr_calc_date = timezone.now() + timezone.timedelta(minutes=60) - - # check that we have enough data to set the curve - can_estimate = True if base or clr_prediction_curve[1][1] or clr_prediction_curve[2][1] or clr_prediction_curve[3][1] else False - if can_estimate: - clr_prediction_curve = [[ele[0], ele[1], ele[1] - base if ele[1] != 0 else 0.0] for ele in clr_prediction_curve ] - else: - clr_prediction_curve = [[0.0, 0.0, 0.0] for x in range(0, 6)] + if save_to_db: + clr_prediction_curve = list(zip(potential_donations, potential_clr)) + base = clr_prediction_curve[0][1] + grant.last_clr_calc_date = timezone.now() + grant.next_clr_calc_date = timezone.now() + timezone.timedelta(minutes=60) + + # check that we have enough data to set the curve + can_estimate = True if base or clr_prediction_curve[1][1] or clr_prediction_curve[2][1] or clr_prediction_curve[3][1] else False + if can_estimate: + clr_prediction_curve = [[ele[0], ele[1], ele[1] - base if ele[1] != 0 else 0.0] for ele in clr_prediction_curve ] + else: + clr_prediction_curve = [[0.0, 0.0, 0.0] for x in range(0, 6)] - print(grant.id) - print(grant.title) - print(clr_prediction_curve) + print(clr_prediction_curve) - # clr_round.record_clr_prediction_curve(grant, clr_prediction_curve) + clr_round.record_clr_prediction_curve(grant, clr_prediction_curve) - # if from_date > (clr_calc_start_time - timezone.timedelta(hours=1)): - # grant.save() + if from_date > (clr_calc_start_time - timezone.timedelta(hours=1)): + grant.save() - debug_output.append({'grant': grant.id, "title": grant.title, "clr_prediction_curve": clr_prediction_curve, "grants_clr": grants_clr}) + debug_output.append({'grant': grant.id, "title": grant.title, "clr_prediction_curve": (clr_prediction_curve, "grants_clr": grants_clr}) print(f"\nTotal execution time: {(timezone.now() - clr_calc_start_time)}\n") diff --git a/app/grants/management/commands/estimate_clr.py b/app/grants/management/commands/estimate_clr.py index 3108fa064ee..c37b11ff5b3 100644 --- a/app/grants/management/commands/estimate_clr.py +++ b/app/grants/management/commands/estimate_clr.py @@ -61,7 +61,7 @@ def handle(self, *args, **options): for clr_round in active_clr_rounds: if sync == 'true': # run it sync -> useful for payout / debugging - clr = predict_clr( + predict_clr( save_to_db=True if not skip_save else False, from_date=timezone.now(), clr_round=clr_round, @@ -69,10 +69,6 @@ def handle(self, *args, **options): what=what, use_sql=use_sql, ) - - if skip_save: - # print output while running in sync and no save to DB - print(clr) else: # runs it as celery task. process_predict_clr( From 589966f4625ba7302697dcb41fd0228f8f1375bb Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 20:09:56 +0000 Subject: [PATCH 10/11] fix: ensures we dont spread the remainder if we havent reached the saturation point --- app/grants/clr.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index 3703876e884..8668d568c59 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -347,8 +347,10 @@ def normalise(bigtot, totals, total_pot, match_cap_per_grant): [{'id': proj, 'number_contributions': _num, 'contribution_amount': _sum, 'clr_amount': tot}] ''' + # check if saturation is reached + is_saturated = bigtot >= total_pot # check for saturation and normalise if reached - if bigtot >= total_pot: + if is_saturated: # print(f'saturation reached. Total Pot: ${total_pot} | Total Allocated ${bigtot}. Normalizing') for key, t in totals.items(): t['clr_amount'] = ((t['clr_amount'] / bigtot) * total_pot) @@ -359,12 +361,13 @@ def normalise(bigtot, totals, total_pot, match_cap_per_grant): for key, t in totals.items(): t['clr_amount'] = t['clr_amount'] * (1 + percentage_increase) - totals = apply_cap(totals, match_cap_per_grant) + # apply the match cap post-normalisation + totals = apply_cap(totals, match_cap_per_grant, is_saturated) return totals -def apply_cap(totals, match_cap_per_grant): +def apply_cap(totals, match_cap_per_grant, should_spread): # work out how much of the pool is remaining after capping each grant remainder = 0 # amount left to be redistributed after cap uncapped = 0 # total amount matched for grants which haven't capped @@ -382,16 +385,12 @@ def apply_cap(totals, match_cap_per_grant): # grant has not exceed cap so add amount to uncapped uncapped += t['clr_amount'] - # check that we have both capped and uncapped grants - if remainder > 0 and uncapped > 0: - # there are grants which have capped and not capped - + # check that we have both capped and uncapped grants and that we should be spreading the remainder + if should_spread and remainder > 0 and uncapped > 0: # div so we can spread the remainder proportionally per_remainder = remainder / uncapped - # reset remainder to check if any grants enter the cap region after spreading the remainder remainder = 0 - # spread the remainder for key, t in totals.items(): if t['clr_amount'] < match_cap_per_grant: @@ -402,7 +401,7 @@ def apply_cap(totals, match_cap_per_grant): # apply the cap again (recursively) if remainder > 0: - apply_cap(totals, match_cap_per_grant) + apply_cap(totals, match_cap_per_grant, should_spread) return totals From cd35f874e62dfabf42978d09b010ca501ddbb0f8 Mon Sep 17 00:00:00 2001 From: Graham Dixon Date: Tue, 7 Dec 2021 20:12:11 +0000 Subject: [PATCH 11/11] fix: debug output --- app/grants/clr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/grants/clr.py b/app/grants/clr.py index 8668d568c59..a952e5e07e4 100644 --- a/app/grants/clr.py +++ b/app/grants/clr.py @@ -543,7 +543,7 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn if from_date > (clr_calc_start_time - timezone.timedelta(hours=1)): grant.save() - debug_output.append({'grant': grant.id, "title": grant.title, "clr_prediction_curve": (clr_prediction_curve, "grants_clr": grants_clr}) + debug_output.append({'grant': grant.id, "title": grant.title, "clr_prediction_curve": (potential_donations, potential_clr), "grants_clr": grants_clr}) print(f"\nTotal execution time: {(timezone.now() - clr_calc_start_time)}\n")