优化机器';python中的应用

优化机器';python中的应用,python,optimization,Python,Optimization,我需要找到最佳组合:最大限度地提高效率或最小化3台机器的利用率所需的功率(成本=输出/效率),以产生给定的输出。 我发现一个库kneed可以给我每个效率曲线的最优值,但是问题更复杂 如果我需要10000个输出:我会使用BM5的所有输出,因为它有最好的优化(效率),并且它完全覆盖了所需的输出 如果我需要15000个输出:我会使用BM5到它的optima~10000+BM3到它的optima~4000+一点额外的BM5到它的optima,我猜 如果我需要20000输出:我将使用BM5达到其最优

我需要找到最佳组合:最大限度地提高效率或最小化3台机器的利用率所需的功率(成本=输出/效率),以产生给定的输出。 我发现一个库kneed可以给我每个效率曲线的最优值,但是问题更复杂

  • 如果我需要10000个输出:我会使用BM5的所有输出,因为它有最好的优化(效率),并且它完全覆盖了所需的输出

  • 如果我需要15000个输出:我会使用BM5到它的optima~10000+BM3到它的optima~4000+一点额外的BM5到它的optima,我猜

  • 如果我需要20000输出:我将使用BM5达到其最优值~10000+BM4达到其最优值~10000

总体而言,BM5具有最高的效率优化,但BM3在较低的产量(高达4000吨)下具有最高的效率优化

如果有人能给我指出正确的道路,我将不胜感激 也许是分数背包问题的一个聪明应用

这可能有助于: 我将把微调留给您。还要注意的是,这只是一个暴力解决方案,所以如果你有更多的机器,它将爆炸相当快

#Data from your graph at glance. You probably want more data points for more precise outputs.
machine1 = data.frame(efficiency=c(0.4, 0.5, 0.6, 0.7, 0.8), output=c(2200, 2400, 2600, 2800, 3000 ))
machine2 = data.frame(efficiency=c(0.3, 0.4, 0.5, 0.6, 0.7, 0.8), output=c(4000, 5000, 6000, 7000, 8000, 9000))
machine3 = data.frame(efficiency=c(0.3, 0.4, 0.5, 0.6, 0.7, 0.8), output=c(4100, 5100, 6100, 7100, 8100, 9100))


combinations <- data.frame(m1eff=numeric(), m2eff=numeric(), m3eff=numeric(),
                           output1=numeric(), output2=numeric(), output3=numeric(),
                           totalOutput=numeric(), requiredPower=numeric())


#I don't have exact relation for the power input required.
#So I will go by the output = power * efficiency
# o = p1 * e1 + p2 * e2 + p3 * e3
# p_total = p1 + p2 + p3
# we know o1, o2, o3, e1, e2, e3 so we can compute the power required
# and we will want to minimize that.
computeEffandPow <- function(m1eff, m1out, m2eff, m2out, m3eff, m3out) {
  totalOutput <- 0
  requiredPower <- 0
  if (m1eff > 0) {
    totalOutput <- totalOutput + m1out
    requiredPower <- requiredPower + (1/m1eff) * m1out
  }
  if (m2eff > 0) {
    totalOutput <- totalOutput + m2out
    requiredPower <- requiredPower + (1/m2eff) * m2out
  }
  if (m3eff > 0) {
    totalOutput <- totalOutput + m3out
    requiredPower <- requiredPower + (1/m3eff) * m3out
  }
  return(c(m1eff, m1out, m2eff, m2out, m3eff, m3out, requiredPower, totalOutput))
  
}

