[net.sources] C Inference

tools@raybed2.UUCP (TOOLS) (01/27/86)

As requested by the author we are reposting the source and documentation of
a C inference engine. Address all questions to George Hageman at:
UUCP: {asgb!benish}!hageman
MAIL:	George W. Hageman
	P.O. Box 11234
	Boulder, Colorado  80301
NOTE: RAYTHEON Inc. is not reponsible for the contents and/or consequences
of use of this software. This software is totally the work of George Hageman
and is being reposted as per his request (see following message). Address all
questions, comments, etc. to him.
=========================================================================
>From linus!decvax!seismo!hao!asgb!benish!hageman Fri Jan 24 07:31:04 1986
>Subject: Re:  C inference engine
>
>	... it seems that
>	the probability of getting somthing out to net.and is
>	inversely proportional to the number of hops it has to go.
>
>	I'll send you all of the shars (inference rulecompiler and 
>	the storm expert).  If you could make sure that they are
>	available at your site either by reposting them from your
>	end or by some other means it would be appreciated.
>
>	Thanks,
>
>George [Hageman]
=========================================================================
-------------------------CUT HERE----------------------------------------
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	inference.doc
sed 's/^X//' << 'SHAR_EOF' > README
XFrom linus!decvax!decwrl!pyramid!ut-sally!seismo!hao!asgb!hageman Tue Dec 31 15:31:49 1985
XRelay-Version: version B 2.10 5/3/83; site raybed2.UUCP
XPosting-Version: version B 2.10.2 9/18/84; site asgb.UUCP
XPath: raybed2!linus!decvax!decwrl!pyramid!ut-sally!seismo!hao!asgb!hageman
XFrom: hageman@asgb.UUCP (George W. Hageman)
XNewsgroups: net.sources
XSubject: Inference engine documentation
XMessage-ID: <831@asgb.UUCP>
XDate: Tue, 31-Dec-85 15:31:49 EST
XArticle-I.D.: asgb.831
XPosted: Tue Dec 31 15:31:49 1985
XDate-Received: Wed, 1-Jan-86 20:25:24 EST
XDistribution: na
XOrganization: Burroughs Corp. ASG, Boulder Colo.
XLines: 1201
X
XThe following is the documentation file for an inference engine
Xwritten in C.   There will be  three other submittals to net.souces
Xconsisting of the source for a rule compiler, inference engine, and,
Xa weather prediction expert rule base including an animals expert.
X
XHave fun....
X
X-----------------------  Cut Here -----------------------------
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > inference.doc
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        INTRODUCTION: 
X
X        The  software contained in this distribution is copyright (C)  by 
X        George   Hageman   1985   and  is  released   into   the   public               
X        domain with the following restrictions:                         
X
X             (1)   This  software  is intended  for  non-commertial usage.                                              
X             (2)    I   am   held  save  from  damages   resulting   from               
X             its use, and
X             (3)   The following concepts and legal jargon are agreed  to 
X             by the user of this software.
X
X             User-supported software concept:
X
X                  IF          you find use for this software
X                  ANDIF       it saves you some development time
X                  THEN            send me $10.00
X                  ANDTHENHYP      you will feel good!
X
X        This source code is provided on an "as is" basis without warranty 
X        of any kind,  expressed or implied,  including but not limited to 
X        the  implied  warranties  of merchantability and  fitness  for  a 
X        particular   purpose.    The  entire  risk  as  to  quality   and 
X        performance  of this software is with you.   Should the  software 
X        prove  defective,  you  assume the entire cost of  all  necessary 
X        repair, servicing, or correction.  In no event will the author be 
X        liable to you for any damages,  including any lost profits,  lost 
X        savings, or other incidental or consequential damages arising out 
X        of  the   use  of inability to use this software.   In  short  my 
X        friends,  I  have done  a reasonable amount of work in  debugging 
X        this  software and I think it is pretty good but,  as  you  know, 
X        there  is always some chance that a bug is still lurking  around. 
X        If you should happen to be lucky enough to  find one,  please let 
X        me know so I    can make an attempt to fix it.          
X
X             The  following  is  a short description of how  to  use  the 
X        inference  engine  and rule-compiler contained in  this  software 
X        release.    The source and object files for the rule compiler and 
X        the inference engine are contained in the rcomp.lbr and infer.lbr 
X        respectively.   There are common files contained in each library.  
X        These  common  files  are header files which are used  to  define 
X        common terms between the different sources.    The most important 
X        header file is the file named "expert.h" which not only  contains 
X        common  definitions  used  between  the  rule  compiler  and  the 
X        inference  engine,  but has a short description of their usage as 
X        well.    This inference engine, and its associated rule compiler, 
X        represents  a  significant  time investment for  me,  so  if  you 
X        believe in the  shareware concept please remember my address.
X
X                            George W. Hageman
X                            P.O. Box 11234
X                            Boulder, Colorado  80301
X
X
X
X
X
X        George W. Hageman            --1--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X             This  software compiles using the Microsoft C  Compiler  Rev 
X        3.0  using the make function which comes with the Microsoft Macro 
X        Assembler Rev.  4.0.  I have nothing but good things to say about 
X        these  two products and suggest that you consider their  purchase 
X        if  you are into serious software development for the  PC.   This 
X        software  also compiles and runs under UNIX system  V.   Use  the 
X        UNIXSV  flag  in the makefile or use a -DUNIXSV when you  compile 
X        it.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --2--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        INFERENCE ENGINES:
X
X             An  inference engine is merely a program which  attempts  to 
X        prove consequents given a certain set of antecedents and a set of 
X        rules  which define the TRUTH or FALSEness of each consequent  in 
X        terms  of the antecedents.     The consequents,  antecedents  and 
X        rules  for  this  inference engine are contained in a  text  file 
X        which is compiled by the rule-compiler into a form the  inference 
X        engine  can understand.   Often these two functions are contained 
X        in the same executeable,  but I have decided to split them up  to 
X        make the inference engine as small as possible.
X
X             Rules  are collections of ANTECEDENTS and CONSEQUENTS formed 
X        into  TRUTH statements.   Each rule is an attempt state that  "If 
X        all of the antecedents for this particular RULE are  TRUE,   then 
X        all  of the consequents connected to this rule are TRUE.   If one 
X        or  more  of the antecedents for a RULE are  FALSE,  then  it  is 
X        assumed that this rule cannot prove the TRUTH of the consequents, 
X        but  this does not necessarily prove the consequents FALSE  since 
X        some  other rule may prove them TRUE."  Rules must have at  least 
X        one  ANTECEDENT  and  at least one CONSEQUENT  to  be  considered 
X        valid. 
X
X             Each   ANTECEDENT  and  CONSEQUENT  is  a  simple  statement 
X        consisting  of  a  leading  KEYWORD,   and  a  FOLLOWING  STRING.  
X        KEYWORDS tell the inference engine what the FOLLOWING STRING will 
X        mean or what is to be done with it.  The FOLLOWING STRINGs may be 
X        either  in upper or lower case and are either statements such  as 
X        "THE  ANIMAL IS A BAT",  or,  a pathname to an executeable  which 
X        will  be loaded and executed depending on what is defined by  the 
X        KEYWORD. Strings, except for the number of leading blanks, can be 
X        considered equal only if they are identical.  The reason for this 
X        rule  will  become  apparent later.   An example  of  a  pathname 
X        FOLLOWING STRING is "/b1/hageman/expert/storm/gt_3200  data.fil".  
X        Note  that  the strings denoting pathnames should be  exactly  as 
X        they  would  be if the pathname were to be given at  a  terminal, 
X        also,  you  may  include  parameters with  any  pathname.   These 
X        parameters  are no different than the parameters that  you  would 
X        use  if  you  were initiating the executeable from  the  terminal 
X        rather than via the inference engine.    Under MS_DOS these  path 
X        names  can  either  be  upper or lower case,  and  for  the  UNIX 
X        operating system, they must correspond to the exact path name.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --3--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        QUICK AND DIRTY:
X
X             Impatient?   Well  here  are some quick ways to get  started 
X        with the inference engine,  leave all that reading till later!
X
X        ONE:
X
X             Use  your  text  editor (WS in the  Non-document  mode  only 
X        Please) to create a quick rule file,  or use the animals  example 
X        contained in this release.   Skip to the next page if you want to 
X        find out what the KEYWORDS are and how to use them.
X
X        TWO:
X
X             Compile the rules with the rule-compiler by typing..
X
X             rulecomp inputfile outputfile 
X
X             where  the inputfile is the filename of the file  containing 
X        your  rules,  and the outputfile is the file inwhich you want the 
X        compiled rules to be written to.  Caution, the rule compiler does 
X        not  check  for the equivalence of the inputfile  and  outputfile 
X        filenames,   if they are identical you will probably have to type 
X        in your rules again.
X
X        THREE:
X
X             Run the inference engine by typing ..
X
X             inference outputfile
X
X             answer the questions and go back to step ONE if you found an 
X        error with your rules or you want to expand them.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --4--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        KEYWORDS:
X
X             The  following are the KEYWORDS which the rule compiler  can 
X        recognize,  and  a short description of what each means  and  how 
X        each  would be used.    Note that the members of each group  have 
X        identical meaning and can therefore be substituted for each other 
X        without  effecting the sense of the rule.   Latter examples  will 
X        attempt to demonstrate this fact.
X
X
X
X        IF, AND, ANDIF:
X
X             These KEYWORDS define the FOLLOWING STRING as an ANTECEDENT, 
X             and  the TRUTH sense of the string is TRUE if the string  is 
X             TRUE.    These  KEYWORDS can be used interchangeable without 
X             effecting the sense of the rule being expressed.
X
X                  Example:
X
X                       IF the animal is a mammal
X                       ANDIF the animal has hooves
X                       AND the animal has horns         
X
X                  This is equivalent to:
X
X                       AND the animal is a mammal
X                       IF the animal has hooves
X                       ANDIF the animal has horns
X
X             Note that since the antecedent part of a rule is essentially 
X             a  large AND statement,  the order in which  the  individual 
X             statements  are  arranged  is a matter  of  esthetics  only.  
X             However,  it may be more readable to the human, if a certain 
X             order is maintained.
X
X        IFNOT, ANDNOT
X
X             These  KEYWORDS  are  essentially  identical  to  the  above 
X             KEYWORDS except that the sense of the statement is reversed.   
X             That is to say that if the following string is TRUE then the 
X             truth   value   of   the  statement  is  FALSE.              
X
X                  Example:
X
X                       IFNOT the animal is a mammal
X                       ANDNOT the animal has smooth skin
X                       ANDNOT the animal breaths air
X                       THEN animal is a fish 
X
X
X
X
X
X
X
X
X        George W. Hageman            --5--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        IFRUN, ANDRUN, ANDIFRUN
X
X             These KEYWORDS tell the inference engine that the  FOLLOWING 
X             STRING is to be used as a pathname to an executeable.   This 
X             executeable  is to be loaded and run and the resultant TRUTH 
X             value returned when the routine exits is the TRUTH value  of 
X             the ANTECEDENT statement.   Like the AND, IF, ANDIF KEYWORDS 
X             above,  each  of  these  may be substituted for any  of  the 
X             others  without effecting the sense of the  rule  statement.   
X             Note  that  the  full path name of the  executeable  is  not 
X             needed  if  the  executeable  file resides  in  the  working 
X             directory from which the inference engine was initiated.
X
X                  Example:
X
X                       IFRUN /b1/hageman/expert/gt3000
X                       ANDRUN /b1/hageman/expert/sedir direction.dat
X                       ANDIFRUN falling barompress
X                       THEN sorry about the picnic
X               
X        IFNOTRUN, ANDNOTRUN     
X
X             These are used as the KEYWORDS above are used -- to initiate 
X             the execution of an ANTECEDENT executeable file, except that 
X             the truth value of the result is reversed as with the IFNOT, 
X             ANDNOT and the ANDIFNOT KEYWORDS.
X
X                  Example:
X                       
X                       IFNOTRUN gt3000
X                       ANDNOTRUN sedir direction.dat
X                       ANDNOTRUN falling barompress
X                       THEN how about a picnic?
X         
X        THEN, ANDTHEN, THENHYP, ANDTHENHYP    
X
X             These KEYWORDS tell the inference engine that the  FOLLOWING 
X             STRING  is  a  CONSEQUENT.     If  all  of  the  immediately 
X             proceeding ANTECEDENTS have a truth value of TRUE,  then the 
X             inference  engine INFERS that the CONSEQUENT is  TRUE.   The 
X             THEN KEYWORDS ending in "HYP" tell the inference engine that 
X             the  FOLLOWING STRING is an ending CONCLUSION and no further 
X             processing  or inferencing is required.   The  routine  will 
X             exit  when one of the THENHYP or ANDTHENHYP CONSEQUENTS  are 
X             proven   TRUE.     Therefore,   one  should  use  the  "HYP" 
X             CONSEQUENT KEYWORDS with care. 
X
X                  Examples:
X
X                       IF you have an aunt
X                       ANDIF your aunt has a child
X                       THEN you have a cousin
X
X                       IF you have a cousin
X                       THENHYP you have at least two relatives
X
X
X        George W. Hageman            --6--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        THENRUN, ANDTHENRUN, THENRUNHYP, ANDTHENRUNHYP 
X
X             These are similar to the THEN,  ANDTHEN etc. KEYWORDS except 
X             they  perform  the  loading and execution of  the  FOLLOWING 
X             STRING  path  name  if they  are  proven  TRUE.   The  value 
X             returned  by  the executeable file loaded becomes the  value 
X             remembered  for  the  CONSEQUENT.   The truth  value  for  a 
X             CONSEQUENT proceeded with the KEYWORDS of THEN or ANDTHEN is 
X             only remembered if it is proven TRUE.  However, with the RUN 
X             type of CONSEQUENT since it is initiated only when found  to 
X             be proven, the predicate value it returns is remembered even 
X             if  it is FALSE.  This prevents the rerunning of  CONSEQUENT 
X             routines.  
X
X             In this manner one can use rules to determine weather or not 
X             a particular routine should be executed,  then use the truth 
X             value  returned  by the routine upon its exit in other  rule 
X             statements.   An obvious use for such a function would be in 
X             the field of diagnostics.   Through a set of rules it  could 
X             be  determined  that a particular diagnostic should be  run,  
X             once  the diagnostic has been run,  further rules could  use 
X             the  fact  of whether the diagnostic test passed  (TRUE)  or 
X             failed (FALSE) to make decisions about the further isolation 
X             of the hardware failure.
X
X                  Example:
X                       
X                       !
X                       IFNOTRUN isdev1
X                       IFNOTRUN isdev2
X                       IFNOTRUN isdev3
X                       THENHYP there are no devices to run diagnostics on
X                       !     
X                       ! see note below for the following rule
X                       !
X                       IF isdev1
X                       ANDIFRUN dev1diag
X                       THENHYP device one is faulty
X                       !
X                       IFRUN isdev2
X                       ANDIFRUN dev2diag
X                       THENHYP device two is faulty
X                       !
X                       IFRUN isdev3
X                       ANDIFRUN dev3diag
X                       THENHYP device three is faulty
X                       !
X                       IFNOTRUN dev1diag
X                       IFNOTRUN dev2diag
X                       IFNOTRUN dev3diag
X                       IFRUN isdev1
X                       ANDRUN isdev2
X                       THENRUN diag12
X                       !
X                       !
X
X
X        George W. Hageman            --7--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X                       !
X                       IFRUN diag12
X                       THENHYP device two is suspect remove and re-run test
X                       !
X                       IFNOTRUN diag12
X                       THENHYP device one is suspect, remove and re-run test 
X                       !
X
X             Note:
X
X             You   have  probably  noticed  that  the  FOLLOWING  STRINGS 
X             associated  with  the  RUN KEYWORDS and  the  IF,  AND  etc. 
X             KEYWORDS are interchangeable.   This is due to fact that the 
X             TRUTH  of  a  string is kept as a pointer  into  the  string 
X             buffer,  and therefore have no information concerning  their 
X             nature and only have meaning when used in conjunction with a 
X             KEYWORD.  If you are sure that the string "isdev1" will have 
X             its   truth  determined  earlier  by  running  the   routine 
X             "isdev1",   Then you may use it as a regular string in later 
X             rules,  however,  if its truth has not been determined  then 
X             the  inference  engine  will ask you for the  truth  of  the 
X             statement  "isdev1" rather than running the routine.   To be 
X             sure  use  the "RUN" form for the strings  which  relate  to 
X             executeables,   they will only be run once as it is,  so you 
X             don't really have to keep them straight.
X
X                  Notice also that if the first rule is not proved by the 
X             fact  that  isdev1  turns up being TRUE  and  therefore  the 
X             antecedent  statement  is FALSE due to the reverse sense  of 
X             the IFNOTRUN KEYWORD,  then the others will not be run until 
X             they are encountered in other rules containing them.   So be 
X             safe and use the RUN forms of the KEYWORDS if you intend the 
X             execution of an object.
X         
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --8--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        USAGE:
X
X             Ok,  now  that we know what all the key words are,  how does 
X        one go about using an inference engine, and more specifically how 
X        does one use this inference engine and what for?  
X             
X             People  usually use inference engines  as part of  what  are 
X        known  as expert systems.   Expert systems are a study associated 
X        with  a  branch  of  software  engineering  known  as  Artificial 
X        Intelligence (AI).    (I am probably going to get some heat  from 
X        that  statement).    Expert systems are supposed to mimic the way 
X        in which human experts deal with a particular physical or  mental 
X        problem.    A  clear  example  is an expert  system  which  could 
X        isolate  a  fault within a complex computer system as well as  or 
X        almost  as well as its human counterpart.    It is apparent  that 
X        the  computer  expert  system  would lack  much  of  the  tactile 
X        resources  the human expert would have,  but the computer  expert 
X        could still be of great value when coupled with a novice computer 
X        user.    In  this way the computer expert would rely on the human 
X        to  perform  actions  and observations  the  computer  expert  is 
X        incapable  of  doing.   The computer expert and the  novice  then 
X        could form a team which might perform as well as the human expert 
X        alone and at a probably much lower per/hour labor rate.
X
X             Unfortunately,  in  order to develop an expert  system,  one 
X        must  either  be  an expert in the area one wants to  develop  an 
X        expert system for or have a ready access to one.   Assuming  that 
X        you are or have found one,  the following is a description of how 
X        one  would  use  the inference engine and the  rule  compiler  to 
X        produce an expert system.    Fortunately one of the sticker tasks 
X        of  developing  the inference engine has been done,  and all  you 
X        have  to do is develop the rule base,  compile it with  the  rule 
X        compiler  and  use  the resultant compiled rule-base  file  as  a 
X        parameter  when  you initiate the inference engine.   In  reality 
X        this is a much tougher job than developing the inference engine.
X
X             Expert   systems  generally  consist  of  three  parts,    a 
X        KNOWLEDGE BASE,  HUMAN INTERFACE,  and an INFERENCE ENGINE.   The 
X        following is a short description of each:
X
X        THE RULE or KNOWLEDGE BASE:
X
X             The  rules  consisting of ANTECEDENTS  and  CONSEQUENTS  are 
X        known  as  the  "KNOWLEDGE  BASE"  of  the  expert  system.    An 
X        additional part of the KNOWLEDGE BASE consists of the executeable 
X        files  and  their  shared data files.   The  way  the  "knowledge 
X        engineer"  puts  these rules together determines how good  and/or 
X        effective  the resultant expert system becomes.    The  KNOWLEDGE 
X        BASE  is the smarts of the expert system,  and the basic data  on 
X        which the inference engine is to operate upon.
X
X
X
X
X
X
X
X        George W. Hageman            --9--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        THE HUMAN INTERFACE:
X
X             The  expert system needs a way to ask the human  user  about 
X        the  TRUTH or FALSENESS of the antecedents contained in the  rule 
X        base.   This  is  contained  as a part of  the  inference  engine 
X        associated with this release.    These routines will ask the user 
X        whether or not FOLLOWING STRINGS are TRUE or FALSE.    Additional 
X        human interfaces may be contained in the executeable files.
X
X        THE INFERENCE ENGINE:
X
X             The inference engine released with this software is known as 
X        a backwards chaining inference engine.    It works by identifying 
X        consequents  and  attempting  to find rules to  prove  that  each 
X        consequent  is TRUE.   Once a consequent is proved  TRUE,  it  is 
X        remembered  as being TRUE.    Each antecedent which is determined 
X        either TRUE or FALSE is remembered so that the user does not have 
X        to  be  asked more than once to verify  a  particular  statement.  
X        Remember  that if a consequent is not proved TRUE,  then it  does 
X        not  necessarily  mean that it is FALSE.    For more  information 
X        consult  the "inference.str" file which is a  preliminary  pseudo 
X        code  description  of the inference engine.   It is  not  correct 
X        because   I  have  not  gone  back  and  up  dated  it  from  the 
X        implementation effort (Tom De Marco please forgive me) but, it is 
X        close  enough to provide a basis for understanding the  code.   I 
X        suggest  looking  at the code to understand  how  this  inference 
X        engine  works.    I have also left in all of the debug statements 
X        which I found helpful so by modifying the makefile to include the 
X        DEBUG FLAGS, you can observe the inference engine working.
X
X             This   inference  engine  attempts  to  prove  all  of   the 
X        consequents  from the top of the rule base through to the  bottom 
X        in a linear way if possible.  If however, an antecedent is really 
X        a  consequent  of a rule,  the inference engine will  attempt  to 
X        prove  that consequent even if it occurs later in the rule  base.  
X        In  this sense,  the inference engine will exhibit  some  forward 
X        chaining characteristics.
X
X             There  are  several good books on the development of  expert 
X        systems,  inference  engines  and the like.   I have  included  a 
X        bibliography  which contain the books I consulted to  build  this 
X        one.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --10--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        BUILDING EXPERT SYSTEMS:
X
X             The  builders  of  expert systems  are  sometimes  known  as 
X        "knowledge engineers".    As the name implies, they deal with the 
X        manipulation  and  representation  of knowledge  leading  to  the 
X        development  of the Knowledge base the inference engine  operates 
X        upon.    In  order  to develop the knowledge base  the  knowledge 
X        engineer  needs either to be an expert in the area for which  the 
X        expert system is to be developed or, have ready access to a human 
X        expert in the field.   
X
X             The  inference engine in this distribution accepts knowledge 
X        in  many  ways.   The first of which are the rules  as  discussed 
X        above which are relatively simple logical or predicate statements 
X        about the TRUTH of well defined consequents.    The other is  the 
X        somewhat  complex  knowledge representation as contained  in  the 
X        executeable files which may be initiated by the inference engine.  
X        In  fact,  the inference engine and the rule_compiler each can be 
X        one  of these executeable files so you can have recursive  expert 
X        systems  if  you  have a mind to!    You  can  even  use  another 
X        executeable  to produce a text file of rules,  which then can  be 
X        operated  on  by  the  rule-compiler  and  then  fed  to  another 
X        inference  engine  producing  self-modifying or  learning  expert 
X        system.   So even though the inference engine is only 12K and the 
X        rule  compiler 10K these are sufficient enough to produce  rather 
X        powerful expert systems.
X
X             To  develop the knowledge base the knowledge engineer  first 
X        must  under  stand  the limitations which are acceptable  to  the 
X        expert  system  user.   For example,  if the user  of  an  animal 
X        identification  expert  system is not concerned with whether  the 
X        expert  can  differentiate  between a snake and a  lizard  or  is 
X        not interested in reptiles at all,  then the expert system can be 
X        simplified  by leaving out this knowledge.    Once the boundaries 
X        of  an expert system are well known,  the expert system  designer 
X        can concentrate on how to define the particulars.   This software 
X        release  contains  two examples of simple  expert  systems.   The 
X        first is the more or less classical animal identification expert, 
X        and  the second is a weather predictor expert which  demonstrates 
X        the usage of the IFRUN, ANDTHENRUN, etc. KEYWORDS.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --11--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        ANIMALS:
X
X             This is a simple expert which can differentiate between only 
X        certain  types of animals -- Mammals and Birds.   And among these 
X        two groups it can only tell you that the animal you are  thinking 
X        about  is  either  a  Giraffe,  Zebra,  Cheeta,  Tiger,  Penguin, 
X        albatross,  Duck,  and  so on.   The example has been limited  to 
X        these  few  identifications  in  order to  greatly  simplify  the 
X        development  effort  and  to help  demonstrate  the  strategy  of 
X        developing the rules associated with this simple expert system.
X
X             The strategy associated with the development of a consistent 
X        set  of  rules  which  will identify a  particular  animal  given 
X        certain  physical  characteristics  to work with  is  DIVIDE  AND 
X        CONQUER.    The  idea being to use rules which build  a  decision 
X        tree  where each branch of the tree is formed by a rule which can 
X        decide  which direction to go at that junction.    Since  we  are 
X        obviously  dealing  with birds and mammals then we can build  our 
X        root  branch  or  the  grossest division  as  a  rule  which  can 
X        differentiate between birds and mammals.   Like:
X                  
X                  !
X                  IF animal gives milk
X                  ANDIF animal has hair
X                  THEN animal is mammal
X                  !
X                  IFNOT animal is mammal
X                  THEN animal is bird
X                  !
X                  .
X                  .
X
X             Notice  that if the animal is not a mammal we  automatically 
X        assume  that it is a bird since this is the domain of our  expert 
X        system  -- it  does not consider any other type of  animal  as  a 
X        possibility.   If  we  were to include perhaps reptiles then  the 
X        following might be used instead:
X
X                  !
X                  IF animal gives milk
X                  ANDIF animal has hair
X                  THEN animal is mammal
X                  !
X                  IFNOT animal is mammal
X                  AND animal has feathers
X                  AND animal lays eggs
X                  THEN animal is bird
X                  !
X                  IFNOT animal is mammal
X                  IFNOT animal is bird
X                  THEN animal is reptile
X                  !
X
X
X
X
X
X        George W. Hageman            --12--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X             Again  the last category is the default and needs no further 
X        definitions  because it is within the limitations of  the  expert 
X        system.
X
X
X             Further  refinement of the decision tree associated with the 
X        animals  expert should build on the knowledge gained  by  earlier 
X        branching.   So  one should use the knowledge that the animal has 
X        been  identified  as a bird to further  define  the  animal.   An 
X        example of the further definition of the type of mammal follows:
X
X                  !
X                  IF animal is mammal
X                  ANDIF animal eats meat
X                  ANDIF animal eats little vegetation
X                  THEN animal is carnivore
X                  !
X                  IFNOT animal is carnivore
X                  ANDNOT animal eats little vegetation
X                  THEN animal is vegetarian
X                  !
X
X             Finer  and  finer branching is achieved by this  divide  and 
X        conquer strategy until the leaves of the tree are reached,  These 
X        leaves  are  the  actual hypothesis which end the  search  for  a 
X        particular animal.  
X
X                  .
X                  .
X                  !
X                  IF animal is cat
X                  AND animal has tan color
X                  AND animal has stripes
X                  THENHYP animal is tiger
X                  !
X                  IF animal is cat
X                  AND animal has tan color
X                  AND animal has spots
X                  THENHYP animal is cheeta
X                  !
X                  .
X                  .
X
X             Notice  that  "animal  is cat" should be a  THEN  Consequent 
X        somewhere or else the inference engine will simply ask you if the 
X        "animal  is  cat" statement is TRUE or not -- which  may  not  be 
X        construed  as  a  particularly intelligent thing  for  an  expert 
X        system to do.   The intelligence represented by the expert system 
X        is directly related to the intelligence you give it.  However, it 
X        is possible to get very confused when there are a large number of 
X        rules for a particular expert system and mistakes in logic or the 
X        development  of  circular  logic occurs.   The first  will  cause 
X        incorrect  conclusions to be drawn and the second will cause  the 
X        inference engine to crash.   Circular logic causes the  inference 
X        engine to run out of stack space.  
X
X
X        George W. Hageman            --13--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X             A  circular argument is an argument which cannot be resolved 
X        because  its proof relies on another rule which in turn relies on 
X        proving the first statement before it can be proved such as in:
X
X                       !
X                       IF the second one is true
X                       THEN the first one is true
X                       !
X                       IF the first one is true
X                       THEN the second one is true
X                       !
X
X             Or to expand the concept:
X
X                       !
X                       IF the third one is true
X                       THEN the first one is true
X                       !
X                       IF the first one is true
X                       THEN the second one is true
X                       !
X                       IF the second one is true
X                       THEN the third on is true
X                       !
X
X             Usually,   when  the inference engine tells you that  "Stack 
X        overflow" has occurred -- this will be the problem.
X
X             Look at the animal file contained in this release,  see  how 
X        the  rules are built and as an exercise add another animal to  be 
X        differentiated  like a platypus,  and later add a whole class  of 
X        animals such as domestic farm animals, or even a division such as 
X        reptiles or insects.
X
X             You  will soon notice that your knowledge base will increase 
X        very  quickly  with each set of animals you want your  expert  to 
X        differentiate.   With this growth of the knowledge base come real 
X        difficulty  in keeping the rules correct  and  non-circular.    A 
X        strategy  for limiting the complexity for these rules is  to  use 
X        the IFRUN or THENRUN capability of this inference engine to fire-
X        up  a whole new inference engine which is an expert in one of the 
X        major branches of animals.   In this manner one only has to  make 
X        the  major decisions associated with a class of animals and  then 
X        run  the  expert system which knows how to  handle  the  specific 
X        class of animals.  
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --14--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        For example:
X
X                  !
X                  IF animal has feathers
X                  AND animal lays eggs
X                  THEN animal is bird
X                  THENRUNHYP  inference.exe birds.cmp
X                  !
X                  IFNOT animal is bird
X                  AND  animal has hair
X                  AND  animal gives milk
X                  THEN animal is mammal
X                  THENRUNHYP inference.exe mammals.cmp
X                  !
X
X             The  files  "birds.cmp" and "mammals.cmp" are the  resultant 
X        compiled  files  from  the  text  knowledge  bases  "birds"   and 
X        "mammals"  which  the knowledge engineer would need  to  produce.   
X        But,  as stated above, these files would represent expert systems 
X        knowing  only the limited area of birds or mammals and  therefore 
X        can be greatly simplified.    NOTE:  inference.exe returns a TRUE 
X        value  if  it has proved anything while it ran,  and FALSE if  it 
X        could  not  prove anything.   With an IBM AT with 512  KBYTES  of 
X        memory  I  was able to load four copies of  an  inference  engine 
X        simultaneously.   A good way to see how many your system can deal 
X        with at the same time compile the following test:
X
X                       !
X                       IFRUN INFERENCE.EXE TEST.CMP
X                       THENHYP I am done
X                       ! 
X
X
X        If this file is named TEST, then compile it using the following:
X
X                  rulecomp test test.cmp
X
X        Then, run the inference engine with the test.cmp file as follows:
X
X                  inference test.cmp
X
X
X             Notice  that when any routine cannot be run for some  reason 
X        or another, an attempt is made to tell you what went wrong -- out 
X        of memory,  can't find it,  or some other reason, and the routine 
X        will  be assumed to have returned normally with a TRUE  predicate 
X        value.   This  is done so that the inference engine won't  simply 
X        die at some mysterious point.   The "I infer that : I am done" at 
X        the top was the last inference engine which could be loaded which 
X        could run but could not spawn a new process, the next one down is 
X        the  last one which could spawn one,  and any others  below  this 
X        line  plus  this  one will tell you the number of levels  of  the 
X        inference engine you can run on your system.  
X
X
X
X
X        George W. Hageman            --15--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        THE WEATHER EXPERT:
X
X             The  other  expert system knowledge base included with  this 
X        release  is  a weather predicting  expert.   This  expert  system 
X        demonstrates   the   use  of  executeable  files  to  expand  the 
X        abilities  of  the inference engine to deal with other  forms  of 
X        knowledge.   Look  a  the source files for  the  weather  expert, 
X        notice how each member of this set of routines uses a common file 
X        for  the  transfer of needed data.   The need of a file for  this 
X        transfer of data is done because it was the only standard form of 
X        data  transmission  which was not machine dependent according  to 
X        MS-DOS and UNIX operating systems.   Specific methods for dealing 
X        with this problem can be found for your machine which can greatly 
X        speed up this cumbersome data transfer method -- but it works.   
X
X             UNIX  and the Microsoft C compiler allows a routine to  exit 
X        with a value which will be returned to the parent process.   This 
X        method  is  used to allow each executeable to return  its  TRUTH-
X        VALUE  or  PREDICATE-VALUE back to  the  inference  engine.   The 
X        routine  runRoutine(consequent) performs this task.   If you look 
X        at  the  file runrouti.c you can see that this is done  with  the 
X        "exit(value) ;" statement.  The values used to indicate the TRUTH 
X        and  FALSEness  of  the  routine  are  "RETURN_ROUTINE_TRUE"  and 
X        "RETURN_ROUTINE_FALSE"   as   contained  in   the   header   file 
X        "routine.h".   This header file should be included in any routine 
X        which returns a TRUE/FALSE value to the inference engine.
X
X             The   strategy  for  using  this  method  of  expanding  the 
X        knowledge  base  is essentially the same as that for  the  animal 
X        type  expert  system,  except that it is noticed that the  simple 
X        form  of  the  knowledge base does not  have  the  capability  to 
X        perform  some  of  the functions  needed.   Cases  where  complex 
X        questions  or the manipulation of data are necessary must  resort 
X        to  the use of executeable files which can deal with them.   Such 
X        is the case for the weather predicting expert system.
X
X             The  weather expert must deal with such data  as  barometric 
X        pressure,  wind direction,  and the current rate of change of the 
X        barometric  pressure.    Additional data such as cloud conditions 
X        can  be  handled  by the predicate  functions  of  the  inference 
X        engine.     Again  the  strategy  is  to divide  and  conquer  by 
X        determining  which  information  needs  to  be  gathered  by  the 
X        executeable portion of the expert system,  what routines must  be 
X        used  to  convert  this data into a form which is usable  by  the 
X        inference engine i.e.  TRUE or FALSE,  and,  what information can 
X        be  gathered  directly  by the  inference  engine.    Once  these 
X        decisions are made then a decision tree can be built in a similar 
X        manner  to  the  one  built  for  the  animal  expert  but   also 
X        incorporating the executeable files where appropriate.    Look at 
X        the  file  "weather"  and  at each of the source  files  for  the 
X        executeable portion of the weather expert.  
X
X
X
X
X
X
X        George W. Hageman            --16--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X             Notice  that there is a "main" routine (even though  all  of 
X        the  programs  are  stand-a-lone programs and are have  the  name 
X        "main").   This routine is in the file "MESSAGE1.C", and provides 
X        the  data entry for all of the data needed by the expert  system.  
X        The  routine  explains to the user what  is  needed,  checks  for 
X        reasonable  responses,  and  writes the data to a disk  file  for 
X        later  use  by  the other routines associated with  this  system.  
X        These other routines,  when initiated,  have the task of  reading 
X        the  disk file produced by the "MESSAGE1.EXE" executeable,  check 
X        for  some conditions,  and return "ROUTINE_RETURN_TRUE",  if  the 
X        conditions are met and "ROUTINE_RETURN_FALSE" if they are not.
X
X             In  this  manner  the knowledge  engineer  can  make  expert 
X        systems   of  a  higher  complexity  and  usefulness  than  would 
X        otherwise be possible.
X
X        CONCLUSION:
X
X             I hope that this short definition of the inference engine is 
X        enough  to  get  you started into the fascinating  field  of  AI.   
X        There are some useful additions the enthusiastic programmer could 
X        make  to the inference engine to both enhance its usefulness  and 
X        its  ability to assist in the debugging of knowledge  basses.   A 
X        "Why"  function which shows the complete logical path which  lead 
X        to  the  question being asked,  showing each statement  as  being 
X        known or unknown and if known what its predicate value is,  would 
X        be very helpful.    Further,  the addition of different  KEYWORDS 
X        such  as  an  OR function,  might expand the  usefulness  of  the 
X        inference engine.  I may include these in my next release of this 
X        software  but If you have made such an addition -- I will include 
X        them in the next release and refund your $10.00 if you have  been 
X        so good as to send it to me.
X
X             Good  luck  and if you have any questions or would  like  to 
X        discuss this concept please drop me a line.
X
X                                 Thanks,
X
X                                      George W. Hageman
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --17--
X
X
X
X
X
X        INFERENCE          -- SOFTMAN ENTERPRIZES --        Dec. 30, 1985
X
X
X        BIBLIOGRAPHY:
X
X             The  following  books  and articles  were  helpful  in  the 
X        development of this inference engine.  
X
X             MVP-FORTH EXPERT SYSTEM TOOLKIT,  Jack Park,   Mountain View 
X        Press,  Inc.  P.O. Box 4656 Mountain View, CA 94040 Phone: (415)-
X        961-4130.
X
X             MVP-FORTH EXPERT-2 TUTORIAL,  Mitch Derick and Linda Derick, 
X        Mountain View Press.
X
X             INSIDE F83, C. H. Ting,  OFFETE ENTERPRISES, INC.  Available 
X        from Moutain View Press. 
X
X             Expert  Systems  and the Weather,  Jack  Park,   Dr.  Dobb's 
X        Journal, April 1984, pp. 24-28.
X
X             Programming in Prolog,  William F.  Clocksin and Christopher 
X        S. Mellish, Springer-Verlag 
X
X             LISP,  Patrick H.  Winston and Berthold Klaus and Paul Horn, 
X        Addison Weseley.
X
X             A  special  thankyou to Jack Park and the  MVP-FORTH  EXPERT 
X        SYSTEM  TOOLKIT.   Many  of  the ideas in this document  and  the 
X        development environment afforded by FORTH were the starting point 
X        for many of the ideas developed in this inference engine.  If you 
X        are into FORTH this is an excellent source of information on  the 
X        subject.  
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X        George W. Hageman            --18--
X
X
X
X
X----------------------  Cut Here --------------------------------
X
XGeorge Hageman  ( ...bmcg!asgb!benish!hageman )
X
XHappy New Year!
X
X
SHAR_EOF
exit

