?
Solved

A simple question about include!!!!

Posted on 2006-05-05
26
Medium Priority
?
616 Views
Last Modified: 2013-11-18
I have two file. The first is Language.h (header file : declare only) and Language.cpp (implement file).
 In these files i have to class and two sets of function, each set of functions do a different work. Now i want to devide these files into 4 group (each .cpp and .h are a group): the first class, the seconde class, the first set of function, the second set of function. Each of these are a group. But i have error "undeclared identifier" . I'm not sure about how to do this. can anyone tell me about how to do??? How to include cpp and h file so it can work well ???
 Thanks a lot !!!
0
Comment
Question by:hiepbeo
  • 12
  • 11
  • 2
  • +1
26 Comments
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16619882
Hi hiepbeo,

> error "undeclared identifier"
While I falied to understand what you are trying to do, the above error means that you forgot to declare some variable ... Possible causes:

1. did not declare
2. Case mismtach - variable names are case sensitive
3. Spelling mistake in variable name
4. If variable is defined in one file and used in another, it needs to be declared as extern

Cheers!
Sunnycoder
0
 

Author Comment

by:hiepbeo
ID: 16619921
Sorry . I will tell more.
I have two file. The first  knowledgeBase.h (header file : declare only) and knowledgeBase.cpp (implement file).
 In these file i have two class : PropNode and KnowledgeBase. And two sets of functions: do another work: BackwardChaining and ForwardChaining.
Now i want to devide these files in to 4 group of files:
PropNode.cpp & PropNode.h
KnowledgeBase.cpp & KnowledgeBase.h
BackwardChaining.cpp & BackwardChaining.h
ForwardChaining.cpp & ForwardChaining.h

I created these new file, copied and pasted code from the knowledgeBase.h and knowledgeBase.cpp to these files. But it doesn't work. It tell me error: "undeclared identifier" and anothers errors.

 I know i have to include these file to each other. I opened these file and included:
with header file:
#include "PropNode.h"
#include "ForwardChaining.h"
#include "BackwardChaining.h"
#include "KnowledgeBase.h"
 and with cpp file:
#include "PropNode.cpp"
#include "ForwardChaining.cpp"
#include "BackwardChaining.cpp"
#include "KnowledgeBase.cpp"

It tells me that  fatal error C1014: too many include files : depth = 1024

How to include each other file so it can work well ??
 Thank you sunnycoder! Hope that you and everybody can help me :).
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16619948
For each header file add inclusion protection

#ifndef NAME_OF_HEADER_FILE_H
#define NAME_OF_HEADER_FILE_H
...
//contents of header file go here
...
#endif

Next show us the exact code for each and every file
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 

Author Comment

by:hiepbeo
ID: 16619956
Sorry this code is lengthy. Here is my code:
File KnowledgeBase.cpp
#include <iostream>

#ifdef DEBUG
    #define Assert( flag, err_str ) assert( flag && err_str )
#else
    #define Assert( flag, err_str )             \
    do                                          \
    {                                           \
        if( (flag) == false )                   \
        {                                       \
            std::cerr<< err_str << std::endl;   \
            exit(1);                            \
        }                                       \
    }while(false)                          
#endif

#include "KnowledgeBase.h"

bool KB_DEBUG = false;

//--------------------------------------- PropNode -----------------------------------//
const std::string PropNode::IMPLICATION("->");
const std::string PropNode::OR("+");
const std::string PropNode::NOT("~");
const std::string PropNode::AND("*");

PropNode::PropNode( PropNode& copy )
:name(copy.name), mDeepDelete(true)
{
   for( std::list<PropNode*>::iterator iter = copy.children.begin();
        iter != copy.children.end(); iter++)
            children.push_back( (*iter)->clone() );
}

PropNode::PropNode( const std::string& gname, bool gdeepDelete )
:name(gname), mDeepDelete(gdeepDelete), parent(0)
{}

PropNode::PropNode( bool deepDelete )
:mDeepDelete(deepDelete), parent(0)
{}

void PropNode::addChild(PropNode* child)
{
    children.push_back(child);
    child->parent = this;
}

PropNode::~PropNode()
{
      if( ! mDeepDelete) return;

      for( std::list<PropNode*>::iterator delIter = children.begin();
                  delIter != children.end(); delIter++)
                        delete *delIter;
}

bool PropNode::isOperator()
{
      return name == IMPLICATION ||
           name == OR ||
           name == NOT ||
           name == AND;
}

/**
    We can optimize this by checking the heights for those trees
 */
bool PropNode::equals( PropNode* node )
{
      if( node->children.size() != children.size() ) return false;
      if( name != node->name ) return false;

      std::list<PropNode*>::iterator iter;
      std::list<PropNode*>::iterator niter;
      for( iter = children.begin(), niter = node->children.begin();
                  iter != children.end();
                  iter++, niter++ )
                  {
                              if( (*iter)->equals(*niter) == false) return false;
                  }

      return true;
}

void PropNode::print()
{
    par = 0;
    //setLevel(0);
    print(this);
}

void PropNode::print( PropNode* root )
{
   for( int i = 0; i < root->par; i++) std::cout << ' ';
   std::cout << root->name << '\n';

   for( std::list<PropNode*>::iterator iter = root->children.begin();
        iter != root->children.end(); iter++)
   {
       (*iter)->par = root->par + 1;
       print( *iter );
   }
}

void PropNode::print( std::list<PropNode*>& printlist)
{
     
      while( !printlist.empty() )
      {
            std::list<PropNode*>::iterator printIter = printlist.begin();            

        for( int i = 0; i < (*printIter)->par; i++) std::cout << ' ';
            std::cout << (*printIter)->name << '\n';

        int count = (*printIter)->children.size();
            std::list<PropNode*>::iterator iter = (*printIter)->children.begin();
          for( ; iter != (*printIter)->children.end(); iter++)
                        printlist.push_back( *iter );

            printlist.erase( printIter );
      }
}

void PropNode::setLevel(int h )
{
    par = h;
    for( std::list<PropNode*>::iterator iter = children.begin();
         iter != children.end(); iter++) (*iter)->setLevel(h+1);
}

int PropNode::level()
{
    return par;
}

PropNode* PropNode::clone()
{
    return new PropNode(*this);
}

void PropNode::cloneChildren(std::list<PropNode*>& copy )
{
    for( std::list<PropNode*>::iterator iter = copy.begin();
         iter != copy.end(); iter++)
        children.push_back( (*iter)->clone() );
}

//--------------------------------------- KnowledgeBase -----------------------------------//

KnowledgeBase::KnowledgeBase(){}

KnowledgeBase::~KnowledgeBase()
{
      for( std::list<PropNode*>::iterator delIter = memory.begin();
                  delIter != memory.end(); delIter++)
                        delete *delIter;
}


void KnowledgeBase::store( PropNode* knowledge )
{
      add(knowledge);
      memory.push_back(knowledge);
}

void KnowledgeBase::add( PropNode* knowledge )
{
      database.push_back(knowledge);
}

bool KnowledgeBase::contains( PropNode* statement )
{
      for( std::list<PropNode*>::iterator iter = database.begin();
                  iter != database.end(); iter++)
                        if( (*iter)->equals( statement ) ) return true;
      return false;
}


void KnowledgeBase::print()
{
      std::cout << "KnowledgeBase content\n";
      int i = 0;
      for( std::list<PropNode*>::iterator printIter = database.begin();
                  printIter != database.end(); printIter++)
      {
            std::cout << "----------- " << i <<  "----------- " << '\n';
            (*printIter)->print();
            i++;
      }
      std::cout << std::endl; //flush to cout
}

