電腦模擬

紀錄與電腦模擬相關內容與紀錄, 使用工具 Python3, RoboDK (RoboDK API)

PyQt5

pyqt5 程式 http://projects.skylogic.ca/blog/how-to-install-pyqt5-and-build-your-first-gui-in-python-3-4/

run.py, 自行編寫用從 core/main.py 中導入 MainWindow 類別建立案例後執行

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication

    from core.main import MainWindow

    app = QApplication(sys.argv)

    main = MainWindow()
    main.show()

    sys.exit(app.exec_())

core/main.py, 以 main.ui 滑鼠右鍵 generate Dialog Code 產生

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

"""
Module implementing MainWindow.
"""

from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QMainWindow

from PyQt5.QtCore import QLineF
from PyQt5.QtWidgets import QFrame
from PyQt5.QtWidgets import QGraphicsScene,  QGraphicsView,  QGraphicsEllipseItem

from .Ui_main import Ui_MainWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    """
    Class documentation goes here.
    """
    def __init__(self, parent=None):
        """
        Constructor

        @param parent reference to the parent widget
        @type QWidget
        """
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)

    @pyqtSlot()
    def on_actionAbout_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        #raise NotImplementedError
        #建立景物
        scene = QGraphicsScene(-200, -200, 400, 400)
        # Create Ellipse Item
        item = QGraphicsEllipseItem(-150, -100, 300, 300)
        # Add item
        scene.addItem(item)
        # 納入繪圖物件
        scene.addText("終於可以!")
        scene.addLine(QLineF(0, 0, 200, 200))
        # set no frame to graphicsView
        self.graphicsView.setFrameShape(QFrame.NoFrame)
        # 在既有的 graphicsView 中設定景物
        # graphicsView in a layout and set layout to the grid to fit the size of window
        self.graphicsView.setScene(scene)

        # 顯示
        self.graphicsView.show()

    @pyqtSlot()
    def on_actionQuit_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        #raise NotImplementedError
        self.close()

core/Ui_main.py, 利用 main.ui 以 compile form 產生


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

