# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
# ---

from pulp import *
problem = LpProblem("Marketing Spend", LpMaximize)

# Setup Sets
markets = ["Facebook", "Instagram", "Twitter"]
saturation_level = [1, 2]
buckets = [1, 2]

# Setup Data
clicks_per_dollar = {("Facebook", 1):0.10, ("Facebook", 2):0.20, \
                         ("Instagram", 1):0.12, ("Instagram", 2):0.18, \
                         ("Twitter", 1):0.11, ("Twitter", 2):0.19}
conversion_rate = {("Facebook", 1):0.10, ("Facebook", 2):0.02, \
                   ("Instagram", 1):0.14, ("Instagram", 2):0.05, \
                   ("Twitter", 1):0.12, ("Twitter", 2):0.05 }
cost_breakpoint = {"Facebook":1000, \
                   "Instagram":1500, \
                   "Twitter":900 }
saturation_point = {"Facebook":100, \
                    "Instagram":50, \
                    "Twitter":50}
total_budget = 3000
big_m = 1000000

# +
# Setup Decision Variables
spend = LpVariable.dicts("spend", \
                         [(m,b) for m in markets for b in buckets], \
                         lowBound=0, upBound=None, cat='Continous')

clicks = LpVariable.dicts("clicks", \
                          [(m,s) for m in markets for s in saturation_level], \
                          lowBound = 0, upBound=None, cat='Continuous')
is_saturated = LpVariable.dicts("is_saturated", markets, lowBound=0, upBound=None, cat='Continous')
use_bucket_2 = LpVariable.dicts("use_bucket_2", markets, 0, 1, LpInteger)
# -

# Set objective to maximize Customer Acquisition
problem += lpSum([clicks[m,s] * conversion_rate[m,s] \
                    for m in markets \
                    for s in saturation_level])


# Create constraint for total budget
problem += lpSum([spend[(m,b)] for m in markets for b in buckets]) <= total_budget, "Budget Constraint"

# If Bucket 1 is filled, can use Bucket 2
for m in markets:
    problem += spend[(m,1)] >= cost_breakpoint[m] * use_bucket_2[m], f"Bucket1Filled_{m}"

# Bucket 2 can be used if use_bucket_2 turned on
for m in markets:
    problem += spend[(m,2)] <= big_m * use_bucket_2[m], f"Bucket2Available_{m}"

# Impressions for Market material balance
for m in markets:
    problem += lpSum([clicks[m,s] for s in saturation_level]) == lpSum([spend[m,b]*clicks_per_dollar[m,b] for b in buckets]), f"ImpressionBalance:{m}"

# Impressions for Saturation Level 1 cannot exceed Saturation Point
for m in markets:
    problem += clicks[(m,1)] <= saturation_point[m], f"SaturationLevel:{m}"

problem.solve()

# +
# Check the status
status = LpStatus[problem.status]
print("Status:", LpStatus[problem.status])

# It is best practice to always check the status of the solve before using the
# values of the decision variables
if status == "Optimal":
    for v in problem.variables():
        print(v.name, "=", v.varValue)
    print("Total Conversions = ", value(problem.objective))
# -

# See where we expect the conversions to come from
for m in markets:
    estimated_conversions = sum([clicks[m,s].varValue * conversion_rate[m,s] for s in saturation_level])
    print(f"Conversions for {m}: {estimated_conversions:n}")



StarcoderdataJupyterScriptsDedupFiltered