/**********************************************************************/
/*    Kima -- an Automated Error-Correction System of KL1 Programs    */
/*                            Version 2.0                             */
/*                                                                    */
/*                             March 1999                             */
/*                                                                    */
/*                   Yasuhiro Ajiro, Kazunori Ueda                    */
/*                                                                    */
/*           Department of Information and Computer Science           */
/*                         Waseda University                          */
/*                 {ajiro,ueda}@ueda.info.waseda.ac.jp                */
/*                                                                    */
/*         Copyright (C) 1999  Yasuhiro Ajiro, Kazunori Ueda          */
/*                                                                    */
/**********************************************************************/


1. OVERVIEW

Kima ver.2 can correct near-misses automatically by means of a static
analysis. Near-misses are a few wrong variable symbol occurrences in KL1
programs. This sounds very restrictive, but most of simple errors occur on
variable symbols because variable symbols are used heavily in (concurrent)
logic/constraint programs, and it is not easy for programmers to correct
such misses by themselves. So Kima's function is very reasonable and useful.

Even when Kima ver.2 fails to correct errors, it can identify them in a
small region on a program text. But it is to be noticed that errors are not
always detected by Kima ver.2.

Automated error-correction consists of the following three processes roughly,
where mode/type analyses play fundamental roles all the time.

  (1. Detection) Mode/type analyses under strong-moding/typing

  (2. Identification) Compute minimal inconsistent subsets of 
                      mode/type constraints 

  (3. Correction) Search alternatives based on variable symbols 
                  pointed out in (2)

Mode/type analyses of KL1 language are constraint satisfaction problems with
many simple mode/type constraints which is lead from symbols in a program
text and moding/typing rules of the form `symbols => constraints', and can
be solved efficiently [3, 4]. If such mode/type constraints are satisfiable,
the program is said to be well-moded/tyepd. If unsatisfiable, it is said to
be non-well-moded/typed.

When a KL1 program includes bugs, it is vely likely that mode constraints
obtained from it are inconsistent. Furthermore type constraints with mode
ones enable the detection power to increase. Then a small number of
constraints can be pointed out as a source of errors by computing a minimal
inconsistent subset from an inconsistent set of mode/type constraints, and
suspicious symbols in some clauses which impose them are identified. Since
the size of minimal inconsistent subsets have been proved to be small from
experiences and experiments, the suspicious region is always small [2].

The mode/type constraints change by making symbol occurrences in clauses
change, and a whole set of constraints may become consistent. So Kima ver.2
regard well-moded/typed programs as `correct', and searches alternatives by
mutating variable symbols systematically [1].

Furthermore Kima ver.2 prioritizes (multiple) alternatives found by search
procedure using heuristics. The heuristics employed by Kima ver.2 are as
follows:

  Heuristics

   (1) Alternatives with stronger mode constraints where
          - a singleton variable is occurring in a clause body, or 
          - the same variable is occuring more than once in a clause head
       are less likely to be an intended solution.

   (2) Alternatives where a variable occurs both at CAR of lists and a path
       constrained to be list-type are less likely to be an intended one.

   (3) Alternatives where a variable doesn't occur in the clause guard but
       in the head are highly likely to be an error.

   (4) Alternatives where a variable occurs on both sides of unification
       are highly likely to be an error.

Kima ver.2 only puts priority points with regard to (1) and (2), but
alternatives which (3) or (4) can be applied are eliminated completely.

Kima ver.2 has the ability to display minimal inconsistent subsets, use only
mode (type) constraints, designate the depth of search (= the number of
rewriting) and so on by way of command line options.


1.1. Main differences between Kima ver.2 and Klint ver.2

Kima ver.2 makes use of Klint ver.2, which is a static analyzer for Kl1
programs. But they have a few differences in two respects in terms of type
analysis:

(1) Though Klint ver.2 doesn't define strong typing, Kima ver.2 does by
classifying function symbols as follows and does not allow different
function symbols to occur at the same path.


  Types  Kinds             Wrapped term in KLIC compiler
 ----------------------------------------------------------------
   F1    integer           integer(Int)
   F2    floating point    floating_point(Float)
   F3    string            string(Str)
   F4    vector            vector({Elem, ...})
   F5    list              list([Car|Cdr]) or atom([])
   F6    structure         functor(Functor(Arg, ...)) or atom(Atom)
                                                  Atom are all but `[]'

(2) Kima ver.2 imposes list-type constraints on the variables occurring
at CDR of lists, which is not done in Klint ver.2.


2. USAGE

INPUT:

All you have to do to run Kima ver.2 is to give your KL1 source files to
kima as:

  % kima xxx.kl1 yyy.kl1 zzz.kl1

OUPUT:

This outputs alternatives which have the highest priority by depth-1 search.

When you want only to indetify the possible region of errors, you can get
minimal inconsistent subsets using a command line option as:

  % kima +mis xxx.kl1 yyy.kl1 zzz.kl1

When Kima ver.2 cannot find alternatives, nothing is output.  It is the
same as to minimal inconsistent subsets.


3. EXAMPLES

Example 1. -- Append program with one error

 +------- append.kl1 ---------------------------------------------------+
 |                                                                      |
 | :- module test.                                                      |
 |                                                                      |
 | append([],   Y,Z) :- true | Y=Z.                                     |
 | %append([A|X],Y,Z0) :- true | Z0=[A|Z], append(X,Y,Z).  <-- correct  |
 | append([A|Y],Y,Z0) :- true | Z0=[A|Z], append(X,Y,Z).                |
 |                                                                      |
 +----------------------------------------------------------------------+

When you want to obtain alternatives up to priority 100, you need to give
the following command line option. Then Kima ver.2 outputs:

  % kima +p 100 append.kl1
 
    ================= Suspected Group 1 =================

           ------------- Priority 1 -------------
  append([A|Y],X,Z0):-true|Z0=[A|Z],append(X,Y,Z)
                                  at place(test,append/3,2)
           -----
  append([A|X],Y,Z0):-true|Z0=[A|Z],append(X,Y,Z)
                                  at place(test,append/3,2)
           -----
           ------------- Priority 2 -------------
  append([A|Y],Y,Z0):-true|Z0=[A|Z],append(Z,Y,Z)
                                  at place(test,append/3,2)
           -----
  append([A|Y],Y,Z0):-true|Z0=[A|Z],append(Z0,Y,Z)
                                  at place(test,append/3,2)
           -----
         ------------- Priority 3 -------------
  append([A|Y],Y,Z0):-true|Z0=[A|Z],append(Y,Y,Z)
                                  at place(test,append/3,2)
           -----
           ------------- Priority 4 -------------
  append([A|Y],Y,Z0):-true|Z0=[A|Z],append(A,Y,Z)
                                  at place(test,append/3,2)
           -----

This means six alternatives are found from priority 1 to 6. Priority 1 which 
contains two alternatives is the highest priority. There is a `-----' between
alternatives. 

Here `place(test,append/3,2)' says that alternatives are as to:

  the 2nd clause of definition of `append' with 3 arguments in module `test'.

The second alternative in the Priority 1 is the intended one, and the first
alternative becomes a program which merges two input lists by taking their
elements alternately [1].

Next, a minimal inconsistent subset -- described `MIS' below -- will be
shown which is computed for searching alternatives:

  % kima +mis append.kl1

  < Minimal Inconsistent Subsets of *Mode* constraints >
  ig([((test:append)/3,1),(cons,2)])
      <- hv(variable(1,"Y"),place(test,append/3,2))
  og([((test:append)/3,1)])
      <- bv(variable(4,"X"),place(test,append/3,2))
  -----
  < Minimal Inconsistent Subsets of *Type* constraints >
   --Constraints are consistent, and there is no MIS--


MISs of mode constraints are obtained first, those of type ones
second. Multiple independent MISs can be computed at once [2], and are
displayed divided with `-----'. In this example, only one MIS is obtained on
modes, while type constraints are consistent.

In a MIS, lines which begin at the end of a line correspond to constraints.
MIS of this example consists of two constraints. The next line which begin
with `<-' expresses a source symbol which imposes the upper constraint, where
`place(module,predicate,number)' presents the same as above. That is to say,
a constraint `ig([((test:append)/3,1),(cons,2)])' is imposed from
 
          a variable symbol `Y' at place(test,append/3,2)