//--------------------------------------- Backward-Chaining ----------------------------//
/**
    p->q becomes ~p v q
*/
void eliminateImplications(PropNode* statement )
{
    if( statement->name == PropNode::IMPLICATION )
    {
        statement->name = PropNode::OR;
     
        PropNode* notP = new PropNode( PropNode::NOT );

        notP->addChild( *statement->children.begin() );
        statement->children.pop_front();

        statement->children.push_front( notP );
    }
   
    for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
        eliminateImplications(*iter);
}

/**
    ~(pvq) becomes ~p ^ ~q
    ~(p^q) becomes ~p v ~q
    ~~p becomes p
*/
void moveNots( PropNode* statement )
{
    //remove double not's
    while( statement->name == PropNode::NOT &&
        (*statement->children.begin())->name == PropNode::NOT)
    {
       //the tree looks like this,
       //"NOT"->"NOT"->NODE1->(...)
       //OLD points to, "NOT"->NODE1
       //The steps are:
       //1, statement copies from NODE1 (the first "NOT" becomes NODE1)
       //2, break the link to (...)
       //3, finally, we delete OLD (which includes "NOT"->NODE1)

       PropNode* old = *statement->children.begin();
       PropNode* newNode = *old->children.begin();

       statement->name = newNode->name;
       statement->children = newNode->children;

       newNode->children.clear(); //break the link to sub-tree
       delete old;
    }

    //distribute '~' over '^' and 'v'
    //note: the previous while loop eliminated all
    //the double nots in the current node
    if( statement->name == PropNode::NOT &&
        (*statement->children.begin())->isOperator() == true )
    {
        Assert( (*statement->children.begin())->name == PropNode::OR ||
                (*statement->children.begin())->name == PropNode::AND,
                "the child name is either AND or OR. didn't elminate IMPLICATION's?");
 
        //setup:
        //statement(NOT)->childNode(OR/AND)->(children...)
        //result:
        //statement(AND/OR)->(not-children...)
        PropNode* childNode = *statement->children.begin();

        std::string opposite = childNode->name == PropNode::OR ?
                                    PropNode::AND : PropNode::OR;
        statement->name = opposite;
        statement->children.clear(); //break link to childNode;
 
        for( std::list<PropNode*>::iterator iter = childNode->children.begin();
             iter != childNode->children.end(); iter++)
        {
            PropNode* notChild = new PropNode( PropNode::NOT );
            notChild->addChild( *iter );
            statement->addChild( notChild );
        }
        childNode->children.clear(); //drop all old children
        delete childNode;
    }

    for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
            moveNots( *iter );
}

/**
Example,

original:
(a^b)vcv(d^e)

distribute AND over OR:
(avcv(d^e))^(avcv(d^e))

resursive step:
((avcvd)^(avcve))^(avcv(d^e))
((avcvd)^(avcve))^((avcvd)^(avcve))
*/
void distributeAnds( PropNode* node )
{
   if( node->name == PropNode::OR )
   {
       //find a child with AND
       PropNode* andChild = 0;
       for( std::list<PropNode*>::iterator iter = node->children.begin();
            iter != node->children.end(); iter++)
           if( (*iter)->name == PropNode::AND )
           { //remove the AND-child from the node
                andChild = *iter;
                node->children.erase(iter);
                break;
           }

       //found a child with name == AND
       //distribute the AND over the OR
       if( andChild != 0 )
       {
           //the new node is a AND-node
           node->name = PropNode::AND;

           std::list<PropNode*> children; //the new OR-children for the AND-node

           //for each node in the and-child,
           //create a OR-child with the remaining nodes
           for( std::list<PropNode*>::iterator iter = andChild->children.begin();
                iter != andChild->children.end(); iter++)
           {
                PropNode* orChild = new PropNode( PropNode::OR );
                orChild->addChild( *iter );
                orChild->cloneChildren( node->children ); //add other children
                children.push_back(orChild);
           }

           //destroy the old nodes
           for( std::list<PropNode*>::iterator delIter = node->children.begin();
                delIter != node->children.end(); delIter++)
                    delete *delIter;
            node->children = children; //the new children is a list of OR-nodes

           andChild->children.clear();
           delete andChild; //destory the AND-symbol
       }
   }

   //resursive step
   for( std::list<PropNode*>::iterator iter = node->children.begin();
        iter != node->children.end(); iter++)
           distributeAnds( *iter );    
}

//TODO: need to sort all sub-trees
/**
 * @param pname the operator of the parent (either OR or AND)
 *
 * Example:
 * (avb)^((c^d)^e)
 * (avb)^a^d^e
 */
void flattenConDis( PropNode* node )
{
   if( node->isOperator() == false ) return; //a term

   for( std::list<PropNode*>::iterator iter = node->children.begin();
        iter != node->children.end(); iter++)
            flattenConDis(*iter);

   for( std::list<PropNode*>::iterator iter2 = node->children.begin();
        iter2 != node->children.end(); )
   {
        if( (*iter2)->name == node->name )
        {
           node->children.merge( (*iter2)->children );
           (*iter2)->children.clear();

           delete *iter2;
           iter2 = node->children.erase(iter2);
        }
        else
        { //go to the next element
            iter2++;
        }
   }
}

template<class T, class S>
class DeRefLessThanComparable
{
    public:
        bool operator()( T arg1, S arg2 ){ return *arg1 < *arg2; }
};

/**
    returns the form of (avbvc)^(dvef..)^...
*/
void convertToCNF(PropNode* statement )
{
   eliminateImplications(statement);
   moveNots(statement);
   distributeAnds(statement);
   flattenConDis(statement);
}

/**
    convert the sentence into CNF and break the conjunction into
    a list of disjunctions
*/
void convertToDisjunctions( PropNode*& statement,
                            std::list<PropNode*>& disjuncts)
{
    convertToCNF(statement);
    if( statement->name == PropNode::OR )
    { //only one disjunction
      disjuncts.push_back(statement);
    }
    else
    {
        for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
        disjuncts.push_back(*iter);
        statement->children.clear();
        delete statement;
    }
    statement = 0;
}

/**
    #param statement disjunction of terms
    Horn clauses are formed by EXACTLY one positive term
    and OR'ed with any number of negative terms.

    Examples:
    ~a v ~b v ~c v d ==> a^b^c -> d
    ~a               ==> ~a         //standalone term
    b                ==> b          //standalone term
*/
void convertToHorn( PropNode* statement )
{
    //already is a term?
    if( statement->children.size() == 0 ) return;
    Assert( statement->name == PropNode::OR, "not a disjunction?");

    PropNode* andNode = new PropNode(PropNode::AND);
    PropNode* posTerm = 0;

    for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
    {
       if( (*iter)->name == PropNode::NOT )
       {
           PropNode* term = *(*iter)->children.begin();
           //remove the NOT from the negated term
           andNode->addChild(term);

           (*iter)->children.clear(); //break the link to the term
           delete *iter;
       }
       else if( posTerm == 0 )
           posTerm = *iter;
       else
           Assert( false, "Bad Horn clause, more than one positive term.");
    }

    Assert( posTerm != 0, "Bad Horn clause. All terms are negated.");

    //build horn clause
    statement->name = PropNode::IMPLICATION;
    statement->children.clear();

    //link the implication terms
    statement->addChild(andNode);
    statement->addChild(posTerm);
}

/**
    convert the statement to a list of horn clauses, and
    store them to the KB. The pointer to the old PropNode is
    set to NULL (0).

    Example:
     
*/
void addHorns(KnowledgeBase& KB, PropNode*& statement )
{
    std::list<PropNode*> disjuncts;
    convertToDisjunctions(statement, disjuncts);
    for( std::list<PropNode*>::iterator iter = disjuncts.begin();
         iter != disjuncts.end(); iter++)
    {
         convertToHorn(*iter);
         KB.store(*iter);
    }
}

