passagemath-gap-pkg-float 10.8.1a4__cp311-cp311-macosx_13_0_x86_64.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.
Files changed (46) hide show
  1. gap/pkg/float/COPYING +340 -0
  2. gap/pkg/float/PackageInfo.g +109 -0
  3. gap/pkg/float/README.md +76 -0
  4. gap/pkg/float/THANKS +1 -0
  5. gap/pkg/float/TODO +9 -0
  6. gap/pkg/float/bin/x86_64-apple-darwin24-default64-kv10/float.so +0 -0
  7. gap/pkg/float/build-aux/compile +348 -0
  8. gap/pkg/float/build-aux/config.guess~ +1748 -0
  9. gap/pkg/float/build-aux/config.sub~ +1884 -0
  10. gap/pkg/float/build-aux/depcomp +791 -0
  11. gap/pkg/float/build-aux/install-sh +541 -0
  12. gap/pkg/float/build-aux/install-sh~ +541 -0
  13. gap/pkg/float/build-aux/ltmain.sh +11524 -0
  14. gap/pkg/float/build-aux/missing +215 -0
  15. gap/pkg/float/config.h.in +105 -0
  16. gap/pkg/float/init.g +51 -0
  17. gap/pkg/float/lib/cxsc.gi +604 -0
  18. gap/pkg/float/lib/float.gd +187 -0
  19. gap/pkg/float/lib/fplll.gi +27 -0
  20. gap/pkg/float/lib/mpc.gi +243 -0
  21. gap/pkg/float/lib/mpfi.gi +270 -0
  22. gap/pkg/float/lib/mpfr.gi +328 -0
  23. gap/pkg/float/lib/pickle.g +131 -0
  24. gap/pkg/float/lib/polynomial.gi +12 -0
  25. gap/pkg/float/lib/pslq.gi +431 -0
  26. gap/pkg/float/libtool +12190 -0
  27. gap/pkg/float/makedoc.g +11 -0
  28. gap/pkg/float/read.g +46 -0
  29. gap/pkg/float/tst/arithmetic.tst +35 -0
  30. gap/pkg/float/tst/fplll.tst +19 -0
  31. gap/pkg/float/tst/polynomials.tst +30 -0
  32. gap/pkg/float/tst/testall.g +63 -0
  33. passagemath_gap_pkg_float/.dylibs/libfplll.9.dylib +0 -0
  34. passagemath_gap_pkg_float/.dylibs/libgmp.10.dylib +0 -0
  35. passagemath_gap_pkg_float/.dylibs/libmpc.3.dylib +0 -0
  36. passagemath_gap_pkg_float/.dylibs/libmpfi.0.dylib +0 -0
  37. passagemath_gap_pkg_float/.dylibs/libmpfr.6.dylib +0 -0
  38. passagemath_gap_pkg_float/__init__.py +3 -0
  39. passagemath_gap_pkg_float-10.8.1a4.dist-info/METADATA +92 -0
  40. passagemath_gap_pkg_float-10.8.1a4.dist-info/METADATA.bak +93 -0
  41. passagemath_gap_pkg_float-10.8.1a4.dist-info/RECORD +46 -0
  42. passagemath_gap_pkg_float-10.8.1a4.dist-info/WHEEL +6 -0
  43. passagemath_gap_pkg_float-10.8.1a4.dist-info/top_level.txt +2 -0
  44. sage/all__sagemath_gap_pkg_float.py +1 -0
  45. sage/libs/all__sagemath_gap_pkg_float.py +1 -0
  46. sage/libs/gap_pkg_float.cpython-311-darwin.so +0 -0