and a moding rule `hv'[4]. So the MIS tells that varables `X' and `Y' in the
2nd clause of definition of `append' with 3 arguments in module `test' are
suspicious. Then Kima ver.2 searches alternatives by increasing or
decreasing those symbol occurrences in the clause.


Example 2. -- Combination program with two independent errors

The next example is a combination program in the field of probability
theory, which includes two errors.

  +--------- comb.kl1 ---------------------------------------------+
  | :- module probability.                                         |
  |                                                                |
  | % nCr (n >= r >= 0)                                            |
  | % Use: combination(N,R,C)                                      |
  | %   e.g. combinaiton(3,2,Res) --> [[1,1,0], [1,0,1], [0,1,1]]  |
  | combination(N,0,C) :- true | init_list(0,N,0,[],C0), C=[C0].   |
  | combination(N,N,C) :- true | init_list(0,N,1,[],C0), C=[C0].   |
  | combination(N,R,C) :- N>R  |                                   |
  |     N1:=N-1, R1:=R-1,                                          |
  |     combination(N1,R1,C0), cons_list(1,C0,CC0),                |
  |     combination(N1,R, C1), cons_list(0,C1,CC1),                |
  | %   append(CC0,CC1,C).                            <-- correct  |
  |     append(CC0,CC1,CC).                                        |
  |                                                                |
  | init_list(N,Len,E,L0,L) :- N =:= Len | L0=L.                   |
  | %init_list(N,Len,E,L0,L) :- N  <  Len |           <-- correct  |
  | init_list(N,Len,E,L0,L0) :- N  <  Len |                        |
  |     L1=[E|L0], N1:=N+1, init_list(N1,Len,E,L1,L).              |
  |                                                                |
  | cons_list(_,[],    L) :- true | L=[].                          |
  | cons_list(A,[X|Xs],L) :- true |                                |
  |     L=[[A|X]|L1], cons_list(A,Xs,L1).                          |
  |                                                                |
  | append([],   Y,Z ) :- true | Y=Z.                              |
  | append([A|X],Y,Z0) :- true | Z0=[A|Z], append(X,Y,Z).          |
  +----------------------------------------------------------------+

Kima ver.2 searches alternatives by depth-1 search:

  % kima comb.kl1

    ================= Suspected Group 1 =================

           ------------- Priority 1 -------------
  combination(N,R,C):-N>R|N1:=N-1,R1:=R-1,combination(N1,R1,C0),
  cons_list(1,C0,CC0),combination(N1,R,C1),cons_list(0,C1,CC1),
  append(CC0,CC1,C)
                                  at place(probability,combination/3,3)
           -----
  combination(N,R,CC):-N>R|N1:=N-1,R1:=R-1,combination(N1,R1,C0),
  cons_list(1,C0,CC0),combination(N1,R,C1),cons_list(0,C1,CC1),
  append(CC0,CC1,CC)
                                  at place(probability,combination/3,3)
           -----
    ================= Suspected Group 2 =================

           ------------- Priority 1 -------------
  init_list(N,Len,E,L0,L):-N<Len|L1=[E|L0],N1:=N+1,init_list(N1,Len,E,L1,L)
                                  at place(probability,init_list/5,2)
           -----