#since you have only three machines and the data set is not that large
#I shall take the brute force approach. There is most likely some neat mathematical solution
#Which unfortunately eludes me at the moment.
#So I will simply discretize your data into intervals, compute all possible combinations of output-efficiencies
#Then sort the values.
for (i in 1:nrow(machine1)) {
  for (j in 1:nrow(machine2)) {
   for (k in 1:nrow(machine3)) {
     m1eff <- machine1$efficiency[i]
     m1out <- machine1$output[i] 
     m2eff <- machine2$efficiency[j]
     m2out <- machine2$output[j] 
     m3eff <- machine3$efficiency[k]
     m3out <- machine3$output[k] 
     
     
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, m2eff, m2out, m3eff, m3out))
     #note that this includes unnecessary duplicities
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, m2eff, m2out, 0, 0))
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, 0, 0, m3eff, m3out))
     combinations <- rbind(combinations, computeEffandPow(0, 0, m2eff, m2out, m3eff, m3out))
    
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, 0, 0, 0, 0))
     combinations <- rbind(combinations, computeEffandPow(0, 0, m2eff, m2out, 0, 0))
     combinations <- rbind(combinations, computeEffandPow(0, 0, 0, 0, m3eff, m3out))
    
   } 
  }
}
#I did something wrong and the rbind killed the names.
colnames(combinations) = c("m1eff", "m1out","m2eff", "m2out","m3eff", "m3out", "reqPow", "totalOut")
#do away with duplicities
combinations <- unique(combinations)
combinations <- combinations[order(combinations$totalOut, combinations$reqPow),]


listEfficiencies <- function(combinations, requiredOutput, minimumOnly=F) {
  #here I use approximate output since I chose rather large chunks.
  #if you make the intervals smaller, the you will be able to afford smaller tolerance.
  approximateOutput <- combinations[combinations$totalOut < requiredOutput + 500 & combinations$totalOut > requiredOutput - 500, ]
  if (minimumOnly) {
    approximateOutput <- approximateOutput[which(approximateOutput$reqPow == min(approximateOutput$reqPow)),]
  }
  return(approximateOutput)
}

什么是机器,什么是输出,你如何衡量效率?我不明白你们想优化什么。机器是鼓风机,输出是流量,效率已经给了我。这里的关键是,图表显示,对于特定的流量,每个鼓风机的效率不同。谢谢您的帮助。你说得对,第一台机器(BM3)的效率并不高。然而,对于低输出(高达4000)更为方便。我想测试一下你的方法,但是你的代码不是Python.rats,sry,我被R所吸引,因为我在其中做了一些事情,但是我错过了标记。但是,您的问题与语言无关,如果您发现这种方法有效,您可以使用您选择的语言以更好的方式重新编写代码。请尝试运行它,这样您就不需要安装R,因为我的疏忽:-)对不起,但是我目前正在工作,所以没有时间用python重写它。要得到结果,首先按原样编写代码,然后在控制台中运行
listefficies(combines,15000)
。如果只想过滤最小值,请添加
TRUE
作为第三个参数。15000可以替换为您选择的一些C:-)。谢谢,但我从来没有使用过R,如果我不能阅读它,就很难用Python重新编写。
#Data from your graph at glance. You probably want more data points for more precise outputs.
machine1 = data.frame(efficiency=c(0.4, 0.5, 0.6, 0.7, 0.8), output=c(2200, 2400, 2600, 2800, 3000 ))
machine2 = data.frame(efficiency=c(0.3, 0.4, 0.5, 0.6, 0.7, 0.8), output=c(4000, 5000, 6000, 7000, 8000, 9000))
machine3 = data.frame(efficiency=c(0.3, 0.4, 0.5, 0.6, 0.7, 0.8), output=c(4100, 5100, 6100, 7100, 8100, 9100))


combinations <- data.frame(m1eff=numeric(), m2eff=numeric(), m3eff=numeric(),
                           output1=numeric(), output2=numeric(), output3=numeric(),
                           totalOutput=numeric(), requiredPower=numeric())


#I don't have exact relation for the power input required.
#So I will go by the output = power * efficiency
# o = p1 * e1 + p2 * e2 + p3 * e3
# p_total = p1 + p2 + p3
# we know o1, o2, o3, e1, e2, e3 so we can compute the power required
# and we will want to minimize that.
computeEffandPow <- function(m1eff, m1out, m2eff, m2out, m3eff, m3out) {
  totalOutput <- 0
  requiredPower <- 0
  if (m1eff > 0) {
    totalOutput <- totalOutput + m1out
    requiredPower <- requiredPower + (1/m1eff) * m1out
  }
  if (m2eff > 0) {
    totalOutput <- totalOutput + m2out
    requiredPower <- requiredPower + (1/m2eff) * m2out
  }
  if (m3eff > 0) {
    totalOutput <- totalOutput + m3out
    requiredPower <- requiredPower + (1/m3eff) * m3out
  }
  return(c(m1eff, m1out, m2eff, m2out, m3eff, m3out, requiredPower, totalOutput))
  
}

