Quellcode durchsuchen

[research/lotterysim] reward pid

police vor 3 Jahren
Ursprung
Commit
e44d9f0d67

+ 96 - 0
script/research/lotterysim/RPID.py

@@ -0,0 +1,96 @@
+from utils import *
+
+REWARD_MIN = 0
+REWARD_MAX = 1000
+
+class RPID:
+    def __init__(self, kp=0, ki=0, kd=0, dt=1, target=15, Kc=0, Ti=0, Td=0, Ts=0, debug=False):
+        self.Kp = kp # discrete pid kp
+        self.Ki = ki # discrete pid ki
+        self.Kd = kd # discrete pid kd
+        self.T = dt # discrete pid frequency time.
+        self.Ti = Ti # takahashi ti
+        self.Td = Td # takahashi td
+        self.Ts = Ts # takahashi ts
+        self.Kc = Kc # takahashi kc
+        self.target = target # pid set point
+        self.prev_feedback = 0
+        self.feedback_hist = [0, 0]
+        self.f_hist = [0]
+        self.error_hist = [0, 0]
+        self.debug=debug
+
+    def discrete_pid(self, feedback, debug=True):
+        k1 = self.Kp + self.Ki + self.Kd
+        k2 = -1 * self.Kp - 2 * self.Kd
+        k3 = self.Kd
+        err = self.proportional(feedback)
+        ret = self.f_hist[-1] + k1 * err + k2 * self.error_hist[-1] + k3 * self.error_hist[-2]
+        self.error_hist+=[err]
+        self.feedback_hist+=[feedback]
+        return ret
+
+    def takahashi(self, feedback, debug=True):
+        err = self.proportional(feedback)
+        ret = self.f_hist[-1] + self.Kc * (self.feedback_hist[-1] - feedback + self.Ts * err/ self.Ti +  self.Td / self.Ts * (2*self.feedback_hist[-1] - feedback  - self.feedback_hist[-2]))
+        self.error_hist+=[err]
+        self.feedback_hist+=[feedback]
+        return ret
+
+    def pid_clipped(self, feedback, controller=CONTROLLER_TYPE_DISCRETE, debug=True):
+        pid_value = None
+        if controller == CONTROLLER_TYPE_TAKAHASHI:
+            pid_value = self.takahashi(feedback, debug)
+        elif controller == CONTROLLER_TYPE_DISCRETE:
+            pid_value = self.discrete_pid(feedback, debug)
+        else:
+            pid_value = self.pid(feedback)
+
+        if pid_value <= 0.0:
+            pid_value = REWARD_MIN
+        elif pid_value >= 1:
+            pid_value =  REWARD_MAX
+
+        self.f_hist+=[pid_value]
+        return pid_value
+
+    def error(self, feedback):
+        return feedback - self.target
+
+    def proportional(self,  feedback):
+        return self.error(feedback)
+
+    def integral(self, feedback):
+        return sum(self.feedback_hist[-10:]) + feedback
+
+    def derivative(self, feedback):
+        return (self.error(self.prev_feedback) - self.error(feedback)) / self.T
+
+    def write_feedback(self, lead_hist_file):
+        if len(self.feedback_hist)==0:
+            return
+        buf = ''
+        buf+=str(self.feedback_hist[0])
+        buf+=','
+        for i in self.feedback_hist[1:]:
+            buf+=str(i)+','
+        with open(lead_hist_file, "w+") as f:
+            f.write(buf)
+
+    def write_fval(self, f_hist_file):
+        if len(self.f_hist)==0:
+            return
+        buf = ''
+        buf+=str(self.f_hist[0])
+        buf+=','
+        for i in self.f_hist[1:]:
+            buf+=str(i)+','
+        with open(f_hist_file, "w+") as f:
+            f.write(buf)
+
+    def write(self, lead_hist_file='leads.hist', f_hist_file='f.hist'):
+        self.write_feedback(lead_hist_file)
+        self.write_fval(f_hist_file)
+
+    def acc(self):
+        return sum(np.array(self.feedback_hist)==1)/float(len(self.feedback_hist))

+ 1 - 0
script/research/lotterysim/constants.py

@@ -11,6 +11,7 @@ REWARD = 1000
 F_MIN = 0.0001
 F_MIN = 0.0001
 F_MAX = 0.9999
 F_MAX = 0.9999
 EPSILON = 1
 EPSILON = 1