Though alternatives are hard to read a little or more, there proves to be
two `Suspected Group's. Kima ver.2 searches alternatives by depth-N search
independently for each group into which MISs are devided checking whether
they point the same clause. In this example, Kima ver.2 concluded that there
are two error regions independently, and search alternatives by depth-1
search for each. As a result Kima ver.2 succeeded in finding the intended
alternative for each error. By the way, two alternatives in the Suspected
Group 1 are all the same though the ways of rewriting are different.


Example 3. -- Quicksort program with two errors in the same group

There are two wrong variable symbol occurrences in the same clause.

 +--------- qsort.kl1 -------------------------------------------------------+
 | :- module main.                                                           |
 |                                                                           |
 | main :- true | quicksort([3,8,2,5,6],Res),io:ousstream([print(Res),nl]).  |
 |                                                                           |
 | quicksort(Xs,Ys) :- qsort(Xs,Ys,[]).                                      |
 | qsort([],    Ys0,Ys ) :- true | Ys=Ys0.                                   |
 | qsort([X|Xs],Ys0,Ys3) :- true |                                           |
 |     part(X,Xs,S,L), qsort(S,Ys0,Ys1),                                     |
 | %   Ys1=[X|Ys2], qsort(L,Ys2,Ys3).               <-- correct              |
 |     Ys2=[X|Ys1], qsort(L,Ys2,Ys3).                                        |
 |                                                                           |
 | part(_,[],    S, L ) :- true | S=[], L=[].                                |
 | part(A,[X|Xs],S0,L ) :- A>=X | S0=[X|S], part(A,Xs,S,L).                  |
 | part(A,[X|Xs],S, L0) :- A< X | L0=[X|L], part(A,Xs,S,L).                  |
 +---------------------------------------------------------------------------+

Depth-1 search will be tried first:

  % kima qsort.kl1

    ================= Suspected Group 1 =================

           ------------- Priority 1 -------------
  qsort([X|Xs],Ys0,Ys3):-true|part(X,Xs,S,L),qsort(S,Ys0,Ys1),Ys2=[X|Ys1],
  qsort(L,Ys1,Ys3)
                                  at place(main,qsort/3,2)
           -----

But this solution is a strange program, where variable `Ys2' is instantiated
but not referred anywhere.

Now depth-2 search are tried:

  % kima +d 2 qsort.kl1

    ================= Suspected Group 1 =================

           ------------- Priority 1 -------------
  qsort([X|Xs],Ys0,Ys3):-true|part(X,Xs,S,L),qsort(S,Ys0,Ys1),Ys1=[X|Ys2],
  qsort(L,Ys2,Ys3)
                                  at place(main,qsort/3,2)
           -----
  qsort([X|Xs],Ys0,Ys3):-true|part(X,Xs,S,L),qsort(S,Ys0,Ys2),Ys2=[X|Ys1],
  qsort(L,Ys1,Ys3)
                                  at place(main,qsort/3,2)
           -----

The intended program is obtained as the first alternative, and the second is
the same program. At depth-2 search, alternatives by depth-1 search are
obtained simultaneously, and Kima ver.2 prioritizes all alternatives
obtained by depth-1 and 2 search. That is to say, at depth-N search,
depth-1, ..., N searches are done at a time.

In this example, since the alternative by depth-1 search has lower priority
than alternatives obtained by depth-2 search in terms of heuristics-1, the
alternative by depth-1 search is not output as solutions with the highest
priority.

An implausible alternative is output at depth-1 search, because heuristics-1
does not delete solutions but only prioritizes them. So you must judge
whether obtained alternative is intended or not at any depth search by
yourself.


4. DETAILS OF USAGE --- command line options

The following options are available in Kima ver.2.

     Options     Works
    ----------------------------------------------------------------------
      +mode      use only mode information of minimal inconsistent subsets

      +type      use only type information of minimal inconsistent subsets

      +mis       display Minimal Inconsistent Subsets

      +d <N>     search alternatives by iterative-deepening up to depth N
                   N should be an integer number, and 0<N=<10 

      +p <N>     search alternatives up to priority N
                   N should be an integer number, and 0<N

      +h         display on-line help


Other command line arguments than options above are all considered as 
names of files. If nonexistent file is designated, Kima ver.2 will stop
running. 

If no option is designated, Kima ver.2 runs as options are:

  % kima +mode +type +d 1 +p 1  FILE1 FILE2 ...

that is, Kima ver.2 computes the most plausible alternatives by depth-1
search using mode and type constraints.

Other rules:

(1) When `+d' or `+p' is given but `N' is not done, Kima ver.2 considers
    N = 1.

(2) When `+mis' is given, Kima ver.2 only displays MISs but donesn't search
    alternatives. If you want to search alternatives at the same time, you
    need to designate them together like `+mis +d'

(3) `+h' must be given at the head of options.

It is to be noticed that options begin with `+', which is different from
common UNIX commands. This is because options which begin with `-' have
already been reserved by KLIC compiler.

Last I must say `+d' can recieve the number from 1 to 10 as N, but I
encourage not to give 3 or larger, because of time complexity.
Current implemntation of Kima ver.2 is harsh especially to space complexity
because time complexity is thought to be more important.


