2 //**************************************************************************
3 //* This file is property of and copyright by the ALICE HLT Project *
4 //* ALICE Experiment at CERN, All rights reserved. *
6 //* Primary Authors: Thorsten Kollegger <kollegge@ikf.uni-frankfurt.de> *
7 //* for The ALICE HLT Project. *
9 //* Permission to use, copy, modify and distribute this software and its *
10 //* documentation strictly for non-commercial purposes is hereby granted *
11 //* without fee, provided that the above copyright notice appears in all *
12 //* copies and that both the copyright notice and this permission notice *
13 //* appear in the supporting documentation. The authors make no claims *
14 //* about the suitability of this software for any purpose. It is *
15 //* provided "as is" without express or implied warranty. *
16 //**************************************************************************
18 /// @file AliHLTHuffman.cxx
19 /// @author Thorsten Kollegger, Matthias Richter
21 /// @brief Huffman code generator/encoder/decoder
23 #include "AliHLTHuffman.h"
30 AliHLTHuffmanNode::AliHLTHuffmanNode()
38 AliHLTHuffmanNode::AliHLTHuffmanNode(const AliHLTHuffmanNode& other)
40 , fValue(other.GetValue())
41 , fWeight(other.GetWeight())
45 AliHLTHuffmanNode& AliHLTHuffmanNode::operator =(const AliHLTHuffmanNode& other) {
46 /// assignment operator
47 this->fValue = other.fValue;
48 this->fWeight = other.fWeight;
52 AliHLTHuffmanNode::~AliHLTHuffmanNode() {
55 void AliHLTHuffmanNode::AssignCode() {
56 /// assign code to this node loop to right and left nodes
58 // shift current bit pattern to left and add one
59 std::bitset < 64 > v = (this->GetBinaryCode() << 1);
61 GetLeftChild()->SetBinaryCode(this->GetBinaryCodeLength() + 1, v);
62 GetLeftChild()->AssignCode();
64 if (GetRightChild()) {
65 std::bitset < 64 > v = (this->GetBinaryCode() << 1);
67 GetRightChild()->SetBinaryCode(this->GetBinaryCodeLength() + 1, v);
68 GetRightChild()->AssignCode();
72 void AliHLTHuffmanNode::Print(Option_t* /*option*/) const {
74 std::cout << "value=" << GetValue() << ", weight=" << GetWeight() << ", length="
75 << GetBinaryCodeLength() << ", code=" << GetBinaryCode().to_string()
78 GetLeftChild()->Print();
80 if (GetRightChild()) {
81 GetRightChild()->Print();
85 ClassImp(AliHLTHuffmanNode)
87 ///////////////////////////////////////////////////////////////////////////////////////////////
89 AliHLTHuffmanTreeNode::AliHLTHuffmanTreeNode()
91 , fBinaryCodeLength(0)
99 AliHLTHuffmanTreeNode::AliHLTHuffmanTreeNode(const AliHLTHuffmanTreeNode& other)
100 : AliHLTHuffmanNode()
101 , fBinaryCodeLength(other.fBinaryCodeLength)
102 , fBinaryCode(other.fBinaryCode)
103 , fLeft(other.GetLeftChild())
104 , fRight(other.GetRightChild())
109 AliHLTHuffmanTreeNode& AliHLTHuffmanTreeNode::operator =(const AliHLTHuffmanTreeNode& other)
111 /// assignment operator
112 if (&other==this) return *this;
113 this->fBinaryCodeLength = other.GetBinaryCodeLength();
114 this->fBinaryCode = other.GetBinaryCode();
115 this->fLeft = other.GetLeftChild();
116 this->fRight = other.GetRightChild();
117 AliHLTHuffmanNode::operator=(other);
121 AliHLTHuffmanTreeNode::AliHLTHuffmanTreeNode(AliHLTHuffmanNode* l, AliHLTHuffmanNode* r)
122 : AliHLTHuffmanNode()
123 , fBinaryCodeLength(0)
128 SetWeight(l->GetWeight() + r->GetWeight());
129 } else if (l && !r) {
130 SetWeight(l->GetWeight());
131 } else if (!l && r) {
132 SetWeight(r->GetWeight());
136 AliHLTHuffmanTreeNode::~AliHLTHuffmanTreeNode()
141 ClassImp(AliHLTHuffmanTreeNode)
143 ///////////////////////////////////////////////////////////////////////////////////////////////
145 AliHLTHuffmanLeaveNode::AliHLTHuffmanLeaveNode()
146 : AliHLTHuffmanNode()
147 , fBinaryCodeLength(0)
155 AliHLTHuffmanLeaveNode::AliHLTHuffmanLeaveNode(const AliHLTHuffmanLeaveNode& other)
156 : AliHLTHuffmanNode()
157 , fBinaryCodeLength(other.fBinaryCodeLength)
158 , fBinaryCode(other.fBinaryCode)
159 , fLeft(other.GetLeftChild())
160 , fRight(other.GetRightChild())
165 AliHLTHuffmanLeaveNode& AliHLTHuffmanLeaveNode::operator =(const AliHLTHuffmanLeaveNode& other)
167 /// assignment operator
168 if (&other==this) return *this;
169 this->fBinaryCodeLength = other.GetBinaryCodeLength();
170 this->fBinaryCode = other.GetBinaryCode();
171 this->fLeft = other.GetLeftChild();
172 this->fRight = other.GetRightChild();
173 AliHLTHuffmanNode::operator=(other);
177 AliHLTHuffmanLeaveNode::~AliHLTHuffmanLeaveNode()
182 ClassImp(AliHLTHuffmanLeaveNode)
184 ///////////////////////////////////////////////////////////////////////////////////////////////
186 AliHLTHuffman::AliHLTHuffman()
196 AliHLTHuffman::AliHLTHuffman(const AliHLTHuffman& other)
199 , fMaxBits(other.fMaxBits)
200 , fMaxValue(other.fMaxValue)
201 , fNodes(other.fNodes)
202 , fHuffTopNode(NULL) {
206 AliHLTHuffman::AliHLTHuffman(const char* name, UInt_t maxBits)
209 , fMaxValue((((AliHLTUInt64_t) 1) << maxBits) - 1)
210 , fNodes((((AliHLTUInt64_t) 1) << maxBits))
213 /// standard constructor
214 for (AliHLTUInt64_t i = 0; i <= fMaxValue; i++) {
215 fNodes[i].SetValue(i);
219 AliHLTHuffman::~AliHLTHuffman() {
223 const std::bitset<64>& AliHLTHuffman::Encode(const AliHLTUInt64_t v, AliHLTUInt64_t& codeLength) const {
226 if (v <= fMaxValue) {
227 // valid symbol/value
229 // huffman code has been generated
230 codeLength = fNodes[v].GetBinaryCodeLength();
231 return fNodes[v].GetBinaryCode();
233 HLTError("encoder '%s' does not seem to be initialized", GetName());
236 HLTError("encoder %s: value %llu exceeds range of %d bits", GetName(), v, GetMaxBits());
239 static const std::bitset<64> dummy;
243 Bool_t AliHLTHuffman::Decode(std::bitset<64> bits, AliHLTUInt64_t& value) const {
244 // TODO: check decoding logic, righ now it is just as written
245 AliHLTHuffmanNode* currNode = fHuffTopNode;
246 if (currNode->GetValue() >= 0) {
247 // handle case with just one node - also quite unlikely
248 value = currNode->GetValue();
252 if (bits[0] && currNode->GetLeftChild()) {
253 // follow left branch
254 currNode = currNode->GetLeftChild();
256 if (currNode->GetValue() >= 0) {
257 value = currNode->GetValue();
261 if (!bits[0] && currNode->GetRightChild()) {
262 currNode = currNode->GetRightChild();
264 if (currNode->GetValue() >= 0) {
265 value = currNode->GetValue();
270 value = ((AliHLTUInt64_t)1) << 63;
274 Bool_t AliHLTHuffman::AddTrainingValue(const AliHLTUInt64_t value,
275 const float_t weight) {
276 if (value > fMaxValue) {
277 /* TODO: ERROR message */
280 fNodes[value].AddWeight(weight);
284 Bool_t AliHLTHuffman::GenerateHuffmanTree() {
285 // insert pointer to nodes into ordered structure to build tree
286 std::multiset<AliHLTHuffmanNode*, AliHLTHuffmanNode::less> nodeCollection;
287 // std::copy(fNodes.begin(), fNodes.end(),
288 // std::inserter(freq_coll, freq_coll.begin()));
289 for (std::vector<AliHLTHuffmanLeaveNode>::iterator i = fNodes.begin(); i
290 != fNodes.end(); ++i) {
291 nodeCollection.insert(&(*i));
293 while (nodeCollection.size() > 1) {
294 // insert new node into structure, combining the two with lowest probability
295 nodeCollection.insert(
296 new AliHLTHuffmanTreeNode(*nodeCollection.begin(),
297 *++nodeCollection.begin()));
298 nodeCollection.erase(nodeCollection.begin());
299 nodeCollection.erase(nodeCollection.begin());
302 fHuffTopNode = *nodeCollection.begin();
303 fHuffTopNode->AssignCode();
307 void AliHLTHuffman::Print(Option_t* option) const {
308 std::cout << GetName() << endl;
309 bool bPrintShort=strcmp(option, "short")==0;
310 if (fHuffTopNode && !bPrintShort) {
311 std::cout << "Huffman tree:" << endl;
312 fHuffTopNode->Print();
314 Double_t uncompressedSize = 0;
315 Double_t compressedSize = 0;
316 Double_t totalWeight = 0;
318 std::cout << std::endl << "Huffman codes:" << std::endl;
319 for (AliHLTUInt64_t i = 0; i <= fMaxValue; i++) {
320 if (!bPrintShort) fNodes[i].Print();
321 totalWeight += fNodes[i].GetWeight();
322 uncompressedSize += fNodes[i].GetWeight() * fMaxBits;
323 compressedSize += fNodes[i].GetWeight()
324 * fNodes[i].GetBinaryCodeLength();
326 if (uncompressedSize > 0) {
327 std::cout << "compression ratio: " << compressedSize
328 / uncompressedSize << std::endl;
329 std::cout << "<bits> uncompressed: " << uncompressedSize / totalWeight
331 std::cout << "<bits> compressed: " << compressedSize / totalWeight
336 AliHLTHuffman& AliHLTHuffman::operator =(const AliHLTHuffman& other) {
337 fMaxValue = other.fMaxValue;
338 fNodes = other.fNodes;
343 ClassImp(AliHLTHuffman)