/*************************************************************************/ /* Copyright (c) 2012, 2013 Linas Vepstas */ /* All rights reserved */ /* */ /* Use of the Viterbi parsing system is subject to the terms of the */ /* license set forth in the LICENSE file included with this software. */ /* This license allows free redistribution and use in source and binary */ /* forms, with or without modification, subject to certain conditions. */ /* */ /*************************************************************************/ #ifndef _ATOMBASE_COMPILE_H #define _ATOMBASE_COMPILE_H #include #include #include "atom.h" namespace atombase { // Classes that convert run-time atom types into compile-time static // types, so that the compiler can check these for correctness. // These are here purely for C++ programming convenience; the true // structure that matters is the dynamic run-time (hyper-)graphs. /// Simple string label node. class Label : public Node { public: Label(const NameString& n, const TV& tv = TV()) : Node(LABEL, n, tv) {} }; /// Index, ID /// Identification Node, holds one or several numeric ID values. /// Intended primarily for debugging. class Index : public Node { public: Index(int a, const TV& tv = TV()) : Node(INDEX, ({ char buff[80]; snprintf(buff, 80, "%d", a); buff;}), tv) {} Index(int a, int b, const TV& tv = TV()) : Node(INDEX, ({ char buff[80]; snprintf(buff, 80, "%d, %d", a, b); buff;}), tv) {} Index(unsigned int a, int b, int c, const TV& tv = TV()) : Node(INDEX, ({ char buff[80]; snprintf(buff, 80, "%u, %d, %d", a, b, c); buff;}), tv) {} Index(double a, const TV& tv = TV()) : Node(INDEX, ({ char buff[80]; snprintf(buff, 80, "%20.16f", a); buff;}), tv) {} }; /// Holder of one floating-poing number class Number : public Node { public: Number(double a, const TV& tv = TV()) : Node(NUMBER, ({ char buff[80]; snprintf(buff, 80, "%20.16g", a); buff;}), tv), _value(a) {} double get_value() const { return _value; } protected: double _value; }; /// Named relation, as defined in model theory. /// /// This consists of a name (Label), followed by an ordered sequence /// of atoms. The atoms are all related by the relation. There are /// many different ways of thinking about this: /// 1) as a predicate: the relation is true/satisfied if it exists. /// (the truth of which is given by the _tv, of course) /// 2) as a graph of a function (in the sense of Bourbaki) /// 3) as a (named) function, the first n atoms being the arguments, /// the last being the value of the function for those arguments. /// 4) the atom that is (more or less) equivalent to the OpenCog ExecutionLink class Relation : public Link { public: // Binary relation; add others if needed. Relation(Label* lab, Atom* arg, Atom* val, const TV& tv = TV()) : Link(RELATION, ({OutList o(1,lab); o.push_back(arg); o.push_back(val); o;}), tv) {} Relation(const char* name, Atom* arg, Atom* val, const TV& tv = TV()) : Link(RELATION, ({OutList o(1, new Label(name)); o.push_back(arg); o.push_back(val); o;}), tv) {} }; /// Unordered multiset /// A Set inherits fom Link, and is an unordered set of zero or more /// atoms. Properly speaking, it is a multi-set; the same atom may /// appear more than once in the set. class Set : public Link { public: Set(const TV& tv = TV()) : Link(SET, tv) {} Set(const OutList& ol, const TV& tv = TV()) : Link(SET, ol, tv) {} Set(Atom* singleton, const TV& tv = TV()) : Link(SET, OutList(1, singleton), tv) {} Set(Atom* a, Atom* b, const TV& tv = TV()) : Link(SET, ({OutList o(1,a); o.push_back(b); o;}), tv) {} Set(Atom* a, Atom* b, Atom* c, const TV& tv = TV()) : Link(SET, ({OutList o(1,a); o.push_back(b); o.push_back(c); o;}), tv) {} Set(Atom* a, Atom* b, Atom* c, Atom* d, const TV& tv = TV()) : Link(SET, ({OutList o(1,a); o.push_back(b); o.push_back(c); o.push_back(d); o;}), tv) {} Set(Atom* a, Atom* b, Atom* c, Atom* d, Atom* e, const TV& tv = TV()) : Link(SET, ({OutList o(1,a); o.push_back(b); o.push_back(c); o.push_back(d); o.push_back(e); o;}), tv) {} protected: /// The sole purpose of this ctor is to allow inheritance. Set(AtomType t, const TV& tv = TV()) : Link(t, tv) {} Set(AtomType t, const OutList& oset, const TV& tv = TV()) : Link(t, oset, tv) {} // Only for classes that inherit from Set Set(AtomType t, Atom* singleton, const TV& tv = TV()) : Link(t, OutList(1, singleton), tv) {} Set(AtomType t, Atom* a, Atom* b, const TV& tv = TV()) : Link(t, ({OutList o(1,a); o.push_back(b); o;}), tv) {} Set(AtomType t, Atom* a, Atom* b, Atom* c, const TV& tv = TV()) : Link(t, ({OutList o(1,a); o.push_back(b); o.push_back(c); o;}), tv) {} Set(AtomType t, Atom* a, Atom* b, Atom* c, Atom* d, const TV& tv = TV()) : Link(t, ({OutList o(1,a); o.push_back(b); o.push_back(c); o.push_back(d); o;}), tv) {} Set(AtomType t, Atom* a, Atom* b, Atom* c, Atom* d, Atom* e, const TV& tv = TV()) : Link(t, ({OutList o(1,a); o.push_back(b); o.push_back(c); o.push_back(d); o.push_back(e); o;}), tv) {} public: // See the C file for documentation Set* flatten() const { return new Set(flatset(), _tv); } Atom* super_flatten() const; // Set-union (append) other set to this set. virtual Set* sum(const Set*) const; virtual Set* clone() const { return new Set(*this); } Set* append(Atom* a) const { return dynamic_cast(Link::append(a)); } Set* replace(Atom* novi, Atom* ctari) const { return dynamic_cast(Link::replace(novi, ctari)); } protected: OutList flatset() const; }; /// Unique set. An atom may appear at most once in the outgoing set. /// Duplicates are removed during construction. class Uniq : public Set { public: Uniq(const TV& tv = TV()) : Set(UNIQ, tv) {} Uniq(const OutList& ol, const TV& tv = TV()) : Set(UNIQ, uniqify(ol), tv) {} Uniq(Atom* singleton, const TV& tv = TV()) : Set(UNIQ, uniqify(OutList(1, singleton)), tv) {} Uniq(Atom* a, Atom* b, const TV& tv = TV()) : Set(UNIQ, uniqify(({OutList o(1,a); o.push_back(b); o;})), tv) {} Uniq(Atom* a, Atom* b, Atom* c, const TV& tv = TV()) : Set(UNIQ, uniqify(({OutList o(1,a); o.push_back(b); o.push_back(c); o;})), tv) {} // Special copy constructor Uniq(Set* sset) : Set(UNIQ, uniqify(sset->get_outgoing_set()), sset->_tv) {} // XXX TODO we really should overload append, and enforce uniqueness. ... protected: static OutList uniqify(const OutList& ol); }; /// Ordered sequence /// Seq inherits from Set, and is an ordered sequence of zero or more /// atoms. class Seq : public Set { public: Seq() : Set(SEQ) {} Seq(const OutList& ol, const TV& tv = TV()) : Set(SEQ, ol, tv) {} Seq(Atom* singleton, const TV& tv = TV()) : Set(SEQ, OutList(1, singleton), tv) {} Seq(Atom* a, Atom* b, const TV& tv = TV()) : Set(SEQ, ({OutList o(1,a); o.push_back(b); o;}), tv) {} // See the Set class for documentation Seq* flatten() const { return new Seq(flatset(), _tv); } virtual Seq* clone() const { return new Seq(*this); } Seq* append(Atom* a) const { return dynamic_cast(Link::append(a)); } /// Get the first and last atoms in the sequence Atom* get_first() const { if (0 < get_arity()) return get_outgoing_atom(0); else return NULL; } Atom* get_last() const { size_t sz = get_arity(); if (0 < sz) return get_outgoing_atom(sz-1); else return NULL; } protected: /// The sole purpose of this ctor is to allow inheritance. Seq(AtomType t) : Set(t) {} Seq(AtomType t, const OutList& oset, const TV& tv = TV()) : Set(t, oset, tv) {} Seq(AtomType t, Atom* a, Atom* b, const TV& tv = TV()) : Set(t, ({OutList o(1,a); o.push_back(b); o;}), tv) {} Seq(AtomType t, Atom* a, Atom* b, Atom* c, const TV& tv = TV()) : Set(t, ({OutList o(1,a); o.push_back(b); o.push_back(c); o;}), tv) {} Seq(AtomType t, Atom* a, Atom* b, Atom* c, Atom* d, const TV& tv = TV()) : Set(t, ({OutList o(1,a); o.push_back(b); o.push_back(c); o.push_back(d); o;}), tv) {} }; /// Unordered OR of all children class Or : public Set { public: Or(const TV& tv = TV()) : Set(OR, tv) {} Or(const OutList& ol, const TV& tv = TV()) : Set(OR, ol, tv) {} Or(Atom* singleton, const TV& tv = TV()) : Set(OR, OutList(1, singleton), tv) {} Or(Atom* a, Atom* b, const TV& tv = TV()) : Set(OR, ({OutList o(1,a); o.push_back(b); o;}), tv) {} Or(Atom* a, Atom* b, Atom* c, const TV& tv = TV()) : Set(OR, ({OutList o(1,a); o.push_back(b); o.push_back(c); o;}), tv) {} // Return disjunctive normal form (DNF) Atom* disjoin() const; // See the Set class for documentation Or* flatten() const { return new Or(flatset(), _tv); } // Remove repeated entries Or* uniq() const; virtual Or* clone() const { return new Or(*this); } Or* append(Atom* a) const { return dynamic_cast(Link::append(a)); } }; /// Ordered sequence /// And inherits from Seq, since the order of the atoms in /// its outgoing set is important. class And : public Seq { public: And() : Seq(AND) {} And(const OutList& ol, const TV& tv = TV()) : Seq(AND, ol, tv) {} And(Atom* singleton, const TV& tv = TV()) : Seq(AND, OutList(1, singleton), tv) {} And(Atom* a, Atom* b, const TV& tv = TV()) : Seq(AND, ({OutList o(1,a); o.push_back(b); o;}), tv) {} And(Atom* a, Atom* b, Atom* c, const TV& tv = TV()) : Seq(AND, ({OutList o(1,a); o.push_back(b); o.push_back(c); o;}), tv) {} // Return disjunctive normal form (DNF) // Does not modify this atom; just returns a new one. Atom* disjoin(); // See the Set class for documentation And* flatten() const { return new And(flatset(), _tv); } /// Remove optional clauses. /// XXX Perhaps this should not be a method on this class... Atom* clean() const; virtual And* clone() const { return new And(*this); } And * append(Atom* a) const { return dynamic_cast(Link::append(a)); } }; } // namespace atombase #endif // _ATOMBASE_COMPILE_H