# Form implementation generated from reading ui file 'Y:\tmp\pyqt5_vault\ex3\core\main.ui'
#
# Created by: PyQt5 UI code generator 5.8.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralWidget = QtWidgets.QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        self.graphicsView = QtWidgets.QGraphicsView(self.centralWidget)
        self.graphicsView.setGeometry(QtCore.QRect(-15, -29, 871, 581))
        self.graphicsView.setObjectName("graphicsView")
        MainWindow.setCentralWidget(self.centralWidget)
        self.menuBar = QtWidgets.QMenuBar(MainWindow)
        self.menuBar.setGeometry(QtCore.QRect(0, 0, 800, 22))
        self.menuBar.setObjectName("menuBar")
        self.menuFile = QtWidgets.QMenu(self.menuBar)
        self.menuFile.setObjectName("menuFile")
        MainWindow.setMenuBar(self.menuBar)
        self.actionAbout = QtWidgets.QAction(MainWindow)
        self.actionAbout.setObjectName("actionAbout")
        self.actionQuit = QtWidgets.QAction(MainWindow)
        self.actionQuit.setObjectName("actionQuit")
        self.menuFile.addAction(self.actionAbout)
        self.menuFile.addAction(self.actionQuit)
        self.menuBar.addAction(self.menuFile.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.menuFile.setTitle(_translate("MainWindow", "File"))
        self.actionAbout.setText(_translate("MainWindow", "About"))
        self.actionQuit.setText(_translate("MainWindow", "Quit"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

main.ui



 MainWindow
 
  
   
    0
    0
    800
    600
   
  
  
   MainWindow
  
  
   
    
     
      -15
      -29
      871
      581
     
    
   
  
  
   
    
     0
     0
     800
     22
    
   
   
    
     File
    
    
    
   
   
  
  
   
    About
   
  
  
   
    Quit
   
  
 
 
 

Binary Genetic Algorithm

#encoding=utf8
# genetic.py
#
import random
import operator
# for Intersect
from math import *
MAXIMIZE, MINIMIZE = 11, 22
class Individual:
    # 染色體先設為 None
    chromosome = None
    # 得分也先設為 None
    score = None
    # Here the size of var depends on var_number print
    # var 變數的元素個數取決於 var_number 的個數 (即變數個數)
    var = []
    # 表示適應值變數個數有兩個
    var_number = 2
    #先將 var 數列中元素都設為 0
    for i in range(var_number):
        var.append(0)
    # 等位基因表示各基因可選的內容, 這裡表示不是 0 就是 1
    alleles = (0,1)
    # 2**10 = 32*32 = 1024, 表示若用十個 binary 位數來表示整數, 可以表示從 0 到 1023 的數值大小
    # 若也用另外 十個 binary 位數來表示小數值, 則也是 0 到 1023 的數值表示能力, 
    # 而再加一個表示正負的代表 binary 位數, 每一個變數需要 21 個 binary numbers 
    # 以下為參數可負數時的編碼考量
    #前10為小數,後10為整數,第21則為正負號
    #0~9表示小數,10~19表示整數,而指標第20則表示第一數的正號或負號,若為0則表示正,若為1表示負號.
    #21~30表示第二數的小數部分,31~40則表示第二數的整數部分,第41指標則表示第二數的正號或負號
    #42~51表示第三數的小數部分,52~61則表示第二數的整數部分,第62指標則表示第三數的正號或負號
    # -1023 ~ 1023
    #length = 21*var_number,若接受負數參數,則必須同步修改 20->21
    # 因為這裡只接受正的變數值, 所以每一個變數需要 20 個 binary 位數
    length = 20*var_number
    seperator = ''
    optimization = MINIMIZE

    def __init__(self, chromosome=None):
        self.chromosome = chromosome or self._makechromosome()
        self.score = None  # set during evaluation

    '''
    bitwise operators (binary left shift): The left operands value is moved left by the number of bits specified by the right operand.
    x << y
    Returns x with the bits shifted to the left by y places (and new bits on the right-hand-side are zeros). This is the same as multiplying x by 2**y.
    '''
    # 根據染色體各位元的值轉為 10 進位值
    def _getvar(self, chromosome=None):
        # x 起始值設為 0
        x = 0
        for i in range(0, self.var_number):
            # 先根據前 20 個位元值, 透過 binary left shift 轉為 10 進位之後, 再轉為對應小數
            for j in range(i*20, i*20+10):
                x += self.chromosome[j]<<(j-(i*20))
            # 因為前 20 個 binary 數, 負責 10 進位數的小數點後 3 個位數, 只要轉為 10 進位值之後, 若大於 999, 則僅取 999,
            # 再除以 1000, 可以得到 .999 表示 .999 為最大的小數表示數, 不要因為大於 1000 後若除以 1000 將進位到整數, 會與整數有交互影響
            if (x>999):
                x = 999
            x /= 1000.
            # 整數部份 0 ~ 1023 的表示範圍則沒有問題, 利用 bitwise 轉換後, 直接取整數值
            for j in range(i*20+10, i*20+20):
                x += self.chromosome[j]<<(j-(i*20+10))
            self.var[i] = x
        return self.var

    ''' for -1023 ~ 1023,當設計變數可以接受負值時使用,每一變數使用21個 bit strings
    #for design variable -1023 ~1023
        for i in range(self.var_number):
            x = 0
            for j in range(i*21, i*21+10):
                x += self.chromosome[j]<<(j-(i*21))
            if (x>999):
                x = 999
            x /= 1000.
            for j in range(i*(21)+10, i*(21)+20):
                x += self.chromosome[j]<<(j-(i*21+10))
            # 各變數範圍第 21 位數若為 1, 則表示該數為負數
            if(self.chromosome[i*(21)+20] == 1):
                self.var[i] = -x
            else:
                self.var[i] = x
            # 讓 x 再設回原值 0 表示內定各變數為正數
            x = 0
        return self.var
    '''
    # 建立染色體
    def _makechromosome(self):
        "makes a chromosome from randomly selected alleles."
        return [random.choice(self.alleles) for gene in range(self.length)]

    # 計算適應值
    def evaluate(self, optimum=None):
        "this method MUST be overridden to evaluate individual fitness score."
        pass

    # 交配方法
    def crossover(self, other):
        "override this method to use your preferred crossover method."
        return self._twopoint(other)

    # 突變方法
    def mutate(self, gene):
        "override this method to use your preferred mutation method."
        self._pick(gene)

    # sample mutation method
    def _pick(self, gene):
        "chooses a random allele to replace this gene's allele."
        self.chromosome[gene] = random.choice(self.alleles)

    # sample crossover method
    def _twopoint(self, other):
        "creates offspring via two-point crossover between mates."
        left, right = self._pickpivots()

        def mate(p0, p1):
            chromosome = p0.chromosome[:] # 交配時,以p0的基因為基礎(複製整個 p0 的染色體內容
            chromosome[left:right] = p1.chromosome[left:right] # 接續上一個 p0 的染色體內容,將索引 left 至 right 的內容,替換成 p1 的基因
            child = p0.__class__(chromosome)
            child._repair(p0, p1)
            return child
        return mate(self, other), mate(other, self)

    # some crossover helpers ...
    def _repair(self, parent1, parent2):
        "override this method, if necessary, to fix duplicated genes."
        pass

    def _pickpivots(self):
        left = random.randrange(1, self.length-2)
        right = random.randrange(left, self.length-1)
        return left, right
    #
    # other methods
    #
    def __repr__(self):
        "returns string representation of self"
        '''
        return '<%s chromosome="%s" score=%s var=%s>' % \
               (self.__class__.__name__,
                self.seperator.join(map(str,self.chromosome)), self.score,self._getvar(self.chromosome))
        '''
        return '<%s score=%s var=%s>' % \
               (self.__class__.__name__,self.score,self._getvar(self.chromosome))
    # since the __cmp__ special function is gone  use the __lt__ in stead
    # use the expression (a > b) - (a < b) as the equivalent for cmp(a, b)
    #def __cmp__(self, other):
    # these are for python 3
    def __cmp__(self, other):
        if self.optimization == MINIMIZE:
            #return cmp(self.score, other.score)
            return (self.score > other.score) - (self.score < other.score)
        else: # MAXIMIZE
            #return cmp(other.score, self.score)
            return (other.score > self.score) - (other.score < self.score)

    def __lt__(self, other):
        return self.__cmp__(other) < 0
    def __le__(self, other):
        return self.__cmp__(other) <= 0
    def __gt__(self, other):
        return self.__cmp__(other) > 0
    def __ge__(self, other):
        return self.__cmp__(other) >= 0 
    def copy(self):
        twin = self.__class__(self.chromosome[:])
        twin.score = self.score
        return twin
class Environment(object):
    x = [0]
    y = [0]

    def __init__(self, kind, population=None, size=100, maxgenerations=100,
                 crossover_rate=0.90, mutation_rate=0.07, optimum=None):
        self.kind = kind
        self.size = size
        self.optimum = optimum
        self.population = population or self._makepopulation()
        for individual in self.population:
            individual.evaluate(self.optimum)
        self.crossover_rate = crossover_rate
        self.mutation_rate = mutation_rate
        self.maxgenerations = maxgenerations
        self.generation = 0
        self.report()

    def _makepopulation(self):
        return [self.kind() for individual in range(self.size)]

    def run(self):
        while not self._goal():
            self.step()

    def _goal(self):
        return self.generation > self.maxgenerations or \
               self.best.score == self.optimum

    def step(self):
        # this sort is not working with python 3.0, modification is needed
        self.population.sort()
        self._crossover()
        self.generation += 1
        self.report()
        self.x.append(self.generation)
        # 設定為只附加所選定範圍的值,這裡只取大於或等於 0 的 score 值
        if self.best.score <=5:
            self.y.append(self.best.score)
        else:
            self.y.append(5)

    def _crossover(self):
        next_population = [self.best.copy()]
        while len(next_population) < self.size:
            mate1 = self._select()
            if random.random() < self.crossover_rate:
                mate2 = self._select()
                offspring = mate1.crossover(mate2)
            else:
                offspring = [mate1.copy()]
            for individual in offspring:
                self._mutate(individual)
                individual.evaluate(self.optimum)
                next_population.append(individual)
        self.population = next_population[:self.size]

    def _select(self):
        "override this to use your preferred selection method"
        return self._tournament()

    def _mutate(self, individual):
        for gene in range(individual.length):
            if random.random() < self.mutation_rate:
                individual.mutate(gene)
    #
    # sample selection method
    #
    def _tournament(self, size=8, choosebest=0.90):
        competitors = [random.choice(self.population) for i in range(size)]
        competitors.sort()
        if random.random() < choosebest:
            return competitors[0]
        else:
            return random.choice(competitors[1:])

    def best():
        doc = "individual with best fitness score in population."
        def fget(self):
            return self.population[0]
        return locals()
    best = property(**best())

    def report(self):
        try:
            print ("="*70)
            print ("generation: ", self.generation)
            print ("best:       ", self.best)
        except:
            g.es ("="*70)
            g.es ("generation: ", self.generation)
            g.es ("best:       ", self.best)

# 以上為 genetic.py 目前將兩者結合在一起
#encoding=utf8
# volume.py - useage example
#
# the fittest individual will have a chromosome consisting of 40 '1's
#
#
#import genetic
class Volume(Individual):
    optimization = MAXIMIZE
    def evaluate(self, optimum=None):
        SURFACE = 80
        # self.score is the fitness value
        self._getvar(self.chromosome)

        x = self.var[0]
        y = self.var[1]
        z=(SURFACE - x*y)/(2.*(x+y))
        fitness_value = x*y*z

        self.score = fitness_value

    def mutate(self, gene):
        self.chromosome[gene] = not self.chromosome[gene] # bit flip

class Intersect(Individual):
    optimization = MINIMIZE
    def evaluate(self, optimum=None):
        # self.score is the fitness value
        self._getvar(self.chromosome)

        t = self.var[0]
        deg = pi/180
        theta = self.var[1]*deg
        xtarget = 0.75/2
        ytarget = 0.5
        x = t*sqrt(-225*sin(theta)**2 + 529)/10 - sqrt(-225*sin(theta)**2 + 529)/92 + 3*cos(theta)/2
        y = (-3*t/2 + 123/92)*sin(theta)
        # 適應值
        fitness_value = pow(x-xtarget, 8)+pow(y-ytarget, 8)

        # 指定 t 的範圍, 小於 1 大於 0, 否則給予處罰
        if t > 1:
            fitness_value += 1000
        if t < 0:
            fitness_value += 1000
        # 指定 theta 的範圍, 小於 2pi 大於 0, 否則給予處罰
        if theta > 2*pi:
            fitness_value += 1000
        if theta < 0:
            fitness_value += 1000


        self.score = fitness_value

    def mutate(self, gene):
        self.chromosome[gene] = not self.chromosome[gene] # bit flip


if __name__ == "__main__":
    env = Environment(Volume, size=500, maxgenerations=100)
    #env = Environment(Intersect, size=500, maxgenerations=100)
    env.run()

Deap 與 Scoop

Deap: https://github.com/DEAP/deap

Scoop: https://en.wikipedia.org/wiki/Python_SCOOP_(software)

https://groups.google.com/forum/#!topic/deap-users/v3wbky0EUf0

https://groups.google.com/forum/m/#!msg/deap-users/P4IkiE-Bvbg/xSoMDphbMR4J

平行運算

http://research.cs.wisc.edu/htcondor/

https://github.com/J-Robinson/GridGA

利用 Blender 製作

Essence of calculus

Essence of linear algebra