-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsim.py
290 lines (228 loc) · 9.35 KB
/
sim.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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
import scipy.stats
from numpy import matrix, zeros, ones
import numpy
# Represents a group of people
class bunch:
# This is the total of the goods they want to consume
def total_goods_wanted(self):
all_goods = matrix(zeros(len(goods))) # matrix([[0,0,0,0]])
for person in self.people:
all_goods += person.goods_wanted
return all_goods
# This is their estimate for what is needed to produce
# their target in their industry
# (not that important -- not really used)
def average_production_input(self):
all_production_input = matrix(zeros(len(goods))) # matrix([[0,0,0,0]])
for person in self.people:
all_production_input += person.production_input
return all_production_input / len(self.people)
# Create a number of people
def __init__(self, number):
self.people = []
for i in range(number):
self.people += [person()]
# This is where we store the information about each industry
class Factory:
# Create a factory
def __init__(self, name, work_type, production_matrix, workers):
self.name = name
self.work_type = work_type # What proportions of work are nedded
self.production_matrix = production_matrix
self.workers = workers
for w in workers.people:
w.factory = self
self.plan = None
def production_output(self,production_input):
# This is a function that determines the means of production
# Can be the subject of discussion on the worker's council
# and determining it is the key aspect of worker's self-management
#
# Here we fake it by pretending it is a simple linear
# relationship between inputs and outputs.
return (self.production_matrix * production_input.transpose())
# This determines the needed inputs for the production
# and is the result of self-management
def production_input_total(self):
if self.plan is not None:
return self.plan
return self.workers.average_production_input()
# What all the workers want to consume
def total_consumption(self):
return self.workers.total_goods_wanted()
def production_output_total(self):
return self.production_output(self.production_input_total())
# How many people need to work in this factory
# (return the number of workers)
def units_of_work(self):
return len(self.workers.people)
# Do the maths to help compute prices...
def update_to_price_matrix(self):
# What we need to do the work
raw_materials = self.production_input_total()
raw_labour = (self.work_type * self.units_of_work())
all_raw = numpy.hstack((raw_materials,raw_labour))
# Outputs from the work
all_outputs = self.production_output_total()
all_outputs = numpy.vstack((all_outputs, zeros((len(goods),1))))
m = ((all_outputs* 1.0) / sum(all_outputs.flat)) * all_raw
for i in range(all_outputs.size):
m[i,i] += -1.0 * all_outputs[i]
# Now we sort out the consumption side of the matrix
consume = self.total_consumption()
#consume_all = numpy.hstack( (consume, zeros((1,4))) )
consume_all = zeros((1,len(goods)+len(tasks)))
work_all = numpy.hstack((zeros((1,len(tasks))), self.work_type))
w = work_all.transpose() * consume_all
total_work = self.units_of_work()
for i in range(work_all.size):
w[i,i] += work_all[0,i]
m = m + w
return m
# How much value is consumed and produced by this factory.
def factory_value(self,values):
# Inputs of production
raw_materials = self.production_input_total()
all_raw = numpy.hstack((raw_materials,zeros((1,len(tasks)))))
value_inputs = values.transpose() * all_raw.transpose()
value_inputs = value_inputs[0,0]
# Outputs from the work
all_outputs = self.production_output_total()
all_outputs = numpy.vstack((all_outputs, zeros((len(tasks),1))))
value_outputs = values.transpose() * all_outputs
value_outputs = value_outputs[0,0]
value_added = value_outputs - value_inputs
# Value added per unit labour
raw_labour = (self.work_type * self.units_of_work())
value_per_unit_work = value_added / sum(raw_labour.flat)
return value_inputs, value_outputs, value_added, value_per_unit_work
# The heart of ParEcon to determine prices
class Economy:
def __init__(self, factories):
self.factories = factories
# Goes through all factories and updates the price matrix
def price_matrix(self):
econ_size = len(goods) + len(tasks)
z = zeros((econ_size,econ_size))
for f in self.factories:
z += f.update_to_price_matrix()
return z
# Total goods produced by all industries
def total_production(self):
z = matrix(zeros(len(goods))).transpose()
for f in self.factories:
z += f.production_output_total()
return z.transpose()
# Total inputs needed by all industries
def total_inputs(self):
z = matrix(zeros(len(goods)))
for f in self.factories:
z += f.production_input_total()
return z
# Total goods needed by all people in the Economy
def total_consumption(self):
z = matrix(zeros(len(goods)))
for f in self.factories:
z += f.total_consumption()
return z
# Goods needed in the economy (industry + people + some slack)
def total_needed(self):
v = self.total_inputs() + self.total_consumption()
v = v * 1.05 # Allow a 5% slack
return v
# Calculate the price of all goods
def prices(self):
econ = self.price_matrix()
vals = numpy.hstack((zeros((1,len(goods))), ones((1,len(tasks)))))
prices = numpy.linalg.solve(econ, vals.transpose())
return prices
# The value of all industries in the economy
def value_of_industries(self):
p = self.prices()
print "prices: %s" % p.transpose()
for fac in self.factories:
(i_v, o_v, a_v, puw_v) = fac.factory_value(p)
print "%s\t%s\t%s\t%s\t%s" % (fac.name, i_v, o_v, a_v, puw_v)
# Instanciate a first economy
# Define the goods and tasks in the Economy
goods = ["Blue stuff", "Red stuff", "Purple stuff", "Colourless stuff"]
tasks = ["Extract Blue", "Extract Red", "Mix to purple", "Scrub to colourless"]
PRICES = 8 # how many things we value: goods + tasks
# Store the production matrices (pM is 4 x 8)
#
# pI: input production vector [ goods, tasks] -- 8 rows
# pO: outpur production [ goods ] -- 4 rows
# pI x pM = pO
production = {}
# Unit production matrices
#
# Describe in our model the relationship between inputs and production outputs
# (In reality this is the product of self management.)
#
production["Extract Blue"] = matrix([[10, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0] ])
production["Extract Red"] = matrix([[0, 0, 0, 0],
[0, 10, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]])
production["Mix"] = matrix([[0,0,0,0],
[0,0,0,0],
[1,1,0,0],
[0,0,0,0] ])
production["Scrub"] = matrix([[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[1,1,1,0] ])
# Define a person and their "needs"
class person:
def __init__(self):
# These are determined by a utility function
# (fix them for this silly example)
self.goods_wanted = matrix([[5, 5, 5, 5]])
self.goods_received = matrix([[0, 0, 0, 0]]).transpose()
# This is the initial 'guess' of this person regarding what is needed
# for their workplace to meet their production output.
self.production_input = matrix([[50, 0, 0, 0]])
# Where do I work?
self.factory = None # determine this by bunch
# Factory syndicates
blue_bunch = bunch(10)
red_bunch = bunch(10)
purple_bunch = bunch(10)
shitbleach_bunch = bunch(10)
blue_factory = Factory("Blue & co",
matrix([1,0,0,0]),
production["Extract Blue"],
blue_bunch)
blue_factory.plan = matrix([[50, 0, 0, 0]])
red_factory = Factory("Red'r'us",
matrix([0,1,0,0]),
production["Extract Red"],
red_bunch)
red_factory.plan = matrix([[0, 50, 0, 0]])
purple_factory = Factory("McPurple",
matrix([0,0,1,0]),
production["Mix"],
purple_bunch)
purple_factory.plan = matrix([[110,110,0,0]])
bleach_factory = Factory("Whitewash & Son",
matrix([0,0,0,1]),
production["Scrub"],
shitbleach_bunch)
bleach_factory.plan = matrix([[105,105,0,0]])
# The whole economy:
# -----------------
# Make an economy out of all the factories
myFirstEconomy = Economy([blue_factory, red_factory, purple_factory, bleach_factory])
# Compute all the prices for this economy
econ = myFirstEconomy.price_matrix()
# Print how much each factory is getting in and getting out
myFirstEconomy.value_of_industries()
# Print out the needed goods and produced goods (to detect deficit)
print "PRODUCTION: %s" % myFirstEconomy.total_production()
print "NEEDED: %s" % myFirstEconomy.total_needed()
# Determine if the budget of workers satisfies their needs
worker_budget = matrix([[5,5,5,5,0,0,0,0]]) * myFirstEconomy.prices()
print "Worker budget: %s" % worker_budget