Пример #1
0
class LaCReME(page_replacement_algorithm):
    def __init__(self, N):
        self.N = N
        self.CacheRecency = Disk(N)
        self.CacheFrequecy = priorityqueue(N)
        self.Hist1 = Disk(N)
        self.Hist2 = priorityqueue(N)

        ## Config variables
        self.decayRate = 1
        self.epsilon = 0.05
        self.lamb = 0.05
        self.learning_phase = N / 2
        #         self.error_discount_rate = (0.005)**(1.0/N) ## TODO ADD BACK
        self.error_discount_rate = 1

        ##
        self.learning = True
        self.policy = 0
        self.evictionTime = {}
        self.policyUsed = {}
        self.weightsUsed = {}
        self.freq = {}

        ## TODO add decay_time and decay_factor
        self.decay_time = N
        self.decay_factor = 1

        ## Accounting variables
        self.time = 0

        self.W = np.array([.5, .5], dtype=np.float32)

        self.X = np.array([], dtype=np.int32)
        self.Y1 = np.array([])
        self.Y2 = np.array([])

    def get_N(self):
        return self.N

    def visualize(self, plt):
        #         print(np.min(self.X), np.max(self.X))
        ax = plt.subplot(2, 1, 1)
        ax.set_xlim(np.min(self.X), np.max(self.X))
        l1, = plt.plot(self.X, self.Y1, 'b-', label='W_lru')
        l2, = plt.plot(self.X, self.Y2, 'r-', label='W_lfu')
        return [l1, l2]

    ##########################################
    ## Add a page to cache using policy 'poly'
    ##########################################
    def addToCache(self, page, pagefreq=0):
        self.CacheRecency.add(page)
        self.CacheFrequecy.add(page)
        self.CacheRecency.increaseCount(page, amount=pagefreq)
        self.CacheFrequecy.increase(page, amount=pagefreq)

    ######################
    ## Get LFU or LFU page
    ######################
    def selectEvictPage(self, policy):
        r = self.CacheRecency.getIthPage(0)
        f = self.CacheFrequecy.peaktop()
        pageToEvit, policyUsed = None, None
        if r == f:
            pageToEvit, policyUsed = r, -1
        elif policy == 0:
            pageToEvit, policyUsed = r, 0
        elif policy == 1:
            pageToEvit, policyUsed = f, 1
        return pageToEvit, policyUsed

    def evictPage(self, pg):
        self.CacheRecency.delete(pg)
        self.CacheFrequecy.delete(pg)

    ##############################################################
    ## There was a page hit to 'page'. Update the data structures
    ##############################################################
    def pageHitUpdate(self, page):
        if page in self.CacheRecency and page in self.CacheFrequecy:
            self.CacheRecency.moveBack(page)
            self.CacheRecency.increaseCount(page)
            self.CacheFrequecy.increase(page)

    #########################
    ## Get the Q distribution
    #########################
    def getQ(self):
        return (1 - self.lamb) * self.W + self.lamb * np.ones(2) / 2

    ############################################
    ## Choose a page based on the q distribution
    ############################################
    def chooseRandom(self):
        q = self.getQ()
        r = np.random.rand()
        for i, p in enumerate(q):
            if r < p:
                return i
        return len(q) - 1

    def updateWeight(self, cost):
        self.W = self.W * (1 - self.epsilon * cost)
        self.W = self.W / np.sum(self.W)

    ########################################################################################################################################
    ####REQUEST#############################################################################################################################
    ########################################################################################################################################
    def request(self, page):
        page_fault = False
        self.time = self.time + 1
        #         if self.time % self.learning_phase == 0 :
        #             self.learning = not self.learning

        #####################
        ## Visualization data
        #####################
        prob = self.getQ()
        self.X = np.append(self.X, self.time)
        self.Y1 = np.append(self.Y1, prob[0])
        self.Y2 = np.append(self.Y2, prob[1])

        if self.time % self.N == 0:
            self.CacheFrequecy.decay(self.decay_factor)
            self.Hist2.decay(self.decay_factor)

        ##########################
        ## Process page request
        ##########################
        if page in self.CacheFrequecy:
            page_fault = False
            self.pageHitUpdate(page)
        else:

            #####################################################
            ## Learning step: If there is a page fault in history
            #####################################################
            pageevict, histpage_freq = None, 1
            policyUsed = -1
            if page in self.Hist1:
                pageevict = page
                histpage_freq = self.Hist1.getCount(page)
                self.Hist1.delete(page)
                policyUsed = 0
                self.W[0] = self.W[0] * (
                    1 -
                    self.epsilon) if self.policyUsed[page] != -1 else self.W[0]
            elif page in self.Hist2:
                pageevict = page
                histpage_freq = self.Hist2.getCount(
                    page)  ## Get the page frequency in history
                self.Hist2.delete(page)
                policyUsed = 1
                self.W[1] = self.W[1] * (
                    1 -
                    self.epsilon) if self.policyUsed[page] != -1 else self.W[1]
            self.W = self.W / np.sum(self.W)
            #             if pageevict is not None :
            #                 q = self.weightsUsed[pageevict]
            # #                 err = self.error_discount_rate ** (self.time - self.evictionTime[pageevict])
            #                 err = 1
            #                 reward = np.array([0,0], dtype=np.float32)
            #                 if policyUsed == 0 : # LRU
            #                     reward[0] = err
            #                 if policyUsed == 1:
            #                     reward[1] = err
            #                 reward_hat = reward

            #################
            ## Update Weights
            #################
            #                 if self.policyUsed[pageevict] != -1 :
            # #                     self.W = self.W * np.exp(self.lamb * reward_hat / 2)
            #                     self.W = self.W * (1 - reward*self.epsilon)
            #                     self.W = self.W / np.sum(self.W)

            ####################
            ## Remove from Cache
            ####################
            if self.CacheRecency.size() == self.N:

                ################
                ## Choose Policy
                ################
                #                 if  not self.learning :
                #                     act = np.argmax(self.getQ())
                #                 else :
                #                 act = self.chooseRandom()

                act = np.argmax(self.W)  ## REMOVE

                cacheevict, poly = self.selectEvictPage(act)
                pagefreq = self.CacheFrequecy.getCount(cacheevict)

                self.policyUsed[cacheevict] = poly
                self.weightsUsed[cacheevict] = self.getQ()
                self.evictionTime[cacheevict] = self.time

                ## TODO ADD BACK
                #                 if not self.learning :
                #                     self.policyUsed[cacheevict] = -1

                ###################
                ## Evict to history
                ###################
                histevict = None
                if (poly == 0) or (poly == -1 and np.random.rand() < 0.5):
                    if self.Hist1.size() == self.N:
                        histevict = self.Hist1.getIthPage(0)
                        self.Hist1.delete(histevict)
                    self.Hist1.add(cacheevict)
                    self.Hist1.setCount(cacheevict, pagefreq)
                else:
                    if self.Hist2.size() == self.N:
                        histevict = self.Hist2.popmin()
                    self.Hist2.add(cacheevict)
                    self.Hist2.increase(cacheevict, pagefreq - 1)

                if histevict is not None:
                    del self.evictionTime[histevict]
                    del self.policyUsed[histevict]
                    del self.weightsUsed[histevict]

                self.evictPage(cacheevict)

            self.addToCache(page, pagefreq=histpage_freq)

            page_fault = True

        return page_fault

    def get_list_labels(self):
        return ['L']
