class GRelation {
private:
friend class GRelationIter;
typedef boost::shared_ptr<VarImpl::RelationImpl> Impl;
Impl pimpl_; ///> Relation storage
/// Avoid default construction
GRelation(void);
/// Constructor taking an implementation
explicit GRelation(Impl impl);
public:
/// \name Constructors, destructors and assignement
//@{
/// Constructor for an empty relation of arity \a a
explicit GRelation(int a);
/// Copy constructor
GRelation(const GRelation& r);
/// Assignment
GRelation& operator=(GRelation& right);
void become(const GRelation& other);
/// Destructor
~GRelation(void);
/// Constructs the relation \f$R=\mathcal{U}_{a}\f$
static GRelation create_full(int a);
//@}
/// \name Modification operations
//@{
/**
* \brief Adds tuple \a t to the relation. If \f$ t \in this \f$ the relation
* remains unchanged.
*/
void add(const Tuple& t);
/**
* \brief Adds the tuples contained in \a s to the relation.
*/
void add(const std::vector<Tuple>& s);
/**
* \brief Union of relations: \f$ this = this \cup r \f$.
*/
void unionAssign(const GRelation& r);
/**
* \brief Difference of relations: \f$ this = this \setminus r \f$.
*/
void differenceAssign(const GRelation& r);
//@}
/// \name Set operations
//@{
/// Computes \f$ this \setminus r \f$
GRelation difference(const GRelation& r) const;
/// Computes \f$ this \cap r \f$
GRelation intersect(const GRelation& r) const;
/// Computes \f$ this \cup r \f$
GRelation Union(const GRelation& r) const;
/// Computes \f$ \overline{this}\f$
GRelation complement(void) const;
//@}
/// \name Column permutation
//@{
/**
* \brief Computes the permutation of \a this according to \a desc.
*
* \warning The permutation descriptor has to be valid for the relation. If it
* is not then a InvalidPermDescriptor exception is thrown.
*/
GRelation permute(const std::vector<std::pair<int,int>>& desc) const;
/**
* \brief Computes the permutation of \a this according to \a desc.
*
* \warning The permutation descriptor has to be valid for the relation. If it
* is not then a InvalidPermDescriptor exception is thrown.
*/
GRelation permute(const PermDescriptor& desc) const;
/**
* \brief Computes the relation resulting by shifting all the columns in \a r
* \a n possitions to the right.
*
* The first \a n columns of \a r does not appear in the final relation.
*/
GRelation shiftRight(int n) const;
//@}
/// \name Cross product
//@{
/**
* \brief Computes \f$ \mathcal{U}_n \times this\f$.
*/
GRelation timesULeft(int n) const;
/**
* \brief Computes \f$ this \times \mathcal{U}_n \f$.
*/
GRelation timesURight(int n) const;
/**
* \brief Computes \f$ this \times r \f$
*/
GRelation times(const GRelation& r) const;
//@}
/// \name Relational algebra operations
//@{
/**
* \brief Returns: \f$ \mathit{this}\;\bowtie_{j}\; r \f$.
*
* This is, the result of joining the two relations on the \a j right most
* columns of \a this and the \a j left most columns of \a r.
*/
GRelation join(int j,const GRelation& r) const;
/**
* \brief Returns: \f$ \mathit{this}_{\smile_{f}}r \f$.
*
* \todo documentation
*/
GRelation follow(int f,const GRelation& r) const;
/**
* \brief Returns: \f$ \Pi_{p} this \f$.
*
* This is, the projection of \a this on the \a p rightmost columns.
*
* \warning Throws an exception InvalidProjection if \a p is not a valid column
* in the relation.
*/
GRelation project(int p) const;
//@}
/// \name Quantification
//@{
/**
* \brief Returns the relation resulting from existencially quantifying on
* column \a c
*
* \param c a column: \f$ 0 \leq c < \text{arity}(\text{this})\f$
*/
GRelation exists(int c) const;
/**
* \brief Returns the relation resulting from uniquely quantifying on column
* \a c
*
* \param c a column: \f$ 0 \leq c < \text{arity}(\text{this})\f$
*/
GRelation unique(int c) const;
/**
* \brief Returns the relation resulting from uniquely quantifying on all the
* columns in \a c.
*
* \param c a vector of columns: \f$ \forall_{i \in
* \{0,\ldots,\text{size}(c)-1\}}: 0 \leq c[i] <
* \text{arity}(\text{this})\f$
*/
GRelation unique(const std::vector<int>& c) const;
/**
* \brief Returns the relation resulting from universaly quantifying on column
* \a c
*
* \param c a column: \f$ 0 \leq c < \text{arity}(\text{this})\f$
*/
GRelation forall(int c) const;
//@}
/**
* \brief Computes the relation resulting by shifting all the columns in \a r
* \a n possitions to the left.
*
* The new columns in the resulting relation are existentially quantified.
*/
//GRelation shiftLeft(int n) const;
/// Returns the relation \f$ this \times r \f$
//@}
/// \name Test operations
//@{
/// Tests \f$ this \subseteq r \f$
bool subsetEq(const GRelation& r) const;
/// Tests \f$ this \supset r \f$
bool superset(const GRelation& r) const;
/// Tests \f$ this \cap r = \emptyset \f$
bool disjoint(const GRelation& r) const;
/// Tests whether this represents the same relation as \a r
bool eq(const GRelation& r) const;
/// Tests whther the relation is empty
bool empty(void) const;
/// Tests whther the relation represents the universe
bool universe(void) const;
//@}
/// \name Relation information
//@{
/// Returns the arity (i.e. number of columns) of the relation
int arity(void) const;
/// Returns the cardinality (i.e. number of tuples) of the relation
double cardinality(void) const;
//@}
/// \name Constant relations
//@{
/// Creates the binary relation \f$ R = \{(x,y) : x = y \} \f$
//static GRelation equalXY(void);
//@}
/// \name Content access
//@{
/**
* \brief Returns one tuple represented by the relation.
*
* The only guarantee on the returned tuple is that it belongs to
* the relation.
*/
Tuple pickOneTuple(void) const;
//@}
/// \name Output
//{@
void print(std::ostream& os) const;
//@}
};
GRelation::GRelation(Impl impl)
: pimpl_(impl) {}
GRelation::GRelation(int a)
: pimpl_(Impl(new RelationImpl(a)))
{}
GRelation::GRelation(const GRelation &r)
: pimpl_(new RelationImpl(*(r.pimpl_))) { }
GRelation& GRelation::operator =(GRelation& right) {
pimpl_.swap(right.pimpl_);
return *this;
}
void GRelation::become(const GRelation& other) {
pimpl_ = Impl(new RelationImpl(*(other.pimpl_)));
}
GRelation::~GRelation(void) {}
GRelation GRelation::create_full(int a) {
RelationImpl full = RelationImpl::create_full(a);
return
GRelation(
Impl(new RelationImpl(full))
);
}
/*
* Modification
*/
void GRelation::add(const Tuple &t) {
pimpl_->add(t);
}
void GRelation::add(const std::vector<Tuple>& s) {
std::for_each(s.begin(), s.end(),
[=](const Tuple& t) { pimpl_->add(t); });
}
void GRelation::unionAssign(const GRelation &r) {
pimpl_->add(*(r.pimpl_));
}
void GRelation::differenceAssign(const GRelation &r) {
pimpl_->remove(*(r.pimpl_));
}
/*
* Set operations
*/
GRelation GRelation::difference(const GRelation &r) const {
return
GRelation(
Impl(new RelationImpl(VarImpl::difference(*pimpl_,*(r.pimpl_))))
);
}
GRelation GRelation::intersect(const GRelation &r) const {
return
GRelation(
Impl(new RelationImpl(VarImpl::intersect(*pimpl_,*(r.pimpl_))))
);
}
GRelation GRelation::Union(const GRelation &r) const {
return
GRelation(
Impl(new RelationImpl(VarImpl::Union(*pimpl_,*(r.pimpl_))))
);
}
GRelation GRelation::complement(void) const {
return
GRelation(
Impl(new RelationImpl(VarImpl::complement(*pimpl_)))
);
}
/*
* Column permutation
*/
GRelation GRelation::permute(const std::vector<std::pair<int,int>>& desc) const {
return
GRelation(
Impl(new RelationImpl(pimpl_->permute(desc)))
);
}
GRelation GRelation::permute(const PermDescriptor& desc) const {
typedef boost::error_info<struct tag_perm_descriptor,std::string>
perm_descriptor;
if (!desc.valid(arity()))
throw InvalidPermDescriptor()
<< errno_code(errno)
<< perm_descriptor("Invalid permutation description used at: GRelation::permute");
return permute(desc.getPerm());
}
GRelation GRelation::shiftRight(int n) const {
return
GRelation(
Impl(new RelationImpl(pimpl_->shiftRight(n)))
);
}
/*
* Cross product
*/
GRelation GRelation::timesULeft(int n) const {
return
GRelation(Impl(new RelationImpl(pimpl_->timesULeft(n))));
}
GRelation GRelation::timesURight(int n) const {
return
GRelation(Impl(new RelationImpl(pimpl_->timesURight(n))));
}
GRelation GRelation::times(const GRelation& r) const {
return join(0,r);
}
/*
* Relational algebra
*/
GRelation GRelation::join(int j,const GRelation& r) const {
typedef boost::error_info<struct tag_invalid_join,std::string>
invalid_join;
if (arity() < j || r.arity() < j)
throw InvalidJoin()
<< errno_code(errno)
<< invalid_join("There are not enough columns for the join");
return
GRelation(
Impl(new RelationImpl(pimpl_->join(j, *(r.pimpl_))))
);
}
GRelation GRelation::follow(int f,const GRelation& right) const {
/// \todo handle arity errors with exceptions
// if (arity() < j || r.arity() < j)
// throw InvalidJoin()
// << errno_code(errno)
// << invalid_join("There are not enough columns for the join");
return
GRelation(
Impl(new RelationImpl(pimpl_->follow(f, *(right.pimpl_))))
);
}
GRelation GRelation::project(int p) const {
typedef boost::error_info<struct tag_projection,std::string>
projection;
if(p <= 0 || p > arity()) {
throw InvalidProjection()
<< errno_code(errno)
<< projection("Invalid columns to project on");
}
return
GRelation(
Impl(new RelationImpl(pimpl_->project(p)))
);
}
/*
* Quantification
*/
GRelation GRelation::exists(int c) const {
return
GRelation(
Impl(new RelationImpl(pimpl_->exists(c)))
);
}
GRelation GRelation::unique(int c) const {
return
GRelation(
Impl(new RelationImpl(pimpl_->unique(c)))
);
}
GRelation GRelation::unique(const std::vector<int>& c) const {
return
GRelation(
Impl(new RelationImpl(pimpl_->unique(c)))
);
}
GRelation GRelation::forall(int c) const {
return
GRelation(
Impl(new RelationImpl(pimpl_->forall(c)))
);
}
/*
* Test operations
*/
bool GRelation::subsetEq(const GRelation& r) const {
return VarImpl::subsetEq(*pimpl_,*r.pimpl_);
}
bool GRelation::superset(const GRelation& r) const {
return VarImpl::superset(*pimpl_,*r.pimpl_);
}
bool GRelation::disjoint(const GRelation& r) const {
return VarImpl::disjoint(*pimpl_,*r.pimpl_);
}
bool GRelation::eq(const GRelation& r) const {
return *pimpl_ == *(r.pimpl_);
}
bool GRelation::empty(void) const {
return pimpl_->empty();
}
bool GRelation::universe(void) const {
return pimpl_->universe();
}
/*
* Relation information
*/
int GRelation::arity(void) const {
return pimpl_->arity();
}
double GRelation::cardinality(void) const {
return pimpl_->cardinality();
}
/*
* Content access
*/
Tuple GRelation::pickOneTuple(void) const {
/// \todo throw an exception
assert(!empty() && "Relation is empty, nothing to return");
return
pimpl_->pickOneTuple();
}
/*
* Relation output
*/
void GRelation::print(std::ostream& os) const {
pimpl_->print(os);
}
std::ostream& operator<< (std::ostream& os, const GRelation& r) {
r.print(os);
return os;
}