--* From BMT%WATSON.vnet.ibm.com@yktvmv.watson.ibm.com  Fri Aug 12 12:37:11 1994
--* Received: from yktvmv-ob.watson.ibm.com by asharp.watson.ibm.com (AIX 3.2/UCB 5.64/930311)
--*           id AA18609; Fri, 12 Aug 1994 12:37:11 -0400
--* Received: from watson.vnet.ibm.com by yktvmv.watson.ibm.com (IBM VM SMTP V2R3)
--*    with BSMTP id 6845; Fri, 12 Aug 94 12:37:14 EDT
--* Received: from YKTVMV by watson.vnet.ibm.com with "VAGENT.V1.0"
--*           id <A.BMT.NOTE.VAGENT2.9767.Aug.12.12:37:13.-0400>
--*           for asbugs@watson; Fri, 12 Aug 94 12:37:13 -0400
--* Received: from YKTVMV by watson.vnet.ibm.com with "VAGENT.V1.0"
--*           id 9761; Fri, 12 Aug 1994 12:37:12 EDT
--* Received: from spadserv.watson.ibm.com by yktvmv.watson.ibm.com
--*    (IBM VM SMTP V2R3) with TCP; Fri, 12 Aug 94 12:37:10 EDT
--* Received: by spadserv.watson.ibm.com (AIX 3.2/UCB 5.64/900524)
--*           id AA01553; Fri, 12 Aug 1994 12:34:55 -0400
--* Date: Fri, 12 Aug 1994 12:34:55 -0400
--* From: bmt@spadserv.watson.ibm.com
--* X-External-Networks: yes
--* Message-Id: <9408121634.AA01553@spadserv.watson.ibm.com>
--* To: asbugs@watson.ibm.com
--* Subject: [3] doesn't find conditional convert: S -> InputForm, but does find other converts which shouldn't be present.

--@ Fixed  by:  SSD   Fri Apr 14 17:40:19 EDT 1995 
--@ Tested by:  none 
--@ Summary:    Now finding conditional converts; two meanings for convert OK. 


-- Command line: asharp -b/spad/mnt/rios/asharp kl.as
-- Version: 0.36.2
-- Original bug file name: kl.as

#include "axiom.as"
CACHSET ==> CachableSet;


+++ A cachable set is a set whose elements keep an integer as part of their
+++ structure.
define MyCachableSet: Category== with {
        OrderedSet;
        position: % -> NonNegativeInteger;
                ++ `position(x)' returns the integer `n' associated to `x'.

        setPosition: (%,NonNegativeInteger) -> ();
                ++ `setPosition(x, n)' associates the integer `n' to `x'.

}

SCACHE ==> SortedCache;

N ==> NonNegativeInteger;

DIFF ==> 1024;