Пример #2
0
class BANDIT_DOUBLE_HIST(page_replacement_algorithm):
    def __init__(self, N):
        self.N = N
        self.Cache = Disk(N)
        self.Hist1 = Disk(N)
        self.Hist2 = Disk(N)

        ## Config variables
        self.decayRate = 0.99
        self.epsilon = 0.95
        self.lamb = 0.05
        self.learning_phase = N / 2
        self.error_discount_rate = (0.005)**(1.0 / N)
        ##
        self.learning = True
        self.policy = 0
        self.accessedTime = {}
        self.frequency = {}
        self.evictionTime = {}
        self.policyUsed = {}
        self.weightsUsed = {}
        ## Accounting variables
        self.time = 0

        self.W = np.array([.5, .5], dtype=np.float32)

        self.X = np.array([])
        self.Y1 = np.array([])
        self.Y2 = np.array([])

    def get_N(self):
        return self.N

    def visualize(self, plt):
        print('visualize')
        l1, = plt.plot(self.X, self.Y1, 'b-', label='W_lru')
        l2, = plt.plot(self.X, self.Y2, 'r-', label='W_lfu')
        plt.xlabel('time')
        plt.ylabel('Weight')
        plt.legend(handles=[l1, l2])
#         plt.show()

#         print('W = ', self.W)

    def __keyWithMinVal(self, d):
        v = list(d.values())
        k = list(d.keys())
        return k[v.index(min(v))]

    def getMinValueFromCache(self, values):
        minpage, first = -1, True
        for q in self.Cache:
            if first or values[q] < values[minpage]:
                minpage, first = q, False
        return minpage

    def selectEvictPage(self, policy):
        r = self.getMinValueFromCache(self.accessedTime)
        f = self.getMinValueFromCache(self.frequency)

        #         if r == f :
        #             return r,-1
        if policy == 0:
            return r, 0
        return f, 1

    def countUniquePagesSince(self, t):
        cnt = 0
        for p in self.Cache:
            if self.accessedTime[p] > t:
                cnt += 1
        for p in self.Hist1:
            if self.accessedTime[p] > t:
                cnt += 1
        for p in self.Hist2:
            if self.accessedTime[p] > t:
                cnt += 1

        return cnt

    def getQ(self):
        return (1 - self.lamb) * self.W + self.lamb * np.ones(2) / 2
#         return self.W

    def chooseRandom(self):
        q = self.getQ()

        r = np.random.rand()

        #         if self.time < 10000 + 1751 and self.time > 1751:
        #             print('r = ', r, 'q = ', q)

        for i, p in enumerate(q):
            if r < p:
                return i
        return len(q) - 1

    def updateWeight(self, cost):
        self.W = self.W * (1 - self.epsilon * cost)
        self.W = self.W / np.sum(self.W)

    ########################################################################################################################################
    ####REQUEST#############################################################################################################################
    ########################################################################################################################################
    def request(self, page):
        page_fault = False
        self.time = self.time + 1
        ############################
        ## Save data for training ##
        ############################

        if self.time % self.learning_phase == 0:
            self.learning = not self.learning

        ## Visualization data
        prob = self.getQ()
        self.X = np.append(self.X, self.time)
        self.Y1 = np.append(self.Y1, prob[0])
        self.Y2 = np.append(self.Y2, prob[1])

        #########################
        ## Process page reques ##
        #########################
        if page in self.Cache:
            page_fault = False
        else:

            pageevict = None
            policyUsed = -1
            if page in self.Hist1:
                pageevict = page
                self.Hist1.delete(page)
                policyUsed = 0
            elif page in self.Hist2:
                pageevict = page
                self.Hist2.delete(page)
                policyUsed = 1

            if pageevict is not None:
                q = self.weightsUsed[pageevict]

                err = self.error_discount_rate**(self.time -
                                                 self.evictionTime[pageevict])
                reward = np.array([0, 0], dtype=np.float32)
                if policyUsed == 0:
                    reward[1] = err
                if policyUsed == 1:
                    reward[0] = err

                reward_hat = reward / q

                #                 print('self.policyUsed[%d] = %d' % (pageevict,self.policyUsed[pageevict] ))
                ## Update Weights
                if self.policyUsed[pageevict] != -1:
                    #                     print('Updating weights')
                    self.W = self.W * np.exp(self.lamb * reward_hat / 2)
                    self.W = self.W / np.sum(self.W)

            ## Remove from Cache
            if self.Cache.size() == self.N:
                if not self.learning:
                    act = np.argmax(self.getQ())
                else:
                    act = self.chooseRandom()

#                 act = self.chooseRandom()

                cacheevict, poly = self.selectEvictPage(act)
                self.policyUsed[cacheevict] = poly

                #                 if self.time < 10000 + 1751 and self.time > 1751:
                #                     if act == 1 :
                #                         print('LFU')

                if not self.learning:
                    self.policyUsed[cacheevict] = -1

                self.Cache.delete(cacheevict)

                self.weightsUsed[cacheevict] = self.getQ()
                self.evictionTime[cacheevict] = self.time

                histevict = -1
                if act == 0:
                    if self.Hist1.size() == self.N:
                        histevict = self.Hist1.getIthPage(0)
                        self.Hist1.delete(histevict)
                    self.Hist1.add(cacheevict)
#                     print('Adding %d to hist1' % cacheevict)
                if act == 1:
                    if self.Hist2.size() == self.N:
                        histevict = self.Hist2.getIthPage(0)
                        self.Hist2.delete(histevict)
                    self.Hist2.add(cacheevict)
#                     print('Adding %d to hist2' % cacheevict)

                if histevict != -1:
                    del self.evictionTime[histevict]
                    del self.accessedTime[histevict]
                    del self.frequency[histevict]
                    del self.policyUsed[histevict]
                    del self.weightsUsed[histevict]
#                 print('act = ', act)
#                 self.Hist.add(evictPage)

            if page not in self.frequency:
                self.frequency[page] = 0
            self.Cache.add(page)
            page_fault = True

        for q in self.Cache:
            self.frequency[q] *= self.decayRate
        self.frequency[page] += 1
        self.accessedTime[page] = self.time

        return page_fault

    def get_list_labels(self):
        return ['L']
Пример #3
0
class ARCOPT(page_replacement_algorithm):
    def __init__(self, N, traces):
        self.T = []
        self.N = N
        self.T1 = Disk(N)
        self.T2 = Disk(N)
        self.B1 = Disk(N)
        self.B2 = Disk(2 * N)
        self.P = 0

        self.page_request_time = {}

        ##
        for i, p in enumerate(traces):
            if p not in self.page_request_time:
                self.page_request_time[p] = Queue.Queue()
            self.page_request_time[p].put(i)

    def get_N(self):
        return self.N

    def request(self, page):

        x = self.page_request_time[page].get()

        #print self.T1.size(), self.T2.size()
        page_fault = False
        #if inList(self.T, page):
        if self.T1.inDisk(page) or self.T2.inDisk(page):
            #self.T = moveToMRU(self.T,page)
            if page in self.T1:
                self.T1.delete(page)
            if page in self.T2:
                self.T2.delete(page)

            if not self.T2.add(page):
                print('failed adding at Case 1')

        elif self.B1.inDisk(page):
            self.__replace(page)
            self.B1.delete(page)
            if not self.T2.add(page):
                print('failed adding at B1')

            page_fault = True
        elif self.B2.inDisk(page):
            self.__replace(page)
            self.B2.delete(page)
            if not self.T2.add(page):
                print('failed adding at B2')
            page_fault = True
        else:
            t1 = self.T1.size()
            t2 = self.T2.size()
            b1 = self.B1.size()
            b2 = self.B2.size()

            if t1 + b1 == self.N:
                if t1 < self.N:
                    self.B1.deleteFront()
                    self.__replace(page)
                else:
                    self.T1.deleteFront()
            elif t1 + b1 < self.N:
                if t1 + t2 + b1 + b2 >= self.N:
                    if t1 + t2 + b1 + b2 == 2 * self.N:
                        self.B2.deleteFront()
                    self.__replace(page)

            # Add page to the MRU position in T1
            # self.T.append(page)
            if not self.T1.add(page):
                print('failed adding at case 4')
            page_fault = True

        return page_fault

    def __replace(self, x):

        if self.T1.size() == 0:
            y = self.T2.deleteFront()
            if not y == None:
                self.B2.add(y)
        elif self.T2.size() == 0:
            y = self.T1.deleteFront()
            if not y == None:
                self.B1.add(y)
        else:

            t1_page = self.T1.getIthPage(0)
            t2_page = self.T2.getIthPage(0)

            if not self.page_request_time[t1_page].empty():
                page1_time = self.page_request_time[t1_page].queue[0]
            else:
                page1_time = int(1e15)

            if not self.page_request_time[t2_page].empty():
                page2_time = self.page_request_time[t2_page].queue[0]
            else:
                page2_time = int(1e15)

            if page1_time > page2_time:
                y = self.T2.deleteFront()
                if not y == None:
                    self.B2.add(y)
            else:
                y = self.T1.deleteFront()
                if not y == None:
                    self.B1.add(y)

    def get_data(self):
        return [
            self.T1.get_data(),
            self.T2.get_data(),
            self.B1.get_data(),
            self.B2.get_data()
        ]

    def get_list_labels(self):
        return ['T1', 'T2', 'B1', 'B2']
