||
近年来,北京大学图书馆的存包柜被长期占用的情况十分严重。尽管图书馆在《北京大学图书馆存包柜使用须知》中明确规定了闭馆前不带走物品和挂锁的行为为占柜,并应该被清理,而因为种种原因这一规定并没有得到彻底的执行。
近来,随着图书馆方面加强了对存包柜的清理,一些利益相关者在北大未名BBS的PKULibrary版面上产生了很多的争执。有一些网友认为,清理存书柜的行为不具有正当性,而违规占柜是正当的。他们的理由包括清理存包柜会导致实际的利用效率下降。
针对这些争论,我对北京大学图书馆的存包过程进行了简化假设,并构建了模拟模型,利用python语言对其进行了实现和求解,并研究了不同参数下的模型结果。
该模型的假设简要概括如下:
北京大学图书馆(PKULib)每天开放10小时。
PKULib有1000位读者,其中100位为不遵守规定的读者(badreader),900位为遵守规定的读者(goodreader)。
北京大学图书馆提供150个存包柜(locker)供读者使用。
每天,所有读者都会一个个的进馆,并都会使用存包柜。其进入图书馆的时间基本满足均匀分布,即每小时进入的人数相差不大。每人进馆后都会寻找空的储物柜,如果找到,该读者会感到开心(happiness);如果存包柜都被沾满,该读者会感到郁闷(madness)。
goodreader每天会在图书馆呆到下一个整点,且这一天就不再来图书馆。他们走的时候会带走存包柜里自己的东西。
badreader走的时间谁也不知道,而且他们不会带走自己在存包柜里的东西。
每隔一段时间(emptyperiod),图书馆会在闭馆后清理存包柜,此时badreader占用的存包柜会被清空。直到下一次badreader来到图书馆,他们才会重新占据一个存包柜。
我编写并求解了这一模型。在参数emptyperiod不同的情况下,获得了不同的结果。经过多次尝试,发现参数不变的情况下结果的差异不大(可以算方差表征)。典型的值如下:
当每天清一次柜时,happiness为90209,madness为9791;
当每30天清一次柜时,happiness为1314,madness为98686。
这样的模拟结果说明,在模型假设条件下,每天清柜相比每30天清柜,会显著的增加happiness,降低madness。
附:代码LibSim_1_0_0.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | # FileName: LibSim.py '''Libsim 1.0.0 LibSim program is an agent-based simulation program to study the occupation of lockers in Peking University library. It is a python 3 styled code written in object-oriented fashion. Programmer: Meng Xiangxi PhD student, Peking University mengxiangxibme(>_<)gmail.com History: 1.0.0 Released 20141213 ''' import random # Model specifications, constants hours = 10 # Total openning hours of PKULib emptyperiod = 30 # Period of evacuation simdays = 100 # Days to simulate numlocker = 150 # Set number of lockers numgoodreader = 900 # Set number of good readers numbadreader = 100 # Set number of bad readers #=====================Classes====================# class Locker: '''The locker in PKULib''' empty = True # If the locker is empty readerID = 'null' # The reader occupying the locker def chkempty(self): # Check if the locker is empty return self.empty def setempty(self, value): # Change the empty status self.empty = value # value is Boolean def getreaderID(self): # Return the occupyer return self.readerID def setreaderID(self, ID): # Change the occupyer self.readerID = ID def emptygoodreader(self): # Only good readers leave if self.readerID[0] == 'G': self.empty = True self.readerID = 'null' class Reader: '''Parent class for the readers''' numlocker = -1 # The last used locker number def chklocker(self, locker): # When entering PKULib, reader look for locker for lockernum in range(0,numlocker): # Traverse the lockers if locker[lockernum].chkempty(): # If locker is empty inchappy() # Feel happy locker[lockernum].setempty(False) # Occupy it self.numlocker = lockernum # Record the locker number return 0 # Stop looking for lockers self.numlocker = -1 # Cannot find locker def getlockernum(self): # Return the number of locker last used return self.numlocker def leave(self,locker): # Leaving PKULib, release the locker if self.numlocker > 0: locker[self.numlocker].setreaderID('Null') locker[self.numlocker].setempty(True) self.numlocker = -1 class GoodReader(Reader): '''Readers taking their own belongings''' def __init__(self): # Inherit the __init__() and parameter of Reader Reader.__init__(self) numlocker = -1 self.numlocker = numlocker def chklocker(self,locker,ID): # The chklocker() function of child class for lockernum in range(0,numlocker): if locker[lockernum].chkempty(): inchappy() locker[lockernum].setempty(False) self.numlocker = lockernum locker[lockernum].setreaderID('G'+str(ID)) # G for 'GoodReader' return 0 self.numlocker = -1 incmad() class BadReader(Reader): '''Readers leaving their own belongings''' def __init__(self): # Inherit the __init__() and parameter of Reader Reader.__init__(self) numlocker = -1 # Don't know why have to write this... But bugs if not self.numlocker = numlocker def chklocker(self,locker,ID): # The chklocker() function of child class for lockernum in range(0,numlocker): if locker[lockernum].chkempty(): inchappy() locker[lockernum].setempty(False) self.numlocker = lockernum locker[lockernum].setreaderID('B'+str(ID)) # B for 'BadReader' return 0 self.numlocker = -1 incmad() #====================Paramters===================# # Total number of readers numtotreader = numgoodreader + numbadreader # Hourly entrance number hrnumreader = (numgoodreader+numbadreader)//hours hrnumreaderres = (numgoodreader+numbadreader)%hours # Initialize the parameters locker = [Locker() for _ in range(numlocker)] goodreader = [GoodReader() for _ in range(numgoodreader)] badreader = [BadReader() for _ in range(numbadreader)] # Target variable happiness = 0 madness = 0 def inchappy(): '''Access and alter the variable 'happiness'.''' global happiness happiness += 1 def incmad(): '''Access and alter the variable 'madness'.''' global madness madness += 1 #=====================Function===================# def readerenter(namelistpara, numreaderenterpara): '''A certain reader enters.''' numreaderenter = namelistpara[numreaderenterpara] # Convert to the subscript of the reader if numreaderenter < 0: goodreader[-numreaderenter-1].chklocker(locker,-numreaderenter-1) # Convert the negative values to the subscript of goodreader else: badreader[numreaderenter].chklocker(locker, numreaderenter) #=======================Main=====================# for day in range(0,simdays): # Simulate for each day if day%emptyperiod == 0: # Empty the lockers periodically for i in badreader: # Propell badreaders i.leave(locker) namelist = [] # Initialze namelist container ### Here, namelist combines goodreader and badreader. Negative values are ### for goodreader and vice versa. The subscript of goodreader is obtained by ### convertion: -numnamelist - 1. for numnamelist in range(-numgoodreader, numbadreader): # Construct original namelist namelist.append(numnamelist) random.shuffle(namelist) # Shuffle(): change the order of element randomly for varhour in range(0, hours-1): # Simulate hour by hour for numreaderenterori in range(varhour*hrnumreader, (varhour+1)*hrnumreader): # Every hour except the last, an equal number of readers enter readerenter(namelist, numreaderenterori) for goodreaderleave in goodreader: # goodreader leave after one hour goodreaderleave.leave(locker) varhour = hours - 1 # The last opening hour for numreaderenterori in range(varhour*hrnumreader, numtotreader): # In the last hour, all unentered readers enters readerenter(namelist, numreaderenterori) for goodreaderleave in goodreader: # All goodreader leave goodreaderleave.leave(locker) #======================Output====================# print('happiness:', happiness) print('madness:', madness) |
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-9-23 16:56
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社