Skip to content

Commit

Permalink
Support printing tree in 'parents' format
Browse files Browse the repository at this point in the history
  • Loading branch information
ifsmirnov committed Oct 15, 2017
1 parent 7f9bb55 commit fc46219
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 69 deletions.
8 changes: 5 additions & 3 deletions doc/printers.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ Note that Jngen does not interact with stl-defined operators. That mean that wri
* Action: print number of edges of a graph.
* Default: unset.
#### printEdges(bool value = true)
* Action: when printing a tree, print a list of edges. Opposite to *printParents*.
* Action: when printing a tree, print a list of edges.
* Default: set.
#### printParents(bool value = true)
#### printParents(int value = -1)
* Action: when printing a tree, print a parent of each vertex. Opposite to *printEdges*.
* Default: unset.
* Arguments: *value* stands for the root of the tree. If *value* is *0* or greater, then the parent of each vertex is printed, having root's parent as
*-1* (*0* if *add1()* is present). *value = -1* is a special value: in this case tree is rooted at *0* and its parent is not printed (printing *n-1* values in total).
* Note: this option and *printEdges* cancel each other.
#### endl(bool value = true)
* Action: separate elements of the array with line breaks instead of spaces.
* Default: unset.
2 changes: 1 addition & 1 deletion doc/tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Note that all generators return trees with sorted edges to make tests more human
* randomly swap egdes' endpoints.

#### Array parents(int root) const
* Returns: array of size *n*, where *i*-th element is a parent of vertex *i* if the tree is rooted at *root*. Parent of *root* is *root* itself.
* Returns: array of size *n*, where *i*-th element is a parent of vertex *i* if the tree is rooted at *root*. Parent of *root* is *-1*.