Пример #4
0
class BANDIT(page_replacement_algorithm):
    def __init__(self, N):
        self.N = N
        self.Cache = Disk(N)
        self.Hist = Disk(N)

        ## Config variables
        self.decayRate = 0.99
        self.epsilon = 0.99
        self.lamb = 0.05

        ##
        self.accessedTime = {}
        self.frequency = {}
        self.evictionTime = {}
        self.policyUsed = {}
        self.weightsUsed = {}
        ## Accounting variables
        self.time = 0

        self.W = np.array([.5, .5], dtype=np.float32)

        self.X = np.array([])
        self.Y1 = np.array([])
        self.Y2 = np.array([])

    def get_N(self):
        return self.N

    def visualize(self):
        l1, = plt.plot(self.X, self.Y1, 'b-', label='W0')
        l2, = plt.plot(self.X, self.Y2, 'r-', label='W1')
        plt.xlabel('time')
        plt.ylabel('W')
        plt.legend(handles=[l1, l2])
        plt.show()

#         print('W = ', self.W)

    def __keyWithMinVal(self, d):
        v = list(d.values())
        k = list(d.keys())
        return k[v.index(min(v))]

    def getMinValueFromCache(self, values):
        minpage, first = -1, True
        for q in self.Cache:
            if first or values[q] < values[minpage]:
                minpage, first = q, False
        return minpage

    def selectEvictPage(self, policy):
        r = self.getMinValueFromCache(self.accessedTime)
        f = self.getMinValueFromCache(self.frequency)

        if r == f:
            return r, -1
        if policy == 0:
            return r, 0
        return f, 1

    def countUniquePagesSince(self, t):
        cnt = 0
        for p in self.Cache:
            if self.accessedTime[p] > t:
                cnt += 1
        for p in self.Hist:
            if self.accessedTime[p] > t:
                cnt += 1
        return cnt

    def getQ(self):
        return (1 - self.lamb) * self.W + self.lamb * np.ones(2) / 2
#         return self.W

    def chooseRandom(self):
        q = self.getQ()

        r = np.random.rand()
        for i, p in enumerate(q):
            if r < p:
                return i
        return len(q) - 1

    def updateWeight(self, cost):
        self.W = self.W * (1 - self.epsilon * cost)
        self.W = self.W / np.sum(self.W)

    ########################################################################################################################################
    ####REQUEST#############################################################################################################################
    ########################################################################################################################################
    def request(self, page):
        page_fault = False
        self.time = self.time + 1
        ############################
        ## Save data for training ##
        ############################

        self.X = np.append(self.X, self.time)
        self.Y1 = np.append(self.Y1, self.W[0])
        self.Y2 = np.append(self.Y2, self.W[1])

        #########################
        ## Process page reques ##
        #########################
        if page in self.Cache:
            page_fault = False
        else:

            if page in self.Hist:
                self.Hist.delete(page)

                ## Update weights
                poly = self.policyUsed[page]
                q = self.weightsUsed[page]
                uniq = self.countUniquePagesSince(self.accessedTime[page])

                cost = np.array([0, 0], dtype=np.float32)
                if poly == 0:
                    cost[0] = 1
                if poly == 1:
                    cost[1] = 1
                if uniq < self.N:
                    cost = cost * (1.0 / uniq)
                self.updateWeight(cost)

                del self.evictionTime[page]
                del self.accessedTime[page]
                del self.frequency[page]
                del self.policyUsed[page]
                del self.weightsUsed[page]

            ## Remove from Hist
            if self.Hist.size() == self.N:
                evictPage = self.Hist.getIthPage(0)
                self.Hist.delete(evictPage)

                ## Update weights
                del self.evictionTime[evictPage]
                del self.accessedTime[evictPage]
                del self.frequency[evictPage]
                del self.policyUsed[evictPage]
                del self.weightsUsed[evictPage]

            ## Remove from Cache
            if self.Cache.size() == self.N:
                act = self.chooseRandom()

                evictPage, self.policyUsed[evictPage] = self.selectEvictPage(
                    act)
                self.weightsUsed[evictPage] = self.getQ()

                self.Cache.delete(evictPage)
                self.evictionTime[evictPage] = self.time

                self.Hist.add(evictPage)

            self.frequency[page] = 0
            self.Cache.add(page)
            page_fault = True

        for q in self.Cache:
            self.frequency[q] *= self.decayRate
        self.frequency[page] += 1
        self.accessedTime[page] = self.time

        return page_fault

    def get_list_labels(self):
        return ['L']
