Board 0.9.6
examples/Huffman.cpp
#include <Board.h>
#include <map>
#include <vector>
using namespace LibBoard;
struct Node {
std::string symbol;
double probability;
std::string codeword;
Node(const std::string & symbol, double probability, Node * left = nullptr, Node * right = nullptr) //
{
}
{
delete left;
delete right;
}
int height() const
{
int h = 1;
if (left) {
h = 1 + left->height();
}
if (right) {
h = std::max(h, 1 + right->height());
}
return h;
}
};
void extract_probabilities(const Node * tree, std::map<std::string, double> & m)
{
if (!tree) {
return;
}
if (!tree->left && !tree->right) {
m[tree->symbol] = tree->probability;
}
}
void extract_leaves(const Node * tree, std::vector<Node> & n)
{
if (!tree) {
return;
}
extract_leaves(tree->left, n);
extract_leaves(tree->right, n);
if (!tree->right && !tree->left) {
n.push_back(Node{tree->symbol, tree->probability});
}
}
Node * clone(Node * node)
{
if (!node) {
return nullptr;
}
return new Node(node->symbol, node->probability, clone(node->left), clone(node->right));
}
void fill_probabilities(Node * tree, const std::map<std::string, double> & m)
{
if (!tree) {
return;
}
if (!tree->left && !tree->right) {
tree->probability = m.at(tree->symbol);
} else {
}
}
void fill_probabilities(Node * tree, double probability)
{
if (!tree) {
return;
}
if (tree->left && tree->right) {
fill_probabilities(tree->left, probability * 0.5);
fill_probabilities(tree->right, probability * 0.5);
} else {
tree->probability = probability;
}
}
Group LeaveBox(const Node & node)
{
char text[128];
sprintf(text, "%.3g", node.probability);
Group top = boardFontText(Point(), node.symbol, 10, Color::Blue);
Group bottom = boardFontText(Point(), std::string(text), 10, Color::Blue);
Group codeword = boardFontText(Point(), std::string(node.codeword), 5, Color::Black);
top.append(bottom, Direction::Bottom, Alignment::Center, 5);
top.append(codeword, Direction::Bottom, Alignment::Center, 5);
return framed(top, 5.0, Color::Blue, Color::Null, 1.0);
}
bool operator()(const Node * a, const Node * b)
{ //
return (a->probability > b->probability) || //
((a->probability == b->probability) && (a->height() > b->height()));
}
};
Node * HuffmanTree(const std::vector<Node> & nodes)
{
if (nodes.empty()) {
return nullptr;
}
std::priority_queue<Node *, std::vector<Node *>, NodeGreaterThan> nodeQueue;
for (const Node & node : nodes) {
nodeQueue.push(new Node{node.symbol, node.probability});
}
while (nodeQueue.size() != 1) {
Node * left = nodeQueue.top();
nodeQueue.pop();
Node * right = nodeQueue.top();
nodeQueue.pop();
if (nodeQueue.size()) {
if ((nodeQueue.top()->probability == left->probability) || //
(nodeQueue.top()->probability == right->probability)) {
std::cerr << "Warning: Non unique tree because of probability " //
<< nodeQueue.top()->probability << std::endl;
}
}
nodeQueue.push(new Node{"", left->probability + right->probability, left, right});
}
return nodeQueue.top();
}
{
std::map<std::string, double> p;
Node * c = clone(tree);
std::vector<Node> n;
delete c;
Node * result = HuffmanTree(n);
fill_probabilities(result, p);
return result;
}
void fill_codeword(const std::string codeword, Node * tree)
{
if (!tree) {
return;
}
tree->codeword = codeword;
if (tree->left && tree->right) {
fill_codeword(codeword + "0", tree->left);
fill_codeword(codeword + "1", tree->right);
}
}
Group merge(Group left, Group right)
{
const float margin = 5;
Rect bboxLeft = left.boundingBox(LineWidthFlag::IgnoreLineWidth);
Rect bboxRight = right.boundingBox(LineWidthFlag::IgnoreLineWidth);
const double fullWidth = bboxLeft.width + margin + bboxRight.width;
Group g;
left.moveCenter(bboxLeft.width * 0.5, bboxLeft.height * -0.5);
right.moveCenter(bboxLeft.width + margin + 0.5 * bboxRight.width, bboxRight.height * -0.5);
Polyline polyline(
{
Point(bboxLeft.width * 0.5, 0.0), //
Point(fullWidth * 0.5, margin * 3), //
Point(bboxLeft.width + margin + 0.5 * bboxRight.width, 0.0) //
},
Path::Open, Color::Green, Color::Null, 1.0, LineStyle::SolidStyle, LineCap::RoundCap);
g << left << right << polyline;
Group labelLeft = boardFontText(Point(), std::string("0"), 3, Color::Black);
Group box;
box << rectangle(labelLeft.bbox(LineWidthFlag::UseLineWidth).growed(2), Color::Green, Color::White);
box << labelLeft.moveCenter(labelLeft.center());
box.moveCenter(mix(polyline[0], polyline[1], 0.5));
g << box;
Group labelRight = boardFontText(Point(), std::string("1"), 3, Color::Black);
box.clear();
box << rectangle(labelRight.bbox(LineWidthFlag::UseLineWidth).growed(2), Color::Green, Color::White);
box << labelRight.moveCenter(labelRight.center());
box.moveCenter(mix(polyline[1], polyline[2], 0.5));
g << box;
return g;
}
{
if (!node->left && !node->right) {
return LeaveBox(*node);
}
Group left;
left << HuffmanTree(node->left);
Group right;
right << HuffmanTree(node->right);
return merge(left, right);
}
int main(int, char *[])
{
Board board;
Style::setDefaultLineWidth(0.5);
std::vector<Node> nodes = {
{"X", 0.73}, //
{"N", 0.08}, //
{"H", 0.09}, //
{"W", 0.04}, //
{"P", 0.03}, //
{"E", 0.015}, //
{"Z", 0.015} //
};
Node * tree = HuffmanTree(nodes);
Node * c = canonicalized(tree);
fill_codeword(std::string(""), c);
board << HuffmanTree(c);
delete tree;
delete c;
board.saveSVG("Huffman.svg");
// system("display Huffman.svg");
}
Declaration of the Board class.
void extract_leaves(const Node *tree, std::vector< Node > &n)
Definition Huffman.cpp:57
Group LeaveBox(const Node &node)
Definition Huffman.cpp:103
void fill_probabilities(Node *tree, const std::map< std::string, double > &m)
Definition Huffman.cpp:77
Node * canonicalized(Node *tree)
Definition Huffman.cpp:149
void extract_probabilities(const Node *tree, std::map< std::string, double > &m)
Definition Huffman.cpp:45
void fill_codeword(const std::string codeword, Node *tree)
Definition Huffman.cpp:163
Group merge(Group left, Group right)
Definition Huffman.cpp:175
Node * HuffmanTree(const std::vector< Node > &nodes)
Definition Huffman.cpp:123
Node * clone(Node *node)
Definition Huffman.cpp:69
int main(int argc, char *argv[])
Definition arithmetic.cpp:16
Group text()
Definition board_font_text.cpp:17
Definition Board.h:55
Path mix(const Path &a, const Path &b, double time)
Interpolate two paths according to a time (0 is a, 1 is b)
Definition Path.cpp:390
Polyline rectangle(double left, double top, double width, double height, Color penColor=Style::defaultPenColor(), Color fillColor=Style::defaultFillColor(), double lineWidth=Style::defaultLineWidth(), const LineStyle lineStyle=Style::defaultLineStyle(), const LineCap cap=Style::defaultLineCap(), const LineJoin join=Style::defaultLineJoin())
Definition Polyline.cpp:569
Group framed(const Shape &shape, double margin=0.0, const Color &penColor=Style::defaultPenColor(), const Color &fillColor=Style::defaultFillColor(), double lineWidth=Style::defaultLineWidth(), LineStyle lineStyle=Style::defaultLineStyle(), int sketchyCount=0)
Surround a shape with a rectangular frame.
Definition Board.cpp:1081
Group boardFontText(Point baselineStart, const std::string &text, double size, Color penColor=Style::defaultPenColor(), double lineWidth=0.0)
Create a text with board's font.
Definition BoardFontText.cpp:320
Class for EPS, FIG or SVG drawings.
Definition Board.h:61
void saveSVG(const char *filename, PageSize size=PageSize::BoundingBox, double margin=0.0, Unit unit=Unit::Millimeter) const
Definition Board.cpp:765
A group of shapes. A group is basically a ShapeList except that when rendered in either an SVG of a F...
Definition Group.h:40
Rect boundingBox(LineWidthFlag) const override
Definition Group.cpp:212
Struct representing a 2D point.
Definition Point.h:42
A polygonal line described by a series of 2D points.
Definition Polyline.h:38
Struct representing a rectangle on the plane.
Definition Rect.h:40
double height
Definition Rect.h:44
double width
Definition Rect.h:43
Rect growed(double margin)
Return the rectangle growed by a given distance (margin) in each direction.
Definition Rect.cpp:135
ShapeList & append(const Shape &shape, Direction direction=Direction::Right, Alignment alignment=Alignment::Center, double margin=0.0, LineWidthFlag lineWidthFlag=UseLineWidth)
Definition ShapeList.cpp:232
Shape & moveCenter(double x, double y, LineWidthFlag lineWidthFlag=IgnoreLineWidth)
Definition Shape.cpp:64
virtual Point center(LineWidthFlag lineWidthFlag=IgnoreLineWidth) const
Definition Shape.cpp:59
Rect bbox(LineWidthFlag) const
Definition Shape.h:332
Definition Huffman.cpp:115
bool operator()(const Node *a, const Node *b)
Definition Huffman.cpp:116
Definition Huffman.cpp:17
int height() const
Definition Huffman.cpp:32
Node * right
Definition Huffman.cpp:22
double probability
Definition Huffman.cpp:19
~Node()
Definition Huffman.cpp:27
Node * left
Definition Huffman.cpp:21
std::string symbol
Definition Huffman.cpp:18
std::string codeword
Definition Huffman.cpp:20