/*
* opencog/atoms/scope/Variables.h
*
* Copyright (C) 2015 Linas Vepstas
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License v3 as
* published by the Free Software Foundation and including the exceptions
* at http://opencog.org/wiki/Licenses
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to:
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _OPENCOG_VARIABLES_H
#define _OPENCOG_VARIABLES_H
#include <map>
#include <set>
#include <opencog/util/empty_string.h>
#include <opencog/atoms/base/Handle.h>
#include <opencog/atoms/base/Atom.h>
#include <opencog/atoms/free/FreeVariables.h>
#include <opencog/atoms/scope/TypedVariableLink.h>
namespace opencog
{
/** \addtogroup grp_atomspace
* @{
*/
typedef std::map<Handle, TypedVariableLinkPtr> VariableTypeMap;
/// The Variables struct defines a list of typed variables "unbundled"
/// from the hypergraph in which they normally occur. The goal of this
/// structure is to make it easier and faster to work with VariableNodes
/// in C++; specifically, to check any type restrictions that may apply.
///
/// This class is used by VariableList and ScopeLink to define typed,
/// scoped, bound variables; in particular, it is heavily used by the
/// pattern matcher.
///
struct Variables : public FreeVariables
{
// CTors. The ordered flag indicates whether we care about the
// order of the variables. It is false by default and only enabled
// if VariableList is used.
Variables(bool ordered=false);
Variables(const Handle& vardecl, bool ordered=false);
Variables(const HandleSeq& vardecls, bool ordered=false);
/// Whether the order matters or not. Typically if constructed with
/// VariableList then the order matters, if constructed with
/// VariableSet then the order does not matter.
bool _ordered;
/// Unbundled variables and type restrictions for them.
/// _typemap holds back-ponters to TypedVariableLinkPtrs
VariableTypeMap _typemap;
// Validate the variable decls
void validate_vardecl(const Handle&);
void validate_vardecl(const HandleSeq&);
void unpack_vartype(const Handle&);
/// Return true iff all variables are well typed. For now only
/// simple types are supported, specifically if some variable is
/// simple typed NOTYPE, then it returns false.
bool is_well_typed() const;
// Return true if the other Variables struct is equal to this one,
// up to alpha-conversion. That is, same number of variables, same
// type restrictions, but different actual variable names.
// Same as satisfying this->is_type(other->varseq) and also
// other->is_type(this->varseq) -- the equality is symmetric.
bool is_equal(const Variables& other) const;
bool is_equal(const Variables& other, size_t index) const;
bool operator==(const Variables& other) const;
// Comparison operators. Convenient to define containers of Variables
bool operator<(const Variables& other) const;
// Return true if the variable `othervar` in `other` is
// alpha-convertible to the variable `var` in this. That is,
// return true if they are the same variable, differing only
// in name.
bool is_alpha_convertible(const Handle& var,
const Handle& othervar,
const Variables& other,
bool check_type=false) const;
// Return true if we are holding a single variable, and the handle
// given as the argument satisfies the type restrictions (if any).
// Else return false.
bool is_type(const Handle&) const;
// Return true if we are holding a single variable, and it can
// be the indicated type.
bool is_type(Type) const;
// Return true if we are holding the variable `var`, and `val`
// satisfies the type restrictions that apply to `var`.
bool is_type(const Handle& var, const Handle& val) const;
bool is_type(const Handle& var, const ValuePtr& val) const;
// Return true if the sequence is of the same length as the variable
// declarations we are holding, and if they satisfy all of the type
// restrictions (if any).
bool is_type(const HandleSeq& hseq) const;
// Return true if the int satisfies the lower bound interval restriction.
// Return false otherwise.
bool is_lower_bound(const Handle& glob, size_t n) const;
// Return true if the int satisfies the upper bound interval restriction.
// Return false otherwise.
bool is_upper_bound(const Handle& glob, size_t n) const;
// Return true if the variable is has a range other than
// (1,1) i.e. if it can match more than one thing.
bool is_globby(const Handle& glob) const;
// Given the tree `tree` containing variables in it, create and
// return a new tree with the indicated arguments `args` substituted
// for the variables. The `args` must pass the typecheck, else an
// exception is thrown. If "silent" is true, then the exception
// will not be logged; this allows this method to be used for
// filtering, where type mis-checks are expected and normal.
Handle substitute(const Handle& tree,
const HandleSeq& args,
bool silent=false) const;
// Like the above, but using a partial map.
Handle substitute(const Handle& tree,
const HandleMap& map,
bool silent=false) const;
// Extend this by adding in the given variables. If either this or
// the other are ordered, then the result is ordered.
void extend(const Variables&);
void extend_intersect(const Variables&);
/// Erase the given variable, if it exists.
void erase(const Handle&);
/// Remove *all* variables that do not appear in any of the terms.
void trim(const HandleSeq&);
/// Remove *all* variables that do not appear in the term.
void trim(const Handle& h) { trim(HandleSeq({h})); }
/// Return the TypedVariableLink for the indicated variable.
/// Return just the Variable itself, if its not typed.
Handle get_type_decl(const Handle&, const Handle&) const;
/// Inverse of Variables(vardecl).get_variable()
///
/// That is, convert Variables object into a variable declaration,
/// that is a VariableList, VariableSet, TypedVariableLink,
/// VariableNode or GlobNode, suitable for direct use in a
/// ScopeLink.
///
/// If empty then return the empty VariableList or VariableSet.
Handle get_vardecl() const;
/// Like FreeVariables::find_variables but set _ordered to false,
/// on the ground that if this method is called, then no order
/// was intended in the variable scope.
void find_variables(const Handle& body);
void find_variables(const HandleSeq& oset, bool ordered_link=true);
const GlobInterval get_interval(const Handle&) const;
// Useful for debugging
std::string to_string(const std::string& indent=empty_string) const;
};
// Debugging helpers see
// http://wiki.opencog.org/w/Development_standards#Print_OpenCog_Objects
// The reason indent is not an optional argument with default is
// because gdb doesn't support that, see
// http://stackoverflow.com/questions/16734783 for more explanation.
std::string oc_to_string(const VariableTypeMap&,
const std::string& indent=empty_string);
std::string oc_to_string(const Variables&,
const std::string& indent=empty_string);
/** @}*/
}
#endif // _OPENCOG_VARIABLES_H