5. INSTALLATION

Kima ver.2 is totally written in KL1 and can be compiled using KLIC.  Please
refer to INSTALL file contained with this Readme in this distribution.

For your information, the Kima ver.2 distribution contains the following
files:

  (1) Makefile  -- make file
  (2) Readme    -- This file
      Readme-j  -- Japanese version of this file
  (3) INSTALL   -- Installation manual
      INSTALL-j -- Japanese version of an installation manual
  (4) kima-main5.kl1 read_program4.kl1 normalize5.kl1 unify.kl1
      builtin_DB_st5.kl1 numberbuiltin3.kl1 findpath4.kl1
      constraints_st9.kl1 type_st2.kl1 stdinout2.kl1
      minsub.kl1 type_minsub.kl1 copygraph3.kl1 tcopygraph.kl1
      group_doubt2.kl1 generate_test5.kl1 gen_alt.kl1
      test_alt4.kl1 heuristics4.kl1 common2.kl1 probability.kl1
      command_line2.kl1 graphD.kl1 decode2.kl1 reduce6.kl1 sort.kl1
      outmessage4.kl1 tdecode.kl1 tgraph_st3.kl1
                -- Source files of Kima ver.2 (29 files in total)
  (5) examples/append-error.kl1
               comb-error.kl1
               fib-error.kl1
               qsort-d2-error.kl1
                -- Sample KL1 programs with errors used in this Readme


6. FEATURES NOT YET SUPPORTED

  (1) Stratification of programs

  (2) Policy to identify errors in smaller region [1].

  (3) Correction of constant symbols

  (4) Full occur-check

When polimorphic predicates like append or length are called from multiple
places, there are many cases where programs become non-well-moded/typed,
because (1) has not been implemented yet. This problem is more serious
especially on types. To escape it, the same predicates must be define with
different names for each call now, which is a rather adhoc solution.


7. RESTRICTIONS

(1) If a Stream is stored to a Vector directly, it causes non-well-moded,
because the predicate `new_vector/2' is allowed to use in two ways ---
new_vector(Vector,Int) and new_vector(Vector,List) in the current version of
KLIC compiler. Since Kima ver.2 analyzes programs assuming that any calls
are in the former way, top mode of elements of a vector becomes `in'. This
is because KLIC compiler initializes elements of a vector with `0'. It is
also the case with Klint ver.2.

(2) At a correction of variables, it is necessary to consider rewriting some
symbol to a completely fresh variable in the clause. Since Kima ver.2 uses
the variable name `FreshVarN'(N is an integer, 0=<N<10) for this purpose,
dont't use this variable name in your program.  If you do, alternatives may
not be computed properly.

(3) Since Kima ver.2 utilizes Klint ver.2, restrictions of Klint ver.2
become those of Kima ver.2 as they are. It is the same with features not yet
supported. Refer to Readme and so on in [5] as to Klint ver.2.


REFERENCES

[1] Ajiro, Y., Ueda, K., Cho, K., Error-Correcting Source Code. In
Proc. Fourth Int. Conf. on Principles and Practice of Constraint Programming
(CP'98), LNCS 1520, Springer, 1998, pp.40-54.

[2] Cho, K. and Ueda, K., Diagnosing Non-Well-Moded Concurrent Logic
Programs, In Proc. 1996 Joint Int. Conf. and Symp. on Logic Programming
(JICSLP'96), The MIT Press, 1996, pp.215-229.

[3] Ueda, K. and Morita, M., Moded Flat GHC and Its Message-Oriented
Implementation Technique. New Generation Computing, Vol.13, No.1 (1994),
pp.3-43.

[4] Ueda, K., Experiences with Strong Moding in Concurrent Logic/Constraint
Programming. In Proc. Int. Workshop on Parallel Symbolic Languages and
Systems, LNCS 1068, Springer, 1996, pp.134-153.

[5] Ueda, K., klint --- Static Analyzer for KL1 Programs.
Available from
http://www.icot.or.jp/AITEC/FGCS/funding/itaku-H9-index-E.html, 1998.