bool backwardChaining( KnowledgeBase& KB, char* query, int limit )
{
    return backwardChaining( KB, std::string(query), limit );
}

/**
    @param goal a list of terms that must be satisfied
*/
bool backwardChaining( KnowledgeBase& KB, std::list<PropNode*>& goal, int limit )
{
    if( limit == 0 ) return false;
    limit--;
    for( std::list<PropNode*>::iterator iter = goal.begin();
         iter != goal.end(); iter++)
            if( backwardChaining( KB, (*iter)->name, limit ) == false ) return false;
    return true;
}

bool backwardChaining( KnowledgeBase& KB, const std::string& query, int limit )
{
   if( limit == 0 ) return false;
   limit--;

   PropNode qnode(query);
   if( KB.contains(&qnode) )
   {
       if(KB_DEBUG) std::cerr << "backwardChaining found: " << query << '\n';
       return true;
   }

   for( std::list<PropNode*>::iterator iter = KB.database.begin();
        iter != KB.database.end(); iter++)
   {
       if((*iter)->isOperator() == true && //if it is a rules, not a term
           (*iter)->name != PropNode::NOT)
       {
            Assert((*iter)->name == PropNode::IMPLICATION,
                "KB does not contain horn clauses");

            std::list<PropNode*>::iterator target = (*iter)->children.begin();
            std::list<PropNode*>::iterator premise = target;

            Assert((*premise)->name == PropNode::AND,
                "KB does not contain horn clauses");

            target++;
            if( query == (*target)->name && 
                backwardChaining( KB, (*premise)->children, limit ) )
            {
                if(KB_DEBUG)
                {
                    std::cerr << "backward-chaining satisfied premises for:\n";
                    (*iter)->print();
                }
                return true;
            }
       }
   }
   return false;
}

//--------------------------------------- Forward-Chaining -----------------------------------//
void forwardChaining( KnowledgeBase& KB, PropNode* p, bool store )
{
      if( KB.contains(p) ) return;
      
      if( store )
            KB.store(p);
      else
            KB.add(p);

      for( std::list<PropNode*>::iterator iter = KB.database.begin();
                  iter != KB.database.end(); iter++)
      {
             modusPonens(  KB,  *iter,  p );
             modusPonens(  KB,  p, *iter );

             doubleNegationElimination(  KB,  p );

             disjuntResolution(  KB,  *iter, p );
             disjuntResolution(  KB, p, *iter );

             implicativeResolution(  KB,  *iter,  p );
             implicativeResolution(  KB,  p, *iter );

             deMorgansLaw(  KB,  p );
      }
}

void modusPonens( KnowledgeBase& KB, PropNode* prop, PropNode* a )
{
      if( prop->name != PropNode::IMPLICATION) return;
      
      std::list<PropNode*>::iterator iter = prop->children.begin();
      if( (*iter)->equals(a) )
      {
            iter++;

            if( KB_DEBUG )
            {
                  std::cout << "modusPonens found\n";
                  (*iter)->print();
                  std::cout << '\n';
            }

            forwardChaining(KB, *iter, false); //we are re-using beta, do not store
      }
}

void doubleNegationElimination( KnowledgeBase& KB, PropNode* a )
{
      if( a->name != PropNode::NOT ) return;

      std::list<PropNode*>::iterator iter = a->children.begin();
      if( (*iter)->name == PropNode::NOT )
      {

            if( KB_DEBUG )
            {
                  std::cout << "doubleNegationElimination found\n";
                  (*(*iter)->children.begin())->print();
                  std::cout << '\n';
            }
            forwardChaining(KB, *(*iter)->children.begin(), false); //we are re-using alpha, do not store
      }
}

/**
*         {a V b, ~b v c} implies
*                 a v c
*
*
* */
void disjuntResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 )
{
      if( prop1->name != PropNode::OR) return;
      if( prop2->name != PropNode::OR) return;

      std::list<PropNode*>::iterator b2 = prop2->children.begin();
      
      if( (*b2)->name != PropNode::NOT ) return;
      b2 = (*b2)->children.begin();
      
      std::list<PropNode*>::iterator b1 = prop1->children.begin();
      b1++; //b is in the 2nd child for the first logic-statement

      if( (*b1)->equals(*b2) )
      {
            PropNode* infer = new PropNode( PropNode::OR, false);

            PropNode* a = *prop1->children.begin();

        std::list<PropNode*>::iterator c2 = prop2->children.begin();
        c2++;
        PropNode* c = *c2;

            infer->addChild(a);
            infer->addChild(c);

            if( KB_DEBUG )
            {
                  std::cout << "disjuntResolution found\n";
                  infer->print();
                  std::cout << '\n';
            }

            forwardChaining(KB, infer); //infer is a new node, store it in the KB
      }
}

void implicativeResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 )
{
      if( prop1->name != PropNode::IMPLICATION) return;
      if( prop2->name != PropNode::IMPLICATION) return;

      std::list<PropNode*>::iterator b2 = prop2->children.begin();      
      std::list<PropNode*>::iterator b1 = prop1->children.begin();
      b1++; //b is in the 2nd child for the first logic-statement

      if( (*b1)->equals(*b2) )
      {
            PropNode* infer = new PropNode(PropNode::IMPLICATION, false);

            PropNode* a = *prop1->children.begin();
            b2++;
            PropNode* c = *b2;

            infer->addChild(a);
            infer->addChild(c);

            if( KB_DEBUG )
            {
                  std::cout << "implicativeResolution found\n";
                  infer->print();
                  std::cout << '\n';
            }

            forwardChaining(KB, infer); //infer is a new node, store it in the KB
      }
}

      /**
            Not (x Or y) -->  Not x  And  Not y
      */
 void deMorgansLaw( KnowledgeBase& KB, PropNode* prop )
 {
       if( prop->name != PropNode::NOT ) return;
       PropNode* child = *prop->children.begin();
       if( child->name != PropNode::OR ) return;

       PropNode* notX = new PropNode(PropNode::NOT, false); //dont destory x and y
       PropNode* notY = new PropNode(PropNode::NOT, false);

       std::list<PropNode*>::iterator original = child->children.begin();

       notX->addChild(*original);
     original++;
 
      notY->addChild(*original);

      PropNode* infer = new PropNode(PropNode::AND); //infer WILL destroy not-x and not-y when deleted
                                                   //but not-x and not-y would not delete x and y
      infer->addChild(notX);
      infer->addChild(notY);

      if( KB_DEBUG )
      {
            std::cout << "deMorgansLaw found\n";
            infer->print();
            std::cout << '\n';
      }

      forwardChaining(KB, infer); //infer is a new node, store it in the KB
 }

0
 

Author Comment

by:hiepbeo
ID: 16619960
File KnowledgeBase.h:

#ifndef _KNOWLEDGE_BASE_H_
#define  _KNOWLEDGE_BASE_H_

