Sindbad~EG File Manager

Current Path : /usr/home/beeson/Otter-Lambda/otter2/
Upload File :
Current File : /usr/home/beeson/Otter-Lambda/otter2/fsubsto.c

/* Author: M. Beeson */

#include <assert.h>
#include "header.h"
#include "beta.h"
#include "bterms.h"
#include "bsym.h"
#include "unify2.h"  // forbid
#include "fsubsto.h"
#include "unify.h"   // BIND
static struct term *apply2(struct term *t,struct context *c);

/*_________________________________________________________________________________________*/
struct term * fsubst3(struct term *a, struct term *x, struct context * c1, struct term *b, struct context *c2, struct trail **trp)
/* substitute a for (x,c1) in (b,c2).  It is assumed that a is a variable that does not 
occur in contexts c1 or c2.  
   If x is not a variable,  then substituting a for (x,c1) in b  should yield a if 
x equals b ;  but more generally if x,c1 UNIFIES with b,c2  it should 
yield a.  Example:  substitute z for g(X) in g(Y),  should succeed with result z,
recording the substitution X = Y in the context(s) and adding to the trail appropriately.
   If x is an unassigned variable, we
call unify.   But otherwise we just return a copy of b.
   The return value must be a term that makes sense in context c2.  
Hence the BIND call at the end.
   After this returns, the variable a is going to become a lambda-bound variable,  so 
the bindings that are made in c2 during fsubst3 should neither bind a, nor bind any
other variable to a term depending on a.
*/
{ term t, w, ans;
  struct rel *r,*s; 
  struct context *d;
  if(x->type == COMPLEX || x->type == NAME)
     { if(term_ident2(x,b,0))  // constant terms, equal except for renaming of bound variables
          return copy_term(a);
       if(c1==c2 && term_ident2(x,b,0))
          return copy_term(a);
       if(unify(x,c1,b,c2,trp))
          return copy_term(a);  // this can't bind a or bind to a since a doesn't occur in c1 or c2.
     }
  if(b->type == COMPLEX)
     { if(BINDER(b->sym_num) && VARNUM(ARG0(b))== VARNUM(a) && c1 == c2)
           return copy_term(b);  // should never happen since a doesn't occur in c1, c2.
           // without that hypothesis, we should rename the bound variable of b first
       ans = get_term();
       ans->sym_num = b->sym_num;
       ans->type = COMPLEX;
       s = get_rel();
       ans->farg = s;
       for(r = b->farg; r; r=r->narg)
          { s->argval = fsubst3(a,x,c1,r->argval,c2,trp);
            if(r->narg)
              { s->narg = get_rel();
                s = s->narg;
              }
          }
       return ans;
     }
  if(b->type == NAME)
      return copy_term(b);
  // now b->type == VARIABLE 

  if(c2->bound[b->varnum])
      return copy_term(b);  // do not substitute for a lambda bound variable!
  if(x->varnum == b->varnum && c1 == c2)
      return copy_term(a);  // even if b has a value in c2
  t = c2->terms[b->varnum];
  d = c2->contexts[b->varnum];
  if(!t)
     return copy_term(b);
  DEREFERENCE(t,d);
  w = fsubst3(a,x,c1,t,d,trp);
  if(w->type == VARIABLE && w->varnum == a->varnum)
     return w;  // a->varnum must be a,  since it didn't occur in either c1 or c2 to begin with.
  if(d == c2)
     return w;
  /* Originally I was going to create a new variable and BIND it to w.
     But that will violate the specification that nothing should be bound in c2
     to a term containing a.  Instead we must actually carry out the substitutions in d: */
  return apply2(w,d);
}
/*__________________________________________________________*/
struct clause *getContainingClause(struct term *t)
// If you can get to a clause by repeatedly taking t->occ.rel->argof
// until this is NULL and then t->occ.lit->container,  return that clause.
// If not (which will happen e.g. it t is TRUE or FALSE) return NULL.
{ struct term *p = t;
  while(p->occ.rel && p->occ.rel->argof && 
        (p->type == VARIABLE || p->varnum == 0)
       )
     p=p->occ.rel->argof;
  if(p->occ.lit == NULL)
       return NULL;
  return p->occ.lit->container;
}  
/*__________________________________________________________*/
static struct term *getContainingAtom(struct term *t)
{ struct term *p = t;
  while(p->occ.rel && p->occ.rel->argof && 
        (p->type == VARIABLE || p->varnum == 0)
       )
     p=p->occ.rel->argof;
  return p;
}  