+++ \indented{1}{Cache of elements in a set} Author: Manuel Bronstein Date
+++ Created: 31 Oct 1988 Date Last Updated: 14 May 1991 \indented{2}{A sorted
+++ cache of a cachable set `S' is a dynamic structure that} \indented{2}{keeps
+++ the elements of `S' sorted and assigns an integer to each}
+++ \indented{2}{element of `S' once it is in the cache. This way, equality and
+++ ordering} \indented{2}{on `S' are tested directly on the integers associated
+++ with the elements} \indented{2}{of `S', once they have been entered in the
+++ cache.}
MySortedCache (S: MyCachableSet): with {
        clearCache: () -> ();
                ++ `clearCache()' empties the cache.

        cache: () -> List S;
                ++ `cache()' returns the current cache as a list.

        enterInCache: (S,S -> Boolean) -> S;
                ++ `enterInCache(x, f)' enters `x' in the cache, calling `f(y)'
                ++ to determine whether `x' is equal to `y'. It returns `x' with
                ++ an integer associated with it.

        enterInCache: (S,(S,S) -> Integer) -> S;
                ++ `enterInCache(x, f)' enters `x' in the cache, calling `f(x,
                ++ y)' to determine whether `x < y (f(x,y) < 0), x = y (f(x,y) =
                ++ 0)', or `x > y (f(x,y) > 0)'. It returns `x' with an integer
                ++ associated with it.

}
== add {
        import from Integer;
        import from NonNegativeInteger;
        import from S;
        import from Record (cche: List S);
        default shiftCache: (List S,N) -> ();
        default insertInCache: (List S,List S,S,N) -> S;
        cach := [nil]$Record(cche: List(S));
        cache():List S == cach cche;
        shiftCache(l:List S,n:N):() == {
                for x in l repeat setPosition(x,n + position x);
                ();
        }

        clearCache():() == {
                import from List S;
                for x in cache() repeat setPosition(x,0);
                cach cche := nil;
                ();
        }

        enterInCache(x:S,equal?:S -> Boolean):S == {
                scan := cache();
                while not (null scan) repeat {
                        equal? (y := first scan) => {
                                setPosition(x,position y);
                                return y;
                        }
                        scan := rest scan;
                }
                setPosition(x,1 + #cache());
                cach cche := concat(cache(),x);
                x;
        }

        enterInCache(x:S,triage:(S,S) -> Integer):S == {
                import from SingleInteger;
                local i:Integer;
                scan := cache();
                pos:N := 0;
                import from Segment Integer;
                for (free i) in 1..((#scan)::Integer) repeat {
                        zero? (n := triage(x,y := first scan)) => {
                                setPosition(x,position y);
                                return y;
                        }
                        n < 0$Integer =>
                          return
                            insertInCache(
                              first(cache(),(i - 1)::NonNegativeInteger),scan,x,
                                pos);
                        scan := rest scan;
                        pos := position y;
                }
                setPosition(x,pos + 1024::NonNegativeInteger);
                cach cche := concat(cache(),x);
                x;
        }

        insertInCache(before:List S,after:List S,x:S,pos:N):S == {
                if pos + 1 = position first after then
                  shiftCache(after,1024::NonNegativeInteger);
                setPosition(x,pos +
                  (position first after::Integer - pos::Integer)::
                    NonNegativeInteger quo 2::NonNegativeInteger);
                cach cche := concat(before,concat(x,after));
                x;
        }

}

MKCHSET ==> MakeCachableSet;


+++ MakeCachableSet(`S') returns a cachable set which is equal to `S' as a set.
MyMakeCachableSet (S: SetCategory): with {
        MyCachableSet;
        CoercibleTo S;
        coerce: S -> %;
                ++ `coerce(s)' returns `s' viewed as an element of \%.

}
== add {
        Rep ==> Record(setpart: S,pos: N);
        import from S;
        import from MySortedCache %;
        import from Rep;
        clearCache();
        position (x:%):N == (rep(x)).pos;
        setPosition(x:%,n:N):() == { (rep(x)).pos := n; () };
        coerce (x:%):S == (rep(x)).setpart;
        coerce (x:%):OutputForm == x::OutputForm;
        coerce (s:S):% ==
          enterInCache(per([s,0]$Rep),((%1:%):Boolean) +-> s = %1::S);

        (x:%) < (y:%):Boolean == {
                if position x = 0 then
                  enterInCache(x,((%1:%):Boolean) +-> x::S = %1::S);
                if position y = 0 then
                  enterInCache(y,((%1:%):Boolean) +-> y::S = %1::S);
                position x < position y;
        }

        (x:%) = (y:%):Boolean == {
                if position x = 0 then
                  enterInCache(x,((%1:%):Boolean) +-> x::S = %1::S);
                if position y = 0 then
                  enterInCache(y,((%1:%):Boolean) +-> y::S = %1::S);
                position x = position y;
        }

}

KERNEL ==> Kernel;

O ==> OutputForm;

OP ==> BasicOperator;

SYMBOL ==> "%symbol";

PMPRED ==> "%pmpredicate";

PMOPT ==> "%pmoptional";

PMMULT ==> "%pmmultiple";

PMCONST ==> "%pmconstant";

SPECIALDISP ==> "%specialDisp";

SPECIALEQUAL ==> "%specialEqual";

SPECIALINPUT ==> "%specialInput";


+++ A kernel over a set `S' is an operator applied to a given list of arguments
+++ from `S'.
MyKernel (S: OrderedSet): with {
        MyCachableSet;
        Patternable S;
        name: % -> Symbol;
                ++ `name(op(a1,...,an))' returns the name of op.

        operator: % -> OP;
        argument: % -> List S;
                ++ `argument(op(a1,...,an))' returns `[a1,...,an]'.

        height: % -> N;
        kernel: (OP,List S,N) -> %;
        kernel: Symbol -> %;
                ++ `kernel(x)' returns `x' viewed as a kernel.

        symbolIfCan: % -> Union(value1:Symbol, failed:Enumeration failed);
                ++ `symbolIfCan(k)' returns `k' viewed as a symbol if `k' is a
                ++ symbol, and "failed" otherwise.

        is?: (%,OP) -> Boolean;
        is?: (%,Symbol) -> Boolean;
                ++ `is?(op(a1,...,an), s)' tests if the name of op is `s'.

        if S has ConvertibleTo InputForm then ConvertibleTo InputForm;
}
== add {
        Rep ==> Record(op: OP,arg: List S,nest: N,posit: N);
        import from S;
        import from MySortedCache %;
        import from Rep;
        clearCache();
        default B2Z: Boolean -> Integer;
        default triage: (%,%) -> Integer;
        default preds: OP -> List Any;
        is?(k:%,s:Symbol):Boolean == is?(operator k,s);
        is?(k:%,o:OP):Boolean == operator k = o;
        name (k:%):Symbol == name operator k;
        height (k:%):N == (rep(k)).nest;
        operator (k:%):OP == (rep(k)).op;
        argument (k:%):List S == (rep(k)).arg;
        position (k:%):N == (rep(k)).posit;
        setPosition(k:%,n:N):() == (rep(k)).posit := n;
        B2Z (flag:Boolean):Integer == { flag => - 1; 1 };
        kernel (s:Symbol):% == s pretend %; -- for now
          --per(kernel(assert(operator(s,0),"%symbol"),nil,1));


        preds (o:OP):List Any == {
                import from Union(value1:None, failed:'failed');
                (u := property(o,"%pmpredicate")) case failed => nil;
                u.value1 pretend List Any;
        }

        symbolIfCan (k:%):Union(value1:Symbol,failed:Enumeration failed) == {
                import from OP;
                has?(operator k,"%symbol") =>
                  [name operator k];
                [failed];
        }

        (k1:%) = (k2:%):Boolean == {
                if (rep(k1)).posit = 0 then enterInCache(k1,triage);
                if (rep(k2)).posit = 0 then enterInCache(k2,triage);
                (rep(k1)).posit = (rep(k2)).posit;
        }

        (k1:%) < (k2:%):Boolean == {
                if (rep(k1)).posit = 0 then enterInCache(k1,triage);
                if (rep(k2)).posit = 0 then enterInCache(k2,triage);
                (rep(k1)).posit < (rep(k2)).posit;
        }

        kernel(fn:OP,x:List S,n:N):% == {
                import from Union(value1:NonNegativeInteger, failed:'failed');
                (u := arity fn) case value1 and not
                  (#x = u.value1) => error "Wrong number of arguments";
                enterInCache(per([fn,x,n,0]$Rep),triage);
        }

        coerce (k:%):O == {
                import from Symbol;
                import from Union(value1:Symbol, failed:'failed');
                (v := symbolIfCan k) case value1 => v.value1::OutputForm;
                import from Union(value1:None, failed:'failed');
                (f := property(o := operator k,"%specialDisp")) case value1 =>
                  (f.value1 pretend List S -> OutputForm).(argument k);
                l := [x::OutputForm for x in argument(k)]$List(O);
                import from Union(value1:List OutputForm->OutputForm, failed:'failed');
                (u := display o) case failed => prefix(name o::OutputForm,l);
                (u.value1).l;
        }

        triage(k1:%,k2:%):Integer == {
                import from List S;
                import from Union(value1:None, failed:'failed');
                (rep(k1)).nest::Integer = (rep(k2)).nest::Integer => {
                      (rep(k1)).op = (rep(k2)).op => {
                           (n1 := #argument k1::Integer) =
                             (n2 := #argument k2::Integer) => {
                                  (func :=
                                       property(operator k1,"%specialEqual"))
                                           case value1 and
                                            (func.value1
                                                  pretend (%,%) -> Boolean).
                                                    (k1, k2) => 0$Integer;
                                  for x1 in argument k1 for x2 in
                                            argument k2 repeat {
                                                  x1 = x2 => ();
                                                  return B2Z (x1 < x2);
                                          }
                                          0;
                                }
                                B2Z (n1 < n2);
                        }
                        B2Z ((rep(k1)).op < (rep(k2)).op);
                }
                B2Z ((rep(k1)).nest < (rep(k2)).nest);
        }

        if S has ConvertibleTo InputForm then
          convert (k:%):InputForm == {
                  import from Union(value1:Symbol, failed:'failed');
                  import from Union(value1:None, failed:'failed');
                  (v := symbolIfCan k) case value1 =>
                    convert (v.value1) @ InputForm;
                  (f := property(o := operator k,"%specialInput")) case value1 =>
                    (f.value1 pretend  List S -> InputForm).(argument k);
                  import from List S, List InputForm, S;
                  l := [convert(x)@InputForm for x in argument(k)]$List(InputForm);
                  import from Union(value1:List InputForm -> InputForm, failed:'failed');
                  (u := input operator k) case failed =>
                    convert concat(convert name operator k,l);
                  (u.value1).l;
          }
        if S has ConvertibleTo Pattern Integer then
          convert (k:%):Pattern Integer == {
                  import from List S, List Any;
                  import from List Pattern Integer;
                  o := operator k;
                  import from Union(value1:Symbol, failed:'failed');
                  (v := symbolIfCan k) case value1 => {
                          s :=
                            patternVariable(v.value1,has?(o,"%pmconstant"),
                              has?(o,"%pmoptional"),has?(o,"%pmmultiple"));
                          empty? (l := preds o) => s;
                          setPredicates(s,l);
                  }
                  o([convert(x) for x in (rep(k)).arg]$List(Pattern(Integer)));
          }
        if S has ConvertibleTo Pattern Float then
          convert (k:%):Pattern Float == {
                  import from Float;
                  import from List S, List Any;
                  import from List Pattern Float;
                  o := operator k;
                  import from Union(value1:Symbol, failed:'failed');
                  (v := symbolIfCan k) case value1 => {
                          s :=
                            patternVariable(v.value1,has?(o,"%pmconstant"),
                              has?(o,"%pmoptional"),has?(o,"%pmmultiple"));
                          empty? (l := preds o) => s;
                          setPredicates(s,l);
                  }
                  o([convert(x) for x in (rep(k)).arg]$List(Pattern(Float)));
          }
}

KERNEL2 ==> KernelFunctions2;


+++
MyKernelFunctions2(R: OrderedSet,S: OrderedSet): with {
        constantKernel: R -> Kernel S;
        constantIfCan: Kernel S -> Union(value1:R,failed:Enumeration failed);
}
== add {
        import from S;
        import from R;
        import from BasicOperatorFunctions1 R;
        import from NonNegativeInteger;
        import from List S;
        constantKernel (r:R):Kernel S == kernel(constantOperator r,empty(),1);
        constantIfCan (k:Kernel S):Union(value1:R,failed:Enumeration failed) ==
          constantOpIfCan operator k;

}

 
