\documentclass{article} \usepackage{axiom} \begin{document} \title{Provisos: A Programming Extension for \\ Conditional Computational Algebra} \author{Timothy Daly} \maketitle \begin{abstract} Provisos are a method of representing conditional information during a computation. This paper motivates the need for provisos and examines the changes necessary to a computer algebra system to add a proviso mechanism. In particular, we consider transparency and post-facto extensions as mechansims for extending classes in an object oriented system. We consider the classes of proviso information to maintain during a computation. We consider the computation of the proviso information and how the proviso information affects the results obtained. Finally we raise and examine the topic of an algebra of provisos. \end{abstract} \eject \tableofcontents \eject \section{Introduction} \subsection{What is the motivation?} If we examine the mathematics literature there are many instances of formulas where we find the information about the formula structured: \begin{verbatim} Given these assumptions then we have the formula provided these restrictions \end{verbatim} \noindent The "given" portion of the equation is usually embedded as text in the paragraph preceeding the formula. This information includes many assumptions that restrict the domain of interest, such as: \begin{verbatim} assume x is real ... \end{verbatim} \noindent The formula portion states the conclusion the author wishes to draw. The "provided" portion of the statement contains certain restrictions that limit the applicability of the formula or constrain the truth of the answer. These generally are of the form: \begin{verbatim} x = 0 \end{verbatim} \noindent if the restriction can be stated as a formula or they are written in paragraph form if there is no notational conventions for writing the restrictions. As a particular example we have: \begin{verbatim} Given x is real then the integral of 1/x is abs(log(x)) provided x != 0 \end{verbatim} \noindent We will refer to this example as "the integration example" throughout this paper.. Most computer algebra systems (hereafter CAS) attack this problem by simply ignoring it. This is somewhat reasonable for single computations where it leaves open the potential for misleading the user but still giving reasonable answers. The problem arises when the results are used in further computations. If, in further computations, the domain of interest includes places where the assumptions or restrictions make the formula invalid the results can be completely wrong. So we would like to build a system that carries this auxillary information with a computation and modifes the results based on this information. We call the auxillary information a {\bf proviso}. The class of all such things is called the Proviso domain. In this paper we will examine other approaches to the problem and then present the approach we have taken. \section{What is the problem?} \begin{list}{} \item global info reasoning across scopes/levels? \item (depth issue) \item cross-branch information? \item (breadth issue) \item fundamental issues \end{list} \subsection{Representation} How provisos are represented affects the ability to reason with the information Prior systems have implemented the representation as a global table of facts. We feel that proviso information can occur at many levels in a computation and that this information should be scoped relative to its point of application. Thus, each object in the system should carry its own proviso information. \subsection{Control} A single computation can generate multiple answers. This implies that the computation must be carried on for each branch and that the state of each branch must be maintained separately. \subsubsection{Of} \begin{list}{} \item What information should be kept in a proviso? (meromorphic?) \item What should be added? (global/local) \item When can it be removed? (invalidated?) \item When can it be ignored? (matrix inversion) \item How do we combine this information (combinatorial explosion) \item How do we compute this information (algebra of provisos) \end{list} \subsubsection{With} \begin{list}{} \item How should the proviso information interact with a computation? \end{list} \section{Representation: What is the language issue?} \subsection{Transparency} In an Axiom system every object has a type which defines the operations that can be performed on the object. The operations are exported by the class, referred to as a "domain" in Axiom. To see the problem with Axiom's type system, which is typical of most type systems, look at an operation from the type Polynomial. Consider additions, which is an operation with the signature: \begin{verbatim} +(a:Symbol, b:Symbol) : Polynomial \end{verbatim} that is, '$+$' takes a symbol and a symbol and symbolically adds them, returning a polynomial. The simple transformation that allows one to produce an object of type Proviso would be to create a domain called PROVISO and introduce an operation called ``new'' that takes a symbol and returns a new PROVISO object, thus: \begin{verbatim} Proviso: Domain with { new:Symbol -> % +: (Symbol, Symbol) -> Polynomial; assume: (Symbol, Condition) -> %; } \end{verbatim} \noindent then one could create objects of type PROVISO and operation on them with the '$+$' operation from the PROVISO domain, thus: \begin{verbatim} x:=new('x) y:=new('y) z:=x+y \end{verbatim} \noindent this approach would work but has the fundamental flaw that all of the operations we wish to perform must be exported from the domain PROVISO. Since provisos are intended to be a wrapper around other types we get an explosion of the number of operations we need to export from this domain. Essentially our type system collapses into one type, PROVISO. This is unacceptable. Ideally it should be possible to construct a wrapper type that has a property we refer to as "transparency". Transparency would allow a type to be extended in both functions available and representation. This extended type would behave like the original type in all normal contexts. That is, unless an operation is ``proviso-aware'' there is no need for another operation to be aware that they are operating with a proviso. Such a transparent domain would act exactly as a member of its component domain except for proviso-related operations. Thus, declaring a symbol to be a proviso object would have the effect of adding another slot in its representation to carry the proviso information. This is similar to the notion of a variant record in a strongly typed Pascal system. \subsection{Post-Facto Extensions} In Axiom it is possible to extend an existing domain to add operations to the domain. Thus, one would write the following code: \begin{verbatim} extend Polynomial: Domain with { assume: (Symbol, Condition) -> % } \noindent which has the effect of adding the additional function "assume" to an existing domain Polynomial. As far as we are aware, post-facto extensions of classes only exists in the Axiom system. Even so, this mechanism is not sufficient to support provisos because, while extensions can add functions, they do not change the representation of the object. Provisos require that the object representation be extended to include space for the proviso information. Thus, in lieu of a full extension facility the approach we've take is to rewrite the domains that are proviso-aware to carry the extra proviso information as part of their data structure. The down side of this approach is that additional memory will be allocated even if provisos are never used. In the research prototype of the system this is considered a reasonable tradeoff. \subsection{Of: How do we compute proviso information?} There is an issue about global versus local information. Consider an apparently simple case. It seems obvious that every time a division is performed one should add a proviso that the denominator of the returned ratio should not be zero. This a a fairly straightforward change to the system. We need only change the division routine to add this information. Consider the effect of this change. When we do a division we now know that we made an assumption that the denominator cannot be zero. Thus, we can check this condition later and avoid situations that violate this assumption. However, if we consider the domain of matrix computations we find that there are two algorithms that will compute the determinant of a matrix. One, gaussian elimination, uses division in the computation. Using this algorithm the final result will contain restrictions on the values of various variables. However, if we use a different algorithm that is division free (?ref) then we will get the same result but without the restrictions. There are several solutions to this problem. First, we could have a division routine check for a special proviso property, say 'zero-free' which means that the division routine should not add its assumption.. This places global knowledge within the division routine. Of course, if the range of the variables is known never to include zero then the division routine would not add the provisos in the first place. In general, it seems to be unreasonable for the low level division routing to know higher level information. Second, we could have the higher level algorithm remove the various assumptions added by the division routine. However, some of these assumptions may have been added by other routines for other reasons. This means that the global routine must know what provisos will be added to the result, where they came from, and how they might have been combined with other profisos in the course of the intermediate computaiton. In general, it seems to be unreasonable that a high level routine be aware of the possible combinations of provisos in lower level routines. Third, we could ignore the problem and claim that the provisos belong there because of the algorithm chosen. For the purpose of this work the third approach is taken. \subsection{Of: Algebra of conditions} Having decided how to handle the issue of global versus local information we need to look at the computation of provisio information as a domain of its own. What kinds of information resides in a proviso? An examination of the mathematics literature shows what appears to be a wide range of possible conditions. However, a large number of these can be captured in one or two froms, either as a symbol representing type and/or property information or as an interval statement such as $x \in [0..10]$. Intervals can be symbolic or numeric. How do we combine this information in meaningful ways? Wiebel and Bonnet (?ref) have developed an algebra of properties. Such work is necessary to put the algebra of provisos on a firm theoretical footing. Because we've reduced the proviso information we consider to two classes we have only to consider how to combine information within these two classes. The question of combinding intervals in meaningful ways is a question of set membership and the mathematics is well-defined. If the endpoints of the intervals are numeric then interval arithmetic is appropriate (?ref). Symbolic property information is considered static but can be combined with other information. How this combination is done is dependent on the meaning of the symbolic information. For example, one could say that a function $f(x)$ is continuous on the interval $[0..)$. For now we consider symbolic information to be a separate domain and defer the issue of combining symbolic information with interval information. \subsection{With: How does proviso information interact with the computation?} \section{Prior Approaches} When this problem has been attacked in other systems the effort has been to create an ``assume'' facility. This allows one to make global statements about the restrictions or assumptions to be placed on an object. Thus, one would perform a computation assuming $x > 0$. \section{What have others done?} \subsection{Dynamic Questions} Macsyma will perform a computation and when it needs to answer a question it constructs a question and asks the user. While this seems like a reasonable approach the problem is that the user can be asked questions that may be stated in terms of variables that don't occur in the original statement of the problem or be asked a question for which the user has no answer. So one might get a question like: $is x > 0?$ where $x$ does not occur in the input equation. The generic approach taken by users seems to be ``just say yet''. \subsection{Carry Forward} In the carry forward approach one uses functions such as signum or other ``lazy'' mechanisms to continue the computation. Maple uses the signum function to delay the binding of parameters until the final result. Once the sign of the parameter is known the signum function can be replaced by the sign of the parameter times 1 (or, in general, the unit). The problems with this approach are that sometimes the signum of a parameter is neither positive nor negative but zero. Then, instead of a positive or negative 1 multiplier, we should use 0. This could be fixed by using a different ``signum'' function. The second problem is related to the solution of the first in that we need to be able to create these special functions that have definitions which depend on the parameters and can participate in the computation but are ``lazy'' in their decisions. This is very difficult to do in general. \subsection{Depth First} Depth first is an approach that uses a top-level control strategy and a stack of decisions. Each decision point puts the other possible choices on a stack and, when the computation returns to the choice point, it is restarted with the next stacked decision. Depth first has several problems, the most serious from a semantics point of view is the confusion of provisos-for-decision vs provisos-for-control. When we ask a question do we want to decide the answer (is $x > 0 \ldots$ yes) or do we want to split the answer into several cases and take each branch? Another serious problem is that we need a general backtracking control mechanism which exists over the top of the computation. If the proviso information is ``discovered'' during the computation that is performed without the top-level backtracker running then the other branches could fall on the floor. \subsection{Frames} Frames introduces the idea of multiple name spaces. Axiom currently supports frames. The variable $x$ could have one value in one frame and a variable $x$ could have another value in another frame. They both have the same name but are distinguished by the name space in which they reside. Such an idea occurs in systems like common lisp where symbols live in ``packages''. Frames introduce a method of carrying the information needed in a very weak sense but do not address the control issue in any way. \subsection{Threads} Threads are a very low level operating system dependent attack on the problem. One cold create a new thread of computation at every branch point using a call to the operating system. Each fork of the computation would compute in parallel with different values of the parameter. Since each fork is a complete copy of the computation we have certainly solved the control issue. It is not clear how the various branches of the computation are to be joined together. This approach is at such a low level that it makes it difficult to see how to change the computation to take advantage of such a mechanism. \subsection{Continuations} Continuations are a mechanism that could be used to solve portions of the proble, as evidenced by Gomez-Dias's work. One problem is that such a solution depends on the underlying mechanism only available in the Scheme language, called continuations. Continuations allow one to get hold of the root of the enclosing $IF$ construct so that the test result can be recomputed. The problem is that the proviso is being evaluated as a side-effect of the test condition of the $IF$ statement. Each proviso is reaching up to the containing $IF$ to save state information. Continuations provide the appropriate control mechanism if every provios implies a branch (provisos-for-control). However they are note appropriate to cases where the proviso simply adds additional information or restrictions (provisos-for-decision). \subsection{``NIF''} This approach involves redefining the semantics of the $IF$ statement, referred to as the {\bf New IF} or {\bf NIF} statement. There are two ways of accomplishing this task. The first is to rewrite every interesting $IF$ statement into a $NIF$ statement. Such an approach is feasible if tedious. The second is theoretically more interesting. One could define a domain called $NIF$ and have it export the $IF$ operation with a signature something like: \begin{verbatim} IF: (text, statement, statement, statement) -> result \end{verbatim} \noindent so that there was a 3-way, or in general, $N$-way $IF$ statement. While there is not theoretical reason why $IF$, $GOTO$, and other statements can't be viewed as functions and redefined by the user it appears that object-oriented compiler technology is not up to the task. \subsection{Assume} One approach is to assume a particular answer and evaluate the result under that assumption. This has 2 problems, the first being that we have to pre-assume certain results which we may only know we need the answers to during the computation. The second is that we will get a single result from the computation, the assumed result. Also assumes that happen before a computation must be global as the objects that they refer to may not be in existence at the time they are done so there is no place to put the assumed information except in a global table. \subsection{Rewrite} One could change the algebra functions to know about provisos. This is a large task but seemingly the only feasible solution if one wishes to do more than just build a global assume-style facility. \section{Provisos} There is also the general problem of cross-branch information. Facts from one branch can affect further computations in another branch. \begin{list}{} \item what is the proposed solution? \item what is a proviso \item how does this solve the problem? \end{list} \section{Proviso Information} \begin{list}{} \item what information could we maintain? \item what information should we maintain? \end{list} \section{Implementation} \begin{list}{} \item how do we maintain that information? \end{list} \section{Computation of Provisos} \begin{list}{} \item how do we compute the proviso result of an operation? \end{list} \section{Computation with Provisos} How does the proviso information affect the computation? There are two uses of proviso information. The first use is to answer symbolic questions. For example, we might want to be able to simplify a square root such as $\sqrt(x^2)$. We could do this simplification if we knew that $x$ was real. If $x$ were complex then the simplification is not valid in general since $x^2 = -1$ if $x$ is $i$. The second use for provisos is in contructing continuations. Consider the question: \begin{verbatim} if x = 0 \end{verbatim} \noindent we could have 4 possible answers: \begin{verbatim} { x < 0, x = 0, x > 0, unknown } \end{verbatim} \noindent and, as a result, there are 4 possible continuations of the computation. If the computation were broken up at this point we could continue each branch of the computation with a proviso attached to each branch restricting the result to the case we assumed. Thus, there would be 4 continuations generated at this point in the computation. Of course such a branching/continuation model assumes some control mechanism is in place. The simplest and most elegant control mechanism is to use continuations as they are implemented in Scheme. These would allow multiple returns from an $IF$ statement, one for each possible path. This approach was used by Gomez-Dias. Alternatively one could use a backtracking control mechanism and keep a stack of the possibilities. Yet another approach, used by Duval, is to repeat the entire computation choosing different paths each time through. There are many issues involved in repeating a computation in each of these choices, not the least of which is that some steps in the computation could de-allocate the storage in use for one of the instances of an object causing disasterous results if the object is reused in a repeated computation. This is an instance of the general problem of side-effecting functions (such as storage allocation). \section{Examples} \subsection{Assumptions} There are examples where we make statements about the valid ranges of the variables before we do the computation. \subsection{Computed Assumptions} These are examples were we make statements about the valid ranges of the variables from an analysis of the equation prior to the integration. In this example we can analyze the denominator to find that there is a zero in the range of the integral. We can compute the result but need to attach a proviso about when the result is valid. $$integrate(1/x,x=0,\infty)$$ \subsection{Derived Assumptions} These are examples where we make statements about the valid ranges of the result from an analysis of the equation after the integration. In this example we have an integral which diverges for a given value of the parameter: $$integrate(1/(x-2), x=0,\infty)$$ \noindent The more general case has 2 answers, $1/a$ if $a > 0$, else divergent: $$integrate(1/(x-a),x=0,\infty)$$ \subsection{Symbolic Numbers} In the field of Numerical Polynomial Algebra there are many instances where numeric computations suffer the problem of {\sl intermediate cancellation}. For example, when computing with numeric polynomials the coefficients are sometimes only known to a finite precision. During matrix elimination we compute differences of polynomials which may lead to a polynomial with ``tiny'' coefficients. There are generally two cases that occur, either only one of the coefficients becomes small or all of the coefficients become small. Since the precision of the coefficients is only specified to a couple decimal places the notion that a coefficient is small means that we have gone below the bounds of known precision. In some cases it is reasonable to assume that a small coefficient is identical to zero and we can elide the term. If all of the coefficients are small it may be reasonable to elide the whole polynomial. In other cases the 'small' value may be due to {\sl intermediate cancellation}. In this case the order of the operations becomes important. For instance, if we know that a number N is known to two decimal places we can divide it by $1^6$ which will make it appear to be so small that it is essentially zero. However we could later multiply it by $1^6$ which will bring it back into range. In that case it would be incorrect to assume the term has vanished. Using infinite precision arithmetic this may not be a problem. However if we are using machine floats it may be the case that we create such small numbers that we ``underflow'' the range losing significant digits. In this case the remaining digits are noise and the multiplication can magnify the noise to the point where it overwhelms the computation. Instead we introduce the idea of a {\sl symbolic number}. A symbolic number is an ordinary number wrapped in a proviso. Operations on the number that could potentially lose significant digits are not carried out directly but added to the proviso. At the final stage of the computation the operations stored in the proviso are carried out in the order which preserves the maximum number of significant digits. Thus, in the example given, if we take $0.01$ and divide it by $1^6$ we delay the computation by forming a symbolic number \[\{0.01 {\rm\ pending\ division\ by\ }1^6\}\] Later, when we encounter the multiplication we form another proviso \[\{\{0.01 {\rm\ pending\ division\ by\ }1^6\}{\rm\ pending\ multiplication\ by\ }1^6\}\] which we can immediately reduce to \[\{0.01{\rm\ provided\ true]}\] which can be coerced back to a normal number \[0.01\] \subsection{Indefinite Integers} \section{Conclusions} \section{package PROVISO Provisos} <>= )abbrev package PROVISO Provisos ++ Author: Timothy Daly April 1995 @ <<*>>= @ \eject \begin{thebibliography}{99} \bibitem{1} Bellman, R., Cooke, K.L. {\sl Asymptotic behaviour of solutions of differential-difference equations} Mem. Amer. Math. Soc. 35 (1959) \bibitem{2} Bellman, R., Cooke, K.L. {\sl Differential-difference equations} Academic Press, New York (1963) \bibitem{3} Feldstein, A., Iserles, A. {\sl Numerical Methods for neutral equations with monotone delays} To appear. \bibitem{4} Fox, L., mayers, D. F., Ockendon, J. R., Tayler, A. B., {\sl On a functional differential equation} J. Inst. Maths Applics (1971) 8, 271--307 \end{thebibliography} \end{document}