Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/designs/incidence_structures.py
4069 views
1
"""
2
Incidence structures.
3
4
An incidence structure is specified by a list of points, blocks,
5
and an incidence matrix ([1], [2]).
6
7
Classes:
8
9
IncidenceStructure
10
11
This software is released under the terms of the GNU General Public
12
License, version 2 or above (your choice). For details on
13
licensing, see the accompanying documentation.
14
15
REFERENCES:
16
17
- [1] Block designs and incidence structures from wikipedia,
18
http://en.wikipedia.org/wiki/Block_design
19
http://en.wikipedia.org/wiki/Incidence_structure
20
21
- [2] E. Assmus, J. Key, Designs and their codes, CUP, 1992.
22
23
This is a significantly modified form of part of the module
24
block_design.py (version 0.6) written by Peter Dobcsanyi
25
[email protected].
26
27
Copyright 2007-2008 by David Joyner [email protected], Peter
28
Dobcsanyi [email protected].
29
"""
30
31
from sage.matrix.matrix_space import MatrixSpace
32
from sage.rings.integer_ring import ZZ
33
from sage.rings.arith import binomial
34
from sage.misc.decorators import rename_keyword
35
36
### utility functions -------------------------------------------------------
37
38
def coordinatewise_product(L):
39
"""
40
L is a list of n-vectors or lists all of length n with a common
41
parent. This returns the vector whose i-th coordinate is the
42
product of the i-th coordinates of the vectors.
43
44
EXAMPLES::
45
46
sage: from sage.combinat.designs.incidence_structures import coordinatewise_product
47
sage: L = [[1,2,3],[-1,-1,-1],[5,7,11]]
48
sage: coordinatewise_product(L)
49
[-5, -14, -33]
50
"""
51
n = len(L[0])
52
ans = [1]*n
53
for x in L:
54
ans = [ans[i]*x[i] for i in range(n)]
55
return ans
56
57
def IncidenceStructureFromMatrix(M, name=None):
58
"""
59
M must be a (0,1)-matrix. Creates a set of "points" from the rows
60
and a set of "blocks" from the columns.
61
62
EXAMPLES::
63
64
sage: from sage.combinat.designs.block_design import BlockDesign
65
sage: BD1 = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
66
sage: M = BD1.incidence_matrix()
67
sage: BD2 = IncidenceStructureFromMatrix(M)
68
sage: BD1 == BD2
69
True
70
"""
71
nm = name
72
v = len(M.rows())
73
b = len(M.columns())
74
#points = range(v)
75
blocks = []
76
for i in range(b):
77
B = []
78
for j in range(v):
79
if M[i,j]!=0:
80
B.append(j)
81
blocks.append(B)
82
return IncidenceStructure(range(v), blocks, name=nm)
83
84
class IncidenceStructure(object):
85
"""
86
This the base class for block designs.
87
"""
88
def __init__(self, pts, blks, inc_mat=None, name=None, test=True):
89
"""
90
The parameters are a pair pts, blks, both of which are a list (blks
91
is a list of lists). If each B in blks is contained in pts then the
92
incidence matrix inc_mat need not (and should not) be given.
93
Otherwise, inc_mat should be the ptsxblks (0,1)-matrix A for which
94
A_i,j=1 iff blks[j] is incident with pts[i].
95
96
Optional keywords are: "inc_mat" (for giving the (0,1)-incidence
97
matrix), and "name" (a string, such as "Fano plane"). "test" (True
98
or False) - if True then each block must be a list of pts.
99
100
EXAMPLES::
101
102
sage: IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
103
Incidence structure with 7 points and 7 blocks
104
105
Points are sorted ::
106
107
sage: BD1 = IncidenceStructure([4,6,0,3,2,5,1],[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
108
sage: BD1.points()
109
[0, 1, 2, 3, 4, 5, 6]
110
111
TESTS:
112
113
The following shows that Trac Ticket #11333 is fixed. ::
114
115
sage: A = IncidenceStructure([0,1],[[0]])
116
sage: B = IncidenceStructure([1,0],[[0]])
117
sage: B==A
118
True
119
120
REFERENCES:
121
122
- E. Assmus, J. Key, Designs and their codes, CUP, 1992.
123
"""
124
bs = []
125
self.pnts = pts
126
self.pnts.sort()
127
v, blocks = len(pts), blks
128
for block in blocks:
129
if test:
130
for x in block:
131
if not(x in self.pnts):
132
raise ValueError('Point %s is not in the base set.'%x)
133
try:
134
y = block[:]
135
y.sort()
136
bs.append(y)
137
except:
138
bs.append(block)
139
bs.sort(cmp)
140
self.v = v
141
self.blcks = bs
142
self.name = name
143
self._incidence_matrix = inc_mat
144
145
def __iter__(self):
146
"""
147
Iterator over the blocks.
148
149
EXAMPLE::
150
151
sage: sts = sage.combinat.designs.block_design.steiner_triple_system(9)
152
sage: list(sts)
153
[[0, 1, 5], [0, 2, 4], [0, 3, 6], [0, 7, 8], [1, 2, 3], [1, 4, 7], [1, 6, 8], [2, 5, 8], [2, 6, 7], [3, 4, 8], [3, 5, 7], [4, 5, 6]]
154
"""
155
156
return iter(self.blcks)
157
158
159
def __repr__(self):
160
"""
161
A print method.
162
163
EXAMPLES::
164
165
sage: from sage.combinat.designs.block_design import BlockDesign
166
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
167
sage: BD
168
Incidence structure with 7 points and 7 blocks
169
"""
170
repr = 'Incidence structure with %s points and %s blocks'%(len(self.pnts),len(self.blcks))
171
return repr
172
173
def __str__(self):
174
"""
175
A print method.
176
177
EXAMPLES::
178
179
sage: from sage.combinat.designs.block_design import BlockDesign
180
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
181
sage: print BD
182
BlockDesign<points=[0, 1, 2, 3, 4, 5, 6], blocks=[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]>
183
sage: BD = IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
184
sage: print BD
185
IncidenceStructure<points=[0, 1, 2, 3, 4, 5, 6], blocks=[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]>
186
"""
187
if self.name:
188
repr = '%s<points=%s, blocks=%s>'%(self.name, self.pnts, self.blcks)
189
else:
190
repr = 'IncidenceStructure<points=%s, blocks=%s>'%( self.pnts, self.blcks)
191
return repr
192
193
def automorphism_group(self):
194
"""
195
Returns the subgroup of the automorphism group of the incidence
196
graph which respects the P B partition. This is (isomorphic to) the
197
automorphism group of the block design, although the degrees
198
differ.
199
200
EXAMPLES::
201
202
sage: from sage.combinat.designs.block_design import BlockDesign
203
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
204
sage: G = BD.automorphism_group(); G
205
Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)]
206
sage: BD = BlockDesign(4,[[0],[0,1],[1,2],[3,3]],test=False)
207
sage: G = BD.automorphism_group(); G
208
Permutation Group with generators [()]
209
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
210
sage: G = BD.automorphism_group(); G
211
Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)]
212
"""
213
from sage.groups.perm_gps.partn_ref.refinement_matrices import MatrixStruct
214
from sage.groups.perm_gps.permgroup import PermutationGroup
215
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
216
M1 = self.incidence_matrix()
217
M2 = MatrixStruct(M1)
218
M2.run()
219
gens = M2.automorphism_group()[0]
220
v = len(self.points())
221
G = SymmetricGroup(v)
222
gns = []
223
for g in gens:
224
L = [j+1 for j in g]
225
gns.append(G(L))
226
return PermutationGroup(gns)
227
228
def block_design_checker(self, t, v, k, lmbda, type=None):
229
"""
230
This is *not* a wrapper for GAP Design's IsBlockDesign. The GAP
231
Design function IsBlockDesign
232
http://www.gap-system.org/Manuals/pkg/design/htm/CHAP004.htmSSEC001.1
233
apparently simply checks the record structure and no mathematical
234
properties. Instead, the function below checks some necessary (but
235
not sufficient) "easy" identities arising from the identity.
236
237
INPUT:
238
239
- ``t`` - the t as in "t-design"
240
241
- ``v`` - the number of points
242
243
- ``k`` - the number of blocks incident to a point
244
245
- ``lmbda`` - each t-tuple of points should be incident with
246
lmbda blocks
247
248
- ``type`` - can be 'simple' or 'binary' or 'connected'
249
Depending on the option, this wraps IsBinaryBlockDesign,
250
IsSimpleBlockDesign, or IsConnectedBlockDesign.
251
252
- Binary: no block has a repeated element.
253
254
- Simple: no block is repeated.
255
256
- Connected: its incidence graph is a connected graph.
257
258
WARNING: This is very fast but can return false positives.
259
260
EXAMPLES::
261
262
sage: from sage.combinat.designs.block_design import BlockDesign
263
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
264
sage: BD.parameters()
265
(2, 7, 3, 1)
266
sage: BD.block_design_checker(2, 7, 3, 1)
267
True
268
sage: BD.block_design_checker(2, 7, 3, 1,"binary")
269
True
270
sage: BD.block_design_checker(2, 7, 3, 1,"connected")
271
True
272
sage: BD.block_design_checker(2, 7, 3, 1,"simple")
273
True
274
"""
275
from sage.sets.set import Set
276
if not(v == len(self.points())):
277
return False
278
b = lmbda*binomial(v,t)/binomial(k,t)
279
r = int(b*k/v)
280
if not(b == len(self.blocks())):
281
return False
282
if not(ZZ(v).divides(b*k)):
283
return False
284
A = self.incidence_matrix()
285
#k = sum(A.columns()[0])
286
#r = sum(A.rows()[0])
287
for i in range(b):
288
if not(sum(A.columns()[i]) == k):
289
return False
290
for i in range(v):
291
if not(sum(A.rows()[i]) == r):
292
return False
293
gD = self._gap_()
294
if type==None:
295
return True
296
if type=="binary":
297
for b in self.blocks():
298
if len(b)!=len(Set(b)):
299
return False
300
return True
301
if type=="simple":
302
B = self.blocks()
303
for b in B:
304
if B.count(b)>1:
305
return False
306
return True
307
if type=="connected":
308
Gamma = self.incidence_graph()
309
if Gamma.is_connected():
310
return True
311
else:
312
return False
313
314
def blocks(self):
315
"""
316
Return the list of blocks.
317
318
EXAMPLES::
319
320
sage: from sage.combinat.designs.block_design import BlockDesign
321
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
322
sage: BD.blocks()
323
[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]
324
"""
325
B = self.blcks
326
B.sort()
327
return B
328
329
def __eq__(self, other):
330
"""
331
Returns true if their points and blocks are equal (resp.).
332
333
EXAMPLES::
334
335
sage: from sage.combinat.designs.block_design import BlockDesign
336
sage: BD1 = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
337
sage: M = BD1.incidence_matrix()
338
sage: BD2 = IncidenceStructureFromMatrix(M)
339
sage: BD1 == BD2
340
True
341
"""
342
bool1 = self.points() == other.points()
343
bool2 = self.blocks() == other.blocks()
344
return (bool1 and bool2)
345
346
def block_sizes(self):
347
"""
348
Return a list of block's sizes.
349
350
EXAMPLES::
351
352
sage: from sage.combinat.designs.block_design import BlockDesign
353
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
354
sage: BD.block_sizes()
355
[3, 3, 3, 3, 3, 3, 3]
356
"""
357
self._block_sizes = map(len,self.blocks())
358
return self._block_sizes
359
360
def _gap_(self):
361
"""
362
Return the GAP string describing the design.
363
364
EXAMPLES::
365
366
sage: from sage.combinat.designs.block_design import BlockDesign
367
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
368
sage: BD._gap_()
369
'BlockDesign(7,[[1, 2, 3], [1, 4, 5], [1, 6, 7], [2, 4, 6], [2, 5, 7], [3, 4, 7], [3, 5, 6]])'
370
"""
371
from sage.sets.set import Set
372
B = self.blocks()
373
v = len(self.points())
374
gB = []
375
for b in B:
376
gB.append([x+1 for x in b])
377
return "BlockDesign("+str(v)+","+str(gB)+")"
378
379
@rename_keyword(deprecated='Sage version 4.6', method="algorithm")
380
def dual_incidence_structure(self, algorithm=None):
381
"""
382
Wraps GAP Design's DualBlockDesign (see [1]). The dual of a block
383
design may not be a block design.
384
385
Also can be called with ``dual_design``.
386
387
REQUIRES: algorithm="gap" option requires GAP's Design package.
388
algorithm=None option does *not* require GAP's Design.
389
390
EXAMPLES::
391
392
sage: from sage.combinat.designs.block_design import BlockDesign
393
sage: D = BlockDesign(4, [[0,2],[1,2,3],[2,3]], test=False)
394
sage: D
395
Incidence structure with 4 points and 3 blocks
396
sage: D.dual_design()
397
Incidence structure with 3 points and 4 blocks
398
sage: print D.dual_design(algorithm="gap") # optional - gap_design
399
IncidenceStructure<points=[0, 1, 2], blocks=[[0], [0, 1, 2], [1], [1, 2]]>
400
sage: BD = IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]], name="FanoPlane")
401
sage: BD
402
Incidence structure with 7 points and 7 blocks
403
sage: print BD.dual_design(algorithm="gap") # optional - gap_design
404
IncidenceStructure<points=[0, 1, 2, 3, 4, 5, 6], blocks=[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]]>
405
sage: BD.dual_incidence_structure()
406
Incidence structure with 7 points and 7 blocks
407
408
REFERENCE:
409
410
- Soicher, Leonard, Design package manual, available at
411
http://www.gap-system.org/Manuals/pkg/design/htm/CHAP003.htm
412
"""
413
from sage.interfaces.gap import gap, GapElement
414
from sage.sets.set import Set
415
from sage.misc.flatten import flatten
416
from sage.combinat.designs.block_design import BlockDesign
417
from sage.misc.functional import transpose
418
if algorithm=="gap":
419
gap.eval('LoadPackage("design")')
420
gD = self._gap_()
421
gap.eval("DD:=DualBlockDesign("+gD+")")
422
v = eval(gap.eval("DD.v"))
423
gblcks = eval(gap.eval("DD.blocks"))
424
gB = []
425
for b in gblcks:
426
gB.append([x-1 for x in b])
427
return IncidenceStructure(range(v), gB, name=None, test=False)
428
pts = self.blocks()
429
M = transpose(self.incidence_matrix())
430
blks = self.points()
431
return IncidenceStructure(pts, blks, M, name=None, test=False)
432
433
dual_design = dual_incidence_structure # to preserve standard terminology
434
435
def incidence_matrix(self):
436
"""
437
Return the incidence matrix A of the design. A is a (v x b) matrix
438
defined by: A[i,j] = 1 if i is in block B_j 0 otherwise
439
440
EXAMPLES::
441
442
sage: BD = IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
443
sage: BD.block_sizes()
444
[3, 3, 3, 3, 3, 3, 3]
445
sage: BD.incidence_matrix()
446
[1 1 1 0 0 0 0]
447
[1 0 0 1 1 0 0]
448
[1 0 0 0 0 1 1]
449
[0 1 0 1 0 1 0]
450
[0 1 0 0 1 0 1]
451
[0 0 1 1 0 0 1]
452
[0 0 1 0 1 1 0]
453
"""
454
if self._incidence_matrix!=None:
455
return self._incidence_matrix
456
else:
457
v = len(self.points())
458
blks = self.blocks()
459
b = len(blks)
460
MS = MatrixSpace(ZZ,v,b)
461
A = MS(0)
462
#A = NUM.zeros((v,b), NUM.Int)
463
for i in range(v):
464
for j, b in enumerate(blks):
465
if i in b:
466
A[i,j] = 1
467
self._incidence_matrix = A
468
return A
469
470
def incidence_graph(self):
471
"""
472
Returns the incidence graph of the design, where the incidence
473
matrix of the design is the adjacency matrix of the graph.
474
475
EXAMPLE::
476
477
sage: BD = IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
478
sage: BD.incidence_graph()
479
Bipartite graph on 14 vertices
480
sage: A = BD.incidence_matrix()
481
sage: Graph(block_matrix([[A*0,A],[A.transpose(),A*0]])) == BD.incidence_graph()
482
True
483
484
REFERENCE:
485
486
- Sage Reference Manual on Graphs
487
"""
488
from sage.graphs.bipartite_graph import BipartiteGraph
489
A = self.incidence_matrix()
490
return BipartiteGraph(A)
491
#same as return Graph(block_matrix([[A*0,A],[A.transpose(),A*0]]))
492
493
def is_block_design(self):
494
"""
495
Returns a pair True, pars if the incidence structure is a t-design,
496
for some t, where pars is the list of parameters [t, v, k, lmbda].
497
The largest possible t is returned, provided t=10.
498
499
EXAMPLES::
500
501
sage: BD = IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
502
sage: BD.is_block_design()
503
(True, [2, 7, 3, 1])
504
sage: BD.block_design_checker(2, 7, 3, 1)
505
True
506
sage: BD = WittDesign(9) # requires optional gap package 'design'
507
sage: BD.is_block_design() # requires optional gap package 'design'
508
(True, [2, 9, 3, 1])
509
sage: BD = WittDesign(12) # requires optional gap package 'design'
510
sage: BD.is_block_design() # requires optional gap package 'design'
511
(True, [5, 12, 6, 1])
512
sage: BD = AffineGeometryDesign(3, 1, GF(2))
513
sage: BD.is_block_design()
514
(True, [2, 8, 2, 2])
515
"""
516
from sage.combinat.designs.incidence_structures import coordinatewise_product
517
from sage.combinat.combinat import unordered_tuples, combinations
518
from sage.coding.linear_code import hamming_weight
519
A = self.incidence_matrix()
520
v = len(self.points())
521
b = len(self.blocks())
522
k = sum(A.columns()[0])
523
rowsA = A.rows()
524
VS = rowsA[0].parent()
525
r = sum(rowsA[0])
526
for i in range(b):
527
if not(sum(A.columns()[i]) == k):
528
return False
529
for i in range(v):
530
if not(sum(A.rows()[i]) == r):
531
return False
532
t_found_yet = False
533
lambdas = []
534
for t in range(2,min(v,11)):
535
#print t
536
L1 = combinations(range(v),t)
537
L2 = [[rowsA[i] for i in L] for L in L1]
538
#print t,len(L2)
539
lmbda = hamming_weight(VS(coordinatewise_product(L2[0])))
540
lambdas.append(lmbda)
541
pars = [t,v,k,lmbda]
542
#print pars
543
for ell in L2:
544
a = hamming_weight(VS(coordinatewise_product(ell)))
545
if not(a == lmbda) or a==0:
546
if not(t_found_yet):
547
pars = [t-1,v,k,lambdas[t-3]]
548
return False, pars
549
else:
550
#print pars, lambdas
551
pars = [t-1,v,k,lambdas[t-3]]
552
return True, pars
553
t_found_yet = True
554
pars = [t-1,v,k,lambdas[t-3]]
555
return True, pars
556
557
def parameters(self, t=2):
558
"""
559
Returns (t,v,k,lambda). Does not check if the input is a block
560
design. Uses t=2 by default.
561
562
EXAMPLES::
563
564
sage: from sage.combinat.designs.block_design import BlockDesign
565
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]], name="FanoPlane")
566
sage: BD.parameters()
567
(2, 7, 3, 1)
568
sage: BD.parameters(t=3)
569
(3, 7, 3, 0)
570
"""
571
v = len(self.points())
572
blks = self.blocks()
573
k = len(blks[int(0)])
574
b = len(blks)
575
#A = self.incidence_matrix()
576
#r = sum(A.rows()[0])
577
lmbda = int(b/(binomial(v,t)/binomial(k,t)))
578
return (t,v,k,lmbda)
579
580
def points(self):
581
"""
582
Returns the list of points.
583
584
EXAMPLES::
585
586
sage: from sage.combinat.designs.block_design import BlockDesign
587
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
588
sage: BD.points()
589
[0, 1, 2, 3, 4, 5, 6]
590
"""
591
return self.pnts
592
593
def points_from_gap(self):
594
"""
595
Literally pushes this block design over to GAP and returns the
596
points of that. Other than debugging, usefulness is unclear.
597
598
REQUIRES: GAP's Design package.
599
600
EXAMPLES::
601
602
sage: from sage.combinat.designs.block_design import BlockDesign
603
sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
604
sage: BD.points_from_gap() # requires optional gap package 'design'
605
[1, 2, 3, 4, 5, 6, 7]
606
"""
607
from sage.interfaces.gap import gap, GapElement
608
from sage.sets.set import Set
609
gap.eval('LoadPackage("design")')
610
gD = self._gap_()
611
gP = gap.eval("BlockDesignPoints("+gD+")").replace("..",",")
612
return range(eval(gP)[0],eval(gP)[1]+1)
613
614
615
616
617