class ExpertLearning_v2(page_replacement_algorithm):
    def __init__(self, N):
        self.T = []
        self.N = N
        self.disk = Disk(N)
        self.freq = {}

        ## Training variables
        self.X, self.Y = [], []
        self.reward = []
        self.regret = []

        ## Config variables
        self.batchsize = N
        self.numbatch = 5
        self.discountrate = 0.9
        self.error = 0.5
        self.reduceErrorRate = 0.975

        ## Aux variables
        self.cachebuff = dequecustom()
        self.Xbuff = dequecustom()
        self.Ybuff = dequecustom()
        self.pageHitBuff = dequecustom()
        self.hist = dequecustom()
        self.batchsizeBuff = dequecustom()

        ## Accounting variables
        self.currentPageHits = 0
        self.current = 0
        self.uniquePages = Counter()

        ## Batch action variable
        self.action = [0]

        #self.discount = 0.9
        #self.sampleCount = 0
        #self.trainingSampleSize = 5 * N

        ## start tf
        tf.reset_default_graph()

        self.input = tf.placeholder(shape=[1, self.N], dtype=tf.float32)
        W1 = tf.Variable(tf.random_uniform([self.N, 8], 0, 0.01))
        out1 = tf.sigmoid(tf.matmul(self.input, W1))
        W2 = tf.Variable(tf.random_uniform([8, 2], 0, 0.01))
        self.out = tf.matmul(out1, W2)
        self.predictaction = tf.argmax(self.out)

        self.nextQ = tf.placeholder(shape=[1, 2], dtype=tf.float32)
        loss = tf.reduce_sum(tf.square(self.out - self.nextQ))
        trainer = tf.train.GradientDescentOptimizer(learning_rate=0.1)
        self.updatemodel = trainer.minimize(loss)

        init = tf.global_variables_initializer()
        self.sess = tf.Session()
        self.sess.run(init)

    def get_N(self):
        return self.N

    def __keyWithMinVal(self, d):
        v = list(d.values())
        k = list(d.keys())
        return k[v.index(min(v))]

    def __discountedReward(self, reward):
        discounted_reward = np.zeros(len(reward))
        rsum = 0
        for t in reversed(range(0, len(reward))):
            rsum = self.discount * rsum + reward[t]
            discounted_reward[t] = rsum
        return discounted_reward

    def __getRegret(self):
        cache = set(self.cachebuff.getleft())
        requestSequence = list(self.hist)

        ## Compute distance
        dist = {}
        for j, p in enumerate(requestSequence):
            if p not in dist:
                dist[p] = dequecustom()
            dist[p].append(j)

        discountedregret = 0

        i = 0
        batchid = 0
        optsum = 0
        hitsum = 0
        for hits, sz in zip(self.pageHitBuff, self.batchsizeBuff):
            opthits = 0
            batchid += 1
            for _ in range(0, sz):
                p = requestSequence[i]
                i += 1
                if p in cache:
                    opthits += 1
                else:
                    if len(cache) >= self.N:
                        rem = 'xxxxxxxxxxxxx'
                        for c in cache:
                            if c not in dist or len(dist[c]) == 0:
                                rem = c
                                break
                            if rem not in dist or dist[c].getleft(
                            ) > dist[rem].getleft():
                                rem = c
                        ## Evict from cache
                        cache = cache - {rem}
                    ## Add page to cache
                    cache = cache | {p}
                ## Pop from dist
                dist[p].popleft()

            regret = opthits - hits
            discountedregret = discountedregret + regret * (0.9)**(batchid - 1)
            optsum += opthits
            hitsum += hits
            break

        return discountedregret

    def getState(self):
        x = np.zeros(self.N, np.float32)
        for i, page in enumerate(self.disk):
            x[i] = 1.0 * self.freq[page]
        if np.sum(x) > 0.00001:
            x = x / np.sum(x)
        return x

    ########################################################################################################################################
    ####REQUEST#############################################################################################################################
    ########################################################################################################################################
    def request(self, page):
        page_fault = False

        ############################
        ## Save data for training ##
        ############################
        if len(self.uniquePages) == 0:
            ## Compute regret for the first batch

            if len(self.Xbuff) >= self.numbatch:
                r = self.__getRegret()
                cache = self.cachebuff.popleft()
                s1 = np.array(self.Xbuff.popleft())
                s2 = np.array(self.Xbuff.getleft())
                act = self.Ybuff.popleft()
                hits = self.pageHitBuff.popleft()
                sz = self.batchsizeBuff.popleft()
                for _ in range(0, sz):
                    temp = self.hist.popleft()

                #############################################################################################################################
                ## Train here ###############################################################################################################
                #############################################################################################################################
                allq = self.sess.run(self.out, feed_dict={self.input: s1})
                nextq = self.sess.run(self.out, feed_dict={self.input: s2})
                Qmax = np.max(nextq)
                targetQ = allq
                targetQ[0, act[0]] = r + self.discountrate * Qmax

                _ = self.sess.run(self.updatemodel,
                                  feed_dict={
                                      self.input: s1,
                                      self.nextQ: targetQ
                                  })
                #self.error = self.error * self.reduceErrorRate

            #####################
            ## Choose randomly ##
            #####################
            state = np.array([self.getState()])
            #print(state)
            self.action = self.sess.run(self.predictaction,
                                        feed_dict={self.input: state})

            if np.random.rand() < self.error:
                self.action[0] = 0 if np.random.rand() < 0.5 else 1

            self.cachebuff.append(self.disk.getData())
            self.Xbuff.append(state)
            self.Ybuff.append(self.action)

        #########################
        ## Process page reques ##
        #########################
        if self.disk.inDisk(page):
            self.disk.moveBack(page)
            self.freq[page] += 1
            self.currentPageHits += 1
        else:
            if self.disk.size() == self.N:
                if self.action[0] == 0:
                    ## Remove LRU page
                    lru = self.disk.getIthPage(0)
                    self.disk.delete(lru)
                    del self.freq[lru]
                elif self.action[0] == 1:
                    ## Remove LFU page
                    lfu = self.__keyWithMinVal(self.freq)
                    self.disk.delete(lfu)
                    del self.freq[lfu]
            # Add page to the MRU position
            self.disk.add(page)
            self.freq[page] = 1
            page_fault = True

        #self.uniquePages = self.uniquePages | {page}
        self.uniquePages.update({page: 1})

        ## Store page hits for current batch
        if len(self.uniquePages) == self.N:
            self.pageHitBuff.append(self.currentPageHits)
            self.batchsizeBuff.append(sum(self.uniquePages.values()))
            ## Reset variables
            self.uniquePages.clear()
            self.currentPageHits = 0

        self.hist.append(page)

        return page_fault

    def get_data(self):
        # data = []
        # for i,p,m in enumerate(self.T):
        #     data.append((p,m,i,0))
        # return data
        return [self.disk.get_data()]

    def get_list_labels(self):
        return ['L']
class LaCReME_context1(page_replacement_algorithm):

    def __init__(self, N):
        self.N = N
        self.CacheRecency = Disk(N)
        self.CacheFrequecy = priorityqueue(N)
        
        self.Hist1 = Disk(N)        
        self.Hist2 = priorityqueue(N)        
        
        ## Config variables
        self.decayRate = 1
        self.epsilon = 0.90
        self.lamb = 0.05
        self.learning_phase = N/2
        self.error_discount_rate = (0.005)**(1.0/N)
#         self.error_discount_rate = 1
        
        ## 
        self.learning = True
        self.policy = 0
        self.evictionTime = {}
        self.policyUsed = {}
        self.weightsUsed = {}
        self.freq = {}
        
        ## TODO add decay_time and decay_factor
        self.decay_time = N
        self.decay_factor = 1
        
        ## Accounting variables
        self.time = 0
        self.W = np.zeros((10,2))
        self.W[:,:] = 0.5
        
        self.X = np.array([],dtype=np.int32)
        self.Y1 = np.array([])
        self.Y2 = np.array([])
        
        
        ###
        self.q = Queue.Queue()
        self.sum = 0
        self.NewPages = []
        
        
    def get_N(self) :
        return self.N
    
    def visualize(self, plt):
#         print(np.min(self.X), np.max(self.X))
        ax = plt.subplot(2,1,1)
        ax.set_xlim(np.min(self.X), np.max(self.X))
        l1, = plt.plot(self.X,self.Y1, 'b-', label='W_lru')
        l2, = plt.plot(self.X,self.Y2, 'r-', label='W_lfu')
        l3, = plt.plot(self.X, self.NewPages, 'g-', label='New Pages')
        return [l1,l2,l3]
        
    def __keyWithMinVal(self,d):
        v=list(d.values())
        k=list(d.keys())
        return k[v.index(min(v))]
    
    def getMinValueFromCache(self, values):
        minpage,first = -1, True
        for q in self.Cache :
            if first or values[q] < values[minpage] :
                minpage,first=q,False
        return minpage
    
    ##########################################
    ## Add a page to cache using policy 'poly'
    ##########################################
    def addToCache(self, page,pagefreq=0):
        self.CacheRecency.add(page)
        self.CacheFrequecy.add(page)
        self.CacheRecency.increaseCount(page, amount=pagefreq)
        self.CacheFrequecy.increase(page, amount=pagefreq)
    ######################
    ## Get LFU or LFU page
    ######################    
    def selectEvictPage(self, policy):
        r = self.CacheRecency.getIthPage(0)
        f = self.CacheFrequecy.peaktop()
        pageToEvit,policyUsed = None, None
        if r == f :
            pageToEvit,policyUsed = r,-1
        elif policy == 0:
            pageToEvit,policyUsed = r,0
        elif policy == 1:
            pageToEvit,policyUsed = f,1
        return pageToEvit,policyUsed
    
    def evictPage(self, pg):
        self.CacheRecency.delete(pg)
        self.CacheFrequecy.delete(pg)
    
    ##############################################################
    ## There was a page hit to 'page'. Update the data structures
    ##############################################################
    def pageHitUpdate(self, page):
        if page in self.CacheRecency and page in self.CacheFrequecy:
            self.CacheRecency.moveBack(page)
            self.CacheRecency.increaseCount(page)
            self.CacheFrequecy.increase(page)
    
    #########################
    ## Get the Q distribution
    #########################
    def getQ(self,wid):
        return (1-self.lamb) * self.W[wid] + self.lamb*np.ones(2)/2
    ############################################
    ## Choose a page based on the q distribution
    ############################################
    def chooseRandom(self, wid):
        q = self.getQ(wid)
        r = np.random.rand()
        for i,p in enumerate(q):
            if r < p:
                return i 
        return len(q)-1
    def updateWeight(self, cost):
        self.W = self.W * (1-self.epsilon * cost)
        self.W = self.W / np.sum(self.W)
    
    ########################################################################################################################################
    ####REQUEST#############################################################################################################################
    ########################################################################################################################################
    def request(self,page) :
        page_fault = False
        self.time = self.time + 1