#### Tree link(int vInThis, const Tree& other, int vInOther)
* Returns: a tree made of _*this_ and *other*, with an extra edge between two vertices with ids *vInThis* and *vInOther*, respectively.
Expand Down
6 changes: 4 additions & 2 deletions generic_graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class GenericGraph {
virtual void addEdge(int u, int v, const Weight& w = Weight{});
virtual bool isConnected() const { return dsu_.isConnected(); }

virtual int vertexLabel(int v) const { return vertexLabel_[v]; }
virtual int vertexByLabel(int v) const { return vertexByLabel_[v]; }
virtual int vertexLabel(int v) const { return vertexLabel_.at(v); }
virtual int vertexByLabel(int v) const { return vertexByLabel_.at(v); }

// v: label
// return: array<label>
Expand Down Expand Up @@ -60,6 +60,8 @@ class GenericGraph {
virtual bool operator>=(const GenericGraph& other) const;

protected:
static WeightArray prepareWeightArray(WeightArray a, int requiredSize);

void doShuffle();

void extend(size_t size);
Expand Down
32 changes: 14 additions & 18 deletions impl/generic_graph_inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ Arrayp GenericGraph::edges() const {
return edges;
}

WeightArray GenericGraph::prepareWeightArray(WeightArray a, int requiredSize) {
ENSURE(a.hasNonEmpty(), "Attempt to print empty weight array");

a.extend(requiredSize);
int type = a.anyType();
for (auto& x: a) {
if (x.empty()) {
x.setType(type);
}
}

return a;
}

void GenericGraph::doShuffle() {
// this if is to be removed after all checks pass
if (vertexLabel_.size() < static_cast<size_t>(n())) {
Expand Down Expand Up @@ -173,24 +187,6 @@ void GenericGraph::addEdge(int u, int v, const Weight& w) {
}
}

namespace {

WeightArray prepareWeightArray(WeightArray a, int requiredSize) {
ENSURE(a.hasNonEmpty(), "Attempt to print empty weight array");

a.extend(requiredSize);
int type = a.anyType();
for (auto& x: a) {
if (x.empty()) {
x.setType(type);
}
}

return a;
}

} // namespace

void GenericGraph::doPrintEdges(
std::ostream& out, const OutputModifier& mod) const
{
Expand Down
53 changes: 51 additions & 2 deletions impl/tree_inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Array Tree::parents(int root) const {
root = vertexByLabel(root);

Array parents(n());
parents[root] = root;
parents[root] = -1;
std::vector<int> used(n());
std::vector<int> queue{root};
for (size_t i = 0; i < queue.size(); ++i) {
Expand All @@ -45,7 +45,9 @@ Array Tree::parents(int root) const {
}

for (auto& x: parents) {
x = vertexLabel(x);
if (x != -1) {
x = vertexLabel(x);
}
}

return parents;
Expand Down Expand Up @@ -218,3 +220,50 @@ Tree Tree::kary(int size, int k) {
return t;
}

void Tree::doPrintParents(std::ostream& out, const OutputModifier& mod) const {
int root = mod.printParents;
if (root == -1) {
root = 0;
}

auto parents = this->parents(root);
if (mod.printParents == -1) {
parents.erase(parents.begin());
}

if (mod.printN) {
out << n() << "\n";
}

// TODO: avoid copy-paste from doPrintEdges
if (mod.printWeights && vertexWeights_.hasNonEmpty()) {
auto vertexWeights = prepareWeightArray(vertexWeights_, n());
for (int i = 0; i < n(); ++i) {
if (i > 0) {
out << " ";
}
JNGEN_PRINT_NO_MOD(vertexWeights[vertexByLabel(i)]);
}
out << "\n";
}

auto t(mod);
{
auto mod(t);
mod.printN = false;

if (mod.printWeights && edgeWeights_.hasNonEmpty()) {
ensure(false, "Printing parents and edge weights is not supported");
ensure(
mod.printParents == -1,
"Root must not be set to any exact value when printing a tree "
"with edge weights. To fix it, either set printParents() "
"or printWeights(false)");
ENSURE(root == 0);
// TODO: some code to be here
} else {
JNGEN_PRINT(parents);
}
}
}

124 changes: 92 additions & 32 deletions jngen.h
Original file line number Diff line number Diff line change
Expand Up @@ -2388,8 +2388,9 @@ struct OutputModifier {
bool printN = false;
bool printM = false;

bool printParents = false;
int printParents;
bool printEdges = true;
bool printWeights = true;

char sep = ' ';
};
Expand Down Expand Up @@ -2437,15 +2438,22 @@ class Repr {
return *this;
}

Repr<T>& printParents(bool value = true) {
Repr<T>& printParents(int value = -1) {
mod_.printParents = value;
mod_.printEdges = !value;
mod_.printEdges = false;
return *this;
}

Repr<T>& printEdges(bool value = true) {
mod_.printEdges = value;
mod_.printParents = !value;
if (!value) {
mod_.printParents = -1;
}
return *this;
}

Repr<T>& printWeights(bool value = true) {
mod_.printWeights = value;
return *this;
}

Expand Down Expand Up @@ -2493,7 +2501,7 @@ class ReprProxy : public BaseReprProxy {
return repr;
}

Repr<T> printParents(bool value = true) {
Repr<T> printParents(int value = -1) {
Repr<T> repr(static_cast<const T&>(*this));
repr.printParents(value);
return repr;
Expand All @@ -2505,6 +2513,12 @@ class ReprProxy : public BaseReprProxy {
return repr;
}

Repr<T> printWeights(bool value = true) {
Repr<T> repr(static_cast<const T&>(*this));
repr.printWeights(value);
return repr;
}

Repr<T> endl(bool value = true) {
Repr<T> repr(static_cast<const T&>(*this));
repr.endl(value);
Expand Down Expand Up @@ -5219,8 +5233,8 @@ class GenericGraph {
virtual void addEdge(int u, int v, const Weight& w = Weight{});
virtual bool isConnected() const { return dsu_.isConnected(); }

virtual int vertexLabel(int v) const { return vertexLabel_[v]; }
virtual int vertexByLabel(int v) const { return vertexByLabel_[v]; }
virtual int vertexLabel(int v) const { return vertexLabel_.at(v); }
virtual int vertexByLabel(int v) const { return vertexByLabel_.at(v); }

// v: label
// return: array<label>
Expand Down Expand Up @@ -5254,6 +5268,8 @@ class GenericGraph {
virtual bool operator>=(const GenericGraph& other) const;

protected:
static WeightArray prepareWeightArray(WeightArray a, int requiredSize);

void doShuffle();

void extend(size_t size);
Expand Down Expand Up @@ -5388,6 +5404,20 @@ Arrayp GenericGraph::edges() const {
return edges;
}

WeightArray GenericGraph::prepareWeightArray(WeightArray a, int requiredSize) {
ENSURE(a.hasNonEmpty(), "Attempt to print empty weight array");

a.extend(requiredSize);
int type = a.anyType();
for (auto& x: a) {
if (x.empty()) {
x.setType(type);
}
}

return a;
}

void GenericGraph::doShuffle() {
// this if is to be removed after all checks pass
if (vertexLabel_.size() < static_cast<size_t>(n())) {
Expand Down Expand Up @@ -5486,24 +5516,6 @@ void GenericGraph::addEdge(int u, int v, const Weight& w) {
}
}

namespace {

WeightArray prepareWeightArray(WeightArray a, int requiredSize) {
ENSURE(a.hasNonEmpty(), "Attempt to print empty weight array");

a.extend(requiredSize);
int type = a.anyType();
for (auto& x: a) {
if (x.empty()) {
x.setType(type);
}
}

return a;
}

} // namespace

void GenericGraph::doPrintEdges(
std::ostream& out, const OutputModifier& mod) const
{
Expand Down Expand Up @@ -5649,18 +5661,17 @@ class Tree : public ReprProxy<Tree>, public GenericGraph {
static Tree caterpillar(int size, int length);
static Tree binary(int size);
static Tree kary(int size, int k);

void doPrintParents(std::ostream& out, const OutputModifier& mod) const;
};

JNGEN_DECLARE_SIMPLE_PRINTER(Tree, 2) {
ensure(t.isConnected(), "Cannot print a tree: it is not connected");

if (mod.printParents) {
ensure(false, "Printing parents is not implemented");
} else if (mod.printEdges) {
if (mod.printEdges) {
t.doPrintEdges(out, mod);
} else {
ensure(false, "Print mode is not set, select one of 'printParents'"
" or 'printEdges'");
t.doPrintParents(out, mod);
}
}

Expand Down Expand Up @@ -5710,7 +5721,7 @@ Array Tree::parents(int root) const {
root = vertexByLabel(root);

Array parents(n());
parents[root] = root;
parents[root] = -1;
std::vector<int> used(n());
std::vector<int> queue{root};
for (size_t i = 0; i < queue.size(); ++i) {
Expand All @@ -5725,7 +5736,9 @@ Array Tree::parents(int root) const {
}

for (auto& x: parents) {
x = vertexLabel(x);
if (x != -1) {
x = vertexLabel(x);
}
}

return parents;
Expand Down Expand Up @@ -5898,6 +5911,53 @@ Tree Tree::kary(int size, int k) {
return t;
}

void Tree::doPrintParents(std::ostream& out, const OutputModifier& mod) const {
int root = mod.printParents;
if (root == -1) {
root = 0;
}

auto parents = this->parents(root);
if (mod.printParents == -1) {
parents.erase(parents.begin());
}

if (mod.printN) {
out << n() << "\n";
}

// TODO: avoid copy-paste from doPrintEdges
if (mod.printWeights && vertexWeights_.hasNonEmpty()) {
auto vertexWeights = prepareWeightArray(vertexWeights_, n());
for (int i = 0; i < n(); ++i) {
if (i > 0) {
out << " ";
}
JNGEN_PRINT_NO_MOD(vertexWeights[vertexByLabel(i)]);
}
out << "\n";
}

auto t(mod);
{
auto mod(t);
mod.printN = false;

if (mod.printWeights && edgeWeights_.hasNonEmpty()) {
ensure(false, "Printing parents and edge weights is not supported");
ensure(
mod.printParents == -1,
"Root must not be set to any exact value when printing a tree "
"with edge weights. To fix it, either set printParents() "
"or printWeights(false)");
ENSURE(root == 0);
// TODO: some code to be here
} else {
JNGEN_PRINT(parents);
}
}
}

#undef JNGEN_INCLUDE_TREE_INL_H
#endif // JNGEN_DECLARE_ONLY

Expand Down
Loading

0 comments on commit fc46219

Please sign in to comment.