protected function highAffinities(Matrix $distances) : Matrix
    {
        $zeros = array_fill(0, count($distances), 0);

        $p = [];

        foreach ($distances as $i => $row) {
            $affinities = $zeros;
            $minBeta = -INF;
            $maxBeta = INF;
            $beta = 1.;

            for ($l = 0; $l < self::BINARY_PRECISION; $l++) {
                $affinities = [];
                $pSigma = 0.;

                foreach ($row as $j => $distance) {
                    if ($i !== $j) {
                        $affinity = exp(-$distance * $beta);
                    } else {
                        $affinity = 0.;
                    }

                    $affinities[] = $affinity;
                    $pSigma += $affinity;
                }

                if ($pSigma === 0.) {
                    $pSigma = EPSILON;
                }

                $distSigma = 0.;

                foreach ($affinities as $j => &$prob) {
                    $prob /= $pSigma;
                    $distSigma += $row[$j] * $prob;
                }

                $entropy = log($pSigma) + $beta * $distSigma;

                $diff = $entropy - $this->entropy;

                if (abs($diff) < self::SEARCH_TOLERANCE) {
                    break 1;
                }

                if ($diff > 0.) {
                    $minBeta = $beta;

                    if ($maxBeta === INF) {
                        $beta *= 2.;
                    } else {
                        $beta = ($beta + $maxBeta) / 2.;
                    }
                } else {
                    $maxBeta = $beta;

                    if ($minBeta === -INF) {
                        $beta /= 2.;
                    } else {
                        $beta = ($beta + $minBeta) / 2.;
                    }
                }
            }

            $p[] = $affinities;
        }

        $p = Matrix::quick($p);

        $pHat = $p->add($p->transpose());

        $sigma = $pHat->sum()
            ->clipLower(EPSILON);

        return $pHat->divide($sigma);
    }