我需要支持为PuLP中建模的线性优化问题设置约束。
背景:
有一种产品有标签。标签空间根据产品尺寸的不同而不同-最大空间是已知和设置的。
每个标签都有与特定国家/地区相关的语言。因此,一个标签=语言国家关系集群。
(目前,为了简化,集群数量是手动预设的,可以更改以满足可行的解决方案。然而,理想情况下,模型需要确定最小集群数量,以满足规定的标准。)
语言在标签上需要不同的空间。
此外,每个国家都有一套要求,例如:
-
某个BBD格式(日期前最佳);
-
某个生产日期格式;
-
原产地声明等。
国家/地区不能链接到多个集群。
不具有相同要求的国家不能聚集在一起
(这就是我陷入困境的地方)
例如:
-
US不能与CA集群,因为它们具有不同的BBD格式;
-
IN不能与GB群集,因为IN需要标签上的生产日期,而GB不需要;
-
SG不能与AT集群,因为它们有不同的原产地声明,即使BBD和生产日期格式等相同。
任务是创建一个优化模型,根据规定的限制条件将国家分组。最终,由于限制,无论可用的标签空间如何,一些集群总是会有一个或两个国家。同时,80%的国家都有相同的要求,这些国家需要根据有限的标签空间和其他最大化目标(如每个国家的数量)进行集群,同时不要混合20%的独特集群。
目标将根据国家数量、销售单位数量或销售份额等(不包括在问题中)最大化每个集群。
我需要帮助或提示如何只对有共同需求的国家进行集群。
我能够将国家分组在不同的集群下,满足空间限制并最大化,但从需求的角度来看,它们都是混合的。
以下是数据元素及其关系,也是我的代码的一部分。提前感谢!
CTY=["SG", "AT", "BE", "BG", "CH", "CY", "CZ", "DE", "DK", "DO", "ES", "FI", "FR", "GR", "HR", "HU", "IE", "IS", "IT", "LT", "LV", "NL", "NO", "PL", "PT", "RO", "RS", "SE", "SI", "SK", "RU", "US", "PR", "CA", "AU", "NZ", "JP", "IN", "PH", "GB", "CN"]
language=["EN_GB", "BG_BG", "CS_CZ", "DA_DK", "DE_DE", "EL_GR", "EN_GB", "ES_ES", "FI_FI", "FR_FR", "HR_HR", "HU_HU", "IT_IT", "LT_LT", "LV_LV", "NL_NL", "NO_NO", "PL_PL", "PT_PT", "RO_RO", "SK_SK", "SL_SI", "SR_RS", "SV_SE", "RU_RU", "EN_US", "EN_CA", "FR_CA", "EN_AU", "JA_JP", "EN_AU", "EN_IN", "EN_PH", "ZH_CN"]
BBD=["DD-MM-YYYY", "DD-ABC-YYYY", "YYYY/AB/DD", "YYYY-MM-DD"]
production_date=["DD-MM-YYYY", "YYYY-MM-DD", "NO"]
origin=["FP", "PI", "NO"]
space=[1, 2, 3]
max_language_space=5 #Main constraint - maximum allowed space for label. Value can change depending on the size of product.
clusters=np.arange(1, 12) #Number of clusters are a consequence to meet an optimal solution - aim to have as little number of clusters as possible at an optimal solution.
CTY_BBD={"SG":"DD-MM-YYYY", "AT":"DD-MM-YYYY", "BE":"DD-MM-YYYY", "BG":"DD-MM-YYYY", "CH":"DD-MM-YYYY", "CY":"DD-MM-YYYY", "CZ":"DD-MM-YYYY", "DE":"DD-MM-YYYY", "DK":"DD-MM-YYYY", "DO":"DD-MM-YYYY", "ES":"DD-MM-YYYY", "FI":"DD-MM-YYYY", "FR":"DD-MM-YYYY", "GR":"DD-MM-YYYY", "HR":"DD-MM-YYYY", "HU":"DD-MM-YYYY", "IE":"DD-MM-YYYY", "IS":"DD-MM-YYYY", "IT":"DD-MM-YYYY", "LT":"DD-MM-YYYY", "LV":"DD-MM-YYYY", "NL":"DD-MM-YYYY", "NO":"DD-MM-YYYY", "PL":"DD-MM-YYYY", "PT":"DD-MM-YYYY", "RO":"DD-MM-YYYY", "RS":"DD-MM-YYYY", "SE":"DD-MM-YYYY", "SI":"DD-MM-YYYY", "SK":"DD-MM-YYYY", "RU":"DD-MM-YYYY", "US":"DD-ABC-YYYY", "PR":"DD-ABC-YYYY", "CA":"YYYY/AB/DD", "AU":"DD-MM-YYYY", "NZ":"DD-MM-YYYY", "JP":"YYYY-MM-DD", "IN":"DD-MM-YYYY", "PH":"DD-ABC-YYYY", "GB":"DD-MM-YYYY", "CN":"YYYY-MM-DD"}
language_space={"EN_GB":1, "BG_BG":1, "CS_CZ":1, "DA_DK":1, "DE_DE":1, "EL_GR":1, "EN_GB":1, "ES_ES":1, "FI_FI":1, "FR_FR":1, "HR_HR":1, "HU_HU":1, "IT_IT":1, "LT_LT":1, "LV_LV":1, "NL_NL":1, "NO_NO":1, "PL_PL":1, "PT_PT":1, "RO_RO":1, "SK_SK":1, "SL_SI":1, "SR_RS":1, "SV_SE":1, "RU_RU":3, "EN_US":1, "EN_CA":1, "FR_CA":1, "EN_AU":1, "JA_JP":3, "EN_AU":1, "EN_IN":1, "EN_PH":1, "ZH_CN":2}
CTY_language={"SG":["EN_GB"], "AT":["DE_DE"], "BE":["FR_FR", "NL_NL"], "BG":["BG_BG"], "CH":["DE_DE", "FR_FR"], "CY":["EL_GR"], "CZ":["CS_CZ"], "DE":["DE_DE"], "DK":["DA_DK"], "DO":["ES_ES"], "ES":["ES_ES"], "FI":["FI_FI"], "FR":["FR_FR"], "GR":["EL_GR"], "HR":["HR_HR"], "HU":["HU_HU"], "IE":["EN_GB"], "IS":["FI_FI", "SV_SE"], "IT":["IT_IT"], "LT":["LT_LT"], "LV":["LV_LV"], "NL":["NL_NL"], "NO":["NO_NO"], "PL":["PL_PL"], "PT":["PT_PT"], "RO":["RO_RO"], "RS":["SR_RS"], "SE":["SV_SE"], "SI":["SL_SI"], "SK":["SK_SK"], "RU":["RU_RU"], "US":["EN_US"], "PR":["EN_US"], "CA":["EN_CA", "FR_CA"], "AU":["EN_AU"], "NZ":["EN_AU"], "JP":["JA_JP"], "IN":["EN_IN"], "PH":["EN_PH"], "GB":["EN_GB"], "CN":["ZH_CN"]}
CTY_production_date={"SG":"DD-MM-YYYY", "AT":"DD-MM-YYYY", "BE":"DD-MM-YYYY", "BG":"DD-MM-YYYY", "CH":"DD-MM-YYYY", "CY":"DD-MM-YYYY", "CZ":"DD-MM-YYYY", "DE":"DD-MM-YYYY", "DK":"DD-MM-YYYY", "DO":"DD-MM-YYYY", "ES":"DD-MM-YYYY", "FI":"DD-MM-YYYY", "FR":"DD-MM-YYYY", "GR":"DD-MM-YYYY", "HR":"DD-MM-YYYY", "HU":"DD-MM-YYYY", "IE":"DD-MM-YYYY", "IS":"DD-MM-YYYY", "IT":"DD-MM-YYYY", "LT":"DD-MM-YYYY", "LV":"DD-MM-YYYY", "NL":"DD-MM-YYYY", "NO":"DD-MM-YYYY", "PL":"DD-MM-YYYY", "PT":"DD-MM-YYYY", "RO":"DD-MM-YYYY", "RS":"DD-MM-YYYY", "SE":"DD-MM-YYYY", "SI":"DD-MM-YYYY", "SK":"DD-MM-YYYY", "RU":"DD-MM-YYYY", "US":"NO", "PR":"NO", "CA":"NO", "AU":"NO", "NZ":"NO", "JP":"NO", "IN":"DD-MM-YYYY", "PH":"NO", "GB":"NO", "CN":"YYYY-MM-DD"}
CTY_origin:{"SG":"FP", "AT":"PI", "BE":"PI", "BG":"PI", "CH":"PI", "CY":"PI", "CZ":"PI", "DE":"PI", "DK":"PI", "DO":"PI", "ES":"PI", "FI":"PI", "FR":"PI", "GR":"PI", "HR":"PI", "HU":"PI", "IE":"PI", "IS":"PI", "IT":"PI", "LT":"PI", "LV":"PI", "NL":"PI", "NO":"PI", "PL":"PI", "PT":"PI", "RO":"PI", "RS":"PI", "SE":"PI", "SI":"PI", "SK":"PI", "RU":"NO", "US":"FP", "PR":"FP", "CA":"FP", "AU":"NO", "NZ":"NO", "JP":"FP", "IN":"NO", "PH":"NO", "GB":"NO", "CN":"FP"}
prob=LpProblem('RU per cluster') #Eventually it is a LpMaximize optimization. The objective will be set to maximize CTY volume, or number of selling units, or sales share, etc. per cluster
x_cr=LpVariable.dicts('x',[(c, r) for c in clusters for r in CTY], 0, 1, LpBinary)
prob+=lpSum([language_space[l]*x_cr[(c, r)] for c in clusters for r in CTY for l in language if l in CTY_language[r]])
for c in clusters:
prob+=lpSum([language_space[l]*x_cr[(c, r)] for r in CTY for l in language if l in CTY_language[r]])<=max_language_space
for r in CTY:
prob+=lpSum(x_cr[(c, r)] for c in clusters)==1