#         if self.time % self.learning_phase == 0 :
#             self.learning = not self.learning
        
        partitions = 5
        newpagesratio = 1.0*self.sum / self.N
        weigthid = int(newpagesratio*partitions) if newpagesratio < 1.0 else partitions-1
        
        #####################
        ## Visualization data
        #####################
        prob = self.getQ(weigthid)
        self.X = np.append(self.X, self.time)
        self.Y1 = np.append(self.Y1, prob[0])
        self.Y2 = np.append(self.Y2, prob[1])
        notInHistory = 0
        
        
        ##########################
        ## Process page request 
        ##########################
        if page in self.CacheFrequecy:
            page_fault = False
            self.pageHitUpdate(page)
        else :
            
            #####################################################
            ## Learning step: If there is a page fault in history
            #####################################################
            pageevict, histpage_freq = None,1
            policyUsed = -1
            if page in self.Hist1:
                pageevict = page
                histpage_freq = self.Hist1.getCount(page)
                self.Hist1.delete(page)
                policyUsed = 0
            elif page in self.Hist2:
                pageevict = page
                histpage_freq = self.Hist2.getFreq(page) ## Get the page frequency in history
                self.Hist2.delete(page)
                policyUsed = 1
            else:
                notInHistory = 1
                
            if pageevict is not None :
                q = self.weightsUsed[pageevict]
                err = self.error_discount_rate ** (self.time - self.evictionTime[pageevict])
                reward = np.array([0,0], dtype=np.float32)
                if policyUsed == 0 : # LRU
                    reward[1] = err
                if policyUsed == 1:
                    reward[0] = err
                reward_hat = reward / q
                
                #################
                ## Update Weights
                #################
                if self.policyUsed[pageevict] != -1 :
                    self.W[weigthid] = self.W[weigthid] * np.exp(self.lamb * reward_hat / 2)
                    self.W[weigthid] = self.W[weigthid] / np.sum(self.W[weigthid])
            
            ####################
            ## Remove from Cache
            ####################
            if self.CacheRecency.size() == self.N:
                
                ################
                ## Choose Policy
                ################
                if  not self.learning :
                    act = np.argmax(self.W[weigthid])
                else :
                    act = self.chooseRandom(weigthid)

                cacheevict,poly = self.selectEvictPage(act)
                pagefreq = self.CacheFrequecy.getCount(cacheevict) 
                
                self.policyUsed[cacheevict] = poly
                self.weightsUsed[cacheevict] = self.getQ(weigthid)
                self.evictionTime[cacheevict] = self.time
                        
                if not self.learning :
                    self.policyUsed[cacheevict] = -1
                
                ###################
                ## Evict to history
                ###################
                histevict = None
                if (poly == 0) or (poly==-1 and np.random.rand() <0.5):
                    if self.Hist1.size() == self.N :
                        histevict = self.Hist1.getIthPage(0)
                        self.Hist1.delete(histevict)
                    self.Hist1.add(cacheevict)
                    self.Hist1.setCount(cacheevict, pagefreq)
                else:
                    if self.Hist2.size() == self.N :
                        histevict = self.Hist2.popmin()
                    self.Hist2.add(cacheevict)
                    self.Hist2.increase(cacheevict, pagefreq-1)
                
                if histevict is not None :
                    del self.evictionTime[histevict]
                    del self.policyUsed[histevict]
                    del self.weightsUsed[histevict]
                
                self.evictPage(cacheevict)
                
            self.addToCache(page, pagefreq=histpage_freq)
            
            page_fault = True

        self.q.put(notInHistory)
        self.sum += notInHistory
        if self.q.qsize() > self.N:
            self.sum -= self.q.get()
        
        self.NewPages.append(newpagesratio)
        
        return page_fault

    def get_list_labels(self) :
        return ['L']
Пример #7
0
class LaCReME_simple(page_replacement_algorithm):
    def __init__(self, N):
        self.N = N
        self.CacheRecency = Disk(N)
        self.CacheFrequecy = priorityqueue(N)
        self.Hist1 = Disk(N)
        self.Hist2 = priorityqueue(N)

        ## Config variables
        self.decayRate = 1
        self.epsilon = 0.05
        self.learning_phase = N / 2

        ##
        self.learning = True
        self.policy = 0
        self.evictionTime = {}
        self.policyUsed = {}
        self.weightsUsed = {}
        self.freq = {}

        ## TODO add decay_time and decay_factor
        self.decay_time = N
        self.decay_factor = 1

        ## Accounting variables
        self.time = 0
        self.W = np.array([.5, .5], dtype=np.float32)

        ## For visualization
        self.X = np.array([], dtype=np.int32)
        self.Y1 = np.array([])
        self.Y2 = np.array([])

    def get_N(self):
        return self.N

    def visualize(self, plt):
        ax = plt.subplot(2, 1, 1)
        ax.set_xlim(np.min(self.X), np.max(self.X))
        l1, = plt.plot(self.X, self.Y1, 'b-', label='W_lru')
        l2, = plt.plot(self.X, self.Y2, 'r-', label='W_lfu')
        return [l1, l2]

    ##########################################
    ## Add a page to cache using policy 'poly'
    ##########################################
    def addToCache(self, page, pagefreq=0):
        self.CacheRecency.add(page)
        self.CacheFrequecy.add(page)
        self.CacheRecency.increaseCount(page, amount=pagefreq)
        self.CacheFrequecy.increase(page, amount=pagefreq)

    ######################
    ## Get LFU or LFU page
    ######################
    def selectEvictPage(self, policy):
        r = self.CacheRecency.getIthPage(0)
        f = self.CacheFrequecy.peaktop()
        pageToEvit, policyUsed = None, None
        if r == f:
            pageToEvit, policyUsed = r, -1
        elif policy == 0:
            pageToEvit, policyUsed = r, 0
        elif policy == 1:
            pageToEvit, policyUsed = f, 1
        return pageToEvit, policyUsed

    def evictPage(self, pg):
        self.CacheRecency.delete(pg)
        self.CacheFrequecy.delete(pg)

    ##############################################################
    ## There was a page hit to 'page'. Update the data structures
    ##############################################################
    def pageHitUpdate(self, page):
        if page in self.CacheRecency and page in self.CacheFrequecy:
            self.CacheRecency.moveBack(page)
            self.CacheRecency.increaseCount(page)
            self.CacheFrequecy.increase(page)

    ############################################
    ## Choose a page based on the q distribution
    ############################################
    def chooseRandom(self):
        q = self.getQ()
        r = np.random.rand()
        for i, p in enumerate(q):
            if r < p:
                return i
        return len(q) - 1

    ##################
    ####REQUEST#######
    ##################
    def request(self, page):
        page_fault = False
        self.time = self.time + 1

        #####################
        ## Visualization data
        #####################
        self.X = np.append(self.X, self.time)
        self.Y1 = np.append(self.Y1, self.W[0])
        self.Y2 = np.append(self.Y2, self.W[1])

        if self.time % self.N == 0:
            self.CacheFrequecy.decay(self.decay_factor)
            self.Hist2.decay(self.decay_factor)

        ##########################
        ## Process page request
        ##########################
        if page in self.CacheFrequecy:
            page_fault = False
            self.pageHitUpdate(page)
        else:

            #####################################################
            ## Learning step: If there is a page fault in history
            #####################################################
            histpage_freq = 1
            if page in self.Hist1:
                histpage_freq = self.Hist1.getCount(page)
                self.Hist1.delete(page)
                self.W[0] = self.W[0] * (
                    1 -
                    self.epsilon) if self.policyUsed[page] != -1 else self.W[0]
            elif page in self.Hist2:
                histpage_freq = self.Hist2.getCount(
                    page)  ## Get the page frequency in history
                self.Hist2.delete(page)
                self.W[1] = self.W[1] * (
                    1 -
                    self.epsilon) if self.policyUsed[page] != -1 else self.W[1]

            ####################
            ## Normalize weights
            ####################
            self.W = self.W / np.sum(self.W)

            ####################
            ## Remove from Cache
            ####################
            if self.CacheRecency.size() == self.N:

                ################################################################
                ## Choose Policy by picking the one with the highest weight
                ################################################################
                act = np.argmax(self.W)

                cacheevict, poly = self.selectEvictPage(act)
                pagefreq = self.CacheFrequecy.getCount(cacheevict)

                self.policyUsed[cacheevict] = poly
                self.weightsUsed[cacheevict] = self.W
                self.evictionTime[cacheevict] = self.time

                ###################
                ## Evict to history
                ###################
                histevict = None
                if (poly == 0) or (poly == -1 and np.random.rand() < 0.5):
                    if self.Hist1.size() == self.N:
                        histevict = self.Hist1.getIthPage(0)
                        self.Hist1.delete(histevict)
                    self.Hist1.add(cacheevict)
                    self.Hist1.setCount(cacheevict, pagefreq)
                else:
                    if self.Hist2.size() == self.N:
                        histevict = self.Hist2.popmin()
                    self.Hist2.add(cacheevict)
                    self.Hist2.increase(cacheevict, pagefreq - 1)

                ##################################
                ## Remove histevict from the system
                ###################################
                if histevict is not None:
                    del self.evictionTime[histevict]
                    del self.policyUsed[histevict]
                    del self.weightsUsed[histevict]

                ##############################################
                ## Remove cacheevict from both data structures
                ##############################################
                self.evictPage(cacheevict)

            ###################################
            ## Add page to both data structures
            ###################################
            self.addToCache(page, pagefreq=histpage_freq)

            page_fault = True

        return page_fault

    def get_list_labels(self):
        return ['L']
