COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/sets.e687097.14%61478078.72%166
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
is_subset_()254259.52%17
embed_union_()334967.35%16
subsets()72330.43%16
distributes_left_()172860.71%11
distributes_right_()172860.71%11
difference()344477.27%10
is_injective()31323.08%10
map()132065.00%7
intersection_()303683.33%6
has_right_unit()91464.29%5
operation()101566.67%5
section()141973.68%5
delta()81266.67%4
bounded_integer()5862.50%3
has_unit_()4757.14%3
report_error()030.00%3
union1()91275.00%3
define_operation()121485.71%2
has_inverse()020.00%2
image()5771.43%2
is_associative()131586.67%2
is_right_unit_()6875.00%2
is_symmetric()101283.33%2
sequences_to_map()131586.67%2
set()111384.62%2
union_()384095.00%2
add_to_()6785.71%1
all_right_units()141593.33%1
change_target_()151693.75%1
combine_maps()192095.00%1
compose_map_()8988.89%1
direct_map()111291.67%1
fiber_over_()91090.00%1
has_left_unit()3475.00%1
iota()7887.50%1
is_bijective()3475.00%1
is_surjective_()3475.00%1
product_()151693.75%1
remove_from_()6785.71%1
abs()44100.00%0
add_to()22100.00%0
all_left_units()22100.00%0
all_left_units_()1010100.00%0
amalgamated_sum()66100.00%0
belongs_to()44100.00%0
bfind()2525100.00%0
cardinal()22100.00%0
change_target()22100.00%0
compose_map()22100.00%0
define_map()77100.00%0
diagram_commutes()22100.00%0
distributes_over()22100.00%0
embed_union()22100.00%0
embedding()22100.00%0
fiber_over()22100.00%0
fiber_product()99100.00%0
has_unit()66100.00%0
intersection()22100.00%0
is_left_unit()44100.00%0
is_subset()22100.00%0
is_surjective()22100.00%0
is_unit()22100.00%0
product()22100.00%0
product_map()1010100.00%0
range()66100.00%0
remove_from()22100.00%0
restrict()1010100.00%0
reverse_map()1111100.00%0
sequence_to_set()22100.00%0
union()22100.00%0
LINE COVERAGE DETAIL
#Executed
1
-- (c) Copyright - See License.txt
2
--
3
namespace sets
4
5
--****
6
-- == Sets
7
--
8
-- <>
9
--
10
-- The sets.e module defines a type for sets and provides basic tools for handling them.
11
--
12
-- Other modules may be built upon them, for instance graph handling or simple topology, finite groups etc.
13
--
14
-- Notes:
15
-- * A //set// is an ordered sequence in ascending order, not more, not less
16
-- * A //map// from setA to setB is a sequence the length of setA whose elements are indexes into setB,
17
-- followed by {length(setA),length(setB)}.
18
-- * An //operation// of E x F ==> G is a two dimensional sequence of elements of G, indexed by
19
-- E x F, and the triple {card(E),card(F),card(G)}.
20
--
21
22
include std/error.e
23
include std/sequence.e
24
250
26
-- Description: Prints an error message on stderr and abort(1)s.
27
-- Takes: {routine name,error message}; both are strings.
280
crash("Error in routine %s in module %s: %s",{s[1],"sets.e",s[2]})
290
end procedure
30
31
--****
32
-- === Types
33
--
34
35
--**
36
-- A set is a sequence in which each item is greater than the previous item.
37
--
38
-- See Also:
39
-- [[:compare]]
40
4185
42
object x,y
43
4485
if atom(s) then
450
return 0
46
end if
47
4885
if length(s) < 2 then
492
return 1
50
end if
51
5283
x = s[1]
5383
for i = 2 to length(s) do
54365
y = s[i]
55365
if eu:compare(y, x) < 1 then
560
return 0
57
end if
58
59365
x = y
60365
end for
61
6283
return 1
63
end type
64
65612
66
-- Description: Returns 0 for a non integer or an out of bounds integer, else 1.
67
-- Takes: object to test; lower allowable bound; upper allowable bound.
68
-- Returns: 1 if x is an integer greater or equal to lbound and less than or
69
-- equal to ubound, else 0.
70
--
71
-- See Also: map, is_left_unit, is_right_unit
72612
if not integer(x) then
730
return 0
74
end if
75612
if x < lbound then
760
return 0
77
end if
78
79612
if x > ubound then
800
return 0
81
end if
82
83612
return 1
84
85
end function
86
87
--**
88
-- Returns 1 if a sequence of integers is a valid map descriptor, else 0.
89
--
90
-- Comments:
91
-- A map is a sequence of indexes. Each index is between 1 and the maximum allowed for the particular map.
92
--
93
-- Actually, what is being called a ##map## is a class of maps, as the elements of the input
94
-- sequence, except for the last two, are ordinals rather than set elements. A map
95
-- contains the information required to map as expected the elements of a set, given by index,
96
-- to another set, where the images are indexes again. Technically, those are maps of the
97
-- category of finite sets quotiented by equality of cardinal.
98
--
99
-- The objects that map.e handle are completely unrelated to these.
100
--
101
-- Example 1:
102
--
103
-- sequence s0 = {2, 3, 4, 1, 4, 2, 6, 4}
104
-- ? map(s0) -- prints out 1.
105
--
106
--
107
-- See Also:
108
-- [[:define_map]], [[:fiber_over]], [[:restrict]], [[:direct_map]], [[:reverse_map]],
109
-- [[:is_injective]], [[:is_surjective]], [[:is_bijective]]
110
111127
112
object p,q
113
114127
if atom(s) then
1150
return 0
116
end if
117
118127
if length(s) <= 2 then
1190
return 0
120
end if
121
122
-- The 2nd last element contains the number of items in the map.
123127
q = s[$-1]
124127
if not integer(q) then
1250
return 0 -- Sanity check failed.
126
end if
127127
if q != length(s)-2 then
1280
return 0 -- Sanity check failed.
129
end if
130
131
-- The last element contains the upper boundary for element values.
132127
p = s[$]
133
134127
if not integer(p) then
1350
return 0 -- Sanity check failed.
136
end if
137
138127
if p < 0 then
1390
return 0 -- Sanity check failed.
140
end if
141
142
-- Check that each element is within the boundaries.
143127
for i = 1 to q do
144609
if not bounded_integer(s[i], 1, p) then
1450
return 0
146
end if
147609
end for
148
149127
return 1
150
end type
151
152
--**
153
-- Returns 1 if the data represents a map from the product of two sets to a third one.
154
--
155
-- Comments:
156
--
157
-- An operation from FxG to H is defined as a sequence of mappings from G to H, plus the
158
-- cardinals of the sets F, G and H. If the input data is consistent with this description,
159
-- 1 is returned, else 0.
160
--
161
-- Example 1:
162
--
163
-- sequence s = {{{2, 3}, {3, 1}, {1, 2}, {2, 3}, {3, 1}}, {5,2,3}}
164
-- -- s represents the addition modulo 3 from {0, 1, 2, 3, 4} x {1, 2} to {0, 1, 2}
165
-- ? operation(s) -- prints out 1.
166
--
167
16819
169
sequence u
170
17119
if atom(s) then
1720
return 0
173
end if
174
17519
if length(s) != 2 then
1760
return 0
177
end if
178
17919
if length(s[2]) != 3 then
1800
return 0
181
end if
182
18319
if length(s[1]) != s[2][1] then
1840
return 0
185
end if
186
187
18819
u = s[2][2..3]
18919
for i=1 to length(s[1]) do
19087
if not map(s[1][i] & u) then
1910
return 0
192
end if
19387
end for
19419
return 1
195
end type
196
197
--****
198
-- === Inclusion and belonging.
199
--
200
201111
202
integer r,c
203
204111
if endpoint > length(haystack) then
2056
endpoint = length(haystack)
206
end if
207111
if startpoint < 1 then
20812
startpoint = 1
209
end if
210
211111
c=eu:compare(needle,haystack[startpoint])
212111
if c=1 then
21394
c=eu:compare(needle,haystack[endpoint])
21494
if c=-1 then
21578
while endpoint - startpoint>1 do
216130
r=floor((endpoint+startpoint)/2)
217130
c=eu:compare(needle,haystack[r])
218130
if c=-1 then
21949
endpoint=r
22081
elsif c=0 then
22166
return r
222
else
22315
startpoint=r
224
end if
22564
end while
22612
return -endpoint
22716
elsif c=0 then
2287
return endpoint
229
else
2309
return -1-endpoint
231
end if
23217
elsif c=0 then
2337
return startpoint
234
else
23510
return -startpoint
236
end if
237
end function
238
239
include std/sort.e
240
include std/sequence.e
241
242
--**
243
-- Makes a set out of a sequence by sorting it and removing duplicate elements.
244
--
245
-- Parameters:
246
-- # ##s## : the sequence to transform.
247
--
248
-- Returns:
249
--
250
-- A **set**, which is the ordered list of distinct elements in ##s##.
251
--
252
-- Example 1:
253
--
254
-- sequence s0 = {1,3,7,5,7,4,1}
255
-- set s1 = sequence_to_set(s0) -- s1 is now {1,3,4,5,7}
256
--
257
--
258
-- See Also:
259
-- [[:set]]
260
26110
26210
return remove_dups(s, RD_SORT)
263
end function
264
265
--**
266
-- Return the cardinal of a set
267
--
268
-- Parameters:
269
-- # ##S## : the set being queried.
270
--
271
-- Returns:
272
--
273
-- An **integer**, the count of elements in S.
274
--
275
-- See Also:
276
-- [[:set]]
277
2781
2791
return length(S)
280
end function
281
282
--**
283
-- Decide whether an object is in a set.
284
--
285
-- Parameters:
286
-- # ##x## : the object inquired about
287
-- # ##S## : the set being queried
288
--
289
-- Returns:
290
--
291
-- An **integer**, 1 if ##x## is in ##S##, else 0.
292
--
293
-- Example 1:
294
--
295
-- set s0 = {1,3,5,7}
296
-- ?belongs_to(2,s) -- prints out 0
297
--
298
--
299
-- See Also:
300
-- [[:is_subset]] , [[:intersection]], [[:difference]]
301
3024
3034
if length( s ) then
3043
return bfind(x, s) > 0
305
else
3061
return 0
307
end if
308
end function
309
3102
311
integer p
312
3132
if length(s) = 0 then
3140
return {x}
315
end if
316
3172
p=bfind(x, s)
3182
if p < 0 then
3191
return insert(s,x,-p)
320
end if
3211
return s
322
end function
323
324
--**
325
-- Add an object to a set.
326
--
327
-- Parameters:
328
-- # ##x## : the object to add
329
-- # ##S## : the set to augment
330
--
331
-- Returns:
332
--
333
-- A **set**, which is a **copy** of ##S##, with the addition of ##x## if it was not there already.
334
--
335
-- Example 1:
336
--
337
-- set s0 = {1,3,5,7}
338
-- s0=add_to(2,s) -- s0 is now {1,2,3,5,7}
339
--
340
--
341
-- See Also:
342
-- [[:remove_from]], [[:belongs_to]], [[:union]]
343
3442
3452
return add_to_(x,S)
346
end function
347
3482
349
integer p
350
3512
if length(s) = 0 then
3520
return s
353
end if
354
3552
p=bfind(x,s)
3562
if p>0 then
3571
return remove(s,p)
358
else
3591
return s
360
end if
361
end function
362
363
--**
364
-- Remove an object from a set.
365
--
366
-- Parameters:
367
-- # ##x## : the object to add
368
-- # ##S## : the set to remove from
369
--
370
-- Returns:
371
--
372
--A **set**, which is a **copy** of ##S##, with ##x## removed if it was there.
373
--
374
-- Example 1:
375
--
376
-- set s0 = {1,2,3,5,7}
377
-- s0=remove_from(2,s0) -- s0 is now {1,3,5,7}
378
--
379
--
380
-- See Also:
381
-- [[:remove_from]], [[:belongs_to]], [[:union]]
382
3832
3842
return remove_from_(x,s)
385
end function
386
3874
388
-- Returns: {1,2,...,count}, or "" if count is not greater than 0.
389
sequence result
3904
if count<=0 then
3910
return ""
392
end if
3934
result=repeat(1,count)
3944
for i=2 to count do
39518
result[i]=i
39618
end for
3974
return result
398
end function
399
4004
401
integer p,q,ls1
402
sequence result
403
4044
q=length(s2)
4054
ls1=length(s1)
4064
if q>ls1 then
4074
if ls1>1 then
4084
result=repeat(0,ls1)
4094
p=1
4104
for i=1 to ls1/2 do
4114
p=bfind(s1[i],s2,p,q)
4124
if p<0 then
4132
return 0
414
end if
4152
result[i]=p
4162
p+=1
4172
q=bfind(s1[$+1-i],s2,p,q)
4182
if q<0 then
4190
return 0
420
end if
4212
result[$+1-i]=q
4222
q-=1
4232
end for
4242
if and_bits(ls1,1) then
4252
p=bfind(s1[(ls1+1)/2],s2,p,q)
4262
if p<=0 then
4270
return 0
428
end if
4292
result[(ls1+1)/2]=p
430
end if
4312
if mode then
4321
return result
433
else
4341
return 1
435
end if
4360
elsif ls1=1 then
4370
p=find(s1[1],s2)
4380
if p=0 then
4390
return 0
4400
elsif mode then
4410
return {p}
442
else
4430
return 1
444
end if
445
else
4460
if mode then
4470
return {}
448
else
4490
return 1
450
end if
451
end if
4520
elsif q
4530
return 0
454
else
4550
if mode then
4560
return iota(ls1)
457
else
4580
return not eu:compare(s1,s2)
459
end if
460
end if
461
end function
462
463
--**
464
-- Checks whether a set is a subset of another.
465
--
466
-- Parameters:
467
-- # ##small## : the set to test
468
-- # ##large## : the supposedly larger set.
469
--
470
-- Returns:
471
--
472
-- An **integer**, 1 if ##small## is a subset of ##large##, else 0.
473
--
474
-- Example 1:
475
--
476
-- set s0 = {1,3,5,7}
477
-- ? is_subset({3,5},s0) -- prints out 1
478
--
479
--
480
-- See Also:
481
-- [[:subsets]], [[:belongs_to]], [[:difference]], [[:embedding]], [[:embed_union]]
4822
4832
return is_subset_(small,large,0)
484
end function
485
486
--**
487
-- Returns the set of indexes of the elements of a set in a larger set, or 0 if not applicable
488
--
489
-- Parameters:
490
-- # ##small## : the set to embed
491
-- # ##large## : the supposedly larger set
492
--
493
-- Returns:
494
--
495
-- A **set**, of indexes if ##small## [[:is_subset]]() ##large##, else 0. Each element
496
-- is the index in ##large## of the corresponding element of ##small##. Its length is ##
497
-- length(small)## and the values range from 1 to ##length(large)##.
498
--
499
-- Example 1:
500
--
501
-- set s0 = {1,3,5,7}
502
-- set s = embedding({3,5},s0) -- s is now {2,3}
503
--
504
--
505
-- See Also:
506
-- [[:subsets]], [[:belongs_to]], [[:difference]], [[:is_subset]]
507
--
5082
5092
return is_subset_(small,large,1)
510
end function
511
51248
513
-- Description: Returns the absolute value of p.
51448
if p>0 then
51523
return p
516
else
51725
return -p
518
end if
519
end function
520
5215
522
-- Description: Wrapped by embed_union so as to avoid some type checks.
523
integer p,q,q_1,ls1
524
sequence result,temp
525
5265
q=length(s2)
5275
if q>1 then
5285
ls1=length(s1)
5295
if ls1>1 then
5305
if eu:compare(s1[$],s2[1])=-1 then
5310
return iota(length(s1))
5325
elsif eu:compare(s2[$],s1[1])=-1 then
5330
return iota(length(s1))+q
534
end if
5355
temp=s1
5365
p=1
5375
for i=1 to length(s1)/2 do
53813
p=bfind(s1[i],s2,p,q)
53913
temp[i]=p
54013
if p>0 then
5416
p+=1
542
else
5437
p=-p-1
544
end if
54513
q=bfind(s1[$+1-i],s2,p,q)
54613
temp[$+1-i]=q
54713
if q>0 then
5485
q-=1
549
else
5508
q=-q
551
end if
55213
end for
5535
if and_bits(ls1,1) then
5543
temp[(ls1/2)+1]=bfind(s1[(ls1/2)+1],s2,p,q)
555
end if
5565
result=temp
5575
if result[1]<0 then
5583
result[1]*=-1
559
end if
5605
q_1=temp[1]
5615
for i=2 to length(result) do
56224
q=temp[i]
56324
result[i]=abs(q)-abs(q_1)+result[i-1]+(q_1<0)
56424
q_1=q
56524
end for
5665
return result
5670
elsif length(s1)=1 then
5680
q=find(s1[1],s2)
5690
if q>0 then
5700
return {q}
571
else
5720
return {-q}
573
end if
574
else
5750
return ""
576
end if
5770
elsif q=0 then
5780
return iota(length(s1))
579
else
5800
q=find(s2[1],s1)
5810
if q>0 then
5820
return iota(length(s1))
583
else
5840
result=iota(length(s1))
5850
result[-q..$]+=1
5860
return result
587
end if
588
end if
589
end function
590
591
--**
592
-- Returns the embedding of a set into its union with another.
593
--
594
-- Parameters:
595
-- # ##S1## : the set to embed
596
-- # ##S2## : the other set
597
--
598
-- Returns:
599
--
600
-- A **set**, of indexes representing S1 inside ##union(S1,S2)##. Its length is ##length(S1)##, and the values range from 1 to ##length(S1) + length(S2)##.
601
--
602
-- Example 1:
603
--
604
-- set s1 = {2, 5, 7}, s2 = {1, 3, 4}
605
-- sequence s = embed_union(s1,s2) -- s is now {2, 5, 6}
606
--
607
--
608
-- See Also:
609
-- [[:embedding]], [[:union]]
610
6111
6121
return embed_union_(s1,s2)
613
end function
614
615
--**
616
-- Returns the list of all subsets of the input set.
617
--
618
-- Parameters:
619
-- # ##s## : the set to enumerate the subsets of.
620
--
621
-- Returns:
622
-- A **sequence**, containing all the subsets of the input set.
623
--
624
-- Comments:
625
--
626
-- ##s## must not have more than 29 elements, as the length of the output sequence is
627
-- ##power(2,length(s))##, which rapidly grows out of integer range.
628
-- The order in which the subsets are output is implementation dependent.
629
--
630
-- Example 1:
631
--
632
-- set s0 = {1,3,5,7}
633
-- s0 = subsets(s0) -- s0 is now:
634
-- {{},{1},{3},{5},{7},{1,3},{1,5},{1,7},{3,5},{3,7},{5,7},{1,3,5},{1,3,7},{1,5,7},{3,5,7},{1,3,5,7}}
635
--
636
--
637
-- See Also:
638
-- [[:is_subset]]
639
6401
641
integer p,k,L
642
sequence result,s1,s2,x
643
6441
L=length(s)
6451
if L<=3 then
6461
if L=0 then
6470
return {{}}
6481
elsif L=1 then
6490
return {{},s}
6501
elsif L=2 then
6510
return {{},{s[1]},{s[2]},s}
652
else
6531
return {{},{s[1]},{s[2]},{s[3]},s[1..2],{s[1],s[3]},s[2..3],s}
654
end if
655
else
6560
result=repeat(0,power(2,L))
6570
p=floor(L/2)
6580
s1=subsets(s[1..p])
6590
s2=subsets(s[p+1..$])
6600
k=1
6610
for i=1 to length(s1) do
6620
x=s1[i]
6630
for j=1 to length(s2) do
6640
result[k]=x&s2[j]
6650
k+=1
6660
end for
6670
end for
6680
return result
669
end if
670
end function
671
672
--****
673
-- === Basic set-theoretic operations.
674
--
675
6764
677
-- Description: Wrapped by intersection() so as to avoid some type checks.
678
integer k1,k2,k,c,ls1,ls2
679
sequence result
680
6814
ls2=length(s2)
6824
result=s1
6834
if ls2=0 then
6840
return ""
6854
elsif ls2=1 then
6861
if belongs_to(s2[1],s1) then
6870
return s2
688
else
6891
return ""
690
end if
691
end if
6923
ls1=length(s1)
6933
k1=1
6943
k2=1
6953
k=1
6963
c=eu:compare(s1[1],s2[1])
6973
while k1<=ls1 and k2<=ls2 do
69813
if c=0 then
6997
result[k]=s1[k1]
7007
k+=1
7017
k1+=1
7027
k2+=1
7037
if k1>ls1 or k2>ls2 then
7043
return result[1..k-1]
705
else
7064
c=eu:compare(s1[k1],s2[k2])
707
end if
7086
elsif c=1 then
7091
k2=bfind(s1[k1],s2,k2,length(s2))
7101
if k2>=0 then
7110
c=0
712
else
7131
k2=-k2
7141
c=-1
715
end if
716
else
7175
k1=bfind(s2[k2],s1,k1,length(s1))
7185
if k1>=0 then
7195
c=0
720
else
7210
k1=-k1
7220
c=1
723
end if
724
end if
72510
end while
7260
return result[1..k-1]
727
end function
728
729
--**
730
-- Returns the set of elements belonging to both s1 and s2.
731
--
732
-- Parameters:
733
-- # ##S1## : One of the sets to intersect
734
-- # ##S2## : the other set.
735
--
736
-- Returns:
737
--
738
-- A **set**, made of all elements belonging to both ##S1## and ##S2##.
739
--
740
-- Example 1:
741
--
742
-- set s0,s1,s2
743
-- s1={1,3,5,7} s2={-1,2,3,7,11}
744
-- s0=intersection(s1,s2) -- s0 is now {3,7}.
745
--
746
--
747
-- See Also:
748
-- [[:is_subset]], [[:subsets]], [[:belongs_to]]
749
7503
7513
return intersection_(S1,S2)
752
end function
753
7546
755
-- Description: Wrapped by union() and delta() to avoid type checking.
756
-- mode=1 for union and 0 for delta (union=intersection+delta)
757
integer k1,k2,k,c,k0
758
sequence result
759
7606
result=s1&s2
7616
k1=1
7626
k2=1
7636
k=1
7646
c=eu:compare(s1[1],s2[1])
7656
while k1<=ls1 and k2<=ls2 do
76634
if c=0 then
76714
if mode then
7689
result[k]=s1[k1]
7699
k+=1
770
end if
77114
k1+=1
77214
k2+=1
77314
if k1>ls1 or k2>ls2 then
7744
exit
775
else
77610
c=eu:compare(s1[k1],s2[k2])
777
end if
77820
elsif c=1 then
7796
k0=bfind(s1[k1],s2,k2,length(s2))
7806
if k0>=0 then
7810
c=0
782
else
7836
k0=-k0
7846
c=-1
785
end if
7866
result[k..k-k2+k0-1]=s2[k2..k0-1]
7876
k+=(k0-k2)
7886
k2=k0
789
else
79014
k0=bfind(s2[k2],s1,k1,length(s1))
79114
if k0>=0 then
79212
c=0
793
else
7942
k0=-k0
7952
c=1
796
end if
79714
result[k..k-k1+k0-1]=s1[k1..k0-1]
79814
k+=(k0-k1)
79914
k1=k0
800
end if
80130
end while
8026
result=result[1..k-1]
8036
if k1<=ls1 then
8044
return result & s1[k1..$]
8052
elsif k2<=ls2 then
8062
return result & s2[k2..$]
807
else
8080
return result
809
end if
810
end function
811
8125
813
integer ls1,ls2
814
8155
ls1=length(s1)
8165
ls2=length(s2)
8175
if ls2=0 then
8180
return s1
8195
elsif ls1=0 then
8201
return s2
8214
elsif ls1=1 then
8220
return add_to_(s1[1],s2)
8234
elsif ls2=1 then
8240
return add_to_(s2[1],s1)
825
end if
8264
return union_(s1,s2,ls1,ls2,1)
827
end function
828
829
--**
830
-- Returns the set of elements belonging to any of two sets.
831
--
832
-- Parameters:
833
-- # ##S1##: one of the sets to merge
834
-- # ##S2##: the other set.
835
--
836
-- Returns:
837
--
838
-- The **set** of all elements belonging to ##S1## or ##S2##, and possibly to both.
839
--
840
-- Example 1:
841
--
842
-- set s0,s1,s2
843
-- s1={1,3,5,7} s2={-1,2,3,7,11}
844
-- s0=union(s1,s2) -- s0 is now {-1,1,2,3,5,7,11}.
845
--
846
--
847
-- See Also:
848
-- [[:is_subset]], [[:subsets]], [[:belongs_to]]
849
--
8502
8512
return union1(S1,S2)
852
end function
853
854
--**
855
-- Returns the set of elements belonging to either of two sets.
856
--
857
-- Parameters:
858
-- # ##s1## : One of the sets to take a symmetrical difference with
859
-- # ##s2## : the other set.
860
--
861
-- Returns:
862
--
863
-- The **set**, of all elements belonging to either ##s1## or ##s2##.
864
--
865
-- Example 1:
866
--
867
-- set s0,s1,s2
868
-- s1={1,3,5,7} s2={-1,2,3,7,11}
869
-- s0=delta(s1,s2) -- s0 is now {-1,1,2,5,11}.
870
--
871
--
872
-- See Also:
873
-- [[:intersection]], [[:union]], [[:difference]]
874
--
8752
876
integer ls1,ls2
877
8782
ls1=length(s1)
8792
ls2=length(s2)
8802
if ls2=0 then
8810
return s1
8822
elsif ls1=0 then
8830
return s2
8842
elsif ls1=1 then
8850
return remove_from_(s1[1],s2)
8862
elsif ls2=1 then
8870
return remove_from_(s2[1],s1)
888
end if
8892
return union_(s1,s2,ls1,ls2,0)
890
end function
891
892
--**
893
-- Returns the set of elements belonging to some set and not to another.
894
--
895
-- Parameters:
896
-- # ##base## : the set from which a difference is to be taken
897
-- # ##removed## : the set of elements to remove from ##base##.
898
--
899
-- Returns:
900
--
901
-- The **set**, of elements belonging to ##base## but not to ##removed##.
902
--
903
-- Example 1:
904
--
905
-- set s0,s1,s2
906
-- s1={1,3,5,7} s2={-1,2,3,7,11}
907
-- s0=difference(s1,s2) -- s0 is now {1,5}.
908
--
909
--
910
-- See Also:
911
-- [[:remove_from]], [[:is_subset]], [[:delta]]
912
--
9131
914
integer k1,k2,k,c,ls1,ls2,k0
915
sequence result
9161
ls1=length(base)
9171
ls2=length(removed)
9181
if ls2=0 then
9190
return base
9201
elsif ls1=0 then
9210
return ""
9221
elsif ls2=1 then
9230
return remove_from_(removed[1],base)
9241
elsif ls1=1 then
9250
if bfind(base[1],removed,1,length(removed))>0 then
9260
return ""
927
else
9280
return base
929
end if
930
end if
9311
result=base&removed
9321
k1=1
9331
k2=1
9341
k=1
9351
c=eu:compare(base[1],removed[1])
9361
while k1<=ls1 and k2<=ls2 do
9375
if c=0 then
9382
k1+=1
9392
k2+=1
9402
if k1>ls1 or k2>ls2 then
9411
exit
942
else
9431
c=eu:compare(base[k1],removed[k2])
944
end if
9453
elsif c=1 then
9461
k2=bfind(base[k1],removed,k2,length(removed))
9471
if k2>=0 then
9480
c=0
949
else
9501
k2=-k2
9511
c=-1
952
end if
953
else
9542
k0=bfind(removed[k2],base,k1,length(base))
9552
if k0>=0 then
9562
c=0
957
else
9580
k0=-k0
9590
c=1
960
end if
9612
result[k..k-k1+k0-1]=base[k1..k0-1]
9622
k+=(k0-k1)
9632
k1=k0
964
end if
9654
end while
9661
result=result[1..k-1]
9671
if k1<=ls1 then
9681
return result & base[k1..$]
969
else
9700
return result
971
end if
972
end function
973
9743
975
-- Description: Wrapped by product() to skip type checking
976
sequence result
977
integer ls1,ls2,k
978
object x
979
9803
ls1=length(s1)
9813
ls2=length(s2)
9823
if not (ls1 and ls2) then
9830
return ""
984
end if
9853
k=1
9863
result=repeat(0,ls1*ls2)
9873
for i=1 to ls1 do
98812
x={s1[i],0}
98912
for j=1 to ls2 do
99026
x[2]=s2[j]
99126
result[k]=x
99226
k+=1
99326
end for
99412
end for
9953
return result
996
end function
997
998
--**
999
-- Returns the set of all pairs made of an element of a set and an element of another set.
1000
--
1001
-- Parameters:
1002
-- # ##S1## : The set where the first coordinate lives
1003
-- # ##S2## : The set where the second coordinate lives
1004
--
1005
-- Returns:
1006
--
1007
-- The **set**, of all pairs made of an element of ##S1## and an element of ##S2##.
1008
--
1009
-- Example 1:
1010
--
1011
-- set s0,s1,s2
1012
-- s1 = {1, 3, 5, 7} s2 = {-1, 3}
1013
-- s0 = product(s1, s2) -- s0 is now {{1, -1}, {1, 3}, {3, -1}, {3, 3}, {5, -1}, {5, 3}, {7, -1}, {7, 3}}
1014
--
1015
--
1016
-- See Also:
1017
-- [[:product_map]], [[:amalgamated_sum]], [[:fiber_product]]
1018
10191
10201
return product_(S1, S2)
1021
end function
1022
1023
--****
1024
-- === Maps between sets.
1025
1026
--**
1027
-- Returns a map which sends each element of its source set to the corresponding
1028
-- one in a list.
1029
--
1030
-- Parameters:
1031
-- # ##mapping## : the sequence mapped to
1032
-- # ##target## : the target set that contains the elements ##mapping## refers to by index
1033
--
1034
-- Returns:
1035
--
1036
-- The requested **map**, descriptor.
1037
--
1038
-- Example 1:
1039
--
1040
-- sequence s0 = {2, 3, 4, 1, 4, 2}
1041
-- set s1 = {-1, 1, 2, 3, 4}
1042
-- map f = define_map(s0,s1)
1043
-- -- As a sequence, f is {3, 4, 5, 2, 5, 3, 6, 5}
1044
--
1045
--
1046
-- See Also:
1047
-- [[:map]], [[:sequences_to_map]], [[:direct_map]]
1048
10491
1050
sequence result
1051
integer lt
1052
10531
lt = length(target)
10541
result = mapping & length(mapping) & lt
10551
for i = 1 to length(mapping) do
10567
result[i] = bfind(mapping[i], target)
10577
end for
1058
10591
return result
1060
end function
1061
1062
--**
1063
-- Returns a map which sends each element of some sequence to the corresponding one in another sequence.
1064
--
1065
-- Parameters:
1066
-- # ##mapped## : the source sequence
1067
-- # ##mapped_to## : the sequence it must map to.
1068
-- # ##mode## : an integer, nonzero to also return the minimal sets the result map maps.
1069
--
1070
-- Returns:
1071
-- A **sequence**,
1072
-- * If ##mode## is 0, a map which maps ##mapped## to ##mapped_to##, between the smallest possible sets.
1073
-- * If mode is not zero, the sequence has length 3. The first element is the map above. The other two elements are the sets derived from the input sequences.
1074
--
1075
-- Comments:
1076
--
1077
-- Elements in excess in ##mapped_to## are discarded.
1078
--
1079
-- If an element is repeated in ##mapped##, only the mapping of the last occurrence is retained.
1080
--
1081
-- Example 1:
1082
--
1083
-- sequence s0, s1
1084
-- s0 = {2, 3, 4, 1, 4}
1085
-- s1 = {"aba", "aac", 3, "def"}
1086
--
1087
-- map f = sequences_to_map(s0,s1)
1088
-- -- As a sequence, f is {3,2,1,4,4,4}
1089
--
1090
--
1091
-- See Also:
1092
-- [[:map]], [[:define_map]]
1093
10941
1095
sequence result
1096
set sorted,sorted_to
1097
integer ls,lm_to,lm
1098
10991
lm=length(mapped)
11001
lm_to=length(mapped_to)
1101
11021
if lm>lm_to then
11030
mapped=mapped[1..lm_to]
1104
end if
1105
11061
sorted=sequence_to_set(mapped)
11071
sorted_to=sequence_to_set(mapped_to)
11081
ls=length(sorted)
11091
result=repeat(0,ls)&ls&length(sorted_to)
1110
11111
for i=1 to lm do
11127
result[find(mapped[i],sorted)]=find(mapped_to[i],sorted_to)
11137
end for
1114
11151
if mode then
11160
return {result,sorted,sorted_to}
1117
else
11181
return result
1119
end if
1120
end function
1121
1122
--**
1123
-- If an object is in some input set, returns how it is mapped to a set.
1124
--
1125
-- Parameters:
1126
-- # ##f## : the map to apply
1127
-- # ##x## : the object to apply ##f## to
1128
-- # ##input## : the source set
1129
-- # ##output## : the target set.
1130
--
1131
-- Returns:
1132
-- An **object**, f(x) if it can be reckoned.
1133
--
1134
-- Errors:
1135
--
1136
-- ##x## must belong to ##input## for ##f(x) ##to be computed.
1137
-- ##f## must not map to sets larger than ##output##; otherwise, it cannot be defined from ##input## to ##output##.
1138
--
1139
-- Example 1:
1140
--
1141
-- map f={3,1,2,2,4,3}
1142
-- set s1,s2
1143
-- s1={"Albert","Beatrix","Conrad","Doris"} s2={13,17,19}
1144
-- object x = image(f,"Conrad",s1,s2}
1145
-- -- x is now 17.
1146
--
1147
--
1148
-- See Also:
1149
-- [[:direct_map]]
1150
11511
1152
integer p
1153
11541
if f[$]>length(output) then
11550
report_error({"image","The map range would not fit into the supplied target set."})
1156
end if
1157
11581
p = bfind(x, input)
1159
11601
if p<0 or p>f[$-1] then
11610
report_error({"image","The map is not defined for the supplied argument."})
1162
else
11631
return output[f[p]]
1164
end if
1165
end function
1166
1167
--**
1168
-- Returns the set of all values taken by a map in some output set.
1169
--
1170
-- Parameters:
1171
-- # ##f## : the map to inspect
1172
-- # ##set## : the output set
1173
--
1174
-- Returns:
1175
--
1176
-- The **set**, of all ##f(x)##.
1177
--
1178
-- Example 1:
1179
--
1180
-- map f = {3, 2, 5, 2, 4, 6}
1181
-- set s = {"Albert", "Beatrix", "Conrad", "Doris", "Eugene", "Fabiola"}
1182
-- set s1 = range(f, s)
1183
-- -- s1 is now {"Beatrix", "Conrad", "Eugene"}
1184
--
1185
--
1186
-- See Also:
1187
-- [[:direct_map]], [[:image]]
1188
11891
1190
sequence result
1191
11921
result=sequence_to_set(f[1..$-2])
11931
for i=1 to length(result) do
11943
result[i]=s[result[i]]
11953
end for
1196
11971
return result
1198
end function
1199
1200
--**
1201
-- Returns the image of a list by a map, given the input and output sets.
1202
--
1203
-- Parameters:
1204
-- # ##f## : the map to apply
1205
-- # ##input## : the source set
1206
-- # ##elements## : the sequence to map
1207
-- # ##output## : the target set.
1208
--
1209
-- Returns:
1210
-- A **sequence**, of elements of ##output## obtained by applying ##f## to the corresponding
1211
-- element of ##input##.
1212
--
1213
-- Errors:
1214
-- This function errors out if ##f## cannot map ##input## to ##output##.
1215
--
1216
-- Comments:
1217
--
1218
-- If ##elements## has items which are not on ##input##, they are ignored. Items may appear in any order any number of times.
1219
--
1220
-- Example:
1221
--
1222
-- sequence s0 = {2,3,4,1,4}
1223
-- set t1,t2
1224
-- t1={1,2,2.5,3,4} t2={11,13,17,19,23,29}
1225
-- map f = {3,1,4,5,3,5,5}
1226
-- sequence s2 = direct_map(f,t1,s0,t2)
1227
-- -- s2 is now {11,29,17,17,17}.
1228
--
1229
--
1230
-- See Also:
1231
-- [[:reverse_map]]
1232
12331
1234
sequence result
1235
integer k,p
1236
12371
if f[$-1] > length(s1) or f[$] > length(s2) then
12380
report_error({"direct_map","The supplied map cannot map the source set into the target set."})
1239
end if
1240
12411
k=1
12421
result=s0
1243
12441
for i=1 to length(s0) do
12453
p = bfind(s0[i], s1)
12463
if p>0 then
12473
result[k]=s2[f[p]]
12483
k+=1
1249
end if
12503
end for
1251
12521
return result[1..k-1]
1253
end function
1254
1255
--**
1256
-- Restricts f to the intersection of an input set and another set
1257
--
1258
-- Parameters:
1259
-- # ##f## : the map to restrict
1260
-- # ##source## : the initial source set for ##f##
1261
-- # ##restriction## : the set which will help forming a restricted source set.
1262
--
1263
-- Returns:
1264
--
1265
-- A **map**, defined on ##difference(source,restriction)## which agrees with ##f##.
1266
--
1267
-- Example 1:
1268
--
1269
-- set s1 = {1,3,5,7,9,11,13,17,19,23}}
1270
-- map f = [3,7,1,4,5,2,7,1,6,2,10,7}
1271
-- set s0 = {3,11,13,19,29}
1272
-- map f0 = restrict(f,s1,s0)
1273
-- f0 is now: {7,2,7,6,4,7}
1274
--
1275
--
1276
-- See Also:
1277
-- [[:is_subset]], [[:direct_map]], [[:difference]]
1278
--
12792
12802
sequence result = restriction
12812
integer p = 1, k = 0
1282
12832
for i=1 to length(restriction) do
128410
p=bfind(restriction[i],source,p,length(source))
128510
if p>0 then
128610
k+=1
128710
result[k]=f[p]
1288
end if
128910
end for
1290
12912
return result[1..k]&k&f[$]
1292
end function
1293
12945
1295
-- Description: Wrapped by change_target() to avoid some type checks.
1296
sequence result,done
1297
integer p,fi
1298
12995
result=f
13005
done=repeat(0,f[$])
1301
13025
for i=1 to f[$-1] do
130336
fi=f[i]
130436
p=done[fi]
130536
if p then
130620
result[i]=p
1307
else
130816
p=bfind(s1[fi],s2)
130916
if p<0 then
13100
report_error({"change_target","map range not included in new target set."})
1311
else
131216
result[i]=p
131316
done[fi]=p
1314
end if
1315
end if
131636
end for
13175
result[$]=length(s2)
1318
13195
return result
1320
end function
1321
1322
--**
1323
-- Converts a map by changing its output set.
1324
--
1325
-- Parameters:
1326
-- # ##f## : the map to retarget
1327
-- # ##old_target## : the initial target set for ##f##
1328
-- # ##new_target## : the new target set.
1329
--
1330
-- Returns:
1331
--
1332
-- A **map**, which agrees with ##f## and has values in ##new_target## instead of ##
1333
-- old_target##, or "" if ##f## hits something outside ##new_target##.
1334
--
1335
-- Example 1:
1336
--
1337
-- set s1,s2
1338
-- s1={1,3,5,7,9,11} s2={1,3,7,11,17,19,23}
1339
-- map f = {2,1,4,6,2,6,6,6}
1340
-- map f0 = change_target(f,s1,s2)
1341
-- f0 is now: {2,1,3,4,2,4,6,7}
1342
--
1343
--
1344
-- See Also:
1345
-- [[:restrict]], [[:direct_map]]
1346
13471
13481
return change_target_(f,old_target,new_target)
1349
end function
1350
1351
--**
1352
-- Combines two maps into one defined from the union of source sets to the union
1353
-- of target sets.
1354
--
1355
-- Parameters:
1356
-- # ##f1## : the first map
1357
-- # ##source1## : its source set
1358
-- # ##target1## : its target set
1359
-- # ##f2## : the second map
1360
-- # ##source2## : its source set
1361
-- # ##target2## : its target set
1362
--
1363
-- Returns:
1364
-- A **map**, from ##union(source1,source2)## to ##union(target1,target2)##
1365
-- which agrees with ##f1## and ##f2##, or "" if ##f1##
1366
-- and ##f2## disagree at any point of ##intersection(s11,s21)##.
1367
--
1368
-- Errors:
1369
-- If f1 and f2 are both defined for some point, they must have the
1370
-- same value at this point..
1371
--
1372
-- Example 1:
1373
--
1374
-- set s11,s12,s21,s22
1375
-- s11={2,3,5,7,11,13,17,19} s21={7,13,19,23,29}
1376
-- s12={-1,0,1,4} s22={-2,0,1,2,6}
1377
-- map f1,f2
1378
-- f1={2,1,3,3,2,3,1,2,8,4} f2={3,3,2,4,5,5,5}
1379
-- map f = combine_maps(f1,s11,s12,f2,s21,s22)
1380
-- -- f is now: {3,2,4,4,3,4,2,3,5,7,10,7}.
1381
--
1382
--
1383
-- See Also:
1384
-- [[:restrict]], [[:direct_map]]
1385
13862
1387
integer len_result,p
1388
set s
1389
sequence result
1390
13912
s=union1(target1,target2)
13922
f1=change_target_(f1,target1,s)
13932
f2=change_target_(f2,target2,s)
13942
s=embed_union_(source1,source2)
13952
len_result=length(source1)+length(source2)
13962
result=repeat(0,len_result)
13972
for i=1 to length(s) do
139816
result[s[i]]=f1[i]
139916
end for
14002
s=embed_union_(source2,source1)
14012
for i=1 to length(s) do
140210
p=s[i]
140310
if result[p] then
14046
if result[p]!=f2[i] then
14050
report_error({"combine_maps",
1406
"Maps disagree at some point where they are both defined."})
1407
else
14086
len_result-=1
1409
end if
1410
else
14114
result[p]=f2[i]
1412
end if
141310
end for
14142
return result[1..len_result]&len_result&f1[$]
1415
end function
1416
1417
14183
1419
-- Description: Wrapped by compose_map(), so as to avoid some type checks.
1420
sequence result
1421
14223
if find(0, f1[1..$-2] <= f2[$-1]) then
14230
report_error({"compose_maps","One or more elements in f1 are outside the range of f2."})
1424
end if
14253
result = f1
14263
for i = 1 to length(f1)-2 do
142720
result[i] = f2[ f1[i] ]
142820
end for
14293
result[$] = f2[$]
14303
return result
1431
end function
1432
1433
--**
1434
-- Creates a new map using elements from ##f2##, mapped against ##f1##
1435
--
1436
-- Parameters:
1437
-- # ##f1## : the map containing indexes into ##f2##
1438
-- # ##f2## : the map containing elements used to build the resulting map.
1439
--
1440
-- Returns:
1441
-- A **map**, ##f## defined by ##f(x)=f2(f1(x))## for all ##x##
1442
--
1443
-- Comments:
1444
-- Each element in ##f1## is an index into the elements of ##f2##. So if
1445
-- ##f1## contains {3,2,1} the result map contains the 3rd, 2nd and 1st element
1446
-- from ##f2## in that order.
1447
--
1448
-- Errors:
1449
-- Every element of ##f1## must be a valid index into ##f2##.
1450
--
1451
-- Example 1:
1452
--
1453
-- map f1,f2,f
1454
-- f1={2,3,1,1,2,5,3}
1455
-- f2={4,8,1,2,6,7,6,9}
1456
-- f=compose_map(f1,f2)
1457
-- -- f is now: {8,1,4,4,8,5,9}
1458
--
1459
--
1460
-- See Also:
1461
-- [[:diagram_commutes]]
1462
--
14631
14641
return compose_map_(f1,f2)
1465
end function
1466
1467
--**
1468
-- Decide whether taking two different paths along a square map diagrams results in the same map.
1469
--
1470
-- Parameters:
1471
-- # ##from_base_path_1## : the outgoing map along path 1
1472
-- # ##from_base_path_2## : the outgoing map along path 2
1473
-- # ##to_target_path_1## : the incoming map along path 1
1474
-- # ##to_target_path_2## : the incoming map along path 2
1475
--
1476
-- Returns:
1477
--
1478
-- An **integer**, either 1 if to_target_path_1 o from_base_path_1 = to_target_path_2 o from_base_path_2.
1479
--
1480
-- Example 1:
1481
--
1482
-- map f12a,f12b,f2a3,f2b3
1483
-- f12a={2,3,1,1,2,5,3}
1484
-- f2a3={4,8,1,2,6,7,6,9}
1485
-- f12b={2,4,2,3,1,5,4}
1486
-- f2b3={8,8,4,1,3,5,8}
1487
-- ?diagram_commutes(f12a,f12b,f2a3,f2b3) -- prints out 0
1488
--
1489
--
1490
-- See Also:
1491
-- [[:compose_map]]
1492
--
14931
14941
return not eu:compare(compose_map_(f2a3,f12a),compose_map_(f2b3,f12b))
1495
end function
1496
1497
--**
1498
-- Determines whether there is a point in an output set hit twice or more by a map.
1499
--
1500
-- Parameters:
1501
-- # ##f## : the map being queried.
1502
--
1503
-- Returns:
1504
--
1505
-- An **integer**, 0 if f ever maps two points to the same element, else 1.
1506
--
1507
-- Example 1:
1508
--
1509
-- map f = {2,3,1,1,2,5,3}
1510
-- ?is_injective(f) -- prints out 0
1511
--
1512
--
1513
-- See Also:
1514
-- [[:is_surjective]], [[:is_bijective]], [[:reverse_map]], [[:fiber_over]]
1515
--
15161
1517
sequence s
1518
integer p
1519
object x,y
1520
15211
if f[$-1]>f[$] then
15221
return 0
1523
end if
1524
15250
p=length(f)-2
15260
s=sort(f[1..p])
15270
x=s[1]
1528
15290
for i=2 to p do
15300
y=s[i]
15310
if y=x then
15320
return 0
1533
end if
15340
x=y
15350
end for
1536
15370
return 1
1538
end function
1539
15401
15411
if f[$-1]
15420
return 0
1543
else
15441
return equal(sequence_to_set(f[1..$-2]),iota(f[$]))
1545
end if
1546
end function
1547
1548
--**
1549
-- Determine whether all points in the output set are hit by a map.
1550
--
1551
-- Parameters:
1552
-- # ##f## : the map to test.
1553
--
1554
-- Returns:
1555
--
1556
-- An **integer**, 0 if ##f## ever misses some point in the target set, else 1.
1557
--
1558
-- Example 1:
1559
--
1560
-- map f = {2,3,1,1,2,5,3}
1561
-- ?is_surjective(f) -- prints out 1
1562
--
1563
--
1564
-- See Also:
1565
-- [[:is_surjective]], [[:is_bijective]], [[:direct_map]], [[:section]]
1566
--
15671
15681
return is_surjective_(f)
1569
end function
1570
1571
--**
1572
-- Determine whether a map is one-to-one.
1573
--
1574
-- Parameters:
1575
-- # ##f## : the map to test.
1576
--
1577
-- Returns:
1578
--
1579
-- An **integer**, 1 if f is one-to-one, else 0.
1580
--
1581
-- Example 1:
1582
--
1583
-- map f = {2,3,1,1,2,5,3}
1584
-- ? is_surjective(f) -- prints out 0
1585
--
1586
--
1587
-- See Also:
1588
-- [[:is_surjective]], [[:is_bijective]], [[:direct_map]], [[:has_inverse]]
1589
--
15901
15911
if f[$]!=f[$-1] then
15921
return 0
1593
else
15940
return is_surjective_(f)
1595
end if
1596
end function
1597
15984
1599
sequence fibers,result
1600
integer p
16014
if f[$-1]!=length(s1) or f[$]!=length(s2) then
16020
return ""
1603
end if
16044
fibers=sequence_to_set(f[1..$-2])
16054
result=repeat({},length(fibers))
16064
for i=1 to length(s1) do
160737
p=find(f[i],fibers)
160837
result[p]=append(result[p],s1[i])
160937
end for
16104
return {result,fibers}
1611
end function
1612
1613
--****
1614
-- === Reverse mappings
1615
--
1616
1617
--**
1618
-- Given a map between two sets, returns {list of antecedents of elements in target, effective target}.
1619
--
1620
-- Parameters:
1621
-- # ##f## : the inspected map
1622
-- # ##source## : the source set
1623
-- # ##target## : the target set.
1624
--
1625
-- Returns:
1626
--
1627
-- A **sequence**, which is empty on failure. On success, it has two elements:
1628
-- * A sequence of sets; each of these sets is included in ##source## and is mapped to a single point by ##f##.
1629
-- * A set, the points in ##target## hit by ##f##.
1630
--
1631
-- Comments:
1632
--
1633
-- The listed sets, which are reverse images of points in ##target##,
1634
-- are called //fibers// of ##f## over points, specially if they are isomorphic to one
1635
-- another for some extra algebraic or topological structure.
1636
--
1637
-- The fibers are enumerated in the same order as the points in the effective target, i.e.
1638
-- the points in ##target## ##f## hits.
1639
--
1640
-- Example 1:
1641
--
1642
-- set s1,s2
1643
-- s1={5,7,9,11} s2={13,17,19,23,29}
1644
-- map f = {2,1,4,1,4,5}
1645
-- sequence s = fiber_over(f,s1,s2)
1646
-- -- s is now {{{7,11},{5},{9}},{13,17,23}}.
1647
--
1648
--
1649
-- See Also:
1650
-- [[:reverse_map]], [[:fiber_product]]
1651
--
16521
16531
return fiber_over_(f,source,target)
1654
end function
1655
1656
--**
1657
-- Given a map between two sets, returns the smallest subset whose image contains the set of elements in a list.
1658
--
1659
-- Parameters:
1660
-- # ##f## : the map relative to which reverse images are to be taken
1661
-- # ##source## : the source set
1662
-- # ##elements## : the list of elements in ##target## to lift to ##source##
1663
-- # ##target## : the target set
1664
--
1665
-- Returns:
1666
-- A **set**, which is included in ##source## and contains all antecedents of elements in ##elements## by ##f##.
1667
--
1668
--Comments:
1669
--
1670
-- Elements which ##f## does not hit are ignored.
1671
--
1672
-- Example 1:
1673
--
1674
-- set s1,s2
1675
-- s1={5,7,9,11} s2={13,17,19,23,29}
1676
-- sequence s0 = {23,13,17,23}
1677
-- map f = {5,3,1,3,4,5}
1678
-- set s = reverse_map(f,s1,s0,s2)
1679
-- s is now {9}.
1680
--
1681
--
1682
-- See Also:
1683
-- [[:direct_map]], [[:fiber_over]]
1684
16851
1686
sequence x,done,result
1687
integer p
1688
16891
x=fiber_over_(f,s1,s2)
16901
result=""
16911
done=repeat(0,length(x[2]))
1692
16931
for i=1 to length(s0) do
16941
p=find(bfind(s0[i],s1), x[2])
16951
if p and not done[p] then
16961
done[p]=1
16971
result=union1(result,x[1][p])
1698
end if
16991
end for
17001
return result
1701
end function
1702
1703
--**
1704
-- Return a right, and left is possible, inverse of a map over its [[:range]].
1705
--
1706
-- Parameters:
1707
-- # ##f## : the map to invert.
1708
--
1709
-- Returns:
1710
-- A **map**, ##g## such that ##f(g(y)) = y## whenever ##y## is hit by ##f##. and If f is
1711
-- injective, it also holds that ##g(f(x))=x##.
1712
--
1713
-- Example 1:
1714
--
1715
-- map f = {2, 3, 1, 1, 2, 5, 3}, g = section(f)
1716
-- -- g is now {3,1,2,3,5}.
1717
--
1718
--
1719
-- See Also:
1720
-- [[:reverse_map]], [[:is_injective]]
1721
17221
17231
sequence result = f
17241
integer k = 0, p = f[$-1]
1725
17261
for i=1 to p do
172710
result[f[i]]=i
172810
end for
1729
17301
for i=1 to p do
173110
if result[i] and k then
17320
result[k]=result[i]
17330
k+=1
173410
elsif result[i]=0 and k=0 then
17350
k=i
1736
end if
173710
end for
1738
17391
if k then
17400
result[k]=k-1
17410
result=result[1..k]&p
1742
else
17431
result[$]=p
17441
result[$-1]=f[$]
1745
end if
1746
17471
return result
1748
end function
1749
1750
1751
--****
1752
-- === Products
1753
--
1754
1755
--**
1756
-- Builds a map to a product from a map to each of its components.
1757
--
1758
-- Parameters:
1759
-- # ##f1## : the map going to the first component
1760
-- # ##f2## : the map going to the second component
1761
--
1762
-- Returns:
1763
--
1764
-- A **map**, ##f=f1 x f2## defined by ##f(x,y)={f1(x),f2(y)}## wherever this makes sense.
1765
--
1766
-- Example 1:
1767
--
1768
-- set s = {1,3,5,7}
1769
-- map f = {3,1,4,1,4,4}
1770
-- map f1 = product(f,f)
1771
-- -- f1 is {11,9,12,9,3,1,4,1,15,13,16,13,3,1,4,1,16,16}.
1772
--
1773
--
1774
-- See Also:
1775
-- [[:product]], [[:amalgamated_sum]], [[:fiber_product]]
1776
--
17771
1778
sequence result,s
1779
integer k ,p
17801
k=1
17811
p=f2[$-1]
17821
result=repeat(0,f1[$-1]*p)&f1[$-1]*p&f1[$]*f2[$]
17831
s=f2[1..$-2]-p
17841
for i=1 to f1[$-1] do
17857
result[k..k+p-1]=s+p*f1[i]
17867
k+=p
17877
end for
17881
return result
1789
end function
1790
1791
--**
1792
-- Returns all pairs in a product that come from applying two maps to the same element in a base set.
1793
--
1794
-- Parameters:
1795
-- # ##first## : one of the sets to involved in the sum
1796
-- # ##second## : the other set
1797
-- # ##base## : the base set
1798
-- # ##base_to_1## : the map from ##base## to ##first##
1799
-- # ##base_to_2## : the map from ##base## to ##second##
1800
--
1801
-- Returns:
1802
--
1803
-- A **set**, of pairs obtained by applying f01Xf02 to s0.
1804
--
1805
-- Example 1:
1806
--
1807
-- set s0,s1,s2
1808
-- s0={1,2,3} s1={5,7,9,11} s2={13,17,19}
1809
-- map f01,f02
1810
-- f01={2,4,1,3,4} f02={2,2,1,3,3}
1811
-- set s = amalgamated_product(s1,s2,s0,f01,f02)
1812
-- -- s is now {{7,17},{11,17},{5,13}}.
1813
--
1814
--
1815
-- See Also:
1816
-- [[:product]], [[:product_map]], [[:fiber_product]]
1817
--
1818
18191
1820
sequence result
1821
18221
result=base
18231
for i=1 to length(base) do
18247
result[i]={first[base_to_1[i]],second[base_to_2[i]]}
18257
end for
18261
return sequence_to_set(result)
1827
end function
1828
1829
--**
1830
-- Returns the set of all pairs in a product on which two given componentwise maps agree.
1831
--
1832
-- Parameters:
1833
-- # ##first## : the first product component
1834
-- # ##second## : the second product component
1835
-- # ##base## : the base set the fiber product is built on
1836
-- # ##from_1_to_base## : the map from ##first## to ##base##.
1837
-- # ##from_2_to_base## : the map from ##second## to ##base##.
1838
--
1839
-- Returns:
1840
--
1841
-- The **set**, of pairs whose coordinates are mapped consistently to ##base## by ##
1842
-- from_1_to_base## and ##from_2_to_base## respectively.
1843
--
1844
-- Example 1:
1845
--
1846
-- set s0,s1,s2
1847
-- s0={1,2,3} s1={5,7,9,11} s2={13,17,19,23,29}
1848
-- map f10,f20
1849
-- f10={2,1,2,1,4,3} f20={1,3,3,2,3,5,3}
1850
-- set s = fiber_product(s1,s2,s0,f10,f20)
1851
-- -- s is now {{5,23},{7,13},{9,23},{11,13}}.
1852
--
1853
--
1854
-- See Also:
1855
-- [[:reverse_map]], [[:amalgamated_sum]], [[:fiber_over]]
1856
--
18571
1858
sequence result,x1,x2,x0
1859
18601
x1=fiber_over_(from_1_to_base,first,base)
18611
x2=fiber_over_(from_2_to_base,second,base)
18621
x0=intersection_(x1[2],x2[2])
18631
result={}
1864
18651
for i=1 to length(x0) do
18662
result&=product_(x1[1][find(x0[i],x1[2])],x2[1][find(x0[i],x2[2])])
18672
end for
1868
18691
return result
1870
end function
1871
1872
--****
1873
-- === Constants
1874
--
1875
1876
--**
1877
-- The following constants denote orientation of distributivity or unitarity~:
1878
-- * ##SIDE_NONE## ~-- no units, or no distributivity
1879
-- * ##SIDE_LEFT## ~-- property is requested or verified on the left side
1880
-- * ##SIDE_RIGHT## ~-- property is requested or verified on the right side
1881
-- * ##SIDE_BOTH## ~-- property is requested or verified on both sides.
1882
1883
18841
public enum SIDE_NONE = 0, SIDE_LEFT, SIDE_RIGHT, SIDE_BOTH
1885
1886
--****
1887
-- === Operations on sets
1888
--
1889
1890
--**
1891
-- Returns an operation that splits by left action into the supplied mappings.
1892
--
1893
-- Parameters:
1894
-- # ##left_actions## : a sequence of maps, the left actions of each element in the left hand set.
1895
--
1896
-- Returns:
1897
-- An operation ##F##, realizing the conditions above, with minimal cardinal values, or "" if
1898
-- the maps are not defined on the same set.
1899
--
1900
-- Errors:
1901
-- ##left_actions## must be a rectangular matrix.
1902
--
1903
-- Comments:
1904
--
1905
-- If ##F## is the result, and is defined from ##E1 x E2## to ##E##, then each left action is
1906
-- a map from ##E2## to ##E##, the "left multiplication" by an element of ##E1##.
1907
--
1908
-- Example 1:
1909
--
1910
-- sequence s = {{2, 3, 2, 3}, {3, 1, 2, 5}, {1, 2, 2, 2}, {2, 3, 2, 4}, {3, 1, 2, 3}}
1911
-- operation F = define_operation(s)
1912
-- -- F is now {{{2,3},{3,1},{1,2},{2,3},{3,1}},{5,2,3}
1913
-- ? operation(s) -- prints out 1.
1914
--
1915
--
1916
-- See Also:
1917
-- [[:operation]]
1918
19191
1920
integer size_left,size_right
1921
map f
1922
19231
f=left_actions[1]
19241
size_left=f[$-1]
19251
size_right=f[$]
19261
left_actions[1]=f[1..$-2]
19271
for i=2 to length(left_actions) do
19284
f=left_actions[i]
19294
if f[$-1]!=size_left then
19300
report_error({"define_operation","All specified actions do not map to the same result set."})
1931
end if
19324
if f[$]>size_right then
19330
size_right=f[$]
1934
end if
19354
left_actions[i]=f[1..$-2]
19364
end for
19371
return {left_actions,{size_left,length(left_actions),size_right}}
1938
end function
1939
1940
--**
1941
-- Determine whether f(x,y) always equals f(y,x).
1942
--
1943
-- Parameters:
1944
-- # ##f## : the operation to test.
1945
--
1946
-- Returns:
1947
--
1948
-- An **integer**, 1 if exchanging operands makes sense and has no effect, else 0.
1949
--
1950
-- Example 1:
1951
--
1952
-- operation f = {{{1,2,3},{2,3,4},{3,4,5}},{3,3,5}}
1953
-- -- f is the addition from {0,1,2}x{0,1,2} to {0,1,2,3,4}.
1954
-- ? is_symmetric(f) -- prints out 1.
1955
--
1956
--
1957
-- See Also:
1958
-- [[:operation]], [[:has_unit]]
1959
19601
1961
sequence s
1962
integer n
19631
n=f[2][1]
19641
if n!=f[2][2] then
19650
return 0
1966
end if
19671
s=f[1]
19681
for i=1 to n-1 do
19694
for j=i+1 to n do
197010
if s[i][j]!=s[j][i] then
19710
return 0
1972
end if
197310
end for
19744
end for
19751
return 1
1976
end function
1977
1978
--**
1979
-- Determine whether the identity f(f(x,y),z)=f(x,f(y,z)) always makes sense and holds.
1980
--
1981
-- Parameters:
1982
-- # ##f## : the operation to test.
1983
--
1984
-- Returns:
1985
-- An **integer**, 1 if ##f## is an internal operation on a set and is associative, else 0.
1986
--
1987
-- Comments:
1988
--
1989
-- Being associative is equivalent to not depending on parentheses for
1990
-- defining iterated execution.
1991
--
1992
-- Example 1:
1993
--
1994
-- operation f = {{{1, 2, 3}, {2, 3, 1}, {3, 1, 2}}, {3, 3, 3}}
1995
-- -- f is the addition modulo 3 from {0, 1, 2} x {0, 1, 2} to {0, 1, 2}.
1996
-- ? is_symmetric(f) -- prints out 1.
1997
--
1998
--
1999
-- See Also:
2000
-- [[:operation]], [[:has_unit]]
2001
20021
2003
sequence s
2004
integer n
2005
20061
s=f[2]
20071
n=s[1]
20081
if s[2]!=n or s[3]!=n then
20090
return 0
2010
end if
20111
s=f[1]
20121
for i=1 to n do
20135
for j=1 to n do
201425
for k=1 to n do
2015125
if s[s[i][j]][k]!=s[i][s[j][k]] then
20160
return 0
2017
end if
2018125
end for
201925
end for
20205
end for
20211
return 1
2022
end function
2023
20241
20251
if f[2][2]!=f[2][3] then
20260
return 0
2027
else
20281
return find(iota(f[2][2]),f[1])
2029
end if
2030
end function
2031
20322
2033
sequence result,s
20342
if f[2][2]!=f[2][3] then
20351
return ""
2036
else
20371
result=""
20381
s=iota(f[2][2])
20391
for i=1 to f[2][1] do
20405
if equal(f[1][i],s) then
20411
result&=i
2042
end if
20435
end for
20441
return result
2045
end if
2046
end function
2047
2048
--**
2049
-- Finds all left units for an operation.
2050
--
2051
-- Parameters:
2052
-- # ##f## : the operation to test.
2053
--
2054
-- Returns:
2055
--
2056
-- A possibly empty **sequence**, listing all ##x## such that ##f(x,.)## is the identity map.
2057
--
2058
-- Example 1:
2059
--
2060
-- operation f = {{{1,2,3},{1,2,3},{3,1,2}},{3,3,3}}
2061
-- sequence s = all_left_units(f)
2062
-- s is now {1,2}.
2063
--
2064
--
2065
-- See Also:
2066
-- [[:all_right_units]], [[:is_unit]], [[:has_unit]]
2067
20681
20691
return all_left_units_(f)
2070
end function
2071
20722
20732
if f[2][2]!=f[2][3] or not bounded_integer(x,1,f[2][1]) then
20741
return 0
2075
else
20761
return equal(f[1][x],iota(f[2][2]))
2077
end if
2078
end function
2079
20801
2081
integer p
20821
if f[2][3]!=f[2][1] then
20830
return ""
2084
else
20851
for i=1 to f[2][1] do
20861
p=0
20871
for j=1 to f[2][2] do
20882
if f[1][j][i]!=j then
20890
p=j
20900
exit
2091
end if
20922
end for
20931
if p=0 then
20941
return i
2095
end if
20960
end for
20970
return 0
2098
end if
2099
end function
2100
2101
--**
2102
-- Finds all right units for an operation.
2103
--
2104
-- Parameters:
2105
-- # ##f## : the operation to test.
2106
--
2107
-- Returns:
2108
--
2109
-- A possibly empty **sequence**, of all ##y## such that ##f(.,y)## is the identity map..
2110
--
2111
-- Example 1:
2112
--
2113
-- operation f = {{{1,2,3},{1,2,3},{3,1,2}},{3,3,3}}
2114
-- sequence s = all_right_units(f)
2115
-- s is now empty.
2116
--
2117
--
2118
-- See Also:
2119
-- [[:all_left_units]], [[:is_unit]], [[:has_unit]]
2120
21211
2122
integer p
2123
sequence result
2124
21251
result=""
21261
if f[2][3]!=f[2][1] then
21270
return result
2128
else
21291
for i=1 to f[2][2] do
21302
p=0
21312
for j=1 to f[2][1] do
21326
if f[1][j][i]!=j then
21331
p=j
21341
exit
2135
end if
21365
end for
21372
if p=0 then
21381
result&=i
2139
end if
21402
end for
21411
return result
2142
end if
2143
end function
2144
21452
2146
-- Description: Wrapped by is_right_unit() so as to avoid some type checks.
21472
if f[2][3]!=f[2][1] or not bounded_integer(x,1,f[2][2]) then
21480
return 0
2149
else
21502
for i=1 to f[2][1] do
21513
if f[1][i][x]!=i then
21522
return 0
2153
end if
21541
end for
21550
return 1
2156
end if
2157
end function
2158
21591
2160
sequence s
21611
s=all_left_units_(f)
21621
if length(s)!=1 then
21631
return 0
21640
elsif is_right_unit_(s[1],f) then
21650
return s[1]
2166
else
21670
return 0
2168
end if
2169
end function
2170
2171
--**
2172
-- Returns an unit of a given kind for an operation if there is any, else 0.
2173
--
2174
-- Parameters:
2175
-- # ##f## : the operation to test.
2176
-- # ##flags## : an integer, which says whether one or two sided units are looked for. Defaults to ##SIDE_BOTH##.
2177
--
2178
-- Returns:
2179
-- An **integer**, if ##f## has a unit of the requested type, it is returned. Otherwise, 0 is returned..
2180
--
2181
-- Comments:
2182
--
2183
-- If there is a two sided inverse, it is unique.
2184
--
2185
-- Only the two lower bits of ##flags## matter. They must be ##SIDE_LEFT## to check for left
2186
-- units, ##SIDE_RIGHT## for right units. Otherwise, two sided units are determined.
2187
--
2188
-- Example 1:
2189
--
2190
-- operation f = {{{1,2,3},{2,3,1},{3,1,2}},{3,3,3}}
2191
-- ? has_unit(f) -- prints out 1.
2192
--
2193
--
2194
-- See Also:
2195
-- [[:all_left_units]], [[:all_right_units]],[[:is_unit]]
2196
21973
21983
flags = and_bits(flags, SIDE_BOTH)
21993
switch flags do
2200
case SIDE_LEFT then
22011
return has_left_unit(f)
2202
2203
case SIDE_RIGHT then
22041
return has_right_unit(f)
2205
2206
case else
22071
return has_unit_(f)
2208
end switch
2209
end function
2210
2211
--**
2212
-- Determines if an element is a (one sided) unit for an operation.
2213
--
2214
-- Parameters:
2215
-- # ##x## : an integer, the element to test
2216
-- # ##f## : the operation involved
2217
--
2218
-- Returns:
2219
--
2220
-- An **integer**, either ##SIDE_NONE##, ##SIDE_LEFT##, ##SIDE_RIGHT## or ##SIDE_BOTH##.
2221
--
2222
-- Example 1:
2223
--
2224
-- operation f = {{{1, 2, 3}, {1, 2, 3}, {3, 1, 2}}, {3, 3,3 }}
2225
-- ? is_left_unit(3, f) -- prints out 0.
2226
--
2227
--
2228
-- See Also:
2229
-- [[:all_left_units]], [[:has_unit]]
2230
22312
22322
return is_left_unit(x, f) + SIDE_RIGHT * is_right_unit_(x, f)
2233
end function
2234
2235
--**
2236
-- Returns the bilateral inverse of an element by a operation if it exists and the operation has a unit.
2237
--
2238
-- Parameters:
2239
-- # ##x## : the element to test
2240
-- # ##f## : the operation involved.
2241
--
2242
-- Returns:
2243
--
2244
-- If ##f##, has a bilateral unit ##e## and there is a (necessarily unique) ##y## such that ##f(x,y)=e##,
2245
-- ##y## is returned. Otherwise, 0 is returned..
2246
--
2247
-- Example 1:
2248
--
2249
-- operation f = {{{1, 2, 3}, {2, 3, 1}, {3, 1, 2}}, {3, 3, 3}}
2250
-- ? has_inverse(3, f) -- prints out 2.
2251
--
2252
--
2253
-- See Also:
2254
-- [[:has_unit]]
2255
22560
22570
return find(has_unit_(f),f[1][x])
2258
end function
2259
22601
2261
-- Description: Wrapped by distributes_left(), so as to avoid some type checks.
2262
integer p,q,p1
2263
sequence f1,g1
22641
p=product[2][2]
22651
if transpose then
22660
q=3
2267
else
22681
q=1
2269
end if
22701
p1=product[2][q]
22711
if p=product[2][4-q] and not find(0,sum[2]=p) then
22721
f1=product[1]
22731
g1=sum[1]
22741
if transpose then
22750
for i=1 to p1 do
22760
for j=1 to p do
22770
for k=1 to p do
22780
if f1[i][g1[k][j]]!=g1[f1[i][k]][f1[i][j]] then
22790
return 0
2280
end if
22810
end for
22820
end for
22830
end for
2284
else
22851
for i=1 to p do
22863
for j=1 to p1 do
22879
for k=1 to p1 do
228827
if f1[i][g1[j][k]]!=g1[f1[i][j]][f1[i][k]] then
22890
return 0
2290
end if
229127
end for
22929
end for
22933
end for
2294
end if
22951
return 1
2296
else
22970
return 0
2298
end if
2299
end function
2300
23011
2302
integer p,q,p1
2303
sequence f1,g1
23041
p=product[2][2]
23051
if transpose then
23061
q=1
2307
else
23080
q=3
2309
end if
23101
p1=product[2][q]
23111
if p=product[2][4-q] and not find(0,sum[2]=p) then
23121
f1=product[1]
23131
g1=sum[1]
23141
if transpose then
23151
for i=1 to p1 do
23163
for j=1 to p do
23179
for k=1 to p do
231827
if f1[i][g1[j][k]]!=g1[f1[i][j]][f1[i][k]] then
23190
return 0
2320
end if
232127
end for
23229
end for
23233
end for
2324
else
23250
for i=1 to p do
23260
for j=1 to p1 do
23270
for k=1 to p1 do
23280
if f1[i][g1[k][j]]!=g1[f1[i][k]][f1[i][j]] then
23290
return 0
2330
end if
23310
end for
23320
end for
23330
end for
2334
end if
23351
return 1
2336
else
23370
return 0
2338
end if
2339
end function
2340
2341
--**
2342
-- Determine whether a product map distributes over a sum
2343
--
2344
-- Parameters:
2345
-- # ##product##: the operation that may be distributive over ##sum##
2346
-- # ##sum##: : the operations over which ##product## might distribute
2347
-- # ##transpose##: an integer, nonzero if ##product## is a right operation. Defaults to 0.
2348
--
2349
-- Returns:
2350
--
2351
-- An **integer**, either of
2352
-- * ##SIDE_NONE## ~-- ##product## does not distribute either way over ##sum##
2353
-- * ##SIDE_LEFT## ~-- ##product## distributes over ##sum## on the left only
2354
-- * ##SIDE_RIGHT## ~-- ##product## distributes over ##sum## on the right only
2355
-- * ##SIDE_BOTH## ~-- ##product## distributes over ##sum## o(both ways)
2356
--
2357
-- Example 1:
2358
--
2359
-- operation sum = {{{1,2,3},{2,3,1},{3,1,2}},{3,3,3}}
2360
-- operation product = {{{1,1,1},{1,2,3},{1,3,2}},{3,3,3}}
2361
-- ?distributes_right(product,sum,0) -- prints out 1.
2362
--
2363
--
2364
23651
23661
return distributes_left_(product,sum,transpose)+2*distributes_right_(product,sum,not transpose)
2367
end function
2368