#include <string>
#include <list>
      
      extern bool KB_DEBUG; //debug flag

      class PropNode;

      /**
      * KnowledgeBase holds a collection of Propositional statements (PropNode).
      */
      class KnowledgeBase
      {
            friend void forwardChaining( KnowledgeBase& KB, PropNode* p, bool storeInKB );
        friend void addHorns(KnowledgeBase& KB, PropNode*& statement );

            public:
            KnowledgeBase();

        /**
         * delete all nodes that are stored in this KnowledgeBase
         * @see store()
         */
            virtual ~KnowledgeBase();

      /**
      true if the given node is in the knowledge base
      */
      bool contains( PropNode* statement );

      /**
      prints the statements in this knowledge base
      */
      void print();

      /**
      a list of statements in this KnowledgeBase.
      */
      std::list<PropNode*> database;

      /**
      stores a new piece of knowledge into the knowledge base,

      The KnowledgeBase gains control of the memory of the node. i.e.
      when this KnowledgeBase is destroyed it will delete the node

        Note: normally, you would use some inference function (e.g. forward-chaining)
              to add new nodes to the KnowledgeBase.
      */
      void store( PropNode* knowledge );

      /**
      similar to store, except it doesn't manage PropNode's memory
      @see store()
      */
      void add( PropNode* knowledge );


    private:
        /**
         * a list of nodes with memory managed by the KnowledgeBase
         */
      std::list<PropNode*> memory;
      };

      /**
            class PropNode represents a propositional logic statement
      */
      class PropNode
      {
            public:
                  static const std::string IMPLICATION;
                  static const std::string OR;
                  static const std::string NOT;
                  static const std::string AND;

            /**
             * @param deepDelete if deepDelete is false, then the children
             *        are not deleted when the destructor is called.
             *        
             *        This is useful because the many of the inference rules
             *        can reuse sub-trees of the argument sentences.
             *        e.g. resolution rule states: (a->b) & (b->c) ==> a->c
             *        we can reuse 'a' and 'c'.
             *
             *        In this case, the original trees (a->b and b->c),
             *        would delete all four sub-trees when their dtor are called,
             *        but the new inferred tree would not
             *        (by having deepDelete = false)
             */
            PropNode( const std::string& name, bool deepDelete = true );
        PropNode( PropNode& copy );
        PropNode* clone();
        void cloneChildren(std::list<PropNode*>& copy );

            /**
             * @param deepDelete if deepDelete is false, then the children
             *        are not deleted when the destructor is called.
             */
            PropNode( bool deepDelete = true );

            virtual ~PropNode();

            /**
             * add a child to this node
             */
            void addChild( PropNode* child );


            /**
             * compares two nodes and also their children
             */
            bool equals( PropNode* node );

            /**
             * Determines if the current node represents an operator.
             *
             * Example operators:
             * AND, OR, NOT, and IMPLICATION
             */
            bool isOperator();
            void print();

            bool mDeepDelete;

            /**
             * the name of this node
             * this could be a symbol (e.g. OR and NOT)
             * or the name of the term
             */
            std::string name;

            /**
             * a list of children for this node
             */
                  std::list<PropNode*> children;

            int par;

            /**
            * sets the level of this node
            * and also recursively sets its
            * children. Root has level == 0
            */
            void setLevel( int h );
            int level();

      private:
          static void print( std::list<PropNode*>& printlist);
            static void print( PropNode* root );
            PropNode* parent;
      };

    //------------------------ forward-chaining ----------------------------//
      /**
            note: our version is propositional logic with limited inference

            we implement the following inference rules:
            - modus ponens,
            - double-negation elimination,
            - and resolution (both versions),
            - de Morgan's laws (one way):
      */
      void forwardChaining( KnowledgeBase& KB, PropNode* p, bool store = true );

      /**
            {a->b, a} implies
            b
      */
      void modusPonens( KnowledgeBase& KB, PropNode* prop1, PropNode* a );

      /**
            {~~a} implies
            a
      */
      void doubleNegationElimination( KnowledgeBase& KB, PropNode* a );

      /**
            {a v b, ~b v c} implies
            a v c

        Note: if we have (b v a, ~b v c), we would not deduce a new statement
        even though logically we can.
      */
      void disjuntResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 );

      /**
            {~a -> b, b -> c} implies
            ~a -> c

            note: the book uses ~a, but {a->b, b->c} also implies a->c
      */
      void implicativeResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 );

      /**
            Not (x Or y) -->  Not x  And  Not y

        Note: The reverse is not checked.
      */
      void deMorgansLaw( KnowledgeBase& KB, PropNode* prop );

    //---------------------------- backward-chaining -----------------------//
    /**
        eliminateImplications

        Example:
        (A->B)->C
        (~AvB)->C
        ~(~AvB)vC
    */
    void eliminateImplications(PropNode* statement );

    /**
        move not's

        Example:
        ~~~(~~(A*B)+~C+~~D)
        ~(~~(A*B)+~C+~~D)
        ~~~(A*B)*~~C*~~~D
        ~(A*B)*C*~D
        (~A+~B)*C*~D
    */
    void moveNots( PropNode* statement );

    /**
        distribute-ands over or's

        Example:
        (a^b)vcv(d^e)
        (avcv(d^e))^(bvcv(d^e))
        ((avcvd)^(avcve))^(bvcv(d^e))
        ((avcvd)^(avcve))^((bvcvd)^(bvcve))
    */
    void distributeAnds( PropNode* node );


    /**
        flatten '^' and 'v''s

        Example:
        ((avcvd)^(avcve))^((bvcvd)^(bvcve))
        (avcvd)^(avcve)^(bvcvd)^(bvcve)
    */
    void flattenConDis( PropNode* node );
 
    /**
    calls convertToCNF, but the disjunctions are broken up
    and put into the list.
    */
    void convertToDisjunctions( PropNode*& statement,
                            std::list<PropNode*>& disjuncts);

    /**
    Convert the given statement into CNF -- conjunction of disjunctions.
 
    Examples:
    ~(a+b)*(c+d+~(e+(f*g)))
    is converted into:
    ~a * (~e + c + d) * ~b * (~f + ~g + c + d)

    ~(a->b)*(c+d+~(e->(f*g)))
    is converted into:
    a * ~b * (e + c + d) * (~f + ~g + c + d)

    @see eliminateImplications
    @see moveNots
    @see distributeAnds
    @see flattenConDis
    */
    void convertToCNF(PropNode* statement );

    /**
        Given a disjunction of literals, and convert it
        into a definite horn clause.
       
        convertToHorn assumes the given statement is a disjunction of literals.
        (e.g. "~a + ~b + c " ) The disjunction is required to have EXACTLY
        one positive literal, but can contain any number of negated literals.
        Invalid input will result in program termination. The only exception
        to this rule is when the statement is simply a single negated literal.
        For example, "~a" and "~a+b" are allowed, but "~a+~b" is not.

        Example:
        ~a v b      a -> b
        ~c         ~c
        d          d
    */
    void convertToHorn( PropNode* statement );

    /**
        Convert the statement into CNF and then convert the individual
        disjunctions into horn clauses. The derived horn clauses are stored into
        the KnowledgeBase. The KB takes control over the memory management
        of the statement.

        addHorns takes a generic propositional statement and stores the
        logically equivalent horn clauses in the given KnowledgeBase.
        Interally, the statement is first converted into CNF, then
        the disjunctions in the CNF are converted into Horn Clauses
        by calling convertToHorn.

        If the conversion is sucessful, statement is set to NULL (0).

        @see convertToHorn
        @see convertToCNF
        @see convertToDisjunctions
    */
    void addHorns(KnowledgeBase& KB, PropNode*& statement );

    /**
        Backward chaining performs a depth-limited-search using
        generalized modus ponens. The KB is assumed to contain
        ONLY horn clauses. Because of this, backward-chaining
        cannot be mixed with forward-chaining in the same KB.

        @param limit the depth limit for the search.
    */
    bool backwardChaining( KnowledgeBase& KB, char* query, int limit );
    bool backwardChaining( KnowledgeBase& KB,
                           std::list<PropNode*>& goal,
                           int limit );

    bool backwardChaining( KnowledgeBase& KB,
                           const std::string& query,
                           int limit);

#endif // _KNOWLEDGE_BASE_H_

0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16619972
that makes 2 files .. what about the other two .. I am trying to create a project and compile them at my end
0
 

Author Comment

by:hiepbeo
ID: 16619994
OK here is my project : 39KB
http://download.yousendit.com/3E0412A77C8B4959
0
 

Expert Comment

