foortec / php-vector-similarity
A lightweight PHP library for comparing sparse vectors and finding similar vectorized objects.
Requires
- php: ^8.3
Requires (Dev)
- phpunit/phpunit: ^12.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A lightweight PHP library for working with sparse vectors, calculating vector similarity, and ranking objects by similarity.
The package is framework-agnostic and can be used with any objects that can be represented as vectors.
Installation
composer require foortec/php-vector-similarity
Basic usage
Create a sparse vector
A sparse vector stores only non-zero dimensions.
use Foortec\PhpVectorSimilarity\ValueObject\SparseVector; $vector = SparseVector::fromDimensions([2, 8, 17]); $vector->values(); // [ // 2 => 1.0, // 8 => 1.0, // 17 => 1.0, // ]
Weighted vectors are supported as well:
$vector = SparseVector::fromArray([ 2 => 3.0, 8 => 1.5, 17 => 2.0, ]);
Zero values are omitted automatically.
$vector = SparseVector::fromArray([ 2 => 3.0, 8 => 0.0, 17 => 1.0, ]); $vector->values(); // [ // 2 => 3.0, // 17 => 1.0, // ]
Vector operations
$vector->count(); $vector->dimensions(); $vector->has(8); $vector->get(8); $vector->norm(); $vector->normSquared();
The vector is immutable, so modifications return a new instance:
$updated = $vector->with(42, 2.0); $without = $updated->without(8);
Setting a dimension to 0 removes it:
$updated = $vector->with(8, 0);
Calculate cosine similarity
use Foortec\PhpVectorSimilarity\Similarity\CosineSimilarity; $a = SparseVector::fromDimensions([1, 2]); $b = SparseVector::fromDimensions([1, 3]); $similarity = (new CosineSimilarity())->calculate($a, $b); // 0.5
For identical vectors:
$a = SparseVector::fromDimensions([1, 2, 3]); $b = SparseVector::fromDimensions([1, 2, 3]); $similarity = (new CosineSimilarity())->calculate($a, $b); // 1.0
For vectors with no common dimensions:
$a = SparseVector::fromDimensions([1, 2]); $b = SparseVector::fromDimensions([3, 4]); $similarity = (new CosineSimilarity())->calculate($a, $b); // 0.0
Compare domain objects
Objects can implement Vectorizable to expose their vector representation:
use Foortec\PhpVectorSimilarity\Contract\Vectorizable; use Foortec\PhpVectorSimilarity\ValueObject\SparseVector; final class Article implements Vectorizable { public function __construct( private array $tagIds, ) { } public function toVector(): SparseVector { return SparseVector::fromDimensions($this->tagIds); } }
Now two objects can be compared without the library knowing anything about the Article class:
use Foortec\PhpVectorSimilarity\Similarity\CosineSimilarity; use Foortec\PhpVectorSimilarity\Similarity\VectorComparator; $comparator = new VectorComparator( new CosineSimilarity(), ); $score = $comparator->compare($articleA, $articleB);
Rank similar objects
Use SimilarityRanker to find the most similar candidates:
use Foortec\PhpVectorSimilarity\Similarity\CosineSimilarity; use Foortec\PhpVectorSimilarity\Similarity\SimilarityRanker; use Foortec\PhpVectorSimilarity\Similarity\VectorComparator; $ranker = new SimilarityRanker( new VectorComparator( new CosineSimilarity(), ), ); $results = $ranker->rank( $sourceArticle, $articles, limit: 10, );
Each result contains the original object and its similarity score:
foreach ($results as $result) { $article = $result->item; $score = $result->score; echo $score; }
Results are sorted from the highest similarity score to the lowest.
A minimum score can also be specified:
$results = $ranker->rank( $sourceArticle, $articles, limit: 10, minScore: 0.5, );
Custom similarity metrics
Similarity calculation is decoupled from object comparison through SimilarityMetric.
A custom metric can be implemented without changing VectorComparator or SimilarityRanker:
use Foortec\PhpVectorSimilarity\Contract\SimilarityMetric; use Foortec\PhpVectorSimilarity\ValueObject\SparseVector; final class MySimilarityMetric implements SimilarityMetric { public function calculate( SparseVector $a, SparseVector $b, ): float { // Custom similarity calculation... } }
Then inject it into the comparator:
$comparator = new VectorComparator( new MySimilarityMetric(), );
Design
The library keeps vector representation and similarity calculation independent:
Your object
↓
Vectorizable
↓
SparseVector
↓
SimilarityMetric
↓
CosineSimilarity
↓
VectorComparator / SimilarityRanker
This makes the package suitable for comparing any kind of vectorizable data, including articles, products, documents, tags, features, or other domain objects.
Requirements
- PHP 8.3+
- Composer
License
MIT