Sindbad~EG File Manager

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

/* M. Beeson, 11.4.03
 Connections between Otter and external simplification routines.
 Communication is via ASCII strings.  Terms are converted to strings
 and all the literals of a clause are passed at once to an external
 simplification function.  The result comes back, again as an array of 
 strings (and an array of signs of the literals), and is converted 
 back to a new Otter clause.  The memory used for both arrays of intermediate 
 strings is freed.

7.1.04  added postProcess
7.24.05 modified postProcess
3.20.06 changed include filenames to lowercase
7.2.06 changed 2 to 1  in line 154
7.20.08  added EXTERNAL_SIMPLIFY
*/
// #define DIAGNOSTICS   // to see diagnostic printout 
#include <stdlib.h>     // calloc and free
#include <assert.h>
#include "header.h"
#include "simplify.h"
#include "externalsimplify.h"
#include "bsym.h"
#include "proto.h"
#include "export.h"
#include "heap.h"
#include "heaps.h"
// #define EXTERNAL_SIMPLIFY   // comment this out to cut the link with MathXpert so it can compile without MathXpert
                            // If you want to supply some other simplification code you can put this back in

static FILE *tfp = NULL;

/*___________________________________________________________*/

void out_of_space(void)
{ abend("Out of space in MathXpert heap: more than one megabyte used for a simplification.");
}  

/*_________________________________________________________________*/
static int needs_translation(struct term *t)
// return 1 if t contains SUM, PRODUCT, LIMIT,  DIFF, or INTEGRAL
{ struct rel *r;
  if(t->type!= COMPLEX)
    return 0;
  if(t->sym_num == SUM || t->sym_num == PRODUCT || t->sym_num == LIMIT ||
     t->sym_num == DIFF || t->sym_num == INTEGRAL
    )
    return 1;
  for(r=t->farg;r;r=r->narg)
     { if(needs_translation(r->argval))
          return 1;
     }
  return 0;
}  
  
/*_________________________________________________________________*/
static struct term *Translate(struct term *t)
// return a completely new term that can shortly be destroyed 
// the term should translate t to the form Mathpert wants to see
// doesn't handle LIMITS, DIFF, or indefinite integrals yet  FINISH THIS
{ struct term *ans;
  struct rel *r, *r2, *r3, *r4;
  if(t == NULL)
     assert(0);
  ans = get_term();
  ans->type = t->type;
  ans->sym_num = t->sym_num;
  ans->varnum = t->varnum;
  if (t->type != COMPLEX)
    return(ans);
  r3 = NULL;
  r = t->farg;
  if(t->sym_num == SUM || t->sym_num == PRODUCT || t->sym_num == INTEGRAL)
     { // switch the first and second arguments 
       r2 = get_rel();
       ans->farg = r2;
       r3 = get_rel();
       r2->narg = r3;
       r3->argval = Translate(r->argval);
       r = r->narg;
       r2->argval = Translate(r->argval);
       r = r->narg;
       if(r == NULL)
          { r3->narg = NULL;
            return ans;
          }
       while(r)
         { r4 = get_rel();
           r3->narg = r4;
           r4->argval = Translate(r->argval);          
           r3 = r4;
           r = r->narg;
         }
       return ans;
     }
  while (r) 
    { r2 = get_rel();
      if (r3 == NULL)
	      ans->farg = r2;
      else
	      r3->narg = r2;
      r2->argval = Translate(r->argval);
      r3 = r2;
      r = r->narg;
    }
  return(ans);
} 