by:c89c
ID: 16620001
Wait.  All you have to do is have the .cpp files including as part of your project and then simply include the .h files.  And yes, you should always begin a header file with the next few lines of code ( i'll use file.h for the header file name).

#IFNDEF FILE_H
#DEFINE FILE_H

The only reason not to include define would be if you use inline delegation.
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16620057
only error I get with that project is

csworldclient.cpp(3) : fatal error C1083: Cannot open include file: 'Connection.h': No such file or directory
0
 

Author Comment

by:hiepbeo
ID: 16620067
you don't have to include all this file in this directory to your project. I include 9 files:

KnowledgeBase.cpp;
y.tab.cpp;
parser.cpp;
lex.yy.cpp
HornClauseDemo.cpp

y.tab.h;
KnowledgeBase.h;
unistd.h;
parser.h;

it works well:
------ Build started: Project: BTL, Configuration: Debug Win32 ------

BTL - up-to-date.


---------------------- Done ----------------------

    Build: 1 succeeded, 0 failed, 0 skipped
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 16621315
Here's what you need to do basically (used one, two, three and four for each module instead of your names) :

---- one.h ----
#ifndef ONE_H
#define ONE_H

#include "two.h" /* only if it's used in this module !!! */
#include "three.h" /* only if it's used in this module !!! */
#include "four.h" /* only if it's used in this module !!! */

/* your declarations for module one */

#endif /* ONE_H */
---- ----

---- one.cpp ----
#include "one.h"

/* your implementations for module one */
---- ----

Same for the other three modules !

Note that if module A is ONLY used in the implementation (B.cpp) of module B, and not in the declaration (B.h), then move the #include "A.h" to B.cpp, and remove it from B.h

Basically : including other modules is only needed if and where you're using them.
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16621385
Hi hiepbeo,
> it works well:
> ------ Build started: Project: BTL, Configuration: Debug Win32 ------

> BTL - up-to-date.


> ---------------------- Done ----------------------

>     Build: 1 succeeded, 0 failed, 0 skipped

If it compiles fine, then I believe your problem is solved!!!

Cheers!
Sunnycoder
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 16621393
@ sunnycoder : he wants to split up KnowledgeBase.cpp & KnowledgeBase.h into :

PropNode.cpp & PropNode.h
KnowledgeBase.cpp & KnowledgeBase.h
BackwardChaining.cpp & BackwardChaining.h
ForwardChaining.cpp & ForwardChaining.h

The project he put online has the original KnowledgeBase.cpp & KnowledgeBase.h, not the split up versions.
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16621407
Hi Infinity08,

Thanks :) ... That made the problem lot more clear to me ...

hiepbeo,

Post the code after splitting ... the one in which you were encountering the error ...

Cheers!
Sunnycoder
0
 

Author Comment

by:hiepbeo
ID: 16621725
After looking back the answer of synnycoder. I notice
 4. If variable is defined in one file and used in another, it needs to be declared as extern
 maybe the problem i have is here. When i declare a class, it belong to the KnowledgeBase group file. But in another file which have another class and function. These files and functions use Class (declared in KnowledgeBase group file) to construct themself 's .
 IF variable we use extern, but if Class what will we use ?????
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16621737
keep class declaration in .h file and class definition in .cpp file ... Include the .h in all the files that you wish to you.

Another way is to use a forward declaration such as

class Kb;

//Now you can use Kb ... definition can be provided later
0
 

Author Comment

by:hiepbeo
ID: 16621792
Here are all my file after deleting a lot of comment  code:

FIle KnowledgeBase.h:
#ifndef _KNOWLEDGE_BASE_H_
#define  _KNOWLEDGE_BASE_H_

#include <string>
#include <list>
#include "PropNode.h"
#include "BackwardChaining.h"
#include "ForwardChaining.h"
      
      extern bool KB_DEBUG; //debug flag

   class KnowledgeBase
      {
            friend void forwardChaining( KnowledgeBase& KB, PropNode* p, bool storeInKB );
        friend void addHorns(KnowledgeBase& KB, PropNode*& statement );
            public:
            KnowledgeBase();
            virtual ~KnowledgeBase();
      bool contains( PropNode* statement );
      void print();
      std::list<PropNode*> database;
      void store( PropNode* knowledge );
      void add( PropNode* knowledge );
    private:
      std::list<PropNode*> memory;
      };
#endif // _KNOWLEDGE_BASE_H_
********************************************************************
FIle KnowledgeBase.cpp:
#include <iostream>
#include "KnowledgeBase.h"
#include "PropNode.cpp"
#include "ForwardChaining.cpp"
#include "BackwardChaining.cpp"

#ifdef DEBUG
    #define Assert( flag, err_str ) assert( flag && err_str )
#else
    #define Assert( flag, err_str )             \
    do                                          \
    {                                           \
        if( (flag) == false )                   \
        {                                       \
            std::cerr<< err_str << std::endl;   \
            exit(1);                            \
        }                                       \
    }while(false)                          
#endif



bool KB_DEBUG = false;


//--------------------------------------- KnowledgeBase -----------------------------------//

KnowledgeBase::KnowledgeBase(){}

KnowledgeBase::~KnowledgeBase()
{
      for( std::list<PropNode*>::iterator delIter = memory.begin();
                  delIter != memory.end(); delIter++)
                        delete *delIter;
}
void KnowledgeBase::store( PropNode* knowledge )
{
      add(knowledge);
      memory.push_back(knowledge);
}

void KnowledgeBase::add( PropNode* knowledge )
{
      database.push_back(knowledge);
}

bool KnowledgeBase::contains( PropNode* statement )
{
      for( std::list<PropNode*>::iterator iter = database.begin();
                  iter != database.end(); iter++)
                        if( (*iter)->equals( statement ) ) return true;
      return false;
}
void KnowledgeBase::print()
{
      std::cout << "KnowledgeBase content\n";
      int i = 0;
      for( std::list<PropNode*>::iterator printIter = database.begin();
                  printIter != database.end(); printIter++)
      {
            std::cout << "----------- " << i <<  "----------- " << '\n';
            (*printIter)->print();
            i++;
      }
      std::cout << std::endl; //flush to cout
}

********************************************************************
FIle PropNode.h:
#ifndef _PROP_NODE_H_
#define  _PROP_NODE_H_

class PropNode
      {
            public:
                  static const std::string IMPLICATION;
                  static const std::string OR;
                  static const std::string NOT;
                  static const std::string AND;
                   PropNode( const std::string& name, bool deepDelete = true );
                  PropNode( PropNode& copy );
                  PropNode* clone();
                  void cloneChildren(std::list<PropNode*>& copy );
                   PropNode( bool deepDelete = true );
                  virtual ~PropNode();
                  void addChild( PropNode* child );
                  bool equals( PropNode* node );
                  bool isOperator();
                  void print();
                  bool mDeepDelete;
                  std::string name;
                  std::list<PropNode*> children;
                  int par;
                  void setLevel( int h );
                  int level();

            private:
                static void print( std::list<PropNode*>& printlist);
            static void print( PropNode* root );
            PropNode* parent;
      };

#endif // _PROP_NODE_H_
********************************************************************
FIle PropNode.cpp:
#include "PropNode.h"

const std::string PropNode::IMPLICATION("->");
const std::string PropNode::OR("+");
const std::string PropNode::NOT("~");
const std::string PropNode::AND("*");

PropNode::PropNode( PropNode& copy )
:name(copy.name), mDeepDelete(true)
{
   for( std::list<PropNode*>::iterator iter = copy.children.begin();
        iter != copy.children.end(); iter++)
            children.push_back( (*iter)->clone() );
}

PropNode::PropNode( const std::string& gname, bool gdeepDelete )
:name(gname), mDeepDelete(gdeepDelete), parent(0)
{}

PropNode::PropNode( bool deepDelete )
:mDeepDelete(deepDelete), parent(0)
{}

