-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSimulateNextState.py
260 lines (243 loc) · 12 KB
/
SimulateNextState.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# Authors: Majid Alkaee Taleghan, Mark Crowley, Thomas Dietterich
# Invasive Species Project
# 2012 Oregon State University
# Send code issues to: [email protected]
# Date: 12/20/12:3:26 PM
#
from Utilities import InvasiveUtility
from numpy.random import random
import numpy as np
from numpy.matlib import *
class GerminationDispersionParameterClass:
def __init__(self, germinationSuccNat, germinationSuccTam):
self.germinationSuccTam = germinationSuccTam
self.germinationSuccNat = germinationSuccNat
class SimulationParameterClass:
"""
This class contains the related parameters, which define the invasive species domain
"""
#two different alternatives that exogenousOnOffIndicator could have
#the exogenous arrival is on
ExogenousArrivalOn = 2
#the exogenous arrival is off
ExogenousArrivalOff = 1
def __init__(self, nbrReaches, habitatSize, prodRate, deathRate, exogenousOnOffIndicator, reachArrivalRates,
reachArrivalProbs, upStreamRate, downStreamRate, competitionFactor, graph):
"""
:param competitionFactor, competition parameter
:param deathRate (array of length 2 of float), first column shows Native, and the second column shows Tamarisk
:param habitatSize (int)
:param exogenousOnOffIndicator (On=2, Off=1), indicates if there is exogenous arrival
:param prodRate (array of length 2 of float) production rate
:param reachArrivalProbs (matrix of size (nbrReaches,2)), first column shows Native, and the second column shows Tamarisk
:param reachArrivalRates (matrix of size (nbrReaches,2)), first column shows Native, and the second column shows Tamarisk
:param upStreamRate (float)
:param downStreamRate (float)
:param graph (networkx graph), a graph representing the river network
Note that the position of the reaches in the state and action is based on the graph.edges() output
"""
self.nbrReaches = nbrReaches
self.habitatSize = habitatSize
self.prodRate = prodRate
self.deathRate = deathRate
self.exogenousArrivalIndicator = exogenousOnOffIndicator
self.reachArrivalRates = reachArrivalRates
self.reachArrivalProbs = reachArrivalProbs
self.downStreamRate = downStreamRate
self.upStreamRate = upStreamRate
self.competitionFactor = competitionFactor
self.graph = graph
class ActionParameterClass:
"""
This class contains the related parameters, which define the actions and state costs
"""
def __init__(self, costPerTree, eradicationCost, restorationCost, eradicationRate, restorationRate, costPerReach,
emptyCost, varEradicationCost, varInvasiveRestorationCost, varEmptyRestorationCost, budget):
"""
:param budget (float)
:param costPerReach (float), cost per invaded reach
:param costPerTree (float), cost per invaded tree
:param emptyCost (float), cost for empty slot
:param eradicationCost (float), fixed eradication cost
:param eradicationRate (float), eradication success rate
:param restorationCost (float), fixed restoration cost
:param restorationRate (float), restoration success rate
:param varEmptyRestorationCost (float), variable restoration cost for empty slot
:param varEradicationCost (float), variable eradication cost for empty slot
:param varInvasiveRestorationCost (float), variable restoration cost for empty slot
"""
self.costPerTree = costPerTree
self.eradicationCost = eradicationCost
self.restorationCost = restorationCost
self.eradicationRate = eradicationRate
self.restorationRate = restorationRate
self.costPerReach = costPerReach
self.emptyCost = emptyCost
self.varEradicationCost = varEradicationCost
self.varInvasiveRestorationCost = varInvasiveRestorationCost
self.varEmptyRestorationCost = varEmptyRestorationCost
self.budget = budget
def binomial(nv, pv):
if size(pv) == 1:
if pv == 1:
return nv
else:
[rows, cols] = shape(nv)
result = np.zeros((rows, cols))
nnz, cnz = np.nonzero(nv)
for index in range(len(nnz)):
row = nnz[index]
col = cnz[index]
result[row, col] = random.binomial(nv[row, col], pv)
return result
else:
assert size(nv,0)==size(pv,0)
assert size(nv,1)==size(pv,1)
[rows, cols] = shape(nv)
result = np.zeros((rows, cols))
nnz, cnz = np.nonzero(nv)
for index in range(len(nnz)):
row = nnz[index]
col = cnz[index]
#H = nv.shape[0] / nv.shape[1]
#result[row, col] = random.binomial(nv[row, col], pv[row / float(H), col])
result[row, col] = random.binomial(nv[row, col], pv[row, col])
return result
def simulateNextState(state, action, simulationParameterObj, actionParameterObj, dispertionTable,
germinationObj):
"""
simulate based on the input parameters and state and action
:param state (an array of length simulationParameterObj.nbrReaches* simulationParameterObj.habitatSize)
:param action (array of length simulationParameterObj.nbrReaches)
:param simulationParameterObj (SimulationParameterClass)
:param dispertionTable (matrix of size (simulationParameterObj.nbrReaches,simulationParameterObj.nbrReaches))
:param germinationObj (GerminationClass)
:return next state
"""
H = simulationParameterObj.habitatSize
Prod_rate = simulationParameterObj.prodRate
Death_Rate = simulationParameterObj.deathRate
on_off_indicator = simulationParameterObj.exogenousArrivalIndicator
reach_arrival_rates = simulationParameterObj.reachArrivalRates
reach_arrival_probs = simulationParameterObj.reachArrivalProbs
beta = simulationParameterObj.competitionFactor
eradication_rate = actionParameterObj.eradicationRate
restoration_rate = actionParameterObj.restorationRate
nbr_Reaches = simulationParameterObj.nbrReaches
Nat_Prod_rate = Prod_rate[0]
Tam_Prod_rate = Prod_rate[1]
Nat_Death_Rate = Death_Rate[0]
Tam_Death_Rate = Death_Rate[1]
nbr_samples = 1
result = np.zeros((nbr_samples, len(state)))
for sampling_idx in range(nbr_samples):
S_ad = np.zeros((len(state), 1))
rnd_v = random.rand(1, len(state))
for i in range(len(state)):
beforeDeath = state[i]
action_type = action[int(np.floor(i / H))]
afterDeath = 0
rnd = rnd_v[0, i]
if(action_type == InvasiveUtility.Not):
if (beforeDeath == InvasiveUtility.Emp):
afterDeath = InvasiveUtility.Emp
else:#(beforeDeath!=Emp)
if beforeDeath == InvasiveUtility.Tam and rnd <= Tam_Death_Rate:
afterDeath = InvasiveUtility.Emp
elif beforeDeath == InvasiveUtility.Nat and rnd <= Nat_Death_Rate:
afterDeath = InvasiveUtility.Emp
else:
afterDeath = beforeDeath
elif(action_type == InvasiveUtility.Erad):
if (beforeDeath == InvasiveUtility.Emp):
afterDeath = InvasiveUtility.Emp
else:#(beforeDeath!=Emp)
if (beforeDeath == InvasiveUtility.Tam):
if rnd <= eradication_rate:
afterDeath = InvasiveUtility.Emp
else:
afterDeath = beforeDeath
elif (beforeDeath == InvasiveUtility.Nat):
if rnd <= Nat_Death_Rate:
afterDeath = InvasiveUtility.Emp
else:
afterDeath = beforeDeath
elif(action_type == InvasiveUtility.EradRes):
if (beforeDeath == InvasiveUtility.Nat):
if rnd <= Nat_Death_Rate:
afterDeath = InvasiveUtility.Emp
else:
afterDeath = InvasiveUtility.Nat
elif(beforeDeath == InvasiveUtility.Tam):
if rnd <= eradication_rate * (1 - restoration_rate):
afterDeath = InvasiveUtility.Emp
elif rnd <= eradication_rate:
afterDeath = InvasiveUtility.Nat
else:
afterDeath = InvasiveUtility.Tam
elif(beforeDeath == InvasiveUtility.Emp):
afterDeath = InvasiveUtility.Emp
# if rnd <= (1 - restoration_rate):
# afterDeath = Invasive_Utility.Emp
# else:
# afterDeath = Invasive_Utility.Nat
elif(action_type == InvasiveUtility.Res):
if (beforeDeath == InvasiveUtility.Emp):
if rnd <= (1 - restoration_rate):
afterDeath = InvasiveUtility.Emp
else:
afterDeath = InvasiveUtility.Nat
else:#(beforeDeath!=Emp)
if beforeDeath == InvasiveUtility.Tam and rnd <= Tam_Death_Rate:
afterDeath = InvasiveUtility.Emp
elif beforeDeath == InvasiveUtility.Nat and rnd <= Nat_Death_Rate:
afterDeath = InvasiveUtility.Emp
else:
afterDeath = beforeDeath
S_ad[i] = afterDeath
G_T = Tam_Prod_rate * (S_ad == InvasiveUtility.Tam)
G_N = Nat_Prod_rate * (S_ad == InvasiveUtility.Nat)
G_T=sum(reshape(G_T,(nbr_Reaches,-1)),1)
G_N=sum(reshape(G_N,(nbr_Reaches,-1)),1)
Exg_T = 0
Exg_N = 0
if on_off_indicator == SimulationParameterClass.ExogenousArrivalOn:
if size(reach_arrival_rates) > 0:
Exg = binomial(reach_arrival_rates, reach_arrival_probs)
Exg_T = Exg[:, 1]
Exg_N = Exg[:, 0]
gT_to = np.sum(binomial(repmat(G_T, nbr_Reaches,1).T, dispertionTable), axis=0)
gN_to = sum(binomial(repmat(G_N, nbr_Reaches,1).T, dispertionTable), axis=0)
arr = array([gT_to + Exg_T, gN_to + Exg_N])
gt_vec = reshape(arr.conj().transpose(), (1, size(arr)))
#Germination Process
gt_vec[0:2:] = binomial(gt_vec[0:2:], germinationObj.germinationSuccTam)
gt_vec[1:2:] = binomial(gt_vec[1:2:], germinationObj.germinationSuccNat)
landed = repmat(gt_vec, H, 1)
new_S = binomial(landed, 1 / float(H))
final_S = np.zeros((len(state), 1), dtype='int')
for i in range(nbr_Reaches):
for h in range(H):
idx = H * i + h
si = S_ad[idx, 0]
ghT_land = new_S[h, 2 * i]
ghN_land = new_S[h, 2 * i + 1]
if (si == InvasiveUtility.Emp):
if (ghT_land == 0 and ghN_land == 0):
final_S[idx] = InvasiveUtility.Emp
else:
rnd = random.random()
Tam_p = beta * ghT_land / (beta * ghT_land + ghN_land)
if rnd <= Tam_p:
final_S[idx] = InvasiveUtility.Tam
else:
final_S[idx] = InvasiveUtility.Nat
else:
final_S[idx] = si
#new_S=final_S
final_S = np.squeeze(np.asarray(final_S))
if nbr_samples == 1:
return final_S
else:
result[sampling_idx, :] = final_S#.conj().transpose()
return result