class ExpertLearning(page_replacement_algorithm):
    def __init__(self, N):
        self.T = []
        self.N = N
        self.disk = Disk(N)
        self.freq = {}

        ## Training variables
        self.X, self.Y = [], []
        self.reward = []
        self.regret = []

        ## Config variables
        self.batchsize = N
        self.numbatch = 5

        ## Aux variables
        self.hist = queue.deque()
        self.Xbuff = queue.deque()
        self.Ybuff = queue.deque()
        self.pageHitBuff = deque()

        self.current = 0
        self.action = 1
        self.currentPageHits = 0

        #self.discount = 0.9
        #self.sampleCount = 0
        #self.trainingSampleSize = 5 * N

    def get_N(self):
        return self.N

    def __keyWithMinVal(self, d):
        v = list(d.values())
        k = list(d.keys())
        return k[v.index(min(v))]

    def __discountedReward(self, reward):
        discounted_reward = np.zeros(len(reward))
        rsum = 0
        for t in reversed(range(0, len(reward))):
            rsum = self.discount * rsum + reward[t]
            discounted_reward[t] = rsum
        return discounted_reward

    def __getRegret(self):
        return 0

    def getState(self):
        x = np.zeros(self.N, np.float32)
        for i, page in enumerate(self.disk):
            x[i] = 1.0 * self.freq[page]
        if np.sum(x) > 0.00001:
            x = x / np.sum(x)
        return x

    def request(self, page):
        page_fault = False

        ############################
        ## Save data for training ##
        ############################
        if self.current == 0:
            ## Compute regret for the first batch
            if len(self.hist) == self.numbatch * self.batchsize:
                reg = self.__getRegret()  ## Regret of first n pages
                x = self.Xbuff.popleft()
                y = self.Ybuff.popleft()
                h = self.pageHitBuff.popleft()

                ## Remove from hist and buffers
                for _ in range(0, self.N):
                    self.hist.get()
            ## Choose randomly
            self.action = 1 if np.random.rand() < 0.5 else 2
            self.Xbuff.append(self.getState())
            self.Ybuff.append(self.action)

        #########################
        ## Process page reques ##
        #########################
        if self.disk.inDisk(page):
            self.disk.moveBack(page)
            self.freq[page] += 1
        else:
            if self.disk.size() == self.N:
                if self.action == 1:
                    ## Remove LRU page
                    lru = self.disk.getIthPage(0)
                    self.disk.delete(lru)
                    del self.freq[lru]
                elif self.action == 2:
                    ## Remove LFU page
                    lfu = self.__keyWithMinVal(self.freq)
                    self.disk.delete(lfu)
                    del self.freq[lfu]

            # Add page to the MRU position
            self.disk.add(page)
            self.freq[page] = 1
            page_fault = True

        ## Increate page hits counter
        self.currentPageHits += 1 * (not page_fault)

        ## Save page hits for current batch
        if self.current + 1 == self.batchsize:
            self.pageHitBuff.append(self.currentPageHits)

        ## Save page in history
        self.hist.put(page)

        ## Increase batch size counter
        self.current = (self.current + 1) % self.batchsize

        return page_fault

    def get_data(self):
        # data = []
        # for i,p,m in enumerate(self.T):
        #     data.append((p,m,i,0))
        # return data
        return [self.disk.get_data()]

    def get_list_labels(self):
        return ['L']