/*__________________________________________________________*/
void prepare_context(struct term *t1, struct context *c1, int max)
/* set the forbid and next_var fields in c1 and c2 so that all bound variables in t1 are 
marked bound in c1, and all bound variables in t2 are marked bound in c2, and 
next_var exceeds all varnums in t1 and also is at least max.
*/
{ struct clause *cl1 = getContainingClause(t1); 
  struct literal *lit;
  memset(c1->forbidden,0,MAX_VARS *sizeof(int));
  memset(c1->bound,0,MAX_VARS *sizeof(int));
  for(lit =  cl1->first_lit; lit; lit = lit->next_lit)
     forbid_bound(c1,lit->atom);
  c1->next_var  = max_vars(cl1,t1);
  if(c1->next_var < max)
     c1->next_var = max;
}  
/*_______________________________________________________*/
 //static  // temporarily exposed for debugging
 int check_lambda(struct term *t)
/* return 0 if t has a subterm of the form lambda(s,.. where s is not a variable. 
Otherwise return 1. */
{ struct rel *r;
  if(t->type != COMPLEX)
     return 1;
  if(FUNCTOR(t)== LAMBDA && ARG0(t)->type != VARIABLE)
     return 0;
  for(r=t->farg;r;r=r->narg)
     { if(!check_lambda(r->argval))
          return 0;
     }
  return 1;
}  

/*_______________________________________________________*/
int check_lambdas(struct clause *c)
/* return 0 if there are any terms lambda(s,.. where s is not a variable.
Before returning, free the clause, its literals, and all their terms.  
If there are no such illegal lambda-terms, return 1.
*/
  