tools@raybed2.UUCP (TOOLS) (01/27/86)

As requested by the author we are reposting the source and documentation of
a C inference engine. Address all questions to George Hageman at:
UUCP: {asgb!benish}!hageman
MAIL:	George W. Hageman
	P.O. Box 11234
	Boulder, Colorado  80301
NOTE: RAYTHEON Inc. is not reponsible for the contents and/or consequences
of use of this software. This software is totally the work of George Hageman
and is being reposted as per his request (see following message). Address all
questions, comments, etc. to him.
=========================================================================
>From linus!decvax!seismo!hao!asgb!benish!hageman Fri Jan 24 07:31:04 1986
>Subject: Re:  C inference engine
>
>	... it seems that
>	the probability of getting somthing out to net.and is
>	inversely proportional to the number of hops it has to go.
>
>	I'll send you all of the shars (inference rulecompiler and 
>	the storm expert).  If you could make sure that they are
>	available at your site either by reposting them from your
>	end or by some other means it would be appreciated.
>
>	Thanks,
>
>George [Hageman]
=========================================================================


_____CUT for inference.sh_____
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	expert.h
#	infer.h
#	inference.h
#	keywords.h
#	routine.h
#	gettruth.c
#	inference.c
#	remante.c
#	runrouti.c
#	verify.c
#	verifytr.c
#	weknow.c
#	inference.str
#	makeinfe
#	makercom
#	README
# This archive created: Sun Jan 12 16:12:08 1986
export PATH; PATH=/bin:$PATH
if test -f 'expert.h'
then
	echo shar: will not over-write existing file "'expert.h'"
else
cat << \SHAR_EOF > 'expert.h'

/*************************************************************************
**									**
**	The software contained in this distribution is copyright (C)	**
**	by George Hageman 1985 and is released into the public 		**
**	domain with the following restrictions:	 			**
**									**
**		(1)  This software is intended for non-commertial	**
**			usage.						**
**		(2)  I am held save from damages resulting from		**
**			its use, and					**
**		(3)  The following concepts and legal jargon are	**
**			agreed to by the user of this software.		**
**									**
**	User-supported software concept: 				**
**									**	
**	IF    you find use for this software				**
**	ANDIF it saves you some development time			**
**	THEN        send me $10.00					**
**	ANDTHENHYP  you will feel good!					**
**									**
**									**
**	This source code is provided on an "as is" basis without	**
**	warranty of any kind, expressed or implied, including but	**
**	not limited to the implied warranties of merchantability	**
**	and fitness for a particular purpose.  The entire risk as	**
**	to quality and performance of this software is with you. 	**
**	Should the software prove defective, you assume the entire	**
**	cost of all necessary repair, servicing, or correction.  In	**
**	no event will the author be liable to you for any damages,	**
**	including any lost profits, lost savings, or other		**
**	incidental or consequential damages arising out of the  use	**
**	of inability to use this software.  In short my friends, I	**
**	have done  a reasonable ammount of work in debugging this	**
**	software and I think it is pretty good but, as you know,	**
**	there is always some chance that a bug is still lurking 	**
**	around. If you should happen to be lucky enough to  find one,	**
**	please let me know so I	can make an attempt to fix it.		**
**									**
**				Thanks,					**
**									**
**				George Hageman				**
**				P.O. Box 11234				**
**				Boulder, Colorado 80302			**
**									**
*************************************************************************/


/*
**	These are the structures of the rulebase which will
**	be used to compile the rules into.  
*/

#define FALSE 			0 
#define TRUE  			-1 
#define MAX_STRING_BUFF 	5000
#define MAX_STR_LEN		100
#define MAX_RULE_STATEMENTS 	500
#define MAX_HYPS		250 
#define ANTECEDENT 		1
#define CONSEQUENT 		2
#define COMMENT_CHAR		'!'
#define	BLANK 			0x20
#define EOL			0x0a

#define KEY_EOF			-2 
#define LINE_ERROR		-3
#define KEY_WORD_ERROR		-4
#define ERROR		 	-5	
#define STR_LEN_ERROR		-6

/*
**	Other definitions of key words
*/

#define	AND_N       	 0
#define	ANDIF_N     	 1
#define	ANDIFRUN_N  	 2
#define	ANDNOT_N    	 3	
#define	ANDNOTRUN_N 	 4
#define	ANDRUN_N    	 5
#define	ANDTHEN_N   	 6 
#define ANDTHENHYP       7
#define	ANDTHENRUN_N	 8
#define	ANDTHENRUNHYP_N  9
#define	IF_N        	10
#define	IFNOT_N     	11
#define	IFNOTRUN_N  	12
#define	IFRUN_N     	13
#define	THEN_N      	14
#define	THENHYP_N     	15  
#define THENRUN_N	16
#define THENRUNHYP_N    17
		
/*
**	Flag definitions:
*/

#define	STRING_TRUE	 1
#define	STRING_FALSE	 2
#define	ROUTINE_TRUE	 3
#define ROUTINE_FALSE	 4
#define STRING_TRUE_HYP  5
#define ROUTINE_TRUE_HYP 6

#define NUM_KEYWORDS	18

struct	rule_statement_r
		{
		int flag ;   /* logical flag for inference engine */
		int string ; /* offset into string buffer */
		};


/* 
**	rules are compiled into the array rules in the folloiwng form:
**
**	antecedent-group consequent-group 
**	... 
**	antecedent-group consequent-group
**	end-group
**
**	Each group of consequences and antecedents
**	are compiled in a group like the following:
**
**	flag pointer flag pointer ... flag pointer 0-flag 0-pointer
**
**	The end-group is merely:
**
**	0-flag 0-pointer 0-flag 0-pointer 0-flag 0-pointer
**
**	flags are used by the inference engine to determine what to
**	do with the following string pointer.  
**	string pointers are merely offsets into the string array.
**	The pointers may either point
**	to a string which is a rule statement such as "the animal has wings"
**	or is a UNIX pathname for a particular routine which is to be
**	executed such as "/g1/hageman/Diagnostics/Disk1diag".   This
**	routine will then be executed and will return either a true or
**	false indication.  Latter versions of the inference engin may be
**	capable of returning more than this via some pipe-line mechanism or
**	other.
**
**	Once an anicedent whether string or routine is verified it is placed
**	in either a known-true or known-false stack for later verification 
**	in other rules which use them.  In short they only have to be verified
**	once.
**
**	Examples of a rule structure are:
**
**	IFNOT the animal is a bird
**	AND the animal has wings
**	ANDNOT the animal lives in caves
**	AND the animal is nocternal
**	THEN the animal is a bat
**	IF the animal is a bat
**	ANDRUN /g1/hageman/Src/Expert/speed_of_bat
**	THENHYP the bat is out of hell
**	IF the animal is a bat
**	ANDNOTRUN /g1/hageman/Src/Expert/speed_of_bat
**	THENHYP the bat is out of cave
**
*/
SHAR_EOF
fi # end of overwriting check
if test -f 'infer.h'
then
	echo shar: will not over-write existing file "'infer.h'"
else
cat << \SHAR_EOF > 'infer.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*
**	the following are the global common variables which
**	are used in the inference engine...
**
**	all routines except inference.c should have this
**	file included.
*/

#define	MAX_KNOWN	500

int	numHypot, hypStack[MAX_HYPS],strBuffOfst ;
char	strBuff[MAX_STRING_BUFF] ;
int	ruleBuffOfst ;
int	knownTrue[MAX_KNOWN], knownFalse[MAX_KNOWN] ;
int	numTrue, numFalse ;
struct  rule_statement_r ruleBuff[MAX_RULE_STATEMENTS] ;

SHAR_EOF
fi # end of overwriting check
if test -f 'inference.h'
then
	echo shar: will not over-write existing file "'inference.h'"
else
cat << \SHAR_EOF > 'inference.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*************************************************************************
**									**
**	The software contained in this distribution is copyright (C)	**
**	by George Hageman 1985 and is released into the public 		**
**	domain with the following restrictions:	 			**
**									**
**		(1)  This software is intended for non-commertial	**
**			usage.						**
**		(2)  I am held save from damages resulting from		**
**			its use, and					**
**		(3)  The following concepts and legal jargon are	**
**			agreed to by the user of this software.		**
**									**
**	User-supported software concept: 				**
**									**	
**	IF    you find use for this software				**
**	ANDIF it saves you some development time			**
**	THEN        send me $10.00					**
**	ANDTHENHYP  you will feel good!					**
**									**
**									**
**	This source code is provided on an "as is" basis without	**
**	warranty of any kind, expressed or implied, including but	**
**	not limited to the implied warranties of merchantability	**
**	and fitness for a particular purpose.  The entire risk as	**
**	to quality and performance of this software is with you. 	**
**	Should the software prove defective, you assume the entire	**
**	cost of all necessary repair, servicing, or correction.  In	**
**	no event will the author be liable to you for any damages,	**
**	including any lost profits, lost savings, or other		**
**	incidental or consequential damages arising out of the  use	**
**	of inability to use this software.  In short my friends, I	**
**	have done  a reasonable ammount of work in debugging this	**
**	software and I think it is pretty good but, as you know,	**
**	there is always some chance that a bug is still lurking 	**
**	around. If you should happen to be lucky enough to  find one,	**
**	please let me know so I	can make an attempt to fix it.		**
**									**
**				Thanks,					**
**									**
**				George Hageman				**
**				P.O. Box 11234				**
**				Boulder, Colorado 80302			**
**									**
*************************************************************************/


/*
Expert system inference engine

This inference engine is backwards-chaining only and features the
running of binary files if:

	1) they are antecedents associated with a particuar consequent
	   being proved, or
	2) they are consequents which have been proven true by verify().
	   their actual predicate value will be determined by their returned
	   result after running.

This inference engine is designed with diagnostics in mind and so will probably
be best suited for this application.  Later revisons will include 
forward-chaining so that the user will have the opportunity to give pre-existant
conditons, or that these my be supplied by the calling process.

(If you cant tell by the above description -- I am very excited about the 
possibilties presented in this form of computer control of the diagnostic
process... Geo.)

See structure design for details of operation,  but basically the 

inference reads in all of the compiled information as produced by the
    rule compiler.
    
it proceeds to attempt to prove each consequent by proving the truth
	or falseness of any antecedent associated with this consequent.
if any antecedent of a consequent turns out to be a consequent itself, then
        the inference engine will recursively attempt to prove this consequent.

the process is complete when all of the predicate values of the consequents has
	been determined.
	
Additional features which I may put in at a later time is the abiltiy for
the inference engine to expalin itself to the user when the user asks why
the inference engine needs to know the predicate value of a particular
antecedent.   This will be done by forward and backward chaining of predicat
clauses, the truth of each will be displayed.
*/
#define	MAX_ANTECEDENTS		25

extern 	int	numHypot, hypStack[],strBuffOfst ;
extern 	char	strBuff[] ;
extern	int	ruleBuffOfst ;
extern	int	knownTrue[], knownFalse[] ;
extern	int	numTrue, numFalse ;
extern	struct  rule_statement_r ruleBuff[] ;
SHAR_EOF
fi # end of overwriting check
if test -f 'keywords.h'
then
	echo shar: will not over-write existing file "'keywords.h'"
else
cat << \SHAR_EOF > 'keywords.h'

char	*keyWords[NUM_KEYWORDS] =
	{
	"AND           ",
	"ANDIF         ",
	"ANDIFRUN      ",
	"ANDNOT        ",
	"ANDNOTRUN     ",
	"ANDRUN        ",
	"ANDTHEN       ", 
	"ANDTHENHYP    ",
	"ANDTHENRUN    ",
	"ANDTHENRUNHYP ",
	"IF            ",
	"IFNOT         ",
	"IFNOTRUN      ",
	"IFRUN         ",
	"THEN          ",
	"THENHYP       ",
	"THENRUN       ",
	"THENRUNHYP    "
	} ;

SHAR_EOF
fi # end of overwriting check
if test -f 'routine.h'
then
	echo shar: will not over-write existing file "'routine.h'"
else
cat << \SHAR_EOF > 'routine.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*
**	these are the two return values
**	which must be returned as the exit
**	value.  Any other will result in
**	an assumption that the result is true
**	or that some sort of error occured.
*/

#define RETURN_ROUTINE_TRUE	254
#define RETURN_ROUTINE_FALSE	255

SHAR_EOF
fi # end of overwriting check
if test -f 'gettruth.c'
then
	echo shar: will not over-write existing file "'gettruth.c'"
else
cat << \SHAR_EOF > 'gettruth.c'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*************************************************
**
**	getTruth(antecedent) 
**
**	asks user for the truth of a string or
**	returns --
**		TRUE if user says the statement is TRUE
**		FALSE if the user says the statement is FALSE
**
*************************************************/

#include <stdio.h>

#ifdef MSDOS
#include <conio.h>
#endif

#include "expert.h"
#include "inference.h"

int getTruth(cnsquent)
	int	cnsquent ;
{
int done,c ;
done = FALSE ;

while(!done)
	{
	printf("\n Is the following statement True?  (T/F,Y/N)\n\n ") ;
	printf("%s    ?",&strBuff[ruleBuff[cnsquent].string]) ;
#ifdef MSDOS
	c = getche() ;
#endif
#ifdef UNIXSV
	c = getchar() ;	
	getchar() ;
#endif
	switch(c) 
		{
		case 'y' :
		case 'Y' :
		case 't' :
		case 'T' :
			printf("\n\n") ;
			return(TRUE) ;
		case 'n' :
		case 'N' :
		case 'f' :
		case 'F' :
			printf("\n\n") ;
			return(FALSE) ;
		case 'w' :
		case 'W' :
			printf("\n Why is not implemented \n") ;
		default :
			printf("\n Please try again \"T\" or \"F\" \n ") ;
		}
	}
}




SHAR_EOF
fi # end of overwriting check
if test -f 'inference.c'
then
	echo shar: will not over-write existing file "'inference.c'"
else
cat << \SHAR_EOF > 'inference.c'
/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*******************************************************************
**
**	inference engine main routine
**
*******************************************************************/

#include <stdio.h>
#include <string.h>

#include "expert.h"
#include "routine.h"

#define	MAX_KNOWN	100

int	numHypot, hypStack[MAX_HYPS],strBuffOfst ;
char	strBuff[MAX_STRING_BUFF] ;
int	ruleBuffOfst ;
int	knownTrue[MAX_KNOWN], knownFalse[MAX_KNOWN] ;
int	numTrue, numFalse ;
struct  rule_statement_r ruleBuff[MAX_RULE_STATEMENTS] ;

int	main(argc,argv)
int argc ;
char **argv ;

{
int	i,consequent ;
int	proved ;
int	p_value ;
FILE	*infile ;

for( proved = 0; proved < MAX_STRING_BUFF; proved ++ )
	strBuff[proved] = 0 ;

proved = FALSE ;

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP argc=%d ",argc) ;
#endif

if(argc != 2 )
	{
	fprintf(stdout, "\n\n Usage: inference in.file \n " ) ;
	exit(RETURN_ROUTINE_FALSE) ;
	}
infile = fopen( argv[1], "rb" );
if(infile == NULL)
	{
	fprintf(stdout,"\n\n Cannot open input file %s \n ", argv[1]);
	exit(RETURN_ROUTINE_FALSE) ;
	}
for(i=0;i<MAX_KNOWN;i++)
	knownTrue[i]=knownFalse[i]=0 ;
/*
**
**	read in the compiled rules
**
*/

fread(&numHypot,sizeof(int),1,infile) ;
fread(hypStack,sizeof(int),numHypot,infile) ;
fread(&ruleBuffOfst,sizeof(int),1,infile) ;
fread(ruleBuff,2*sizeof(int),ruleBuffOfst,infile) ;
fread(&strBuffOfst,sizeof(int),1,infile) ;
fread(strBuff,1,strBuffOfst,infile) ;

#ifdef	DEBUG
	
printf("\nDEBUG-main, numHypot = %d",numHypot) ;
for(i=0;i<numHypot;i++)
	{
	printf("\nDEBUG-main, consequent[%d]= %d, string=%s",i,hypStack[i],
			&strBuff[(ruleBuff[hypStack[i]].string)] ) ;
	}
printf("\nDEBUG-main, number of rules = %d",ruleBuffOfst) ;
printf("\nDEBUG-main, number of bytes in stringbuffer=%d",strBuffOfst) ;
for(i=0;i<ruleBuffOfst;i++)
	{
	if(ruleBuff[i].flag !=0)
		{
		printf("\nDEBUG-main, rule[%d].flag=%d, rule[%d].string= %d->%s"
        		  ,i,ruleBuff[i].flag,i,ruleBuff[i].string,&strBuff[ruleBuff[i].string]) ;
		}
	}
printf("\n") ;

#endif

for( i=0 ; i < numHypot ; i++ )

	{
	consequent = hypStack[i] ;

#ifdef DEBUG
	printf("\nDEBUG-main, consequent = %d ",consequent ) ;
#endif

	if(weKnow(consequent,&p_value) == TRUE)
		{
#ifdef DEBUG
	printf("\nDEBUG-main, we knew this consequent was ") ;
	if(p_value == TRUE)
		printf("-- TRUE") ;
	else
		printf("-- FALSE") ;
#endif
		continue ;
		}
		
	if ( verify(consequent) == TRUE )
		{
		
#ifdef DEBUG
			printf("\nDEBUG-main, consequent verified TRUE " ) ;
#endif
		
		if( (ruleBuff[consequent].flag == ROUTINE_TRUE) ||
			(ruleBuff[consequent].flag == ROUTINE_TRUE_HYP) )
			{
			if(weKnow(consequent,&p_value) == TRUE)
				continue ;
#ifdef DEBUG
			printf("\nRuning Routine %s",&strBuff[ruleBuff[consequent].string]) ;
#endif
			if (runRoutine(consequent) == TRUE)
				{
				knownTrue[numTrue++]=ruleBuff[consequent].string ;
#ifdef DEBUG
				printf(" -- TRUE\n") ;
#endif
				if(ruleBuff[consequent].flag == ROUTINE_TRUE_HYP)
					{
					printf("\nCONCLUSION\n") ;
					exit(RETURN_ROUTINE_TRUE) ;
					}
				}
			else
				{
				knownFalse[numFalse++]=ruleBuff[consequent].string ;
#ifdef DEBUG
				printf(" -- FALSE\n") ;
#endif
				}
			}
		else
			{
			knownTrue[numTrue++]=ruleBuff[consequent].string ;
			proved = TRUE ;
			printf("\nI infer that : %s\n",&strBuff[ruleBuff[consequent].string]) ;
			if(ruleBuff[consequent].flag == STRING_TRUE_HYP)
				{
				printf("\nCONCLUSION\n") ;
				exit(RETURN_ROUTINE_TRUE) ;
				}
			}
		}
	else
		{
#ifdef DEBUG
			printf("\nDEBUG-main, consequent not proved " ) ;
#endif
		}
	}
if(proved == FALSE)
	{
	printf("\n I can't prove anything\n") ;
	exit(RETURN_ROUTINE_FALSE) ;
	}
exit(RETURN_ROUTINE_TRUE) ;
}

/* --<<hidden tof */

/******************************************************
**
**	known(hypot,knownFile,numKnown)
**
**	checks to see if hypot is in the stack knownFile of length
**		numKnown
**
**	returns true if known, false otherwise
**
******************************************************/



known(hypot,knownFile,numKnown)
	int 	hypot,numKnown ;
	int	knownFile[] ;
{
int i ;
for (i = 0 ; i < numKnown ; i++ )
	if (ruleBuff[hypot].string == knownFile[i] )
		return(TRUE) ;
return(FALSE) ;
}


SHAR_EOF
fi # end of overwriting check
if test -f 'remante.c'
then
	echo shar: will not over-write existing file "'remante.c'"
else
cat << \SHAR_EOF > 'remante.c'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/***********************************************
**
**	remAnte(antecedent)
**
**	returns the truth value of the fact to be remembered
**	similar to verify except that the fact is a known antecedent
**	and is not a consequent of any rule.  And therefore can be remembered
**	false as well as true.
**
************************************************/

#include <stdio.h>
#include "expert.h"
#include "inference.h"


int	remAnte(antecedent)
	int	antecedent ;
{
int p_value ;

switch(ruleBuff[antecedent].flag)
	{
	case STRING_TRUE :
	case STRING_TRUE_HYP:
		knownTrue[numTrue++]=ruleBuff[antecedent].string ;
		return(TRUE) ;
	case STRING_FALSE :
		knownTrue[numTrue++]=ruleBuff[antecedent].string ;
		return(FALSE) ;
	default:  /* routine to run */
		if(weKnow(antecedent,&p_value) == TRUE)
			return(p_value) ;
		if( runRoutine(antecedent) == TRUE )
			{
			knownTrue[numTrue++]=ruleBuff[antecedent].string ;
			if((ruleBuff[antecedent].flag == ROUTINE_TRUE) ||
				(ruleBuff[antecedent].flag == ROUTINE_TRUE_HYP))
				{
				return(TRUE) ;
				}
			else
				{
				return(FALSE) ;
				}
			}
		else
			{
			knownFalse[numFalse++]=ruleBuff[antecedent].string ;
			if(ruleBuff[antecedent].flag == ROUTINE_FALSE)
				{
				return(TRUE) ;
				}
			else
				{
				return(FALSE) ;
				}
			}
	}
}		 
SHAR_EOF
fi # end of overwriting check
if test -f 'runrouti.c'
then
	echo shar: will not over-write existing file "'runrouti.c'"
else
cat << \SHAR_EOF > 'runrouti.c'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*****************************************************************
**
**	runRoutine(antecedent)
**
**	spawns the process with the path name specified in
**
**	ruleBuff[antecedent].string
**
**	and returns the value as TRUE or FALSE  depending on
**	the value returned from the exit() command from the spawnd routine.
**
**	the routine returns TRUE if there is any problem with spawning
**	the specified executable.
**
******************************************************************/
#define	MAX_ARGS	20

#include <stdio.h>

#ifdef MSDOS
#include <process.h>
#endif

#include <errno.h>

#include "expert.h"
#include "inference.h"
#include "routine.h"

int	runRoutine(cnsquent)
	int	cnsquent ;
{
extern int errno ;

#ifdef UNIXSV
int	pnid ;
#endif

int	i,argc,p_value,numChars ;
char	buffer[MAX_STR_LEN], *string_p;
char	*argv[MAX_ARGS] ;

/*
** copy string to buffer to get parameters
*/

string_p = &strBuff[ruleBuff[cnsquent].string] ;

for (numChars = 0 ; numChars < MAX_STR_LEN ; numChars++)
	{
	buffer[numChars]= *( string_p + numChars ) ; 
	if(buffer[numChars] == NULL)
		break ;
	}
	
#ifdef DEBUG
printf("\nDEBUG -- runroutine -- copied string is %s\n",buffer) ;
#endif

/*
** set the argv(alues) to the proper location within the buffer
*/

argc = 1 ;
argv[0] = buffer ;

for(i=0;i<numChars;i++)
	{
#ifdef DEBUG
printf("\n DEBUG -- runroutine parameters i = %d, char = %c \n",i,buffer[i]) ;
#endif
	if(buffer[i] == NULL)
		{
		break ;
		}
	if(buffer[i] == BLANK)
		{
		buffer[i] = NULL ;
		while( buffer[++i] == BLANK ) ;
		if(buffer[i] == NULL)
			{
			break ;
			}
		argv[argc++] = &buffer[i] ;
		if(argc == MAX_ARGS)
			{
			printf("\n maximum arguments exceeded for %s\n",string_p);
			argc -= 1 ;
			break ;
			}
		}
	}
argv[argc]=NULL ;
#ifdef DEBUG
for( i = 0 ; i < argc ; i++)
	{
	printf("\n argv[%d] = %s\n",i,argv[i]) ;
	}

printf("\nRunning Routine %s ",argv[0] ) ;
#endif

#ifdef MSDOS
p_value=spawnv(P_WAIT,argv[0],argv ) ;
#endif


#ifdef UNIXSV
pnid = fork() ;
if(pnid == -1)
	{
	printf("\nFork failure! Running %s -- returning TRUE \n",argv[0]) ;
	return(TRUE) ;
	}
if(pnid != 0 ) 		/* parent */
	{
	wait(&p_value) ;
	if(p_value != -1)
		p_value = (p_value >> 8 ) & 0x0ff ;
	}
else			/* child */
	{
	execv(argv[0],argv) ;
	}
#endif

/*
**	The return value is set by the routine having an exit(X)  where
**	X is the value to be returned...
**	There is a problem since the return value can also provide an
**	indication that there was some problem with the attempt as follows:
*/

if(p_value == RETURN_ROUTINE_TRUE)
	{
#ifdef DEBUG
	printf(" -- TRUE\n") ;
#endif
	return(TRUE) ;
	}
if(p_value == RETURN_ROUTINE_FALSE)
	{
#ifdef DEBUG
	printf(" -- FALSE \n") ;
#endif
	return(FALSE) ;
	}
if(p_value)
	switch(errno)
		{
		case ENOENT :
			printf("\n Executable file %s not found assumed TRUE\n",argv[0]) ;
			return(TRUE) ;
		case ENOEXEC :
			printf("\n File %s is not executable assumed TRUE\n",argv[0]) ;
			return(TRUE) ;
		case ENOMEM :
			printf("\ Not enough memory to run -- assumed TRUE\n") ;
			return(TRUE) ;
		}	
printf("\n Routine did not return either ROUTINE_TRUE or ROUTINE_FALSE assumed TRUE\n") ;
return(TRUE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'verify.c'
then
	echo shar: will not over-write existing file "'verify.c'"
else
cat << \SHAR_EOF > 'verify.c'

/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/********************************************************
**
**	verify(consequent)
**
**	finds the truth about the consequent -- returns
**	TRUE if consequent is proved (all antecedents are TRUE)
**	FALSE if any of the antecedents are FALSE
**
********************************************************/

#include <stdio.h>
#include "expert.h"
#include "inference.h"

int	verify(cnsquent) 
	int	cnsquent ;

{
int 	i,j,k,m,n ;
int	antecedent[MAX_ANTECEDENTS] ;
int	consequent[MAX_ANTECEDENTS] ;
int	p_value ;			/* predicate value */

#ifdef DEBUG
	int di ;
	for(di=0;di<numTrue;di++)
		printf("\nDEBUG-verify knownTrueFact = %d",knownTrue[di]) ;
	for(di=0;di<numFalse;di++)
		printf("\nDEBUG-verify knownFalseFact = %d",knownFalse[di]) ;

#endif

/*
**
**	get all of the antecedents for the consequent
**
**	First locate the antecedents -- should be directly in front
**	of the consequent, delimited by a consequent with a flag of zero
*/

#ifdef DEBUG
	printf("\nDEBUG -- verify consequent = %d",cnsquent ) ;
#endif

j = 0 ;

for(i=cnsquent; i>=0 ; i--)
	{
	if(ruleBuff[i].flag == 0 )
		break ;
	}

if(i == -1)
	{
	printf("\n Bad Consequent, has no antecedents! returning TRUE value \n ") ;
	return(TRUE);
	}

for(i = i-1 ;i>=0; i--)
	{
	if(ruleBuff[i].flag != 0)
		antecedent[j++]=i ;
	else
		break ;
	}

if(j==0)
	{
	printf("\n Bad Consequent, has no antecedents! returning TRUE value \n ") ;
	return(TRUE);
	}
	
#ifdef DEBUG
	printf("\nDEBUG -- verify antecedents = ") ;
	for(di=0; di < j; di++)
		printf("\n 	%d -- %d",di,antecedent[di]) ;
#endif

/*
**	at this point we should have some antecedents in the antecedent
**	stack so now lets see if each can be proved, and if there are
**	any consequents which will need verification.
*/

/*
**	main verificaiton loop:
*/

for(i=j-1 ; i >= 0 ; i--) /* for all of the antecedents in our stack */ 
	{

/*
**	determine if the antecedent is itself a consequent
**	
**	compare value of the string pointer of the antecedent needs to
**	be compaired with the value of the string pointer of all of the
**	consequents, if there is a match then the antecedent is a consequent
**
**	There may be more
**	than one consequent and this is handled below since all of these
**	must be false before we give up hope that one will be verified--
**	REMEMBER -- consequents are not remembered FALSE they can only be
**	remembered when they are true -- FALSEness for a consequent merely
**	means that this particular rule did not verify it , some other one
**	might.
**
*/

	for(k=0; k< numHypot; k++ )
		if(ruleBuff[hypStack[k]].string == ruleBuff[antecedent[i]].string)
			break ;

	if(k != numHypot)  /* we have an antecedent which is a consequent */
		{

#ifdef DEBUG
	printf("\nDEBUG -- verify antecedent %d is consequent %d",i, antecedent[i] ) ;
#endif

/*
**	What we have is an antecedent which is a consequent of another
**	rule or rules.  What is needed then is to place each of these consequents
**	into a stack and prove them one at a time.  We will return truth
**	if any of these are proven true and return false only when all of
**	them are false.   We can use veriry recursively in this case to
**	verify each one.
**
**	get all consequents matching hypStack[k].string into a stack
**	look for truth of any consequent.
**	if consequent is true (according to flag) return true.
**	if all consequents are false then return false.
*/
		n = 0 ;
		for( m = 0 ; m < numHypot ; m++)
			{
			if(ruleBuff[antecedent[i]].string == ruleBuff[hypStack[m]].string)
				{
#ifdef DEBUG
				printf("\nDEBUG--consequent stack(%d) = %d",n,hypStack[m]) ;
#endif
				consequent[n++] = hypStack[m] ;
				}
			}
/*
**	verify each consequent
*/

		p_value = FALSE ;
		for(m = 0 ; m < n ; m++)		
			{

#ifdef DEBUG
	printf("\nDEBUG -- verify(2) consequent = %d",consequent[m] ) ;
#endif
			if( verify(consequent[m]) == TRUE )
				{
				p_value = TRUE ;
				if(known(consequent[m],knownTrue,numTrue) == FALSE)
					{
					printf("\nI infer that : %s\n",&strBuff[ruleBuff[consequent[m]].string]) ;
					knownTrue[numTrue++]=ruleBuff[consequent[m]].string ;
					}
				if(remAnte(antecedent[i]) == TRUE)
					{
					break ;
					}
				else
					{
					return(FALSE) ;
					}
				}
			}
		if(p_value == FALSE) /* all of the consequents were not proved */
			{
			switch(ruleBuff[antecedent[i]].flag)
				{
				case STRING_FALSE :
				case ROUTINE_FALSE :
					continue ;
				case STRING_TRUE :
				case STRING_TRUE_HYP :
				case ROUTINE_TRUE :
				case ROUTINE_TRUE_HYP :
					return(FALSE) ;
				}
			}
		else			/* at least one was known */
			{
			switch(ruleBuff[antecedent[i]].flag)
				{
				case STRING_TRUE :
				case STRING_TRUE_HYP :
				case ROUTINE_TRUE:
				case ROUTINE_TRUE_HYP:
					continue ;
				case STRING_FALSE :
				case ROUTINE_FALSE :
					return(FALSE) ;
				}
			}
		}
		
	else	/* we have a plane old string or routine antecedent */
		
		{
		
		if(weKnow(antecedent[i],&p_value) == TRUE)
			{
			if(p_value == TRUE)
				continue ;
			else
				return(FALSE) ;
			}
/*
**	Things arent known and are simple consequents so prove them
**	either by asking the user or by running the routine
*/
		if(verifyTruth(antecedent[i]) == TRUE)
			continue ;
		else
			return(FALSE) ;
		}
	}
/*
**	Everything was TRUE in the big and statement so return it
*/
return(TRUE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'verifytr.c'
then
	echo shar: will not over-write existing file "'verifytr.c'"
else
cat << \SHAR_EOF > 'verifytr.c'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*****************************************************
**
**	verifyTruth(antecedent) ;
**
**	This routine verifies the truth of a string or routine which
**	is not a consequnt of a rule (ie an antecedent)
**
**	The routine remembers the final state of the antecedent in
**	the knownTrue, or knownFalse stacks
**
**	accomplishes task either by running the routine or by
**	asking the user for the specific truth of a statement
**
**	returns -- 
**		the "true" predicate value of the antecedent
**		according to its .flag:
**
**			TRUE if the antecedent phrase is TRUE and
**			   the antecedent .flag indicates positive,
**			FALSE if the antecedent phrase is TRUE and
**			   the antecedent .flag indicates negative.
**			etc.
**
*******************************************************/

#include <stdio.h>
#include "expert.h"
#include "inference.h"

int	verifyTruth(antecedent) 
	int antecedent ;
{
switch(ruleBuff[antecedent].flag)
	{
	case STRING_TRUE :
	case STRING_TRUE_HYP:
		if( getTruth(antecedent) == TRUE) 
			{
			knownTrue[numTrue++] = ruleBuff[antecedent].string ;
			return(TRUE) ;
			}
		else
			{
			knownFalse[numFalse++] = ruleBuff[antecedent].string ;
			return(FALSE) ;
			}
	case STRING_FALSE :
		if( getTruth(antecedent) == TRUE) 
			{
			knownTrue[numTrue++] = ruleBuff[antecedent].string ;
			return(FALSE) ;
			}
		else
			{
			knownFalse[numFalse++] = ruleBuff[antecedent].string ;
			return(TRUE) ;
			}
	case ROUTINE_TRUE :
	case ROUTINE_TRUE_HYP:
		if( runRoutine(antecedent) == TRUE) 
			{
			knownTrue[numTrue++] = ruleBuff[antecedent].string ;
			return(TRUE) ;
			}
		else
			{
			knownFalse[numFalse++] = ruleBuff[antecedent].string ;
			return(FALSE) ;
			}
	case ROUTINE_FALSE :
		if (runRoutine(antecedent) == TRUE)
			{
			knownTrue[numTrue++] = ruleBuff[antecedent].string ;
			return(FALSE) ;
			}
		else
			{
			knownFalse[numFalse++] = ruleBuff[antecedent].string ;
			return(TRUE) ;
			}
		default:
			printf("\major problem # 0001 -- llegal antecedent flag\n") ;
			return(TRUE) ;
		}
}

SHAR_EOF
fi # end of overwriting check
if test -f 'weknow.c'
then
	echo shar: will not over-write existing file "'weknow.c'"
else
cat << \SHAR_EOF > 'weknow.c'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*****************************************************************
**	
**	weKnow(antecedent,&predicate) 
**
**	routines searches both knownTrue and knownFalse
**	stacks to determine whether the antecedent is known.
**
**	the return value of the routine is TRUE if known and FALSE otherwise
**
**	the predicate is set to the "true" value of the antecedent according
**	to whether its phase is TRUE or FALSE and its .flag indicator.
**
*****************************************************************/

#include "expert.h"
#include "inference.h"

int	weKnow(antecedent,p_value)
	int antecedent,*p_value ;
{
if(known(antecedent,knownTrue,numTrue) == TRUE )
	switch(ruleBuff[antecedent].flag)
		{
		case STRING_TRUE:
		case STRING_TRUE_HYP:
		case ROUTINE_TRUE:
		case ROUTINE_TRUE_HYP:
			*p_value = TRUE ;
			return(TRUE)  ;
		case STRING_FALSE:
		case ROUTINE_FALSE :
			*p_value = FALSE ;
			return(TRUE) ;
		}
if(known(antecedent,knownFalse,numFalse) == TRUE )
	switch(ruleBuff[antecedent].flag)
		{
		case STRING_TRUE:
		case STRING_TRUE_HYP:
		case ROUTINE_TRUE:
		case ROUTINE_TRUE_HYP :
			*p_value = FALSE ;
			return(TRUE) ;
		case STRING_FALSE:
		case ROUTINE_FALSE:
			*p_value = TRUE ;
			return(TRUE)  ;
		}
return(FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'inference.str'
then
	echo shar: will not over-write existing file "'inference.str'"
else
cat << \SHAR_EOF > 'inference.str'
/*
**
**	This is the inference engine for which the rule compiler
**	has the task of compiling the rules into a knowledge base
**	This knowledge base has the following parts:

		hypstack consisting of a stack of integers, each
		of which points to the offset into the rule base
		which is a hypothesis.
		
		rule base consisting of an orderd set of flags and
		pointers, each comprising a single rule statement.
		Each flag identifies the type of rule and the pointer
		points to the specific string within the string buffer
		which accompanied the rule keyword.
		
		the keywords are defined in the rule compiler documentation
		so look there for it.
		
		
**
**
**
*/

/*********************INFERENCE ENGINE STRUCTURE******************/

/*
**   MAIN VERIFICATION DRIVER
**

MAIN(ARGC,ARGV)
{
READ ALL DATA FROM COMPILED RULES INTO INTERNAL BUFFERS
CLEAR THE KNOWN TRUE AND KNOWN FALSE STACKS
WHILE(ALL CONSEQUENT NOT DONE)
	{
	POP A CONSEQUENT OFF OF THE CONSEQUENT STACK (INVERSE ORDER)
	IF((CONSEQUENT IS KNOWN TRUE) OR (CONSEQUENT IS KNOWN FALSE))
		{
		CONTINUE
		}
	VERIFY(CONSEQUENT) 
	IF(CONSEQUENT IS TRUE)
		{
		IF(CONSEQUENT.FLAG == ROUTINE_TRUE)
			{
			IF(CONSEQUENT IS NOT KNOWN TRUE OR 
			     CONSEQUENT IS NOT KNOWN FALSE)
				{
				PRINT RUNNING CONSEQUENT (CONSEQUENT)
				RESULT = RUN ROUTINE (CONSEQUENT)
				TELL USER RESULT OF RUN
				}
			}
		ELSE
			{
			TELL USER THE TRUTH AND OR CONCLUSION
			}
		}
	}
IF(NO CONSEQUENT WAS PROVEN)
	{
	TELL USER "CANNOT PROVE ANYTHING"
	}
}
**
**
*/

/*
**
**	VERIFY A PARTICULAR CONSEQUENT
**

VERIFY(CONSEQUENT)  (RECURSIVE VERIFY OF THE CONSEQUENT)
{
GET ALL ANTECEDENTS FOR CONSEQUENT ONTO STACK
IF(THERE ARE NO ANTECEDENTS FOR THE CONSEQUENT)
	{
	PRINT "BAD CONSEQUENT -- HAS NO ANTECEDENTS"
	RETURN(TRUE)
	}
WHILE(ALL ANTECEDENTS FOR CONSEQUENT NOT PROVED)
	{
	POP ANTECEDENT OFF OF STACK
	IF(ANTECEDENT IS CONSEQUENT)
		{
		IF(CONSEQUENT IS KNOWN FALSE)
			{
			RETURN(FALSE)
			}
		IF(CONSEQUENT IS KNOWN TRUE)
			{
			CONTINUE
			}
		VERIFY(CONSEQUENT)
		IF(CONSEQUENT IS TRUE)
			{
			IF(CONSEQUENT.FLAG == ROUTINE_TRUE)
				{
				PRINT RUNNING CONSEQUENT (CONSEQUENT)
				RESULT = RUN ROUTINE (CONSEQUENT)
				IF (RESULT == FALSE)
					{
					RETURN(FALSE)
					}
				}
			ELSE
				{
				PUT CONSEQUENT ON KNOWN TRUE STACK
				}
			CONTINUE
			}
		ELSE
			{
			PUT CONSEQUENT ON KNOWN FALSE STACK
			RETURN(FALSE)
			}
		}
	ELSE
		{
		IF(ANTECEDENT IS KNOWN TRUE)
			{
			CONTINUE
			}
		IF(ANTECEDENT IS KNOWN FALSE)
			{
			RETURN (FALSE)
			}
		SWITCH(ANTECEDENT.FLAG):
			{
			CASE (STRING_TRUE) :
				RESULT = GET TRUTH FOR STATEMNT (ANTECEDENT)
				IF(RESULT == FALSE)
					{
					RETETURN (FALSE)
					}
				BREAK ;
			CASE (STRING_FALSE) :
				RESULT = GET TRUTH FOR STATEMNT (ANTECEDENT)
				IF(RESULT == TRUE)
					{
					RETURN(FALSE)
					}
				BREAK ;
			CASE (ROUTINE_TRUE) : 
				PRINT "RUNNING ROUTINE --"
				PRINT STRING POINTED TO BY ANTECEDENT.STRING
				RESULT = RUN ROUTINE (ANTECEDENT)
				IF(RESULT == FALSE)
					{
					RETURN (FALSE)
					}
				BREAK ;
			CASE (ROUTINE_FALSE) : 
				PRINT "RUNNING ROUTINE --"
				PRINT STRING POINTED TO BY ANTECEDENT.STRING
				RESULT = RUN ROUTINE(ANTECEDENT)
				IF(TRUE)
					{
					RETURN(FALSE)
					}
				BREAK ;
			DEFAULT:
				'DIS IS SOME PROBLEM MAMA!
			}
		}
	}
RETURN(TRUE)
}

**
**
*/

/*
**
**	ROUTINE FOR GETTING TRUTH OUT OF USER
**	PRINTS STRING AND ASKS FOR WHETHER IT IS TRUE OR FALSE
**

GET TRUTH FOR STATEMNT(ANTECEDENT)
{
PRINT "IS THE FOLLOWING TRUE?"
PRINT STATEMENT AT ANTECEDENT.STRING
GET USER RESPONSE (YES, WHY OR NO)
DO FOREVER
	{
	IF(USER RESPONSE IS YES)
		{
		PLACE ANTECEDENT IN KNOWN TRUE STACK
		RETURN(TRUE)
		}
	IF(USER RESPONSE IS NO)
		{
		PLACE ANTECEDENT IN KNOW FALSE STACK
		RETETURN (FALSE)
		}
	IF(USER RESPONSE IS WHY)
		{
		PRINT OUT CONSEQUENT/ANTECEDENT STACK IN A NICE FORMAT
		}
	}
}
**
**
*/

/*
**
**	ROUTINE TO TEST THE TRUTH OF A ROUTINE
**


RUN ROUTINE (ANTECEDENT)
{
SPAWN THE ROUTINE NAMED IN THE STRING POINTED TO BY ANTECEDENT.STRING
WAIT FOR ROUTINE TO FINISH
GET RESULT OF THE ROUTINE
IF(RESULT OF ROUTINE IS TRUE)
	{
	PLACE ANTECEDENT IN KNOWN TRUE STACK
	RETURN(TRUE)
	}
ELSE
	{
	PLACE ANTECEDENT IN KNOWN FALSE STACK
	RETURN (FALSE)
	}
}

**
**
**
*/


SHAR_EOF
fi # end of overwriting check
if test -f 'makeinfe'
then
	echo shar: will not over-write existing file "'makeinfe'"
else
cat << \SHAR_EOF > 'makeinfe'
#
# 	Makefile 
# 

# debug the file and do a 80286 model

#CFLAGS = /DDEBUG /DMSDOS /G2 /Zd /Od /Fc

CFLAGS = /DMSDOS 

# All object modules

inference.obj : inference.c expert.h 
	msc $(CFLAGS) inference.c ;

verify.obj : verify.c expert.h inference.h expert.h
	msc $(CFLAGS) verify.c ;
	lib inference -verify +verify ;

runrouti.obj : runrouti.c inference.h expert.h routine.h
	msc $(CFLAGS) runrouti.c ;
	lib inference -runrouti +runrouti ;

verifytr.obj : verifytr.c inference.h expert.h
	msc $(CFLAGS) verifytr.c ;
	lib inference -verifytr +verifytr ;

weknow.obj : weknow.c inference.h expert.h
	msc $(CFLAGS) weknow.c ;
	lib inference -weknow +weknow ;

remante.obj : remante.c inference.h expert.h routine.h
	msc $(CFLAGS) remante.c ;
	lib inference -remante +remante ;

gettruth.obj : gettruth.c inference.h expert.h	
	msc $(CFLAGS) gettruth.c ;
	lib inference -gettruth +gettruth ;
	


# 	inference.exe -- main target
#
inference.exe : inference.obj inference.lib 
#	link inference.obj ,inference.exe, inference.map, inference.lib /MAP/LINE/STACK:9000 ;
 	link inference.obj ,inference.exe, inference.map, inference.lib /STACK:9000 ;
#
#	mapsym inference
#
SHAR_EOF
fi # end of overwriting check
if test -f 'makercom'
then
	echo shar: will not over-write existing file "'makercom'"
else
cat << \SHAR_EOF > 'makercom'
#
# 	Makefile 
# 

# debug the file and do a 80286 model

#CFLAGS = /DDEBUG /G0 /Zd /Od /Fc

CFLAGS = /G0

# All object modules

rulecomp.obj : rulecomp.c expert.h keywords.h
	msc $(CFLAGS) rulecomp.c ;

getkeywo.obj : getkeywo.c expert.h
	msc $(CFLAGS) getkeywo.c ;

putstrin.obj : putstrin.c expert.h
	msc $(CFLAGS) putstrin.c ;


# 	rulecomp.exe -- main target
#
rulecomp.exe : rulecomp.obj getkeywo.obj putstrin.obj 
	link rulecomp.obj getkeywo.obj putstrin.obj ,rulecomp.exe,/STACK:15000 ;
#	link rulecomp.obj getkeywo.obj putstrin.obj ,rulecomp.exe,/MAP/LINE/STACK:15000 ;
#
#	mapsym rulecomp
#
SHAR_EOF
fi # end of overwriting check
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
To compile:

cc *.c -DUNIXSV -o inference


There is no need for a make but the one included is for the
Microsoft make command which comes whith their 4.0 Macro-assembler.

Geo.
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

tools@raybed2.UUCP (TOOLS) (01/27/86)

As requested by the author we are reposting the source and documentation of
a C inference engine. Address all questions to George Hageman at:
UUCP: {asgb!benish}!hageman
MAIL:	George W. Hageman
	P.O. Box 11234
	Boulder, Colorado  80301
NOTE: RAYTHEON Inc. is not reponsible for the contents and/or consequences
of use of this software. This software is totally the work of George Hageman
and is being reposted as per his request (see following message). Address all
questions, comments, etc. to him.
=========================================================================
>From linus!decvax!seismo!hao!asgb!benish!hageman Fri Jan 24 07:31:04 1986
>Subject: Re:  C inference engine
>
>	... it seems that
>	the probability of getting somthing out to net.and is
>	inversely proportional to the number of hops it has to go.
>
>	I'll send you all of the shars (inference rulecompiler and 
>	the storm expert).  If you could make sure that they are
>	available at your site either by reposting them from your
>	end or by some other means it would be appreciated.
>
>	Thanks,
>
>George [Hageman]
=========================================================================
____Cut for rulecomp.sh______
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	expert.h
#	infer.h
#	inferenc.h
#	keywords.h
#	routine.h
#	getkeywo.c
#	putstrin.c
#	rulecomp.c
#	README.TO
#	makercom
#	rulecomp.str
# This archive created: Sun Jan 12 16:13:31 1986
export PATH; PATH=/bin:$PATH
if test -f 'expert.h'
then
	echo shar: will not over-write existing file "'expert.h'"
else
cat << \SHAR_EOF > 'expert.h'

/*************************************************************************
**									**
**	The software contained in this distribution is copyright (C)	**
**	by George Hageman 1985 and is released into the public 		**
**	domain with the following restrictions:	 			**
**									**
**		(1)  This software is intended for non-commertial	**
**			usage.						**
**		(2)  I am held save from damages resulting from		**
**			its use, and					**
**		(3)  The following concepts and legal jargon are	**
**			agreed to by the user of this software.		**
**									**
**	User-supported software concept: 				**
**									**	
**	IF    you find use for this software				**
**	ANDIF it saves you some development time			**
**	THEN        send me $10.00					**
**	ANDTHENHYP  you will feel good!					**
**									**
**									**
**	This source code is provided on an "as is" basis without	**
**	warranty of any kind, expressed or implied, including but	**
**	not limited to the implied warranties of merchantability	**
**	and fitness for a particular purpose.  The entire risk as	**
**	to quality and performance of this software is with you. 	**
**	Should the software prove defective, you assume the entire	**
**	cost of all necessary repair, servicing, or correction.  In	**
**	no event will the author be liable to you for any damages,	**
**	including any lost profits, lost savings, or other		**
**	incidental or consequential damages arising out of the  use	**
**	of inability to use this software.  In short my friends, I	**
**	have done  a reasonable ammount of work in debugging this	**
**	software and I think it is pretty good but, as you know,	**
**	there is always some chance that a bug is still lurking 	**
**	around. If you should happen to be lucky enough to  find one,	**
**	please let me know so I	can make an attempt to fix it.		**
**									**
**				Thanks,					**
**									**
**				George Hageman				**
**				P.O. Box 11234				**
**				Boulder, Colorado 80302			**
**									**
*************************************************************************/


/*
**	These are the structures of the rulebase which will
**	be used to compile the rules into.  
*/

#define FALSE 			0 
#define TRUE  			-1 
#define MAX_STRING_BUFF 	5000
#define MAX_STR_LEN		100
#define MAX_RULE_STATEMENTS 	500
#define MAX_HYPS		250 
#define ANTECEDENT 		1
#define CONSEQUENT 		2
#define COMMENT_CHAR		'!'
#define	BLANK 			0x20
#define EOL			0x0a

#define KEY_EOF			-2 
#define LINE_ERROR		-3
#define KEY_WORD_ERROR		-4
#define ERROR		 	-5	
#define STR_LEN_ERROR		-6

/*
**	Other definitions of key words
*/

#define	AND_N       	 0
#define	ANDIF_N     	 1
#define	ANDIFRUN_N  	 2
#define	ANDNOT_N    	 3	
#define	ANDNOTRUN_N 	 4
#define	ANDRUN_N    	 5
#define	ANDTHEN_N   	 6 
#define ANDTHENHYP       7
#define	ANDTHENRUN_N	 8
#define	ANDTHENRUNHYP_N  9
#define	IF_N        	10
#define	IFNOT_N     	11
#define	IFNOTRUN_N  	12
#define	IFRUN_N     	13
#define	THEN_N      	14
#define	THENHYP_N     	15  
#define THENRUN_N	16
#define THENRUNHYP_N    17
		
/*
**	Flag definitions:
*/

#define	STRING_TRUE	 1
#define	STRING_FALSE	 2
#define	ROUTINE_TRUE	 3
#define ROUTINE_FALSE	 4
#define STRING_TRUE_HYP  5
#define ROUTINE_TRUE_HYP 6

#define NUM_KEYWORDS	18

struct	rule_statement_r
		{
		int flag ;   /* logical flag for inference engine */
		int string ; /* offset into string buffer */
		};


/* 
**	rules are compiled into the array rules in the folloiwng form:
**
**	antecedent-group consequent-group 
**	... 
**	antecedent-group consequent-group
**	end-group
**
**	Each group of consequences and antecedents
**	are compiled in a group like the following:
**
**	flag pointer flag pointer ... flag pointer 0-flag 0-pointer
**
**	The end-group is merely:
**
**	0-flag 0-pointer 0-flag 0-pointer 0-flag 0-pointer
**
**	flags are used by the inference engine to determine what to
**	do with the following string pointer.  
**	string pointers are merely offsets into the string array.
**	The pointers may either point
**	to a string which is a rule statement such as "the animal has wings"
**	or is a UNIX pathname for a particular routine which is to be
**	executed such as "/g1/hageman/Diagnostics/Disk1diag".   This
**	routine will then be executed and will return either a true or
**	false indication.  Latter versions of the inference engin may be
**	capable of returning more than this via some pipe-line mechanism or
**	other.
**
**	Once an anicedent whether string or routine is verified it is placed
**	in either a known-true or known-false stack for later verification 
**	in other rules which use them.  In short they only have to be verified
**	once.
**
**	Examples of a rule structure are:
**
**	IFNOT the animal is a bird
**	AND the animal has wings
**	ANDNOT the animal lives in caves
**	AND the animal is nocternal
**	THEN the animal is a bat
**	IF the animal is a bat
**	ANDRUN /g1/hageman/Src/Expert/speed_of_bat
**	THENHYP the bat is out of hell
**	IF the animal is a bat
**	ANDNOTRUN /g1/hageman/Src/Expert/speed_of_bat
**	THENHYP the bat is out of cave
**
*/
SHAR_EOF
fi # end of overwriting check
if test -f 'infer.h'
then
	echo shar: will not over-write existing file "'infer.h'"
else
cat << \SHAR_EOF > 'infer.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*
**	the following are the global common variables which
**	are used in the inference engine...
**
**	all routines except inference.c should have this
**	file included.
*/

#define	MAX_KNOWN	500

int	numHypot, hypStack[MAX_HYPS],strBuffOfst ;
char	strBuff[MAX_STRING_BUFF] ;
int	ruleBuffOfst ;
int	knownTrue[MAX_KNOWN], knownFalse[MAX_KNOWN] ;
int	numTrue, numFalse ;
struct  rule_statement_r ruleBuff[MAX_RULE_STATEMENTS] ;

SHAR_EOF
fi # end of overwriting check
if test -f 'inferenc.h'
then
	echo shar: will not over-write existing file "'inferenc.h'"
else
cat << \SHAR_EOF > 'inferenc.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*************************************************************************
**									**
**	The software contained in this distribution is copyright (C)	**
**	by George Hageman 1985 and is released into the public 		**
**	domain with the following restrictions:	 			**
**									**
**		(1)  This software is intended for non-commertial	**
**			usage.						**
**		(2)  I am held save from damages resulting from		**
**			its use, and					**
**		(3)  The following concepts and legal jargon are	**
**			agreed to by the user of this software.		**
**									**
**	User-supported software concept: 				**
**									**	
**	IF    you find use for this software				**
**	ANDIF it saves you some development time			**
**	THEN        send me $10.00					**
**	ANDTHENHYP  you will feel good!					**
**									**
**									**
**	This source code is provided on an "as is" basis without	**
**	warranty of any kind, expressed or implied, including but	**
**	not limited to the implied warranties of merchantability	**
**	and fitness for a particular purpose.  The entire risk as	**
**	to quality and performance of this software is with you. 	**
**	Should the software prove defective, you assume the entire	**
**	cost of all necessary repair, servicing, or correction.  In	**
**	no event will the author be liable to you for any damages,	**
**	including any lost profits, lost savings, or other		**
**	incidental or consequential damages arising out of the  use	**
**	of inability to use this software.  In short my friends, I	**
**	have done  a reasonable ammount of work in debugging this	**
**	software and I think it is pretty good but, as you know,	**
**	there is always some chance that a bug is still lurking 	**
**	around. If you should happen to be lucky enough to  find one,	**
**	please let me know so I	can make an attempt to fix it.		**
**									**
**				Thanks,					**
**									**
**				George Hageman				**
**				P.O. Box 11234				**
**				Boulder, Colorado 80302			**
**									**
*************************************************************************/


/*
Expert system inference engine

This inference engine is backwards-chaining only and features the
running of binary files if:

	1) they are antecedents associated with a particuar consequent
	   being proved, or
	2) they are consequents which have been proven true by verify().
	   their actual predicate value will be determined by their returned
	   result after running.

This inference engine is designed with diagnostics in mind and so will probably
be best suited for this application.  Later revisons will include 
forward-chaining so that the user will have the opportunity to give pre-existant
conditons, or that these my be supplied by the calling process.

(If you cant tell by the above description -- I am very excited about the 
possibilties presented in this form of computer control of the diagnostic
process... Geo.)

See structure design for details of operation,  but basically the 

inference reads in all of the compiled information as produced by the
    rule compiler.
    
it proceeds to attempt to prove each consequent by proving the truth
	or falseness of any antecedent associated with this consequent.
if any antecedent of a consequent turns out to be a consequent itself, then
        the inference engine will recursively attempt to prove this consequent.

the process is complete when all of the predicate values of the consequents has
	been determined.
	
Additional features which I may put in at a later time is the abiltiy for
the inference engine to expalin itself to the user when the user asks why
the inference engine needs to know the predicate value of a particular
antecedent.   This will be done by forward and backward chaining of predicat
clauses, the truth of each will be displayed.
*/
#define	MAX_ANTECEDENTS		25

extern 	int	numHypot, hypStack[],strBuffOfst ;
extern 	char	strBuff[] ;
extern	int	ruleBuffOfst ;
extern	int	knownTrue[], knownFalse[] ;
extern	int	numTrue, numFalse ;
extern	struct  rule_statement_r ruleBuff[] ;
SHAR_EOF
fi # end of overwriting check
if test -f 'keywords.h'
then
	echo shar: will not over-write existing file "'keywords.h'"
else
cat << \SHAR_EOF > 'keywords.h'

char	*keyWords[NUM_KEYWORDS] =
	{
	"AND           ",
	"ANDIF         ",
	"ANDIFRUN      ",
	"ANDNOT        ",
	"ANDNOTRUN     ",
	"ANDRUN        ",
	"ANDTHEN       ", 
	"ANDTHENHYP    ",
	"ANDTHENRUN    ",
	"ANDTHENRUNHYP ",
	"IF            ",
	"IFNOT         ",
	"IFNOTRUN      ",
	"IFRUN         ",
	"THEN          ",
	"THENHYP       ",
	"THENRUN       ",
	"THENRUNHYP    "
	} ;

SHAR_EOF
fi # end of overwriting check
if test -f 'routine.h'
then
	echo shar: will not over-write existing file "'routine.h'"
else
cat << \SHAR_EOF > 'routine.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*
**	these are the two return values
**	which must be returned as the exit
**	value.  Any other will result in
**	an assumption that the result is true
**	or that some sort of error occured.
*/

#define RETURN_ROUTINE_TRUE	254
#define RETURN_ROUTINE_FALSE	255

SHAR_EOF
fi # end of overwriting check
if test -f 'getkeywo.c'
then
	echo shar: will not over-write existing file "'getkeywo.c'"
else
cat << \SHAR_EOF > 'getkeywo.c'

#include <stdio.h>
#include <string.h>
#include "expert.h"


/******************************************************************
**
**
**		GET KEYWORD
**
**
******************************************************************/

/*
**
**	getKeyWord(infile,keyWords,lineNum) ;
**
**	returns either KEY_EOF, or number of keyword, or indications
**		that keyword was not first word on line.
**
*/

int	getKeyWord (infile,keyWords,lineNum)

FILE	*infile ;
char	*keyWords[] ;
int	*lineNum ;

{
int	firstc,c,i,j ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD") ;
#endif

/*
**	get first non blank character
*/

i = 0 ;
while( TRUE )
	{
	c = getc(infile);
	putchar(c) ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD character= %c,%x",c,c) ;
#endif
	if( c == EOF )
		return (KEY_EOF) ;
	if( (i == 0) && (c == COMMENT_CHAR) )	/* ignore comment line */
		{
		while(  c != EOL )
			{
#ifdef DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD (delete comment) character=%c,%x",c,c);
#endif
			c = getc(infile) ;
			if( c == EOF)
				return (KEY_EOF) ;
			putchar(c) ;
			} 
		printf("%04d  ",*lineNum) ;
		*lineNum += 1 ;
		i = 0 ;
		}
	else
		{
		i = 1 ;
		if( c != BLANK )
			{
			if(c == EOF)
				return(KEY_EOF) ;
			break ;
			}
		}
	}

/*
**	locate first keyword with matching first character
*/

for( i = 0 ; i < NUM_KEYWORDS ; i++ )
	{
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD i=%d, keyword=%c",i,*(keyWords[i])) ;
#endif
	if ( *(keyWords[i]) == c )
		break ;
	}
if( i == NUM_KEYWORDS )
	return (KEY_WORD_ERROR)  ;

/*
**	find the key word if there
**
**	Note that this search algrorithm is very dependant on having
**	the keyWord file being in strict alphabetical order!!!
**
*/

j=0 ; 		
firstc = c ;

while( i < NUM_KEYWORDS  )
	{
	if( (c=getc(infile)) == *(keyWords[i]+(++j)) )
		{
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD char=%c,keyword=%c",c,*((keyWords[i])+j)) ;
#endif
		putchar(c) ;
		if( c == BLANK )
			return (i) ;
		if( c == EOF )
			return(KEY_EOF) ;
		}
/*
**	increment the keyWord pointer to be tested
**	decrement the character pointer in keyWord
**	and put the last character tested back.
*/

/*
**	since the keyWord array is alphabetical, testing
**	for a first character change would indicate that
**	the possible keywords have been exhausted.
*/

	else
		{
		i++ ;
		j-- ;
		ungetc(c,infile) ;
		if( c == EOF )
			return (KEY_EOF) ;
		if( firstc != *(keyWords[i]))
			return (KEY_WORD_ERROR) ;
		}
	}

/*
**	no keywords were found because we exhausted the keyWord array
*/

return (KEY_WORD_ERROR)  ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'putstrin.c'
then
	echo shar: will not over-write existing file "'putstrin.c'"
else
cat << \SHAR_EOF > 'putstrin.c'

#include <stdio.h>
#include <string.h>
#include "expert.h"


/*****************************************************************
**
**	PUT STRING
**
**	looks for string on rule line and
**	    either returns the offset into the
**		string buffer if found or places
**		it into the string buffer and returns
**		the offset to it.
**	strBuffOfst is the pointer to the offset to
**		the last used location in the string buffer
**
**
*****************************************************************/

int	putString (infile,strBuff,strBuffOfst) 

	FILE	*infile ;
	char	*strBuff ;
	int	*strBuffOfst ;

{
int	i,offSet,strLen,c,newline ;
char	buff[MAX_STR_LEN] ;

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
#endif

/*
**
**	get file positioned to first non blank character (after keyword)
**
*/

while( ( c=getc(infile)) == BLANK )
	putchar(c) ;
if( c == EOL )
	{
	putchar(c) ;
	return (LINE_ERROR) ;
	}
if( c == EOF )
	return (KEY_EOF) ;
ungetc(c,infile);

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING c = %c", c) ;
#endif
/*
**
** 	load the string on the line into the string buffer for 
**	later comparison to strings in the line buffer.
**
*/
newline = FALSE ;
for( i = 0 ; i < (MAX_STR_LEN-1) ; i++ )
	{
	buff[i]=c=getc(infile) ;

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING c =%c, i = %d -- ", c,i) ;
#endif
	putchar(c) ;
	if(c == '\\')
		{
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING newline is TRUE");
#endif
		newline = TRUE ;
		continue ;
		}
	if( newline == TRUE )
		{
		if( c == 'n' ) 
			{
			i -= 1 ;
			buff[i] = '\n' ;
			}
#ifdef	DEBUG
		fprintf(stdout,"\nDEBUG-PUTSTRING newline is FALSE");
#endif
		newline = FALSE ;
		continue ;
		}
	if(c == EOL)
		{
		buff[i]=0 ;
		break ;
		}
	if(c == EOF)
		{
		buff[i]=0 ;
		ungetc(c,infile) ;
		break ;
		}
	}

/*
**	remove trailing blanks in the buffer 
**
*/
for( --i ; i > -1 ; i-- )
	{
	if( buff[i] != BLANK )
		break ;
	buff[i]=0 ;
	}	
if(i <= 0)
	return(STR_LEN_ERROR) ;
strLen = i ;

buff[MAX_STR_LEN-1] = 0 ;

/*
**	at this point strLen should be the offset to the last character
**	in the string and is also, therefore, the length of the string -1
**
**	search for the string in the string buffer
**	return offset to string if found else put the string
**	in the string buffer and uptate buffer offset returning
**	pointer to new string
**
*/

offSet = 0 ;
while( offSet < *strBuffOfst )
	{
	if( strcmp(&strBuff[offSet], buff) == 0 )
		return(offSet) ;
	while( strBuff[++offSet] ) ;   	/* look for end of null trmntd string */
	++offSet ;			/* move past the null to next string  */
	}
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
	fprintf(stdout,"\nDEBUG-PUTSTRING offSet = %d",offSet) ;
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuff= %s",&strBuff[offSet]);
	fprintf(stdout,"\nDEBUG-PUTSTRING buff   = %s",buff) ;
#endif
strcpy(&strBuff[*strBuffOfst],buff) ;
if(*strBuffOfst == 0 )
	{
	*strBuffOfst += strLen + 2 ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
#endif
	return(0) ;
	}
else
	{
	offSet = *strBuffOfst ;
	*strBuffOfst += strLen + 2 ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
#endif
	return(offSet) ;
	}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'rulecomp.c'
then
	echo shar: will not over-write existing file "'rulecomp.c'"
else
cat << \SHAR_EOF > 'rulecomp.c'

/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*****************************************************************
**	Expert system rule compiler
**
**	This compiler produces a file of the form:
**
**	Number_of_bytes_in_hypstack_section
**	Hypstack_section
**	Number_of_bytes_in_rule_section
**	Rule base section
**	Number_of_bytes_in_string_section
**	String section
**	EOF
**	
**	The rule section consits of integer flags and long-integer
**	pointers to strings in the string section.
**	
**	All strings in the string section will be unique nomatter how
**	many times they are repeated in the rules which are compiled
**	into the rule base by this compiler.
**
**
**	Usage:
**
**	rulecomp rule.file object.file
**
*****************************************************************/

/*****************************************************************
**
**	rule compiler main routine
**
*******************************************************************/

#include <stdio.h>
#include <string.h>

#include "expert.h"
#include "keywords.h"

int	main(argc,argv)
int argc ;
char **argv ;

{
char	strBuff[MAX_STRING_BUFF] ;
int	i ;
int	state ;
int	strAddr;
int	numHypot, hypStack[MAX_HYPS],strBuffOfst ;
int	c ;
int	ruleBuffOfst ;
int	keyWrdNum ;
int	getKewWord() ;
int	putString() ;
int	lineNum ;

struct  rule_statement_r ruleBuff[MAX_RULE_STATEMENTS] ;

int	done ;
FILE	*infile, *outfile ;

for( done = 0; done < MAX_STRING_BUFF; done ++ )
	strBuff[done] = 0 ;
for( done = 0; done < MAX_HYPS ; done++ )
	hypStack[done]=0 ;
done = FALSE ;

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP argc=%d ",argc) ;
#endif

if(argc != 3 )
	{
	fprintf(stdout, "\n\n Usage: rulecomp in.file out.file\n\n" ) ;
	exit() ;
	}
infile = fopen( argv[1], "r" );
if(infile == NULL)
	{
	fprintf(stdout,"\n\n Cannot open input file %s ", argv[1]);
	exit() ;
	}
outfile = fopen(argv[2], "wb" ) ;
if(outfile == NULL)
	{
	fprintf(stdout,"\n\n Cannot open output file %s ",argv[2]);
	exit() ;
	}
done = FALSE ;

numHypot = 0 ;				/* number of hypothesis is zero */
strBuffOfst = 0 ;			/* pointer in buffer is zero */
ruleBuffOfst = 0 ;			/* rule buffer offset is zero */


state = ANTECEDENT ;

/* Compilation states:
**
**	Antecedent group in progress -- 1
**	Consequent group in progress -- 2
**
**	If state 1 and you get a consequent then output group barrier.
**		change state to 2.
**	If state 2 and you get an antecedent then output group barrier.
**		change state to 1.
*/
lineNum = 1 ;
printf("\n") ;
while( !done )
	{

/*
**   	get the key word number from the
**	input file
*/
	printf("%04d  ",lineNum++) ;
	keyWrdNum = getKeyWord(infile,keyWords,&lineNum);
/*
**	error occured on line clear the line and
**	start over.
*/
	if(keyWrdNum == KEY_EOF)
		{
		done = TRUE ;
		continue ;
		}
	if(keyWrdNum == KEY_WORD_ERROR)
		{
		while( ( (c = getc(infile))) != EOL && (c != EOF) )
			putchar(c) ;
		fprintf(stdout," **** KEY WORD not found on line " );
		if(c == EOF)
			{
			done = TRUE ;
			break ;
			}
		putchar(c) ;
		continue;
		}
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP keyWrdNum = %d",keyWrdNum ) ;
#endif
/*
**	based on the key Word build the
**	rule files
*/

	switch(keyWrdNum)
		{
		case AND_N :
		case ANDIF_N :
		case IF_N :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case AND_N, ANDIF_N, IF_N ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = STRING_TRUE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr= %d",strAddr ) ;
#endif
			break ;
		case ANDRUN_N :
		case ANDIFRUN_N :
		case IFRUN_N :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case AND_N, ANDIF_N, IF_N ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = ROUTINE_TRUE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr= %d",strAddr ) ;
#endif
			break ;
		case ANDNOT_N :
		case IFNOT_N  :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDNOT_N, IFNOT_N    ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = STRING_FALSE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case ANDNOTRUN_N :
		case IFNOTRUN_N  :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDNOT_N, IFNOT_N    ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = ROUTINE_FALSE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case ANDTHEN_N :
		case THEN_N :
		case THENHYP_N :
		case ANDTHENHYP :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDTHEN_N,THEN_N,THENHYP_N");
#endif
			if(state == ANTECEDENT)
				{
				state = CONSEQUENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}

			if( (keyWrdNum == THENHYP_N) || (keyWrdNum == ANDTHENHYP) )
				ruleBuff[ruleBuffOfst].flag = STRING_TRUE_HYP ;
			else
				ruleBuff[ruleBuffOfst].flag = STRING_TRUE ;

			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			hypStack[numHypot++] = ruleBuffOfst ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case ANDTHENRUN_N :
		case THENRUN_N :
		case THENRUNHYP_N :
		case ANDTHENRUNHYP_N :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDTHEN_N,THEN_N,THENHYP_N");
#endif
			if(state == ANTECEDENT)
				{
				state = CONSEQUENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}

			if( (keyWrdNum == THENRUNHYP_N ) || (keyWrdNum == ANDTHENRUNHYP_N) )
				ruleBuff[ruleBuffOfst].flag = ROUTINE_TRUE_HYP ;
			else
				ruleBuff[ruleBuffOfst].flag = ROUTINE_TRUE ;

			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			hypStack[numHypot++] = ruleBuffOfst ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case KEY_EOF :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case KEY_EOF ") ;
#endif
			done = TRUE ;
			break ;
		default:
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case DEFAULT "  ) ;
#endif
			fprintf(stdout, " \n\n illegal keyword number found " );
		}
	}

/* 
**	set up some blank space at the end of the rule file 
*/

ruleBuff[ruleBuffOfst].flag = NULL ;
ruleBuff[ruleBuffOfst++].string = NULL ;
ruleBuff[ruleBuffOfst].flag = NULL ;
ruleBuff[ruleBuffOfst++].string = NULL ;
ruleBuff[ruleBuffOfst].flag = NULL ;
ruleBuff[ruleBuffOfst++].string = NULL ;
if(ruleBuffOfst%2 == 0 )
	{
	ruleBuff[ruleBuffOfst].flag = NULL ;
	ruleBuff[ruleBuffOfst++].string = NULL ;
	}
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP ruleBoffOfst=%d", ruleBuffOfst ) ;
#endif
/*
**	ruleBuffOfst -3 is the number of rule statements processed 
*/

/*
**
**	Write out all of the compiled information as follows:
**
**		numHypot*2	Number_of_bytes_in_hypstack_section
**		hypStack	Hypstack_section
**		ruleBuffOfst	Number_of_bytes_in_rule_section
**		ruleBuff	Rule base section
**		strBuffOfst	Number_of_bytes_in_string_section
**		strBuff		String section
**		EOF
**
*/
#ifdef DEBUG

	fprintf(stdout,"\nDEBUG numHypot=%d",numHypot ) ;

	for(i=0;i<numHypot;i++)
		fprintf(stdout,"\nDEBUG     hypStack=%d",hypStack[i] ) ;

	fprintf(stdout,"\nDEBUG ruleBuffOfst=%d  ",ruleBuffOfst ) ;

	for(i=0;i<ruleBuffOfst;i++)
		{
		fprintf(stdout,"\nDEBUG ruleBuff[%d].flag=%d ",i,ruleBuff[i].flag ) ;
		fprintf(stdout,"\nDEBUG ruleBuff[%d].string=%d ",i,ruleBuff[i].string ) ;
		}

	fprintf(stdout,"\nDEBUG strBuffOfst=%d",strBuffOfst ) ;

	for(i=0;i<strBuffOfst;i++)
		fprintf(stdout,"\nDEBUG strBuff[%d]=%d(d),%c(c)",i,strBuff[i],strBuff[i] ) ;
#endif
fwrite(&numHypot,sizeof(int),1,outfile) ;
fwrite(hypStack,sizeof(int),numHypot,outfile) ;
fwrite(&ruleBuffOfst,sizeof(int),1,outfile) ;
fwrite(ruleBuff,2*sizeof(int),ruleBuffOfst,outfile) ;
fwrite(&strBuffOfst,sizeof(int),1,outfile) ;
fwrite(strBuff,1,strBuffOfst,outfile) ;
fclose(infile);
fclose(outfile);
#ifdef DEBUG
	fclose(stdout) ;
#endif
printf("\n\n") ;
exit(0) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'README.TO'
then
	echo shar: will not over-write existing file "'README.TO'"
else
cat << \SHAR_EOF > 'README.TO'
To compile:

cc *.c -DUNIXSV -orulecomp


No other command is necessary..

Geo.


SHAR_EOF
fi # end of overwriting check
if test -f 'makercom'
then
	echo shar: will not over-write existing file "'makercom'"
else
cat << \SHAR_EOF > 'makercom'
#
# 	Makefile 
# 

# debug the file and do a 80286 model

#CFLAGS = /DDEBUG /G0 /Zd /Od /Fc

CFLAGS = /G0

# All object modules

rulecomp.obj : rulecomp.c expert.h keywords.h
	msc $(CFLAGS) rulecomp.c ;

getkeywo.obj : getkeywo.c expert.h
	msc $(CFLAGS) getkeywo.c ;

putstrin.obj : putstrin.c expert.h
	msc $(CFLAGS) putstrin.c ;


# 	rulecomp.exe -- main target
#
rulecomp.exe : rulecomp.obj getkeywo.obj putstrin.obj 
	link rulecomp.obj getkeywo.obj putstrin.obj ,rulecomp.exe,/STACK:15000 ;
#	link rulecomp.obj getkeywo.obj putstrin.obj ,rulecomp.exe,/MAP/LINE/STACK:15000 ;
#
#	mapsym rulecomp
#
SHAR_EOF
fi # end of overwriting check
if test -f 'rulecomp.str'
then
	echo shar: will not over-write existing file "'rulecomp.str'"
else
cat << \SHAR_EOF > 'rulecomp.str'

/*
Pseudo code for the rule compiler :

compile_rules(rule_file,output_compile_file)
{
OPEN rule_file ;
WHILE ( EOF in rule_file NOT reached )
	{
	locate keyword
	IF ( keyword not located on line and line not blank )
		{
		OUTPUT error message to user telling of problem
		}
	place flag associated with keyword into rule section
	IF (following string is in string section)
		{
		place the address of the string into the rule section
		}
	ELSE
		{
		place the string into the string section (0 delimit)
		place the address of the string into the rule section
		}
	IF ( the keyword is a THEN or THENHYP )
		{
		place and additional IF flag and a zeroed 
		    pointer in the rule section 
		place address of hypothesis or then clause into
		    hypstack section
		}
	}
IF (last keyword not of a "HYP" type )
	{
	OUTPUT warning to user about this being a problem
	}
place  two successive IF flags - zeroed pointer into the rule section
    to mark the end of the rules section.
CLOSE rule_file 
OPEN compile_output_file 
OUTPUT number of bytes in rule section to compile_output_file
COPY rule section to compile_output_file
OUTPUT number of bytes in string section to compile_output_file
COPY string section to compile_output_file
CLOSE compile_output_file
}
*/
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

tools@raybed2.UUCP (TOOLS) (01/27/86)

As requested by the author we are reposting the source and documentation of
a C inference engine. Address all questions to George Hageman at:
UUCP: {asgb!benish}!hageman
MAIL:	George W. Hageman
	P.O. Box 11234
	Boulder, Colorado  80301
NOTE: RAYTHEON Inc. is not reponsible for the contents and/or consequences
of use of this software. This software is totally the work of George Hageman
and is being reposted as per his request (see following message). Address all
questions, comments, etc. to him.
=========================================================================
>From linus!decvax!seismo!hao!asgb!benish!hageman Fri Jan 24 07:31:04 1986
>Subject: Re:  C inference engine
>
>	... it seems that
>	the probability of getting somthing out to net.and is
>	inversely proportional to the number of hops it has to go.
>
>	I'll send you all of the shars (inference rulecompiler and 
>	the storm expert).  If you could make sure that they are
>	available at your site either by reposting them from your
>	end or by some other means it would be appreciated.
>
>	Thanks,
>
>George [Hageman]
=========================================================================
____Cut for storm.sh _____
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	routine.h
#	weather.h
#	edir.c
#	gt_301.c
#	gt_302.c
#	lt_298.c
#	lt_301.c
#	message1.c
#	ndir.c
#	nedir.c
#	nwdir.c
#	rpd_fall.c
#	rpd_rise.c
#	sdir.c
#	sedir.c
#	slo_fall.c
#	slo_rise.c
#	steady.c
#	swdir.c
#	wdir.c
#	animal
#	weather
#	makefile
# This archive created: Sun Jan 12 16:14:38 1986
export PATH; PATH=/bin:$PATH
if test -f 'routine.h'
then
	echo shar: will not over-write existing file "'routine.h'"
else
cat << \SHAR_EOF > 'routine.h'
/*
**	these are the two return values
**	which must be returned as the exit
**	value.  Any other will result in
**	an assumption that the result is true
**	or that some sort of error occured.
*/

#define RETURN_ROUTINE_TRUE	254
#define RETURN_ROUTINE_FALSE	255

SHAR_EOF
fi # end of overwriting check
if test -f 'weather.h'
then
	echo shar: will not over-write existing file "'weather.h'"
else
cat << \SHAR_EOF > 'weather.h'

#define	NORTH		1
#define NORTH_EAST	2
#define EAST		3
#define SOUTH_EAST	4
#define SOUTH		5
#define SOUTH_WEST	6
#define WEST		7
#define NORTH_WEST	8

#define STEADY		1
#define RISE_SLOW	2
#define RISE_FAST	3
#define FALL_SLOW	4
#define FALL_FAST	5


SHAR_EOF
fi # end of overwriting check
if test -f 'edir.c'
then
	echo shar: will not over-write existing file "'edir.c'"
else
cat << \SHAR_EOF > 'edir.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==EAST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'gt_301.c'
then
	echo shar: will not over-write existing file "'gt_301.c'"
else
cat << \SHAR_EOF > 'gt_301.c'
#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[0]>3010)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'gt_302.c'
then
	echo shar: will not over-write existing file "'gt_302.c'"
else
cat << \SHAR_EOF > 'gt_302.c'
#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[0]>=3020)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'lt_298.c'
then
	echo shar: will not over-write existing file "'lt_298.c'"
else
cat << \SHAR_EOF > 'lt_298.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[0]<2980)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'lt_301.c'
then
	echo shar: will not over-write existing file "'lt_301.c'"
else
cat << \SHAR_EOF > 'lt_301.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[0]<=3010)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'message1.c'
then
	echo shar: will not over-write existing file "'message1.c'"
else
cat << \SHAR_EOF > 'message1.c'
#include <stdio.h>

#include "routine.h"
#include "weather.h"	/* common definitions for direction and stuff */


int main()
/*
**	note that argv[1] is a pointer to our array of common value
*/

{
char	string[20] ;
int	test ;
int	value[20] ;
FILE	*dataFile ;

dataFile = fopen("WEATHER.DAT","wb") ;

for(test = 0 ; test < 20 ; test++)
	value[test] = 0 ;

/*
**	value[0] = barometric pressure * 100
**	value[1] = condition of pressure
**		1-steady, 2-rise_slow, 3-rise_fast, 4-fall-slow, 5-fall-fast
**	value[2] = direction of ground wind 
**		1-n, 2-ne, 3-e, 4-se, 5-s, 6-sw, 7-w, 8-nw
**
*/

printf("\n \nWEATHER EXPERT: \n") ;
printf("\n This program attempts to prove one of the following:");
printf("\n\tthe weather is ok\n\tthe weather is improving\n\tthe weather is deteriorating\n");
printf("\nNot all weather cases are included in the forecast algorithm.");
printf("\n\nBefore we attempt a forecast, I need some data\n What is the barometric pressure reading?\n");
test = 0 ;
while((test < 2000) || (test > 4000))
	{
	printf("\n(Type in the pressure as an integer (BP*100) 30.1 = 3010...?");
	scanf("%d",&value[0]) ;
	test = value[0] ;
	}
printf("\n\t Thankyou!,  \n\n Now I need to know how the barometer is acting\n");
test = 0;
while((test <1) || (test >5))
	{
	printf("\n\t Please input the correct number for the following:\n");
	printf("\n\t 1 -- It is steady\n\t 2 -- It is rising slowly\n\t 3 -- It is rising rapidly") ;
	printf("\n\t 4 -- It is falling slowly\n\t 5 -- It is falling rapidly \n?");
	scanf("%d",&value[1]);
	test = value[1] ;
	}
test = 0 ;
printf("\n\t Thankyou,") ;
while((test < 1) || ( test > 8 ) )
	{
	printf("\n\nNow I need the wind direction, which direction is it blowing from?\n");
	printf("<n, ne, e, se, s, sw, w, nw>?") ;
	scanf("%s",string) ;
	if(0 == strcmp(string,"n"))
		value[2]=NORTH ;
	if(0 == strcmp(string,"ne"))
		value[2]=NORTH_EAST ;
	if(0 == strcmp(string,"e"))
		value[2]=EAST ;
	if(0 == strcmp(string,"se"))
		value[2]=SOUTH_EAST ;
	if(0 == strcmp(string,"s"))
		value[2]=SOUTH ;
	if(0 == strcmp(string,"sw"))
		value[2]=SOUTH_WEST ;
	if(0 == strcmp(string,"w"))
		value[2]=WEST ;
	if(0 == strcmp(string,"nw"))
		value[2]=NORTH_WEST ;
	if(0 == strcmp(string,"N"))
		value[2]=NORTH ;
	if(0 == strcmp(string,"NE"))
		value[2]=NORTH_EAST ;
	if(0 == strcmp(string,"E"))
		value[2]=EAST ;
	if(0 == strcmp(string,"SE"))
		value[2]=SOUTH_EAST ;
	if(0 == strcmp(string,"S"))
		value[2]=SOUTH ;
	if(0 == strcmp(string,"SW"))
		value[2]=SOUTH_WEST ;
	if(0 == strcmp(string,"W"))
		value[2]=WEST ;
	if(0 == strcmp(string,"NW"))
		value[2]=NORTH_WEST ;
	test = value[2] ;
	}
printf("\n\n\n\n For the next question, you should stand outside with your back");
printf("\nto the surface wind.  You now must observe the direction the");
printf("\nupper level clouds are moving.  You observe them to be moving") ;
printf("\nfrom your right, from your left, or in a direction parallel") ;
printf("\nto that which your are facing.\n") ;
printf("\nUse this information to answer the following question.  If you");
printf("\nare unable to see the upper level clouds, answer no to the following");
printf("\nquestion.\n\n") ;
fwrite(value,2,20,dataFile) ;
fclose(dataFile) ;
exit(RETURN_ROUTINE_TRUE) ;
}





SHAR_EOF
fi # end of overwriting check
if test -f 'ndir.c'
then
	echo shar: will not over-write existing file "'ndir.c'"
else
cat << \SHAR_EOF > 'ndir.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==NORTH)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'nedir.c'
then
	echo shar: will not over-write existing file "'nedir.c'"
else
cat << \SHAR_EOF > 'nedir.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==NORTH_EAST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'nwdir.c'
then
	echo shar: will not over-write existing file "'nwdir.c'"
else
cat << \SHAR_EOF > 'nwdir.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==NORTH_WEST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'rpd_fall.c'
then
	echo shar: will not over-write existing file "'rpd_fall.c'"
else
cat << \SHAR_EOF > 'rpd_fall.c'



#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[1]==FALL_FAST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'rpd_rise.c'
then
	echo shar: will not over-write existing file "'rpd_rise.c'"
else
cat << \SHAR_EOF > 'rpd_rise.c'


#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[1]==RISE_FAST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'sdir.c'
then
	echo shar: will not over-write existing file "'sdir.c'"
else
cat << \SHAR_EOF > 'sdir.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==SOUTH)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'sedir.c'
then
	echo shar: will not over-write existing file "'sedir.c'"
else
cat << \SHAR_EOF > 'sedir.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==SOUTH_EAST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'slo_fall.c'
then
	echo shar: will not over-write existing file "'slo_fall.c'"
else
cat << \SHAR_EOF > 'slo_fall.c'


#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[1]==FALL_SLOW)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'slo_rise.c'
then
	echo shar: will not over-write existing file "'slo_rise.c'"
else
cat << \SHAR_EOF > 'slo_rise.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[1]==RISE_SLOW)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'steady.c'
then
	echo shar: will not over-write existing file "'steady.c'"
else
cat << \SHAR_EOF > 'steady.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[1]==STEADY)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'swdir.c'
then
	echo shar: will not over-write existing file "'swdir.c'"
else
cat << \SHAR_EOF > 'swdir.c'


#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==SOUTH_WEST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'wdir.c'
then
	echo shar: will not over-write existing file "'wdir.c'"
else
cat << \SHAR_EOF > 'wdir.c'

#include <stdio.h>
#include "routine.h"
#include "weather.h"

main()
{
FILE *dataFile ;
int	value[20] ;

dataFile = fopen("WEATHER.DAT","rb") ;
fread(value,2,20,dataFile) ;
fclose(dataFile) ;
if(value[2]==WEST)
	return(RETURN_ROUTINE_TRUE) ;
else
	return(RETURN_ROUTINE_FALSE) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'animal'
then
	echo shar: will not over-write existing file "'animal'"
else
cat << \SHAR_EOF > 'animal'
! THIS IS THE KNOWLEDGE BASE FOR THE
! ANIMAL CLASIFICATION EXPERT   
!
IF ANIMAL HAS FEATHERS
ANDIF ANIMAL LAYS EGGS
THEN ANIMAL IS BIRD   
!
IFNOT ANIMAL IS BIRD  
THEN ANIMAL IS MAMMAL 
!
IF ANIMAL IS MAMMAL
AND ANIMAL EATS MEAT  
THEN ANIMAL IS CARNIVORE    
!
IF ANIMAL IS CARNIVORE        
AND ANIMAL HAS POINTED TEETH   
AND ANIMAL HAS RETRACTABLE CLAWS  
AND ANIMAL HAS FORWARD POINTING EYES    
THEN ANIMAL IS CAT        
! 
IF ANIMAL IS MAMMAL   
ANDNOT ANIMAL IS CARNIVORE
AND ANIMAL HAS HOOFS  
THEN ANIMAL IS UNGULATE        
! 
IF ANIMAL IS CAT  
AND ANIMAL HAS TAWNY COLOR     
AND ANIMAL HAS DARK SPOTS      
THENHYP ANIMAL IS CHEETA       
!
IF ANIMAL IS CAT   
AND ANIMAL HAS TAWNY COLOR     
AND ANIMAL HAS BLACK STRIPES   
THENHYP ANIMAL IS TIGER        
!
IF ANIMAL IS CAT
AND ANIMAL IS SMALL
AND ANIMAL IS DOMESTICATED
AND ANIMAL MOSTLY CATCHES MICE
AND ANIMAL LOVES WARM LAPS
THENHYP ANIMAL IS A HOUSE CAT
! 
IF ANIMAL IS UNGULATE 
AND ANIMAL HAS LONG NECK       
AND ANIMAL HAS LONG LEGS       
AND ANIMAL HAS DARK SPOTS      
THENHYP ANIMAL IS GARAFFE      
!
IF ANIMAL IS BIRD     
ANDNOT ANIMAL FLIES   
ANDNOT ANIMAL SWIMS   
AND ANIMAL HAS LONG NECK       
AND ANIMAL IS BLACK AND WHITE  
THENHYP ANIMAL IS OSTRICH      
!
IF ANIMAL IS UNGULATE 
AND ANIMAL HAS BLACK STRIPES   
THENHYP ANIMAL IS ZEBRA        
!
IF ANIMAL IS BIRD     
ANDNOT ANIMAL FLIES   
AND ANIMAL SWIMS      
AND ANIMAL IS BLACK AND WHITE  
THENHYP ANIMAL IS PENGUIN      
!
IF ANIMAL IS BIRD     
AND ANIMAL FLIES      
AND ANIMAL FLIES WELL 
AND ANIMAL HAS WEBBED FEET
ANDNOT ANIMAL HAS FLAT BILL
THENHYP ANIMAL IS ALBATROS     
! 
IF ANIMAL IS BIRD   
AND ANIMAL FLIES    
AND ANIMAL FLIES WELL        
AND ANIMAL HAS WEBBED FEET   
AND ANIMAL HAS FLAT BILL 
THENHYP ANIMAL IS DUCK
!
!
!
IFNOT ANIMAL IS CHEETA       
IFNOT ANIMAL IS TIGER        
IFNOT ANIMAL IS A HOUSE CAT
IFNOT ANIMAL IS GARAFFE      
IFNOT ANIMAL IS OSTRICH      
IFNOT ANIMAL IS ZEBRA        
IFNOT ANIMAL IS PENGUIN      
IFNOT ANIMAL IS ALBATROS     
IFNOT ANIMAL IS DUCK
THENHYP THIS ANIMAL IS NOT WITHIN MY KNOWLEDGE

SHAR_EOF
fi # end of overwriting check
if test -f 'weather'
then
	echo shar: will not over-write existing file "'weather'"
else
cat << \SHAR_EOF > 'weather'
!
!	WEATHER PREDICTOR AS WRITTEN BY JACK PARK AND 
!	TRANSLATED BY GEORGE HAGEMAN FOR DEMONSTRATION
!	PURPOSES ONLY
!
IF YOU WANT TO HAVE ME PREDICT THE WEATHER
THENRUN message1.exe
!
IFNOT YOU WANT TO HAVE ME PREDICT THE WEATHER
ANDNOT YOU ARE ABSOLUTELY POSITIVE ABOUT IT
THENRUN message1.exe
!
IFNOT YOU WANT TO HAVE ME PREDICT THE WEATHER
ANDIF YOU ARE ABSOLUTELY POSITIVE ABOUT IT
THENHYP TOO BAD, WE COULD HAVE HAD SOME FUN!
!
IFRUN message1.exe
ANDIF YOU CAN SEE UPPER LEVEL CLOUDS
ANDIF CLOUDS MOVING FROM YOUR LEFT
THEN CLOUDS INDICATE BAD WEATHER
!
IFRUN message1.exe
ANDIF YOU CAN SEE UPPER LEVEL CLOUDS
ANDNOT CLOUDS INDICATE BAD WEATHER
ANDIF CLOUDS MOVING FROM YOUR RIGHT
THEN CLOUDS INDICATE WEATHER IMPROVING
!
!
IFRUN message1.exe
ANDIF YOU CAN SEE UPPER LEVEL CLOUDS
ANDNOT CLOUDS INDICATE BAD WEATHER
ANDNOT CLOUDS INDICATE WEATHER IMPROVING
ANDIF CLOUDS MOVE PARALLEL TO DIRECTION
THEN CLOUDS INDICATE STEADY WEATHER
!
IFRUN message1.exe
ANDNOT YOU CAN SEE UPPER LEVEL CLOUDS
THEN CLOUDS INDICATE STEADY WEATHER
!
IFRUN gt_302.exe
ANDRUN slo_fall.exe
ANDRUN wdir.exe
THEN WEATHER OK
THEN FAIR AND WARM NEXT 48 HRS
!
IFRUN gt_302.exe
ANDRUN steady.exe
ANDRUN wdir.exe
THEN CONTINUED FAIR
THEN LITTLE TEMPERATURE CHANGE
THEN WEATHER OK
!
IFRUN gt_301.exe
ANDRUN slo_fall.exe
ANDRUN nedir.exe
AND CLOUDS INDICATE STEADY WEATHER
AND SEASON IS SUMMER
THEN RAIN MAY NOT fall
THEN STEADY FOR SEVERAL DAYS
THEN WEATHER OK
!
IFRUN gt_301.exe
ANDRUN slo_fall.exe
ANDRUN nedir.exe
AND CLOUDS INDICATE BAD WEATHER
AND SEASON IS WINTER
THEN RAIN WITHIN 24 HOURS
THEN WEATHER TURNING BAD
!
IFRUN lt_298.exe
ANDRUN rpd_rise.exe
THEN WEATHER IMPROVING
THEN CLEARING AND COLDER
!
IFRUN lt_301.exe
ANDRUN slo_rise.exe
AND CLOUDS INDICATE WEATHER IMPROVING
THEN CLEARING WITHIN A FEW HOURS
THEN FAIR NEXT SEVERAL DAYS
THEN WEATHER IMPROVING
!
IFRUN gt_301.exe
ANDRUN slo_fall.exe
ANDRUN edir.exe
AND CLOUDS INDICATE BAD WEATHER
THEN RAIN IN 12 - 18 HOURS
THEN WEATHER TURNING BAD
!
IFRUN lt_298.exe
ANDRUN rpd_fall.exe
ANDRUN ndir.exe
THEN SEVERE STORM WARNING
THEN SEVERE NORTHEAST GALES
THEN WEATHER TURNING BAD
!
IFRUN lt_298.exe
ANDRUN rpd_fall.exe
ANDRUN sedir.exe
THEN SEVERE STORM WARNING
THEN RAIN OR SNOW IMMINENT
THEN WEATHER TURNING BAD
!
IFRUN lt_301.exe
ANDRUN slo_fall.exe
ANDRUN edir.exe
AND CLOUDS INDICATE BAD WEATHER
THEN RAIN FOR NEXT DAY OR TWO
THEN WEATHER TURNING BAD
!
IFRUN lt_301.exe
ANDRUN rpd_fall.exe
ANDRUN edir.exe
AND CLOUDS INDICATE BAD WEATHER
THEN CLEARING WITHIN 24 HOURS
THEN COOLER TEMPERATURES
THEN WEATHER TURNING BAD
!
IFRUN gt_301.exe
ANDRUN rpd_rise.exe
ANDRUN wdir.exe
THEN FAIR TODAY
THEN RAIN AND WARMER NEXT 48 HOURS
THEN WEATHER TURNING BAD
!
IFRUN gt_301.exe
ANDRUN slo_fall.exe
ANDRUN wdir.exe
THEN WARMER
THEN RAIN WITHING 24 - 36 HOURS
THEN WEATHER TURNING BAD
!
IFRUN gt_301.exe
ANDRUN rpd_fall.exe
ANDRUN wdir.exe
AND CLOUDS INDICATE BAD WEATHER
THEN WARMER
THEN RAIN WITHIN 18 - 24 HOURS
THEN WEATHER TURNING BAD
!
IFRUN gt_301.exe
ANDRUN slo_fall.exe
ANDRUN sdir.exe
THEN RAIN WITHIN 24 HOURS
THEN WEATHER TURNING BAD
!
IFRUN gt_301.exe
ANDRUN rpd_fall.exe
ANDRUN sdir.exe
THEN WEATHER TURNING BAD
THEN WINDY, RAIN WITHIN 12 HOURS
!
IFNOT WEATHER OK
IFNOT WEATHER TURNING BAD
IFNOT WEATHER IMPROVING
THENHYP INSUFFICIENT DATA FOR A FORECAST
!
IF WEATHER OK
THENHYP  I'M GLAD THAT THE WEATHER WILL BE OK
!
IF WEATHER TURNING BAD
THENHYP TOO BAD ABOUT THE PICKNICK
!
IF WEATHER IMPROVING
THENHYP HOW ABOUT A PICKNICK?
!
SHAR_EOF
fi # end of overwriting check
if test -f 'makefile'
then
	echo shar: will not over-write existing file "'makefile'"
else
cat << \SHAR_EOF > 'makefile'
#make file for weather
storm: message1.exe gt_302.exe gt_301.exe lt_301.exe lt_298.exe \
       wdir.exe nwdir.exe ndir.exe nedir.exe edir.exe sedir.exe sdir.exe \
       swdir.exe steady.exe rpd_fall.exe rpd_rise.exe slo_rise.exe slo_fall.exe


message1.exe: message1.c
	cc message1.c -omessage1.exe

gt_302.exe: gt_302.c
	cc gt_302.c -ogt_302.exe

gt_301.exe: gt_301.c
	cc gt_301.c -ogt_301.exe

lt_301.exe: lt_301.c
	cc lt_301.c -olt_301.exe

lt_298.exe: lt_298.c
	cc lt_298.c -olt_298.exe

wdir.exe: wdir.c
	cc wdir.c -owdir.exe    

nwdir.exe: nwdir.c
	cc nwdir.c -onwdir.exe    

swdir.exe: swdir.c
	cc swdir.c -oswdir.exe    

edir.exe: edir.c
	cc edir.c -oedir.exe    

nedir.exe: nedir.c
	cc nedir.c -onedir.exe    

sedir.exe: sedir.c
	cc sedir.c -osedir.exe    

sdir.exe: sdir.c
	cc sdir.c -osdir.exe    

ndir.exe: ndir.c
	cc ndir.c -ondir.exe    

slo_rise.exe: slo_rise.c
	cc slo_rise.c -oslo_rise.exe

steady.exe: steady.c
	cc steady.c -osteady.exe

rpd_rise.exe: rpd_rise.c
	cc rpd_rise.c -orpd_rise.exe

rpd_fall.exe: rpd_fall.c
	cc rpd_fall.c -orpd_fall.exe

slo_fall.exe: slo_fall.c
	cc slo_fall.c -oslo_fall.exe

SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0