动态生成满足多个条件的受限解决方案

时间:2018-09-26 00:26:22

标签: python constraints linear-programming solver inequalities

我感觉有一个优雅的Python解决方案,我一直在尝试使用VBA解决。 有人可以帮忙吗?

如何生成符合以下条件的数字列表:

  1. 都是整数
  2. 首先在类型之间分配总计。
  3. 将数字进一步划分为子类型,并进行优化以满足所需的百分比。
  4. 总数不超过指定的总数。

此问题的示例:

  • 您计划最多建造102个住宅单元。
  • 建筑类型:其中40%为工作室,而60%为联排别墅建筑类型。 (可以有更多或更少的类型)
  • 未来公寓的居住者有两个优先级列表:辅助和无辅助
    • 需要完全满足Assisted(A)列表中的单位分配百分比,而Unassisted(U)列表则非常灵活。如果可能的话,我们希望Unassisted(U)列表最多占总单位的20%,但我们绝对需要最少80%的Total Assisted(A)单位。
  • 辅助(A)单位总计为102x80%= 81.6单位(已经不是整数)
    • 老年人名单中至少有10%的Assisted(A)名单单元。
    • “辅助(A)”清单中至少有40%用于家庭。
    • “辅助(A)”列表单元中剩余的50%用于有抱负的数据科学家。

总计20%的剩余单位是无人(U)占用单位。

所以:

  • 总数:102个单位。
  • Construction_type_categories=[.4, .6](102个单元分为工作室和联排别墅:40%和60%)
  • Assisted=[.1,.4,.5](有80%以上的单位为辅助单位,根据列表中的百分比进一步分为老年人,家庭和其他人)
  • 非辅助单位是不包含在“辅助”列表的80%以上的剩余单位。 (最多占总单元数的20%)

结果:

[4,16,12,8,7,25,19,11]

故障:

  • 4个老人工作室工作室
  • 为家庭提供援助的16个工作室单元
  • 其他辅助入住类型的12个工作室单元
  • 8个工作室单元(无辅助)
  • 7个协助老年人的联排别墅
  • 25个协助家庭的联排别墅
  • 其他辅助类型的19个联排别墅
  • 11个联排别墅(无助)。

我想到先生成一个四舍五入的初步数组,然后循环遍历并进行调整。 看起来很乏味,我已经开始考虑使用numpy生成大型的数字矩阵并按照概述的条件进行过滤。

手动生成和优化数字非常耗时,因此,感谢您提供更好的解决方案。

import math

def is_even(x):
    if x % 2 == 0:
        return True
    else:
        return False

total=102 
unassisted=.2
unassisted_unit_count= math.floor(total*unassisted)
assisted_unit_count=total- unassisted_unit_count

construction_type_categories=[.4, .6] #Must be even.
assisted_subcategories=[.1,.4,.5] #Last element here will be of least priority.


def Unit_Number_Getter(L):

    if L[1]=='total_constr_type_amounts':
        giventotal= total
    if L[1]=='assisted_constr_type_amounts':
        giventotal= assisted_unit_count

    #Spliting by construction type (preliminary).
    constr_type_amounts=[]
    for ct in construction_type_categories:
        constr_type_amounts.append(round(giventotal * ct))

    #Making the unit counts even for the total construction type amounts (need to).
    for p in constr_type_amounts:
        if not is_even(p):
            add_here=constr_type_amounts.index(p)
            for f in constr_type_amounts:
                if not is_even(f):
                    from_here= constr_type_amounts.index(f)
            constr_type_amounts[add_here] +=1
            constr_type_amounts[from_here] -=1
    assert sum(constr_type_amounts)==giventotal

    print L[1]
    print(constr_type_amounts)
    L[0]=constr_type_amounts


total_constr_type_amounts=0
assisted_constr_type_amounts=0

List_of_lists=[[total_constr_type_amounts,"total_constr_type_amounts"],[assisted_constr_type_amounts,"assisted_constr_type_amounts"]]

#Established the unit counts for each construction type (for Assisted and total units)
for L in List_of_lists:
    Unit_Number_Getter(L)


#Getting a list of the unit counts for each assisted subcategory in each constr type.
testlist=[]
for c in List_of_lists[1][0]:
    already_added=0
    for a in assisted_subcategories[:-1]:
        adding_now= math.ceil(c * a)
        testlist.append(adding_now)
        already_added+=adding_now
    #^Added the priority assisted units (all but the last element).   

    #Now will add the last of the assisted units.
    testlist.append(c-already_added)

    #Now will add he least prioritized unassisted units up to the max.
    Max_unassisted_units= List_of_lists[0][0][List_of_lists[1][0].index(c)]-c

    testlist.append(Max_unassisted_units)

    assert ((c+Max_unassisted_units)== List_of_lists[0][0][List_of_lists[1][0].index(c)])#all units present

print("Result: "+ "\n" + str(testlist))     

0 个答案:

没有答案