1% BEGIN LICENSE BLOCK
2% Version: CMPL 1.1
3%
4% The contents of this file are subject to the Cisco-style Mozilla Public
5% License Version 1.1 (the "License"); you may not use this file except
6% in compliance with the License.  You may obtain a copy of the License
7% at www.eclipse-clp.org/license.
8% 
9% Software distributed under the License is distributed on an "AS IS"
10% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11% the License for the specific language governing rights and limitations
12% under the License.
13%
14% The Original Code is The List Collection for ECLiPSe.
15% The Initial Developer of the Original Code is Lukasz Domagala.
16% Portions created by the Initial Developer are Copyright (C) 2009.
17% All Rights Reserved.
18
19
20:- module(list_collection).
21
22:- comment(categories, ["Data Structures"]).
23:- comment(summary, "Collection of lists library").
24:- comment(author, "Lukasz Domagala").
25:- comment(copyright, "Silesian University of Technology").
26:- comment(date, "$Date: 2009/07/16 09:11:23 $").
27    
28:- comment(desc,ascii("
29    A library for creation and management of list collections (LCOL).
30    Internally the library uses either the a hashtable or arrays to store lists and their tails. 
31    The advantage of a hash LCOL is that its size does not have to be known in advance and that 
32    non number indexes can be used to address lists in the collection. The drawback of a hash LCOL 
33    is that access to collection elements is slower than for array LCOL. Elements of array LCOL 
34    can be addressed only by positive integers which internally are array indexes. See create/2 
35    for more details.
36    
37    The motivation for creating this library was to be able to easily build input lists for global 
38    constraints from collections of input structures (see example). For this purpose an array(3) LCOL 
39    was usually sufficient, and only a limited set of predicates needed (create/2 , append_element/3, 
40    terminate_all_lists/2, get_list/3).
41    
42    But the idea was extended, additional predicates were added for prefixing the lists, and 
43    reinitialisation of lists. The support for hash LCOL has been added. Hash LCOL may be useful for 
44    some filtering, grouping predicates in cases when the number of lists may vary or indexing by 
45    atoms/ground terms is more readable/convenient.
46
47    ")).
48:- comment(eg,"
49llcol_example:-
50    lib(ic),
51    lib(ic_edge_finder),
52
53    ActivityList=[
54        act(4,7 ,2,machine_1),
55        act(3,4 ,1,machine_2 ),
56        act(2,4 ,2,removed),
57        act(7,10,1,machine_1),
58        act(6,15,3,machine_3)
59        % ...
60    ],
61    
62    %create a collection of activity lists for corresponding machines
63    list_collection:create(hash,LCOL_Machines),
64    
65    %sort the activities for machines
66    (foreach(Activity,ActivityList),
67     param(LCOL_Machines) do 
68        Activity=act(_Start,_End,_Resource,Machine),
69        (Machine \\= removed ->
70            %add an activity to the list for the particular machine
71            list_collection:append_element(LCOL_Machines,Machine,Activity)
72        ;true)
73    ),
74    
75    %close the lists get the machine names
76    list_collection:terminate_all_lists(LCOL_Machines,Machines_Indexes),
77    
78    %for each machine
79    (foreach(Machines_Index,Machines_Indexes),
80     param(LCOL_Machines) do 
81        %Note that get_list/3 can be used even if the lists are not terminated but in such a case the operation
82        %is more time consuming, because all the list elements are copied to new closed list and then returned.
83        %Instead of closing all the lists at once it is also possible to use terminate_and_get_list/3 to ensure 
84        %that the list is closed.
85        
86        %get the activity list for the machine
87        list_collection:get_list(LCOL_Machines,Machines_Index,MActivityList),
88        
89        %create a collection for start,duration and resource variable lists
90        list_collection:create(array(3),LCOL_Start_Dur_Res),
91        
92        (foreach(MActivity,MActivityList),
93         param(LCOL_Start_Dur_Res) do
94         
95            MActivity=act(Start,End,Resource,_Machine),
96            ic:(Duration #= End - Start),
97            list_collection:append_element(LCOL_Start_Dur_Res, 1, Start),
98            list_collection:append_element(LCOL_Start_Dur_Res, 2, Duration),
99            list_collection:append_element(LCOL_Start_Dur_Res, 3, Resource)
100        ),
101        
102        %terminate the start,duration,resource lists
103        list_collection:terminate_all_lists(LCOL_Start_Dur_Res,_Indexes),
104        
105        %get the lists for a cumulative constraint
106        list_collection:get_list(LCOL_Start_Dur_Res, 1, StartList),
107        list_collection:get_list(LCOL_Start_Dur_Res, 2, DurationList),
108        list_collection:get_list(LCOL_Start_Dur_Res, 3, ResourceList),
109
110        %post the constraint
111        ic_edge_finder:cumulative(StartList, DurationList, ResourceList, 3)
112    ).
113    ").
114
115:- lib(hash).
116
117
118:- local struct(list_collection(
119        type,
120        open_list_array,
121        tail_array,
122        list_tail_hash 
123        )).
124
125:- comment(create/2, 
126    [
127        amode:(create(++,-) is det),
128        args:["Type":"A ground term", "LCOL":"A list collection"],
129        summary:"Creates a list collection",
130        desc:ascii("
131        If (Type==hash) a LCOL internally uses a hashtable, this is useful when the number of lists is unknown.
132        If (Type=array(Size)) where Size is a natural number, the LCOL internally uses an array to collect lists,
133        the access to any of the lists is faster, but the Size has to be known in advance and only number 
134        indexes can be used to identify lists. 0<Index=<Size."),
135        %eg:"",
136        see_also:[append_element/3,terminate_all_lists/2,get_list/3],
137        %fail_if:"" ,
138        exceptions:[
139            5:"Not supported Type."
140        ]
141    ]).
142
143:-export create/2.  
144:- mode(create(++,-)).  
145create(array(Size),LCOL):-
146    LCOL=list_collection{
147        type:array(Size), 
148        open_list_array:OpenListArray,
149        tail_array     :TailArray,
150        list_tail_hash :not_used
151        },
152    number(Size),0<Size,
153    !,
154    dim(OpenListArray,[Size]),
155    dim(TailArray,[Size]),
156    (count(Index,1,Size),
157     param(OpenListArray,TailArray) do 
158        setarg(Index,OpenListArray,ListTail),
159        setarg(Index,TailArray,ListTail)
160    ),
161    true.
162
163create(hash, LCOL):-
164    LCOL=list_collection{
165        type:hash, 
166        open_list_array:not_used,
167        tail_array     :not_used,
168        list_tail_hash :ListTailHash
169        },
170    !,
171    hash_create(ListTailHash),
172    true.
173    
174create(_Type, _LCOL):-
175    exc_not_supported_type.
176
177:- comment(append_element/3, 
178    [
179        amode:(append_element(+,++,+) is det),
180        args:["LCOL":"A list collection", "Index":"A ground term or number",
181            "Elem":"Term or variable"],
182        summary:"Append an Elem to the internal list identified by Index.",
183        desc:"Complexity O(1).",
184        %eg:"",
185        see_also:[append_list/3,prefix_element/3,prefix_list/3],
186        %fail_if:"",
187        exceptions:[
188            5:"LCOL is not a list collection.",
189            5:"Index is not a number or is out of range.",
190            5:"Index is not ground.",
191            1:"List identified by Index is closed."
192            ]
193    ]).
194:-export append_element/3.  
195:- mode(append_element(+,++,+)).
196append_element(LCOL, Index, Elem):-
197    check_lcol_exc(LCOL),
198    check_index_exc(LCOL, Index),
199    ensure_entry_exists_4_index(LCOL, Index, LTTerm),
200    check_open_tail_exc(LCOL, Index, LTTerm),
201    
202    inner_tail_get(LCOL,Index,LTTerm, [Elem|NewTail]),
203    inner_tail_set(LCOL,Index,LTTerm, NewTail),
204    
205    true.
206
207
208    
209:- comment(append_list/3, 
210    [
211        amode:(append_list(+,++,+) is det),
212        args:["LCOL":"A list collection", "Index":"A ground term or number",
213            "List":"A list of terms or variables"],
214        summary:"Append a List to the internal list identified by Index.",
215        desc:"Complexity O(|List|).",
216        %eg:"",
217        see_also:[append_element/3,prefix_element/3,prefix_list/3],
218       % fail_if:"",
219        exceptions:[
220            5:"LCOL is not a list collection.",
221            5:"Index is not a number or is out of range.",
222            5:"Index is not ground.",
223            1:"List identified by Index is closed."
224            ]
225    ]).
226:-export append_list/3.
227:- mode(append_list(+,++,+)).   
228append_list(LCOL, Index, List):-
229    check_lcol_exc(LCOL),
230    check_index_exc(LCOL, Index),
231    ensure_entry_exists_4_index(LCOL, Index,LTTerm),
232    check_open_tail_exc(LCOL, Index,LTTerm),
233    
234    inner_tail_get(LCOL,Index,LTTerm,OldTail),
235    
236    (foreach(Elem,List),
237     fromto(OldTail,[Elem|OldTailOut],OldTailOut,NewTail) do 
238        true
239    ),
240    
241    inner_tail_set(LCOL,Index,LTTerm,NewTail),
242
243    true.
244    
245:- comment(prefix_element/3, 
246    [
247        amode:(prefix_element(+,++,+) is det),
248        args:["LCOL":"A list collection", "Index":"A ground term or number",
249            "Elem":"Term or variable"],
250        summary:"Prefixes the internal list identified by Index with an Elem.",
251        desc:" Complexity O(1)",
252        %eg:"",
253        see_also:[append_element/3,append_list/3,prefix_list/3],
254       % fail_if:"",
255        exceptions:[
256            5:"LCOL is not a list collection.",
257            5:"Index is not a number or is out of range.",
258            5:"Index is not ground."
259            ]
260    ]). 
261:- export prefix_element/3.
262:- mode(prefix_element(+,++,+)).    
263prefix_element(LCOL, Index, Elem):-
264    prefix_list(LCOL, Index, [Elem]),
265    true.
266    
267
268:- comment(prefix_list/3, 
269    [
270        amode:(prefix_list(+,++,+) is det),
271        args:["LCOL":"A list collection", "Index":"A ground term or number",
272            "List":"A list of terms or variables"],
273        summary:"Prefixes the internal list identified by Index with a List.",
274        desc:"Complexity O(|List|).",
275        %eg:"",
276        see_also:[append_element/3,append_list/3,prefix_list/3],
277       % fail_if:"",
278        exceptions:[
279            5:"LCOL is not a list collection.",
280            5:"Index is not a number or is out of range.",
281            5:"Index is not ground."
282            ]
283    ]).     
284:-export prefix_list/3.
285:- mode(prefix_list(+,++,+)).   
286prefix_list(LCOL, Index, List):-
287    check_lcol_exc(LCOL),
288    check_index_exc(LCOL, Index),
289    ensure_entry_exists_4_index(LCOL, Index,LTTerm),
290
291    (foreach(Elem,List),
292     fromto(NewList,[Elem|NewListOut],NewListOut,NewListTail) do 
293        true
294    ),
295    
296    inner_list_get(LCOL,Index,LTTerm,OldList),
297    inner_list_set(LCOL,Index,LTTerm,NewList),
298    NewListTail = OldList,
299    true.
300    
301    
302:- comment(get_list/3, 
303    [
304        amode:(get_list(+,++,-) is det),
305        args:["LCOL":"A list collection", "Index":"A ground term or number",
306            "List":"A list of terms"],
307        summary:"Retrieves the list of elements identified by Index",
308        desc:"If the internal list identified by Index is open, the elements from the list are copied to a closed List and returned. The internal list remains open. Complexity O(|List|).
309            If the internal list identified by Index is closed, the internal list is returned immediately as List. Complexity O(1).",
310        %eg:"",
311        see_also:[terminate_all_lists/2,terminate_and_get_list/3],
312        %fail_if:"" ,
313        exceptions:[
314            5:"LCOL is not a list collection.",
315            5:"Index is not a number or is out of range.",
316            5:"Index is not ground."
317            ]
318    ]).     
319:-export get_list/3.    
320:- mode(get_list(+,++,-)).      
321get_list(LCOL, Index, List):-
322    check_lcol_exc(LCOL),
323    check_index_exc(LCOL, Index),
324    ensure_entry_exists_4_index(LCOL, Index,LTTerm),
325    
326    inner_list_get(LCOL,Index,LTTerm,OpenList),
327    inner_tail_get(LCOL,Index,LTTerm,OpenListTail),
328    
329    (OpenListTail==[] ->
330        %if the list is closed there is no need to copy the elements, just get list
331        List = OpenList
332    ;
333        (free(OpenList)->
334            %empty list
335            List=[]
336        
337        ;
338            (fromto(OpenList,[Elem|OpenListNext],OpenListOut,[]),
339             foreach(Elem,List),
340             param(OpenListTail) do
341                (OpenListNext\==OpenListTail->
342                    OpenListOut = OpenListNext
343                ;
344                    OpenListOut=[]
345                )
346            )
347        )
348    ),
349    true.
350    
351:- comment(terminate_and_get_list/3, 
352    [
353        amode:(terminate_and_get_list(+,++,-) is det),
354        args:["LCOL":"A list collection", "Index":"A ground term or number",
355            "List":"A list of terms"],
356        summary:"Retrieves the List of elements identified by Index",
357        desc:"Ensures that the internal List of elements identified by Index is terminated, and returns the internal List. Complexity O(1).",
358        %eg:"",
359        see_also:[get_list/3, terminate_all_lists/2,reinit/2],
360       % fail_if:"" ,
361        exceptions:[
362            5:"LCOL is not a list collection.",
363            5:"Index is not a number or is out of range.",
364            5:"Index is not ground."
365            ]
366    ]).     
367:-export terminate_and_get_list/3.
368:- mode(terminate_and_get_list(+,++,-)).    
369terminate_and_get_list(LCOL, Index, List):-
370    check_lcol_exc(LCOL),
371    check_index_exc(LCOL, Index),
372    ensure_entry_exists_4_index(LCOL, Index,LTTerm),
373    
374    inner_tail_get(LCOL,Index,LTTerm,[]),   
375    inner_list_get(LCOL,Index,LTTerm,List),
376    true.
377
378:- comment(terminate_all_lists/2, 
379    [
380        amode:(terminate_all_lists(+,-) is det),
381        args:["LCOL":"A list collection", "Indexes":"List of indexes"],
382        summary:"Terminates all internal lists in the collection, and gets the list of indexes",
383        desc:"Complexity O(ListCount).",
384        %eg:"",
385        see_also:[get_list/3,terminate_and_get_list/3,reinit/2,get_indexes/2],
386        %fail_if:"" 
387        exceptions:[
388            5:"LCOL is not a list collection."
389        ]
390    ]). 
391    
392    
393:-export terminate_all_lists/2.
394:- mode(terminate_all_lists(+,-)).  
395terminate_all_lists(LCOL,Indexes):-
396    check_lcol_exc(LCOL),
397    LCOL=list_collection{
398        type:hash, 
399        open_list_array:_OpenListArray,
400        tail_array     :_TailArray,
401        list_tail_hash :ListTailHash
402        },
403    !,
404    hash_list(ListTailHash,IndexesUnsorted,LTTermLi),
405    sort(IndexesUnsorted,Indexes),
406    (foreach(list_tail(_,[]),LTTermLi) do 
407        true
408    ),
409    true.
410
411terminate_all_lists(LCOL,Indexes):-
412    check_lcol_exc(LCOL),
413    LCOL=list_collection{
414        type:array(_Size), 
415        open_list_array:_OpenListArray,
416        tail_array     :TailArray,
417        list_tail_hash :_ListTailHash
418        },
419    !,
420    (foreacharg([],TailArray,Index),
421     foreach(Index,Indexes) do 
422        true
423    ),
424    true.
425    
426:- comment(get_indexes/2, 
427    [
428        amode:(get_indexes(+,-) is det),
429        args:["LCOL":"A list collection", "Indexes":"List of indexes"],
430        summary:"Retrieves the list of indexes",
431        desc:"Complexity O(ListCount).",
432        %eg:"",
433        see_also:[get_list/3,terminate_and_get_list/3,terminate_all_lists/2],
434        %fail_if:"" 
435        exceptions:[
436            5:"LCOL is not a list collection."
437        ]
438    ]). 
439    
440    
441:-export get_indexes/2.
442:- mode(get_indexes(+,-)).  
443get_indexes(LCOL,Indexes):-
444    check_lcol_exc(LCOL),
445    LCOL=list_collection{
446        type:hash, 
447        open_list_array:_OpenListArray,
448        tail_array     :_TailArray,
449        list_tail_hash :ListTailHash
450        },
451    !,
452    hash_list(ListTailHash,IndexesUnsorted,_LTTermLi),
453    sort(IndexesUnsorted,Indexes),
454    true.
455
456get_indexes(LCOL,Indexes):-
457    check_lcol_exc(LCOL),
458    LCOL=list_collection{
459        type:array(_Size), 
460        open_list_array:_OpenListArray,
461        tail_array     :TailArray,
462        list_tail_hash :_ListTailHash
463        },
464    !,
465    (foreacharg(_Tail,TailArray,Index),
466     foreach(Index,Indexes) do 
467        true
468    ),
469    true.
470
471
472
473    
474:- comment(reinit/2, 
475    [
476        amode:(reinit(+,++) is det),
477        args:["LCOL":"A list collection", "Index":"A ground term or number"],
478        summary:"Creates a new list identified by Index",
479        desc:"Discards the internal list of elements identified by Index, and replaces with a new list. Complexity O(1).",
480        %eg:"",
481        see_also:[terminate_all_lists/2,terminate_and_get_list/3],
482        %fail_if:"" ,
483        exceptions:[
484            5:"LCOL is not a list collection.",
485            5:"Index is not a number or is out of range.",
486            5:"Index is not ground."
487            ]
488    ]).     
489:-export reinit/2.
490:- mode(reinit(+,++)).
491reinit(LCOL, Index):-
492    check_lcol_exc(LCOL),
493    !,
494    check_index_exc(LCOL, Index),
495    ensure_entry_exists_4_index(LCOL, Index,LTTerm),
496    inner_list_set(LCOL,Index,LTTerm,ListTail),
497    inner_tail_set(LCOL,Index,LTTerm,ListTail),
498    true.
499    
500inner_tail_get(LCOL,Index,LTTerm,Tail):-
501    LCOL=list_collection{
502        type:Type, 
503        open_list_array:_OpenListArray,
504        tail_array     :TailArray,
505        list_tail_hash :_ListTailHash
506        },
507    (Type == hash, not free(LTTerm) ->
508        LTTerm = list_tail(_OpenList,Tail)
509    ;
510        (instance(Type,array(_Size))->
511            arg(Index,TailArray,Tail)
512        ;
513            exc_not_supported_type
514        )
515    ).
516    
517inner_tail_set(LCOL,Index,LTTerm,Tail):-
518    LCOL=list_collection{
519        type:Type, 
520        open_list_array:_OpenListArray,
521        tail_array     :TailArray,
522        list_tail_hash :_ListTailHash
523        },
524    (Type == hash,not free(LTTerm) ->
525        setarg(2,LTTerm,Tail)
526    ;
527        (instance(Type,array(_Size))->
528            setarg(Index,TailArray,Tail)
529        ;
530            exc_not_supported_type
531        )
532    ).
533inner_list_get(LCOL,Index,LTTerm,OpenList):-
534    LCOL=list_collection{
535        type:Type, 
536        open_list_array:OpenListArray,
537        tail_array     :_TailArray
538        },
539    (Type == hash,not free(LTTerm) ->
540        LTTerm= list_tail(OpenList,_Tail)
541    ;
542        (instance(Type,array(_Size))->
543            arg(Index,OpenListArray,OpenList)
544        ;
545            exc_not_supported_type
546        )
547    ).
548inner_list_set(LCOL,Index,LTTerm,OpenList):-
549    LCOL=list_collection{
550        type:Type, 
551        open_list_array:OpenListArray,
552        tail_array     :_TailArray,
553        list_tail_hash :_ListTailHash
554        },
555    (Type == hash,not free(LTTerm) ->
556        setarg(1,LTTerm,OpenList)
557    ;
558        (instance(Type,array(_Size))->
559            setarg(Index,OpenListArray,OpenList)
560        ;
561            exc_not_supported_type
562        )
563    ).
564
565    
566ensure_entry_exists_4_index(LCOL, Index,LTTerm):-
567    LCOL=list_collection{
568        type:hash, 
569        open_list_array:_OpenListArray,
570        tail_array     :_TailArray,
571        list_tail_hash :ListTailHash
572        },
573    !,
574    
575    (hash_contains(ListTailHash,Index)->
576        hash_get(ListTailHash,Index,LTTerm)
577    ;
578        functor(LTTerm,list_tail,2),
579        setarg(1,LTTerm,ListTail),
580        setarg(2,LTTerm,ListTail),
581        hash_add(ListTailHash,Index,LTTerm)
582    ),
583    true.   
584    
585ensure_entry_exists_4_index(LCOL, _Index,_LTTerm):-
586    LCOL=list_collection{
587        type:array(_Size), 
588        open_list_array:_OpenListArray,
589        tail_array     :_TailArray
590        },
591    !,
592    true.   
593
594check_index_exc(LCOL, Index):-  
595    LCOL=list_collection{
596        type:hash, 
597        open_list_array:_OpenListArray,
598        tail_array     :_TailArray,
599        list_tail_hash :_ListTailHash
600        },
601    (ground(Index)->
602        true
603    ;
604        exc_index_is_not_ground
605    ),!.
606    
607check_index_exc(LCOL, Index):-  
608    LCOL=list_collection{
609        type:array(Size), 
610        open_list_array:_OpenListArray,
611        tail_array     :_TailArray,
612        list_tail_hash :_ListTailHash
613        },
614    (number(Index),0<Index,Index=<Size->
615        true
616    ;
617        exc_index_is_not_a_num_or_out_of_range
618    ),!.
619    
620check_open_tail_exc(LCOL, Index,LTTerm):-
621    inner_tail_get(LCOL,Index,LTTerm,Tail),
622    (free(Tail)->
623        true
624    ;
625        exc_list_is_closed
626    ).
627    
628check_lcol_exc(LCOL):-
629    (instance(LCOL,list_collection{}),
630     LCOL=list_collection{
631        type:Type, 
632        open_list_array:_OpenListArray,
633        tail_array     :_TailArray,
634        list_tail_hash :_ListTailHash
635        },
636        ground(Type) ->
637        
638        true
639    ;
640        exc_lcol_is_not_a_proper_structure
641    ),
642    true.
643    
644exc_lcol_is_not_a_proper_structure:-
645    writeln(error,"LCOL is not a list collection."),
646    exit_block(lcol_exception).
647    
648exc_not_supported_type:-
649    writeln(error,"Not supported Type."),
650    exit_block(lcol_exception).
651    
652exc_list_is_closed:-
653    writeln(error,"List identified by Index is closed."),
654    exit_block(lcol_exception).
655    
656exc_index_is_not_a_num_or_out_of_range:-
657    writeln(error,"Index is not a number or is out of range."),
658    exit_block(lcol_exception).
659    
660exc_index_is_not_ground:-
661    writeln(error,"Index is not ground."),
662    exit_block(lcol_exception).
663
664
665%----------------------------------------------------------------------
666end_of_file.
667%----------------------------------------------------------------------
668
669%just for testing if documentation is generated properly
670lcol_test_generate_doc:-
671    get_flag(cwd, Cwd),
672    concat_string([Cwd,"list_collection.ecl"],File),
673    document:icompile(File),
674    document:eci_to_html("list_collection.eci", Cwd, ""),
675
676    true.
677
678%self testing of the library, the predicate has to be true
679lcol_self_test:-
680    block(
681        lcol_self_test_lcol_type(wrong_type)
682    ,lcol_exception, true),
683    
684    lcol_self_test_lcol_type(hash),
685    lcol_self_test_lcol_type(array(3)),
686    true.
687    
688lcol_self_test_lcol_type(LCOL_Type):-
689    %Create a Collection Of Lists 
690        list_collection:create(LCOL_Type,LCOL),
691    
692    %appending elements to List1 and List2
693        list_collection:append_element(LCOL, 1, list_1_elem_1),
694        list_collection:append_element(LCOL, 1, list_1_elem_2),
695        list_collection:append_element(LCOL, 2, list_2_elem_1),
696        list_collection:append_element(LCOL, 2, list_2_elem_2),
697    
698    %prefixig the List1 by an element
699        list_collection:prefix_element(LCOL, 1, list_1_pref_1),
700    %prefixing  the List2 by a list of elements
701        list_collection:prefix_list(LCOL,2,[list_2_pref_2,list_2_pref_1]),
702    %appending a list of alements to List3
703        list_collection:append_list(LCOL,3,[list_3_elem_1,list_3_elem_2]),
704    
705    %getting the List1 elements without closing the internal List1
706        get_list(LCOL,1,List1Elements),
707    List1Elements = [list_1_pref_1,list_1_elem_1,list_1_elem_2],
708
709    %still possible to append to List1 because it is not closed
710        list_collection:append_element(LCOL, 1, list_1_elem_3),
711    %terminating the List1 and retrieving it
712        terminate_and_get_list(LCOL, 1, List1),
713    List1 == [list_1_pref_1,list_1_elem_1,list_1_elem_2,list_1_elem_3],
714    block(
715        %the following would cause an exception because the List1 is closed 
716        (
717            list_collection:append_element(LCOL, 1, list_1_elem_4),
718            fail
719        )
720    ,lcol_exception, true),
721    %but it is possible to prefix the List1
722        list_collection:prefix_element(LCOL, 1, list_1_pref_2),
723        terminate_and_get_list(LCOL, 1, List1Prefixed),
724    List1Prefixed == [list_1_pref_2,list_1_pref_1,list_1_elem_1,list_1_elem_2,list_1_elem_3],
725    %internally List1 is discarded and a new List1  is created
726        reinit(LCOL,1),
727        get_list(LCOL,1,List1NewElements),
728    List1NewElements == [],
729        list_collection:append_element(LCOL, 1, list_1_elem_1),
730        terminate_and_get_list(LCOL, 1, List1New),
731    List1New == [list_1_elem_1],
732    block(
733        %the following would cause an exception but only for the array(3) LCOL
734        %because the index is out of range
735        (LCOL_Type == array(3) ->
736            terminate_and_get_list(LCOL, 4, _List4Treminated),
737            fail
738        ;true)
739        %for a hash LCOL it would not cause an exception,  
740        %a new list for index 4 would be created closed and returned
741    ,lcol_exception, true),
742    
743    %terminate all the lists
744        terminate_all_lists(LCOL,Indexes),
745    Indexes = [1,2,3],
746    %check the get_indexes
747        get_indexes(LCOL,Indexes),
748    %after all the lists are terminated get_list/3 does not need to copy the elements 
749    %to a new terminated list as above, it just gives back the internal lists  
750        get_list(LCOL, 2, List2Treminated),
751    List2Treminated == [list_2_pref_2,list_2_pref_1,list_2_elem_1,list_2_elem_2],
752        get_list(LCOL, 3, List3Treminated),
753    List3Treminated == [list_3_elem_1,list_3_elem_2],
754        
755    true.
756    
757%example
758lcol_example:-
759    lib(ic),
760    lib(ic_edge_finder),
761
762    ActivityList=[
763        act(4,7 ,2,machine_1),
764        act(3,4 ,1,machine_2 ),
765        act(2,4 ,2,removed),
766        act(7,10,1,machine_1),
767        act(6,15,3,machine_3)
768        % ...
769    ],
770    
771    %create a collection of activity lists for corresponding machines
772    list_collection:create(hash,LCOL_Machines),
773    
774    %sort the activities for machines
775    (foreach(Activity,ActivityList),
776     param(LCOL_Machines) do 
777        Activity=act(_Start,_End,_Resource,Machine),
778        (Machine \= removed ->
779            %add an activity to the list for the particular machine
780            list_collection:append_element(LCOL_Machines,Machine,Activity)
781        ;true)
782    ),
783    
784    %close the lists get the machine names
785    list_collection:terminate_all_lists(LCOL_Machines,Machines_Indexes),
786    
787    %for each machine
788    (foreach(Machines_Index,Machines_Indexes),
789     param(LCOL_Machines) do 
790        %Note that get_list/3 can be used even if the lists are not terminated but in such a case the operation
791        %is more time consuming, because all the list elements are copied to new closed list and then returned.
792        %Instead of closing all the lists at once it is also possible to use terminate_and_get_list/3 to ensure 
793        %that the list is closed.
794        
795        %get the activity list for the machine
796        list_collection:get_list(LCOL_Machines,Machines_Index,MActivityList),
797        
798        %create a collection for start,duration and resource variable lists
799        list_collection:create(array(3),LCOL_Start_Dur_Res),
800        
801        (foreach(MActivity,MActivityList),
802         param(LCOL_Start_Dur_Res) do
803         
804            MActivity=act(Start,End,Resource,_Machine),
805            ic:(Duration #= End - Start),
806            list_collection:append_element(LCOL_Start_Dur_Res, 1, Start),
807            list_collection:append_element(LCOL_Start_Dur_Res, 2, Duration),
808            list_collection:append_element(LCOL_Start_Dur_Res, 3, Resource)
809        ),
810        
811        %terminate the start,duration,resource lists
812        list_collection:terminate_all_lists(LCOL_Start_Dur_Res,_Indexes),
813        
814        %get the lists for a cumulative constraint
815        list_collection:get_list(LCOL_Start_Dur_Res, 1, StartList),
816        list_collection:get_list(LCOL_Start_Dur_Res, 2, DurationList),
817        list_collection:get_list(LCOL_Start_Dur_Res, 3, ResourceList),
818
819        %post the constraint
820        ic_edge_finder:cumulative(StartList, DurationList, ResourceList, 3)
821    ).