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 ECLiPSe Constraint Logic Programming System. 15% The Initial Developer of the Original Code is Cisco Systems, Inc. 16% Portions created by the Initial Developer are 17% Copyright (C) 1996 - 2006 Cisco Systems, Inc. All Rights Reserved. 18% 19% Contributor(s): 20% 21% END LICENSE BLOCK 22% 23% @(#)umsarrays.tex 1.4 24% 25 26\chapter{Non-logical Storage and References} 27\label{chaparrays} 28%HEVEA\cutdef[1]{section} 29 30%---------------------------------------------------------------------- 31\section{Introduction} 32%---------------------------------------------------------------------- 33 34This chapter describes primitives that allow one to break the normal logic 35programming rules in two ways: 36\begin{itemize} 37\item information can be \emph{saved across logical failures} and backtracking; 38\item information can be accessed by \emph{naming} rather than by argument 39 passing. 40\end{itemize} 41Obviously, these facilities must be used with care and should always 42be encapsulated in an interface that provides logical semantics. 43 44ECLiPSe provides several facilities to store information across 45backtracking. The following table gives an overview. If at all 46possible, the handle-based facilities (bags, shelves and stores) should be 47preferred because they lead to cleaner, reentrant code (without global 48state) and reduce the risk of memory leaks. 49 50\vspace{2mm} 51\begin{center} 52\begin{tabular}{l|l l l} 53Facility & Type & Access & See \\ 54\hline 55shelves& array& by handle& shelf_create/2,3 \\ 56bags& unordered bag& by handle& bag_create/1 \\ 57stores& hash table& by handle& store_create/1 \\ 58anonymous records& ordered list& by handle& record_create/1 \\ 59named shelves& array& by name& shelf/2 \\ 60named stores& hash table& by name& store/1 \\ 61non-logical variables& single cell& by name& variable/1 \\ 62non-logical arrays& array& by name& array/1,2 \\ 63records& ordered list& by name& record/1,2 \\ 64dynamic predicates& ordered list& by name& dynamic/1, assert/1 \\ 65\end{tabular} 66\end{center} 67\vspace{2mm} 68 69\index{reference} 70\index{global reference} 71The other facility described here, \emph{Global References}, does not store 72information across failure, but provides a means to give a name to 73an otherwise logical data structure. See section \ref{globrefs}. 74 75 76%---------------------------------------------------------------------- 77\section{Bags} 78%---------------------------------------------------------------------- 79 80A bag is an anonymous object which can be used to store 81information across failures. 82A bag is unordered and untyped. Any {\eclipse} term can be stored in a bag. 83Bags are referred to by a handle. 84An empty bag is created using 85\bipref{bag_create/1}{../bips/kernel/storage/bag_create-1.html}, 86data is stored in the bag by invoking 87\bipref{bag_enter/2}{../bips/kernel/storage/bag_enter-2.html}, 88and the stored data can be retrieved as a list with 89\bipref{bag_retrieve/2}{../bips/kernel/storage/bag_retrieve-2.html} or 90\bipref{bag_dissolve/2}{../bips/kernel/storage/bag_dissolve-2.html}. 91 92A typical application is the 93implementation of the \predspec{findall/3} predicate or similar functionality. 94As opposed to the use of \predspec{record/2} or \predspec{assert/1}, the 95solution using 96bags is more efficient, more robust, and trivially reentrant. 97\begin{verbatim} 98 simple_findall(Goal, Solutions) :- 99 bag_create(Bag), 100 ( 101 call(Goal), 102 bag_enter(Bag, Goal), 103 fail 104 ; 105 true 106 ), 107 bag_dissolve(Bag, Solutions). 108\end{verbatim} 109 110 111%---------------------------------------------------------------------- 112\section{Shelves} 113%---------------------------------------------------------------------- 114 115A \defnotion{shelf} is an anonymous object which can be used to store information 116across failures. A typical application is counting of solutions, 117keeping track of the best solution, aggregating information across 118multiple solutions, etc. 119 120A shelf is an object with multiple slots whose contents survive 121backtracking. The content of each slot can be set and retrieved 122individually, or the whole shelf can be retrieved as a term. 123 124Shelves are referred to by handle, not by name, so they make it easy 125to write robust, reentrant code. A shelf disappears when the system 126backtracks over its creation, when the shelf handle gets garbage 127collected, or when it is explicitly destroyed. 128 129A shelf is initialized using 130\bipref{shelf_create/2}{../bips/kernel/storage/shelf_create-2.html} or 131\bipref{shelf_create/3}{../bips/kernel/storage/shelf_create-3.html}. 132Data is stored in the slots (or the shelf as a whole) with 133\bipref{shelf_set/3}{../bips/kernel/storage/shelf_set-3.html} 134and retrieved with 135\bipref{shelf_get/3}{../bips/kernel/storage/shelf_get-3.html}. 136 137Example: Counting how many solutions a goal has: 138\begin{verbatim} 139 count_solutions(Goal, Total) :- 140 shelf_create(count(0), Shelf), 141 ( 142 call(Goal), 143 shelf_get(Shelf, 1, Old), 144 New is Old + 1, 145 shelf_set(Shelf, 1, New), 146 fail 147 ; 148 shelf_get(Shelf, 1, Total) 149 ). 150\end{verbatim} 151In this particular example, we could have used 152\bipref{shelf_inc/2}{../bips/kernel/storage/shelf_inc-2.html} to 153increment the counter. 154 155 156%---------------------------------------------------------------------- 157\section{Stores} 158%---------------------------------------------------------------------- 159 160 161\index{hash table} 162A \defnotion{store} is an anonymous object which can be used to store information 163across failures. A typical application is aggregating information across 164multiple solutions. Note that, if it is not necessary to save information 165across backtracking, the use of the 166\bipref{library(hash)}{../bips/lib/hash/index.html} 167is more appropriate and efficient than the facilities described here. 168 169A store is a hash table which can store arbitrary terms under arbitrary 170ground keys. Modifications of a store, as well as the entries within it, 171survive backtracking. The basic operations on stores are entering and 172looking up information under a key, or retrieving the store contents as 173a whole. 174 175Stores come in two flavours: anonymous stores are created with 176\bipref{store_create/1}{../bips/kernel/storage/store_create-1.html} 177and referred to by handle, while named stores are created with a 178\bipref{store/ 1}{../bips/kernel/storage/store-1.html} 179declaration and referred to by their name within a module. 180If possible, anonymous stores should be preferred because they make it 181easier to write robust, reentrant code. For example, an anonymous store 182automatically disappears when the system backtracks over its creation, 183or when the store handle gets garbage collected. Named stores, on the 184other hand, must be explicitly destroyed in order to free the 185associated memory. 186 187Data is entered into a store using 188\bipref{store_set/3}{../bips/kernel/storage/store_set-3.html} 189and retrieved using 190\bipref{store_get/3}{../bips/kernel/storage/store_get-3.html}. 191It is also possible to retrieve information: either all keys with 192\bipref{stored_keys/2}{../bips/kernel/storage/stored_keys-2.html}, 193or the full contents of the table with 194\bipref{stored_keys_and_values/2}{../bips/kernel/storage/stored_keys_and_values-2.html}. 195Entries can be deleted via 196\bipref{store_delete/2}{../bips/kernel/storage/store_delete-2.html} or 197\bipref{store_erase/1}{../bips/kernel/storage/store_erase-1.html}. 198 199\index{memoization} 200\index{Fibonacci} 201\indextt{fib/2} 202A typical use of stores is for the implementation of memoization. 203The following is an implementation of the Fibonacci function, which 204uses a store to remember previously computed results. 205It consists of the declaration of a named store, a wrapper predicate 206\predspec{fib/2} that handles storage and lookup of results, and the standard 207recursive definition \predspec{fib_naive/2}: 208\begin{verbatim} 209 :- local store(fib). 210 211 fib(N, F) :- 212 ( store_get(fib, N, FN) -> 213 F = FN % use a stored result 214 ; 215 fib_naive(N, F), 216 store_set(fib, N, F) % store computed result 217 ). 218 219 fib_naive(0, 0). 220 fib_naive(1, 1). 221 fib_naive(N, F) :- 222 N1 is N-1, N2 is N-2, 223 fib(N1, F1), fib(N2, F2), 224 F is F1 + F2. 225\end{verbatim} 226Using this definition, large function values can be efficiently computed: 227\begin{verbatim} 228 ?- fib(300, F). 229 F = 222232244629420445529739893461909967206666939096499764990979600 230 Yes (0.00s cpu) 231\end{verbatim} 232 233 234 235The next example shows the use of an anonymous store, for computing 236how many solutions of each kind a goal has. 237The store is used to maintain counter values, using the 238solution term as the key to distinguish the different counters: 239\begin{verbatim} 240 solutions_profile(Sol, Goal, Profile) :- 241 store_create(Store), 242 ( 243 call(Goal), 244 store_inc(Store, Sol), 245 fail 246 ; 247 stored_keys_and_values(Store, Profile) 248 ). 249\end{verbatim} 250Running this code produces for example: 251\begin{verbatim} 252 ?- solutions_profile(X, member(X, [a, b, c, b, a, b]), R). 253 X = X 254 R = [a - 2, b - 3, c - 1] 255 Yes (0.00s cpu) 256\end{verbatim} 257 258 259%---------------------------------------------------------------------- 260\section{Non-logical Variables} 261%---------------------------------------------------------------------- 262\index{non-logical variable}\index{variable!non-logical} 263Non-logical variables in {\eclipse} are a means of storing a copy 264of a Prolog term under a name (an atom). 265The atom is the \defnotionni{name} and the associated 266term is the \defnotionni{value} of the non-logical variable. 267This term may be of any form, whether an integer or a huge compound 268structure. 269Note that the associated term is being copied and so if it is not ground, 270the retrieved term is not strictly identical to the stored one 271but is a \emph{variant} of it\footnote{% 272 Though this feature could be used to make a copy of a term with new variables, 273 it is cleaner and more efficient to use 274 \bipref{copy_term/2}{../bips/kernel/termmanip/copy_term-2.html} for that 275 purpose}. 276There are two fundamental operations that can be performed on a non-logical 277variable: 278setting the variable (giving it a value), and referencing the variable 279(finding the value currently associated with it). 280 281The value of a non-logical variable is set using the 282\bipref{setval/2}{../bips/kernel/storage/setval-2.html} 283predicate. 284This has the format 285\begin{quote} 286\preddef{setval(\pattern{Name},~\pattern{Value})}\indextt{setval/2} 287\end{quote} 288For instance, the goal 289\begin{quote} 290\begin{verbatim} 291setval(firm, 3) 292\end{verbatim} 293\end{quote} 294gives the non-logical variable \about{firm} the value 3. 295The value of a non-logical variable is retrieved using the 296\bipref{getval/2}{../bips/kernel/storage/getval-2.html} 297predicate. 298 299The goal 300\begin{quote} 301\begin{verbatim} 302getval(firm, X) 303\end{verbatim} 304\end{quote} 305will unify \about{X} to 306the value of the non-logical variable \about{firm}, which has been previously 307set by 308\bipref{setval/2}{../bips/kernel/storage/setval-2.html}. 309If no value has been previously set, the call raises an exception. 310If the value of a non-logical variable is an integer, the predicates 311\bipref{incval/1}{../bips/kernel/storage/incval-1.html} 312and \bipref{decval/1}{../bips/kernel/storage/decval-1.html} 313may be used toincrement and decrement the value of the 314variable, respectively. 315The predicates \bipref{incval/1}{../bips/kernel/storage/incval-1.html} and 316\bipref{decval/1}{../bips/kernel/storage/decval-1.html} may be used e.g., in a 317failure-driven loop to provide 318an incremental count across failures as in the example: 319\begin{quote} 320\begin{verbatim} 321count_solutions(Goal, _) :- 322 setval(count, 0), 323 call(Goal), 324 incval(count), 325 fail. 326count_solutions(_, N) :- 327 getval(count, N). 328\end{verbatim} 329\end{quote} 330However, code like this should be used carefully. 331Apart from being a non-logical feature, it also causes the code to be 332not reentrant. That is, if \predspec{count_solutions/2} were called recursively 333from 334inside \about{Goal}, this would smash the counter and yield incorrect 335results.\footnote{% 336 A similar problem can occur when the counter is used by an interrupt handler.} 337 338The visibility of a non-logical variable is local to the module 339where it is first set. It is good style to declare them using 340\bipref{local/1}{../bips/kernel/modules/local-1.html} 341\bipref{variable/1}{../bips/kernel/storage/variable-1.html} 342declarations. For example, in the above example one should use 343\begin{quote} 344\begin{verbatim} 345:- local variable(count). 346\end{verbatim} 347\end{quote} 348If it is necessary to access the value of a variable in other modules, 349exported access predicates should be provided. 350 351 352%---------------------------------------------------------------------- 353\section{Non-logical Arrays} 354%---------------------------------------------------------------------- 355\index{non-logical array}\index{array!non-logical} 356Non-logical arrays are a generalisation of the non-logical variable, capable of 357storing 358multiple values. 359An array has to be declared in advance. 360It has a fixed number of dimensions and a fixed size in each dimension. 361Arrays in {\eclipse} are managed solely by special predicates. 362In these predicates, arrays are represented by compound terms, e.g., 363\notation{matrix(5, 8)} 364where \about{matrix} is the name of the array, the arity of 2 specifies 365the number of dimensions, and the integers 5 and 8 specify the size 366in each dimension. The number of elements this array can hold is 367thus 5*8 = 40. 368The elements of this array can be addressed from \notation{matrix(0, 0)} 369up to \notation{matrix(4, 7)}. 370 371An array must be explicitly created using a 372\bipref{local/1}{../bips/kernel/modules/local-1.html} 373\bipref{array/1}{../bips/kernel/storage/array-1.html} 374declaration, e.g., 375\begin{quote} 376\begin{verbatim} 377:- local array(matrix(5, 8)). 378\end{verbatim} 379\end{quote} 380The array is only accessible from within the module where it was declared. 381The declaration will create a two-dimensional, 5-by-8 array with 40 elements 382\notation{matrix(0, 0)} to \notation{matrix(4, 7)}. 383Arrays can be erased using the predicate 384\bipref{erase_array/1}{../bips/kernel/storage/erase_array-1.html}, 385e.g., 386\begin{quote} 387\begin{verbatim} 388erase_array(matrix/2). 389\end{verbatim} 390\end{quote} 391 392The value of an element of the array is set using the 393\bipref{setval/2}{../bips/kernel/storage/setval-2.html} 394predicate. The first argument of 395\bipref{setval/2}{../bips/kernel/storage/setval-2.html} specifies the element 396which is 397to be set, the second specifies the value to assign to it. 398The goal 399\begin{quote} 400\begin{verbatim} 401setval(matrix(3, 2), plato) 402\end{verbatim} 403\end{quote} 404sets the value 405of element (3, 2) of array \about{matrix} to the atom \about{plato}. 406Similarly, values of array elements are retrieved by use of the 407\bipref{getval/2}{../bips/kernel/storage/getval-2.html} 408predicate. The first argument of 409\bipref{getval/2}{../bips/kernel/storage/getval-2.html} specifies the element to 410be 411referenced, the second is unified with the value of that element. 412Thus if the value of \notation{matrix(3, 2)} had been set as above, the goal 413\begin{quote} 414\begin{verbatim} 415getval(matrix(3, 2), Val) 416\end{verbatim} 417\end{quote} 418would unify \about{Val} with the atom \about{plato}. 419Similarly to non-logical variables, the value of integer array elements 420can be updated using \bipref{incval/1}{../bips/kernel/storage/incval-1.html} and 421\bipref{decval/1}{../bips/kernel/storage/decval-1.html}. 422 423It is possible to declare arrays whose elements are 424constrained to belong to certain types. This allows {\eclipse} to increase 425time and space efficiency of array element manipulation. 426Such an array is created for instance by the predicate 427\begin{quote} 428\begin{verbatim} 429:- local array(primes(100),integer). 430\end{verbatim} 431\end{quote} 432The second argument specifies the type of the elements of the array. 433It takes as value an atom from the 434list {\tt float} (for floating point numbers), 435{\tt integer} (for integers), {\tt byte} (an integer modulo 256), 436or {\tt prolog} (any Prolog term---the resulting array is the 437same as if no type was specified). 438When a typed array is created, the value of each element is initialized to zero 439in the case of {\tt byte}, {\tt integer} and {\tt float}, and to 440an uninstantiated variable in the case of {\tt prolog}. 441Whenever a typed array element is set, type checking is carried out. 442 443As an example of the use of a typed array, consider the following goal, which 444creates a 3-by-3 matrix describing a 90 degree rotation about the x-axis of 445a Cartesian coordinate system. 446\begin{quote} 447\begin{verbatim} 448:- local array(rotate(3, 3), integer). 449:- setval(rotate(0, 0), 1), 450 setval(rotate(1, 2), -1), 451 setval(rotate(2, 1), 1). 452\end{verbatim} 453\end{quote} 454(The other elements of the above array are automatically initialized to zero). 455 456The predicate 457\bipref{current_array/2}{../bips/kernel/storage/current_array-2.html} 458is provided to find the size, type and visibility of defined arrays. 459of the array and its type to be found: 460\begin{quote} 461\preddef{current_array(\pattern{Array},~\pattern{Props})} 462\end{quote} 463where \about{Array} is the array specification as in the declaration (but it 464may be uninstantiated or partially instantiated), and \about{Props} is 465a list indicating the array's type and visibility. 466Non-logical variables are also returned: \about{Array} is then an atom, and 467the type is \notation{prolog}. 468\begin{quote} 469\begin{verbatim} 470[eclipse 1]: local(array(pair(2))), 471 setval(count, 3), 472 local(array(count(3,4,5), integer)). 473 474yes. 475[eclipse 2]: current_array(Array, Props). 476 477Array = pair(2) 478Props = [prolog, local] More? (;) 479 480Array = count 481Props = [prolog, local] More? (;) 482 483Array = count(3, 4, 5) 484Props = [integer, local] More? (;) 485 486no (more) solution. 487[eclipse 3]: current_array(count(X,Y,Z), _). 488 489X = 3 490Y = 4 491Z = 5 492yes. 493\end{verbatim} 494\end{quote} 495 496 497%---------------------------------------------------------------------- 498\section{Global References} 499%---------------------------------------------------------------------- 500\label{globrefs} 501Terms stored in non-logical variables and arrays are copies of the 502\bipref{setval/2}{../bips/kernel/storage/setval-2.html} arguments, 503and the terms obtained by 504\bipref{getval/2}{../bips/kernel/storage/getval-2.html} are thus not identical 505to the original terms, in particular their variables are different. 506Sometimes it is necessary to be able 507to access the original term with its variables, i.e., to have 508\emph{global variables} in the meaning of conventional programming 509languages. 510A typical example is global state that a set of predicates wants to 511share without having to pass an argument pair through all the 512predicate invocations. 513 514{\eclipse} offers the possibility to store references to general terms 515and to access them even inside predicates that have no common variables 516with the predicate that has stored them. 517They are stored in so-called \defnotioni{references}{reference}.% 518\index{global reference} 519For example, 520\begin{quote} 521\begin{verbatim} 522:- local reference(p). 523\end{verbatim} 524\end{quote} 525or 526\begin{quote} 527\begin{verbatim} 528:- local reference(p, 0). 529\end{verbatim} 530\end{quote} 531creates a named reference \about{p} (with an initial value of 0) 532which can be used to store references to terms. 533This reference is accessed and modified in the same way as non-logical 534variables, 535with \bipref{setval/2}{../bips/kernel/storage/setval-2.html} 536and \bipref{getval/2}{../bips/kernel/storage/getval-2.html}, 537but the following points are different for references: 538\begin{itemize} 539\item the accessed term is identical to the stored term (with its current 540substitutions): 541\begin{quote} 542\begin{verbatim} 543[eclipse 1]: local reference(a), variable(b). 544 545yes. 546[eclipse 2]: Term = p(X), setval(a, Term), getval(a, Y), Y == Term. 547X = X 548Y = p(X) 549Term = p(X) 550yes. 551[eclipse 3]: Term = p(X), setval(b, Term), getval(b, Y), Y == Term. 552 553no (more) solution. 554\end{verbatim} 555\end{quote} 556 557\item the modifications are backtrackable, when the execution fails 558over the \bipref{setval/2}{../bips/kernel/storage/setval-2.html} call, the 559previous value of the global reference is restored 560 561\begin{quote} 562\begin{verbatim} 563[eclipse 4]: setval(a, 1), (setval(a, 2), getval(a, X); getval(a, Y)). 564X = 2 565Y = Y More? (;) 566 567X = X 568Y = 1 569\end{verbatim} 570\end{quote} 571 572\item there are no arrays of references, but the same effect can be 573achieved by storing a structure in a reference and using the structure's 574arguments. The arguments can then be accessed and modified using 575\bipref{arg/3}{../bips/kernel/termmanip/arg-3.html} and 576\bipref{setarg/3}{../bips/kernel/termmanip/setarg-3.html} respectively. 577\end{itemize} 578 579%There is only a limited number of references available and their 580%use should be considered very carefully. 581The use of references should be considered carefully. 582Their overuse can lead to programs which are 583difficult to understand and difficult to optimize. 584Typical applications use at most a single reference per module, 585for example to hold state that would otherwise have to be passed 586via additional arguments through many predicate invocations. 587 588%HEVEA\cutend 589