"""
## GAMSSOURCE: https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_partssupply.html
## LICENSETYPE: Demo
## MODELTYPE: NLP
## KEYWORDS: nonlinear programming, contract theory, principal-agent problem, adverse selection, parts supply problem
Parts Supply Problem (PARTSSUPPLY)
This model is based on the ps2_f_s.358 .. ps10_s_mn.396 models by
Hideo Hashimoto, Kojun Hamada, and Nobuhiro Hosoe.
Using the following options, these models can be run:
ps2_f : default
ps2_f_eff : --nsupplier=1
ps2_f_inf : --nsupplier=1 --alttheta=1
ps2_f_s : --useic=1
ps2_s : --useic=1
ps3_f : --nsupplier=3
ps3_s : --nsupplier=3 --uselicd=1
ps3_s_gic : --nsupplier=3 --useic=1
ps3_s_mn 1st solve: --nsupplier=3 --uselicd=1
2nd solve: --nsupplier=3 --uselicd=1 --altpi=1
3rd solve: --nsupplier=3 --uselicd=1 --alttheta=1
ps3_s_scp 1st solve: --nsupplier=3 --alttheta=2 --modweight=1 --useic=1
2nd solve: --nsupplier=3 --alttheta=2 --modweight=1 --uselicd=1
--uselicu=1
ps5_s_mn : --nsupplier=5 --uselicd=1 --nsamples=1000
ps10_s : --nsupplier=10 --uselicd=1
ps10_s_mn : --nsupplier=10 --uselicd=1 --nsamples=1000
Alternatively, the corresponding original model files can be found in
the GAMS model library.
"""
from __future__ import annotations
import os
import gamspy.math as gams_math
from gamspy import (
Alias,
Card,
Container,
Equation,
Model,
Ord,
Parameter,
Problem,
Sense,
Set,
Sum,
Variable,
)
def main():
cont = Container(
system_directory=os.getenv("SYSTEM_DIRECTORY", None),
)
# Set
i = Set(cont, name="i", records=["1", "2"], description="type of supplier")
t = Set(cont, name="t", records=["1"], description="Monte-Carlo draws")
j = Alias(cont, name="j", alias_with=i)
# Parameter
theta = Parameter(
cont,
name="theta",
domain=i,
records=[[1, 0.2], [2, 0.3]],
description="efficiency",
)
pt = Parameter(
cont, name="pt", domain=[i, t], description="probability of type"
)
p = Parameter(
cont,
name="p",
domain=i,
records=[[1, 0.2], [2, 0.8]],
description="probability of type for currently evaluated scenario",
)
icweight = Parameter(
cont, name="icweight", domain=i, description="weight in ic constraints"
)
ru = Parameter(
cont, name="ru", records=0, description="reservation utility"
)
pt[i, t] = gams_math.uniform(0, 1)
pt[i, t] = pt[i, t] / Sum(j, pt[j, t])
pt[i, t] = p[i]
# Variable
x = Variable(
cont, name="x", domain=i, type="Positive", description="quality"
)
b = Variable(
cont,
name="b",
domain=i,
type="Positive",
description="maker's revenue",
)
w = Variable(
cont, name="w", domain=i, type="Positive", description="price"
)
# Equation
rev = Equation(
cont, name="rev", domain=i, description="maker's revenue function"
)
pc = Equation(
cont, name="pc", domain=i, description="participation constraint"
)
ic = Equation(
cont,
name="ic",
domain=[i, j],
description="incentive compatibility constraint",
)
licd = Equation(
cont,
name="licd",
domain=i,
description="incentive compatibility constraint",
)
licu = Equation(
cont,
name="licu",
domain=i,
description="incentive compatibility constraint",
)
mn = Equation(
cont, name="mn", domain=i, description="monotonicity constraint"
)
# maker's utility function
obj = Sum(i, p[i] * (b[i] - w[i]))
rev[i] = b[i] == gams_math.sqrt(x[i])
pc[i] = w[i] - theta[i] * x[i] >= ru
ic[i, j] = w[i] - icweight[i] * x[i] >= w[j] - icweight[i] * x[j]
licd[i].where[Ord(i) < Card(i)] = (
w[i] - icweight[i] * x[i]
>= w[i.lead(1, "linear")] - icweight[i] * x[i.lead(1, "linear")]
)
licu[i].where[Ord(i) > 1] = (
w[i] - icweight[i] * x[i]
>= w[i.lag(1, "linear")] - icweight[i] * x[i.lag(1, "linear")]
)
mn[i].where[Ord(i) < Card(i)] = x[i] >= x[i.lead(1, "linear")]
x.lo[i] = 0.0001
m = Model(
cont,
name="m",
equations=[rev, pc, licu],
problem=Problem.NLP,
sense=Sense.MAX,
objective=obj,
)
m_mn = Model(
cont,
name="m_mn",
equations=[rev, pc, licu, mn],
problem=Problem.NLP,
sense=Sense.MAX,
objective=obj,
)
for iter, _ in t.records.itertuples(index=False):
p[i] = pt[i, iter]
icweight[i] = theta[i]
m.solve()
m_mn.solve()
import math
assert math.isclose(m_mn.objective_value, 0.9167, rel_tol=0.001)
if __name__ == "__main__":
main()