量化編程技術—數學最優解

from abc import ABCMeta, abstractmethod
import six
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 每一個人平均壽命指望是75年,約75*365=27375天
K_INIT_LIVING_DAYS = 27375

class Person(object):
    """
        人類
    """

    def __init__(self):
        # 初始化人平均能活的壽命
        self.living = K_INIT_LIVING_DAYS
        # 初始化幸福指數
        self.happiness = 0
        # 初始化財富值
        self.wealth = 0
        # 初始化名望權利
        self.fame = 0
        # 活着的第幾天
        self.living_day = 0

    def live_one_day(self, seek):
        """
        天天只能進行一個seek,這個seek決定了你今天追求的是什麼,獲得了什麼
        seek的類型屬於下面將編寫的BaseSeekDay
        :param seek:
        :return:
        """
        # 調用每一個獨特的BaseSeekDay類都會實現的do_seek_day,獲得今天的收穫
        consume_living, happiness, wealth, fame = seek.do_seek_day()
        # 天天要減去生命消耗,有些seek前面還會增長生命
        self.living -= consume_living
        # seek獲得的幸福指數積累
        self.happiness += happiness
        # seek獲得的財富積累
        self.wealth += wealth
        # seek獲得的名望權力積累
        self.fame += fame
        # 活完這一天了
        self.living_day += 1


class BaseSeekDay(six.with_metaclass(ABCMeta, object)):
    def __init__(self):
        # 每一個追求天天消耗生命的常數
        self.living_consume = 0

        # 每一個追求天天幸福指數常數
        self.happiness_base = 0

        # 每一個追求天天財富積累常數
        self.wealth_base = 0
        # 每一個追求天天名望權利積累常數
        self.fame_base = 0

        # 每一個追求天天消耗生命的可變因素序列
        self.living_factor = [0]

        # 每一個追求天天幸福指數的可變因素序列
        self.happiness_factor = [0]

        # 每一個追求天天財富積累的可變因素序列
        self.wealth_factor = [0]
        # 每一個追求天天名望權利的可變因素序列
        self.fame_factor = [0]

        # 追求了多少天了這一輩子
        self.do_seek_day_cnt = 0
        # 子類進行常數及可變因素序列設置
        self._init_self()

    @abstractmethod
    def _init_self(self, *args, **kwargs):
        # 子類必須實現,設置本身的生命消耗的常數,幸福指數常數等常數設置
        pass

    @abstractmethod
    def _gen_living_days(self, *args, **kwargs):
        # 子類必須實現,設置本身的可變因素序列
        pass

    def do_seek_day(self):
        """
        每一天的追求具體seek
        :return:
        """
        # 生命消耗=living_consume:消耗常數 * happiness_factor:可變序列
        if self.do_seek_day_cnt >= len(self.living_factor):
            # 超出len(self.living_factor), 就取最後一個living_factor[-1]
            consume_living = \
                self.living_factor[-1] * self.living_consume
        else:
            # 每一個類自定義這個追求的消耗生命常數,以及living_factor,好比
            # HealthSeekDay追求健康,living_factor序列的值即由負值->正值
            # 每一個子類living_factor會有本身特色的變化速度及序列長度,致使每一個
            # 追求對生命的消耗隨着追求的次數變化不一
            consume_living = self.living_factor[self.do_seek_day_cnt] \
                             * self.living_consume
        # 幸福指數=happiness_base:幸福常數 * happiness_factor:可變序列
        if self.do_seek_day_cnt >= len(self.happiness_factor):
            # 超出len(self.happiness_factor), 就取最後一個
            # 因爲happiness_factor值由:n—>0 因此happiness_factor[-1]=0
            # 即隨着追求一個事物的次數過多後會變的沒有幸福感
            happiness = self.happiness_factor[
                            -1] * self.happiness_base
        else:
            # 每一個類自定義這個追求的幸福指數常數,以及happiness_factor
            # happiness_factor子類的定義通常是從高->低變化
            happiness = self.happiness_factor[
                            self.do_seek_day_cnt] * self.happiness_base
        # 財富積累=wealth_base:積累常數 * wealth_factor:可變序列
        if self.do_seek_day_cnt >= len(self.wealth_factor):
            # 超出len(self.wealth_factor), 就取最後一個
            wealth = self.wealth_factor[-1] * self.wealth_base
        else:
            # 每一個類自定義這個追求的財富指數常數,以及wealth_factor
            wealth = self.wealth_factor[
                         self.do_seek_day_cnt] * self.wealth_base
        # 權利積累=fame_base:積累常數 * fame_factor:可變序列
        if self.do_seek_day_cnt >= len(self.fame_factor):
            # 超出len(self.fame_factor), 就取最後一個
            fame = self.fame_factor[-1] * self.fame_base
        else:
            # 每一個類自定義這個追求的名望權利指數常數,以及fame_factor
            fame = self.fame_factor[
                       self.do_seek_day_cnt] * self.fame_base
        # 追求了多少天了這一輩子 + 1
        self.do_seek_day_cnt += 1
        # 返回這個追求這一天對生命的消耗,獲得的幸福,財富,名望權利
        return consume_living, happiness, wealth, fame
        
        
def regular_mm(group):
    # 最小-最大規範化
    return (group - group.min()) / (group.max() - group.min())


class HealthSeekDay(BaseSeekDay):
    """
        HealthSeekDay追求健康長壽的一天:
        形象:健身,旅遊,娛樂,作感興趣的事情。
        抽象:追求健康長壽。
    """

    def _init_self(self):
        # 天天對生命消耗的常數=1,即表明1天
        self.living_consume = 1
        # 天天幸福指數常數=1
        self.happiness_base = 1
        # 設定可變因素序列
        self._gen_living_days()

    def _gen_living_days(self):
        # 只生成12000個序列,由於下面的happiness_factor序列值由1->0
        # 因此大於12000次的追求都將只是單純消耗生命,並不增長幸福指數
        # 即隨着作一件事情的次數愈來愈多,幸福感愈來愈低,直到徹底體會不到幸福
        days = np.arange(1, 12000)
        # 基礎函數選用sqrt, 影響序列變化速度
        living_days = np.sqrt(days)

        """
            對生命消耗可變因素序列值由-1->1, 也就是這個追求一開始的時候對生命
            的消耗爲負增加,延長了生命,隨着追求的次數不斷增多對生命的消耗轉爲正
            數由於即便一我的每天鍛鍊身體,每天吃養分品,也仍是會有天然死亡的那
            一天
        """
        # *2-1的目的:regular_mm在0-1之間,HealthSeekDay要結果在-1,1之間
        self.living_factor = regular_mm(living_days) * 2 - 1
        # 結果在1-0之間 [::-1]: 將0->1轉換到1->0
        self.happiness_factor = regular_mm(days)[::-1]
        
        
# 初始化我, 你一輩子的故事:HealthSeekDay
me = Person()
# 初始化追求健康長壽快樂
seek_health = HealthSeekDay()
while me.living > 0:
    # 只要還活着,就追求健康長壽快樂
    me.live_one_day(seek_health)

print('只追求健康長壽快樂活了{}年,幸福指數{},積累財富{},名望權力{}'.format
      (round(me.living_day / 365, 2), round(me.happiness, 2),
       me.wealth, me.fame))
       
       
plt.plot(seek_health.living_factor * seek_health.living_consume)
plt.plot(seek_health.happiness_factor * seek_health.happiness_base)
plt.legend(['living_factor', 'happiness_factor'], loc='best')
相關文章
相關標籤/搜索