modelflowib 2.73__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelBLfunk.py +180 -0
- model_Excel.py +332 -0
- model_cvx.py +139 -0
- model_dynare.py +173 -0
- model_financial_stability.py +88 -0
- model_latex.py +497 -0
- model_latex_class.py +808 -0
- model_parquet_mixin.py +424 -0
- modelclass.py +9828 -0
- modelconstruct.py +1496 -0
- modelconstruct_estimation.py +2872 -0
- modeldash.py +265 -0
- modeldashboot.py +202 -0
- modeldashsidebar.py +456 -0
- modeldekom.py +651 -0
- modeldiff.py +561 -0
- modeldisplay.py +550 -0
- modelestimation.py +1776 -0
- modelestimator_new.py +2613 -0
- modelflowib-2.73.dist-info/METADATA +156 -0
- modelflowib-2.73.dist-info/RECORD +44 -0
- modelflowib-2.73.dist-info/WHEEL +5 -0
- modelflowib-2.73.dist-info/licenses/license.md +10 -0
- modelflowib-2.73.dist-info/top_level.txt +39 -0
- modelgrab.py +318 -0
- modelgrabgdx.py +584 -0
- modelgrabwf2.py +1107 -0
- modelhelp.py +543 -0
- modelhtml.py +606 -0
- modelinvert.py +250 -0
- modeljupyter.py +824 -0
- modeljupytermagic.py +813 -0
- modelmacrograb.py +98 -0
- modelmanipulation.py +1461 -0
- modelmf.py +349 -0
- modelnet.py +114 -0
- modelnewton.py +2178 -0
- modelnormalize.py +430 -0
- modelpattern.py +428 -0
- modelreport.py +2187 -0
- modeluserfunk.py +97 -0
- modelvis.py +1038 -0
- modelwidget.py +718 -0
- modelwidget_input.py +1933 -0
modelmanipulation.py
ADDED
|
@@ -0,0 +1,1461 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Mon Sep 02 19:41:11 2013
|
|
4
|
+
|
|
5
|
+
This module is a textprocessing module which is used to transforms a *template model* for a generic bank into into a unrolled and
|
|
6
|
+
expande model which covers all banks - under control of a list feature.
|
|
7
|
+
|
|
8
|
+
The resulting model can be solved after beeing proccesed in the *modelclass* module.
|
|
9
|
+
|
|
10
|
+
In addition to creating a model for forecasting, the module can also create a model which calculates residulas and and variables
|
|
11
|
+
in historic periods. This model can also be solved by the *modelclass* module.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@author: Ib
|
|
16
|
+
"""
|
|
17
|
+
import re
|
|
18
|
+
from collections import defaultdict
|
|
19
|
+
from collections import namedtuple
|
|
20
|
+
from itertools import groupby,chain
|
|
21
|
+
from sympy import solve, sympify
|
|
22
|
+
import ast
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
from modelpattern import find_statements,split_frml,find_frml,list_extract,udtryk_parse,kw_frml_name,commentchar,split_frml_reqopts
|
|
28
|
+
from modelhelp import debug_var
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class oldsafesub(dict):
|
|
32
|
+
'''A subclass of dict.
|
|
33
|
+
if a *safesub* is indexed by a nonexisting keyword it just return the keyword
|
|
34
|
+
this alows missing keywords when substitution text inspired by Python cookbook '''
|
|
35
|
+
|
|
36
|
+
def __missing__(self, key):
|
|
37
|
+
return '{' + key +'}'
|
|
38
|
+
|
|
39
|
+
class safesub(dict):
|
|
40
|
+
'''A subclass of dict.
|
|
41
|
+
if a *safesub* is indexed by a nonexisting keyword it just return the keyword
|
|
42
|
+
|
|
43
|
+
- key-<number> where key is in integer returns the numeric value of key-number
|
|
44
|
+
- key+<number> where key is in integer returns the numeric value of key+number
|
|
45
|
+
-
|
|
46
|
+
|
|
47
|
+
this alows missing keywords when substitution text inspired by Python cookbook '''
|
|
48
|
+
|
|
49
|
+
def __missing__(self, key):
|
|
50
|
+
# breakpoint()
|
|
51
|
+
if '-' in key:
|
|
52
|
+
try:
|
|
53
|
+
testkey,ofset = key.split('-')
|
|
54
|
+
res = f'{str(int(self.get(testkey.strip()))-int(ofset))}'
|
|
55
|
+
return res
|
|
56
|
+
|
|
57
|
+
except:
|
|
58
|
+
print(f'Wrong key or value in list ofset:<{key}>')
|
|
59
|
+
raise
|
|
60
|
+
|
|
61
|
+
if '+' in key:
|
|
62
|
+
try:
|
|
63
|
+
testkey,ofset = key.split('+')
|
|
64
|
+
res = f'{str(int(self.get(testkey.strip()))+int(ofset))}'
|
|
65
|
+
return res
|
|
66
|
+
|
|
67
|
+
except:
|
|
68
|
+
print(f'Wrong key or value in list ofset:<{key}>')
|
|
69
|
+
raise
|
|
70
|
+
return '{' + key +'}'
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def sub(text, katalog):
|
|
75
|
+
'''Substitutes keywords from dictionary by returning
|
|
76
|
+
text.format_map(safesub(katalog))
|
|
77
|
+
Allows missing keywords by using safesub subclass'''
|
|
78
|
+
return text.format_map(safesub(katalog))
|
|
79
|
+
|
|
80
|
+
def oldsub_frml(ibdic, text, plus='', var='', lig='', sep='\n'):
|
|
81
|
+
''' to repeat substitution from list
|
|
82
|
+
|
|
83
|
+
* *plus* is a seperator, used for creating sums \n
|
|
84
|
+
|
|
85
|
+
* *var* and *lig* Determins for which items the substitution should take place
|
|
86
|
+
by var=abe, lig='ko' substitution is only performed for entries where var=='ko' '''
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
katalog = dict()
|
|
90
|
+
outlist = []
|
|
91
|
+
try:
|
|
92
|
+
keys = [k for k in ibdic.keys()] # find keywords
|
|
93
|
+
# print('var, lig',var,lig)'
|
|
94
|
+
if var == '':
|
|
95
|
+
values = select = ibdic[keys[0]] # no selection criteri
|
|
96
|
+
elif lig != '':
|
|
97
|
+
# We have a selecton criteria and select the situations where it apply
|
|
98
|
+
values = ibdic[var] # the values for thes sublist
|
|
99
|
+
select = [t for t in values if t == lig]
|
|
100
|
+
for taller, k in enumerate(values): # loop over number of values
|
|
101
|
+
if k in select:
|
|
102
|
+
for j in ibdic.keys(): # for each keywords
|
|
103
|
+
ud = ibdic.get(j)
|
|
104
|
+
# print('*****************test',j,taller)
|
|
105
|
+
katalog[j] = ud[taller]
|
|
106
|
+
# make a list with the new text
|
|
107
|
+
outlist.append(sub(text, katalog) + sep)
|
|
108
|
+
except:
|
|
109
|
+
print('***** problem',ibdic, '<'+text+ '>')
|
|
110
|
+
print(' ')
|
|
111
|
+
return plus.join(outlist)
|
|
112
|
+
|
|
113
|
+
def sub_frml(ibdic, text, plus='', xvar='', lig='', sep='\n'):
|
|
114
|
+
''' to repeat substitution from list
|
|
115
|
+
|
|
116
|
+
* *plus* is a seperator, used for creating sums \n
|
|
117
|
+
|
|
118
|
+
* *xvar* and *lig* Determins for which items the substitution should take place
|
|
119
|
+
by var=abe, lig='ko' substitution is only performed for entries where var=='ko'
|
|
120
|
+
|
|
121
|
+
* *xvar* is the variable to chek against selected in list
|
|
122
|
+
* *select list* is a list of elements in the xvar list to be included
|
|
123
|
+
* *matc* is the entry in *select list* from which to select from xvar
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
'''
|
|
127
|
+
# print(f'{text=}')
|
|
128
|
+
# print(f'{ibdic=}')
|
|
129
|
+
katalog = dict()
|
|
130
|
+
outlist = []
|
|
131
|
+
try:
|
|
132
|
+
keys = [k for k in ibdic.keys()] # find keywords
|
|
133
|
+
# print('var, lig',xvar,lig)
|
|
134
|
+
if xvar == '':
|
|
135
|
+
values = select = ibdic[keys[0]] # no selection criteri
|
|
136
|
+
else:
|
|
137
|
+
if xvar not in list(ibdic.keys()):
|
|
138
|
+
raise Exception(f'**** Trying to condition on a sublist which is not there\nCondition:{xvar}\nAllowed sublists:{list(ibdic.keys())}')
|
|
139
|
+
values = ibdic[xvar]
|
|
140
|
+
if lig != '':
|
|
141
|
+
# We have a selecton criteria and select the situations where it apply
|
|
142
|
+
select = [t for t in values if t == lig]
|
|
143
|
+
# print('values:',[t for t in values])
|
|
144
|
+
for taller, k in enumerate(values): # loop over number of values in the list
|
|
145
|
+
katalog={}
|
|
146
|
+
if k in select:
|
|
147
|
+
katalog = {j: ibdic.get(j)[taller] for j in ibdic.keys()}
|
|
148
|
+
outlist.append(sub(text, katalog) + sep)
|
|
149
|
+
# print('>',katalog)
|
|
150
|
+
# print(err1)
|
|
151
|
+
except:
|
|
152
|
+
err1 = f'**** when substitution in formulas:\nDictionary from which values are taken:\n{ibdic}\n{text=} \nSelection:{xvar} == {lig}\n{katalog=}'
|
|
153
|
+
raise Exception(err1)
|
|
154
|
+
return plus.join(outlist)
|
|
155
|
+
|
|
156
|
+
a={'bankdic': {'bank':['Danske','Nordea'],'danske':['yes','no'],'nordisk':['yes','no']}}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def find_res(f):
|
|
160
|
+
''' Finds the expression which calculates the residual in a formel. FRML <res=a,endo=b> x=a*b+c $ '''
|
|
161
|
+
from sympy import solve, sympify
|
|
162
|
+
a, fr, n, udtryk = split_frml(f.upper())
|
|
163
|
+
udres = ''
|
|
164
|
+
tres = kw_frml_name(n, 'RES')
|
|
165
|
+
if tres:
|
|
166
|
+
lhs, rhs = udtryk.split('=', 1)
|
|
167
|
+
res = lhs.strip() + '_J' if tres == 'J' else lhs.strip() + \
|
|
168
|
+
'_JR' if tres == 'JR' else tres
|
|
169
|
+
# we take the the $ out
|
|
170
|
+
kat = sympify('Eq(' + lhs + ',' + rhs[0:-1] + ')')
|
|
171
|
+
res_frml = sympify('res_frml')
|
|
172
|
+
res_frml = solve(kat, res)
|
|
173
|
+
udres = 'FRML ' + 'RES' + ' ' + \
|
|
174
|
+
res.ljust(25) + ' = ' + str(res_frml)[1:-1] + ' $'
|
|
175
|
+
return udres
|
|
176
|
+
|
|
177
|
+
def find_res_dynare(equations):
|
|
178
|
+
''' equations to calculat _res formulas
|
|
179
|
+
FRML <> x=a*b+c +x_RES $ -> FRML <> x_res =x-a*b+c $'''
|
|
180
|
+
from sympy import solve, sympify
|
|
181
|
+
out=[]
|
|
182
|
+
for f in find_frml(equations):
|
|
183
|
+
a, fr, n, udtryk = split_frml(f.upper())
|
|
184
|
+
lhs, rhs = udtryk.split('=', 1)
|
|
185
|
+
res= lhs.strip()+'_RES'
|
|
186
|
+
if res in rhs:
|
|
187
|
+
# we take the the $ out
|
|
188
|
+
kat = sympify('Eq(' + lhs + ',' + rhs[0:-1] + ')')
|
|
189
|
+
res_frml = sympify('res_frml')
|
|
190
|
+
res_frml = solve(kat, res)
|
|
191
|
+
udres = 'FRML ' + 'RES' + ' ' + res + ' = ' + str(res_frml)[1:-1] + ' $'
|
|
192
|
+
out.append(udres)
|
|
193
|
+
return '\n'.join(out)
|
|
194
|
+
|
|
195
|
+
def find_res_dynare_new(equations):
|
|
196
|
+
''' equations to calculat _res formulas
|
|
197
|
+
FRML <> x=a*b+c +x_RES $ -> FRML <> x_res =x-a*b+c $
|
|
198
|
+
not finished to speed time up '''
|
|
199
|
+
out=[]
|
|
200
|
+
for f in find_frml(equations):
|
|
201
|
+
a, fr, n, udtryk = split_frml(f.upper())
|
|
202
|
+
lhs,rhs=udtryk.split('=',1)
|
|
203
|
+
lhs = lhs.strip()
|
|
204
|
+
rhs=rhs.strip()[:-1]
|
|
205
|
+
res= lhs+'_RES'
|
|
206
|
+
if res in rhs:
|
|
207
|
+
rep = rhs.replace(res,'').strip()[:-1]
|
|
208
|
+
new = f'frml <> {res} = {lhs} - ({rep}) $'
|
|
209
|
+
out.append(new)
|
|
210
|
+
|
|
211
|
+
return '\n'.join(out)
|
|
212
|
+
|
|
213
|
+
def find_hist_model(equations):
|
|
214
|
+
''' takes a unrolled model and create a model which can be run for historic periode \n
|
|
215
|
+
and the identities are also calculeted'''
|
|
216
|
+
hist = []
|
|
217
|
+
for f in find_frml(equations):
|
|
218
|
+
a, fr, n, udtryk = split_frml(f.upper())
|
|
219
|
+
if kw_frml_name(n, 'IDENT') or kw_frml_name(n, 'I'):
|
|
220
|
+
# identites are just replicated in order to calculate backdata
|
|
221
|
+
hist.append(f.strip())
|
|
222
|
+
return('\n'.join(hist))
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def exounroll(in_equations):
|
|
226
|
+
''' takes a model and makes a new model by enhancing frml's with <exo=,j=,jr=>
|
|
227
|
+
in their frml name.
|
|
228
|
+
|
|
229
|
+
:exo: the value can be fixed in to a value valuename_x by setting valuename_d=1
|
|
230
|
+
|
|
231
|
+
:jled: a additiv adjustment element is added to the frml
|
|
232
|
+
|
|
233
|
+
:jrled: a multiplicativ adjustment element is added to the frml
|
|
234
|
+
'''
|
|
235
|
+
|
|
236
|
+
nymodel = []
|
|
237
|
+
equations = in_equations[:] # we want do change the e
|
|
238
|
+
for comment, command, value in find_statements(equations.upper()):
|
|
239
|
+
# print('>>',comment,'<',command,'>',value)
|
|
240
|
+
if comment:
|
|
241
|
+
nymodel.append(comment)
|
|
242
|
+
elif command == 'FRML':
|
|
243
|
+
a, fr, n, udtryk = split_frml((command + ' ' + value).upper())
|
|
244
|
+
#print(fr,n, kw_frml_name(n.upper(),'EXO'))
|
|
245
|
+
# we want a relatov adjustment
|
|
246
|
+
if kw_frml_name(n, 'JRLED') or kw_frml_name(n, 'JR'):
|
|
247
|
+
lhs, rhs = udtryk.split('=', 1)
|
|
248
|
+
udtryk = lhs + \
|
|
249
|
+
'= (' + rhs[:-1] + ')*(1+' + lhs.strip() + '_JR )' + '$'
|
|
250
|
+
if kw_frml_name(n, 'JLED') or kw_frml_name(n, 'J'):
|
|
251
|
+
lhs, rhs = udtryk.split('=', 1)
|
|
252
|
+
# we want a absolute adjustment
|
|
253
|
+
udtryk = lhs + '=' + rhs[:-1] + '+' + lhs.strip() + '_J' + '$'
|
|
254
|
+
if kw_frml_name(n, 'EXO'):
|
|
255
|
+
lhs, rhs = udtryk.split('=', 1)
|
|
256
|
+
endogen = lhs.strip()
|
|
257
|
+
dummy = endogen + '_D'
|
|
258
|
+
exogen = endogen + '_X'
|
|
259
|
+
udtryk = lhs + \
|
|
260
|
+
'=(' + rhs[:-1] + ')*(1-' + dummy + ')+' + exogen + '*' + dummy + '$'
|
|
261
|
+
|
|
262
|
+
nymodel.append(command + ' ' + n + ' ' + udtryk)
|
|
263
|
+
else:
|
|
264
|
+
nymodel.append(command + ' ' + value)
|
|
265
|
+
|
|
266
|
+
equations = '\n'.join(nymodel)
|
|
267
|
+
return equations
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def tofrml(expressions,sep='\n'):
|
|
272
|
+
''' a function, wich adds FRML to all expressions seperated by <sep>
|
|
273
|
+
if no start is specified the max lag will be used '''
|
|
274
|
+
|
|
275
|
+
notrans = {'DO','ENDDO','LIST','FRML','DOABLE'}
|
|
276
|
+
|
|
277
|
+
def trans(eq):
|
|
278
|
+
test= eq.strip().upper()+' '
|
|
279
|
+
if len(test.strip()) == 0:
|
|
280
|
+
return ''
|
|
281
|
+
if test.split()[0] in notrans:
|
|
282
|
+
return eq + '$'
|
|
283
|
+
elif test[0] == commentchar:
|
|
284
|
+
return eq
|
|
285
|
+
else:
|
|
286
|
+
return ('FRML ' + (eq if test.startswith('<') else ' <> ' +eq) +' $' )
|
|
287
|
+
|
|
288
|
+
# debug_var(expressions)
|
|
289
|
+
if '$' in expressions:
|
|
290
|
+
return expressions
|
|
291
|
+
else:
|
|
292
|
+
# exp = re.sub(commentchar+'!(.*)\n',r'!\1\n',expressions)
|
|
293
|
+
eqlist = [trans(e) for e in expressions.split(sep)]
|
|
294
|
+
# debug_var(expressions.split(sep))
|
|
295
|
+
return '\n'.join(eqlist)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def dounloop(in_equations,listin=False):
|
|
299
|
+
''' Expands (unrolls do loops in a model template
|
|
300
|
+
goes trough a model template until there is no more nested do loops '''
|
|
301
|
+
equations = in_equations[:].upper() # we want do change the equations
|
|
302
|
+
# print(f'equations \n{equations} \n ')
|
|
303
|
+
liste_dict = listin if listin else list_extract(equations) # Search the whold model for lists
|
|
304
|
+
rest = 1
|
|
305
|
+
while rest: # We want to eat all doo loops
|
|
306
|
+
nymodel = []
|
|
307
|
+
domodel = []
|
|
308
|
+
dolevel = 0
|
|
309
|
+
rest = 0
|
|
310
|
+
liste_name, liste_key, liste_select = '', '', ''
|
|
311
|
+
for comment, command, value in find_statements(equations):
|
|
312
|
+
# print('>>',comment,'<',command,'>',value)
|
|
313
|
+
if command.upper() == 'DO':
|
|
314
|
+
dolevel = dolevel + 1
|
|
315
|
+
if dolevel >= 2:
|
|
316
|
+
rest = 1 # do we have more doolops
|
|
317
|
+
domodel.append(command + ' ' + value)
|
|
318
|
+
#=========================================================================
|
|
319
|
+
# else: # find listname key=select
|
|
320
|
+
#=========================================================================
|
|
321
|
+
elif dolevel == 1:
|
|
322
|
+
liste_name = [
|
|
323
|
+
t.strip().upper() for t in re.split(
|
|
324
|
+
r'[\s,]\s*',
|
|
325
|
+
value[:-1]) if t != '']
|
|
326
|
+
current_dict = liste_dict[liste_name[0]]
|
|
327
|
+
# print('listenavn ',liste_name, current_dict)
|
|
328
|
+
#ibdic, text, plus='', xvar='', lig='', sep='\n',selectlist=None,match=''
|
|
329
|
+
if len(liste_name) == 1:
|
|
330
|
+
liste_key, liste_select = '', ''
|
|
331
|
+
elif len(liste_name) == 4:
|
|
332
|
+
liste_key, liste_select = liste_name[1], liste_name[3]
|
|
333
|
+
# current_dict=liste_dict[value[0:-2].strip()] # find the name of the list
|
|
334
|
+
else:
|
|
335
|
+
raise Exception(f' *** error in DO statement either 1 or 4 arguments:\n{comment=}\n{command=}\nArguments= {value}')
|
|
336
|
+
domodel = []
|
|
337
|
+
elif(command.upper() == 'ENDDO'):
|
|
338
|
+
dolevel = dolevel - 1
|
|
339
|
+
if dolevel == 0:
|
|
340
|
+
if len(liste_name) == 1 or len(liste_name) == 4 or len(liste_name) == 5 :
|
|
341
|
+
ibsud = sub_frml(current_dict, '\n'.join(domodel),plus='',sep='\n',
|
|
342
|
+
xvar=liste_key, lig=liste_select)
|
|
343
|
+
else:
|
|
344
|
+
print('Fejl i liste', liste_name)
|
|
345
|
+
print('Ibsud>',ibsud)
|
|
346
|
+
nymodel.append('\n' + ibsud + '\n')
|
|
347
|
+
elif dolevel >= 1:
|
|
348
|
+
domodel.append(command + ' ' + value + '\n')
|
|
349
|
+
elif dolevel >= 1: # a command to store for do looping
|
|
350
|
+
if comment:
|
|
351
|
+
domodel.append(comment + '')
|
|
352
|
+
else:
|
|
353
|
+
domodel.append(command + ' ' + value)
|
|
354
|
+
else: # a command outside a dooloop
|
|
355
|
+
if comment:
|
|
356
|
+
nymodel.append(comment)
|
|
357
|
+
else:
|
|
358
|
+
nymodel.append(command + ' ' + value)
|
|
359
|
+
equations = '\n'.join(nymodel)
|
|
360
|
+
return equations
|
|
361
|
+
|
|
362
|
+
#%
|
|
363
|
+
def find_arg(funk, streng):
|
|
364
|
+
''' chops a string in 3 parts \n
|
|
365
|
+
1. before 'funk('
|
|
366
|
+
|
|
367
|
+
2. in the matching parantesis
|
|
368
|
+
|
|
369
|
+
3. after the last matching parenthesis '''
|
|
370
|
+
tfunk, tstreng = funk.upper(), streng.upper()
|
|
371
|
+
tfunk = tfunk + '('
|
|
372
|
+
if tfunk in tstreng:
|
|
373
|
+
start = tstreng.find(tfunk)
|
|
374
|
+
match = tstreng[start + len(tfunk):]
|
|
375
|
+
open = 1
|
|
376
|
+
for index in range(len(match)):
|
|
377
|
+
if match[index] in '()':
|
|
378
|
+
open = (open + 1) if match[index] == '(' else (open - 1)
|
|
379
|
+
if not open:
|
|
380
|
+
return tstreng[:start], match[:index], match[index + 1:]
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def sumunroll_old(in_equations,listin=False):
|
|
384
|
+
''' expands all sum(list,'expression') in a model
|
|
385
|
+
returns a new model'''
|
|
386
|
+
nymodel = []
|
|
387
|
+
equations = in_equations[:].upper() # we want do change the e
|
|
388
|
+
liste_dict = listin if listin else list_extract(equations) # Search the whold model for lists
|
|
389
|
+
for comment, command, value in find_statements(equations):
|
|
390
|
+
# print('>>',comment,'<',command,'>',value)
|
|
391
|
+
if comment:
|
|
392
|
+
nymodel.append(comment)
|
|
393
|
+
else:
|
|
394
|
+
while 'SUM(' in value.upper():
|
|
395
|
+
forsum, sumudtryk, eftersum = find_arg('sum', value.upper())
|
|
396
|
+
sumover, sumled = sumudtryk.split(',', 1)
|
|
397
|
+
current_dict = liste_dict[sumover]
|
|
398
|
+
ibsud = sub_frml(current_dict, sumled, '+', '', sep='')
|
|
399
|
+
value = forsum + '(' + ibsud + ')' + eftersum
|
|
400
|
+
nymodel.append(command + ' ' + value)
|
|
401
|
+
equations = '\n'.join(nymodel)
|
|
402
|
+
return equations
|
|
403
|
+
|
|
404
|
+
def lagarray_unroll(in_equations,funks=[]):
|
|
405
|
+
''' expands all sum(list,'expression') in a model
|
|
406
|
+
returns a new model'''
|
|
407
|
+
nymodel = []
|
|
408
|
+
equations = in_equations[:].upper() # we want do change the e
|
|
409
|
+
for comment, command, value in find_statements(equations):
|
|
410
|
+
# print('>>',comment,'<',command,'>',value)
|
|
411
|
+
if comment:
|
|
412
|
+
nymodel.append(comment)
|
|
413
|
+
else:
|
|
414
|
+
while 'LAG_ARRAY(' in value:
|
|
415
|
+
forlag, lagudtryk, efterlag = find_arg('LAG_ARRAY', value.upper())
|
|
416
|
+
lagnumber, lagled = lagudtryk.split(',', 1)
|
|
417
|
+
ibsud = lag_n_tup(lagled,int(lagnumber),funks=funks)
|
|
418
|
+
value = forlag + 'ARRAY([' + ibsud + '])' + efterlag
|
|
419
|
+
nymodel.append(command + ' ' + value)
|
|
420
|
+
equations = '\n'.join(nymodel)
|
|
421
|
+
return equations
|
|
422
|
+
|
|
423
|
+
def sumunroll(in_equations,listin=False):
|
|
424
|
+
''' expands all sum(list,'expression') in a model
|
|
425
|
+
if sum(list xvar=lig,'expression') only list elements where the condition is
|
|
426
|
+
satisfied wil be summed
|
|
427
|
+
|
|
428
|
+
returns a new model'''
|
|
429
|
+
nymodel = []
|
|
430
|
+
equations = in_equations[:].upper() # we want do change the e
|
|
431
|
+
liste_dict = listin if listin else list_extract(equations) # Search the whold model for lists
|
|
432
|
+
for comment, command, value in find_statements(equations):
|
|
433
|
+
# print('>>',comment,'<',command,'>',value)
|
|
434
|
+
if comment:
|
|
435
|
+
nymodel.append(comment)
|
|
436
|
+
else:
|
|
437
|
+
while 'SUM(' in value.upper():
|
|
438
|
+
forsum, sumudtryk, eftersum = find_arg('sum', value.upper())
|
|
439
|
+
suminit, sumled = sumudtryk.split(',', 1)
|
|
440
|
+
|
|
441
|
+
if '=' in suminit:
|
|
442
|
+
sumover,remain = suminit.split(' ',1)
|
|
443
|
+
xvar,lig =remain.replace(' ','').split('=')
|
|
444
|
+
elif ' ' in suminit.strip():
|
|
445
|
+
sumover,remain = suminit.split(' ',1)
|
|
446
|
+
xvar =remain.replace(' ','')
|
|
447
|
+
lig = '1'
|
|
448
|
+
else:
|
|
449
|
+
sumover = suminit
|
|
450
|
+
xvar=''
|
|
451
|
+
lig=''
|
|
452
|
+
|
|
453
|
+
current_dict = liste_dict[sumover.strip()]
|
|
454
|
+
ibsud = sub_frml(current_dict, sumled, '+', xvar=xvar,lig=lig,sep='')
|
|
455
|
+
value = forsum + '(' + ibsud + ')' + eftersum
|
|
456
|
+
nymodel.append(command + ' ' + value)
|
|
457
|
+
equations = '\n'.join(nymodel)
|
|
458
|
+
return equations
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def funkunroll(in_equations,funk='MAX',listin=False,replacefunk=''):
|
|
462
|
+
"""
|
|
463
|
+
Expands all funk(list, 'expression') in a model.
|
|
464
|
+
|
|
465
|
+
If funk(list xvar=lig, 'expression') is used, only list elements where the condition is
|
|
466
|
+
satisfied will be summed.
|
|
467
|
+
|
|
468
|
+
Parameters:
|
|
469
|
+
in_equations (str): A string representing the model to be modified.
|
|
470
|
+
funk (str, optional): The name of the function to be expanded. Defaults to 'MAX'.
|
|
471
|
+
listin (list, optional): A list of dictionaries representing the lists in the model.
|
|
472
|
+
If not provided, the function will search the model for lists.
|
|
473
|
+
replacefunk (str, optional): The name of the function to replace the expanded funk.
|
|
474
|
+
If not provided, the original name will be used.
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
str: A string representing the modified model.
|
|
478
|
+
"""
|
|
479
|
+
|
|
480
|
+
nymodel = []
|
|
481
|
+
equations = in_equations[:].upper() # we want do change the e
|
|
482
|
+
liste_dict = listin if listin else list_extract(equations) # Search the whold model for lists
|
|
483
|
+
for comment, command, value in find_statements(equations):
|
|
484
|
+
# print('>>',comment,'<',command,'>',value)
|
|
485
|
+
if comment:
|
|
486
|
+
nymodel.append(comment)
|
|
487
|
+
else:
|
|
488
|
+
hit=False
|
|
489
|
+
while f'{funk.upper()}(' in value.upper():
|
|
490
|
+
hit=True
|
|
491
|
+
forsum, sumudtryk, eftersum = find_arg(f'{funk.upper()}', value.upper())
|
|
492
|
+
suminit, sumled = sumudtryk.split(',', 1)
|
|
493
|
+
|
|
494
|
+
if '=' in suminit:
|
|
495
|
+
sumover,remain = suminit.split(' ',1)
|
|
496
|
+
xvar,lig =remain.replace(' ','').split('=')
|
|
497
|
+
else:
|
|
498
|
+
sumover = suminit
|
|
499
|
+
xvar=''
|
|
500
|
+
lig=''
|
|
501
|
+
|
|
502
|
+
current_dict = liste_dict[sumover.strip()]
|
|
503
|
+
# print(f'{value=}')
|
|
504
|
+
ibsud = sub_frml(current_dict, sumled, ',', xvar=xvar,lig=lig,sep='')
|
|
505
|
+
value = forsum + 'xxxx_funk_ibhansen(' + ibsud + ')' + eftersum # as we dont replace the funk name
|
|
506
|
+
if hit:
|
|
507
|
+
nymodel.append(f'{command} {value}'.replace('xxxx_funk_ibhansen',replacefunk if replacefunk else funk))
|
|
508
|
+
else:
|
|
509
|
+
nymodel.append(command + ' ' + value)
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
equations = '\n'.join(nymodel)
|
|
513
|
+
# print(equations)
|
|
514
|
+
return equations
|
|
515
|
+
|
|
516
|
+
# print(funkunroll(dounloop(
|
|
517
|
+
# '''list BANKDIC = bank : Danske , Nordea $
|
|
518
|
+
# do BANKDIC $
|
|
519
|
+
# frml x {bank}_income = {bank}_a +{bank}_b $
|
|
520
|
+
# enddo $
|
|
521
|
+
# frml x ialt=max(bankdic,{bank}_income) $''')))
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def argunroll(in_equations,listin=False):
|
|
525
|
+
''' expands all ARGEXPAND(list,'expression') in a model
|
|
526
|
+
returns a new model'''
|
|
527
|
+
nymodel = []
|
|
528
|
+
equations = in_equations[:].upper() # we want do change the e
|
|
529
|
+
liste_dict = listin if listin else list_extract(equations) # Search the whold model for lists
|
|
530
|
+
for comment, command, value in find_statements(equations):
|
|
531
|
+
# print('>>',comment,'<',command,'>',value)
|
|
532
|
+
if comment:
|
|
533
|
+
nymodel.append(comment)
|
|
534
|
+
else:
|
|
535
|
+
while 'ARGEXPAND(' in value.upper():
|
|
536
|
+
forsum, sumudtryk, eftersum = find_arg('ARGEXPAND', value.upper())
|
|
537
|
+
sumover, sumled = sumudtryk.split(',', 1)
|
|
538
|
+
current_dict = liste_dict[sumover]
|
|
539
|
+
ibsud = sub_frml(current_dict, sumled, ',', '', sep='')
|
|
540
|
+
value = forsum + '' + ibsud + '' + eftersum
|
|
541
|
+
nymodel.append(command + ' ' + value)
|
|
542
|
+
equations = '\n'.join(nymodel)
|
|
543
|
+
return equations
|
|
544
|
+
|
|
545
|
+
def creatematrix(in_equations,listin=False):
|
|
546
|
+
''' expands all ARGEXPAND(list,'expression') in a model
|
|
547
|
+
returns a new model'''
|
|
548
|
+
nymodel = []
|
|
549
|
+
equations = in_equations[:].upper() # we want do change the e
|
|
550
|
+
liste_dict = listin if listin else list_extract(equations) # Search the whold model for lists
|
|
551
|
+
for comment, command, value in find_statements(equations):
|
|
552
|
+
# print('>>',comment,'<',command,'>',value)
|
|
553
|
+
if comment:
|
|
554
|
+
nymodel.append(comment)
|
|
555
|
+
else:
|
|
556
|
+
while 'TO_MATRIX(' in value.upper():
|
|
557
|
+
forcreate, createudtryk, eftercreate = find_arg('TO_MATRIX', value.upper())
|
|
558
|
+
temp = createudtryk.split(',', 2)
|
|
559
|
+
mat_name = temp[-1]
|
|
560
|
+
create_row = temp[0]
|
|
561
|
+
row_dict = liste_dict[create_row]
|
|
562
|
+
if len(temp)==2:
|
|
563
|
+
ibsud = '['+sub_frml(row_dict, mat_name, ',', '', sep='')+']'
|
|
564
|
+
else:
|
|
565
|
+
create_column= temp[1]
|
|
566
|
+
column_dict = liste_dict[create_column]
|
|
567
|
+
ibsud0 = '['+sub_frml(column_dict, mat_name, ',', '', sep='')+']'
|
|
568
|
+
ibsud = '['+sub_frml(row_dict, ibsud0 , ',\n', '', sep='')+']'
|
|
569
|
+
|
|
570
|
+
value = forcreate + 'matrix(\n' + ibsud + ')' + eftercreate
|
|
571
|
+
nymodel.append(command + ' ' + value)
|
|
572
|
+
equations = '\n'.join(nymodel)
|
|
573
|
+
return equations
|
|
574
|
+
def createarray(in_equations,listin=False):
|
|
575
|
+
''' expands all to_array(list) in a model
|
|
576
|
+
returns a new model'''
|
|
577
|
+
nymodel = []
|
|
578
|
+
equations = in_equations[:].upper() # we want do change the e
|
|
579
|
+
liste_dict = listin if listin else list_extract(equations) # Search the whold model for lists
|
|
580
|
+
for comment, command, value in find_statements(equations):
|
|
581
|
+
# print('>>',comment,'<',command,'>',value)
|
|
582
|
+
if comment:
|
|
583
|
+
nymodel.append(comment)
|
|
584
|
+
else:
|
|
585
|
+
while 'TO_ARRAY(' in value.upper():
|
|
586
|
+
forcreate, createudtryk, eftercreate = find_arg('TO_ARRAY', value.upper())
|
|
587
|
+
temp = createudtryk.split(',', 2)
|
|
588
|
+
mat_name = temp[-1]
|
|
589
|
+
create_row = temp[0]
|
|
590
|
+
row_dict = liste_dict[create_row]
|
|
591
|
+
if len(temp)==2:
|
|
592
|
+
ibsud = '['+sub_frml(row_dict, mat_name, ',', '', sep='')+']'
|
|
593
|
+
else:
|
|
594
|
+
create_column= temp[1]
|
|
595
|
+
column_dict = liste_dict[create_column]
|
|
596
|
+
ibsud0 = '['+sub_frml(column_dict, mat_name, ',', '', sep='')+']'
|
|
597
|
+
ibsud = '['+sub_frml(row_dict, ibsud0 , ',\n', '', sep='')+']'
|
|
598
|
+
|
|
599
|
+
value = forcreate + 'array(\n' + ibsud + ')' + eftercreate
|
|
600
|
+
nymodel.append(command + ' ' + value)
|
|
601
|
+
equations = '\n'.join(nymodel)
|
|
602
|
+
return equations
|
|
603
|
+
|
|
604
|
+
def kaedeunroll(in_equations,funks=[]):
|
|
605
|
+
''' unrolls a chain (kaede) expression - used in the SMEC moedel '''
|
|
606
|
+
nymodel=[]
|
|
607
|
+
equations=in_equations[:] # we want do change the e
|
|
608
|
+
# modelprint(equations)
|
|
609
|
+
for comment,command,value in find_statements(equations.upper()):
|
|
610
|
+
# print('>>',comment,'<',command,'>',value)
|
|
611
|
+
if comment:
|
|
612
|
+
nymodel.append(comment)
|
|
613
|
+
elif command=='FRML':
|
|
614
|
+
a,fr,n,udtryk=split_frml((command+' '+value).upper())
|
|
615
|
+
while 'KAEDE(' in udtryk.upper():
|
|
616
|
+
forkaede,kaedeudtryk,efterkaede=find_arg('KAEDE',udtryk)
|
|
617
|
+
arg=kaedeudtryk.split(',')
|
|
618
|
+
taller,navner='(','('
|
|
619
|
+
for i in range(len(arg)/2):
|
|
620
|
+
j=i*2
|
|
621
|
+
taller=taller+arg[j]+'*('+lagone(arg[j+1]+'/'+arg[j],funks=funks)+')+'
|
|
622
|
+
navner=navner+lagone(arg[j+1],funks=funks)+'+'
|
|
623
|
+
navner=navner[:-1]+')'
|
|
624
|
+
taller=taller[:-1]+')'
|
|
625
|
+
#print(taller,'/',navner)
|
|
626
|
+
udtryk=forkaede+'('+taller+'/'+navner+')'+efterkaede
|
|
627
|
+
while 'KAEDEP(' in udtryk.upper():
|
|
628
|
+
forkaede,kaedeudtryk,efterkaede=find_arg('KAEDEP',udtryk)
|
|
629
|
+
arg=kaedeudtryk.split(',')
|
|
630
|
+
#print(arg,len(arg)/2)
|
|
631
|
+
taller,navner='(','('
|
|
632
|
+
for i in range(len(arg)/2):
|
|
633
|
+
j=i*2
|
|
634
|
+
taller=taller+arg[j]+'*'+lagone(arg[j+1],funks=funks)+'+'
|
|
635
|
+
navner=navner+lagone(arg[j],funks=funks)+'+'+lagone(arg[j+1],funks=funks)+'+'
|
|
636
|
+
navner=navner[:-1]+')'
|
|
637
|
+
taller=taller[:-1]+')'
|
|
638
|
+
#print(taller,'/',navner)
|
|
639
|
+
udtryk=forkaede+'('+taller+'/'+navner+')'+efterkaede
|
|
640
|
+
while 'MOVAVG(' in udtryk.upper():
|
|
641
|
+
forkaede,kaedeudtryk,efterkaede=find_arg('MOVAVG',udtryk)
|
|
642
|
+
arg=kaedeudtryk.split(',',1)
|
|
643
|
+
avg='(('
|
|
644
|
+
term=arg[0]
|
|
645
|
+
#print(arg,len(arg)/2)
|
|
646
|
+
# breakpoint()
|
|
647
|
+
antal=int(arg[1])
|
|
648
|
+
for i in range(antal):
|
|
649
|
+
avg=avg[:]+term[:]+'+'
|
|
650
|
+
term=lagone(term,funks=funks)
|
|
651
|
+
avg=avg[:-1]+')/'+str(antal)+'.0)'
|
|
652
|
+
#print(taller,'/',navner)
|
|
653
|
+
udtryk=forkaede+avg+efterkaede
|
|
654
|
+
nymodel.append(command+' '+n+' '+udtryk)
|
|
655
|
+
|
|
656
|
+
else:
|
|
657
|
+
nymodel.append(command+' '+value)
|
|
658
|
+
equations='\n'.join(nymodel)
|
|
659
|
+
return equations
|
|
660
|
+
|
|
661
|
+
def check_syntax_frml(frml):
|
|
662
|
+
''' check syntax of frml '''
|
|
663
|
+
try:
|
|
664
|
+
a, fr, n, udtryk = split_frml(frml)
|
|
665
|
+
ast.parse(re.sub(r'\n','',re.sub(' ','',udtryk[:-1])))
|
|
666
|
+
return True
|
|
667
|
+
except:
|
|
668
|
+
return False
|
|
669
|
+
|
|
670
|
+
def check_syntax_udtryk(udtryk):
|
|
671
|
+
''' check syntax of frml '''
|
|
672
|
+
try:
|
|
673
|
+
ast.parse(re.sub(r'\n','',re.sub(' ','',udtryk)))
|
|
674
|
+
return True
|
|
675
|
+
except:
|
|
676
|
+
return False
|
|
677
|
+
|
|
678
|
+
def check_syntax(expression_list, noprint=False, raise_error=True):
|
|
679
|
+
"""
|
|
680
|
+
Check the Python syntax of one or more expressions.
|
|
681
|
+
|
|
682
|
+
Parameters
|
|
683
|
+
----------
|
|
684
|
+
expression_list : str or iterable of str
|
|
685
|
+
A single expression or a collection of expressions to check.
|
|
686
|
+
Each expression is passed to `check_syntax_udtryk_new`.
|
|
687
|
+
|
|
688
|
+
noprint : bool, default False
|
|
689
|
+
If False, syntax errors are printed when found.
|
|
690
|
+
If True, printing is suppressed.
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
raise_error : bool, default True
|
|
694
|
+
If True, a SyntaxError is raised when one or more syntax errors
|
|
695
|
+
are detected.
|
|
696
|
+
If False, errors are not raised.
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
Returns
|
|
700
|
+
-------
|
|
701
|
+
None
|
|
702
|
+
This function does not return a value.
|
|
703
|
+
|
|
704
|
+
Notes
|
|
705
|
+
-----
|
|
706
|
+
If `expression_list` is a string, it is treated as a single expression.
|
|
707
|
+
If syntax errors are found, they can be printed and/or raised depending
|
|
708
|
+
on the values of `noprint` and `raise_error`.
|
|
709
|
+
"""
|
|
710
|
+
expressions = [expression_list] if isinstance(expression_list, str) else expression_list
|
|
711
|
+
|
|
712
|
+
errlist = []
|
|
713
|
+
for udtryk in expressions:
|
|
714
|
+
ok, text = check_syntax_udtryk_new(udtryk)
|
|
715
|
+
if not ok:
|
|
716
|
+
errlist.append(text)
|
|
717
|
+
|
|
718
|
+
if errlist:
|
|
719
|
+
message = "\n\n".join(errlist)
|
|
720
|
+
if not noprint:
|
|
721
|
+
print(message)
|
|
722
|
+
if raise_error:
|
|
723
|
+
if noprint:
|
|
724
|
+
raise SyntaxError(message)
|
|
725
|
+
else:
|
|
726
|
+
raise SyntaxError() from None
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def check_syntax_udtryk_new(udtryk):
|
|
730
|
+
'''Check syntax of an expression, pinpoint errors, and show error location.'''
|
|
731
|
+
try:
|
|
732
|
+
# Parse the original string without modifying it
|
|
733
|
+
ast.parse(udtryk)
|
|
734
|
+
return True, "No syntax errors found."
|
|
735
|
+
except SyntaxError as e:
|
|
736
|
+
# Extract the offending line from the original string
|
|
737
|
+
lines = udtryk.splitlines()
|
|
738
|
+
error_line = lines[e.lineno - 1] if e.lineno and e.lineno <= len(lines) else ""
|
|
739
|
+
marker = " " * (e.offset - 1) + "^" if e.offset else ""
|
|
740
|
+
|
|
741
|
+
# Build the error message with context
|
|
742
|
+
error_message = (
|
|
743
|
+
f"Syntax error at line {e.lineno}, column {e.offset}: {e.msg}\n"
|
|
744
|
+
f"{error_line}\n{marker}"
|
|
745
|
+
)
|
|
746
|
+
return False, error_message
|
|
747
|
+
except Exception as e:
|
|
748
|
+
return False, f"Unexpected error: {e}"
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
def normalize_a_frml(frml,show=False):
|
|
752
|
+
''' Normalize and show a frml'''
|
|
753
|
+
new = normalize(frml,sym=True)
|
|
754
|
+
if show:
|
|
755
|
+
print(f'Try normalizing :{frml} ')
|
|
756
|
+
print(f'After normalization :{new} ')
|
|
757
|
+
if not check_syntax_frml(new):
|
|
758
|
+
print(f'** ERROR in :{new} ')
|
|
759
|
+
print(f'**Normalization did not solve the problem in this formula')
|
|
760
|
+
|
|
761
|
+
return new
|
|
762
|
+
|
|
763
|
+
def nomalize_a_model(equations):
|
|
764
|
+
''' a symbolic normalization is performed if there is a syntaxerror '''
|
|
765
|
+
|
|
766
|
+
out= '\n'.join([frml if check_syntax_frml(frml) else normalize_a_frml(frml,True) for frml in find_frml(equations)])
|
|
767
|
+
return out
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
def normalize(in_equations,sym=False,funks=[]):
|
|
771
|
+
''' Normalize an equation with log or several variables at the left hand side, the first variable is considerd the endogeneeus'''
|
|
772
|
+
def findendo(ind):
|
|
773
|
+
''' finds the equation for the first variable of a string'''
|
|
774
|
+
def endovar(f): # Finds the first variable in a expression
|
|
775
|
+
for t in udtryk_parse(f,funks=funks):
|
|
776
|
+
if t.var:
|
|
777
|
+
ud=t.var
|
|
778
|
+
break
|
|
779
|
+
return ud
|
|
780
|
+
ind=re.sub(r'LOG\(','log(',ind) # sypy uses lover case for log and exp
|
|
781
|
+
ind=re.sub(r'EXP\(','exp(',ind)
|
|
782
|
+
lhs,rhs=ind.split('=',1)
|
|
783
|
+
if len(udtryk_parse(lhs,funks=funks)) >=2: # we have an expression on the left hand side
|
|
784
|
+
# print('Before >>',ind)
|
|
785
|
+
endo=sympify(endovar(lhs))
|
|
786
|
+
kat=sympify('Eq('+lhs+','+rhs[0:-1]+')') # we take the the $ out
|
|
787
|
+
endo_frml=solve(kat,endo,simplify=False,rational=False)
|
|
788
|
+
# print('After >>', str(endo)+'=' + str(endo_frml[0])+'$')
|
|
789
|
+
return str(endo)+'=' + str(endo_frml[0])+'$'
|
|
790
|
+
else: # no need to solve this equation
|
|
791
|
+
return ind
|
|
792
|
+
def normalizesym(in_equations):
|
|
793
|
+
''' Normalizes equations by using sympy '''
|
|
794
|
+
nymodel=[]
|
|
795
|
+
equations=in_equations[:] # we want do change the e
|
|
796
|
+
# modelprint(equations)
|
|
797
|
+
for comment,command,value in find_statements(equations.upper()):
|
|
798
|
+
# print('>>',comment,'<',command,'>',value)
|
|
799
|
+
if comment:
|
|
800
|
+
nymodel.append(comment)
|
|
801
|
+
elif command=='FRML':
|
|
802
|
+
a,fr,n,udtryk=split_frml((command+' '+value).upper())
|
|
803
|
+
while 'DLOG(' in udtryk.upper():
|
|
804
|
+
fordlog,dlogudtryk,efterdlog=find_arg('dlog',udtryk)
|
|
805
|
+
udtryk=fordlog+'diff(log('+dlogudtryk+'))'+efterdlog
|
|
806
|
+
while 'LOGIT(' in udtryk.upper():
|
|
807
|
+
forlogit,logitudtryk,efterlogit=find_arg('LOGIT',udtryk)
|
|
808
|
+
udtryk=forlogit+'(log('+logitudtryk+'/(1.0 -'+logitudtryk+')))'+efterlogit
|
|
809
|
+
while 'DIFF(' in udtryk.upper():
|
|
810
|
+
fordif,difudtryk,efterdif=find_arg('diff',udtryk)
|
|
811
|
+
udtryk=fordif+'(('+difudtryk+')-('+lagone(difudtryk+'',funks=funks)+'))'+efterdif
|
|
812
|
+
nymodel.append(command+' '+n+' '+findendo(udtryk))
|
|
813
|
+
else:
|
|
814
|
+
nymodel.append(command+' '+value)
|
|
815
|
+
equations='\n'.join(nymodel)
|
|
816
|
+
# modelprint(equations)
|
|
817
|
+
return equations
|
|
818
|
+
def normalizehift(in_equations):
|
|
819
|
+
''' Normalizes equations by shuffeling terms around \n
|
|
820
|
+
can handel LOG, DLOG and DIF in the left hans side of = '''
|
|
821
|
+
nymodel=[]
|
|
822
|
+
equations=in_equations[:] # we want do change the e
|
|
823
|
+
# modelprint(equations)
|
|
824
|
+
for comment,command,value in find_statements(equations.upper()):
|
|
825
|
+
# print('>>',comment,'<',command,'>',value)
|
|
826
|
+
if comment:
|
|
827
|
+
nymodel.append(comment)
|
|
828
|
+
elif command=='FRML':
|
|
829
|
+
a,fr,n,udtryk=split_frml((command+' '+value).upper())
|
|
830
|
+
lhs,rhs=udtryk.split('=',1)
|
|
831
|
+
lhsterms=udtryk_parse(lhs,funks=funks)
|
|
832
|
+
if len(lhsterms) == 1: # only one term on the left hand side, no need to shuffel around
|
|
833
|
+
pass
|
|
834
|
+
elif len(lhsterms) == 4: # We need to normalixe expect funk(x) on the levt hand side funk=LOG,DLOG or DIFF
|
|
835
|
+
rhs=rhs[:-1].strip() # discharge the $ strip blanks for nice look
|
|
836
|
+
lhs=lhsterms[2].var # name of the dependent variablem, no syntax check here
|
|
837
|
+
if lhsterms[0].op == 'LOG':
|
|
838
|
+
rhs='EXP('+rhs+')'
|
|
839
|
+
udtryk=lhs+'='+rhs+'$' # now the equation is normalized
|
|
840
|
+
elif lhsterms[0].op == 'DIFF':
|
|
841
|
+
rhs=lagone(lhs,funks=funks)+'+('+rhs+')'
|
|
842
|
+
udtryk=lhs+'='+rhs+'$' # now the equation is normalized
|
|
843
|
+
elif lhsterms[0].op == 'DLOG':
|
|
844
|
+
rhs='EXP(LOG('+lagone(lhs,funks=funks)+')+'+rhs+')'
|
|
845
|
+
udtryk=lhs+'='+rhs+'$' # now the equation is normalized
|
|
846
|
+
elif lhsterms[0].op == 'LOGIT':
|
|
847
|
+
rhs='(exp('+rhs+')/(1+EXP('+rhs+')))'
|
|
848
|
+
udtryk=lhs+'='+rhs+'$' # now the equation is normalized
|
|
849
|
+
# else:
|
|
850
|
+
# print('*** ERROR operand not allowed left of =',lhs)
|
|
851
|
+
# print(lhsterms)
|
|
852
|
+
else:
|
|
853
|
+
pass
|
|
854
|
+
# print('*** Try to normalize relation for:',lhs)
|
|
855
|
+
# now the right hand side is expanded for DLOG and DIFF
|
|
856
|
+
while 'DLOG(' in udtryk.upper():
|
|
857
|
+
fordlog,dlogudtryk,efterdlog=find_arg('dlog',udtryk)
|
|
858
|
+
udtryk=fordlog+'diff(log('+dlogudtryk+'))'+efterdlog
|
|
859
|
+
while 'DIFF(' in udtryk.upper():
|
|
860
|
+
fordif,difudtryk,efterdif=find_arg('diff',udtryk)
|
|
861
|
+
udtryk=fordif+'(('+difudtryk+')-('+lagone(difudtryk+'',funks=funks)+'))'+efterdif
|
|
862
|
+
nymodel.append(command+' '+n+' '+udtryk)
|
|
863
|
+
else:
|
|
864
|
+
nymodel.append(command+' '+value)
|
|
865
|
+
equations='\n'.join(nymodel)
|
|
866
|
+
# modelprint(in_equations,'Before normalization and expansion')
|
|
867
|
+
# modelprint(equations, 'After normalization and expansion')
|
|
868
|
+
return equations
|
|
869
|
+
if sym :
|
|
870
|
+
equations1=normalizesym(in_equations)
|
|
871
|
+
else:
|
|
872
|
+
equations1=normalizehift(in_equations)
|
|
873
|
+
#equations2=normalizesym(equations1) # to speed up
|
|
874
|
+
return equations1
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
def udrul_model(model,norm=True):
|
|
878
|
+
|
|
879
|
+
return explode(model, norm)
|
|
880
|
+
|
|
881
|
+
def explode(model,norm=True,sym=False,funks=[],sep='\n'):
|
|
882
|
+
'''prepares a model from a model template.
|
|
883
|
+
|
|
884
|
+
Returns a expanded model which is ready to solve
|
|
885
|
+
|
|
886
|
+
Eksempel: model = udrul_model(MinModel.txt)'''
|
|
887
|
+
# breakpoint()
|
|
888
|
+
udrullet=tofrml(model,sep=sep)
|
|
889
|
+
modellist = list_extract(udrullet)
|
|
890
|
+
if norm : udrullet = normalize(udrullet,sym,funks=funks ) # to save time if we know that normalization is not needed
|
|
891
|
+
udrullet = lagarray_unroll(udrullet,funks=funks )
|
|
892
|
+
udrullet = exounroll(udrullet) # finaly the exogeneous and adjustment terms - if present - are handled
|
|
893
|
+
udrullet = dounloop(udrullet,listin=modellist) # we unroll the do loops
|
|
894
|
+
# breakpoint()
|
|
895
|
+
udrullet = sumunroll(udrullet,listin=modellist) # then we unroll the sum
|
|
896
|
+
udrullet = creatematrix(udrullet,listin=modellist)
|
|
897
|
+
udrullet = createarray(udrullet,listin=modellist)
|
|
898
|
+
udrullet = argunroll(udrullet,listin=modellist)
|
|
899
|
+
|
|
900
|
+
return udrullet
|
|
901
|
+
|
|
902
|
+
def explode_new(model,norm=True,sym=False,funks=[],sep='\n'):
|
|
903
|
+
'''prepares a model from a model template.
|
|
904
|
+
|
|
905
|
+
Returns a expanded model which is ready to solve
|
|
906
|
+
|
|
907
|
+
Eksempel: model = udrul_model(MinModel.txt)'''
|
|
908
|
+
# breakpoint()
|
|
909
|
+
udrullet=tofrml(model,sep=sep)
|
|
910
|
+
udrullet = doable_unroll(udrullet,funks)
|
|
911
|
+
udrullet = dounloop(udrullet) # we unroll the do loops
|
|
912
|
+
# modellist = list_extract(udrullet)
|
|
913
|
+
# if norm : udrullet = normalize(udrullet,sym,funks=funks ) # to save time if we know that normalization is not needed
|
|
914
|
+
# udrullet = lagarray_unroll(udrullet,funks=funks )
|
|
915
|
+
# udrullet = exounroll(udrullet) # finaly the exogeneous and adjustment terms - if present - are handled
|
|
916
|
+
# # breakpoint()
|
|
917
|
+
# udrullet = sumunroll(udrullet,listin=modellist) # then we unroll the sum
|
|
918
|
+
# udrullet = creatematrix(udrullet,listin=modellist)
|
|
919
|
+
# udrullet = createarray(udrullet,listin=modellist)
|
|
920
|
+
# udrullet = argunroll(udrullet,listin=modellist)
|
|
921
|
+
|
|
922
|
+
return udrullet
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
def modelprint(ind, title=' A model', udfil='', short=0):
|
|
926
|
+
''' prettyprinter for a a model.
|
|
927
|
+
:udfil: if present is output file
|
|
928
|
+
:short: if present condences the model
|
|
929
|
+
Can handle both model templates and models '''
|
|
930
|
+
import sys
|
|
931
|
+
f = sys.stdout
|
|
932
|
+
if udfil:
|
|
933
|
+
f = open(udfil, 'w+')
|
|
934
|
+
maxlenfnavn, maxlenlhs, maxlenrhs = 0, 0, 0
|
|
935
|
+
for comment, command, value in find_statements(ind):
|
|
936
|
+
if command.upper() == 'FRML':
|
|
937
|
+
a, fr, n, udtryk = split_frml(command.upper() + ' ' + value)
|
|
938
|
+
lhs, rhs = udtryk.split('=', 1)
|
|
939
|
+
maxlenfnavn = max(maxlenfnavn, len(n)) # Finds the max length of frml name
|
|
940
|
+
maxlenlhs = max(maxlenlhs, len(lhs)) # finds the max length of left hand variable
|
|
941
|
+
print('! '+ title, file=f)
|
|
942
|
+
dolevel = 0
|
|
943
|
+
for comment, command, value in find_statements(ind):
|
|
944
|
+
print(' ' * dolevel, end='', file=f)
|
|
945
|
+
if comment:
|
|
946
|
+
print(comment, file=f)
|
|
947
|
+
else:
|
|
948
|
+
if command.upper() == 'FRML':
|
|
949
|
+
a, fr, n, udtryk = split_frml(
|
|
950
|
+
command.upper() + ' ' + value)
|
|
951
|
+
lhs , rhs = udtryk.split('=', 1)
|
|
952
|
+
if short:
|
|
953
|
+
print(fr.ljust(5),'X',lhs.strip().ljust(maxlenlhs),
|
|
954
|
+
'=', rhs , file=f)
|
|
955
|
+
else:
|
|
956
|
+
rhs=re.sub(' +',' ',rhs)
|
|
957
|
+
print(
|
|
958
|
+
fr.ljust(5),
|
|
959
|
+
n.strip().ljust(maxlenfnavn),
|
|
960
|
+
lhs.strip().ljust(maxlenlhs),
|
|
961
|
+
'=',
|
|
962
|
+
rhs.replace('\n','\n'+(' ' * dolevel)+(' '*(10+maxlenfnavn+maxlenlhs))),
|
|
963
|
+
file=f)
|
|
964
|
+
elif command.upper() == 'DO':
|
|
965
|
+
print(command, ' ', value, file=f)
|
|
966
|
+
dolevel = dolevel + 1
|
|
967
|
+
elif command.upper() == 'ENDDO':
|
|
968
|
+
print(command, ' ', value, file=f)
|
|
969
|
+
dolevel = dolevel - 1
|
|
970
|
+
else:
|
|
971
|
+
print(command, ' ', value, file=f)
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
def lagone(ind,funks=[],laglead=-1):
|
|
976
|
+
''' All variables in a string i
|
|
977
|
+
s lagged one more time '''
|
|
978
|
+
nt=udtryk_parse(ind,funks=funks)
|
|
979
|
+
fib=[]
|
|
980
|
+
for t in nt:
|
|
981
|
+
if t.op:
|
|
982
|
+
ud=t.op
|
|
983
|
+
elif t.number:
|
|
984
|
+
ud=t.number
|
|
985
|
+
elif t.var:
|
|
986
|
+
lag=t.lag if t.lag else '0'
|
|
987
|
+
org_lag = int(lag)
|
|
988
|
+
new_lag = org_lag+laglead
|
|
989
|
+
if new_lag == 0:
|
|
990
|
+
ud = t.var
|
|
991
|
+
else:
|
|
992
|
+
ud= t.var+ f'({new_lag:+})'
|
|
993
|
+
fib.append(ud)
|
|
994
|
+
return ''.join(fib)
|
|
995
|
+
|
|
996
|
+
def lag_n(udtryk,n=1,funks=[],laglead=-1):
|
|
997
|
+
new=udtryk
|
|
998
|
+
for i in range(n):
|
|
999
|
+
new=lagone(new,funks=funks,laglead=laglead)
|
|
1000
|
+
return f'({new})'
|
|
1001
|
+
lag_n('a+b',n=3,laglead=1)
|
|
1002
|
+
|
|
1003
|
+
def lag_n_tup(udtryk,n=-1,funks=[]):
|
|
1004
|
+
''' return a tuppel og lagged expressions from lag = 0 to lag = n)'''
|
|
1005
|
+
new=udtryk.upper()
|
|
1006
|
+
res=''
|
|
1007
|
+
for i in range(abs(n)):
|
|
1008
|
+
new=lagone(new,funks=funks,laglead=-1 if n < 0 else 1 )
|
|
1009
|
+
res = res + new +','
|
|
1010
|
+
return f'{res[:-1]}'
|
|
1011
|
+
lag_n_tup('a',n=-3)
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
def pastestring(ind,post,funks=[],onlylags = False):
|
|
1016
|
+
''' All variable names in a in a string **ind** is pasted with the string **post**
|
|
1017
|
+
|
|
1018
|
+
This function can be used to awoid variable name conflict with the internal variable names in sympy.
|
|
1019
|
+
|
|
1020
|
+
an advanced function
|
|
1021
|
+
'''
|
|
1022
|
+
nt=udtryk_parse(ind,funks=funks)
|
|
1023
|
+
fib=[]
|
|
1024
|
+
for t in nt:
|
|
1025
|
+
if t.op:
|
|
1026
|
+
ud=t.op
|
|
1027
|
+
elif t.number:
|
|
1028
|
+
ud=t.number
|
|
1029
|
+
elif t.var:
|
|
1030
|
+
if onlylags:
|
|
1031
|
+
if t.lag:
|
|
1032
|
+
ud= t.var+ post.upper()+ ('('+(str(int(t.lag)))+')' if t.lag else '')
|
|
1033
|
+
else:
|
|
1034
|
+
ud= t.var
|
|
1035
|
+
else:
|
|
1036
|
+
ud= t.var+ post+ ('('+(str(int(t.lag)))+')' if t.lag else '')
|
|
1037
|
+
|
|
1038
|
+
fib.append(ud)
|
|
1039
|
+
return ''.join(fib)
|
|
1040
|
+
|
|
1041
|
+
def stripstring(ind,post,funks=[]):
|
|
1042
|
+
''' All variable names in a in a string is **ind** is stripped of the string **post**.
|
|
1043
|
+
|
|
1044
|
+
This function reverses the pastestring process
|
|
1045
|
+
'''
|
|
1046
|
+
nt=udtryk_parse(ind,funks=funks)
|
|
1047
|
+
fib=[]
|
|
1048
|
+
lenpost=len(post)
|
|
1049
|
+
for t in nt:
|
|
1050
|
+
if t.op:
|
|
1051
|
+
ud=t.op
|
|
1052
|
+
elif t.number:
|
|
1053
|
+
ud=t.number
|
|
1054
|
+
elif t.var:
|
|
1055
|
+
if t.var.endswith(post.upper()):
|
|
1056
|
+
ud= t.var[:-lenpost]+ ('('+(str(int(t.lag)))+')' if t.lag else '')
|
|
1057
|
+
else:
|
|
1058
|
+
ud= t.var+ ('('+(str(int(t.lag)))+')' if t.lag else '')
|
|
1059
|
+
|
|
1060
|
+
# print('Tries to strip '+post +' from '+ind)
|
|
1061
|
+
fib.append(ud)
|
|
1062
|
+
return ''.join(fib)
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
def findindex(ind00):
|
|
1066
|
+
''' find the index variables meaning variables on the left hand side of = braced by {} '''
|
|
1067
|
+
ind0 = ind00.strip()
|
|
1068
|
+
if ind0.startswith('<'):
|
|
1069
|
+
ind = ind0[ind0.index('>')+1:].strip()
|
|
1070
|
+
else:
|
|
1071
|
+
ind = ind0
|
|
1072
|
+
lhs=ind.split('=')[0]
|
|
1073
|
+
return (re.findall(r'\{([A-Za-z][\w]*)\}',lhs )) # all the index variables
|
|
1074
|
+
|
|
1075
|
+
def doablelist(expressions,sep='\n'):
|
|
1076
|
+
''' create a list of tupels from expressions seperated by sep,
|
|
1077
|
+
each element in the list is a tupel (index, number og expression, the expression)
|
|
1078
|
+
|
|
1079
|
+
we want make group the expressions acording to index
|
|
1080
|
+
index is elements on the left of = braced by {}
|
|
1081
|
+
'''
|
|
1082
|
+
|
|
1083
|
+
lt = [(findindex(l.strip()),i,l.strip()) for i,l in enumerate(expressions.split(sep))]
|
|
1084
|
+
out = sorted(lt,key = lambda x: (x[0],1./(x[1]+1.)),reverse=True)
|
|
1085
|
+
return out
|
|
1086
|
+
|
|
1087
|
+
def dosubst(index,formular):
|
|
1088
|
+
out=formular[:]
|
|
1089
|
+
for nr,i in enumerate(index):
|
|
1090
|
+
assert nr <= 9 , 'To many indeces in'+formular
|
|
1091
|
+
out = re.sub(r'\%'+str(nr),'{'+i+'}',out)
|
|
1092
|
+
out = re.sub(r'\%i','__'.join(['{'+i+'}' for i in index]),out)
|
|
1093
|
+
return out
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
def doablekeep(formulars):
|
|
1097
|
+
''' takes index in the lhs and creates a do loop around the lines with same indexes
|
|
1098
|
+
on the right side you can use %0_, %1_ an so on to indicate the index, just to awoid typing to much
|
|
1099
|
+
|
|
1100
|
+
Also %i_ will be changed to all the indexes'''
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
sep = '$' if '$' in formulars else '\n'
|
|
1104
|
+
xx = doablelist(formulars,sep)
|
|
1105
|
+
out = []
|
|
1106
|
+
listout = []
|
|
1107
|
+
for xxx,ee in groupby(xx,key=lambda x : x[0]):
|
|
1108
|
+
if xxx:
|
|
1109
|
+
pre = ''.join([' '*i+ 'Do '+x+'_list $\n' for i,x in enumerate(xxx)])
|
|
1110
|
+
post = ''.join([' '*(len(xxx)-1-i)+'Enddo $ \n' for i,x in enumerate(xxx)]) +'\n'
|
|
1111
|
+
frml = ''.join([' '*(len(xxx))+dosubst(xxx,e[2])+ ' $ \n' for e in ee ])
|
|
1112
|
+
out.append([pre + frml + post])
|
|
1113
|
+
else:
|
|
1114
|
+
for l,number,exp in ee:
|
|
1115
|
+
if exp.upper().startswith('LIST'):
|
|
1116
|
+
listout.append([exp + ' $ \n'])
|
|
1117
|
+
elif len(exp) :
|
|
1118
|
+
# print(exp)
|
|
1119
|
+
out.append([exp+ ' $ \n'])
|
|
1120
|
+
return ''.join(chain(*listout,*out))
|
|
1121
|
+
##%%
|
|
1122
|
+
def doable(formulars,funks=[],replace_usd=True):
|
|
1123
|
+
''' takes index in the lhs and creates a do loop around the line
|
|
1124
|
+
on the right side you can use %0_, %1_ an so on to indicate the index, just to awoid typing to much
|
|
1125
|
+
|
|
1126
|
+
Also %i_ will be changed to all the indexes'''
|
|
1127
|
+
|
|
1128
|
+
def endovar(f,funks=[]): # Finds the first variable in a expression
|
|
1129
|
+
for t in udtryk_parse(f,funks=funks):
|
|
1130
|
+
if t.var:
|
|
1131
|
+
ud=t.var
|
|
1132
|
+
break
|
|
1133
|
+
return ud
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
sep = '$' if '$' in formulars else '\n'
|
|
1137
|
+
lt = [(findindex(l.strip()),i,l.strip()) for i,l in enumerate(formulars.split(sep))]
|
|
1138
|
+
|
|
1139
|
+
out = []
|
|
1140
|
+
for xxx,number,exp in lt:
|
|
1141
|
+
if xxx:
|
|
1142
|
+
pre = ''.join([' '*i+ 'Do '+x+'_list $\n' for i,x in enumerate(xxx)])
|
|
1143
|
+
post = ''.join([' '* (len(xxx)-1-i)+'Enddo $ \n' for i,x in enumerate(xxx)]) +'\n'
|
|
1144
|
+
frml = ' '*(len(xxx)) + dosubst(xxx,exp)+ ' $ \n'
|
|
1145
|
+
out.append(pre + frml + post)
|
|
1146
|
+
ind = exp.strip()
|
|
1147
|
+
|
|
1148
|
+
if ind.startswith('<'):
|
|
1149
|
+
frml_name = re.findall(r'\<.*?\>',ind)[0]
|
|
1150
|
+
sumname = kw_frml_name(frml_name, 'sum')
|
|
1151
|
+
if sumname:
|
|
1152
|
+
lhs= ind.split('>',1)[1].split('=',1)[0]
|
|
1153
|
+
lhsvar = endovar(lhs,funks=funks)
|
|
1154
|
+
lhsvar_stub = lhsvar.split('{',1)[0]
|
|
1155
|
+
sumlist = ''.join([f'sum({x}_list,' for x in xxx])+lhsvar+')'*len(xxx)
|
|
1156
|
+
out.append(f'{lhsvar_stub}{sumname} = {sumlist} $ \n\n')
|
|
1157
|
+
elif len(exp) :
|
|
1158
|
+
out.append(exp+ ' $ \n')
|
|
1159
|
+
if replace_usd:
|
|
1160
|
+
res = ''.join(out).replace('$','') # the replace is a quick
|
|
1161
|
+
else:
|
|
1162
|
+
res = ''.join(out)
|
|
1163
|
+
return res
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
##%%
|
|
1167
|
+
def findindex_gams(ind00):
|
|
1168
|
+
'''
|
|
1169
|
+
- an equation looks like this
|
|
1170
|
+
- <frmlname> [index] lhs = rhs
|
|
1171
|
+
|
|
1172
|
+
this function find frmlname and index variables on the left hand side. meaning variables braced by {} '''
|
|
1173
|
+
ind0 = ind00.strip()
|
|
1174
|
+
if ind0.startswith('<'):
|
|
1175
|
+
frmlname = re.findall(r'\<.*?\>',ind0)[0]
|
|
1176
|
+
ind = ind0[ind0.index('>')+1:].strip()
|
|
1177
|
+
else:
|
|
1178
|
+
frmlname='<>'
|
|
1179
|
+
ind=ind0.strip()
|
|
1180
|
+
|
|
1181
|
+
if ind.startswith('['):
|
|
1182
|
+
allindex = re.findall(r'\[.*?\]',ind0)[0]
|
|
1183
|
+
index = allindex[1:-1].split(',')
|
|
1184
|
+
rest = ind[ind.index(']')+1:]
|
|
1185
|
+
else:
|
|
1186
|
+
index = []
|
|
1187
|
+
rest = ind
|
|
1188
|
+
return frmlname,index,rest
|
|
1189
|
+
|
|
1190
|
+
def un_normalize_expression(frml,implicit=False,endo='') :
|
|
1191
|
+
'''This function makes sure that all formulas are unnormalized.
|
|
1192
|
+
if the formula is already decorated with <endo=name> this is kept
|
|
1193
|
+
else the lhs_varriable is used in <endo=>
|
|
1194
|
+
'''
|
|
1195
|
+
frml_name,frml_index,frml_rest = findindex_gams(frml.upper())
|
|
1196
|
+
# debug_var(frml_name,frml_index,frml_rest)
|
|
1197
|
+
|
|
1198
|
+
if kw_frml_name(frml_name.upper(), 'IMPLICIT') or implicit:
|
|
1199
|
+
|
|
1200
|
+
this_endo = endo.upper() if endo else kw_frml_name(frml_name.upper(), 'ENDO')
|
|
1201
|
+
# debug_var(this_endo)
|
|
1202
|
+
lhs,rhs = frml_rest.split('=')
|
|
1203
|
+
if this_endo:
|
|
1204
|
+
lhs_var = this_endo.strip()
|
|
1205
|
+
frml_name_out = frml_name
|
|
1206
|
+
else:
|
|
1207
|
+
lhs_var = lhs.strip()
|
|
1208
|
+
# frml_name_out = f'<endo={lhs_var}>' if frml_name == '<>' else f'{frml_name[:-1]},endo={lhs_var}>'
|
|
1209
|
+
frml_name_out = frml_name[:]
|
|
1210
|
+
new_rest = f'{lhs_var}___res = ( {rhs.strip()} ) - ( {lhs.strip()} )'
|
|
1211
|
+
res = f'{frml_name_out} {frml_index if len(frml_index) else ""} {new_rest}'
|
|
1212
|
+
return res
|
|
1213
|
+
|
|
1214
|
+
else:
|
|
1215
|
+
return frml
|
|
1216
|
+
|
|
1217
|
+
def un_normalize_model(in_equations,implicit=False,funks=[]):
|
|
1218
|
+
''' un normalize a model '''
|
|
1219
|
+
nymodel=[]
|
|
1220
|
+
equations=in_equations.upper() # we want do change the e
|
|
1221
|
+
# modelprint(equations)
|
|
1222
|
+
for comment,command,value in find_statements(equations):
|
|
1223
|
+
# print('>>',comment,'<',command,'>',value)
|
|
1224
|
+
# breakpoint()
|
|
1225
|
+
if comment:
|
|
1226
|
+
nymodel.append(comment)
|
|
1227
|
+
elif command=='FRML':
|
|
1228
|
+
un_frml = un_normalize_expression(value[:-1],implicit=implicit)
|
|
1229
|
+
nymodel.append(f'FRML {un_frml} $')
|
|
1230
|
+
else:
|
|
1231
|
+
nymodel.append(command+' '+value)
|
|
1232
|
+
equations='\n'.join(nymodel)
|
|
1233
|
+
return equations
|
|
1234
|
+
|
|
1235
|
+
def un_normalize_simpel(in_equations,funks=[]):
|
|
1236
|
+
''' un-normalize expressions delimeted by linebreaks'''
|
|
1237
|
+
edm = '\n'.join(un_normalize_expression(f) for f in in_equations.split('\n') if len(f.strip()))
|
|
1238
|
+
fdm = explode(edm)
|
|
1239
|
+
return fdm
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
def eksempel(ind):
|
|
1243
|
+
''' takes a template model as input, creates a model and a histmodel and prints the models'''
|
|
1244
|
+
abe = udrul_model(ind)
|
|
1245
|
+
ko = find_hist_model(abe)
|
|
1246
|
+
modelprint(ind, 'Model template')
|
|
1247
|
+
modelprint(abe, 'Unrolled model')
|
|
1248
|
+
modelprint(ko, 'Historic model')
|
|
1249
|
+
# print('Hej fra modelmanipulation')
|
|
1250
|
+
if __name__ == '__main__' and 0 :
|
|
1251
|
+
#%%
|
|
1252
|
+
print(sub_frml(a['bankdic'],'Dette er {bank}'))
|
|
1253
|
+
print(sub_frml(a['bankdic'],'Dette er {bank}',sep=' and '))
|
|
1254
|
+
print(sub_frml(a['bankdic'],'Dette er {bank}',plus='+',sep=''))
|
|
1255
|
+
print(sub_frml(a['bankdic'],'Dette er {bank}',xvar='danske',lig='no'))
|
|
1256
|
+
print(sub_frml(a['bankdic'],'Dette er {bank}',xvar='danske',lig='yes'))
|
|
1257
|
+
print(sub_frml(a['bankdic'],'Dette er {bank}'))
|
|
1258
|
+
|
|
1259
|
+
#%%
|
|
1260
|
+
fmodel= '''
|
|
1261
|
+
list BANKDIC = bank : Danske , Nordea $
|
|
1262
|
+
list countryDIC = country : Uk , DK, SE , NO , IR, GE US AS AT CA$
|
|
1263
|
+
list countrydanske = country : uk , DK, IR $
|
|
1264
|
+
list countrynordea = country: SE , DK, AT $
|
|
1265
|
+
do bankdic$
|
|
1266
|
+
frml x {bank}_income = {bank}_a +{bank}_b $
|
|
1267
|
+
do country{bank} $
|
|
1268
|
+
frml x {bank}_{country} = 4242 $
|
|
1269
|
+
enddo $
|
|
1270
|
+
do countrydic $
|
|
1271
|
+
frml x {bank}_{country}_all = 42 $
|
|
1272
|
+
enddo $
|
|
1273
|
+
enddo $ '''
|
|
1274
|
+
|
|
1275
|
+
print(dounloop(fmodel))
|
|
1276
|
+
#%%
|
|
1277
|
+
print(stripstring(pastestring('a+b+log(x)','_xx'),'_xx'))
|
|
1278
|
+
split_frml ('FRML x ib =1+gris $')
|
|
1279
|
+
split_frml ('FRML <res> ib =1+gris $')
|
|
1280
|
+
find_statements(' FRML x ib =1+gris $ frml <exo> hane= 27*ged$')
|
|
1281
|
+
find_statements('! FRML x ib =1+gris $ \n frml <exo> hane=27*ged $')
|
|
1282
|
+
find_statements('FRML <x> ib =1+gris*(ko+1) $ ! Comment \n frml <exo> hane= ged $')
|
|
1283
|
+
sub('O {who} of {from}',{'who':'Knights','from':'Ni'})
|
|
1284
|
+
sub('O {who} of {from}, , we have brought you your {weed}',{'who':'Knights','from':'Ni'})
|
|
1285
|
+
sub_frml({'weed':['scrubbery','herring']},'we have brought you your {weed}')
|
|
1286
|
+
sub_frml({'weed':['scrubbery','herring'],'where':['land','sea']},'we have brought you your {weed} from {where} ')
|
|
1287
|
+
sub_frml({'weed':['scrubbery','herring'],'where':['land','sea']},'we have brought you your {weed} from {where} ')
|
|
1288
|
+
a={'bankdic': {'bank':['Danske','Nordea'],'danske':['yes','no']}}
|
|
1289
|
+
sub_frml(a['bankdic'],'Dette er {bank}')
|
|
1290
|
+
sub_frml(a['bankdic'],'Dette er {bank}',sep=' and ')
|
|
1291
|
+
sub_frml(a['bankdic'],'Dette er {bank}',plus='+',sep='')
|
|
1292
|
+
sub_frml(a['bankdic'],'Dette er {bank}',xvar='danske',lig='yes')
|
|
1293
|
+
sub_frml(a['bankdic'],'Dette er {bank}',xvar='danske',lig='no')
|
|
1294
|
+
sub_frml(a['bankdic'],'Dette er {bank}')
|
|
1295
|
+
list_extract('list bankdic = bank : Danske , Nordea / danske : yes , no $')
|
|
1296
|
+
kw_frml_name('<res=abe>','res')
|
|
1297
|
+
kw_frml_name('<res=abe,animal>','animal')
|
|
1298
|
+
find_res('FRML <res=x> ib =x+y+v +ib(-1)$')
|
|
1299
|
+
find_res('FRML <res=J> ib =x+y+v + ib_j $')
|
|
1300
|
+
find_res('FRML <res=JR> ib =(x+y+v + ib_j)*(1+ ib_JR) $)')
|
|
1301
|
+
find_hist_model('FRML <res=x> ib =x+y+v $ frml <ident> y=c+i+x-m $')
|
|
1302
|
+
(exounroll('frml <j> ib=x+y $ frml <jr> ib=x+y $ frml <j,jr'))
|
|
1303
|
+
find_arg('log','x=log(a+b)+77')
|
|
1304
|
+
find_arg('log','x=log(a+log(b))+77')
|
|
1305
|
+
|
|
1306
|
+
kaedeunroll('FRML <res=x> ib =x+y+lAG_ARRAY(v,3) $')
|
|
1307
|
+
#%%
|
|
1308
|
+
x= (dounloop(
|
|
1309
|
+
'''list bankdic = bank : Danske , Nordea /
|
|
1310
|
+
ko : yes , no $
|
|
1311
|
+
do bankdic ko = no $
|
|
1312
|
+
frml x {bank}_income = {bank}_a +{bank}_b $
|
|
1313
|
+
enddo $
|
|
1314
|
+
frml x ialt=sum(bankdic ko= yes,{bank}_income ) $'''))
|
|
1315
|
+
# breakpoint()
|
|
1316
|
+
print(sumunroll(x))
|
|
1317
|
+
#%% sumunroll
|
|
1318
|
+
print(sumunroll(dounloop(
|
|
1319
|
+
'''list BANKDIC = bank : Danske , Nordea $
|
|
1320
|
+
do BANKDIC $
|
|
1321
|
+
frml x {bank}_income = {bank}_a +{bank}_b $
|
|
1322
|
+
enddo $
|
|
1323
|
+
frml x ialt=sum(bankdic,{bank}_income) $''')))
|
|
1324
|
+
#%% funkunroll
|
|
1325
|
+
print(funkunroll(dounloop(
|
|
1326
|
+
'''list BANKDIC = bank : Danske , Nordea $
|
|
1327
|
+
do BANKDIC $
|
|
1328
|
+
frml x {bank}_income = {bank}_a +{bank}_b $
|
|
1329
|
+
enddo $
|
|
1330
|
+
frml x ialt=max(bankdic,{bank}_income) $''')))
|
|
1331
|
+
#%%
|
|
1332
|
+
# Trying some of the features:
|
|
1333
|
+
fmodel='''
|
|
1334
|
+
list BANKDIC = currentbank : Danske , Nordea , Jyske $
|
|
1335
|
+
list BANKDIC2 = loantobank : Danske , Nordea , Jyske $
|
|
1336
|
+
list BANKDIC3 = loanfrombank : Danske , Nordea , Jyske $
|
|
1337
|
+
frml <matrix> msigma = to_matrix(bankdic,bankdic2,cov_{currentbank}_{loantobank} ) $
|
|
1338
|
+
frml <matrix> vreturn = to_matrix(bankdic2,return_{loantobank}) $
|
|
1339
|
+
frml <matrix> vcapitalweights = to_matrix(bankdic2,capitalweights_{loantobank}) $
|
|
1340
|
+
|
|
1341
|
+
do BANKDIC $
|
|
1342
|
+
do bankdic2 $
|
|
1343
|
+
frml setmax loanmax_{currentbank}_to_{loantobank} = {currentbank}_capital*0.25 $
|
|
1344
|
+
frml setmin loanmin_{currentbank}_to_{loantobank} = 0.0 $
|
|
1345
|
+
enddo$
|
|
1346
|
+
frml setmax loanmax_{currentbank}_to_{currentbank} = 0.0 $
|
|
1347
|
+
frml <matrix> {currentbank}_loan_max =to_matrix(bankdic2,loan_max_{currentbank}_to_{loantobank}) $
|
|
1348
|
+
frml <matrix> {currentbank}_loan_min =to_matrix(bankdic2,loan_min_{currentbank}_to_{loantobank}) $
|
|
1349
|
+
enddo $
|
|
1350
|
+
|
|
1351
|
+
do Bankdic $
|
|
1352
|
+
frml <matrix> loan_{currentbank}_to
|
|
1353
|
+
= mv_opt(msigma,vreturn,riskaversion, {currentbank}_totalloan, vcapitalweights, {currentbank}_capital,
|
|
1354
|
+
{currentbank}_loan_max,{currentbank}_loan_min) $
|
|
1355
|
+
enddo $
|
|
1356
|
+
do Bankdic $
|
|
1357
|
+
frml x {currentbank}_loancheck=sum(bankdic2,{currentbank}_to_{loantobank}_loan)$
|
|
1358
|
+
enddo $ '''
|
|
1359
|
+
modelprint(fmodel)
|
|
1360
|
+
modelprint(sumunroll(argunroll(creatematrix(dounloop(fmodel)))))
|
|
1361
|
+
#%%
|
|
1362
|
+
def f1(x):
|
|
1363
|
+
return x
|
|
1364
|
+
|
|
1365
|
+
eq='''FRML <> logit(pd_country_sector) =
|
|
1366
|
+
0.008 + 0.44 * logit(pd_country_sector(-1)) - 0.18 * gdp_country -0.05*gdp_country(-1) + 0.12 * URX_country + 0.02 * sltn_country + 0.11 * nsltn_country(-1) $ '''
|
|
1367
|
+
# eq='''FRML <> logit(cow) = logit(1+1) + diff(a) $ '''
|
|
1368
|
+
# eq='''FRML <> x = diff(f1(a)) $ '''
|
|
1369
|
+
print(eq)
|
|
1370
|
+
print('After normalization' )
|
|
1371
|
+
neq=normalize(eq,funks=[f1]).lower()
|
|
1372
|
+
print(neq)
|
|
1373
|
+
toteq=eq.lower()+neq
|
|
1374
|
+
|
|
1375
|
+
#%%
|
|
1376
|
+
|
|
1377
|
+
org ='''
|
|
1378
|
+
! credit risk
|
|
1379
|
+
! calculate pd for each portefolio sector based on bank specific starting point
|
|
1380
|
+
! remember to do a .replace('%seg%','{bank}__{CrCountry}__{PortSeg}')
|
|
1381
|
+
do banklist $
|
|
1382
|
+
do {bank}CrCoList $
|
|
1383
|
+
do PortSegList $
|
|
1384
|
+
! non defaultet stock
|
|
1385
|
+
non_def_exp_end_y__%seg% = non_def_exp_end_y__%seg%(-1)*(1-pd_pit__Q__%seg%) $
|
|
1386
|
+
|
|
1387
|
+
! for this prototype we just use last period LGD
|
|
1388
|
+
Lgd_pit_new_scen__%seg% = Lgd_pit_new_scen__%seg%(-1) $
|
|
1389
|
+
|
|
1390
|
+
! gross impairemens (losses) newly defaulted stock
|
|
1391
|
+
gross_imp_loss_new_def__%seg% = non_def_exp_end_y__%seg%(-1)*pd_pit__Q__%seg%*Lgd_pit_new_scen__%seg% $
|
|
1392
|
+
|
|
1393
|
+
! share of provision stock which can ofset the impairements
|
|
1394
|
+
alfa__%seg% = pd_pit__Q__%seg% $
|
|
1395
|
+
|
|
1396
|
+
part of provision stock which can ofset losses
|
|
1397
|
+
prov_release_new_def__%seg% = alfa__%seg% * prov_stock_end_y__%seg%(-1) $
|
|
1398
|
+
|
|
1399
|
+
! net impairemens on newly defaulted stock, can only contribute to loss
|
|
1400
|
+
imp_loss_new_def__%seg% = max(0.0, gross_imp_loss_new_def__%seg% - prov_release_new_def__%seg%) $
|
|
1401
|
+
|
|
1402
|
+
! update the stock of provisions relateed to newly defaulted amount after release to cover impairement
|
|
1403
|
+
prov_stock_end_y__%seg% = prov_stock_end_y__%seg%(-1) + diff(imp_loss_new_def__%seg%) $
|
|
1404
|
+
|
|
1405
|
+
! now we look at previous defaulted loans
|
|
1406
|
+
|
|
1407
|
+
! defaulted exposure
|
|
1408
|
+
def_stock_end_y__%seg% = def_stock_end_y__%seg%(-1) + non_def_exp_end_y__%seg%(-1)*pd_pit__Q__%seg% $
|
|
1409
|
+
|
|
1410
|
+
! impairement old defaulted stock, can not contribute to profit only loss
|
|
1411
|
+
imp_loss_old_def__%seg% = max(0,diff(Lgd_pit_old_scen__%seg%)* def_stock_end_y__%seg%(-1)) $
|
|
1412
|
+
|
|
1413
|
+
! amount of provisions stock relateed to old defaulted stock
|
|
1414
|
+
prov_stock_end_y_def__%seg% = prov_stock_end_y_def__%seg%(-1)+imp_loss_old_def__%seg% $
|
|
1415
|
+
|
|
1416
|
+
! total impairment
|
|
1417
|
+
imp_loss_total_def__%seg% = imp_loss_old_def__%seg% +imp_loss_new_def__%seg% $
|
|
1418
|
+
|
|
1419
|
+
enddo $
|
|
1420
|
+
enddo $
|
|
1421
|
+
frml <> imp_loss_total_def__{bank} = sum({bank}CrCoList,sum(PortSegList,imp_loss_total_def__%seg%)) $
|
|
1422
|
+
|
|
1423
|
+
enddo $
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
'''
|
|
1427
|
+
|
|
1428
|
+
print((doable(org)))
|
|
1429
|
+
print(tofrml(doable(org),sep='$'))
|
|
1430
|
+
|
|
1431
|
+
print(tofrml('a=b \n c=55 ',sep='\n'))
|
|
1432
|
+
#%%
|
|
1433
|
+
model = '''\
|
|
1434
|
+
! jjjfj
|
|
1435
|
+
list alist = al : a b c
|
|
1436
|
+
a = c(-1) + b(-1)
|
|
1437
|
+
x = 0.5 * c
|
|
1438
|
+
d = x + 3 * a(-1)
|
|
1439
|
+
'''
|
|
1440
|
+
print(tofrml(model))
|
|
1441
|
+
|
|
1442
|
+
|
|
1443
|
+
# testtofrml
|
|
1444
|
+
mtest = '''
|
|
1445
|
+
list banklist = bank : ib soren marie /
|
|
1446
|
+
country : denmark sweden denmark $
|
|
1447
|
+
|
|
1448
|
+
do banklist $
|
|
1449
|
+
! kkdddk
|
|
1450
|
+
frml <> profit_{bank} = revenue_{bank} - lag_array(-3,expenses_{bank}) $
|
|
1451
|
+
frml <> expenses_{bank} = factor_{country} * revenue_{bank} $
|
|
1452
|
+
enddo $
|
|
1453
|
+
'''
|
|
1454
|
+
|
|
1455
|
+
print(tofrml(mtest))
|
|
1456
|
+
print(explode(mtest))
|
|
1457
|
+
#%% unnormlize
|
|
1458
|
+
if __name__ == '__main__' :
|
|
1459
|
+
|
|
1460
|
+
print(un_normalize_expression('a=b',implicit=True,endo='xx' ))
|
|
1461
|
+
|