class LaCReME_LFU_ARC(page_replacement_algorithm):
    def __init__(self, N):
        self.N = N
        self.CacheARC = ArcDT(N)
        self.CacheFrequecy = priorityqueue(N)

        self.Hist1 = Disk(N, name='Hist1')
        self.Hist2 = Disk(N, name='Hist2')

        ## Config variables
        self.decayRate = 1
        self.epsilon = 0.90
        self.lamb = 0.05
        self.learning_phase = N / 2
        self.error_discount_rate = (0.005)**(1.0 / N)
        ##
        self.learning = True
        self.policy = 0
        self.evictionTime = {}
        self.policyUsed = {}
        self.weightsUsed = {}
        self.freq = {}

        ## TODO add decay_time and decay_factor
        self.decay_time = N
        self.decay_factor = 1

        ## Accounting variables
        self.time = 0

        self.W = np.array([.5, .5], dtype=np.float32)

        self.X = np.array([], dtype=np.int32)
        self.Y1 = np.array([])
        self.Y2 = np.array([])

    def get_N(self):
        return self.N

    def visualize(self, plt):
        #         print(np.min(self.X), np.max(self.X))
        ax = plt.subplot(2, 1, 1)
        ax.set_xlim(np.min(self.X), np.max(self.X))
        l1, = plt.plot(self.X, self.Y1, 'b-', label='W_lru')
        l2, = plt.plot(self.X, self.Y2, 'r-', label='W_lfu')
        return [l1, l2]

    def __keyWithMinVal(self, d):
        v = list(d.values())
        k = list(d.keys())
        return k[v.index(min(v))]

    ##########################################
    ## Add a page to cache using policy 'poly'
    ##########################################
    def addToCache(self, page, pagefreq=0):
        self.CacheARC.request(page)
        self.CacheARC.setCount(page=page, cnt=pagefreq)
        self.CacheFrequecy.add(page)
        self.CacheFrequecy.increase(page, amount=pagefreq)

    ######################
    ## Get LFU or LFU page
    ######################
    def updateCacheUsingPolicy(self, policy, requested_page, page_freq):
        pageToEvit, policyUsed = None, None
        if policy == 0:
            ## Use ARC
            r = self.CacheARC.request(requested_page)
            self.CacheARC.setCount(requested_page, page_freq)
            evict_page_freq = self.CacheFrequecy.getCount(r)
            # Add page to LFU
            self.CacheFrequecy.delete(r)
            self.CacheFrequecy.add(requested_page)

            pageToEvit, policyUsed = r, 0
        elif policy == 1:
            ## Use LFU
            evict_page_freq = self.CacheFrequecy.getCount(
                self.CacheFrequecy.peaktop())
            f = self.CacheFrequecy.popmin()
            self.CacheFrequecy.add(requested_page)

            ## Add page to arc
            self.CacheARC.delete(f)
            self.CacheARC.add(requested_page)

            pageToEvit, policyUsed = f, 1

        return pageToEvit, policyUsed, evict_page_freq

    def evictPage(self, pg):
        self.CacheARC.delete(pg)
        self.CacheFrequecy.delete(pg)

    ##############################################################
    ## There was a page hit to 'page'. Update the data structures
    ##############################################################
    def pageHitUpdate(self, page):
        assert page in self.CacheARC and page in self.CacheFrequecy
        self.CacheARC.request(page)
        self.CacheFrequecy.increase(page)

    #########################
    ## Get the Q distribution
    #########################
    def getQ(self):
        return (1 - self.lamb) * self.W + self.lamb * np.ones(2) / 2

    ############################################
    ## Choose a page based on the q distribution
    ############################################
    def chooseRandom(self):
        q = self.getQ()
        r = np.random.rand()
        for i, p in enumerate(q):
            if r < p:
                return i
        return len(q) - 1

    def updateWeight(self, cost):
        self.W = self.W * (1 - self.epsilon * cost)
        self.W = self.W / np.sum(self.W)

    ########################################################################################################################################
    ####REQUEST#############################################################################################################################
    ########################################################################################################################################
    def request(self, page):
        page_fault = False
        self.time = self.time + 1
        #         if self.time % self.learning_phase == 0 :
        #             self.learning = not self.learning

        #####################
        ## Visualization data
        #####################
        prob = self.getQ()
        self.X = np.append(self.X, self.time)
        self.Y1 = np.append(self.Y1, prob[0])
        self.Y2 = np.append(self.Y2, prob[1])

        ##########################
        ## Process page request
        ##########################
        if page in self.CacheFrequecy:
            page_fault = False
            self.pageHitUpdate(page)
        else:

            #####################################################
            ## Learning step: If there is a page fault in history
            #####################################################
            pageevict, histpage_freq = None, 1
            policyUsed = -1
            if page in self.Hist1:
                pageevict = page
                histpage_freq = self.Hist1.getCount(page)
                self.Hist1.delete(page)
                policyUsed = 0
            elif page in self.Hist2:
                pageevict = page
                histpage_freq = self.Hist2.getCount(
                    page)  ## Get the page frequency in history
                self.Hist2.delete(page)
                policyUsed = 1
            if pageevict is not None:
                q = self.weightsUsed[pageevict]
                err = self.error_discount_rate**(self.time -
                                                 self.evictionTime[pageevict])
                reward = np.array([0, 0], dtype=np.float32)
                if policyUsed == 0:  # LRU
                    reward[1] = err
                if policyUsed == 1:
                    reward[0] = err
                reward_hat = reward / q

                #################
                ## Update Weights
                #################
                if self.policyUsed[pageevict] != -1:
                    self.W = self.W * np.exp(self.lamb * reward_hat / 2)
                    self.W = self.W / np.sum(self.W)

            ####################
            ## Remove from Cache
            ####################
            if self.CacheARC.size() == self.N:
                ################
                ## Choose Policy
                ################
                if not self.learning:
                    act = np.argmax(self.getQ())
                else:
                    act = self.chooseRandom()

                cacheevict, poly, pagefreq = self.updateCacheUsingPolicy(
                    act, page, histpage_freq)

                self.policyUsed[cacheevict] = poly
                self.weightsUsed[cacheevict] = self.getQ()
                self.evictionTime[cacheevict] = self.time

                if not self.learning:
                    self.policyUsed[cacheevict] = -1

                ###################
                ## Evict to history
                ###################
                histevict = None
                if (poly == 0) or (poly == -1 and np.random.rand() < 0.5):
                    if self.Hist1.size() == self.N:
                        histevict = self.Hist1.getIthPage(0)
                        self.Hist1.delete(histevict)
                    assert self.Hist1.add(cacheevict), "Error adding to Hist1."
                    self.Hist1.setCount(cacheevict, pagefreq)
                else:
                    if self.Hist2.size() == self.N:
                        histevict = self.Hist2.getIthPage(0)
                        self.Hist2.delete(histevict)
                    self.Hist2.add(cacheevict)
                    self.Hist2.setCount(cacheevict, pagefreq)

                if histevict is not None:
                    del self.evictionTime[histevict]
                    del self.policyUsed[histevict]
                    del self.weightsUsed[histevict]

                ## Delete page from Cache

            else:
                self.addToCache(page, pagefreq=histpage_freq)

            page_fault = True

        return page_fault

    def get_list_labels(self):
        return ['L']
