如何在python纸浆中使用绝对差条件之和?

How to use sum of absolute difference condition in python pulp?

我一直在查找关于线性规划中绝对值条件的类似 posts,并尝试提出的解决方案。但是,我仍在努力让我的纸浆设置在 python 中工作。

我这里post简化代码。具体来说,在下面的“更近的约束”中,我想强制 绝对差之和 小于某个阈值,“sum(df['diff_orig'])”。 posted 代码有效,但这只是一个总和差异 而不是绝对差异

任何帮助将不胜感激!

J

import pandas as pd
import pulp

# initialize data
nav = 1000
data = [['A', 0.2], ['B', 0.4], ['C', 0.1], ['D', 0.3], ['cash', 0.0]]

# create the pandas DataFrame
df = pd.DataFrame(data, columns=['asset', 'w_star'])
df['prccd'] = [17, 21, 119, 49, None]
df['q_tilde'] = [11, 19, 0, 6, None]
df['val'] = df.prccd * df.q_tilde
df.loc[df.asset == 'cash', 'val'] = nav - sum(df.loc[~df.val.isna(), 'val'])
df['w_act'] = df.val / sum(df.val)
df['diff_orig'] = abs(df.w_star - df.w_act)
df = df.set_index('asset')

# manipulate cash
dfnc = df[df.index != 'cash']

# create variables and model
dq = pulp.LpVariable.dicts("dq", dfnc.index, cat='Integer', lowBound=0)
mod = pulp.LpProblem("CashReduction", pulp.LpMinimize)

# objective function
mod += nav - sum([dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd'] for i in dfnc.index])

# lower bounds:
for i in dfnc.index:
    mod += dq[i] >= 0

# budget constraint
mod += sum([dq[i] * dfnc.loc[i, 'prccd'] for i in dfnc.index]) <= df.loc['cash', 'val']

# nearer constraint
mod += sum(
    [dfnc.loc[i, 'w_star'] - (dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd']) / nav
     for i in dfnc.index]) <= sum(df['diff_orig'])

# individual diff cannot be bigger than 3%
for i in dfnc.index:
    mod += (dfnc.loc[i, 'w_star'] -
            (dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd']) / nav) <= 0.03
for i in dfnc.index:
    mod += (dfnc.loc[i, 'w_star'] -
            (dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd']) / nav) >= -0.03

# solve model
mod.solve()

# output solution
for i in dfnc.index:
    print(i, dq[i].value())```

您需要引入一个额外的索引变量来执行此操作。 ABS 是非线性的,所以处理一个 ABS 函数的典型方法是引入 一个 变量并使该变量大于 pos 值并大于 ABS 目标的否定,如所以:

if we are working with |x - y|...
g > x - y
g > -(x - y)

在你的例子中,你有一个 ABS 函数用于每个要求和的元素,所以你可以通过创建一个新变量来扩展上面的内容,用你想要求和的相同的东西索引,然后使用它......

import pandas as pd
import pulp

# initialize data
nav = 1000
data = [['A', 0.2], ['B', 0.4], ['C', 0.1], ['D', 0.3], ['cash', 0.0]]

# create the pandas DataFrame
df = pd.DataFrame(data, columns=['asset', 'w_star'])
df['prccd'] = [17, 21, 119, 49, None]
df['q_tilde'] = [11, 19, 0, 6, None]
df['val'] = df.prccd * df.q_tilde
df.loc[df.asset == 'cash', 'val'] = nav - sum(df.loc[~df.val.isna(), 'val'])
df['w_act'] = df.val / sum(df.val)
df['diff_orig'] = abs(df.w_star - df.w_act)
df = df.set_index('asset')
print(df)

# manipulate cash
dfnc = df[df.index != 'cash']

# create variables and model
dq = pulp.LpVariable.dicts("dq", dfnc.index, cat='Integer', lowBound=0)
ab_dif_element = pulp.LpVariable.dicts("ab_dif", df.index)
mod = pulp.LpProblem("CashReduction", pulp.LpMinimize)

# objective function
mod += nav - sum([dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd'] for i in dfnc.index])

# this is redundant...you've already set lowBound
# # lower bounds:
# for i in dfnc.index:
#     mod += dq[i] >= 0

# budget constraint
mod += sum([dq[i] * dfnc.loc[i, 'prccd'] for i in dfnc.index]) <= df.loc['cash', 'val']


for i in dfnc.index:
    # pos ab_dif
    mod += ab_dif_element[i] >= dfnc.loc[i, 'w_star'] - (dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd']) / nav
    # neg ab_dif
    mod += ab_dif_element[i] >= -(dfnc.loc[i, 'w_star'] - (dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd']) / nav)

# nearer constraint
mod += sum(ab_dif_element[i] for i in dfnc.index) <= sum(df['diff_orig'])

# individual diff cannot be bigger than 3%
for i in dfnc.index:
    mod += (dfnc.loc[i, 'w_star'] -
            (dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd']) / nav) <= 0.03
for i in dfnc.index:
    mod += (dfnc.loc[i, 'w_star'] -
            (dq[i] * dfnc.loc[i, 'prccd'] + dfnc.loc[i, 'q_tilde'] * dfnc.loc[i, 'prccd']) / nav) >= -0.03

# solve model
mod.solve()

# output solution
for i in dfnc.index:
    print(i, dq[i].value(), ab_dif_element[i].value())