+EPOCH_LENGTH = 10
 
 
 L_HP = Num(L)
 L_HP = Num(L)
 REWARD_HP = Num(REWARD)
 REWARD_HP = Num(REWARD)

+ 6 - 6
script/research/lotterysim/darkie.py

@@ -29,8 +29,8 @@ class Darkie(Thread):
         # note! relation is logarithmic depending on PID output.
         # note! relation is logarithmic depending on PID output.
         if window<len(self.initial_stake):
         if window<len(self.initial_stake):
             windowed_initial_stake = self.initial_stake[-window]
             windowed_initial_stake = self.initial_stake[-window]
-            return Num(self.stake - windowed_initial_stake) / Num(windowed_initial_stake)
-        return Num(self.stake - self.initial_stake[0]) / Num(self.initial_stake[0])
+            return Num(self.stake - windowed_initial_stake) / Num(windowed_initial_stake) if self.stake>0 else Num(0)
+        return Num(self.stake - self.initial_stake[0]) / Num(self.initial_stake[0]) if self.stake>0 else Num(0)
 
 
     def apy_percentage(self):
     def apy_percentage(self):
         return self.apy()*100
         return self.apy()*100
@@ -50,8 +50,8 @@ class Darkie(Thread):
             sigmas = [   c/((self.Sigma+EPSILON)**i) * ( ((L_HP if hp else L)/fact(i)) ) for i in range(1, k+1) ]
             sigmas = [   c/((self.Sigma+EPSILON)**i) * ( ((L_HP if hp else L)/fact(i)) ) for i in range(1, k+1) ]
             scaled_target = approx_target_in_zk(sigmas, Num(stake)) #+ (BASE_L_HP if hp else BASE_L)
             scaled_target = approx_target_in_zk(sigmas, Num(stake)) #+ (BASE_L_HP if hp else BASE_L)
             return scaled_target
             return scaled_target
-        if self.slot>0:
-            self.strategy.set_ratio(self.slot, self.apy())
+
+        self.strategy.set_ratio(self.slot, self.apy())
         T = target(self.f, self.strategy.staked_value(self.finalized_stake))
         T = target(self.f, self.strategy.staked_value(self.finalized_stake))
         self.won = lottery(T, hp)
         self.won = lottery(T, hp)
 
 
@@ -66,9 +66,9 @@ class Darkie(Thread):
         self.stake+= vesting_value
         self.stake+= vesting_value
         return vesting_value
         return vesting_value
 
 
-    def update_stake(self):
+    def update_stake(self, reward):
         if self.won:
         if self.won:
-            self.stake+=REWARD
+            self.stake+=reward
 
 
     def finalize_stake(self):
     def finalize_stake(self):
         if self.won:
         if self.won:

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 1
script/research/lotterysim/f.hist


+ 4 - 2
script/research/lotterysim/instance.py

@@ -1,6 +1,8 @@
 from lottery import *
 from lottery import *
 import os
 import os
 import numpy
 import numpy
+from strategy import LinearStrategy
+
 os.system("rm f.hist; rm leads.hist")
 os.system("rm f.hist; rm leads.hist")
 
 
 RUNNING_TIME = int(input("running time:"))
 RUNNING_TIME = int(input("running time:"))
@@ -10,8 +12,8 @@ NODES=1000
 if __name__ == "__main__":
 if __name__ == "__main__":
     darkies = []
     darkies = []
     egalitarian = ERC20DRK/NODES
     egalitarian = ERC20DRK/NODES
-    darkies += [ Darkie(random.gauss(egalitarian, egalitarian*0.1)) for id in range(int(NODES)) ]
-    #darkies += [Darkie(0) for _ in range(NODES)]
+    darkies += [ Darkie(random.gauss(egalitarian, egalitarian*0.1), strategy=LinearStrategy(EPOCH_LENGTH)) for id in range(int(NODES)) ]
+    darkies += [Darkie(0, strategy=LinearStrategy(EPOCH_LENGTH)) for _ in range(NODES)]
     airdrop = ERC20DRK
     airdrop = ERC20DRK
     effective_airdrop  = 0
     effective_airdrop  = 0
     for darkie in darkies:
     for darkie in darkies:

+ 1 - 1
script/research/lotterysim/leads.hist

@@ -1 +1 @@
-0,0,0,2,4,3,0,0,2,3,1,1,0,0,1,1,1,0,1,2,0,1,2,2,0,0,2,0,2,0,0,3,3,2,0,1,1,1,0,0,1,1,3,0,0,1,0,2,1,1,0,1,2,0,1,2,1,0,0,1,1,2,0,2,0,0,1,0,1,2,0,2,3,1,0,4,0,2,2,1,0,1,1,2,1,2,0,0,1,0,1,1,0,2,1,1,0,4,0,0,1,1,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

+ 6 - 2
script/research/lotterysim/lottery.py

@@ -4,9 +4,10 @@ from darkie import *
 import time
 import time
 from datetime import timedelta
 from datetime import timedelta
 from pid import PID
 from pid import PID
+from RPID import RPID
 
 
 class DarkfiTable:
 class DarkfiTable:
-    def __init__(self, airdrop, running_time, controller_type=CONTROLLER_TYPE_DISCRETE, kp=0, ki=0, kd=0, dt=1, target=1, kc=0, ti=0, td=0, ts=0, debug=False):
+    def __init__(self, airdrop, running_time, controller_type=CONTROLLER_TYPE_DISCRETE, kp=0, ki=0, kd=0, dt=1, target=1, reward_target=15, kc=0, ti=0, td=0, ts=0, debug=False):
         self.Sigma=airdrop
         self.Sigma=airdrop
         self.darkies = []
         self.darkies = []
         self.running_time=running_time
         self.running_time=running_time
@@ -14,6 +15,7 @@ class DarkfiTable:
         self.end_time=None
         self.end_time=None
         self.pid = None
         self.pid = None
         self.pid = PID(kp=kp, ki=ki, kd=kd, dt=dt, target=target, Kc=kc, Ti=ti, Td=td, Ts=ts)
         self.pid = PID(kp=kp, ki=ki, kd=kd, dt=dt, target=target, Kc=kc, Ti=ti, Td=td, Ts=ts)
+        self.rpid = RPID(kp=3, ki=2, kd=-1, target=reward_target)
         self.controller_type=controller_type
         self.controller_type=controller_type
         self.debug=debug
         self.debug=debug
 
 
@@ -42,7 +44,9 @@ class DarkfiTable:
                 total_vesting_stake+=self.darkies[i].update_vesting()
                 total_vesting_stake+=self.darkies[i].update_vesting()
             for i in range(len(self.darkies)):
             for i in range(len(self.darkies)):
                 winners += self.darkies[i].won
                 winners += self.darkies[i].won
-                self.darkies[i].update_stake()
+                apy = self.darkies[i].apy()
+                reward = self.rpid.pid_clipped(apy, self.controller_type, debug)
+                self.darkies[i].update_stake(reward)
             feedback = winners
             feedback = winners
             if winners==1:
             if winners==1:
                 if count >= ERC20DRK:
                 if count >= ERC20DRK:

+ 5 - 3
script/research/lotterysim/strategy.py

@@ -1,13 +1,15 @@
+from utils import *
+
 class Strategy(object):
 class Strategy(object):
     def __init__(self, epoch_len=0):
     def __init__(self, epoch_len=0):
         self.epoch_len = epoch_len
         self.epoch_len = epoch_len
-        self.staked_tokens_ratio = 1
+        self.staked_tokens_ratio = Num(1)
 
 
     def set_ratio(self, slot=0, apy=0):
     def set_ratio(self, slot=0, apy=0):
         pass
         pass
 
 
     def staked_value(self, stake):
     def staked_value(self, stake):
-        return self.staked_tokens_ratio*stake
+        return self.staked_tokens_ratio*Num(stake)
 
 
 class RandomStrategy(Strategy):
 class RandomStrategy(Strategy):
     def __init__(self, epoch_len):
     def __init__(self, epoch_len):
@@ -29,4 +31,4 @@ class LinearStrategy(Strategy):
 
 
     def set_ratio(self, slot, apy):
     def set_ratio(self, slot, apy):
         if slot%self.epoch_len==0:
         if slot%self.epoch_len==0:
-            self.staked_tokens_ratio = apy/self.TARGET_APY
+            self.staked_tokens_ratio = apy/Num(self.TARGET_APY)

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.