static void postProcess(char *s)
/* change !=  to /=   in s */
/*  and when '+' is followed immediately by '-', replace '+' by ' '.  */
{ char *marker;
  int i;
  for(marker = s; marker[1]; ++marker)
     { if(marker[0] == '!' && marker[1] == '=')
          *marker = '/';
       if(marker[0] == '+')
          { for(i=1;;i++)
               { if(marker[i] != ' ')
                    break;
               }
            if(marker[i] == '-')
                marker[0] = ' ';
          }
     }
}
/*_________________________________________________________________*/
static char * term_str(struct term *in)
/* convert an Otter term to a string */
/* Otter has code to print terms to a FILE * but not directly to a string.
Here we imitate print_term_length in writing the term to a temporary file
and reading it back into a character array.   However, unlike print_term_length,
we do not want to impose a fixed limit on the length of that character array.
The return string is allocated using calloc by this function, so it can be
freed later on.
   A complication is that because Otter-lambda requires bound variables to 
be the first argument,  terms involving SUM, PRODUCT, LIMIT, INTEGRAL, and 
DIFF have to be translated to be readable by Mathpert.  It would be nice
if these translations could be user-specified in list(translations) to support
different external simplifiers.  For now that is done by Translate().   
*/  
{ int i;
  // int c;
  int length;  // the length of the term as a string
  fpos_t Length;
  char *s;     // will be allocated as soon as we know length.
  int translation = needs_translation(in);
  struct term *t = translation ? Translate(in) : in;
  if (!tfp)
    tfp = tmpfile();
  rewind(tfp);
  print_term(tfp, t);
  // print_term_nl(stdout,t);  DEBUG
  fprintf(tfp, "%c", '\0');  /* end marker */
  fgetpos(tfp,&Length);
   // Length is 64 bits long, but according to the definition of fpos_t in stdio.h, 
   // depending on the target platform it could be a 64 bit int 
   // or a structure type. Hence the following complicated line of code: 
  // c =  *((int *)(&Length) + 1);  // high bits of Length.    */
  // But this code doesn't work right on Unix.  So, let's forget the whole idea of checking c
  
  fflush(tfp);
  rewind(tfp);
  // if(c)
  //     abend("term too big, or other error, in calling external simplification.");
  length = * ((int *)(&Length));
  s = calloc(length,sizeof(char));
  if(!s)
     abend("term too big, or other error, in calling external simplification.");
  for (i = 0, s[i]=getc(tfp); s[i] ; s[++i]=getc(tfp));
  if(translation)
     zap_term(t);
  postProcess(s);     // change != to /=
  return s;
}  
/*_________________________________________________________________*/
  static void set_vars_clause(struct clause *ans)  
 // fill in the t->varnum fields everywhere, consistently. 
 // similar to set_vars  but that only works on one term at a time.      
 { char *varnames[MAX_VARS];   
   struct literal *L;
   memset(varnames,0,MAX_VARS * sizeof(char *));
   for(L=ans->first_lit;L;L=L->next_lit)
       set_vars_term(L->atom,varnames);
 }
   