void PropNode::addChild(PropNode* child)
{
    children.push_back(child);
    child->parent = this;
}

PropNode::~PropNode()
{
      if( ! mDeepDelete) return;

      for( std::list<PropNode*>::iterator delIter = children.begin();
                  delIter != children.end(); delIter++)
                        delete *delIter;
}

bool PropNode::isOperator()
{
      return name == IMPLICATION ||
           name == OR ||
           name == NOT ||
           name == AND;
}

bool PropNode::equals( PropNode* node )
{
      if( node->children.size() != children.size() ) return false;
      if( name != node->name ) return false;

      std::list<PropNode*>::iterator iter;
      std::list<PropNode*>::iterator niter;
      for( iter = children.begin(), niter = node->children.begin();
                  iter != children.end();
                  iter++, niter++ )
                  {
                              if( (*iter)->equals(*niter) == false) return false;
                  }

      return true;
}

void PropNode::print()
{
    par = 0;
    print(this);
}

void PropNode::print( PropNode* root )
{
   for( int i = 0; i < root->par; i++) std::cout << ' ';
   std::cout << root->name << '\n';

   for( std::list<PropNode*>::iterator iter = root->children.begin();
        iter != root->children.end(); iter++)
   {
       (*iter)->par = root->par + 1;
       print( *iter );
   }
}

void PropNode::print( std::list<PropNode*>& printlist)
{
     
      while( !printlist.empty() )
      {
            std::list<PropNode*>::iterator printIter = printlist.begin();            

        for( int i = 0; i < (*printIter)->par; i++) std::cout << ' ';
            std::cout << (*printIter)->name << '\n';

        int count = (*printIter)->children.size();
            std::list<PropNode*>::iterator iter = (*printIter)->children.begin();
          for( ; iter != (*printIter)->children.end(); iter++)
                        printlist.push_back( *iter );

            printlist.erase( printIter );
      }
}

void PropNode::setLevel(int h )
{
    par = h;
    for( std::list<PropNode*>::iterator iter = children.begin();
         iter != children.end(); iter++) (*iter)->setLevel(h+1);
}

int PropNode::level()
{
    return par;
}

PropNode* PropNode::clone()
{
    return new PropNode(*this);
}

void PropNode::cloneChildren(std::list<PropNode*>& copy )
{
    for( std::list<PropNode*>::iterator iter = copy.begin();
         iter != copy.end(); iter++)
        children.push_back( (*iter)->clone() );
}
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16621801
I dont see forward chaining and backward chaining ... post the code with which you have problems after splitting .. also post the "exact" error messages
0
 

Author Comment

by:hiepbeo
ID: 16621804
********************************************************************
FIle BackwardChaining.h:
#include "KnowledgeBase.h"
#ifndef _BACKWARD_CHAINING_H_
#define  _BACKWARD_CHAINING_H_

class KnowledgeBase;
class PropNode;

    //---------------------------- backward-chaining -----------------------//
    void eliminateImplications(PropNode* statement );
    void moveNots( PropNode* statement );
    void distributeAnds( PropNode* node );
    void flattenConDis( PropNode* node );
    void convertToDisjunctions( PropNode*& statement, std::list<PropNode*>& disjuncts);

    void convertToCNF(PropNode* statement );
    void convertToHorn( PropNode* statement );
    void addHorns(KnowledgeBase& KB, PropNode*& statement );
    bool backwardChaining( KnowledgeBase& KB, char* query, int limit );
    bool backwardChaining( KnowledgeBase& KB,
                           std::list<PropNode*>& goal,
                           int limit );

    bool backwardChaining( KnowledgeBase& KB,
                           const std::string& query,
                           int limit);


      #endif //_BACKWARD_CHAINING_H_
********************************************************************
FIle BackwardChaining.cpp:
#include "BackwardChaining.h"
//--------------------------------------- Backward-Chaining ----------------------------//
void eliminateImplications(PropNode* statement )
{
    if( statement->name == PropNode::IMPLICATION )
    {
        statement->name = PropNode::OR;
     
        PropNode* notP = new PropNode( PropNode::NOT );

        notP->addChild( *statement->children.begin() );
        statement->children.pop_front();

        statement->children.push_front( notP );
    }
   
    for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
        eliminateImplications(*iter);
}

void moveNots( PropNode* statement )
{
      while( statement->name == PropNode::NOT &&
        (*statement->children.begin())->name == PropNode::NOT)
    {
       PropNode* old = *statement->children.begin();
       PropNode* newNode = *old->children.begin();

       statement->name = newNode->name;
       statement->children = newNode->children;

       newNode->children.clear(); //break the link to sub-tree
       delete old;
    }
    if( statement->name == PropNode::NOT &&
        (*statement->children.begin())->isOperator() == true )
    {
        Assert( (*statement->children.begin())->name == PropNode::OR ||
                (*statement->children.begin())->name == PropNode::AND,
                "the child name is either AND or OR. didn't elminate IMPLICATION's?");
        PropNode* childNode = *statement->children.begin();

        std::string opposite = childNode->name == PropNode::OR ?
                                    PropNode::AND : PropNode::OR;
        statement->name = opposite;
        statement->children.clear(); //break link to childNode;
 
        for( std::list<PropNode*>::iterator iter = childNode->children.begin();
             iter != childNode->children.end(); iter++)
        {
            PropNode* notChild = new PropNode( PropNode::NOT );
            notChild->addChild( *iter );
            statement->addChild( notChild );
        }
        childNode->children.clear(); //drop all old children
        delete childNode;
    }

    for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
            moveNots( *iter );
}

void distributeAnds( PropNode* node )
{
   if( node->name == PropNode::OR )
   {
       //find a child with AND
       PropNode* andChild = 0;
       for( std::list<PropNode*>::iterator iter = node->children.begin();
            iter != node->children.end(); iter++)
           if( (*iter)->name == PropNode::AND )
           { //remove the AND-child from the node
                andChild = *iter;
                node->children.erase(iter);
                break;
           }

     if( andChild != 0 )
       {
           //the new node is a AND-node
           node->name = PropNode::AND;

           std::list<PropNode*> children; //the new OR-children for the AND-node
           for( std::list<PropNode*>::iterator iter = andChild->children.begin();
                iter != andChild->children.end(); iter++)
           {
                PropNode* orChild = new PropNode( PropNode::OR );
                orChild->addChild( *iter );
                orChild->cloneChildren( node->children ); //add other children
                children.push_back(orChild);
           }
           for( std::list<PropNode*>::iterator delIter = node->children.begin();
                delIter != node->children.end(); delIter++)
                    delete *delIter;
            node->children = children; //the new children is a list of OR-nodes

           andChild->children.clear();
           delete andChild; //destory the AND-symbol
       }
   }

   for( std::list<PropNode*>::iterator iter = node->children.begin();
        iter != node->children.end(); iter++)
           distributeAnds( *iter );    
}

void flattenConDis( PropNode* node )
{
   if( node->isOperator() == false ) return; //a term

   for( std::list<PropNode*>::iterator iter = node->children.begin();
        iter != node->children.end(); iter++)
            flattenConDis(*iter);

   for( std::list<PropNode*>::iterator iter2 = node->children.begin();
        iter2 != node->children.end(); )
   {
        if( (*iter2)->name == node->name )
        {
           node->children.merge( (*iter2)->children );
           (*iter2)->children.clear();

           delete *iter2;
           iter2 = node->children.erase(iter2);
        }
        else
        { //go to the next element
            iter2++;
        }
   }
}

template<class T, class S>
class DeRefLessThanComparable
{
    public:
        bool operator()( T arg1, S arg2 ){ return *arg1 < *arg2; }
};