#since you have only three machines and the data set is not that large
#I shall take the brute force approach. There is most likely some neat mathematical solution
#Which unfortunately eludes me at the moment.
#So I will simply discretize your data into intervals, compute all possible combinations of output-efficiencies
#Then sort the values.
for (i in 1:nrow(machine1)) {
  for (j in 1:nrow(machine2)) {
   for (k in 1:nrow(machine3)) {
     m1eff <- machine1$efficiency[i]
     m1out <- machine1$output[i] 
     m2eff <- machine2$efficiency[j]
     m2out <- machine2$output[j] 
     m3eff <- machine3$efficiency[k]
     m3out <- machine3$output[k] 
     
     
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, m2eff, m2out, m3eff, m3out))
     #note that this includes unnecessary duplicities
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, m2eff, m2out, 0, 0))
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, 0, 0, m3eff, m3out))
     combinations <- rbind(combinations, computeEffandPow(0, 0, m2eff, m2out, m3eff, m3out))
    
     combinations <- rbind(combinations, computeEffandPow(m1eff, m1out, 0, 0, 0, 0))
     combinations <- rbind(combinations, computeEffandPow(0, 0, m2eff, m2out, 0, 0))
     combinations <- rbind(combinations, computeEffandPow(0, 0, 0, 0, m3eff, m3out))
    
   } 
  }
}
#I did something wrong and the rbind killed the names.
colnames(combinations) = c("m1eff", "m1out","m2eff", "m2out","m3eff", "m3out", "reqPow", "totalOut")
#do away with duplicities
combinations <- unique(combinations)
combinations <- combinations[order(combinations$totalOut, combinations$reqPow),]


listEfficiencies <- function(combinations, requiredOutput, minimumOnly=F) {
  #here I use approximate output since I chose rather large chunks.
  #if you make the intervals smaller, the you will be able to afford smaller tolerance.
  approximateOutput <- combinations[combinations$totalOut < requiredOutput + 500 & combinations$totalOut > requiredOutput - 500, ]
  if (minimumOnly) {
    approximateOutput <- approximateOutput[which(approximateOutput$reqPow == min(approximateOutput$reqPow)),]
  }
  return(approximateOutput)
}
import csv
import itertools
#since we had the data in R, i dumped them into .csv file and read them
reader = csv.reader(open('machines.csv'), delimiter=',')
machines = []
for i in range(0,10):
    machines.append([])

#a bit of bookkeeping
for line in reader:
    for i in range(0,5):
        if line[2 * i + 1] not in ["NA", "efficiency", "output"]:
            machines[2 * i + 1].append(float(line[2 * i + 1]))
            machines[2 * i].append(float(line[2 * i + 2]))

#a little more of bookkeeping - we want to retrieve the values without the need to care about the way
#the data are stored.
#also, since the memory appears to be the problem, we want to store as little data as possible and rest will
#be fetched on demand.
class MachineHolder:
    def __init__(self, machineTable):
        self.machines = machineTable

    def getLen(self, machineInd):
        return len(self.machines[machineInd * 2 + 1])

    def getLenBatch(self, indices):
        return ([x for x in map(lambda x: self.getLen(x), indices)])

    def getMachineInfo(self, machineNumber, lineIndex):
        eff = self.machines[machineNumber * 2 + 1][lineIndex]
        out = self.machines[machineNumber * 2][lineIndex]
        return (eff, out)


    def getMachineInfoBatch(self, i1, i2, i3, i4, i5):
        #I had a nice lambda here and passed indices as a tuple. The overhead was too large as we have only five indices..
        e1 = 0 if i1 == -1 else self.machines[1][i1]
        e2 = 0 if i2 == -1 else self.machines[3][i2]
        e3 = 0 if i3 == -1 else self.machines[5][i3]
        e4 = 0 if i4 == -1 else self.machines[7][i4]
        e5 = 0 if i5 == -1 else self.machines[9][i5]

        o1 = 0 if i1 == -1 else self.machines[0][i1]
        o2 = 0 if i2 == -1 else self.machines[2][i2]
        o3 = 0 if i3 == -1 else self.machines[4][i3]
        o4 = 0 if i4 == -1 else self.machines[6][i4]
        o5 = 0 if i5 == -1 else self.machines[8][i5]

        #at least the structure of our storage is nicely visible.
        return e1, e2, e3, e4, e5, o1, o2, o3, o4, o5

#since the python ints have unlimited size and are in fact objects
#they take unreasonable amount of memory if we only want to store one number
#enters bitpacking. Maybe a bit of an overkill, but I like it.
def packValues(i1, i2, i3, i4, i5, eff, out):
    return i1 | (i2 << 8) | (i3 << 16) | (i4 << 24) | (i5 << 32) | (eff << 64) | (out << 96)

#the size of our packed result is 40 bits. It could be probably shaved down further, however that would require
#multiplication instead of guessing.
#also since we now pack everything, we save additional space by not using tuples.
#our result is just a list of packed ints.
def unpackValues(packedIndices):
    idx1 = packedIndices & 0xFF
    idx2 = (packedIndices & (0xFF << 8)) >> 8
    idx3 = (packedIndices & (0xFF << 16)) >> 16
    idx4 = (packedIndices & (0xFF << 24)) >> 24
    idx5 = (packedIndices & (0xFF << 32)) >> 32
    eff = (packedIndices & (0xFFFFFFFF << 64)) >> 64
    out = (packedIndices & (0xFFFFFFFF << 96)) >> 96
    return idx1, idx2, idx3, idx4, idx5, eff, out




results = []
count = 0
mach = MachineHolder(machines)
m0len = mach.getLen(0)
m1len = mach.getLen(1)
m2len = mach.getLen(2)
m3len = mach.getLen(3)
m4len = mach.getLen(4)
for i in range(0, m0len):
    for j in range(0, m1len):
        for k in range(0, m2len):
            for l in range(0, m3len):
                for m in range(0, m4len):
                    e1, e2, e3, e4, e5, o1, o2, o3, o4, o5 = mach.getMachineInfoBatch(i, j, k, l, m)
                    totalOutput = o1 + o2 + o3 + o4 + o5
                    powerRequired = 1/e1 * o1 + 1/e2 * o2 + 1/e3 * o3 + 1/e4 * o4 + 1/e5 * o5
                    #since the values are in thousands, I think we can safely round
                    results.append(packValues(i, j, k, l, m, int(totalOutput), int(powerRequired)))
                    count += 1
                    if count % 1000000 == 0:
                        print(count, unpackValues(results[count-1]))

                    

#here we can start wasting some space since the number won't be that big anyways
#however we will need to check the array boundaries, otherwise we will crash
#also it is just a mechanical repetition of the step above, so I will leave that up to you
for i in range(0,50):
    for j in range(0,50):
        for k in range(0, 50):
            for l in range(0, 50):
                count += 1
                count += 1
                count += 1
                count += 1
                if count % 10000 == 0:
                    print(count)

for i in range(0, 50):
    for j in range(0, 50):
        for k in range(0, 50):
            count += len([x for x in itertools.combinations([1, 2, 3, 4, 5], 3)])
            if count % 10000 == 0:
                print(count)

for i in range(0, 50):
    for j in range(0, 50):
        count += len([x for x in itertools.combinations([1, 2, 3, 4, 5], 2)])
        if count % 10000 == 0:
            print(count)

for i in range(0, 50):
    count += len([x for x in itertools.combinations([1, 2, 3, 4, 5], 1)])
    if count % 10000 == 0:
        print(count)

print(count)