@@ -0,0 +1,131 @@
1
+ # picklers
2
+
3
+ InstallMethod( IO_Pickle, "for a IEEE754 float", [ IsFile, IsIEEE754FloatRep ],
4
+ function( f, v )
5
+ if IO_Write(f,"I3EF")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
6
+ return IO_Error;
7
+ fi;
8
+ return IO_OK;
9
+ end);
10
+
11
+ IO_Unpicklers.I3EF :=
12
+ function( f )
13
+ local r;
14
+ r := IO_Unpickle(f);
15
+ if not IsList(r) then return IO_Error; fi;
16
+ return NewFloat(IsIEEE754FloatRep,r);
17
+ end;
18
+
19
+ if IsBound(MPFR_INT) then
20
+ InstallMethod( IO_Pickle, "for a MPFR float", [ IsFile, IsMPFRFloat ],
21
+ function( f, v )
22
+ if IO_Write(f,"MPFR")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
23
+ return IO_Error;
24
+ fi;
25
+ return IO_OK;
26
+ end);
27
+
28
+ IO_Unpicklers.MPFR :=
29
+ function( f )
30
+ local r;
31
+ r := IO_Unpickle(f);
32
+ if not IsList(r) then return IO_Error; fi;
33
+ return NewFloat(IsMPFRFloat,r);
34
+ end;
35
+ fi;
36
+
37
+ if IsBound(MPFI_INT) then
38
+ InstallMethod( IO_Pickle, "for a MPFI float", [ IsFile, IsMPFIFloat ],
39
+ function( f, v )
40
+ if IO_Write(f,"MPFI")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
41
+ return IO_Error;
42
+ fi;
43
+ return IO_OK;
44
+ end);
45
+
46
+ IO_Unpicklers.MPFI := function( f )
47
+ local r;
48
+ r := IO_Unpickle(f);
49
+ if not IsList(r) then return IO_Error; fi;
50
+ return NewFloat(IsMPFIFloat,r);
51
+ end;
52
+ fi;
53
+
54
+ if IsBound(MPC_INT) then
55
+ InstallMethod( IO_Pickle, "for a MPC float", [ IsFile, IsMPCFloat ],
56
+ function( f, v )
57
+ if IO_Write(f,"MPCX")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
58
+ return IO_Error;
59
+ fi;
60
+ return IO_OK;
61
+ end);
62
+
63
+ IO_Unpicklers.MPC := function( f )
64
+ local r;
65
+ r := IO_Unpickle(f);
66
+ if not IsList(r) then return IO_Error; fi;
67
+ return NewFloat(IsMPCFloat,r);
68
+ end;
69
+ fi;
70
+
71
+ if IsBound(CXSC_INT) then
72
+ InstallMethod( IO_Pickle, "for a CXSC float", [ IsFile, IsCXSCReal ],
73
+ function( f, v )
74
+ if IO_Write(f,"XSCR")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
75
+ return IO_Error;
76
+ fi;
77
+ return IO_OK;
78
+ end);
79
+
80
+ IO_Unpicklers.XSCR := function( f )
81
+ local r;
82
+ r := IO_Unpickle(f);
83
+ if not IsList(r) then return IO_Error; fi;
84
+ return NewFloat(IsCXSCReal,r);
85
+ end;
86
+
87
+ InstallMethod( IO_Pickle, "for a CXSC float", [ IsFile, IsCXSCInterval ],
88
+ function( f, v )
89
+ if IO_Write(f,"XSCI")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
90
+ return IO_Error;
91
+ fi;
92
+ return IO_OK;
93
+ end);
94
+
95
+ IO_Unpicklers.XSCI := function( f )
96
+ local r;
97
+ r := IO_Unpickle(f);
98
+ if not IsList(r) then return IO_Error; fi;
99
+ return NewFloat(IsCXSCInterval,r);
100
+ end;
101
+
102
+ InstallMethod( IO_Pickle, "for a CXSC float", [ IsFile, IsCXSCComplex ],
103
+ function( f, v )
104
+ if IO_Write(f,"XSCC")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
105
+ return IO_Error;
106
+ fi;
107
+ return IO_OK;
108
+ end);
109
+
110
+ IO_Unpicklers.XSCC := function( f )
111
+ local r;
112
+ r := IO_Unpickle(f);
113
+ if not IsList(r) then return IO_Error; fi;
114
+ return NewFloat(IsCXSCComplex,r);
115
+ end;
116
+
117
+ InstallMethod( IO_Pickle, "for a CXSC float", [ IsFile, IsCXSCBox ],
118
+ function( f, v )
119
+ if IO_Write(f,"XSCB")=fail or IO_Pickle(f,ExtRepOfObj(v))<>IO_OK then
120
+ return IO_Error;
121
+ fi;
122
+ return IO_OK;
123
+ end);
124
+
125
+ IO_Unpicklers.XSCB := function( f )
126
+ local r;
127
+ r := IO_Unpickle(f);
128
+ if not IsList(r) then return IO_Error; fi;
129
+ return NewFloat(IsCXSCBox,r);
130
+ end;
131
+ fi;
@@ -0,0 +1,12 @@
1
+ #############################################################################
2
+ ##
3
+ #W cxsc.gi GAP library Laurent Bartholdi
4
+ ##
5
+ #Y Copyright (C) 2008 Laurent Bartholdi
6
+ ##
7
+ ## This file implements polynomials over floats
8
+ ##
9
+
10
+ #############################################################################
11
+ ##
12
+ #E
@@ -0,0 +1,431 @@
1
+ #############################################################################
2
+ ##
3
+ #W pslq.gi GAP float Steve A. Linton
4
+ ##
5
+ #Y Copyright (C) 2014 Steve Linton & Laurent Bartholdi
6
+ ##
7
+ ## This file implements the PSLQ and multi-pair PSLQ algorithms as described
8
+ ## in "Parallel Integer Relation Detection: Techniques and Applications
9
+ ## David H. Bailey and David J. Broadhurst" Math.Comput. 70 (2001) 1719-1736
10
+ ##
11
+ ## Both implementations follow the paper quite closely. The main input
12
+ ## is a vector of floats in some appropriate extended precision representation
13
+ ## There is currently no detection of whether the representation is extended
14
+ ## enough, although the algorithm will probably not terminate if it is not
15
+ ## when this class is set to level 2 or higher it prints a few numbers
16
+ ## indicating progress at each iteration
17
+
18
+ # TODO: implement the multi-level version
19
+ # TODO: parallelise the multi-pair version.
20
+ # TODO: detect when there is insufficient precisiona and fail cleanly.
21
+
22
+ BindGlobal("defaultgamma@", 2.0/Sqrt(3.0));
23
+
24
+ ## <#GAPDoc Label="PSLQ">
25
+ ## The PSLQ algorithm has been implemented by Steve A. Linton, as an external
26
+ ## contribution to <Package>Float</Package>. This algorithm receives as
27
+ ## input a vector of floats <M>x</M> and a required precision <M>\epsilon</M>,
28
+ ## and seeks an integer vector <M>v</M> such that
29
+ ## <M>|x\cdot v|&lt;\epsilon</M>. The implementation follows quite closely the
30
+ ## original article <Cite Key="MR1836930"/>.
31
+ ##
32
+ ## <ManSection>
33
+ ## <Func Name="PSLQ" Arg="x, epsilon[, gamma]"/>
34
+ ## <Func Name="PSLQ_MP" Arg="x, epsilon[, gamma [,beta]]"/>
35
+ ## <Returns>An integer vector <M>v</M> with <M>|x\cdot v|&lt;\epsilon</M>.</Returns>
36
+ ## <Description>
37
+ ## The PSLQ algorithm by Bailey and Broadhurst (see <Cite Key="MR1836930"/>)
38
+ ## searches for an integer relation between the entries in <M>x</M>.
39
+ ##
40
+ ## <P/><M>\beta</M> and <M>\gamma</M> are algorithm tuning parameters, and
41
+ ## default to <M>4/10</M> and <M>2/\sqrt(3)</M> respectively.
42
+ ##
43
+ ## <P/>The second form implements the "Multi-pair" variant of the algorithm, which is
44
+ ## better suited to parallelization.
45
+ ## <Example><![CDATA[
46
+ ## gap> PSLQ([1.0,(1+Sqrt(5.0))/2],1.e-2);
47
+ ## [ 55, -34 ] # Fibonacci numbers
48
+ ## gap> RootsFloat([1,-4,2]*1.0);
49
+ ## [ 0.292893, 1.70711 ] # roots of 2x^2-4x+1
50
+ ## gap> PSLQ(List([0..2],i->last[1]^i),1.e-7);
51
+ ## [ 1, -4, 2 ] # a degree-2 polynomial fitting well
52
+ ## ]]></Example>
53
+ ## </Description>
54
+ ## </ManSection>
55
+ ## <#/GAPDoc>
56
+ ##
57
+ BindGlobal("PSLQ", function(arg)
58
+ local sample, eps, gamma, one, zero, redentry, swapEntries, n, i,
59
+ y, A, B, s, s2, t, H, j, count, best, m, q, a, t0, t1, t2,
60
+ t3, t4, l, M, rp, ym, x;
61
+
62
+ # Process arguments and set up a few constants
63
+
64
+ if Length(arg) < 2 or Length(arg) > 4 or not ForAll(arg[1], IsFloat) then
65
+ Error("Usage: pslq(x, epsilon [, gamma] ) default gamme is 2/sqrt(3)");
66
+ fi;
67
+
68
+ x := arg[1];
69
+ sample := x[1];
70
+ eps := arg[2];
71
+ if Length(arg) = 3 then
72
+ gamma := arg[3];
73
+ else
74
+ gamma := MakeFloat(sample, defaultgamma@);
75
+ fi;
76
+
77
+ #
78
+ # We can't just use 1.0 or 0.0 because they might not have the right representation
79
+ #
80
+
81
+ one := One(sample);
82
+ zero := Zero(sample);
83
+
84
+
85
+ #
86
+ # Basic step in HNF calculations, used in a couple of places
87
+ #
88
+
89
+ redentry := function(i,j)
90
+ local t, ti;
91
+ t := Round(H[i][j]/H[j][j]);
92
+ ti := Int(t);
93
+ y[j] := y[j] + t*y[i];
94
+ AddRowVector(H[i],H[j],-t,1,j);
95
+ AddRowVector(A[i],A[j],-ti,1,n);
96
+ AddRowVector(B[j],B[i],ti,1,n);
97
+ end;
98
+
99
+
100
+ #
101
+ # swap entries m and m+1 in list a
102
+ #
103
+
104
+ swapEntries := function(a, m)
105
+ local t;
106
+ t := a[m];
107
+ a[m] := a[m+1];
108
+ a[m+1] := t;
109
+ end;
110
+
111
+
112
+ n := Length(x);
113
+
114
+ #
115
+ # If the list includes something close enough to zero, the problem is easy
116
+ #
117
+ i := PositionProperty(x, y->AbsoluteValue(y) < eps);
118
+ if i <> fail then
119
+ y := ListWithIdenticalEntries(n,0);
120
+ y[i] := 1;
121
+ return y;
122
+ fi;
123
+
124
+ #
125
+ # and now to work.
126
+ #
127
+
128
+
129
+ #
130
+ # Initial setup
131
+ #
132
+
133
+ A := IdentityMat(n,Integers);
134
+ B := IdentityMat(n,Integers);
135
+ s := [];
136
+ s2 := zero;
137
+ for i in [n,n-1..1] do
138
+ s2 := s2 + x[i]^2;
139
+ s[i] := Sqrt(s2);
140
+ od;
141
+ t := one/s[1];
142
+ y := t*x;
143
+ s := t*s;
144
+ H := List([1..n], i->[]);
145
+ for j in [1..n-1] do
146
+ for i in [1..j-1] do
147
+ H[i][j] := zero;
148
+ od;
149
+ H[j][j] := s[j+1]/s[j];
150
+ for i in [j+1..n] do
151
+ H[i][j] := -y[i]*y[j]/(s[j]*s[j+1]);
152
+ od;
153
+ od;
154
+
155
+ for i in [2..n] do
156
+ for j in [i-1,i-2..1] do
157
+ redentry(i,j);
158
+ od;
159
+ od;
160
+
161
+ count := 0;
162
+
163
+ #
164
+ # Main loop
165
+ #
166
+ repeat
167
+ count := count+1;
168
+
169
+ #
170
+ # find row to work on (maximum of gamma^i*H[i][i])
171
+ #
172
+ best := -one;
173
+ m := fail;
174
+ q := one;
175
+ for i in [1..n-1] do
176
+ q := q*gamma;
177
+ a := q*AbsoluteValue(H[i][i]);
178
+ if a > best then
179
+ m := i;
180
+ best := a;
181
+ fi;
182
+ od;
183
+
184
+ #
185
+ # exchange step
186
+ #
187
+ swapEntries(y,m);
188
+ swapEntries(A,m);
189
+ swapEntries(B,m);
190
+ swapEntries(H,m);
191
+
192
+
193
+ #
194
+ # Corner step
195
+ #
196
+
197
+ if m <= n-2 then
198
+ t0 := Sqrt(H[m][m]^2 + H[m][m+1]^2);
199
+ t1 := H[m][m]/t0;
200
+ t2 := H[m][m+1]/t0;
201
+ for i in [m..n] do
202
+ t3 := H[i][m];
203
+ t4 := H[i][m+1];
204
+ H[i][m] := t1*t3 + t2*t4;
205
+ H[i][m+1] := -t2*t3 + t1*t4;
206
+ od;
207
+ fi;
208
+
209
+ #
210
+ # Reduction step
211
+ #
212
+
213
+ for i in [m+1..n] do
214
+ l := Minimum(i-1,m+1);
215
+ for j in [l,l-1..1] do
216
+ redentry(i,j);
217
+ od;
218
+ od;
219
+
220
+ #
221
+ # Take stock at the end of the iteration
222
+ #
223
+
224
+ M := 1.0/Maximum(List([1..n-1], i->AbsoluteValue(H[i][i])));
225
+
226
+ rp := 1;
227
+ ym := AbsoluteValue(y[1]);
228
+ for i in [2..n] do
229
+ t := AbsoluteValue(y[i]);
230
+ if t < ym then
231
+ ym := t;
232
+ rp := i;
233
+ fi;
234
+ od;
235
+ Info(InfoFloat, 2, count,": ",Int(M)," ",Int(Log10(ym)));
236
+
237
+ until ym < eps;
238
+ return B[rp];
239
+ end);
240
+
241
+ BindGlobal("defaultbeta@", 4/10);
242
+
243
+ BindGlobal("PSLQ_MP", function(arg)
244
+ local swapEntries, x, eps, sample, n, one, zero, gamma, betan, i,
245
+ y, A, B, s, s2, t, H, j, count, v, q, l, used, pairs, p, m,
246
+ t0, t1, t2, t3, t4, T, k, M, rp, ym;
247
+ #
248
+ # swap entries m and m+1 in list a
249
+ #
250
+
251
+ swapEntries := function(a, m)
252
+ local t;
253
+ t := a[m];
254
+ a[m] := a[m+1];
255
+ a[m+1] := t;
256
+ end;
257
+
258
+ if Length(arg) < 2 or Length(arg) > 4 or not ForAll(arg[1],IsFloat) then
259
+ Error("Usage: pslqMP( x, epsilon[, gamma[, beta]])");
260
+ fi;
261
+ x := arg[1];
262
+ eps := arg[2];
263
+
264
+ sample := x[1];
265
+ n := Length(x);
266
+ one := One(sample);
267
+ zero := Zero(sample);
268
+
269
+ if Length(arg) > 2 then
270
+ gamma := arg[3];
271
+ else
272
+ gamma := MakeFloat(sample, defaultgamma@);
273
+ fi;
274
+
275
+ if Length(arg) > 3 then
276
+ betan := arg[4]*n;
277
+ else
278
+ betan := n*defaultbeta@;
279
+ fi;
280
+
281
+ #
282
+ # If the list includes something close enough to zero, the problem is easy
283
+ #
284
+ i := PositionProperty(x, y->AbsoluteValue(y) < eps);
285
+ if i <> fail then
286
+ y := ListWithIdenticalEntries(n,0);
287
+ y[i] := 1;
288
+ return y;
289
+ fi;
290
+
291
+ #
292
+ # Start the real work
293
+ #
294
+
295
+ A := IdentityMat(n,Integers);
296
+ B := IdentityMat(n,Integers);
297
+ s := [];
298
+ s2 := zero;
299
+ for i in [n,n-1..1] do
300
+ s2 := s2 + x[i]^2;
301
+ s[i] := Sqrt(s2);
302
+ od;
303
+ t := one/s[1];
304
+ y := t*x;
305
+ s := t*s;
306
+ H := List([1..n], i->[]);
307
+ for j in [1..n-1] do
308
+ for i in [1..j-1] do
309
+ H[i][j] := zero;
310
+ od;
311
+ H[j][j] := s[j+1]/s[j];
312
+ for i in [j+1..n] do
313
+ H[i][j] := -y[i]*y[j]/(s[j]*s[j+1]);
314
+ od;
315
+ od;
316
+
317
+ count := 0;
318
+ #
319
+ # Main loop
320
+ #
321
+ repeat
322
+ count := count+1;
323
+ v := [];
324
+ q := one;
325
+ for i in [1..n-1] do
326
+ q := q*gamma;
327
+ # negate to get the sorting order, since that's all we actually care about
328
+ Add(v, -q*AbsoluteValue(H[i][i]));
329
+ od;
330
+ l := [1..n-1];
331
+ SortParallel(v,l);
332
+
333
+ #
334
+ # Now we sort out our pairs
335
+ #
336
+
337
+ used := BlistList([1..n],[]);
338
+ pairs := [];
339
+ for i in [1..n-1] do
340
+ if not used[l[i]] and not used[l[i]+1] then
341
+ Add(pairs,l[i]);
342
+ used[l[i]] := true;
343
+ used[l[i]+1] := true;
344
+ fi;
345
+ if Length(pairs) > betan then
346
+ break;
347
+ fi;
348
+ od;
349
+
350
+
351
+
352
+ p := Length(pairs);
353
+ for m in pairs do
354
+ swapEntries(y,m);
355
+ swapEntries(A,m);
356
+ swapEntries(B,m);
357
+ swapEntries(H,m);
358
+ od;
359
+
360
+
361
+ for m in pairs do
362
+ if m <= n-2 then
363
+ t0 := Sqrt(H[m][m]^2 + H[m][m+1]^2);
364
+ t1 := H[m][m]/t0;
365
+ t2 := H[m][m+1]/t0;
366
+ for i in [m..n] do
367
+ t3 := H[i][m];
368
+ t4 := H[i][m+1];
369
+ H[i][m] := t1*t3 + t2*t4;
370
+ H[i][m+1] := -t2*t3 + t1*t4;
371
+ od;
372
+ fi;
373
+ od;
374
+
375
+
376
+ T:= List([1..n], i->[]);
377
+ for i in [2..n] do
378
+ for j in [1..n-i+1] do
379
+ l := i+j-1;
380
+ for k in [j+1..l-1] do
381
+ H[l][j] := H[l][j] - T[l][k]*H[k][j];
382
+ od;
383
+
384
+ T[l][j] := Round(H[l][j]/H[j][j]);
385
+ H[l][j] := H[l][j] - T[l][j]*H[j][j];
386
+ od;
387
+ od;
388
+
389
+ for j in [1..n-1] do
390
+ for i in [j+1..n] do
391
+ y[j] := y[j] + T[i][j]*y[i];
392
+ od;
393
+ od;
394
+
395
+ for j in [1..n-1] do
396
+ for i in [j+1..n] do
397
+ AddRowVector(A[i],A[j], -Int(T[i][j]));
398
+ AddRowVector(B[j],B[i], Int(T[i][j]));
399
+ od;
400
+ od;
401
+
402
+
403
+
404
+ M := one/Maximum(List([1..n-1], i->AbsoluteValue(H[i][i])));
405
+
406
+ rp := 1;
407
+ ym := AbsoluteValue(y[1]);
408
+ for i in [2..n] do
409
+ t := AbsoluteValue(y[i]);
410
+ if t < ym then
411
+ ym := t;
412
+ rp := i;
413
+ fi;
414
+ od;
415
+ Info(InfoFloat,2,count,": ",Int(M)," ",Int(Log10(ym)));
416
+
417
+ until ym < eps;
418
+ return B[rp];
419
+ end);
420
+
421
+ # These examples are used in the paper cited above to generate a family of test data.
422
+
423
+ BindGlobal("MakePslqTest@", function(r,s)
424
+ local alpha, xs;
425
+ alpha := Exp(Log(3.0)/r) - Exp(Log(2.0)/s);
426
+ xs := List([0..r*s], i-> alpha^i);
427
+ return xs;
428
+ end);
429
+
430
+ #############################################################################
431
+ #E