Huffman encoding implemented

This commit is contained in:
Dennis Eichhorn 2016-05-06 19:17:55 +02:00
parent ce182bab92
commit 121f030064
3 changed files with 388 additions and 6 deletions

View File

@ -1,6 +0,0 @@
<?php
final class Huffman
{
}

View File

@ -0,0 +1,229 @@
<?php
/**
* Orange Management
*
* PHP Version 7.0
*
* @category TBD
* @package TBD
* @author OMS Development Team <dev@oms.com>
* @author Dennis Eichhorn <d.eichhorn@oms.com>
* @copyright 2013 Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link http://orange-management.com
*/
namespace phpOMS\Utils\Encoding\Huffman;
/**
* Gray encoding class
*
* @category Framework
* @package phpOMS\Utils
* @author OMS Development Team <dev@oms.com>
* @author Dennis Eichhorn <d.eichhorn@oms.com>
* @license OMS License 1.0
* @link http://orange-management.com
* @since 1.0.0
*/
final class Dictionary
{
/**
* Huffman dictionary.
*
* @var array
* @since 1.0.0
*/
private $dictionary = [];
/**
* Minimum length.
*
* @var int
* @since 1.0.0
*/
private $min = -1;
/**
* Maximum length.
*
* @var int
* @since 1.0.0
*/
private $max = -1;
/**
* Constructor.
*
* @param string $source Source to create the dictionary from
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function __construct(string $source = '')
{
if (isset($source)) {
$this->generate($source);
}
}
/**
* Get dictionary value by entry
*
* @param string $entry 1 character entry
*
* @return string
*
* @throws
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function get(string $entry) : string
{
if (strlen($entry) !== 1) {
throw new \Exception('Must be a character.');
}
if (!isset($this->dictionary[$entry])) {
throw new \Exception('Character does not exist');
}
return $this->dictionary[$entry];
}
/**
* Get dictionary entry and reduce value
*
* @param string $value Dictionary value
*
* @return null|string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getEntry(&$value)
{
$length = strlen($value);
if ($length < $this->min) {
return null;
}
for ($i = $this->min; $i <= $this->max; ++$i) {
$needle = substr($value, 0, $i);
foreach ($this->dictionary as $key => $val) {
if ($needle === $val) {
$value = substr($value, $i);
return $key;
}
}
}
return null;
}
/**
* Set dictionary value
*
* @param string $entry 1 character entry
* @param string $value Dictionary value
*
* @return void
*
* @throws
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function set(string $entry, string $value)
{
if (strlen($entry) !== 1) {
throw new \Exception('Must be a character.');
}
if (!isset($this->dictionary[$entry])) {
throw new \Exception('Character does not exist');
}
if (strlen(str_replace('0', '', str_replace('1', '', $value))) !== 0) {
throw new \Exception('Bad formatting.');
}
$length = strlen($value);
if ($this->min === -1 || $length < $this->min) {
$this->min = $length;
}
if ($this->max === -1 || $length > $this->max) {
$this->max = $length;
}
$this->dictionary[$entry] = $value;
}
/**
* Generate dictionary from data.
*
* @param string $source Source data to generate dictionary from
*
* @return void
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function generate(string $source)
{
$this->dictionary = [];
$this->min = -1;
$this->max = -1;
$count = [];
while (isset($source[0])) {
$count[] = [substr_count($source, $source[0]), $source[0]];
$source = str_replace($source[0], '', $source);
}
sort($count);
while (count($count) > 1) {
$row1 = array_shift($count);
$row2 = array_shift($count);
$count[] = [$row1[0] + $row2[0], [$row1, $row2]];
sort($count);
}
$this->fill(is_array($count[0][1]) ? $count[0][1] : $count);
}
/**
* Fill dictionary.
*
* @param string $entry Source data to generate dictionary from
* @param string $value Dictionary value
*
* @return void
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
private function fill(string $entry, string $value = '')
{
if (!is_array($entry[0][1])) {
$this->set($entry[0][1], $value . '0');
} else {
$this->fill($entry[0][1], $value . '0');
}
if (isset($entry[1])) {
if (!is_array($entry[1][1])) {
$this->set($entry[1][1], $value . '1');
} else {
$this->fill($entry[1][1], $value . '1');
}
}
}
}

View File

@ -0,0 +1,159 @@
<?php
/**
* Orange Management
*
* PHP Version 7.0
*
* @category TBD
* @package TBD
* @author OMS Development Team <dev@oms.com>
* @author Dennis Eichhorn <d.eichhorn@oms.com>
* @copyright 2013 Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link http://orange-management.com
*/
namespace phpOMS\Utils\Encoding\Huffman;
/**
* Gray encoding class
*
* @category Framework
* @package phpOMS\Utils
* @author OMS Development Team <dev@oms.com>
* @author Dennis Eichhorn <d.eichhorn@oms.com>
* @license OMS License 1.0
* @link http://orange-management.com
* @since 1.0.0
*/
final class Huffman
{
/**
* Huffman dictionary.
*
* @var Dictionary
* @since 1.0.0
*/
private $dictionary = null;
/**
* Set dictionary
*
* @param Dictionary $dictionary Huffman dictionary
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function setDictionary(Dictionary $dictionary)
{
$this->dictionary = $dictionary;
}
/**
* Remove dictionary
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function removeDictionary()
{
$this->dictionary = null;
}
/**
* Get dictionary
*
* @return Dictionary
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getDictionary() : Dictionary
{
return $this->dictionary;
}
/**
* Encode.
*
* @param string $source Source to encode
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function encode(string $source) : string
{
if (empty($source)) {
return '';
}
if (!isset($this->dictionary)) {
$this->dictionary = new Dictionary($source);
}
$binary = '';
for ($i = 0; isset($source[$i]); ++$i) {
$binary .= $this->dictionary->get($source[$i]);
}
$splittedBinaryString = str_split('1' . $binary . '1', 8);
$binary = '';
foreach ($splittedBinaryString as $i => $c) {
while (strlen($c) < 8) {
$c .= '0';
}
$binary .= chr(bindec($c));
}
return $binary;
}
/**
* Decode.
*
* @param string $raw Raw to decode
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function decode(string $raw) : string
{
if (empty($raw)) {
return '';
}
$binary = '';
$rawLenght = strlen($raw);
$source = '';
for ($i = 0; $i < $rawLenght; ++$i) {
$decbin = decbin(ord($raw[$i]));
while (strlen($decbin) < 8) {
$decbin = '0' . $decbin;
}
if ($i === 0) {
$decbin = substr($decbin, strpos($decbin, '1') + 1);
}
if ($i + 1 === $rawLenght) {
$decbin = substr($decbin, 0, strrpos($decbin, '1'));
}
$binary .= $decbin;
while (($entry = $this->dictionary->getEntry($binary)) !== null) {
$source .= $entry;
}
}
return $source;
}
}