Search by

foortec / php-vector-similarity

Foortec

A lightweight PHP library for comparing sparse vectors and finding similar vectorized objects.

Package info

github.com/Foortec/php-vector-similarity

pkg:composer/foortec/php-vector-similarity

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-10-03 16:01 UTC

This package is auto-updated.

Last update: 2026-10-03 16:05:49 UTC


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