{ struct literal *q, *p = NULL;
  for(q = c->first_lit;q;q=q->next_lit)
     { if( !check_lambda(q->atom))
           goto fail;
     }
  return 1;
  fail:
  for(q = c->first_lit;q;q=q->next_lit)
		 { free_term(q->atom);
		   if(p) free_literal(p);
		   p = q;
		 }
  free_literal(p);
  free_clause(c);
  return 0;
}
/*_________________________________________________________________________*/
int blocking_functor(int f)
/* return 1 if f is the sym_num of "ind", "ind1", "ind2", ..."ind5",
or of none of those have sym_nums, of "g" or "e"  Return 0 otherwise.
Arity of these functors could be 1 or 2 depending on the formulation 
of induction.
*/
{
  static int g[5];  // space for the induction functors
  static int k;     // number of induction functors
  struct sym_ent *se;
  int j;
  char buffer[5];
  if(k == -1)       // no induction functors, already checked
     return 0;
  if(k==0)
     { // first call;  get the induction functors
       se = sym_tab_member("ind", 2);
       if(se)
         { g[k] = se->sym_num;
           ++k;
         }
       se = sym_tab_member("ind",1);
       if(se)
         { g[k] = se->sym_num;
           ++k;
         }
       strcpy(buffer,"ind");
       buffer[4] = 0;
       for(j=0;j<4;j++)
          { buffer[3] = '1' + j;
            se = sym_tab_member(buffer,2);
            if(se)
               { g[k] = se->sym_num;
                 ++k;
               }
              se = sym_tab_member(buffer,1);
            if(se)
               { g[k] = se->sym_num;
                 ++k;
               }   
          }
       if(k==0)
          { se = sym_tab_member("g",2);
            if(se)
               { g[k] = se->sym_num;
                 ++k;
               }
            se = sym_tab_member("g",1);   
            if(se)
               { g[k] = se->sym_num;
                 ++k;
               } 
            se = sym_tab_member("e",1);   // used for Hilbert's epsilon symbol
            if(se)
               { g[k] = se->sym_num;
                 ++k;
               }   
          }
       if(k==0)
         { k = -1;
           return 0;
         }
     }  
   for(j=0;j<k;j++)
   if(g[j] == f)
      return 1;
   return 0;
}
/*_________________________________________________________________________*/
static struct term * fsubst6(struct term *a,struct term *x, struct context * c1, struct term *b, struct context *c2, struct trail **trp, int mask, int first, int *last)
/* Presumes that x is a constant or Skolem term (in induction proofs)
 and  that a is a variable that does not 
occur in contexts c1 or c2.  Substitute a for occurrences of x in b that are not
subterms of a term with an "induction functor" g, AND are not subterms of any
lambda term.   Presumes that INDUCTION_FLAG
is set, and it looks for a function symbol (of arity 2) "ind" or "induction", or failing that, 
"g". 
   Like fsubst3,  this must return a term that makes sense in 
context c2.   
   The parameter mask is used when backtracking is desired.  A value of 1 for mask 
indicates no backtracking; just substitute for all occurrences of x in b.  But if mask
is nonzero, then number the occurrences of x in b and substitute for those whose 
numbers match the bits of mask.  For example, if mask is (in binary)  001001,  and there
are six occurrences of x,   substitute for the third and sixth occurrences.   
First and *last are used to count the occurrences of x that have been checked.
*/
{ term t, w, ans;
  struct rel *r,*s; 
  struct context *d;
  int next;
  *last = first;
  if(term_ident2(x,b,0))
     { *last = first + 1;
       if( (1 << first) & mask )
          return copy_term(a);
       else
          return copy_term(b);
     }
  if(x->type == VARIABLE && unify(x,c1,b,c2,trp))
     { *last = first+1;
       if( (1 << first) & mask)
          return copy_term(a);
       else
          return copy_term(b);
     }
  if(b->type == NAME)
      return copy_term(b);  
  if(b->type == COMPLEX)
      { if(BINDER(b->sym_num) && VARNUM(ARG0(b))== VARNUM(a) && c1 == c2)
           return copy_term(b);  // should never happen since a doesn't occur in c1, c2.
        if(blocking_functor(b->sym_num))
           return copy_term(b);  // per the specs
        ans = get_term();
        ans->sym_num = b->sym_num;
        ans->type = COMPLEX;
        s = get_rel();
        ans->farg = s;
        r = b->farg;      
        for(r = b->farg; r; r=r->narg)
           { s->argval = fsubst6(a,x,c1,r->argval,c2,trp,mask,first,&next);
             first = next;
             if(r->narg)
               { s->narg = get_rel();
                 s = s->narg;
               }
           }
        *last = next;
        return ans;
      }
  // now b->type == VARIABLE 
  t = c2->terms[b->varnum];
  if(c2->bound[b->varnum])
     return copy_term(b);    // added  6.26.05
  if(!t)
     { if(x->varnum == b->varnum)
         { *last = 1 + first;
           if( (1 << first) & mask)
              return copy_term(a);
           return copy_term(b);
         }
     }
  d = c2->contexts[b->varnum];
  w = fsubst6(a,x,c1,t,d,trp,mask,first,last);
  BIND(a->varnum,c1,w,c2,trp);
  return copy_term(a);
}