/*_________________________________________________________________*/
struct clause * Simplify(struct clause *c)
/* call an external simplification function (from Mathpert, for example) to 
simplify each literal in the clause.   While simplifying each literal,
the external routine should assume the negations of the other literals.
If there was any simplification, it returns the new clause, leaving the 
old clause unmodified, and adds 'SIMPLIFY_RULE' to the justification list.
If there was no simplification to be done it returns NULL.

Example 1: if the input clause is a unit 
clause f(sqrt(a^2)) = g(a),  then it would simplify to  f(a) = g(a) |  a < 0,
since the side condition for simplifying sqrt(a^2) to a is a >= 0, so we 
add the negation of that condition to the output clause.  

Example 2: If the input clause is  sqrt(a^2) != a,   then  it simplifies to a != a | a < 0, 
which in turn simplifies to a < 0.  Hence if a >= 0 is already deduced, after
the Simplify step is complete one more step will finish the proof.

Example 3:
if the input clause is  sqrt(a^2) = a | a < 0,
then the negation of a < 0 (namely a >= 0) is assumed before simplifying sqrt(a^2) = a,
so it simplifies to true. Then true | a < 0 is true, so the entire clause becomes
true and is dropped.  This is correct as it contains no information beyond what
simplify can supply.   The same is true if sqrt(a^2) = a simplifies to a >= 0;
then again the clause simplies to true.

Example 4: 
if the input clause is sqrt(a^2) = a,  then it simplifies to a >= 0 and this is 
returned.  This is a DIFFERENT RULE of simplification than just sqrt(a^2) = a 
if a >= 0,  as it also contains the information that sqrt(a^2) = a is false when a < 0.
If we only had the latter simplification rule (i.e. leaving open the possibility
that sqrt(a^2) might = a when a is negative)  then simplify would yield 'true'
with the assumption a >= 0.  The new clause is then true | a < 0  which is true.
This may not look right at first but it is:  it means,  if you can derive
a contradiction from 'true', then you can derive one from sqrt(a^2) = a.
Look how this works:  if we also had a < 0,  we'd be able to get a contradiction 
using the first rule [that sqrt(a^2) = a reduces to a >= 0],
proving the theorem that if a < 0 then sqrt(a^2) != a.  
But using the second rule, we would not be able to finish the proof, which is correct.

Domains:  we need to assume the domain of the clause throughout.  Then, at the end,
we need to add back in the negations of the literals whose conjunction is the domain.
Some of those assumptions might be 'or' terms; that will cause trouble in bringing the
output to clausal form.

*/
{ struct int_ptr *p1,*q1;
  int err = 1;
  int p = 0;
  int nlits = 1;
  char **lits, **NewLits;
  int i,nNewLits;
  struct literal *L, *last_lit;
  struct clause *ans;
  char *signs, *newSigns;
  static int nospace_flag = 0;
  if(!nospace_flag)
     set_nospace_handler(out_of_space);
  if(!c->first_lit) 
     return 0;
  for(L=c->first_lit;L->next_lit;L=L->next_lit) 
     ++nlits;
  lits = (char **) calloc(nlits, sizeof(char *));
  signs = (char *) calloc(nlits, sizeof(char));
  for(i=0,L=c->first_lit;L;L=L->next_lit,++i)
      { lits[i] = term_str(L->atom);     // prepare strings to pass to external simplifier
        signs[i] = L->sign;
      }
  if(i != nlits)
     assert(0);
  nNewLits = 100 + nlits;
  NewLits = (char **) calloc(nNewLits,sizeof(char*));
  newSigns = (char *) calloc(nNewLits, sizeof(char));
#ifdef DIAGNOSTICS
  for(i=0;i<nlits;i++)   // use this if you need to see output before ExternalSimplify runs
    fprintf(stdout,"Simplifying: %s\n", lits[i]);
#endif  
#ifdef EXTERNALSIMPLIFY
  err = ExternalSimplify(nlits,lits,signs, &nNewLits,NewLits,newSigns); // call external simplification code
#endif   
#ifdef DIAGNOSTICS
  if(err)
     { for(i=0;i<nlits;i++)
        { fprintf(stdout,"Did not simplify:  %s\n", lits[i]);
        }
     }
  if(!err && nlits == nNewLits)
     { for(i=0;i<nlits;i++)
        { if(signs[i]) 
             fprintf(stdout,"Simplifying: %s\n", lits[i]);
          else  
             fprintf(stdout,"Simplifying: -(%s)\n", lits[i]);
          if(newSigns[i]) 
             fprintf(stdout,"To         : %s\n", NewLits[i]);
          else
             fprintf(stdout,"To         : -(%s)\n", NewLits[i]);
        }
     }
  else if(!err)
     { for(i=0;i<nlits;i++)
          { if(signs[i]) fprintf(stdout,"Simplifying: %s\n", lits[i]);
            else         fprintf(stdout,"Simplifying -(%s)\n", lits[i]);
          }
       for(i=0;i<nNewLits;i++)
          { if(newSigns[i]) fprintf(stdout, "To         : %s\n", NewLits[i]);
            else fprintf(stdout, "To         : - (%s)\n", NewLits[i]);
          }
     }
#endif    
  for(i=0;i<nlits;i++)
     free(lits[i]);    // allocated by term_str before the call to ExternalSimplify
  free(lits);
  free(signs);
  if(err == -1)
     abend("Malloc could not allocate memory for the MathXpert heap.");
  if(err)
     return NULL;  // no simplification;
  // simplification succeeded
  // construct new clause
  ans = get_clause();
  ans->first_lit = NULL;  // in case nNewLits == 1 and the only literal is 'false'  
  for(i=0;i<nNewLits;i++,L = L->next_lit)
     { while( i<nNewLits && 
              (
                (!strcmp(NewLits[i],"false") && newSigns[i] == 1) ||
                (!strcmp(NewLits[i],"true") && newSigns[i] == 0)
              )
            )
           ++i;
       if(i==nNewLits)
           break;
       L = get_literal();
       if(i==0)
          ans->first_lit = L;
       else
          last_lit->next_lit = L;
       last_lit = L;
       L->sign = newSigns[i];
       p = 0;
       L->atom = str_to_term(NewLits[i],&p,0);
       if(L->atom == NULL)
          assert(0);
       L->atom->occ.lit = L;
       L->container = ans;
       if(L->atom->sym_num == NE)
          { L->atom->sym_num = '=';
            L->sign = L->sign ? 0 : 1;
          }
       if (L->atom->sym_num == '=')
           { L->atom->varnum = L->sign ? POS_EQ : NEG_EQ;   
             // vital, or it won't be indexed for use by paramodulation
           }
       else
           L->atom->varnum = NORM_ATOM;
     }
  set_vars_clause(ans);  // fill in the t->varnum fields everywhere, consistently.
  // Finally, add SIMPLIFY_RULE to the list of justifications for this new clause     
  ans->parents = get_int_ptr();
  // Now copy c->parents
  q1 = ans->parents;
  for(p1 = c->parents; p1; p1 = p1->next)
     { q1->i = p1->i;
       q1->next = get_int_ptr();
       q1 = q1->next;
     }
  q1->i = SIMPLIFY_RULE;  // Now add SIMPLIFY to the list of justifications
  q1->next = get_int_ptr();
  q1->next->i = c->id;
  q1->next->next = NULL;  
  free(NewLits);
  free(newSigns);
#ifdef DIAGNOSTICS  
  fprintf(stdout,"Input to Simplify\n");  // DEBUG
  print_clause(stdout,c);  // DEBUG
  fprintf(stdout,"Simplified Otter clause:\n");  // DEBUG 
  print_clause(stdout,ans); // DEBUG
#endif   
  return ans;  // success
} 