void convertToCNF(PropNode* statement )
{
   eliminateImplications(statement);
   moveNots(statement);
   distributeAnds(statement);
   flattenConDis(statement);
}

void convertToDisjunctions( PropNode*& statement,
                            std::list<PropNode*>& disjuncts)
{
    convertToCNF(statement);
    if( statement->name == PropNode::OR )
    { //only one disjunction
      disjuncts.push_back(statement);
    }
    else
    {
        for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
        disjuncts.push_back(*iter);
        statement->children.clear();
        delete statement;
    }
    statement = 0;
}
void convertToHorn( PropNode* statement )
{
    //already is a term?
    if( statement->children.size() == 0 ) return;
    Assert( statement->name == PropNode::OR, "not a disjunction?");

    PropNode* andNode = new PropNode(PropNode::AND);
    PropNode* posTerm = 0;

    for( std::list<PropNode*>::iterator iter = statement->children.begin();
         iter != statement->children.end(); iter++)
    {
       if( (*iter)->name == PropNode::NOT )
       {
           PropNode* term = *(*iter)->children.begin();
           //remove the NOT from the negated term
           andNode->addChild(term);

           (*iter)->children.clear(); //break the link to the term
           delete *iter;
       }
       else if( posTerm == 0 )
           posTerm = *iter;
       else
           Assert( false, "Bad Horn clause, more than one positive term.");
    }

    Assert( posTerm != 0, "Bad Horn clause. All terms are negated.");

    //build horn clause
    statement->name = PropNode::IMPLICATION;
    statement->children.clear();

    //link the implication terms
    statement->addChild(andNode);
    statement->addChild(posTerm);
}

void addHorns(KnowledgeBase& KB, PropNode*& statement )
{
    std::list<PropNode*> disjuncts;
    convertToDisjunctions(statement, disjuncts);
    for( std::list<PropNode*>::iterator iter = disjuncts.begin();
         iter != disjuncts.end(); iter++)
    {
         convertToHorn(*iter);
         KB.store(*iter);
    }
}

bool backwardChaining( KnowledgeBase& KB, char* query, int limit )
{
    return backwardChaining( KB, std::string(query), limit );
}

/**
    @param goal a list of terms that must be satisfied
*/
bool backwardChaining( KnowledgeBase& KB, std::list<PropNode*>& goal, int limit )
{
    if( limit == 0 ) return false;
    limit--;
    for( std::list<PropNode*>::iterator iter = goal.begin();
         iter != goal.end(); iter++)
            if( backwardChaining( KB, (*iter)->name, limit ) == false ) return false;
    return true;
}

bool backwardChaining( KnowledgeBase& KB, const std::string& query, int limit )
{
   if( limit == 0 ) return false;
   limit--;

   PropNode qnode(query);
   if( KB.contains(&qnode) )
   {
       if(KB_DEBUG) std::cerr << "backwardChaining found: " << query << '\n';
       return true;
   }

   for( std::list<PropNode*>::iterator iter = KB.database.begin();
        iter != KB.database.end(); iter++)
   {
       if((*iter)->isOperator() == true && //if it is a rules, not a term
           (*iter)->name != PropNode::NOT)
       {
            Assert((*iter)->name == PropNode::IMPLICATION,
                "KB does not contain horn clauses");

            std::list<PropNode*>::iterator target = (*iter)->children.begin();
            std::list<PropNode*>::iterator premise = target;

            Assert((*premise)->name == PropNode::AND,
                "KB does not contain horn clauses");

            target++;
            if( query == (*target)->name && 
                backwardChaining( KB, (*premise)->children, limit ) )
            {
                if(KB_DEBUG)
                {
                    std::cerr << "backward-chaining satisfied premises for:\n";
                    (*iter)->print();
                }
                return true;
            }
       }
   }
   return false;
}

********************************************************************
FIle ForwardChaining.h:
#include "KnowledgeBase.h"
#ifndef _FORWARD_CHAINING_H_
#define  _FORWARD_CHAINING_H_

class KnowledgeBase;
class PropNode;
//------------------------ forward-chaining ----------------------------//
      
      void forwardChaining( KnowledgeBase& KB, PropNode* p, bool store = true );
      void modusPonens( KnowledgeBase& KB, PropNode* prop1, PropNode* a );
      void doubleNegationElimination( KnowledgeBase& KB, PropNode* a );
      void disjuntResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 );
      void implicativeResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 );
      void deMorgansLaw( KnowledgeBase& KB, PropNode* prop );


#endif //_FORWARD_CHAINING_H_

********************************************************************
FIle ForwardChaining.cpp:
#include "ForwardChaining.h"
//--------------------------------------- Forward-Chaining -----------------------------------//
void forwardChaining( KnowledgeBase& KB, PropNode* p, bool store )
{
      if( KB.contains(p) ) return;
      
      if( store )
            KB.store(p);
      else
            KB.add(p);

      for( std::list<PropNode*>::iterator iter = KB.database.begin();
                  iter != KB.database.end(); iter++)
      {
             modusPonens(  KB,  *iter,  p );
             modusPonens(  KB,  p, *iter );

             doubleNegationElimination(  KB,  p );

             disjuntResolution(  KB,  *iter, p );
             disjuntResolution(  KB, p, *iter );

             implicativeResolution(  KB,  *iter,  p );
             implicativeResolution(  KB,  p, *iter );

             deMorgansLaw(  KB,  p );
      }
}

void modusPonens( KnowledgeBase& KB, PropNode* prop, PropNode* a )
{
      if( prop->name != PropNode::IMPLICATION) return;
      
      std::list<PropNode*>::iterator iter = prop->children.begin();
      if( (*iter)->equals(a) )
      {
            iter++;

            if( KB_DEBUG )
            {
                  std::cout << "modusPonens found\n";
                  (*iter)->print();
                  std::cout << '\n';
            }

            forwardChaining(KB, *iter, false); //we are re-using beta, do not store
      }
}

void doubleNegationElimination( KnowledgeBase& KB, PropNode* a )
{
      if( a->name != PropNode::NOT ) return;

      std::list<PropNode*>::iterator iter = a->children.begin();
      if( (*iter)->name == PropNode::NOT )
      {

            if( KB_DEBUG )
            {
                  std::cout << "doubleNegationElimination found\n";
                  (*(*iter)->children.begin())->print();
                  std::cout << '\n';
            }
            forwardChaining(KB, *(*iter)->children.begin(), false); //we are re-using alpha, do not store
      }
}
void disjuntResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 )
{
      if( prop1->name != PropNode::OR) return;
      if( prop2->name != PropNode::OR) return;

      std::list<PropNode*>::iterator b2 = prop2->children.begin();
      
      if( (*b2)->name != PropNode::NOT ) return;
      b2 = (*b2)->children.begin();
      
      std::list<PropNode*>::iterator b1 = prop1->children.begin();
      b1++; //b is in the 2nd child for the first logic-statement

      if( (*b1)->equals(*b2) )
      {
            PropNode* infer = new PropNode( PropNode::OR, false);

            PropNode* a = *prop1->children.begin();

        std::list<PropNode*>::iterator c2 = prop2->children.begin();
        c2++;
        PropNode* c = *c2;

            infer->addChild(a);
            infer->addChild(c);

            if( KB_DEBUG )
            {
                  std::cout << "disjuntResolution found\n";
                  infer->print();
                  std::cout << '\n';
            }

            forwardChaining(KB, infer); //infer is a new node, store it in the KB
      }
}