/*_________________________________________________________________________*/
struct term * fsubst5(struct term *a,struct term *x, struct context * c1, struct term *b, struct context *c2, struct trail **trp, int mask)
/* Presumes that x is a constant or Skolem term (in induction proofs)
 and  that a is a variable that does not 
occur in contexts c1 or c2.  Substitute a for occurrences of x in b that are not
subterms of a term with an "induction functor" g, AND are not subterms of any
lambda term.   Presumes that INDUCTION_FLAG
is set, and it looks for a function symbol (of arity 2) "ind" or "induction", or failing that, 
"g". 
   Like fsubst3,  this must return a term that makes sense in 
context c2.   
   The parameter mask is used when backtracking is desired.  A value of 1 for mask 
indicates no backtracking; just substitute for all occurrences of x in b.  But if mask
is nonzero, then number the occurrences of x in b and substitute for those whose 
numbers match the bits of mask.  For example, if mask is (in binary)  001001,  and there
are six occurrences of x,   substitute for the third and sixth occurrences.   
*/
{ term t, w, ans;
  struct rel *r,*s; 
  struct context *d;
  int last;
  if(Parms[MAX_UNIFIERS].val != 1)
      return fsubst6(a,x,c1,b,c2, trp, mask,0,&last);
  if(term_ident2(x,b,0))
     return copy_term(a);
  if(x->type == VARIABLE && unify(x,c1,b,c2,trp))
     return copy_term(a);
  if(b->type == NAME)
      return copy_term(b);  
  if(b->type == COMPLEX)
      { if(BINDER(b->sym_num) && VARNUM(ARG0(b))== VARNUM(a) && c1 == c2)
           return copy_term(b);  // should never happen since a doesn't occur in c1, c2.
        if(blocking_functor(b->sym_num))
           return copy_term(b);  // per the specs
        ans = get_term();
        ans->sym_num = b->sym_num;
        ans->type = COMPLEX;
        s = get_rel();
        ans->farg = s;
        r = b->farg;      
        for(r = b->farg; r; r=r->narg)
           { s->argval = fsubst5(a,x,c1,r->argval,c2,trp,mask);
             if(r->narg)
               { s->narg = get_rel();
                 s = s->narg;
               }
           }
        return ans;
      }
  // now b->type == VARIABLE 
  t = c2->terms[b->varnum];
  if(c2->bound[b->varnum])
     return copy_term(b);    // added  6.26.05
  if(!t)
     { if(x->varnum == b->varnum)
           return copy_term(a);
       return copy_term(b);
     }
  d = c2->contexts[b->varnum];
  w = fsubst5(a,x,c1,t,d,trp,mask);
  BIND(a->varnum,c1,w,c2,trp);
  return copy_term(a);
}


/*_______________________________________________________*/

static struct term *apply2(struct term *t,
                   struct context *c)
/* Like McCune's apply, but keeps varnums below MAX_VARS, using next_var */                   
{
  /* dereference if variable */

  /* A NULL context means that the subst was generated by match. */
  /* If the context is NULL, then apply just copies the term.    */

  while (t->type == VARIABLE && c != NULL && c->terms[t->varnum] != NULL) {
    int vn = t->varnum;
    t = c->terms[vn];
    c = c->contexts[vn];
  }

  if (t->type == VARIABLE) {  /* unbound variable */
    struct term *t2 = get_term();
    t2->type = VARIABLE;
    if (c == NULL)
      t2->varnum = t->varnum;
    else
      { t2->varnum = c->next_var;  // here's where apply2 differs from apply
        ++c->next_var;
        if(c->next_var == MAX_VARS)
           abend("Too many variables.");
      }
    return t2;
  }
  else if (t->type == NAME) {  /* name */
    struct term *t2 = get_term();
    t2->type = NAME;
    t2->sym_num = t->sym_num;
    return t2;
  }
  else {  /* complex term */
    struct rel *r1, *r2, *r3;
    struct term *t2;
    int  vv;
    struct term *saveit;
    if(Flags[LAMBDA_FLAG].val && BINDER(t->sym_num))        
        { vv = t->farg->argval->varnum;                     
          saveit = c->terms[vv];                            
          c->terms[vv] = NULL;                            
        }
    t2 = get_term();
    t2->type = COMPLEX;
    t2->sym_num = t->sym_num;
    r3 = NULL;
    r1 = t->farg;
    while (r1 != NULL ) {
      r2 = get_rel();
      if (r3 == NULL)
        t2->farg = r2;
      else
        r3->narg = r2;
      r2->argval = apply2(r1->argval, c);
      r3 = r2;
      r1 = r1->narg;
    }
    if(Flags[LAMBDA_FLAG].val && BINDER(t->sym_num)) // Beeson
        c->terms[vv] = saveit;  // Beeson
    return t2;
  }
}  /* apply2 */

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists