///////////////////////////////////////////////////////////////////////////////
//  This file is generated automatically using Prop (version 2.3.0),
//  last updated on Feb 5, 1997.
//  The original source file is "inference.pC".
///////////////////////////////////////////////////////////////////////////////

#define PROP_INFERENCE_USED
#include <propdefs.h>
//////////////////////////////////////////////////////////////////////////////
//  This is a simple self-contained test to benchmark the speed of
//  naive inferencing in Prop.
//
//  To compile on Unix: 
//
//     prop triangle.pcc
//     gcc -I<prop-include-dir> triangle.cc -o triangle -L<ADLib-library-dir>
//         -lad -liostream -lg++
//////////////////////////////////////////////////////////////////////////////

#include <iostream.h>

//////////////////////////////////////////////////////////////////////////////
//
//  Defines two relations to be used during inference
//
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Forward class definition for Number
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_Number_defined
#define datatype_Number_defined
   typedef class a_Number * Number;
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype Number
///////////////////////////////////////////////////////////////////////////////
class a_Number; // base class for datatype Number

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'Number'
///////////////////////////////////////////////////////////////////////////////
class a_Number : public Fact {
public:
   inline friend int boxed(const a_Number * x) { return 1; }
   inline friend int untag(const a_Number * x) { return 0; }
   int num; 
   inline a_Number (int _xnum)
      : num(_xnum) {}
   inline friend a_Number * num (int _xnum)
      { return new a_Number (_xnum); }
   inline virtual ~a_Number() {}
   static  RelTag relation_tag;
   virtual RelTag get_tag() const;
};


///////////////////////////////////////////////////////////////////////////////
// Forward class definition for Limit
///////////////////////////////////////////////////////////////////////////////
#ifndef datatype_Limit_defined
#define datatype_Limit_defined
   typedef class a_Limit * Limit;
#endif

///////////////////////////////////////////////////////////////////////////////
// Class hierarchy for datatype Limit
///////////////////////////////////////////////////////////////////////////////
class a_Limit; // base class for datatype Limit

///////////////////////////////////////////////////////////////////////////////
// Base class for datatype 'Limit'
///////////////////////////////////////////////////////////////////////////////
class a_Limit : public Fact {
public:
   inline friend int boxed(const a_Limit * x) { return 1; }
   inline friend int untag(const a_Limit * x) { return 0; }
   int limit; 
   inline a_Limit (int _xlimit)
      : limit(_xlimit) {}
   inline friend a_Limit * limit (int _xlimit)
      { return new a_Limit (_xlimit); }
   inline virtual ~a_Limit() {}
   static  RelTag relation_tag;
   virtual RelTag get_tag() const;
};


///////////////////////////////////////////////////////////////////////////////
// Relation class Number interface
///////////////////////////////////////////////////////////////////////////////
Fact::RelTag a_Number::relation_tag = 0;
static InitialiseFact Number_dummy__(a_Number::relation_tag);
Fact::RelTag a_Number::get_tag() const { return a_Number::relation_tag; }

///////////////////////////////////////////////////////////////////////////////
// Relation class Limit interface
///////////////////////////////////////////////////////////////////////////////
Fact::RelTag a_Limit::relation_tag = 0;
static InitialiseFact Limit_dummy__(a_Limit::relation_tag);
Fact::RelTag a_Limit::get_tag() const { return a_Limit::relation_tag; }



//////////////////////////////////////////////////////////////////////////////
//
// The following inference construct defines an inference class
// with two rules and one axiom. 
//
//////////////////////////////////////////////////////////////////////////////
class Triangle : public Rete {
   Triangle(const Triangle&);
   void operator = (const Triangle&);
public:
   static const Node          network_table[];
   static const RelationTable relation_table[];
public:
   Triangle();
   virtual const char * name_of() const;
   void initialise_axioms();
protected:
   virtual void alpha_test (int, int, Fact *);
   virtual int  beta_test  (Join, Fact * []);
   virtual void action     (RuleId, Fact * []);
private:
};


const char * Triangle::name_of() const { return "Triangle"; }

///////////////////////////////////////////////////////////////////////////////
//  Single object tests for inference class Triangle
///////////////////////////////////////////////////////////////////////////////
void Triangle::alpha_test(int predicate__, int i__, Fact * fact__)
{
   Fact * f__[3];
   switch (predicate__) {
      case 1: {
         Number _0 = (Number)(f__[0] = fact__);
         {
            const unsigned char * m__;
            {  static const unsigned char matched_set__[1] =
               {  15 };
               m__ = matched_set__;
            }
            { if (i__) insert_alpha(4,fact__); else remove_alpha(4,fact__); }
            { if (i__) insert_alpha(3,fact__); else remove_alpha(3,fact__); }
            { if (i__) insert_beta(3,f__); else remove_beta(3,f__); }
            { if (i__) insert_beta(1,f__); else remove_beta(1,f__); }
         }} break; 
      case 2: {
         Limit _0 = (Limit)(f__[0] = fact__);
         {
            const unsigned char * m__;
            {  static const unsigned char matched_set__[1] =
               {  1 };
               m__ = matched_set__;
            }
            { if (i__) insert_alpha(1,fact__); else remove_alpha(1,fact__); }
         }} break; 
   }
}

///////////////////////////////////////////////////////////////////////////////
//  Joins for inference class Triangle
///////////////////////////////////////////////////////////////////////////////
int Triangle::beta_test(Join join__, Fact * f__[])
{
   switch (join__) {
      case 1: {
         Number  _0 = (Number )f__[0];
         Limit  _1 = (Limit )f__[1];
         return (_0->num < _1->limit);
      }
      case 3: {
         Number  _0 = (Number )f__[0];
         Number  _1 = (Number )f__[1];
         return (_0->num < _1->num);
      }
      case 4: {
         Number  _0 = (Number )f__[0];
         Number  _1 = (Number )f__[1];
         Number  _2 = (Number )f__[2];
         return ((_1->num < _2->num) && (((_0->num * _0->num) + (_1->num * _1->num)) == (_2->num * _2->num)));
      }
      default: return 0;
   }
}

///////////////////////////////////////////////////////////////////////////////
//  Actions for inference class Triangle
///////////////////////////////////////////////////////////////////////////////
void Triangle::action(Triangle::RuleId r__, Fact * f__[])
{
   switch (r__) {
      case 1: {
         Number  _0 = (Number )f__[0];
         Limit  _1 = (Limit )f__[1];
         assert_fact(num((_0->num + 1)));
      } break;
      case 2: {
         Number  _0 = (Number )f__[0];
         Number  _1 = (Number )f__[1];
         Number  _2 = (Number )f__[2];
          cout << _0->num << " * " << _0->num << " + " 
         << _1->num << " * " << _1->num << " = "
         << _2->num << " * " << _2->num << '\n';
         
      } break;
   }
}

///////////////////////////////////////////////////////////////////////////////
//  Dispatch table for inference class Triangle
///////////////////////////////////////////////////////////////////////////////
const Triangle::RelationTable Triangle::relation_table[] = {
   { &a_Number::relation_tag, 1, "Number" },
   { &a_Limit::relation_tag, 2, "Limit" }
};

///////////////////////////////////////////////////////////////////////////////
//  Network table for inference class Triangle
///////////////////////////////////////////////////////////////////////////////
const Triangle::Node Triangle::network_table[] = {
   { 0, 0, ReteNet::Node::Bot, 0, 0 } /* 0 */,
   { 1, 2, ReteNet::Node::And, 1, 2 } /* 1 */,
   { 0, 2, ReteNet::Node::Bot, 0, 1 } /* 2 */,
   { 1, 3, ReteNet::Node::And, 3, 4 } /* 3 */,
   { 2, 3, ReteNet::Node::And, 4, 5 } /* 4 */,
   { 0, 3, ReteNet::Node::Bot, 0, 2 } /* 5 */
};

///////////////////////////////////////////////////////////////////////////////
//  Axioms for inference class Triangle
///////////////////////////////////////////////////////////////////////////////
void Triangle::initialise_axioms()
{
   assert_fact(num(1));
}

///////////////////////////////////////////////////////////////////////////////
//  Constructor for inference class Triangle
///////////////////////////////////////////////////////////////////////////////
Triangle::Triangle()
   : Rete(6,Triangle::network_table,2,Triangle::relation_table)
      { initialise_axioms(); }



int main()
{ 
   Triangle triangle;   // instantiate an inference module
   int top;         

   ///////////////////////////////////////////////////////////////////////////
   //
   // Get the limit
   //
   ///////////////////////////////////////////////////////////////////////////
   cout << "Please input a limit (say, between 10 - 100): " << flush;
   cin >> top; 
   cout << "Trying all numbers from 1 to " << top << '\n';

   ///////////////////////////////////////////////////////////////////////////
   //
   // Insert the initial parameter into the database.
   //
   ///////////////////////////////////////////////////////////////////////////
   triangle << limit (top);

   ///////////////////////////////////////////////////////////////////////////
   //
   // Run the inference engine until it is stable.
   // The inference rules defined above will be fired and triangular
   // identities will be printed.  
   //
   ///////////////////////////////////////////////////////////////////////////
   triangle.infer();

   return 0;
}
/*
------------------------------- Statistics -------------------------------
Merge matching rules         = yes
Number of DFA nodes merged   = 0
Number of ifs generated      = 0
Number of switches generated = 0
Number of labels             = 0
Number of gotos              = 0
Adaptive matching            = disabled
Fast string matching         = disabled
Inline downcasts             = disabled
--------------------------------------------------------------------------
*/