void implicativeResolution( KnowledgeBase& KB, PropNode* prop1, PropNode* prop2 )
{
      if( prop1->name != PropNode::IMPLICATION) return;
      if( prop2->name != PropNode::IMPLICATION) return;

      std::list<PropNode*>::iterator b2 = prop2->children.begin();      
      std::list<PropNode*>::iterator b1 = prop1->children.begin();
      b1++; //b is in the 2nd child for the first logic-statement

      if( (*b1)->equals(*b2) )
      {
            PropNode* infer = new PropNode(PropNode::IMPLICATION, false);

            PropNode* a = *prop1->children.begin();
            b2++;
            PropNode* c = *b2;

            infer->addChild(a);
            infer->addChild(c);

            if( KB_DEBUG )
            {
                  std::cout << "implicativeResolution found\n";
                  infer->print();
                  std::cout << '\n';
            }

            forwardChaining(KB, infer); //infer is a new node, store it in the KB
      }
}

 void deMorgansLaw( KnowledgeBase& KB, PropNode* prop )
 {
       if( prop->name != PropNode::NOT ) return;
       PropNode* child = *prop->children.begin();
       if( child->name != PropNode::OR ) return;

       PropNode* notX = new PropNode(PropNode::NOT, false); //dont destory x and y
       PropNode* notY = new PropNode(PropNode::NOT, false);

       std::list<PropNode*>::iterator original = child->children.begin();

       notX->addChild(*original);
     original++;
 
      notY->addChild(*original);

      PropNode* infer = new PropNode(PropNode::AND); //infer WILL destroy not-x and not-y when deleted
                                                   //but not-x and not-y would not delete x and y
      infer->addChild(notX);
      infer->addChild(notY);

      if( KB_DEBUG )
      {
            std::cout << "deMorgansLaw found\n";
            infer->print();
            std::cout << '\n';
      }

      forwardChaining(KB, infer); //infer is a new node, store it in the KB
 }


0
 

Author Comment

by:hiepbeo
ID: 16621824
When compiling i have these errors:

PropNode.cpp(72): error C2065: 'cout' : undeclared identifier
 PropNode.cpp(72): error C2039: 'cout' : is not a member of 'std'
 PropNode.cpp(73): error C2039: 'cout' : is not a member of 'std'
 PropNode.cpp(73): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\string(535) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,unsigned char)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(887) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,const unsigned char *)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(880) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,signed char)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(873) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,const signed char *)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(866) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,_Elem)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(828) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,const _Elem *)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(783) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,char)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(744) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,const char *)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(697) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,char)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(659) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,const char *)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(613) : see declaration of 'std::operator`<<''
 PropNode.cpp(73): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 PropNode.cpp(90): error C2039: 'cout' : is not a member of 'std'
 PropNode.cpp(90): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 PropNode.cpp(91): error C2039: 'cout' : is not a member of 'std'
 PropNode.cpp(91): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\string(535) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,unsigned char)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(887) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,const unsigned char *)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(880) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,signed char)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(873) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,const signed char *)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(866) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,_Elem)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(828) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,const _Elem *)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(783) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,char)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(744) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<char,_Traits> &std::operator <<(std::basic_ostream<char,_Traits> &,const char *)' : could not deduce template argument for 'std::basic_ostream<char,_Elem> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(697) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,char)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(659) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C2784: 'std::basic_ostream<_Elem,_Traits> &std::operator <<(std::basic_ostream<_Elem,_Traits> &,const char *)' : could not deduce template argument for 'std::basic_ostream<_Elem,_Traits> &' from ''unknown-type''
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\ostream(613) : see declaration of 'std::operator`<<''
 PropNode.cpp(91): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 PropNode.cpp(93): warning C4267: 'initializing' : conversion from 'size_t' to 'int', possible loss of data
 PropNode.cpp(93): warning C4267: 'initializing' : conversion from 'size_t' to 'int', possible loss of data
 BackwardChaining.cpp(39): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(172): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(192): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(195): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(254): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(260): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(41): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(41): error C2065: 'cout' : undeclared identifier
 ForwardChaining.cpp(43): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(43): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(60): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(60): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(62): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(62): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(95): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(95): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(97): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(97): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(126): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(126): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(128): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(128): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(158): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(158): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 ForwardChaining.cpp(160): error C2039: 'cout' : is not a member of 'std'
 ForwardChaining.cpp(160): error C3861: 'cout': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(39): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(172): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(192): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(195): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(244): error C2039: 'cerr' : is not a member of 'std'
 BackwardChaining.cpp(244): error C2065: 'cerr' : undeclared identifier
 BackwardChaining.cpp(254): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(260): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(269): error C2039: 'cerr' : is not a member of 'std'
 BackwardChaining.cpp(269): error C3861: 'cerr': identifier not found, even with argument-dependent lookup
bison.simple(289): warning C4244: 'initializing' : conversion from '__w64 int' to 'int', possible loss of data
lex.yy.c(912): warning C4267: '=' : conversion from 'size_t' to 'int', possible loss of data
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16621830
1.
>#include "PropNode.cpp"
>#include "ForwardChaining.cpp"
>#include "BackwardChaining.cpp"

Do not #include the .cpp files ... they are linked together during linking phase and as long as symbols resolve fine, you wont face any problems ...

2.
Include proper header files ... e.g. in PropNode.h you are referencing std and list but you did not #include them!!!

Cheers!
sunnycoder
0
 

Author Comment

by:hiepbeo
ID: 16621859

it remains errors:
BackwardChaining.cpp(40): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(173): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(193): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(196): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(255): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
 BackwardChaining.cpp(261): error C3861: 'Assert': identifier not found, even with argument-dependent lookup
bison.simple(289): warning C4244: 'initializing' : conversion from '__w64 int' to 'int', possible loss of data
 PropNode.cpp(93): warning C4267: 'initializing' : conversion from 'size_t' to 'int', possible loss of data
lex.yy.c(912): warning C4267: '=' : conversion from 'size_t' to 'int', possible loss of data

ALL are correct ???
KnowledgeBase.h :
#include <string>
#include <list>
#include "PropNode.h"
#include "BackwardChaining.h"
#include "ForwardChaining.h"

KnowledgeBase.cpp:
#include <iostream>
#include "KnowledgeBase.h"

PropNode.h:
#include <iostream>
#include "KnowledgeBase.h"

PropNode.cpp:
#include "PropNode.h"

ForwardChaining.h:
#include <iostream>
#include "KnowledgeBase.h"

ForwardChaining.cpp
#include "ForwardChaining.h"

BackwardChaining.h
#include <iostream>
#include "KnowledgeBase.h"

BackwardChaining.cpp
#include "BackwardChaining.h"
0
 
LVL 45

Accepted Solution

by:
sunnycoder earned 2000 total points
ID: 16621884
move definition of assert from .cpp file to .h file

bison.simple(289): warning C4244: 'initializing' : conversion from '__w64 int' to 'int', possible loss of data
 PropNode.cpp(93): warning C4267: 'initializing' : conversion from 'size_t' to 'int', possible loss of data
lex.yy.c(912): warning C4267: '=' : conversion from 'size_t' to 'int', possible loss of data

These warning indicate type mistmach ... make sure you are not losig data due to lower precision .. if that is the case then use the higher data types
0
 

Author Comment

by:hiepbeo
ID: 16621903
You can to me more ??? How to move definition of assert from .cpp file to .h file ??? You mean that I must include a another header file ???? I can't find any definition about assert from BACKWARDCHAINING.cpp file.



0
 

Author Comment

by:hiepbeo
ID: 16621940
Well , i have just moved definition of assert from .cpp file to .h file, in KnowledgeBase file, not in BackwardChaining file:D. Sorry.
 Thanks you a lot. I regret that i can only give you 500 points. Your efforts is worth more than that :). I remain a lot of questions, hope that you will help me on these another question like that. Thanks again !!!
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 16621986
Glad to help :)
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface This article introduces an authentication and authorization system for a website.  It is understood by the author and the project contributors that there is no such thing as a "one size fits all" system.  That being said, there is a certa…
Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question