Constraint-Logic Object-Oriented Programming with Free Arrays
aa r X i v : . [ c s . P L ] A ug Constraint-Logic Object-Oriented Programmingwith Free Arrays
Jan C. Dageförde [0000 − − − and Herbert Kuchen ERCIS, Leonardo-Campus 3, 48149 Münster, Germany {dagefoerde,kuchen}@uni-muenster.de
Abstract.
Constraint-logic object-oriented programming provides a use-ful symbiosis between object-oriented programming and constraint-logicsearch. The ability to use logic variables, constraints, non-deterministicsearch, and object-oriented programming in an integrated way facilitatesthe combination of search-related program parts and other business logicin object-oriented applications. With this work we conceptualize array-typed logic variables (“free arrays”), thus completing the set of types thatlogic variables can assume in constraint-logic object-oriented program-ming. Free arrays exhibit interesting properties, such as indeterminatelengths and non-deterministic accesses to array elements.
Keywords: constraint-logic object-oriented programming · free arrays · non-deterministic element access · reference types. In constraint-logic object-oriented programming (CLOOP), one of the remainingmissing puzzle pieces is the ability to use logic variables in lieu of arrays. As anovel paradigm, CLOOP describes programming languages that add constraint-logic features on top of an object-oriented syntax. Most importantly, CLOOP of-fers logic variables, constraints, and encapsulated non-deterministic search, seam-lessly integrated with features from object-oriented programming. As a blueprintfor CLOOP languages, the Mu enster L ogic- I mperative Programming Language(Muli) is a Java-based language that has been successfully used in the generationof artificial neural networks [5], for search problems from the domain of logistics,and for classical search problems [4]. So far, logic variables in Muli can be usedinstead of variables of primitive types [4] or in place of objects [6]. Adding sup-port for array-type logic variables is another step on the path to achieving thefull potential of CLOOP. Potential opportunities are illustrated with the codesnippet in Listing 1. This snippet declares a logic array a , i. e., an array withan indeterminate number of elements and none of the elements are bound toa specific value. Moreover, it uses logic variables as indexes for accessing arrayelements, resulting in non-deterministic accesses.Prior to this work, Muli supported the use of arrays with fixed lengths andlogic variables as elements. In contrast, free arrays are logic variables with anarray type that are not bound to specific values, i. e., the entire array is treated J. C. Dageförde and H. Kuchen int i free ; int j free ; int [] a free ; if (a[i] > a[j]) a[i] = a[j] else ...; Listing 1: Snippet in which an array as well as the indexes for access are notbound.symbolically. In a free array, the individual elements as well as the number of theelements are not known. This work discusses the introduction of free arrays intoCLOOP and Muli. The paper starts off by providing a short introduction to theMuli programming language in Sect. 2. Afterwards, it presents the contributionsof this work: – Sect. 3 introduces and defines the concept of free arrays in a CLOOP lan-guage. – Sect. 4 discusses how to handle non-deterministic accesses to array elementswhen a free variable is used as the index. – These ideas are accompanied by an outline of how free arrays can be im-plemented in the runtime environment of Muli, specifying the handling ofsymbolic array expressions as well as the modified behaviour of array-relatedbytecode instructions (see Sect. 5).Sect. 6 presents related work, followed by a short summary in Sect. 7.
Our proposal is based on the constraint-logic object-oriented programming lan-guage Muli, which facilitates the integrated development of (business) applica-tions that combine deterministic program logic with non-deterministic search.Muli is based on Java 8 and adds features that enable constraint-logic search [4].A key feature of Muli is the ability to declare logic variables. Since logic variablesare not bound to a specific value, they are called free variables . A free variableis declared using the free keyword, as shown in the following example: int size free .Syntactically, declaring a free integer array is valid, too: int [] numbers free ,however, the behaviour of free arrays is not defined yet, so such a declarationwill currently result in an exception at runtime.Following its declaration, a variable can be used in place of other (regular)variables of a compatible type, for instance as part of a condition: if (size > 5) onstraint-Logic Object-Oriented Programming with Free Arrays 3 Solution
Muli. fail ();} else { return number*2; } } Listing 2: Search region that imposes constraints on a free variable number andreturns an expression as its solution.As size is not bound, the condition can be evaluated to true as well as to false , given appropriate circumstances. Upon evaluation of that condition, theexecuting runtime environment non-deterministically takes a decision and im-poses an appropriate constraint that supports and maintains this choice (forexample, size > 5 in order to evaluate the true -branch). To that end, theruntime environment leverages a constraint solver for two purposes: First, theconstraint solver is queried to check whether the constraint system of an appli-cation is consistent, thus avoiding the execution of branches whose constraintsystem cannot be solved. Second, the constraint solver is used to find specificvalues for free variables that respect the imposed constraints.Eventually, the runtime environment considers all alternative decisions. Theresult is a (conceptual) search tree, in which the inner nodes correspond to thepoints at which decisions can be taken, with one subtree per decision alterna-tive [7]. The eventual outcomes of execution (in particular, returned values andthrown exceptions) are the leaves of the tree. A returned value or a thrown ex-ception is a solution of non-deterministic search. In addition, Muli provides thefacility to explicitly cut execution branches that are not of interest by invokingthe
Muli. fail () method.The execution behaviour of Muli applications is, for the most part, deter-ministic and additionally provides encapsulated search . Application parts thatare intended to perform non-deterministic search need to be declared explicitlyin the form of methods or lambda expressions. These parts are called searchregions . In order to start search, a search region is passed to an encapsulatedsearch operator (e. g., Muli. getAllSolutions () ) that causes the runtime toperform search while collecting all found solutions. After execution finishes, thecollected solutions are returned to the invoking (deterministic) part of the ap-plication. Exemplarily, consider the search region presented in Listing 2. For alogic variable number it imposes constraints s. t. 0 ≤ number ≤ number*2 is returned and collected by Muli. getAllSolutions () ,i. e., the presented search region returns the numbers { , , , , , } . J. C. Dageförde and H. Kuchen
ArrayList
ArrayList<>(); for ( int i = 0; i < ( int )(Math.random()*1000); i++)list.add(i); int [] arr = new int [list.size()]; Listing 3: The length of an array is not necessarily known at compile time. Thisexample snippet determines the length at runtime instead.Muli applications are executed on the Münster Logic Virtual Machine (MLVM)[4]. The MLVM is a custom Java virtual machine with support for symbolic exe-cution of Java/Muli bytecode and non-deterministic execution of search regions.The MLVM represents non-deterministic execution in a search tree, in whichthe inner nodes are
Choice nodes (with one subtree per alternative decisionthat can be taken) and the leaf nodes are outcomes of search, i. e., solutions orfailures [7]. Executing a bytecode instruction with non-deterministic behaviourresults in the creation of a
Choice node that is added to the search tree. Forexample, executing an
If_icmpeq instruction (that corresponds to evaluatingan equality expression as part of an if condition) results in the creation of a Choice node with two subtrees, one per alternative outcome, provided that theresult of
If_icmpeq can take either value according to the constraints that havealready been imposed.
Muli relies on the symbolic execution of Java/Muli bytecode, i. e., symbolic ex-pressions are generated during the evaluation of expressions that cannot (yet) beevaluated to a single constant value. Therefore, adding support for free arraysimplies introducing symbolic arrays into the execution core of the MLVM.The length of arrays in Java (and, therefore, in Muli) does not need to beknown at compile time, as the legal code example in Listing 3 demonstrates:The number of elements that the array arr holds will become known at runtime.The length is arbitrary, provided that it can be represented by a positive (signed) int value [13]. As a consequence, a free array that is declared using
T[] arr free comprises – an unknown number of elements, so that arr.length is a free int variable n , where 0 ≤ n ≤ Integer.MAX_VALUE , and – one free variable of type T per element arr[i] with i < arr.length At least in theory, as the
Newarray bytecode instruction takes an int value forthe length. In practice, the actual maximum number of elements may be lower as itdepends on the available heap size on the executing machine.onstraint-Logic Object-Oriented Programming with Free Arrays 5
Treating the length of a free array arr as a free variable provides the benefitthat the length can be influenced by imposing constraints over arr.length ,i. e., by referring to the length as part of if conditions. Moreover, for an array T[] arr free the type of the individual array elements arr[i] depends onwhat T is: – If T is a primitive type, each element is a simple free variable of that type. – If T is an array type, the definition becomes recursive as each element is, inturn, a free array. – If T is a class or interface type, each element is a free object. Therefore, theactual type T’ of each element is T’ (cid:22) T , i. e., an element’s type is either T or a type that extends or implements T . We do not go into specifics on freeobjects, as they are not of particular relevance here. The interested readeris directed to [6] on that matter.Java requires regular arrays to be initialized either using an array creationexpression of the form T[] arr = new
T[n]; , resulting in an array arr with n elements of type T [10, § 15.10.1]; or an array initializer such as int [] arr ={1, 2}; , resulting in an integer array that holds exactly the specified elements[10, § 10.6]. For free arrays, this opens up alternative ways of declaring (andinitializing) a free array in Muli. Simple free variable declaration
First, following the syntax that is used todeclare any free variable,
T[] arr free declares a free array whose lengthand elements are indeterminate.
Modified array creation expression
Second,
T[] arr = new
T[n] free ; isa modified array creation expression that allows to specify a fixed length forthe array (unless n is free) while refraining from defining any of the arrayelements. Modified array initializer
Third, a modification of the array initializer ex-pression facilitates specifying the length as well as some array elements thatshall be free; e. g., int [] a = {1, free , 0}; would define an array witha fixed length with two constant elements and a free one at a[1] . Trivially,regardless of the chosen initializer, array elements can be modified after thearray has been initialized using explicit assignment. For example, a[1] = 2; can be used to replace an element (for example, a free variable) with a con-stant, and int i free ; a[1] = i; replaces the element at index 1 with afree int variable.These considerations facilitate the initialization and subsequent use of logicvariables that represent arrays or array elements. All three alternatives are usefuland should therefore be syntactically valid. For example, Listing 4 combines theinitialization of a free string array via a simple free variable declaration, followedby imposing a constraint over the array’s length (with Muli. fail () effectivelycutting the branch of execution in which that constraint would not be satisfied). J. C. Dageförde and H. Kuchen
String[] outputLines free ; if (outputLines.length > 5) { throw Muli. fail ();} else { // <...> } Listing 4: Limiting a free array’s length to at most five elements by imposing anappropriate constraint.
Reconsider the example snippet from a search region that is given in Listing 1:Free arrays become particularly interesting when array elements are accessedwithout specifying the exact index, i. e., with the index as a free variable (e. g., arr[i] where int i free ). In the comparison a[i] > a[j] , the array a aswell as the indexes for access are free variables. For a more complex example,consider the application depicted in Listing 5. It shows a simple sorting algorithm.The algorithm is not particularly efficient, but rather serves to show how freearrays can be used in a Muli application and demonstrates the use of otherMuli features as well. The general idea of Listing 5 is to find a permutationof the elements of b that leads to a sorted array a . In line 4 of Listing 5, afree array of indexes is introduced. In lines 9–11, the unbound elements of thisarray are used as indexes of the arrays usedIdx and a . The algorithm searchesfor a permutation s. t. the final array is sorted. Consequently, if an index isused more than once, the array idx does not represent a permutation and thecurrent branch of the search fails (line 9). Then, another branch is tried afterbacktracking. If the considered permutation does not lead to a sorted array, thecurrent branch of the search also fails, thus resulting in backtracking (line 13).The efficiency of the algorithm ultimately depends on the constraint solver onwhich the Muli runtime system relies. Currently, Muli offers using either JaCoP[12] or a custom SMT solver from the Münster Generator for Glass-box TestCases (Muggl [8]). Moreover, the MLVM provides a flexible solver componentthat facilitates the addition of alternative constraint solvers to the MLVM [3].Accessing an array with a free index is a non-deterministic operation, becausemore than one array element (or even a thrown runtime exception) could bethe result of the access operation. Subsequently, we present approaches thatcan be used for handling such non-deterministic accesses to arrays. This list ofapproaches is probably non-exhaustive as there may be additional alternatives.A first and simple approach would be to branch over all possible values forthe index i in case that there is an access to a[i] where i free . Effectively,this is the equivalent of a labeling operation, successively considering every arrayelement as the result of the access. Clearly, this would lead to a huge search spaceand it is hence not a reasonable option in most cases. onstraint-Logic Object-Oriented Programming with Free Arrays 71 class SimpleSort { public static double [] sort( double [] b) { int n = b.length; int [] idx free ; boolean [] usedIdx = new boolean [n]; for ( int i=0; i < n; i++) usedIdx[i] = false ; double [] a = new double [n]; for ( int i=0; i < n; i++) { if (usedIdx[idx[i]]) throw Muli. fail (); a[idx[i]] = b[i]; usedIdx[idx[i]] = true ; } for ( int i=0; i < n-1; i++) if (a[i] > a[i+1]) throw Muli. fail (); return a; } public static void main(String[] args) { double [] b = {42.0, 17.0, 56.3, 78.1, 5.9, 27.2}; Solution< double []> a = Muli. getOneSolution ( () -> sort(b) ); for ( int i=0; i< a.value.length; i++) { System.out.print(a.value[i]); } } }
Listing 5: Simple sorting algorithm that leverages free arrays.A second approach could store constraints that involve accesses to arrayelements with unbound indexes symbolically. In the example from Listing 1, thisimplies storing the expression a[i] < a[j] as a constraint. This approach iscomplex to handle. In our example, it would require that, after every change inthe remaining domains for i or j , we would have to check whether there are stillpossible values for i or j such that a[i] < a[j] can be satisfied. In the worstcase that means that we have to check the constraint for all remaining pairs ofvalues for i and j . As a consequence, this approach would be nearly as complexas the first one, the only difference being that the satisfiability check can stopas soon as values for i or j have been detected which satisfy the constraint.A third approach could delay the check of constraints with symbolic array ex-pressions until the involved indexes assume concrete, constant values. This wouldbe similar to the delayed processing of negation in Prolog [1]. However, in con-trast to Prolog, the ongoing computation would still continue. At the latest, theconstraint needs to be checked when leaving the encapsulated search space, pos-sibly after implicit labeling. Alternatively, the Muli application could explicitlydemand checking delayed constraints, and the MLVM could throw an exceptionindicating that there are still delayed constraints when trying to leave an en-capsulated search before a check. This approach is relatively easy to integrateinto the MLVM. However, a major disadvantage of this approach is that time iswasted for exploring parts of the search space which could have been excludedif we had checked the constraint earlier (and found it to be unsatisfiable). Even J. C. Dageförde and H. Kuchen worse, the corresponding computations could have caused external side-effectswhich should have never happened. This is a problem since external side-effectscannot be reverted on backtracking (e. g., file accesses or console output). Hence,they are discouraged in encapsulated search regions, especially in the case of de-layed constraints. Moreover, there is no guarantee that checking the constraintat the end is easier than checking it immediately: If no additional constraintsover i and j are encountered in further evaluation, i and j may still assume thesame values. Therefore, the delayed evaluation of the initial constraint is just ascomplicated as a strict evaluation.A fourth and last approach could entirely forbid constraint expressions thatinvolve unbound variables as array indexes. However, we feel that this approachis too restrictive. Moreover, it would not really provide new possibilities in Muli.Unfortunately, all approaches that we could think of have some disadvantages.After comparing the advantages and disadvantages, we plan to implement thesecond and third approach which seem most suitable to us. As a consequence,the Muli runtime is going to be able to allow developers to configure the systemin order to choose an approach that best suits their respective search problem.A quantitative evaluation will be able to show whether one approach is generallyfavourable over the other. Implementing the above considerations affects two areas of the runtime environ-ment: First, the solver component must be capable of dealing with constraintsover free arrays, i. e., it must be able to check a constraint system that com-prises such constraints for consistency as well as to find values for the involvedvariables. Second, the execution core requires a modified execution semantics ofarray-related bytecode instructions. Subsequently, we outline a concept for animplementation in the MLVM.
Accessing an array element using a free variable as an index, e. g. a[i] with i free , would yield a symbolic array expression (as described in Sect. 5.2).Using that as part of a condition, e. g., if (a[i] == 5) { s } else { s } causes the runtime environment to branch, thus creating a choice with twobranches and appropriate constraints as illustrated in Fig. 1.The way that a constraint involving symbolic array expressions (such as a[i] < a[j] from Listing 1) is modelled depends on the constraint solver. Thetwo solvers that are currently available in the MLVM do not provide nativesupport for array theories (cf. [16]), therefore the MLVM requires additionaleffort in order to emulate support for such constraints. Alternatively, the MLVMcan leverage a solver that features native support. For instance, native support isfeatured by the Z3 solver [15,16], which can be used as an incremental constraint onstraint-Logic Object-Oriented Programming with Free Arrays 9 if (a[i] == 5) s a[i] == 5 s a[i] != 5 Figure 1: Excerpt from a search tree, showing branch constraints that involve asymbolic expression for array element access, namely, a[i] .solver. For handling constraints, the MLVM implements a solver component that abstracts from the actual underlying solver. This is achieved by offering aunified interface for the definition of symbolic expressions and constraints. Usinga set of transformation methods, the defined constraints are transformed into asuitable representation for the respective solver that can then be queried fromthe MLVM using an adapter-pattern implementation. As a consequence, it ispossible to add support for symbolic array expressions to the unified interface asillustrated in Fig. 2. Based on that, we can then proceed with both alternatives,i. e., implement support for using Z3 as the solver (see Fig. 3), but also addtransformation routines for symbolic array expressions to the existing solveradapters.If a solver is used that does not natively provide support for array theories, weneed to implement a check whether there is at least one binding for the involvedindex variables for which a constraint involving a symbolic array expressionholds. This check is implemented in the constraint transformation method for aconstraint that involves symbolic array expressions. A generic approach iteratesover all index variables X ∈ Indexes , and substitute X for an allowed value fromthe domain of X . For example, for the symbolic array expression a[i] > a[j] this would result in the double for loop presented in Listing 6 that iteratesover all possible bindings for i and j and checks a simplified constraint witha constant index together with the active constraint system. If a binding isencountered that satisfies the constraint system, the check returns true becausea single binding suffices. Otherwise, if no such binding is encountered, the checkreturns false to indicate that the constraint system is not satisfiable.In order to support the third approach from Sect. 4, i. e. delayed constraintchecking, the above constraint transformations would only be performed as soonas labelling is required or as soon as one of the index variables has a singletondomain, making the index effectively constant.As an alternative to implementing the proposed emulation for checking con-straints that involve symbolic array expressions, we can integrate the Z3 solverinto the MLVM solver component in order to leverage its native support forsuch constraints. The required modifications to the solver component are illus-trated in Fig. 3, by implementing adapter classes and transformation classes that This is helpful as constraints are added (and removed) incrementally during encap-sulated search.0 J. C. Dageförde and H. Kuchen for(x in Domain(i)) {for (y in Domain(j)) {store.impose(a[x] > a[y]);if (store.isConsistent()) return true;else store.remove(a[x] > a[y]); } }// No binding satisfies the constraint system.return false;
Listing 6: Checking a symbolic array expression constraint by checking simplifiedconstraints that involve only concrete array elements.
ConstraintExpression ≪ interface ≫ Expression
Term
NumericVariable
BinaryOperation
ArrayArrayAccessNot Or NumericEqual ... (Adapted and extended from [2]) Figure 2: Augmenting the unified interface for the definition of constraints andexpressions in order to add symbolic array expressions (additions shaded in red).are similar in structure to the way how the JaCoP solver is integrated into theMLVM.The
Context type is the main class provided by the official Z3 Java bindings[18]. In order to use it from the MLVM, the
Z3SolverManager type serves asan adapter class, implementing the interface that is expected from an MLVMsolver manager and delegating calls to an instance of the
Context type appro-priately. The Z3 context instance needs to be configured to use incrementalsolving in order to properly handle the incremental addition and removal ofconstraints during encapsulated search. Moreover, the
Z3SolverManager relieson the
Z3Transformer in order to transform expressions and constraints spec-ified in the unified interface to a corresponding representation for the Z3 Javabindings. For instance, the Z3 transformer would transform a symbolic arrayexpression of the form a[i] == y (where a is a free integer array and i, y arefree integers) into the following commands for the Z3 solver: onstraint-Logic Object-Oriented Programming with Free Arrays 11 ≪ interface ≫ SolverManager + hasSolution(): boolean+ getSolution(): Solution+ addConstraint(ConstraintExpression ce)+ removeConstraint()
ConstraintExpression (see Fig. 2)
JaCoPSolverManagerZ3SolverManagerZ3Transformer + transformAndImpose(ConstraintExpression ce, Context ctx)
JaCoPTransformer + transformAndImpose(ConstraintExpression ce, Store store) org.jacop.core.Storecom.microsoft.z3.Context (Adapted and extended from [2])
Figure 3: Required modification to the solver component of the MLVM in orderto integrate the Z3 solver (additions shaded in red). (declare-const a (Array Int Int))(declare-const i Int)(declare-const y Int)( assert (= y (select a i)))
The Z3 solver has been successfully used in the context of glass-box test casegeneration, e. g. with the Pex tool [17], even of applications that use symbolicarrays and indices. Therefore, we assume that it will provide adequate perfor-mance (and perhaps a better performance compared to our emulation for othersolvers). Nevertheless, implementing all the above alternatives will facilitate anevaluation of their performance.
The MLVM executes Java bytecode. Implementing the above considerations re-quires modifications to the execution semantics of the following bytecode instruc-tions:
Newarray , Arraylength , Xaload , Xastore (where X is replaced with atype, e. g., Iastore to store an array element of type int [13].
Newarray is typically used in order to create an array on the heap. For thecase of a free array, this requires the creation of an internal representation ofthe free array, comprising a
NumericVariable for the length attribute (so thatthe length of a free array can become part of symbolic expressions) as well asan
ArrayList
Arraylength bytecode instruction returns the length of an array [13,§ 6.5]. If it is executed in the context of a free array, the instruction has to yieldthe symbolic representation of the free array’s length. As an exception to that, ifthe logic variable for the length is already bound to a single value,
Arraylength can return a constant.The modifications to the
Xaload and
Xastore instructions work identicallyregardless of their type X and result in (potentially) non-deterministic execu-tion. The Xaload instruction is the bytecode equivalent of accessing a singlearray element, e. g., a[i] , whereas
Xaload is the equivalent of assigning a valueto an array element, e. g., a[i] = x . Execution requires to make a distinctionbased on what is known about the length n of the involved free array (e. g., fromconstraints that have already been imposed on n ). For a[i] , if i is definitelywithin the range (0 ..n − i is outside that range,the execution (deterministically) results in throwing a runtime exception of thetype ArrayIndexOutOfBoundsException . In all other cases, execution resultsin the creation of a non-deterministic choice, distinguishing successful access(yielding a symbolic expression) and the error case (yielding an exception) as al-ternative outcomes. Each alternative results in imposing appropriate constraintsover i and n . Using backtracking, the MLVM will evaluate both alternativessuccessively. A first approach to a symbolic treatment of arrays dates back to McCarthy’s basic theory of arrays developed in 1962 [14]. It consists of just two axioms, onetelling that if a value v is assigned to a[i] then a[i] later on has this value v .The other axiom essentially says that changing a[i] does not affect any otherarray element. These axioms are clearly not enough for handling free arrays inMuli. McCarthy’s approach was extended to the combinatorial array logic by deMoura and Bjørner [16]. It is expressed by a couple of inference rules, which workon a more abstract level and do not address the processing of the search space.Nevertheless, these rules are among the theoretical foundations of Microsoft’sZ3 SMT solver [15]. Based on this solver, support for arrays was included intoMicrosoft’s test-case generator Pex [17] and into the symbolic code executionmechanism of NASA’s Java Pathfinder, a model checker and test-case generatorfor Java programs [9]. In order to achieve the latter, Fromherz et al. mainlychanged the semantics and treatment of the Xaload and
Xastore bytecodeinstructions of their symbolic variant of the Java virtual machine. Their changesto these instructions are similar to our intended modifications of the MLVM,with the exception that the MLVM has a more sophisticated mechanism forbacktracking and resuming an encapsulated search. The authors do not discuss onstraint-Logic Object-Oriented Programming with Free Arrays 13 approaches for dealing with the potentially huge search space caused by arrayconstraints.Also in the context of test-data generation, Korel [11] presented an array-handling approach which avoids the difficulties of free arrays and symbolic arrayindexes by resorting to a non-symbolic execution. Korel used a concrete evalua-tion in combination with dataflow analysis and so-called function minimizationin order to reduce the search space. This approach is not suitable for a CLOOPlanguage.All the mentioned approaches stem from the domains of test-case generationand model checking. To the best of our knowledge, there is no programminglanguage yet that offers free arrays with symbolic array indexes.
As a research-in-progress paper, this work presents approaches for the additionof free arrays to constraint-logic object-oriented programming, thus starting adiscussion that will eventually result in a prototypical implementation for theMuli programming language. The present paper discusses the characteristics andimplementation aspects of free arrays. In particular, we address the symbolictreatment of the array length and symbolic array indexes based on constraints.Moreover, we propose a syntax for the declaration and initialization of free ar-rays. In addition, we discuss ways of dealing with non-deterministic accesses toarray elements, proposing possible solutions to that end. The proposed conceptsfacilitate the use of logic arrays in the context of encapsulated, non-deterministicsearch that is interleaved with deterministic computations. Moreover, Muli al-lows using arbitrary search strategies in order to use symbolic computations thatinvolve arrays.Future work will implement support for free arrays into the MLVM basedon the approaches presented here. Moreover, the Z3 solver will be added to theMLVM as an alternative backend of the solver component so that its supportfor symbolic array expressions can be leveraged. This allows for an exhaustiveevaluation of the approaches in combination with different solvers.
References
1. Apt, K., Bol, R.: Logic programming and negation: A survey. J. Log.Program. , 9–71 (1994). https://doi.org/10.1016/0743-1066(94)90024-8,https://doi.org/10.1016/0743-1066(94)90024-82. Dageförde, J.C.: An Integrated Constraint-Logic and Object-Oriented Program-ming Language: The Münster Logic-Imperative Language. Dissertation, Universityof Münster (2020)3. Dageförde, J.C., Kuchen, H.: A Constraint-logic Object-oriented Language. In: Pro-ceedings of the 33rd ACM/SIGAPP Symposium On Applied Computing. pp. 1185–1194. ACM (2018). https://doi.org/10.1145/3167132.31672604 J. C. Dageförde and H. Kuchen4. Dageförde, J.C., Kuchen, H.: A Compiler and Virtual Machine for Constraint-logicObject-oriented Programming with Muli. Journal of Computer Languages , 63–78 (2019). https://doi.org/10.1016/j.cola.2019.05.0015. Dageförde, J.C., Kuchen, H.: Applications of Muli: Solving Practical Problems withConstraint-Logic Object-Oriented Programming. In: Lopez-Garcia, P., Giacobazzi,R., Gallagher, J. (eds.) Analysis, Verification and Transformation for DeclarativeProgramming and Intelligent Systems. LNCS, Springer (2020)6. Dageförde, J.C., Kuchen, H.: Free Objects in Constraint-logic Object-oriented Pro-gramming. In: Becker, J., et al. (eds.) Working Papers, European Research Centerfor Information Systems, vol. 32. Münster (2020)7. Dageförde, J.C., Teegen, F.: Structured Traversal of Search Trees in Constraint-logic Object-oriented Programming. In: Hofstedt, P., Abreu, S., John, U.,Kuchen, H., Seipel, D. (eds.) Declarative Programming and Knowledge Manage-ment, Lecture Notes in Artificial Intelligence, vol. 12057, pp. 199–214 (2020).https://doi.org/10.1007/978-3-030-46714-2_138. Ernsting, M., Majchrzak, T.A., Kuchen, H.: Dynamic Solution of LinearConstraints for Test Case Generation. In: 2012 Sixth International Sympo-sium on Theoretical Aspects of Software Engineering. pp. 271–274 (2012).https://doi.org/10.1109/TASE.2012.399. Fromherz, A., Luckow, K.S., Păsăreanu, C.S.: Symbolic Arrays in SymbolicPathFinder. ACM SIGSOFT Software Engineering Notes (6), 1–5 (2017).https://doi.org/10.1145/3011286.301129610. Gosling, J., Joy, B., Steele, G., Bracha, G., Buckley, A.: TheJava R (cid:13) Language Specification – Java SE 8 Edition (2015),https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf11. Korel, B.: Automated Software Test Data Generation. IEEE Transactions on Soft-ware Engineering (8), 870–879 (1990). https://doi.org/10.1109/32.5762412. Kuchcinski, K.: Constraints-driven scheduling and resource assignment. ACMTransactions on Design Automation of Electronic Systems (3), 355–383 (2003).https://doi.org/10.1145/785411.78541613. Lindholm, T., Yellin, F., Bracha, G., Buckley, A.: The Java R (cid:13)(cid:13)