/*_________________________________________________________________*/
int SimplifyInPlace(struct clause *c)
/* Like Simplify, but in case there is simplification to be done,
it replaces the literals of *c with the new literals and appends
SIMPLIFY_RULE to the list of justifications of c,  rather than 
using a new clause and list of justifications. Return 0 if 
some simplification took place, and 1 if no simplification took place.
*/
{ struct clause *ans; 
  struct literal *l;
  struct int_ptr *p,*q;
  ans = Simplify(c);
  if(!ans)
     return 1;
  // should decrease reference counts of the literals in c 
  for(l=ans->first_lit;l;l=l->next_lit)
     l->container = c;
  c->first_lit = ans->first_lit;
  p = c->parents;
  if(p == NULL)
     { c->parents = get_int_ptr();
       c->parents->i = SIMPLIFY_RULE;
       c->parents->next = NULL;
     }
  while(p->next)
     { q = p;
       p = p->next;
     }
  p->next = get_int_ptr();
  p->next->i = SIMPLIFY_RULE;
  p->next->next = NULL;
  return 0;
 }
/*_____________________________________________________________________*/

struct clause *Solve(struct clause *c)
// similar to Simplify,  but tries to find a value of the variables
// return NULL if clause can't be solved.  Otherwise return a new 
// clause, leaving c undisturbed.
{   struct clause *ans;
    ans = c;  // stub for now
    return ans;
}

/*_____________________________________________________________________*/

int  SolveInPlace(struct clause *c)
// similar to Simplify,  but tries to find a value of the variables
// puts the solved clause where c was, destroying old literals.
// Return 0 for success, 1 for failure to solve.
{   struct clause *ans;
    ans = c;  // stub for now
    return 1;
}

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