Python 繪圖 3D:生產組合最佳化

圖表


資源固定下,生產最佳組合

效用:長褲=46	夾克=40
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=27250.00
	棉=0.00	化纖=0.00
效用:長褲=45	夾克=46
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=28375.00
	棉=0.00	化纖=0.00
效用:長褲=49	夾克=41
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=28625.00
	棉=0.00	化纖=0.00
效用:長褲=39	夾克=39
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=24375.00
	棉=0.00	化纖=0.00
效用:長褲=45	夾克=43
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=27625.00
	棉=0.00	化纖=0.00
效用:長褲=56	夾克=28
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=28000.00
	棉=0.00	化纖=0.00
效用:長褲=56	夾克=34
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=29500.00
	棉=0.00	化纖=0.00
效用:長褲=39	夾克=40
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=24625.00
	棉=0.00	化纖=0.00
效用:長褲=46	夾克=43
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=28000.00
	棉=0.00	化纖=0.00
效用:長褲=38	夾克=38
限制:棉=750	化纖=1000
	長褲=375	夾克=250	貢獻=23750.00
	棉=0.00	化纖=0.00

效用固定下,生產最佳組合

效用:長褲=50	夾克=40
限制:棉=756	化纖=966
	長褲=347	夾克=272	貢獻=28230.00
	棉=1.00	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=820	化纖=975
	長褲=322	夾克=331	貢獻=29340.00
	棉=1.50	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=794	化纖=1082
	長褲=415	夾克=252	貢獻=30830.00
	棉=1.00	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=692	化纖=943
	長褲=362	夾克=219	貢獻=26860.00
	棉=1.50	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=797	化纖=948
	長褲=313	夾克=322	貢獻=28530.00
	棉=1.00	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=775	化纖=1062
	長褲=409	夾克=244	貢獻=30210.00
	棉=0.00	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=731	化纖=1109
	長褲=467	夾克=175	貢獻=30350.00
	棉=1.50	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=757	化纖=993
	長褲=367	夾克=259	貢獻=28710.00
	棉=1.50	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=693	化纖=873
	長褲=309	夾克=255	貢獻=25650.00
	棉=1.50	化纖=0.00
效用:長褲=50	夾克=40
限制:棉=737	化纖=972
	長褲=361	夾克=250	貢獻=28050.00
	棉=1.00	化纖=0.00

程式碼

# -*- coding: utf-8 -*-

import numpy as np
import math
from pulp import *
import uuid
from matplotlib import rcParams
from matplotlib import pyplot as plt
import pylab
from mpl_toolkits.mplot3d import Axes3D


class Optimizer:
    PlotData = None

    def __init__(self):
        self.PlotData = []

    def solve(self, nameOfProblem, benefitList, resourceList, noOutput=False):
        prob = LpProblem(nameOfProblem, LpMaximize)

        # 變數
        pants = LpVariable("Pants", lowBound=0, cat='Integer')
        jacket = LpVariable("Jacket", lowBound=0, cat='Integer')

        # 目標
        prob += benefitList[0] * pants + benefitList[1] * jacket

        # 限制
        prob += pants + 1.5 * jacket <= resourceList[0]
        prob += 2 * pants + jacket <= resourceList[1]

        # 解算
        prob.writeLP("%s.lp" % (nameOfProblem))
        prob.solve()

        if not noOutput:
            print u"效用:長褲=%.0f\t夾克=%.0f" % (
                benefitList[0], benefitList[1])
            print u"限制:棉=%.0f\t化纖=%.0f" % (
                resourceList[0], resourceList[1])

        if prob.status == 1:
            # 解答物件

            Pants = Jacket = None
            for v in prob.variables():
                if v.name == 'Pants':
                    Pants = v
                elif v.name == 'Jacket':
                    Jacket = v

            outcome = value(prob.objective)
            if not noOutput:
                print u"\t長褲=%d\t夾克=%d\t貢獻=%.2f" %    \
                    (Pants.varValue, Jacket.varValue, outcome)

            # 殘餘資源
            cotton = resourceList[0] -    \
                        (Pants.varValue + 1.5 * Jacket.varValue)
            polyester = resourceList[1] -    \
                        (2 * Pants.varValue + Jacket.varValue)

            if not noOutput:
                print u"\t棉=%.2f\t化纖=%.2f" % (cotton, polyester)

            self.PlotData.append([
                benefitList[0], benefitList[1],
                resourceList[0], resourceList[1],
                Pants.varValue, Jacket.varValue,
                outcome])
        else:
            if not noOutput:
                print "\t%s" % (LpStatus[prob.status])

    def genNorm(self, mu, sigma, sampleSize, cat=True):
        ret = np.random.normal(mu, sigma, sampleSize)
        for i in range(0, sampleSize):
            if cat:
                ret[i] = math.floor(ret[i])
            else:
                ret[i] = math.ceil(ret[i])

        return (ret)

    def printList(self, randomList):
        for i in randomList:
            print "%.0f" % (i)

    def plot3D(self, cat, fontName='Microsoft MHei'):
        titleChart = [[u"長褲", u"夾克", u"貢獻"], [u"棉", u"化纖", u"貢獻"]]
        AnalysisData = np.array(self.PlotData)

        rcParams['font.family'] = fontName    # Linux 'NanumBarunGothic'

        fig = pylab.figure()
        ax = Axes3D(fig)

        ax.set_title(u"生產最佳組合圖")

        ax.set_xlabel(titleChart[cat][0])
        ax.set_ylabel(titleChart[cat][1])
        ax.set_zlabel(titleChart[cat][2])

        pointSize = []

        for i in range(0, len(AnalysisData)):
            if cat == 0:
                val = math.sqrt(
                        (math.pow(AnalysisData[:, 0][i], 2) +
                        math.pow(AnalysisData[:, 1][i], 2))
                    )

                pointSize.append(val)

                ax.scatter(AnalysisData[:, 0], AnalysisData[:, 1],
                            AnalysisData[:, 6], s=pointSize)
            else:
                val = math.sqrt(
                        (math.pow(AnalysisData[:, 2][i], 2) +
                        math.pow(AnalysisData[:, 3][i], 2))
                    )

                pointSize.append(val)

                ax.scatter(AnalysisData[:, 2], AnalysisData[:, 3],
                            AnalysisData[:, 6], s=pointSize)

        plt.show()

    def ResetPlotData(self):
        self.PlotData = None
        self.PlotData = []

    def Simulation(self, benefitRandomList, resourceRandomList, wantPlot=False):
        sampleSize = cat = 0
        solverID = ['Benefit', 'Constraints']

        if len(benefitRandomList[0]) == 1:
            cat = 1

        if cat == 0:
            sampleSize = len(benefitRandomList[0])
        else:
            sampleSize = len(resourceRandomList[0])

        for i in range(0, sampleSize):
            if cat == 0:
                self.solve(
                    'Opt-%s-%s' % (solverID[cat],
                    uuid.uuid4()),
                    [benefitRandomList[0][i], benefitRandomList[1][i]],
                    [resourceRandomList[0][0], resourceRandomList[1][0]],
                    not wantPlot)
            else:
                self.solve(
                    'Opt-%s-%s' % (solverID[cat],
                    uuid.uuid4()),
                    [benefitRandomList[0][0], benefitRandomList[1][0]],
                    [resourceRandomList[0][i], resourceRandomList[1][i]],
                    not wantPlot)

        if wantPlot:
            self.plot3D(cat)
        else:
            for sol in self.PlotData:
                print u"效用:長褲=%.0f\t夾克=%.0f" % (
                        sol[0], sol[1])
                print u"限制:棉=%.0f\t化纖=%.0f" % (
                        sol[2], sol[3])
                print u"綜效:長褲=%.0f\t夾克=%.0f\t效益=%.0f\n" % (
                        sol[4], sol[5], sol[6])


if __name__ == "__main__":
    optimizer = Optimizer()

    sampleSize = 10

    benefitRandomList = [
        optimizer.genNorm(50, 8, sampleSize),
        optimizer.genNorm(40, 6, sampleSize)
        ]

    resourceRandomList = [[750], [1000]]
    optimizer.Simulation(benefitRandomList, resourceRandomList, True)

    benefitRandomList = [[50], [40]]
    resourceRandomList = [
        optimizer.genNorm(750, 43, sampleSize),
        optimizer.genNorm(1000, 76, sampleSize)]

    optimizer.Simulation(benefitRandomList, resourceRandomList, True)

    optimizer.ResetPlotData()