Skip to content
This repository has been archived by the owner on Jul 8, 2023. It is now read-only.

Commit

Permalink
Implemented PHP-LCS.
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzatron committed Aug 15, 2012
1 parent ff2b012 commit 3d8ff57
Show file tree
Hide file tree
Showing 12 changed files with 447 additions and 3 deletions.
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.gitattributes export-ignore
.gitignore export-ignore
.travis.yml export-ignore
phpunit.xml export-ignore
phpunit.reports.xml export-ignore
test export-ignore
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test/report
vendor
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
language: php
before_script:
- composer install --dev
script: phpunit
php:
- 5.3.3
- 5.3
- 5.4
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright © 2012 Erin Millard

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
76 changes: 73 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,74 @@
php-lcs
=======
# PHP-LCS

Longest common subsequence implementation in PHP
*An implementation of the 'longest common subsequence' algorithm for PHP.*

## What is PHP-LCS?

PHP-LCS is a PHP implementation of an algorithm to solve the 'longest common
subsequence' problem.

From [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem):

> The **longest common subsequence (LCS) problem** is to find the longest
> [subsequence](http://en.wikipedia.org/wiki/Subsequence) common to all
> sequences in a set of sequences (often just two). Note that subsequence is
> different from a substring, see
> [substring vs. subsequence](http://en.wikipedia.org/wiki/Subsequence#Substring_vs._subsequence).
> It is a classic [computer science](http://en.wikipedia.org/wiki/Computer_science)
> problem, the basis of [file comparison](http://en.wikipedia.org/wiki/File_comparison)
> programs such as [diff](http://en.wikipedia.org/wiki/Diff), and has
> applications in [bioinformatics](http://en.wikipedia.org/wiki/Bioinformatics).
## Usage

```php
<?php
use Ezzatron\LCS\LCSSolver;

$solver = new LCSSolver;

$left = array(
'B',
'A',
'N',
'A',
'N',
'A',
);
$right = array(
'A',
'T',
'A',
'N',
'A',
);
$expectedLCS = array(
'A',
'A',
'N',
'A',
);

$LCS = $solver->longestCommonSubsequence(
$left,
$right
);

if ($LCS === $expectedLCS) {
echo 'LCS solver is working.';
} else {
echo 'LCS solver is not working.';
}
// the above outputs 'LCS solver is working.'
```

## Code quality

PHP-LCS strives to attain a high level of quality. A full test suite is
available, and code coverage is closely monitored.

### Latest revision test suite results
[![Build Status](https://secure.travis-ci.org/ezzatron/php-lcs.png)](http://travis-ci.org/ezzatron/php-lcs)

### Latest revision test suite coverage
<http://ci.ezzatron.com/report/php-lcs/coverage/>
22 changes: 22 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "ezzatron/php-lcs",
"description": "An implementation of the 'longest common subsequence' algorithm for PHP.",
"keywords": ["longest","common","subsequence","sequence","diff","algorithm"],
"homepage": "https://github.com/ezzatron/php-lcs",
"license": "MIT",
"authors": [
{
"name": "Erin Millard",
"email": "[email protected]",
"homepage": "http://ezzatron.com/"
}
],
"require": {
"php": ">=5"
},
"autoload": {
"psr-0": {
"Ezzatron\\LCS": "src"
}
}
}
16 changes: 16 additions & 0 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions phpunit.reports.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="test/bootstrap.php"
strict="true"
mapTestClassNameToCoveredClassName="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
verbose="true"
colors="true"
>
<testsuites>
<testsuite>
<directory>test/suite</directory>
</testsuite>
</testsuites>

<logging>
<log
type="coverage-clover"
target="test/report/coverage.xml"
/>

<log
type="coverage-html"
target="test/report/coverage"
charset="UTF-8"
yui="true"
highlight="true"
/>

<log
type="json"
target="test/report/logfile.json"
/>

<log
type="tap"
target="test/report/logfile.tap"
/>

<log
type="junit"
target="test/report/logfile.xml"
logIncompleteSkipped="false"
/>

<log
type="testdox-html"
target="test/report/testdox.html"
/>

<log
type="testdox-text"
target="test/report/testdox.txt"
/>
</logging>

<filter>
<whitelist>
<directory>src</directory>
</whitelist>
</filter>
</phpunit>
17 changes: 17 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="test/bootstrap.php"
strict="true"
mapTestClassNameToCoveredClassName="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
verbose="true"
colors="true"
>
<testsuites>
<testsuite>
<directory>test/suite</directory>
</testsuite>
</testsuites>
</phpunit>
112 changes: 112 additions & 0 deletions src/Ezzatron/LCS/LCSSolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

/*
* This file is part of the PHP-LCS package.
*
* Copyright © 2012 Erin Millard
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Ezzatron\LCS;

class LCSSolver
{
/**
* Returns the longest common subsequence of the given arrays.
*
* See http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
*
* @param array $left The first array.
* @param array $right The second array.
* @param array $additional,... Any number of additional arrays.
*
* @return array The longest common subsequence.
*/
public function longestCommonSubsequence(array $left, array $right)
{
if (func_num_args() > 2) {
$arguments = func_get_args();
array_splice(
$arguments,
0,
2,
array(
$this->longestCommonSubsequence($left, $right)
)
);

return call_user_func_array(
array($this, 'longestCommonSubsequence'),
$arguments
);
}

$m = count($left);
$n = count($right);

// $a[$i][$j] = length of LCS of $left[$i..$m] and $right[$j..$n]
$a = array();

// compute length of LCS and all subproblems via dynamic programming
for ($i = $m - 1; $i >= 0; $i--) {
for ($j = $n - 1; $j >= 0; $j--) {
if ($left[$i] === $right[$j]) {
$a[$i][$j] =
(
isset($a[$i + 1][$j + 1]) ?
$a[$i + 1][$j + 1] :
0
) +
1
;
} else {
$a[$i][$j] = max(
(
isset($a[$i + 1][$j]) ?
$a[$i + 1][$j] :
0
),
(
isset($a[$i][$j + 1]) ?
$a[$i][$j + 1] :
0
)
);
}
}
}

// recover LCS itself
$i = 0;
$j = 0;
$lcs = array();

while($i < $m && $j < $n) {
if ($left[$i] === $right[$j]) {
$lcs[] = $left[$i];

$i++;
$j++;
} elseif (
(
isset($a[$i + 1][$j]) ?
$a[$i + 1][$j] :
0
) >=
(
isset($a[$i][$j + 1]) ?
$a[$i][$j + 1] :
0
)
) {
$i++;
} else {
$j++;
}
}

return $lcs;
}
}
3 changes: 3 additions & 0 deletions test/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

require __DIR__.'/../vendor/autoload.php';
Loading

0 comments on commit 3d8ff57

Please sign in to comment.