class BANDIT_WITH_ARC(page_replacement_algorithm):
    def __init__(self, N):
        self.N = N
        self.Cache = Disk(N, name='Cache')
        self.Hist1 = Disk(N, name='Hist1')
        self.Hist2 = Disk(N, name='Hist2')
        self.Hist3 = Disk(N, name='Hist3')

        ## Config variables
        self.decayRate = 0.99
        self.epsilon = 0.90  ## Learning rate
        self.lamb = 0.05
        self.learning_phase = 2 * N
        self.error_discount_rate = (0.005)**(1.0 / N)

        ## State Variables
        self.learning = True
        self.policy = 0
        self.accessedTime = {}
        self.frequency = {}
        self.accessedSinceInCache = {}
        self.evictionTime = {}
        self.policyUsed = {}
        self.weightsUsed = {}
        self.currentPolicy = np.random.randint(0, 3)
        self.time = 0
        self.learning = True
        self.leaningPhaseCount = 1
        self.W = np.array([1.0 / 3, 1.0 / 3, 1.0 / 3], dtype=np.float32)
        self.P = 0
        self.currentQ = np.zeros(3)

        self.X = np.array([])
        self.Y1 = np.array([])
        self.Y2 = np.array([])
        self.Y3 = np.array([])

    def get_N(self):
        return self.N

    def visualize(self, plt):
        l1, = plt.plot(self.X, self.Y1, 'b-', label='W_lru')
        l2, = plt.plot(self.X, self.Y2, 'r-', label='W_lfu')
        l3, = plt.plot(self.X, self.Y3, 'g-', label='W_arc')

        plt.xlabel('time')
        plt.ylabel('Weight')
        plt.legend(handles=[l1, l2, l3])

    def getArcCache(self):
        T1, T2 = [], []
        for pg in self.Cache:
            if self.accessedSinceInCache[pg] == 1:
                T1.append(pg)
            else:
                T2.append(pg)
        return T1, T2

    def getArcHist(self):
        B1, B2 = [], []
        for pg in self.Hist3:
            if self.accessedSinceInCache[pg] == 1:
                B1.append(pg)
            else:
                B2.append(pg)
        return B1, B2

    def getLru(self, L):
        lru = None
        for pg in L:
            if lru is None or self.accessedTime[
                    pg] < self.accessedSinceInCache[lru]:
                lru = pg
        return lru

    def __keyWithMinVal(self, d):
        v = list(d.values())
        k = list(d.keys())
        return k[v.index(min(v))]

    def getMinValueFromCache(self, values):
        minpage, first = -1, True
        for q in self.Cache:
            if first or values[q] < values[minpage]:
                minpage, first = q, False
        return minpage

    def selectEvictPage(self, policy):
        r = self.getMinValueFromCache(self.accessedTime)
        f = self.getMinValueFromCache(self.frequency)

        #         if r == f :
        #             return r,-1
        if policy == 0:
            return r, 0
        if policy == 1:
            return f, 1

    def getQ(self):
        return (1 - self.lamb) * self.W + self.lamb * np.ones(3) / 3

    def chooseRandom(self):
        q = self.getQ()
        r = np.random.rand()
        for i, p in enumerate(q):
            if r < p:
                return i
        return len(q) - 1

    def updateWeight(self, cost):
        self.W = self.W * (1 - self.epsilon * cost)
        self.W = self.W / np.sum(self.W)

    def __replace(self, T1, T2, B1, B2, x):
        evict = None
        if len(T1) > 0 and (len(T1) > self.P or
                            (x in B1 and len(B1) == self.P)):
            evict = self.getLru(T1)
            self.Cache.delete(evict)
            self.Hist3.add(evict)
        else:
            evict = self.getLru(T2)
            self.Cache.delete(evict)
            self.Hist3.add(evict)
        if evict is None:
            print('__replace debug')
        return evict

    ########################################################################################################################################
    ####REQUEST#############################################################################################################################
    ########################################################################################################################################
    def request(self, page):
        page_fault = False
        self.time = self.time + 1
        ############################
        ## Save data for training ##
        ############################

        if self.time % self.learning_phase == 0:
            lastPolicy = self.currentPolicy
            if np.random.rand() < (0.5 -
                                   0.5 / np.sqrt(self.leaningPhaseCount)):
                self.currentPolicy = np.argmax(self.getQ())
                self.learning = False
            else:
                self.currentPolicy = self.chooseRandom()
                self.leaningPhaseCount += 1
                self.learning = True
                self.currentQ = self.getQ()

            if self.currentPolicy == 2 and lastPolicy != 2:
                self.Hist3.clear()

        ## Visualization data
        prob = self.getQ()
        self.X = np.append(self.X, self.time)
        self.Y1 = np.append(self.Y1, prob[0])
        self.Y2 = np.append(self.Y2, prob[1])
        self.Y3 = np.append(self.Y3, prob[2])

        #########################
        ## Process page reques ##
        #########################
        if page in self.Cache:
            page_fault = False
        else:

            #### HISTORY #########################################################################################################
            pageevict = None
            policyUsed = -1
            wasInArcHist = False
            if page in self.Hist1:
                pageevict = page
                policyUsed = 0
                self.Hist1.delete(page)
            elif page in self.Hist2:
                pageevict = page
                policyUsed = 1
                self.Hist2.delete(page)
            elif page in self.Hist3:
                pageevict = page
                policyUsed = 2
                wasInArcHist = True
                B1, B2 = self.getArcHist()
                if page in B1:
                    if len(B2) > len(B1):
                        r = len(B2) / len(B1)
                    else:
                        r = 1
                    self.P = min(self.P + r, self.N)
                if page in B2:
                    if len(B1) > len(B2):
                        r = len(B1) / len(B2)
                    else:
                        r = 1
                    self.P = max(self.P - r, 0)
                self.Hist3.delete(page)

            if pageevict is not None:
                q = self.weightsUsed[pageevict]
                err = self.error_discount_rate**(self.time -
                                                 self.evictionTime[pageevict])
                reward = np.array([0, 0, 0], dtype=np.float32)
                if policyUsed == 0:
                    reward[1] = reward[2] = err
                if policyUsed == 1:
                    reward[0] = reward[2] = err
                if policyUsed == 2:
                    reward[0] = reward[1] = err

                reward_hat = reward / q
                ## Update Weights
                if self.policyUsed[pageevict] != -1:
                    self.W = self.W * np.exp(self.lamb * reward_hat / 3)
                    self.W = self.W / np.sum(self.W)
            #### END HISTORY ######################################################################################################

            #############################################################################################################
            ## Remove from Cache
            if self.Cache.size() == self.N:
                histevict = -1

                if self.currentPolicy == 0:
                    cacheevict = self.getMinValueFromCache(self.accessedTime)
                    self.Cache.delete(cacheevict)
                    self.weightsUsed[cacheevict] = self.currentQ
                    self.evictionTime[cacheevict] = self.time
                    self.policyUsed[
                        cacheevict] = 0 if not self.learning else -1

                    if self.Hist1.size() == self.N:
                        histevict = self.Hist1.getIthPage(0)
                        self.Hist1.delete(histevict)
                    self.Hist1.add(cacheevict)

                if self.currentPolicy == 1:
                    cacheevict = self.getMinValueFromCache(self.frequency)
                    self.Cache.delete(cacheevict)
                    self.weightsUsed[cacheevict] = self.currentQ
                    self.evictionTime[cacheevict] = self.time
                    self.policyUsed[
                        cacheevict] = 1 if not self.learning else -1

                    if self.Hist2.size() == self.N:
                        histevict = self.Hist2.getIthPage(0)
                        self.Hist2.delete(histevict)
                    self.Hist2.add(cacheevict)

                if self.currentPolicy == 2:
                    T1, T2 = self.getArcCache()
                    B1, B2 = self.getArcHist()
                    cacheevict = None
                    if wasInArcHist:
                        cacheevict = self.__replace(T1, T2, B1, B2, page)
                    else:
                        if len(T1) + len(B1) == self.N:
                            if len(T1) < self.N:
                                histevict = self.getLru(B1)
                                self.Hist3.delete(histevict)
                                cacheevict = self.__replace(
                                    T1, T2, B1, B2, page)
                            else:
                                histevict = self.getLru(T1)
                                self.Cache.delete(histevict)

                            _T1, _T2 = self.getArcCache()
                            _B1, _B2 = self.getArcHist()

                            if len(_T1) + len(_B1) >= 50:
                                print('debug: T1+B1 = ',
                                      len(_T1) + len(_B1), ' T1,B1 = ',
                                      len(_T1), len(_B1))

                        elif len(T1) + len(B1) < self.N:
                            if len(T1) + len(T2) + len(B1) + len(B2) >= self.N:
                                if len(T1) + len(T2) + len(B1) + len(
                                        B2) == 2 * self.N:
                                    histevict = self.getLru(B2)
                                    self.Hist3.delete(histevict)
                                cacheevict = self.__replace(
                                    T1, T2, B1, B2, page)

                    if cacheevict is not None:
                        self.weightsUsed[cacheevict] = self.currentQ
                        self.evictionTime[cacheevict] = self.time
                        self.policyUsed[
                            cacheevict] = 2 if not self.learning else -1
                    else:
                        print('cacheevict is None',
                              len(T1) + len(B1), len(T1), len(B1), cacheevict)
                        pass

                if histevict != -1:
                    del self.evictionTime[histevict]
                    del self.accessedTime[histevict]
                    del self.frequency[histevict]
                    del self.accessedSinceInCache[histevict]
                    del self.policyUsed[histevict]
                    del self.weightsUsed[histevict]

            if page not in self.frequency:
                self.frequency[page] = 0

            if page not in self.accessedSinceInCache or not wasInArcHist:
                self.accessedSinceInCache[page] = 0  ## page - is new to cache

            self.Cache.add(page)
            page_fault = True

        for q in self.Cache:
            self.frequency[q] *= self.decayRate
        self.frequency[page] += 1
        self.accessedTime[page] = self.time
        self.accessedSinceInCache[page] += 1

        return page_fault

    def get_list_labels(self):
        return ['L']