Name | Executed | Routines | % | Executed | Lines | % | Unexecuted |
/home/matt/eu/rds/include/std/sets.e | 68 | 70 | 97.14% | 614 | 780 | 78.72% | 166 |
# | 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 | ||
25 | 0 | |
26 | -- Description: Prints an error message on stderr and abort(1)s. | |
27 | -- Takes: {routine name,error message}; both are strings. | |
28 | 0 | crash("Error in routine %s in module %s: %s",{s[1],"sets.e",s[2]}) |
29 | 0 | 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 | ||
41 | 85 | |
42 | object x,y | |
43 | ||
44 | 85 | if atom(s) then |
45 | 0 | return 0 |
46 | end if | |
47 | ||
48 | 85 | if length(s) < 2 then |
49 | 2 | return 1 |
50 | end if | |
51 | ||
52 | 83 | x = s[1] |
53 | 83 | for i = 2 to length(s) do |
54 | 365 | y = s[i] |
55 | 365 | if eu:compare(y, x) < 1 then |
56 | 0 | return 0 |
57 | end if | |
58 | ||
59 | 365 | x = y |
60 | 365 | end for |
61 | ||
62 | 83 | return 1 |
63 | end type | |
64 | ||
65 | 612 | |
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 | |
72 | 612 | if not integer(x) then |
73 | 0 | return 0 |
74 | end if | |
75 | 612 | if x < lbound then |
76 | 0 | return 0 |
77 | end if | |
78 | ||
79 | 612 | if x > ubound then |
80 | 0 | return 0 |
81 | end if | |
82 | ||
83 | 612 | 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 | ||
111 | 127 | |
112 | object p,q | |
113 | ||
114 | 127 | if atom(s) then |
115 | 0 | return 0 |
116 | end if | |
117 | ||
118 | 127 | if length(s) <= 2 then |
119 | 0 | return 0 |
120 | end if | |
121 | ||
122 | -- The 2nd last element contains the number of items in the map. | |
123 | 127 | q = s[$-1] |
124 | 127 | if not integer(q) then |
125 | 0 | return 0 -- Sanity check failed. |
126 | end if | |
127 | 127 | if q != length(s)-2 then |
128 | 0 | return 0 -- Sanity check failed. |
129 | end if | |
130 | ||
131 | -- The last element contains the upper boundary for element values. | |
132 | 127 | p = s[$] |
133 | ||
134 | 127 | if not integer(p) then |
135 | 0 | return 0 -- Sanity check failed. |
136 | end if | |
137 | ||
138 | 127 | if p < 0 then |
139 | 0 | return 0 -- Sanity check failed. |
140 | end if | |
141 | ||
142 | -- Check that each element is within the boundaries. | |
143 | 127 | for i = 1 to q do |
144 | 609 | if not bounded_integer(s[i], 1, p) then |
145 | 0 | return 0 |
146 | end if | |
147 | 609 | end for |
148 | ||
149 | 127 | 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 | ||
168 | 19 | |
169 | sequence u | |
170 | ||
171 | 19 | if atom(s) then |
172 | 0 | return 0 |
173 | end if | |
174 | ||
175 | 19 | if length(s) != 2 then |
176 | 0 | return 0 |
177 | end if | |
178 | ||
179 | 19 | if length(s[2]) != 3 then |
180 | 0 | return 0 |
181 | end if | |
182 | ||
183 | 19 | if length(s[1]) != s[2][1] then |
184 | 0 | return 0 |
185 | end if | |
186 | ||
187 | ||
188 | 19 | u = s[2][2..3] |
189 | 19 | for i=1 to length(s[1]) do |
190 | 87 | if not map(s[1][i] & u) then |
191 | 0 | return 0 |
192 | end if | |
193 | 87 | end for |
194 | 19 | return 1 |
195 | end type | |
196 | ||
197 | --**** | |
198 | -- === Inclusion and belonging. | |
199 | -- | |
200 | ||
201 | 111 | |
202 | integer r,c | |
203 | ||
204 | 111 | if endpoint > length(haystack) then |
205 | 6 | endpoint = length(haystack) |
206 | end if | |
207 | 111 | if startpoint < 1 then |
208 | 12 | startpoint = 1 |
209 | end if | |
210 | ||
211 | 111 | c=eu:compare(needle,haystack[startpoint]) |
212 | 111 | if c=1 then |
213 | 94 | c=eu:compare(needle,haystack[endpoint]) |
214 | 94 | if c=-1 then |
215 | 78 | while endpoint - startpoint>1 do |
216 | 130 | r=floor((endpoint+startpoint)/2) |
217 | 130 | c=eu:compare(needle,haystack[r]) |
218 | 130 | if c=-1 then |
219 | 49 | endpoint=r |
220 | 81 | elsif c=0 then |
221 | 66 | return r |
222 | else | |
223 | 15 | startpoint=r |
224 | end if | |
225 | 64 | end while |
226 | 12 | return -endpoint |
227 | 16 | elsif c=0 then |
228 | 7 | return endpoint |
229 | else | |
230 | 9 | return -1-endpoint |
231 | end if | |
232 | 17 | elsif c=0 then |
233 | 7 | return startpoint |
234 | else | |
235 | 10 | 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 | ||
261 | 10 | |
262 | 10 | 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 | ||
278 | 1 | |
279 | 1 | 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 | ||
302 | 4 | |
303 | 4 | if length( s ) then |
304 | 3 | return bfind(x, s) > 0 |
305 | else | |
306 | 1 | return 0 |
307 | end if | |
308 | end function | |
309 | ||
310 | 2 | |
311 | integer p | |
312 | ||
313 | 2 | if length(s) = 0 then |
314 | 0 | return {x} |
315 | end if | |
316 | ||
317 | 2 | p=bfind(x, s) |
318 | 2 | if p < 0 then |
319 | 1 | return insert(s,x,-p) |
320 | end if | |
321 | 1 | 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 | ||
344 | 2 | |
345 | 2 | return add_to_(x,S) |
346 | end function | |
347 | ||
348 | 2 | |
349 | integer p | |
350 | ||
351 | 2 | if length(s) = 0 then |
352 | 0 | return s |
353 | end if | |
354 | ||
355 | 2 | p=bfind(x,s) |
356 | 2 | if p>0 then |
357 | 1 | return remove(s,p) |
358 | else | |
359 | 1 | 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 | ||
383 | 2 | |
384 | 2 | return remove_from_(x,s) |
385 | end function | |
386 | ||
387 | 4 | |
388 | -- Returns: {1,2,...,count}, or "" if count is not greater than 0. | |
389 | sequence result | |
390 | 4 | if count<=0 then |
391 | 0 | return "" |
392 | end if | |
393 | 4 | result=repeat(1,count) |
394 | 4 | for i=2 to count do |
395 | 18 | result[i]=i |
396 | 18 | end for |
397 | 4 | return result |
398 | end function | |
399 | ||
400 | 4 | |
401 | integer p,q,ls1 | |
402 | sequence result | |
403 | ||
404 | 4 | q=length(s2) |
405 | 4 | ls1=length(s1) |
406 | 4 | if q>ls1 then |
407 | 4 | if ls1>1 then |
408 | 4 | result=repeat(0,ls1) |
409 | 4 | p=1 |
410 | 4 | for i=1 to ls1/2 do |
411 | 4 | p=bfind(s1[i],s2,p,q) |
412 | 4 | if p<0 then |
413 | 2 | return 0 |
414 | end if | |
415 | 2 | result[i]=p |
416 | 2 | p+=1 |
417 | 2 | q=bfind(s1[$+1-i],s2,p,q) |
418 | 2 | if q<0 then |
419 | 0 | return 0 |
420 | end if | |
421 | 2 | result[$+1-i]=q |
422 | 2 | q-=1 |
423 | 2 | end for |
424 | 2 | if and_bits(ls1,1) then |
425 | 2 | p=bfind(s1[(ls1+1)/2],s2,p,q) |
426 | 2 | if p<=0 then |
427 | 0 | return 0 |
428 | end if | |
429 | 2 | result[(ls1+1)/2]=p |
430 | end if | |
431 | 2 | if mode then |
432 | 1 | return result |
433 | else | |
434 | 1 | return 1 |
435 | end if | |
436 | 0 | elsif ls1=1 then |
437 | 0 | p=find(s1[1],s2) |
438 | 0 | if p=0 then |
439 | 0 | return 0 |
440 | 0 | elsif mode then |
441 | 0 | return {p} |
442 | else | |
443 | 0 | return 1 |
444 | end if | |
445 | else | |
446 | 0 | if mode then |
447 | 0 | return {} |
448 | else | |
449 | 0 | return 1 |
450 | end if | |
451 | end if | |
452 | 0 | elsif q |
453 | 0 | return 0 |
454 | else | |
455 | 0 | if mode then |
456 | 0 | return iota(ls1) |
457 | else | |
458 | 0 | 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]] | |
482 | 2 | |
483 | 2 | 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 | -- | |
508 | 2 | |
509 | 2 | return is_subset_(small,large,1) |
510 | end function | |
511 | ||
512 | 48 | |
513 | -- Description: Returns the absolute value of p. | |
514 | 48 | if p>0 then |
515 | 23 | return p |
516 | else | |
517 | 25 | return -p |
518 | end if | |
519 | end function | |
520 | ||
521 | 5 | |
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 | ||
526 | 5 | q=length(s2) |
527 | 5 | if q>1 then |
528 | 5 | ls1=length(s1) |
529 | 5 | if ls1>1 then |
530 | 5 | if eu:compare(s1[$],s2[1])=-1 then |
531 | 0 | return iota(length(s1)) |
532 | 5 | elsif eu:compare(s2[$],s1[1])=-1 then |
533 | 0 | return iota(length(s1))+q |
534 | end if | |
535 | 5 | temp=s1 |
536 | 5 | p=1 |
537 | 5 | for i=1 to length(s1)/2 do |
538 | 13 | p=bfind(s1[i],s2,p,q) |
539 | 13 | temp[i]=p |
540 | 13 | if p>0 then |
541 | 6 | p+=1 |
542 | else | |
543 | 7 | p=-p-1 |
544 | end if | |
545 | 13 | q=bfind(s1[$+1-i],s2,p,q) |
546 | 13 | temp[$+1-i]=q |
547 | 13 | if q>0 then |
548 | 5 | q-=1 |
549 | else | |
550 | 8 | q=-q |
551 | end if | |
552 | 13 | end for |
553 | 5 | if and_bits(ls1,1) then |
554 | 3 | temp[(ls1/2)+1]=bfind(s1[(ls1/2)+1],s2,p,q) |
555 | end if | |
556 | 5 | result=temp |
557 | 5 | if result[1]<0 then |
558 | 3 | result[1]*=-1 |
559 | end if | |
560 | 5 | q_1=temp[1] |
561 | 5 | for i=2 to length(result) do |
562 | 24 | q=temp[i] |
563 | 24 | result[i]=abs(q)-abs(q_1)+result[i-1]+(q_1<0) |
564 | 24 | q_1=q |
565 | 24 | end for |
566 | 5 | return result |
567 | 0 | elsif length(s1)=1 then |
568 | 0 | q=find(s1[1],s2) |
569 | 0 | if q>0 then |
570 | 0 | return {q} |
571 | else | |
572 | 0 | return {-q} |
573 | end if | |
574 | else | |
575 | 0 | return "" |
576 | end if | |
577 | 0 | elsif q=0 then |
578 | 0 | return iota(length(s1)) |
579 | else | |
580 | 0 | q=find(s2[1],s1) |
581 | 0 | if q>0 then |
582 | 0 | return iota(length(s1)) |
583 | else | |
584 | 0 | result=iota(length(s1)) |
585 | 0 | result[-q..$]+=1 |
586 | 0 | 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 | ||
611 | 1 | |
612 | 1 | 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 | ||
640 | 1 | |
641 | integer p,k,L | |
642 | sequence result,s1,s2,x | |
643 | ||
644 | 1 | L=length(s) |
645 | 1 | if L<=3 then |
646 | 1 | if L=0 then |
647 | 0 | return {{}} |
648 | 1 | elsif L=1 then |
649 | 0 | return {{},s} |
650 | 1 | elsif L=2 then |
651 | 0 | return {{},{s[1]},{s[2]},s} |
652 | else | |
653 | 1 | return {{},{s[1]},{s[2]},{s[3]},s[1..2],{s[1],s[3]},s[2..3],s} |
654 | end if | |
655 | else | |
656 | 0 | result=repeat(0,power(2,L)) |
657 | 0 | p=floor(L/2) |
658 | 0 | s1=subsets(s[1..p]) |
659 | 0 | s2=subsets(s[p+1..$]) |
660 | 0 | k=1 |
661 | 0 | for i=1 to length(s1) do |
662 | 0 | x=s1[i] |
663 | 0 | for j=1 to length(s2) do |
664 | 0 | result[k]=x&s2[j] |
665 | 0 | k+=1 |
666 | 0 | end for |
667 | 0 | end for |
668 | 0 | return result |
669 | end if | |
670 | end function | |
671 | ||
672 | --**** | |
673 | -- === Basic set-theoretic operations. | |
674 | -- | |
675 | ||
676 | 4 | |
677 | -- Description: Wrapped by intersection() so as to avoid some type checks. | |
678 | integer k1,k2,k,c,ls1,ls2 | |
679 | sequence result | |
680 | ||
681 | 4 | ls2=length(s2) |
682 | 4 | result=s1 |
683 | 4 | if ls2=0 then |
684 | 0 | return "" |
685 | 4 | elsif ls2=1 then |
686 | 1 | if belongs_to(s2[1],s1) then |
687 | 0 | return s2 |
688 | else | |
689 | 1 | return "" |
690 | end if | |
691 | end if | |
692 | 3 | ls1=length(s1) |
693 | 3 | k1=1 |
694 | 3 | k2=1 |
695 | 3 | k=1 |
696 | 3 | c=eu:compare(s1[1],s2[1]) |
697 | 3 | while k1<=ls1 and k2<=ls2 do |
698 | 13 | if c=0 then |
699 | 7 | result[k]=s1[k1] |
700 | 7 | k+=1 |
701 | 7 | k1+=1 |
702 | 7 | k2+=1 |
703 | 7 | if k1>ls1 or k2>ls2 then |
704 | 3 | return result[1..k-1] |
705 | else | |
706 | 4 | c=eu:compare(s1[k1],s2[k2]) |
707 | end if | |
708 | 6 | elsif c=1 then |
709 | 1 | k2=bfind(s1[k1],s2,k2,length(s2)) |
710 | 1 | if k2>=0 then |
711 | 0 | c=0 |
712 | else | |
713 | 1 | k2=-k2 |
714 | 1 | c=-1 |
715 | end if | |
716 | else | |
717 | 5 | k1=bfind(s2[k2],s1,k1,length(s1)) |
718 | 5 | if k1>=0 then |
719 | 5 | c=0 |
720 | else | |
721 | 0 | k1=-k1 |
722 | 0 | c=1 |
723 | end if | |
724 | end if | |
725 | 10 | end while |
726 | 0 | 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 | ||
750 | 3 | |
751 | 3 | return intersection_(S1,S2) |
752 | end function | |
753 | ||
754 | 6 | |
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 | ||
760 | 6 | result=s1&s2 |
761 | 6 | k1=1 |
762 | 6 | k2=1 |
763 | 6 | k=1 |
764 | 6 | c=eu:compare(s1[1],s2[1]) |
765 | 6 | while k1<=ls1 and k2<=ls2 do |
766 | 34 | if c=0 then |
767 | 14 | if mode then |
768 | 9 | result[k]=s1[k1] |
769 | 9 | k+=1 |
770 | end if | |
771 | 14 | k1+=1 |
772 | 14 | k2+=1 |
773 | 14 | if k1>ls1 or k2>ls2 then |
774 | 4 | exit |
775 | else | |
776 | 10 | c=eu:compare(s1[k1],s2[k2]) |
777 | end if | |
778 | 20 | elsif c=1 then |
779 | 6 | k0=bfind(s1[k1],s2,k2,length(s2)) |
780 | 6 | if k0>=0 then |
781 | 0 | c=0 |
782 | else | |
783 | 6 | k0=-k0 |
784 | 6 | c=-1 |
785 | end if | |
786 | 6 | result[k..k-k2+k0-1]=s2[k2..k0-1] |
787 | 6 | k+=(k0-k2) |
788 | 6 | k2=k0 |
789 | else | |
790 | 14 | k0=bfind(s2[k2],s1,k1,length(s1)) |
791 | 14 | if k0>=0 then |
792 | 12 | c=0 |
793 | else | |
794 | 2 | k0=-k0 |
795 | 2 | c=1 |
796 | end if | |
797 | 14 | result[k..k-k1+k0-1]=s1[k1..k0-1] |
798 | 14 | k+=(k0-k1) |
799 | 14 | k1=k0 |
800 | end if | |
801 | 30 | end while |
802 | 6 | result=result[1..k-1] |
803 | 6 | if k1<=ls1 then |
804 | 4 | return result & s1[k1..$] |
805 | 2 | elsif k2<=ls2 then |
806 | 2 | return result & s2[k2..$] |
807 | else | |
808 | 0 | return result |
809 | end if | |
810 | end function | |
811 | ||
812 | 5 | |
813 | integer ls1,ls2 | |
814 | ||
815 | 5 | ls1=length(s1) |
816 | 5 | ls2=length(s2) |
817 | 5 | if ls2=0 then |
818 | 0 | return s1 |
819 | 5 | elsif ls1=0 then |
820 | 1 | return s2 |
821 | 4 | elsif ls1=1 then |
822 | 0 | return add_to_(s1[1],s2) |
823 | 4 | elsif ls2=1 then |
824 | 0 | return add_to_(s2[1],s1) |
825 | end if | |
826 | 4 | 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 | -- | |
850 | 2 | |
851 | 2 | 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 | -- | |
875 | 2 | |
876 | integer ls1,ls2 | |
877 | ||
878 | 2 | ls1=length(s1) |
879 | 2 | ls2=length(s2) |
880 | 2 | if ls2=0 then |
881 | 0 | return s1 |
882 | 2 | elsif ls1=0 then |
883 | 0 | return s2 |
884 | 2 | elsif ls1=1 then |
885 | 0 | return remove_from_(s1[1],s2) |
886 | 2 | elsif ls2=1 then |
887 | 0 | return remove_from_(s2[1],s1) |
888 | end if | |
889 | 2 | 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 | -- | |
913 | 1 | |
914 | integer k1,k2,k,c,ls1,ls2,k0 | |
915 | sequence result | |
916 | 1 | ls1=length(base) |
917 | 1 | ls2=length(removed) |
918 | 1 | if ls2=0 then |
919 | 0 | return base |
920 | 1 | elsif ls1=0 then |
921 | 0 | return "" |
922 | 1 | elsif ls2=1 then |
923 | 0 | return remove_from_(removed[1],base) |
924 | 1 | elsif ls1=1 then |
925 | 0 | if bfind(base[1],removed,1,length(removed))>0 then |
926 | 0 | return "" |
927 | else | |
928 | 0 | return base |
929 | end if | |
930 | end if | |
931 | 1 | result=base&removed |
932 | 1 | k1=1 |
933 | 1 | k2=1 |
934 | 1 | k=1 |
935 | 1 | c=eu:compare(base[1],removed[1]) |
936 | 1 | while k1<=ls1 and k2<=ls2 do |
937 | 5 | if c=0 then |
938 | 2 | k1+=1 |
939 | 2 | k2+=1 |
940 | 2 | if k1>ls1 or k2>ls2 then |
941 | 1 | exit |
942 | else | |
943 | 1 | c=eu:compare(base[k1],removed[k2]) |
944 | end if | |
945 | 3 | elsif c=1 then |
946 | 1 | k2=bfind(base[k1],removed,k2,length(removed)) |
947 | 1 | if k2>=0 then |
948 | 0 | c=0 |
949 | else | |
950 | 1 | k2=-k2 |
951 | 1 | c=-1 |
952 | end if | |
953 | else | |
954 | 2 | k0=bfind(removed[k2],base,k1,length(base)) |
955 | 2 | if k0>=0 then |
956 | 2 | c=0 |
957 | else | |
958 | 0 | k0=-k0 |
959 | 0 | c=1 |
960 | end if | |
961 | 2 | result[k..k-k1+k0-1]=base[k1..k0-1] |
962 | 2 | k+=(k0-k1) |
963 | 2 | k1=k0 |
964 | end if | |
965 | 4 | end while |
966 | 1 | result=result[1..k-1] |
967 | 1 | if k1<=ls1 then |
968 | 1 | return result & base[k1..$] |
969 | else | |
970 | 0 | return result |
971 | end if | |
972 | end function | |
973 | ||
974 | 3 | |
975 | -- Description: Wrapped by product() to skip type checking | |
976 | sequence result | |
977 | integer ls1,ls2,k | |
978 | object x | |
979 | ||
980 | 3 | ls1=length(s1) |
981 | 3 | ls2=length(s2) |
982 | 3 | if not (ls1 and ls2) then |
983 | 0 | return "" |
984 | end if | |
985 | 3 | k=1 |
986 | 3 | result=repeat(0,ls1*ls2) |
987 | 3 | for i=1 to ls1 do |
988 | 12 | x={s1[i],0} |
989 | 12 | for j=1 to ls2 do |
990 | 26 | x[2]=s2[j] |
991 | 26 | result[k]=x |
992 | 26 | k+=1 |
993 | 26 | end for |
994 | 12 | end for |
995 | 3 | 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 | ||
1019 | 1 | |
1020 | 1 | 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 | ||
1049 | 1 | |
1050 | sequence result | |
1051 | integer lt | |
1052 | ||
1053 | 1 | lt = length(target) |
1054 | 1 | result = mapping & length(mapping) & lt |
1055 | 1 | for i = 1 to length(mapping) do |
1056 | 7 | result[i] = bfind(mapping[i], target) |
1057 | 7 | end for |
1058 | ||
1059 | 1 | 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 | ||
1094 | 1 | |
1095 | sequence result | |
1096 | set sorted,sorted_to | |
1097 | integer ls,lm_to,lm | |
1098 | ||
1099 | 1 | lm=length(mapped) |
1100 | 1 | lm_to=length(mapped_to) |
1101 | ||
1102 | 1 | if lm>lm_to then |
1103 | 0 | mapped=mapped[1..lm_to] |
1104 | end if | |
1105 | ||
1106 | 1 | sorted=sequence_to_set(mapped) |
1107 | 1 | sorted_to=sequence_to_set(mapped_to) |
1108 | 1 | ls=length(sorted) |
1109 | 1 | result=repeat(0,ls)&ls&length(sorted_to) |
1110 | ||
1111 | 1 | for i=1 to lm do |
1112 | 7 | result[find(mapped[i],sorted)]=find(mapped_to[i],sorted_to) |
1113 | 7 | end for |
1114 | ||
1115 | 1 | if mode then |
1116 | 0 | return {result,sorted,sorted_to} |
1117 | else | |
1118 | 1 | 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 | ||
1151 | 1 | |
1152 | integer p | |
1153 | ||
1154 | 1 | if f[$]>length(output) then |
1155 | 0 | report_error({"image","The map range would not fit into the supplied target set."}) |
1156 | end if | |
1157 | ||
1158 | 1 | p = bfind(x, input) |
1159 | ||
1160 | 1 | if p<0 or p>f[$-1] then |
1161 | 0 | report_error({"image","The map is not defined for the supplied argument."}) |
1162 | else | |
1163 | 1 | 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 | ||
1189 | 1 | |
1190 | sequence result | |
1191 | ||
1192 | 1 | result=sequence_to_set(f[1..$-2]) |
1193 | 1 | for i=1 to length(result) do |
1194 | 3 | result[i]=s[result[i]] |
1195 | 3 | end for |
1196 | ||
1197 | 1 | 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 | ||
1233 | 1 | |
1234 | sequence result | |
1235 | integer k,p | |
1236 | ||
1237 | 1 | if f[$-1] > length(s1) or f[$] > length(s2) then |
1238 | 0 | report_error({"direct_map","The supplied map cannot map the source set into the target set."}) |
1239 | end if | |
1240 | ||
1241 | 1 | k=1 |
1242 | 1 | result=s0 |
1243 | ||
1244 | 1 | for i=1 to length(s0) do |
1245 | 3 | p = bfind(s0[i], s1) |
1246 | 3 | if p>0 then |
1247 | 3 | result[k]=s2[f[p]] |
1248 | 3 | k+=1 |
1249 | end if | |
1250 | 3 | end for |
1251 | ||
1252 | 1 | 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 | -- | |
1279 | 2 | |
1280 | 2 | sequence result = restriction |
1281 | 2 | integer p = 1, k = 0 |
1282 | ||
1283 | 2 | for i=1 to length(restriction) do |
1284 | 10 | p=bfind(restriction[i],source,p,length(source)) |
1285 | 10 | if p>0 then |
1286 | 10 | k+=1 |
1287 | 10 | result[k]=f[p] |
1288 | end if | |
1289 | 10 | end for |
1290 | ||
1291 | 2 | return result[1..k]&k&f[$] |
1292 | end function | |
1293 | ||
1294 | 5 | |
1295 | -- Description: Wrapped by change_target() to avoid some type checks. | |
1296 | sequence result,done | |
1297 | integer p,fi | |
1298 | ||
1299 | 5 | result=f |
1300 | 5 | done=repeat(0,f[$]) |
1301 | ||
1302 | 5 | for i=1 to f[$-1] do |
1303 | 36 | fi=f[i] |
1304 | 36 | p=done[fi] |
1305 | 36 | if p then |
1306 | 20 | result[i]=p |
1307 | else | |
1308 | 16 | p=bfind(s1[fi],s2) |
1309 | 16 | if p<0 then |
1310 | 0 | report_error({"change_target","map range not included in new target set."}) |
1311 | else | |
1312 | 16 | result[i]=p |
1313 | 16 | done[fi]=p |
1314 | end if | |
1315 | end if | |
1316 | 36 | end for |
1317 | 5 | result[$]=length(s2) |
1318 | ||
1319 | 5 | 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 | ||
1347 | 1 | |
1348 | 1 | 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 | ||
1386 | 2 | |
1387 | integer len_result,p | |
1388 | set s | |
1389 | sequence result | |
1390 | ||
1391 | 2 | s=union1(target1,target2) |
1392 | 2 | f1=change_target_(f1,target1,s) |
1393 | 2 | f2=change_target_(f2,target2,s) |
1394 | 2 | s=embed_union_(source1,source2) |
1395 | 2 | len_result=length(source1)+length(source2) |
1396 | 2 | result=repeat(0,len_result) |
1397 | 2 | for i=1 to length(s) do |
1398 | 16 | result[s[i]]=f1[i] |
1399 | 16 | end for |
1400 | 2 | s=embed_union_(source2,source1) |
1401 | 2 | for i=1 to length(s) do |
1402 | 10 | p=s[i] |
1403 | 10 | if result[p] then |
1404 | 6 | if result[p]!=f2[i] then |
1405 | 0 | report_error({"combine_maps", |
1406 | "Maps disagree at some point where they are both defined."}) | |
1407 | else | |
1408 | 6 | len_result-=1 |
1409 | end if | |
1410 | else | |
1411 | 4 | result[p]=f2[i] |
1412 | end if | |
1413 | 10 | end for |
1414 | 2 | return result[1..len_result]&len_result&f1[$] |
1415 | end function | |
1416 | ||
1417 | ||
1418 | 3 | |
1419 | -- Description: Wrapped by compose_map(), so as to avoid some type checks. | |
1420 | sequence result | |
1421 | ||
1422 | 3 | if find(0, f1[1..$-2] <= f2[$-1]) then |
1423 | 0 | report_error({"compose_maps","One or more elements in f1 are outside the range of f2."}) |
1424 | end if | |
1425 | 3 | result = f1 |
1426 | 3 | for i = 1 to length(f1)-2 do |
1427 | 20 | result[i] = f2[ f1[i] ] |
1428 | 20 | end for |
1429 | 3 | result[$] = f2[$] |
1430 | 3 | 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 | -- | |
1463 | 1 | |
1464 | 1 | 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 | -- | |
1493 | 1 | |
1494 | 1 | 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 | -- | |
1516 | 1 | |
1517 | sequence s | |
1518 | integer p | |
1519 | object x,y | |
1520 | ||
1521 | 1 | if f[$-1]>f[$] then |
1522 | 1 | return 0 |
1523 | end if | |
1524 | ||
1525 | 0 | p=length(f)-2 |
1526 | 0 | s=sort(f[1..p]) |
1527 | 0 | x=s[1] |
1528 | ||
1529 | 0 | for i=2 to p do |
1530 | 0 | y=s[i] |
1531 | 0 | if y=x then |
1532 | 0 | return 0 |
1533 | end if | |
1534 | 0 | x=y |
1535 | 0 | end for |
1536 | ||
1537 | 0 | return 1 |
1538 | end function | |
1539 | ||
1540 | 1 | |
1541 | 1 | if f[$-1] |
1542 | 0 | return 0 |
1543 | else | |
1544 | 1 | 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 | -- | |
1567 | 1 | |
1568 | 1 | 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 | -- | |
1590 | 1 | |
1591 | 1 | if f[$]!=f[$-1] then |
1592 | 1 | return 0 |
1593 | else | |
1594 | 0 | return is_surjective_(f) |
1595 | end if | |
1596 | end function | |
1597 | ||
1598 | 4 | |
1599 | sequence fibers,result | |
1600 | integer p | |
1601 | 4 | if f[$-1]!=length(s1) or f[$]!=length(s2) then |
1602 | 0 | return "" |
1603 | end if | |
1604 | 4 | fibers=sequence_to_set(f[1..$-2]) |
1605 | 4 | result=repeat({},length(fibers)) |
1606 | 4 | for i=1 to length(s1) do |
1607 | 37 | p=find(f[i],fibers) |
1608 | 37 | result[p]=append(result[p],s1[i]) |
1609 | 37 | end for |
1610 | 4 | 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 | -- | |
1652 | 1 | |
1653 | 1 | 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 | ||
1685 | 1 | |
1686 | sequence x,done,result | |
1687 | integer p | |
1688 | ||
1689 | 1 | x=fiber_over_(f,s1,s2) |
1690 | 1 | result="" |
1691 | 1 | done=repeat(0,length(x[2])) |
1692 | ||
1693 | 1 | for i=1 to length(s0) do |
1694 | 1 | p=find(bfind(s0[i],s1), x[2]) |
1695 | 1 | if p and not done[p] then |
1696 | 1 | done[p]=1 |
1697 | 1 | result=union1(result,x[1][p]) |
1698 | end if | |
1699 | 1 | end for |
1700 | 1 | 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 | ||
1722 | 1 | |
1723 | 1 | sequence result = f |
1724 | 1 | integer k = 0, p = f[$-1] |
1725 | ||
1726 | 1 | for i=1 to p do |
1727 | 10 | result[f[i]]=i |
1728 | 10 | end for |
1729 | ||
1730 | 1 | for i=1 to p do |
1731 | 10 | if result[i] and k then |
1732 | 0 | result[k]=result[i] |
1733 | 0 | k+=1 |
1734 | 10 | elsif result[i]=0 and k=0 then |
1735 | 0 | k=i |
1736 | end if | |
1737 | 10 | end for |
1738 | ||
1739 | 1 | if k then |
1740 | 0 | result[k]=k-1 |
1741 | 0 | result=result[1..k]&p |
1742 | else | |
1743 | 1 | result[$]=p |
1744 | 1 | result[$-1]=f[$] |
1745 | end if | |
1746 | ||
1747 | 1 | 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 | -- | |
1777 | 1 | |
1778 | sequence result,s | |
1779 | integer k ,p | |
1780 | 1 | k=1 |
1781 | 1 | p=f2[$-1] |
1782 | 1 | result=repeat(0,f1[$-1]*p)&f1[$-1]*p&f1[$]*f2[$] |
1783 | 1 | s=f2[1..$-2]-p |
1784 | 1 | for i=1 to f1[$-1] do |
1785 | 7 | result[k..k+p-1]=s+p*f1[i] |
1786 | 7 | k+=p |
1787 | 7 | end for |
1788 | 1 | 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 | ||
1819 | 1 | |
1820 | sequence result | |
1821 | ||
1822 | 1 | result=base |
1823 | 1 | for i=1 to length(base) do |
1824 | 7 | result[i]={first[base_to_1[i]],second[base_to_2[i]]} |
1825 | 7 | end for |
1826 | 1 | 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 | -- | |
1857 | 1 | |
1858 | sequence result,x1,x2,x0 | |
1859 | ||
1860 | 1 | x1=fiber_over_(from_1_to_base,first,base) |
1861 | 1 | x2=fiber_over_(from_2_to_base,second,base) |
1862 | 1 | x0=intersection_(x1[2],x2[2]) |
1863 | 1 | result={} |
1864 | ||
1865 | 1 | for i=1 to length(x0) do |
1866 | 2 | result&=product_(x1[1][find(x0[i],x1[2])],x2[1][find(x0[i],x2[2])]) |
1867 | 2 | end for |
1868 | ||
1869 | 1 | 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 | ||
1884 | 1 | 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 | ||
1919 | 1 | |
1920 | integer size_left,size_right | |
1921 | map f | |
1922 | ||
1923 | 1 | f=left_actions[1] |
1924 | 1 | size_left=f[$-1] |
1925 | 1 | size_right=f[$] |
1926 | 1 | left_actions[1]=f[1..$-2] |
1927 | 1 | for i=2 to length(left_actions) do |
1928 | 4 | f=left_actions[i] |
1929 | 4 | if f[$-1]!=size_left then |
1930 | 0 | report_error({"define_operation","All specified actions do not map to the same result set."}) |
1931 | end if | |
1932 | 4 | if f[$]>size_right then |
1933 | 0 | size_right=f[$] |
1934 | end if | |
1935 | 4 | left_actions[i]=f[1..$-2] |
1936 | 4 | end for |
1937 | 1 | 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 | ||
1960 | 1 | |
1961 | sequence s | |
1962 | integer n | |
1963 | 1 | n=f[2][1] |
1964 | 1 | if n!=f[2][2] then |
1965 | 0 | return 0 |
1966 | end if | |
1967 | 1 | s=f[1] |
1968 | 1 | for i=1 to n-1 do |
1969 | 4 | for j=i+1 to n do |
1970 | 10 | if s[i][j]!=s[j][i] then |
1971 | 0 | return 0 |
1972 | end if | |
1973 | 10 | end for |
1974 | 4 | end for |
1975 | 1 | 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 | ||
2002 | 1 | |
2003 | sequence s | |
2004 | integer n | |
2005 | ||
2006 | 1 | s=f[2] |
2007 | 1 | n=s[1] |
2008 | 1 | if s[2]!=n or s[3]!=n then |
2009 | 0 | return 0 |
2010 | end if | |
2011 | 1 | s=f[1] |
2012 | 1 | for i=1 to n do |
2013 | 5 | for j=1 to n do |
2014 | 25 | for k=1 to n do |
2015 | 125 | if s[s[i][j]][k]!=s[i][s[j][k]] then |
2016 | 0 | return 0 |
2017 | end if | |
2018 | 125 | end for |
2019 | 25 | end for |
2020 | 5 | end for |
2021 | 1 | return 1 |
2022 | end function | |
2023 | ||
2024 | 1 | |
2025 | 1 | if f[2][2]!=f[2][3] then |
2026 | 0 | return 0 |
2027 | else | |
2028 | 1 | return find(iota(f[2][2]),f[1]) |
2029 | end if | |
2030 | end function | |
2031 | ||
2032 | 2 | |
2033 | sequence result,s | |
2034 | 2 | if f[2][2]!=f[2][3] then |
2035 | 1 | return "" |
2036 | else | |
2037 | 1 | result="" |
2038 | 1 | s=iota(f[2][2]) |
2039 | 1 | for i=1 to f[2][1] do |
2040 | 5 | if equal(f[1][i],s) then |
2041 | 1 | result&=i |
2042 | end if | |
2043 | 5 | end for |
2044 | 1 | 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 | ||
2068 | 1 | |
2069 | 1 | return all_left_units_(f) |
2070 | end function | |
2071 | ||
2072 | 2 | |
2073 | 2 | if f[2][2]!=f[2][3] or not bounded_integer(x,1,f[2][1]) then |
2074 | 1 | return 0 |
2075 | else | |
2076 | 1 | return equal(f[1][x],iota(f[2][2])) |
2077 | end if | |
2078 | end function | |
2079 | ||
2080 | 1 | |
2081 | integer p | |
2082 | 1 | if f[2][3]!=f[2][1] then |
2083 | 0 | return "" |
2084 | else | |
2085 | 1 | for i=1 to f[2][1] do |
2086 | 1 | p=0 |
2087 | 1 | for j=1 to f[2][2] do |
2088 | 2 | if f[1][j][i]!=j then |
2089 | 0 | p=j |
2090 | 0 | exit |
2091 | end if | |
2092 | 2 | end for |
2093 | 1 | if p=0 then |
2094 | 1 | return i |
2095 | end if | |
2096 | 0 | end for |
2097 | 0 | 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 | ||
2121 | 1 | |
2122 | integer p | |
2123 | sequence result | |
2124 | ||
2125 | 1 | result="" |
2126 | 1 | if f[2][3]!=f[2][1] then |
2127 | 0 | return result |
2128 | else | |
2129 | 1 | for i=1 to f[2][2] do |
2130 | 2 | p=0 |
2131 | 2 | for j=1 to f[2][1] do |
2132 | 6 | if f[1][j][i]!=j then |
2133 | 1 | p=j |
2134 | 1 | exit |
2135 | end if | |
2136 | 5 | end for |
2137 | 2 | if p=0 then |
2138 | 1 | result&=i |
2139 | end if | |
2140 | 2 | end for |
2141 | 1 | return result |
2142 | end if | |
2143 | end function | |
2144 | ||
2145 | 2 | |
2146 | -- Description: Wrapped by is_right_unit() so as to avoid some type checks. | |
2147 | 2 | if f[2][3]!=f[2][1] or not bounded_integer(x,1,f[2][2]) then |
2148 | 0 | return 0 |
2149 | else | |
2150 | 2 | for i=1 to f[2][1] do |
2151 | 3 | if f[1][i][x]!=i then |
2152 | 2 | return 0 |
2153 | end if | |
2154 | 1 | end for |
2155 | 0 | return 1 |
2156 | end if | |
2157 | end function | |
2158 | ||
2159 | 1 | |
2160 | sequence s | |
2161 | 1 | s=all_left_units_(f) |
2162 | 1 | if length(s)!=1 then |
2163 | 1 | return 0 |
2164 | 0 | elsif is_right_unit_(s[1],f) then |
2165 | 0 | return s[1] |
2166 | else | |
2167 | 0 | 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 | ||
2197 | 3 | |
2198 | 3 | flags = and_bits(flags, SIDE_BOTH) |
2199 | 3 | switch flags do |
2200 | case SIDE_LEFT then | |
2201 | 1 | return has_left_unit(f) |
2202 | ||
2203 | case SIDE_RIGHT then | |
2204 | 1 | return has_right_unit(f) |
2205 | ||
2206 | case else | |
2207 | 1 | 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 | ||
2231 | 2 | |
2232 | 2 | 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 | ||
2256 | 0 | |
2257 | 0 | return find(has_unit_(f),f[1][x]) |
2258 | end function | |
2259 | ||
2260 | 1 | |
2261 | -- Description: Wrapped by distributes_left(), so as to avoid some type checks. | |
2262 | integer p,q,p1 | |
2263 | sequence f1,g1 | |
2264 | 1 | p=product[2][2] |
2265 | 1 | if transpose then |
2266 | 0 | q=3 |
2267 | else | |
2268 | 1 | q=1 |
2269 | end if | |
2270 | 1 | p1=product[2][q] |
2271 | 1 | if p=product[2][4-q] and not find(0,sum[2]=p) then |
2272 | 1 | f1=product[1] |
2273 | 1 | g1=sum[1] |
2274 | 1 | if transpose then |
2275 | 0 | for i=1 to p1 do |
2276 | 0 | for j=1 to p do |
2277 | 0 | for k=1 to p do |
2278 | 0 | if f1[i][g1[k][j]]!=g1[f1[i][k]][f1[i][j]] then |
2279 | 0 | return 0 |
2280 | end if | |
2281 | 0 | end for |
2282 | 0 | end for |
2283 | 0 | end for |
2284 | else | |
2285 | 1 | for i=1 to p do |
2286 | 3 | for j=1 to p1 do |
2287 | 9 | for k=1 to p1 do |
2288 | 27 | if f1[i][g1[j][k]]!=g1[f1[i][j]][f1[i][k]] then |
2289 | 0 | return 0 |
2290 | end if | |
2291 | 27 | end for |
2292 | 9 | end for |
2293 | 3 | end for |
2294 | end if | |
2295 | 1 | return 1 |
2296 | else | |
2297 | 0 | return 0 |
2298 | end if | |
2299 | end function | |
2300 | ||
2301 | 1 | |
2302 | integer p,q,p1 | |
2303 | sequence f1,g1 | |
2304 | 1 | p=product[2][2] |
2305 | 1 | if transpose then |
2306 | 1 | q=1 |
2307 | else | |
2308 | 0 | q=3 |
2309 | end if | |
2310 | 1 | p1=product[2][q] |
2311 | 1 | if p=product[2][4-q] and not find(0,sum[2]=p) then |
2312 | 1 | f1=product[1] |
2313 | 1 | g1=sum[1] |
2314 | 1 | if transpose then |
2315 | 1 | for i=1 to p1 do |
2316 | 3 | for j=1 to p do |
2317 | 9 | for k=1 to p do |
2318 | 27 | if f1[i][g1[j][k]]!=g1[f1[i][j]][f1[i][k]] then |
2319 | 0 | return 0 |
2320 | end if | |
2321 | 27 | end for |
2322 | 9 | end for |
2323 | 3 | end for |
2324 | else | |
2325 | 0 | for i=1 to p do |
2326 | 0 | for j=1 to p1 do |
2327 | 0 | for k=1 to p1 do |
2328 | 0 | if f1[i][g1[k][j]]!=g1[f1[i][k]][f1[i][j]] then |
2329 | 0 | return 0 |
2330 | end if | |
2331 | 0 | end for |
2332 | 0 | end for |
2333 | 0 | end for |
2334 | end if | |
2335 | 1 | return 1 |
2336 | else | |
2337 | 0 | 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 | ||
2365 | 1 | |
2366 | 1 | return distributes_left_(product,sum,transpose)+2*distributes_right_(product,sum,not transpose) |
2367 | end function | |
2368 |