mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-12 02:08:40 +00:00
Compare commits
No commits in common. "master" and "v1.0.0" have entirely different histories.
12
.github/FUNDING.yml
vendored
Executable file
12
.github/FUNDING.yml
vendored
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # orange_management
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ['https://paypal.me/orangemgmt']
|
||||
37
.github/dev_bug_report.md
vendored
Executable file
37
.github/dev_bug_report.md
vendored
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
name: Dev Bug Report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: stat_backlog, type_bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
# Bug Description
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
# How to Reproduce
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
## Minimal Code Example
|
||||
|
||||
```php
|
||||
<?php
|
||||
// your code ...
|
||||
?>
|
||||
```
|
||||
|
||||
# Expected Behavior
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
# Screenshots
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
# Additional Information
|
||||
Add any other context about the problem here.
|
||||
18
.github/dev_feature_request.md
vendored
Executable file
18
.github/dev_feature_request.md
vendored
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
name: Dev Feature Request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: stat_backlog, type_feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
# What is the feature you request
|
||||
* A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
* A clear and concise description of what you want to happen.
|
||||
|
||||
# Alternatives
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
# Additional Information
|
||||
Add any other context or screenshots about the feature request here.
|
||||
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
|
|
@ -3,9 +3,8 @@ name: CI
|
|||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
general_module_workflow_php:
|
||||
general_module_workflow:
|
||||
uses: Karaka-Management/Karaka/.github/workflows/php_template.yml@develop
|
||||
secrets:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_PAT: ${{ secrets.GH_PAT }}
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
GH_PAT: ${{ secrets.GH_PAT }}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -15,6 +15,7 @@ declare(strict_types=1);
|
|||
namespace phpOMS\Account;
|
||||
|
||||
use phpOMS\Localization\Localization;
|
||||
use phpOMS\Stdlib\Base\Exception\InvalidEnumValue;
|
||||
use phpOMS\Validation\Network\Email;
|
||||
|
||||
/**
|
||||
|
|
@ -163,12 +164,12 @@ class Account implements \JsonSerializable
|
|||
*/
|
||||
public function hasPermission(
|
||||
int $permission,
|
||||
?int $unit = null,
|
||||
?int $app = null,
|
||||
?string $module = null,
|
||||
?int $category = null,
|
||||
?int $element = null,
|
||||
?int $component = null
|
||||
int $unit = null,
|
||||
int $app = null,
|
||||
string $module = null,
|
||||
int $category = null,
|
||||
int $element = null,
|
||||
int $component = null
|
||||
) : bool
|
||||
{
|
||||
foreach ($this->groups as $group) {
|
||||
|
|
@ -316,6 +317,70 @@ class Account implements \JsonSerializable
|
|||
$this->email = \mb_strtolower($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status.
|
||||
*
|
||||
* @return int Returns the status (AccountStatus)
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getStatus() : int
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status.
|
||||
*
|
||||
* @param int $status Status
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidEnumValue This exception is thrown if a invalid status is used
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function setStatus(int $status) : void
|
||||
{
|
||||
if (!AccountStatus::isValidValue($status)) {
|
||||
throw new InvalidEnumValue($status);
|
||||
}
|
||||
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type.
|
||||
*
|
||||
* @return int Returns the type (AccountType)
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getType() : int
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type.
|
||||
*
|
||||
* @param int $type Type
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidEnumValue This exception is thrown if an invalid type is used
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function setType(int $type) : void
|
||||
{
|
||||
if (!AccountType::isValidValue($type)) {
|
||||
throw new InvalidEnumValue($type);
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last activity.
|
||||
*
|
||||
|
|
@ -380,8 +445,8 @@ class Account implements \JsonSerializable
|
|||
public function toArray() : array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => [
|
||||
'id' => $this->id,
|
||||
'name' => [
|
||||
$this->name1,
|
||||
$this->name2,
|
||||
$this->name3,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -71,8 +71,8 @@ final class AccountManager implements \Countable
|
|||
if ($id === 0) {
|
||||
$account = new Account(Auth::authenticate($this->session));
|
||||
|
||||
if (!isset($this->accounts[$account->id])) {
|
||||
$this->accounts[$account->id] = $account;
|
||||
if (!isset($this->accounts[$account->getId()])) {
|
||||
$this->accounts[$account->getId()] = $account;
|
||||
}
|
||||
|
||||
return $account;
|
||||
|
|
@ -92,8 +92,8 @@ final class AccountManager implements \Countable
|
|||
*/
|
||||
public function add(Account $account) : bool
|
||||
{
|
||||
if (!isset($this->accounts[$account->id])) {
|
||||
$this->accounts[$account->id] = $account;
|
||||
if (!isset($this->accounts[$account->getId()])) {
|
||||
$this->accounts[$account->getId()] = $account;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -14,6 +14,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace phpOMS\Account;
|
||||
|
||||
use phpOMS\Stdlib\Base\Exception\InvalidEnumValue;
|
||||
|
||||
/**
|
||||
* Account group class.
|
||||
*
|
||||
|
|
@ -86,6 +88,38 @@ class Group implements \JsonSerializable
|
|||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get group status.
|
||||
*
|
||||
* @return int Group status
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getStatus() : int
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set group status.
|
||||
*
|
||||
* @param int $status Group status
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidEnumValue This exception is thrown if an invalid status is used
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function setStatus(int $status) : void
|
||||
{
|
||||
if (!GroupStatus::isValidValue($status)) {
|
||||
throw new InvalidEnumValue($status);
|
||||
}
|
||||
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string representation.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -24,18 +24,6 @@ namespace phpOMS\Account;
|
|||
*/
|
||||
final class NullAccount extends Account
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $id Model id
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(int $id = 0)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -169,13 +169,13 @@ class PermissionAbstract implements \JsonSerializable
|
|||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
?int $unit = null,
|
||||
?int $app = null,
|
||||
?string $module = null,
|
||||
?string $from = null,
|
||||
?int $category = null,
|
||||
?int $element = null,
|
||||
?int $component = null,
|
||||
int $unit = null,
|
||||
int $app = null,
|
||||
string $module = null,
|
||||
string $from = null,
|
||||
int $category = null,
|
||||
int $element = null,
|
||||
int $component = null,
|
||||
int $permission = PermissionType::NONE
|
||||
) {
|
||||
$this->unit = $unit;
|
||||
|
|
@ -308,12 +308,12 @@ class PermissionAbstract implements \JsonSerializable
|
|||
*/
|
||||
public function hasPermission(
|
||||
int $permission,
|
||||
?int $unit = null,
|
||||
?int $app = null,
|
||||
?string $module = null,
|
||||
?int $category = null,
|
||||
?int $element = null,
|
||||
?int $component = null
|
||||
int $unit = null,
|
||||
int $app = null,
|
||||
string $module = null,
|
||||
int $category = null,
|
||||
int $element = null,
|
||||
int $component = null
|
||||
) : bool
|
||||
{
|
||||
return $permission === PermissionType::NONE ||
|
||||
|
|
@ -352,15 +352,15 @@ class PermissionAbstract implements \JsonSerializable
|
|||
public function jsonSerialize() : mixed
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'unit' => $this->unit,
|
||||
'app' => $this->app,
|
||||
'module' => $this->module,
|
||||
'from' => $this->from,
|
||||
'category' => $this->category,
|
||||
'element' => $this->element,
|
||||
'component' => $this->component,
|
||||
'permission' => $this->getPermission(),
|
||||
'id' => $this->id,
|
||||
'unit' => $this->unit,
|
||||
'app' => $this->app,
|
||||
'module' => $this->module,
|
||||
'from' => $this->from,
|
||||
'category' => $this->category,
|
||||
'element' => $this->element,
|
||||
'component' => $this->component,
|
||||
'permission' => $this->getPermission(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -135,12 +135,12 @@ trait PermissionHandlingTrait
|
|||
*/
|
||||
public function hasPermission(
|
||||
int $permission,
|
||||
?int $unit = null,
|
||||
?int $app = null,
|
||||
?string $module = null,
|
||||
?int $category = null,
|
||||
?int $element = null,
|
||||
?int $component = null
|
||||
int $unit = null,
|
||||
int $app = null,
|
||||
string $module = null,
|
||||
int $category = null,
|
||||
int $element = null,
|
||||
int $component = null
|
||||
) : bool
|
||||
{
|
||||
foreach ($this->permissions as $p) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Account
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Ai\NeuralNetwork
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -22,7 +22,7 @@ namespace phpOMS\Ai\NeuralNetwork;
|
|||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class Neuron
|
||||
class Neuron
|
||||
{
|
||||
/**
|
||||
* Neuron inputs
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Ai\Ocr
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Ai\Ocr\Tesseract
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -85,34 +85,14 @@ final class TesseractOcr
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function parseImage(string $image, array $languages = ['eng', 'deu'], int $psm = 3, int $oem = 3) : string
|
||||
public function parseImage(string $image, array $languages = ['eng'], int $psm = 3, int $oem = 3) : string
|
||||
{
|
||||
$temp = \tempnam(\sys_get_temp_dir(), 'oms_ocr_');
|
||||
if ($temp === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$extension = 'png';
|
||||
try {
|
||||
// Tesseract needs higher dpi to work properly (identify + adjust if necessary)
|
||||
$dpi = (int) \trim(\implode('', SystemUtils::runProc(
|
||||
'identify',
|
||||
'-quiet -format "%x" ' . $image
|
||||
)));
|
||||
|
||||
if ($dpi < 300) {
|
||||
$split = \explode('.', $image);
|
||||
$extension = \end($split);
|
||||
|
||||
SystemUtils::runProc(
|
||||
'convert',
|
||||
'-units PixelsPerInch ' . $image . ' -resample 300 ' . $temp . '.' . $extension
|
||||
);
|
||||
|
||||
$image = $temp . '.' . $extension;
|
||||
}
|
||||
|
||||
// Do actual parsing
|
||||
SystemUtils::runProc(
|
||||
self::$bin,
|
||||
$image . ' '
|
||||
|
|
@ -120,20 +100,12 @@ final class TesseractOcr
|
|||
. ' -c preserve_interword_spaces=1'
|
||||
. ' --psm ' . $psm
|
||||
. ' --oem ' . $oem
|
||||
. (empty($languages) ? '' : ' -l ' . \implode('+', $languages))
|
||||
. ' -l ' . \implode('+', $languages)
|
||||
);
|
||||
} catch (\Throwable $_) {
|
||||
if (\is_file($temp . '.' . $extension)) {
|
||||
\unlink($temp . '.' . $extension);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
if (\is_file($temp . '.' . $extension)) {
|
||||
\unlink($temp . '.' . $extension);
|
||||
}
|
||||
|
||||
$filepath = \is_file($temp . '.txt')
|
||||
? $temp . '.txt'
|
||||
: $temp;
|
||||
|
|
@ -148,7 +120,11 @@ final class TesseractOcr
|
|||
|
||||
$parsed = \file_get_contents($filepath);
|
||||
if ($parsed === false) {
|
||||
$parsed = '';
|
||||
// @codeCoverageIgnoreStart
|
||||
\unlink($temp);
|
||||
|
||||
return '';
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
\unlink($filepath);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -14,141 +14,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace phpOMS\Algorithm\Clustering;
|
||||
|
||||
use phpOMS\Math\Topology\MetricsND;
|
||||
|
||||
/**
|
||||
* Clustering points
|
||||
*
|
||||
* The parent category of this clustering algorithm is hierarchical clustering.
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @license Base: MIT Copyright (c) 2020 Greene Laboratory
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @see ./DivisiveClustering.php
|
||||
* @see ./clustering_overview.png
|
||||
* @see https://en.wikipedia.org/wiki/Hierarchical_clustering
|
||||
* @see https://github.com/greenelab/hclust/blob/master/README.md
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo Implement
|
||||
* @todo Implement missing linkage functions
|
||||
*/
|
||||
final class AgglomerativeClustering implements ClusteringInterface
|
||||
final class AgglomerativeClustering
|
||||
{
|
||||
/**
|
||||
* Metric to calculate the distance between two points
|
||||
*
|
||||
* @var \Closure
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public \Closure $metric;
|
||||
|
||||
/**
|
||||
* Metric to calculate the distance between two points
|
||||
*
|
||||
* @var \Closure
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public \Closure $linkage;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param null|\Closure $metric metric to use for the distance between two points
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(?\Closure $metric = null, ?\Closure $linkage = null)
|
||||
{
|
||||
$this->metric = $metric ?? function (Point $a, Point $b) {
|
||||
$aCoordinates = $a->coordinates;
|
||||
$bCoordinates = $b->coordinates;
|
||||
|
||||
return MetricsND::euclidean($aCoordinates, $bCoordinates);
|
||||
};
|
||||
|
||||
$this->linkage = $linkage ?? function (array $a, array $b, array $distances) {
|
||||
return self::averageDistanceLinkage($a, $b, $distances);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum/Complete-Linkage clustering
|
||||
*/
|
||||
public static function maximumDistanceLinkage(array $setA, array $setB, array $distances) : float
|
||||
{
|
||||
$max = \PHP_INT_MIN;
|
||||
foreach ($setA as $a) {
|
||||
foreach ($setB as $b) {
|
||||
if ($distances[$a][$b] > $max) {
|
||||
$max = $distances[$a][$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum/Single-Linkage clustering
|
||||
*/
|
||||
public static function minimumDistanceLinkage(array $setA, array $setB, array $distances) : float
|
||||
{
|
||||
$min = \PHP_INT_MAX;
|
||||
foreach ($setA as $a) {
|
||||
foreach ($setB as $b) {
|
||||
if ($distances[$a][$b] < $min) {
|
||||
$min = $distances[$a][$b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unweighted average linkage clustering (UPGMA)
|
||||
*/
|
||||
public static function averageDistanceLinkage(array $setA, array $setB, array $distances) : float
|
||||
{
|
||||
$distance = 0;
|
||||
foreach ($setA as $a) {
|
||||
$distance += \array_sum($distances[$a]);
|
||||
}
|
||||
|
||||
return $distance / \count($setA) / \count($setB);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCentroids() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClusters() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNoise() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -25,37 +25,6 @@ namespace phpOMS\Algorithm\Clustering;
|
|||
*
|
||||
* @todo Implement
|
||||
*/
|
||||
final class Birch implements ClusteringInterface
|
||||
final class Birch
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCentroids() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClusters() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNoise() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Clustering;
|
||||
|
||||
/**
|
||||
* Clustering interface.
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering;
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
interface ClusteringInterface
|
||||
{
|
||||
/**
|
||||
* Get cluster centroids
|
||||
*
|
||||
* @return Point[]
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getCentroids() : array;
|
||||
|
||||
/**
|
||||
* Get cluster assignments of the training data
|
||||
*
|
||||
* @return Point[]
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getClusters() : array;
|
||||
|
||||
/**
|
||||
* Cluster a single point
|
||||
*
|
||||
* This point doesn't have to be in the training data.
|
||||
*
|
||||
* @param Point $point Point to cluster
|
||||
*
|
||||
* @return null|Point
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point;
|
||||
|
||||
/**
|
||||
* Get noise data.
|
||||
*
|
||||
* Data points from the training data that are not part of a cluster.
|
||||
*
|
||||
* @return Point[]
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getNoise() : array;
|
||||
|
||||
// Not possible to interface due to different implementations
|
||||
// public function generateClusters(...) : void
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -29,7 +29,7 @@ use phpOMS\Math\Topology\MetricsND;
|
|||
*
|
||||
* @todo Expand to n dimensions
|
||||
*/
|
||||
final class DBSCAN implements ClusteringInterface
|
||||
final class DBSCAN
|
||||
{
|
||||
/**
|
||||
* Epsilon for float comparison.
|
||||
|
|
@ -50,7 +50,7 @@ final class DBSCAN implements ClusteringInterface
|
|||
/**
|
||||
* Points outside of any cluster
|
||||
*
|
||||
* @var Point[]
|
||||
* @var PointInterface[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $noisePoints = [];
|
||||
|
|
@ -58,25 +58,17 @@ final class DBSCAN implements ClusteringInterface
|
|||
/**
|
||||
* All points
|
||||
*
|
||||
* @var Point[]
|
||||
* @var PointInterface[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $points = [];
|
||||
|
||||
/**
|
||||
* Points of the cluster centers
|
||||
*
|
||||
* @var Point[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $clusterCenters = [];
|
||||
|
||||
/**
|
||||
* Clusters
|
||||
*
|
||||
* Array of points assigned to a cluster
|
||||
*
|
||||
* @var array<int, Point[]>
|
||||
* @var array<int, array>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $clusters = [];
|
||||
|
|
@ -116,9 +108,9 @@ final class DBSCAN implements ClusteringInterface
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(?\Closure $metric = null)
|
||||
public function __construct(\Closure $metric = null)
|
||||
{
|
||||
$this->metric = $metric ?? function (Point $a, Point $b) {
|
||||
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
|
||||
$aCoordinates = $a->coordinates;
|
||||
$bCoordinates = $b->coordinates;
|
||||
|
||||
|
|
@ -129,18 +121,18 @@ final class DBSCAN implements ClusteringInterface
|
|||
/**
|
||||
* Expand cluster with additional point and potential neighbors.
|
||||
*
|
||||
* @param Point $point Point to add to a cluster
|
||||
* @param array $neighbors Neighbors of point
|
||||
* @param int $c Cluster id
|
||||
* @param float $epsilon Max distance
|
||||
* @param int $minPoints Min amount of points required for a cluster
|
||||
* @param PointInterface $point Point to add to a cluster
|
||||
* @param array $neighbors Neighbors of point
|
||||
* @param int $c Cluster id
|
||||
* @param float $epsilon Max distance
|
||||
* @param int $minPoints Min amount of points required for a cluster
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function expandCluster(
|
||||
Point $point,
|
||||
PointInterface $point,
|
||||
array $neighbors,
|
||||
int $c,
|
||||
float $epsilon,
|
||||
|
|
@ -174,14 +166,14 @@ final class DBSCAN implements ClusteringInterface
|
|||
/**
|
||||
* Find neighbors of a point
|
||||
*
|
||||
* @param Point $point Base point for potential neighbors
|
||||
* @param float $epsilon Max distance to neighbor
|
||||
* @param PointInterface $point Base point for potential neighbors
|
||||
* @param float $epsilon Max distance to neighbor
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function findNeighbors(Point $point, float $epsilon) : array
|
||||
private function findNeighbors(PointInterface $point, float $epsilon) : array
|
||||
{
|
||||
$neighbors = [];
|
||||
foreach ($this->points as $point2) {
|
||||
|
|
@ -223,9 +215,15 @@ final class DBSCAN implements ClusteringInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Find the cluster for a point
|
||||
*
|
||||
* @param PointInterface $point Point to find the cluster for
|
||||
*
|
||||
* @return int Cluster id
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point
|
||||
public function cluster(PointInterface $point) : int
|
||||
{
|
||||
if ($this->convexHulls === []) {
|
||||
foreach ($this->clusters as $c => $cluster) {
|
||||
|
|
@ -234,26 +232,26 @@ final class DBSCAN implements ClusteringInterface
|
|||
$points[] = $p->coordinates;
|
||||
}
|
||||
|
||||
// @todo this is only good for 2D. Fix this for ND.
|
||||
// @todo: this is only good for 2D. Fix this for ND.
|
||||
$this->convexHulls[$c] = MonotoneChain::createConvexHull($points);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->convexHulls as $c => $hull) {
|
||||
if (Polygon::isPointInPolygon($point->coordinates, $hull) <= 0) {
|
||||
return $hull;
|
||||
return $c;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the clusters of the points
|
||||
*
|
||||
* @param Point[] $points Points to cluster
|
||||
* @param float $epsilon Max distance
|
||||
* @param int $minPoints Min amount of points required for a cluster
|
||||
* @param PointInterface[] $points Points to cluster
|
||||
* @param float $epsilon Max distance
|
||||
* @param int $minPoints Min amount of points required for a cluster
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
|
|
@ -284,48 +282,4 @@ final class DBSCAN implements ClusteringInterface
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCentroids() : array
|
||||
{
|
||||
if (!empty($this->clusterCenters)) {
|
||||
return $this->clusterCenters;
|
||||
}
|
||||
|
||||
$dim = \count(\reset($this->points)->getCoordinates());
|
||||
foreach ($this->clusters as $cluster) {
|
||||
$middle = \array_fill(0, $dim, 0);
|
||||
foreach ($cluster as $point) {
|
||||
for ($i = 0; $i < $dim; ++$i) {
|
||||
$middle[$i] += $point->getCoordinate($i);
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $dim; ++$i) {
|
||||
$middle[$i] /= \count($cluster);
|
||||
}
|
||||
|
||||
$this->clusterCenters = new Point($middle);
|
||||
}
|
||||
|
||||
return $this->clusterCenters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNoise() : array
|
||||
{
|
||||
return $this->noisePoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClusters() : array
|
||||
{
|
||||
return $this->clusters;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Clustering;
|
||||
|
||||
/**
|
||||
* Clustering points
|
||||
*
|
||||
* The parent category of this clustering algorithm is hierarchical clustering.
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @see ./AgglomerativeClustering.php
|
||||
* @see ./clustering_overview.png
|
||||
* @see https://en.wikipedia.org/wiki/Hierarchical_clustering
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo Implement
|
||||
*/
|
||||
final class DivisiveClustering implements ClusteringInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCentroids() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClusters() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNoise() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -25,7 +25,7 @@ use phpOMS\Math\Topology\MetricsND;
|
|||
* @see ./clustering_overview.png
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class Kmeans implements ClusteringInterface
|
||||
final class Kmeans
|
||||
{
|
||||
/**
|
||||
* Epsilon for float comparison.
|
||||
|
|
@ -46,26 +46,10 @@ final class Kmeans implements ClusteringInterface
|
|||
/**
|
||||
* Points of the cluster centers
|
||||
*
|
||||
* @var Point[]
|
||||
* @var PointInterface[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $clusterCenters = [];
|
||||
|
||||
/**
|
||||
* Points of the clusters
|
||||
*
|
||||
* @var Point[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $clusters = [];
|
||||
|
||||
/**
|
||||
* Points
|
||||
*
|
||||
* @var Point[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $points = [];
|
||||
private $clusterCenters = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
|
@ -74,20 +58,28 @@ final class Kmeans implements ClusteringInterface
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(?\Closure $metric = null)
|
||||
public function __construct(\Closure $metric = null)
|
||||
{
|
||||
$this->metric = $metric ?? function (Point $a, Point $b) {
|
||||
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
|
||||
$aCoordinates = $a->coordinates;
|
||||
$bCoordinates = $b->coordinates;
|
||||
|
||||
return MetricsND::euclidean($aCoordinates, $bCoordinates);
|
||||
};
|
||||
|
||||
//$this->generateClusters($points, $clusters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Find the cluster for a point
|
||||
*
|
||||
* @param PointInterface $point Point to find the cluster for
|
||||
*
|
||||
* @return null|PointInterface Cluster center point
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point
|
||||
public function cluster(PointInterface $point) : ?PointInterface
|
||||
{
|
||||
$bestCluster = null;
|
||||
$bestDistance = \PHP_FLOAT_MAX;
|
||||
|
|
@ -103,26 +95,22 @@ final class Kmeans implements ClusteringInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Get cluster centroids
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getCentroids() : array
|
||||
{
|
||||
return $this->clusterCenters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNoise() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the clusters of the points
|
||||
*
|
||||
* @param Point[] $points Points to cluster
|
||||
* @param int<1, max> $clusters Amount of clusters
|
||||
* @param PointInterface[] $points Points to cluster
|
||||
* @param int<0, max> $clusters Amount of clusters
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
|
|
@ -130,7 +118,6 @@ final class Kmeans implements ClusteringInterface
|
|||
*/
|
||||
public function generateClusters(array $points, int $clusters) : void
|
||||
{
|
||||
$this->points = $points;
|
||||
$n = \count($points);
|
||||
$clusterCenters = $this->kpp($points, $clusters);
|
||||
$coordinates = \count($points[0]->coordinates);
|
||||
|
|
@ -153,7 +140,8 @@ final class Kmeans implements ClusteringInterface
|
|||
|
||||
foreach ($clusterCenters as $center) {
|
||||
for ($i = 0; $i < $coordinates; ++$i) {
|
||||
$center->setCoordinate($i, $center->getCoordinate($i) / $center->group);
|
||||
// @todo Invalid center coodinate value in like 5 % of the runs
|
||||
$center->setCoordinate($i, $center->getCoordinate($i) / ($center->group === 0 ? 1 : $center->group));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +149,7 @@ final class Kmeans implements ClusteringInterface
|
|||
foreach ($points as $point) {
|
||||
$min = $this->nearestClusterCenter($point, $clusterCenters)[0];
|
||||
|
||||
if ($clusters !== $point->group) {
|
||||
if ($min !== $point->group) {
|
||||
++$changed;
|
||||
$point->group = $min;
|
||||
}
|
||||
|
|
@ -183,14 +171,14 @@ final class Kmeans implements ClusteringInterface
|
|||
/**
|
||||
* Get the index and distance to the nearest cluster center
|
||||
*
|
||||
* @param Point $point Point to get the cluster for
|
||||
* @param Point[] $clusterCenters All cluster centers
|
||||
* @param PointInterface $point Point to get the cluster for
|
||||
* @param PointInterface[] $clusterCenters All cluster centers
|
||||
*
|
||||
* @return array [index, distance]
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function nearestClusterCenter(Point $point, array $clusterCenters) : array
|
||||
private function nearestClusterCenter(PointInterface $point, array $clusterCenters) : array
|
||||
{
|
||||
$index = $point->group;
|
||||
$dist = \PHP_FLOAT_MAX;
|
||||
|
|
@ -208,71 +196,43 @@ final class Kmeans implements ClusteringInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Initialize cluster centers
|
||||
* Initializae cluster centers
|
||||
*
|
||||
* @param Point[] $points Points to use for the cluster center initialization
|
||||
* @param int<0, max> $n Amount of clusters to use
|
||||
* @param PointInterface[] $points Points to use for the cluster center initialization
|
||||
* @param int<0, max> $n Amount of clusters to use
|
||||
*
|
||||
* @return Point[]
|
||||
* @return PointInterface[]
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function kpp(array $points, int $n) : array
|
||||
{
|
||||
$clusters = [clone $points[\array_rand($points, 1)]];
|
||||
|
||||
$d = \array_fill(0, $n, 0.0);
|
||||
$clusters = [clone $points[\mt_rand(0, \count($points) - 1)]];
|
||||
$d = \array_fill(0, $n, 0.0);
|
||||
|
||||
for ($i = 1; $i < $n; ++$i) {
|
||||
$sum = 0;
|
||||
|
||||
foreach ($points as $key => $point) {
|
||||
$d[$key] = $this->nearestClusterCenter($point, $clusters)[1];
|
||||
$sum += $d[$key];
|
||||
$d[$key] = $this->nearestClusterCenter($point, \array_slice($clusters, 0, 5))[1];
|
||||
$sum += $d[$key];
|
||||
}
|
||||
|
||||
$sum *= \mt_rand(0, \mt_getrandmax()) / \mt_getrandmax();
|
||||
|
||||
$found = false;
|
||||
foreach ($d as $key => $di) {
|
||||
$sum -= $di;
|
||||
|
||||
// The in array check is important to avoid duplicate cluster centers
|
||||
if ($sum <= 0 && !\in_array($c = $points[$key], $clusters)) {
|
||||
$clusters[$i] = clone $c;
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
|
||||
while (!$found) {
|
||||
if (!\in_array($c = $points[\array_rand($points)], $clusters)) {
|
||||
$clusters[$i] = clone $c;
|
||||
$found = true;
|
||||
if ($sum <= 0) {
|
||||
$clusters[$i] = clone $points[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($points as $point) {
|
||||
$point->group = $this->nearestClusterCenter($point, $clusters)[0];
|
||||
$point->group = ($this->nearestClusterCenter($point, $clusters)[0]);
|
||||
}
|
||||
|
||||
return $clusters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClusters() : array
|
||||
{
|
||||
if (!empty($this->clusters)) {
|
||||
return $this->clusters;
|
||||
}
|
||||
|
||||
foreach ($this->points as $point) {
|
||||
$c = $this->cluster($point);
|
||||
$this->clusters[$c?->name] = $point;
|
||||
}
|
||||
|
||||
return $this->clusters;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -25,10 +25,8 @@ use phpOMS\Math\Topology\MetricsND;
|
|||
* @link https://jingga.app
|
||||
* @see ./clustering_overview.png
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo Implement noise points
|
||||
*/
|
||||
final class MeanShift implements ClusteringInterface
|
||||
final class MeanShift
|
||||
{
|
||||
/**
|
||||
* Min distance for clustering
|
||||
|
|
@ -61,7 +59,7 @@ final class MeanShift implements ClusteringInterface
|
|||
/**
|
||||
* Points outside of any cluster
|
||||
*
|
||||
* @var Point[]
|
||||
* @var PointInterface[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $noisePoints = [];
|
||||
|
|
@ -79,10 +77,10 @@ final class MeanShift implements ClusteringInterface
|
|||
/**
|
||||
* Points of the cluster centers
|
||||
*
|
||||
* @var Point[]
|
||||
* @var PointInterface[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $clusterCenters = [];
|
||||
private $clusterCenters = [];
|
||||
|
||||
/**
|
||||
* Max distance to cluster to be still considered part of cluster
|
||||
|
|
@ -102,9 +100,9 @@ final class MeanShift implements ClusteringInterface
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(?\Closure $metric = null, ?\Closure $kernel = null)
|
||||
public function __construct(\Closure $metric = null, \Closure $kernel = null)
|
||||
{
|
||||
$this->metric = $metric ?? function (Point $a, Point $b) {
|
||||
$this->metric = $metric ?? function (PointInterface $a, PointInterface $b) {
|
||||
$aCoordinates = $a->coordinates;
|
||||
$bCoordinates = $b->coordinates;
|
||||
|
||||
|
|
@ -119,7 +117,7 @@ final class MeanShift implements ClusteringInterface
|
|||
/**
|
||||
* Generate the clusters of the points
|
||||
*
|
||||
* @param Point[] $points Points to cluster
|
||||
* @param PointInterface[] $points Points to cluster
|
||||
* @param array<int|float> $bandwidth Bandwidth(s)
|
||||
*
|
||||
* @return void
|
||||
|
|
@ -128,9 +126,8 @@ final class MeanShift implements ClusteringInterface
|
|||
*/
|
||||
public function generateClusters(array $points, array $bandwidth) : void
|
||||
{
|
||||
$this->points = $points;
|
||||
$shiftPoints = $points;
|
||||
$maxMinDist = 1;
|
||||
$shiftPoints = $points;
|
||||
$maxMinDist = 1;
|
||||
|
||||
$stillShifting = \array_fill(0, \count($points), true);
|
||||
|
||||
|
|
@ -170,15 +167,15 @@ final class MeanShift implements ClusteringInterface
|
|||
/**
|
||||
* Perform shift on a point
|
||||
*
|
||||
* @param Point $point Point to shift
|
||||
* @param Point $points Array of all points
|
||||
* @param PointInterface $point Point to shift
|
||||
* @param PointInterface $points Array of all points
|
||||
* @param array<int|float> $bandwidth Bandwidth(s)
|
||||
*
|
||||
* @return Point
|
||||
* @return PointInterface
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function shiftPoint(Point $point, array $points, array $bandwidth) : Point
|
||||
private function shiftPoint(PointInterface $point, array $points, array $bandwidth) : PointInterface
|
||||
{
|
||||
$scaleFactor = 0.0;
|
||||
|
||||
|
|
@ -209,7 +206,7 @@ final class MeanShift implements ClusteringInterface
|
|||
/**
|
||||
* Group points together into clusters
|
||||
*
|
||||
* @param Point[] $points Array of points to assign to groups
|
||||
* @param PointInterface[] $points Array of points to assign to groups
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
|
|
@ -242,14 +239,14 @@ final class MeanShift implements ClusteringInterface
|
|||
/**
|
||||
* Find the closest cluster/group of a point
|
||||
*
|
||||
* @param Point $point Point to find the cluster for
|
||||
* @param array<Point[]> $groups Clusters
|
||||
* @param PointInterface $point Point to find the cluster for
|
||||
* @param array<PointInterface[]> $groups Clusters
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function findNearestGroup(Point $point, array $groups) : int
|
||||
private function findNearestGroup(PointInterface $point, array $groups) : int
|
||||
{
|
||||
$nearestGroupIndex = -1;
|
||||
$index = 0;
|
||||
|
|
@ -272,14 +269,14 @@ final class MeanShift implements ClusteringInterface
|
|||
/**
|
||||
* Find distance of point to best cluster/group
|
||||
*
|
||||
* @param Point $point Point to find the cluster for
|
||||
* @param Point[] $group Clusters
|
||||
* @param PointInterface $point Point to find the cluster for
|
||||
* @param PointInterface[] $group Clusters
|
||||
*
|
||||
* @return float Distance
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function distanceToGroup(Point $point, array $group) : float
|
||||
private function distanceToGroup(PointInterface $point, array $group) : float
|
||||
{
|
||||
$minDistance = \PHP_FLOAT_MAX;
|
||||
|
||||
|
|
@ -295,36 +292,18 @@ final class MeanShift implements ClusteringInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Find the cluster for a point
|
||||
*
|
||||
* @param PointInterface $point Point to find the cluster for
|
||||
*
|
||||
* @return null|PointInterface Cluster center point
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getCentroids() : array
|
||||
{
|
||||
return $this->clusterCenters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point
|
||||
public function cluster(PointInterface $point) : ?PointInterface
|
||||
{
|
||||
$clusterId = $this->findNearestGroup($point, $this->clusters);
|
||||
|
||||
return $this->clusterCenters[$clusterId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNoise() : array
|
||||
{
|
||||
return $this->noisePoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClusters() : array
|
||||
{
|
||||
return $this->clusters;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -28,7 +28,7 @@ class Point implements PointInterface
|
|||
* Coordinates of the point
|
||||
*
|
||||
* @var array<int, int|float>
|
||||
* @since 1.0.0
|
||||
* @sicne 1.0.0
|
||||
*/
|
||||
public array $coordinates = [];
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ class Point implements PointInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isEquals(Point $point) : bool
|
||||
public function isEquals(PointInterface $point) : bool
|
||||
{
|
||||
return $this->name === $point->name && $this->coordinates === $point->coordinates;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -25,10 +25,6 @@ namespace phpOMS\Algorithm\Clustering;
|
|||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @property array<int, int|float> $coordinates
|
||||
* @property string $name
|
||||
* @property int $group
|
||||
*/
|
||||
interface PointInterface
|
||||
{
|
||||
|
|
@ -67,11 +63,11 @@ interface PointInterface
|
|||
/**
|
||||
* Check if two points are equal
|
||||
*
|
||||
* @param Point $point Point to compare with
|
||||
* @param self $point Point to compare with
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function isEquals(Point $point) : bool;
|
||||
public function isEquals(self $point) : bool;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -25,37 +25,6 @@ namespace phpOMS\Algorithm\Clustering;
|
|||
*
|
||||
* @todo Implement
|
||||
*/
|
||||
final class SpectralClustering implements ClusteringInterface
|
||||
final class SpectralClustering
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCentroids() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClusters() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cluster(Point $point) : ?Point
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNoise() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
30
Algorithm/Clustering/Ward.php
Normal file
30
Algorithm/Clustering/Ward.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Clustering;
|
||||
|
||||
/**
|
||||
* Clustering points
|
||||
*
|
||||
* @package phpOMS\Algorithm\Clustering
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @see ./clustering_overview.png
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo Implement
|
||||
*/
|
||||
final class Ward
|
||||
{
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\CoinMatching
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Frequency
|
||||
* @package phpOMS\Algorithm\CoinMatching
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
|
|
@ -12,14 +12,14 @@
|
|||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Frequency;
|
||||
namespace phpOMS\Algorithm\CoinMatching;
|
||||
|
||||
/**
|
||||
* Apriori algorithm.
|
||||
*
|
||||
* The algorithm checks how often a set exists in a given set of sets.
|
||||
* The algorithm cheks how often a set exists in a given set of sets.
|
||||
*
|
||||
* @package phpOMS\Algorithm\Frequency
|
||||
* @package phpOMS\Algorithm\CoinMatching
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
|
|
@ -39,7 +39,7 @@ final class Apriori
|
|||
/**
|
||||
* Generate all possible subsets
|
||||
*
|
||||
* @param array $arr Array of elements
|
||||
* @param array $arr Array of eleements
|
||||
*
|
||||
* @return array<array>
|
||||
*
|
||||
|
|
@ -70,14 +70,13 @@ final class Apriori
|
|||
*
|
||||
* The algorithm cheks how often a set exists in a given set of sets.
|
||||
*
|
||||
* @param array<string[]> $sets Sets of a set (e.g. [[1,2,3,4], [1,2], [1]])
|
||||
* @param string[] $subset Subset to check for (empty array -> all subsets are checked)
|
||||
* @param array<array> $sets Sets of a set (e.g. [[1,2,3,4], [1,2], [1]])
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function apriori(array $sets, array $subset = []) : array
|
||||
public static function apriori(array $sets) : array
|
||||
{
|
||||
// Unique single items
|
||||
$totalSet = [];
|
||||
|
|
@ -91,7 +90,6 @@ final class Apriori
|
|||
|
||||
$totalSet = \array_unique($totalSet);
|
||||
\sort($totalSet);
|
||||
\sort($subset);
|
||||
|
||||
// Combinations of items
|
||||
$combinations = self::generateSubsets($totalSet);
|
||||
|
|
@ -100,18 +98,10 @@ final class Apriori
|
|||
$table = [];
|
||||
foreach ($combinations as &$c) {
|
||||
\sort($c);
|
||||
if (!empty($subset) && $c !== $subset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table[\implode(':', $c)] = 0;
|
||||
}
|
||||
|
||||
foreach ($combinations as $combination) {
|
||||
if (!empty($subset) && $combination !== $subset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($sets as $set) {
|
||||
foreach ($combination as $item) {
|
||||
if (!\in_array($item, $set)) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Graph;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -67,7 +67,7 @@ final class DependencyResolver
|
|||
$unresolved[] = $dependency;
|
||||
self::dependencyResolve($dependency, $items, $resolved, $unresolved);
|
||||
} else {
|
||||
return; // circular dependency
|
||||
continue; // circular dependency
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Graph
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -21,185 +21,9 @@ namespace phpOMS\Algorithm\Graph;
|
|||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo Implement
|
||||
*/
|
||||
final class MarkovChain
|
||||
{
|
||||
/**
|
||||
* Order of the markov chain
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private int $order = 1;
|
||||
|
||||
/**
|
||||
* Trained data
|
||||
*
|
||||
* @var array
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $data = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $order Order of the markov chain
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(int $order = 1)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create markov chain based on input
|
||||
*
|
||||
* @param array $values Training values
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function train(array $values) : void
|
||||
{
|
||||
$temp = [];
|
||||
$length = \count($values) - $this->order;
|
||||
|
||||
$unique = \array_unique($values);
|
||||
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$key = [];
|
||||
for ($j = 0; $j < $this->order; ++$j) {
|
||||
$key[] = $values[$i + $j];
|
||||
}
|
||||
|
||||
$keyString = \implode(' ', $key);
|
||||
|
||||
if (!isset($temp[$keyString])) {
|
||||
foreach ($unique as $value) {
|
||||
$temp[$keyString][$value] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
++$temp[$keyString][$values[$i + 1]];
|
||||
}
|
||||
|
||||
foreach ($temp as $key => $values) {
|
||||
$sum = \array_sum($values);
|
||||
foreach ($values as $idx => $value) {
|
||||
$this->data[$key][$idx] = $value / $sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set training data
|
||||
*
|
||||
* @param array<array<int, int>> $values Training values
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function setTraining(array $values) : void
|
||||
{
|
||||
$this->data = $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a markov chain based on the training data.
|
||||
*
|
||||
* @param int $length Length of the markov chain
|
||||
* @param array $start Start values of the markov chain
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function generate(int $length, ?array $start = null) : array
|
||||
{
|
||||
$orderKeys = \array_keys($this->data);
|
||||
$orderValues = \array_keys(\reset($this->data));
|
||||
|
||||
$output = $start ?? \explode(' ', $orderKeys[\array_rand($orderKeys)]);
|
||||
$key = $output;
|
||||
|
||||
for ($i = $this->order; $i < $length; ++$i) {
|
||||
$keyString = \implode(' ', $key);
|
||||
|
||||
$prob = \mt_rand(1, 100) / 100;
|
||||
$cProb = 0.0;
|
||||
$val = null;
|
||||
$new = null;
|
||||
|
||||
foreach (($this->data[$keyString] ?? []) as $val => $p) {
|
||||
$cProb += $p;
|
||||
|
||||
if ($prob <= $cProb) {
|
||||
$new = $val;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't find possible key
|
||||
$new ??= $orderValues[\array_rand($orderValues)];
|
||||
|
||||
$output[] = $new;
|
||||
$key[] = $new;
|
||||
|
||||
\array_shift($key);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the probability for a certain markov chain.
|
||||
*
|
||||
* @param array $path Markov chain
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function pathProbability(array $path) : float
|
||||
{
|
||||
$length = \count($path);
|
||||
if ($length <= $this->order) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$key = \array_slice($path, 0, $this->order);
|
||||
|
||||
$prob = 1.0;
|
||||
for ($i = $this->order; $i < $length; ++$i) {
|
||||
$prob *= $this->data[\implode(' ', $key)][$path[$i]] ?? 0.0;
|
||||
|
||||
$key[] = $path[$i];
|
||||
\array_shift($key);
|
||||
}
|
||||
|
||||
return $prob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the probability for a certain state change in a markov chain
|
||||
*
|
||||
* @param array $state Current state of the markov chain
|
||||
* @param mixed $next Next markov state
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function stepProbability(array $state, mixed $next) : float
|
||||
{
|
||||
if (\count($state) !== $this->order) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return $this->data[\implode(' ', $state)][$next] ?? 0.0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\JobScheduling
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -57,7 +57,7 @@ class Job implements JobInterface
|
|||
public string $name = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Cosntructor.
|
||||
*
|
||||
* @param float $value Value of the job
|
||||
* @param \DateTime $start Start time of the job
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\JobScheduling
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\JobScheduling
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -62,7 +62,7 @@ final class Weighted
|
|||
}
|
||||
|
||||
/**
|
||||
* Search for a none-conflicting job that comes before a defined job
|
||||
* Search for a none-conflicting job that comes befor a defined job
|
||||
*
|
||||
* @param JobInterface[] $jobs List of jobs
|
||||
* @param int $pivot Job to find the previous job to
|
||||
|
|
@ -130,7 +130,7 @@ final class Weighted
|
|||
|
||||
if ($l != -1) {
|
||||
$value += $valueTable[$l];
|
||||
$jList = \array_merge($resultTable[$l], $jList);
|
||||
$jList = \array_merge($resultTable[$l], $jList);
|
||||
}
|
||||
|
||||
if ($value > $valueTable[$i - 1]) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Scheduling\Dependency;
|
||||
|
||||
/**
|
||||
* Material.
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Material
|
||||
{
|
||||
public int $id = 0;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Scheduling\Dependency;
|
||||
|
||||
/**
|
||||
* Material.
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Qualification
|
||||
{
|
||||
public int $id = 0;
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling\Dependency
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -24,96 +24,32 @@ namespace phpOMS\Scheduling;
|
|||
*/
|
||||
class Job
|
||||
{
|
||||
/**
|
||||
* Id
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public int $id = 0;
|
||||
|
||||
/**
|
||||
* Time of the execution
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public int $executionTime = 0;
|
||||
|
||||
/**
|
||||
* Priority.
|
||||
*
|
||||
* @var float
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public float $priority = 0.0;
|
||||
|
||||
/**
|
||||
* Value this job generates.
|
||||
*
|
||||
* @var float
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public float $value = 0.0;
|
||||
|
||||
/**
|
||||
* Cost of executing this job.
|
||||
*
|
||||
* @var float
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public float $cost = 0.0;
|
||||
|
||||
/**
|
||||
* How many iterations has this job been on hold in the queue.
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
/** How many iterations has this job been on hold in the queue */
|
||||
public int $onhold = 0;
|
||||
|
||||
/**
|
||||
* How many iterations has this job been in process in the queue.
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
/** How many iterations has this job been in process in the queue */
|
||||
public int $inprocessing = 0;
|
||||
|
||||
/**
|
||||
* What is the deadline for this job?
|
||||
*
|
||||
* @param \DateTime
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public \DateTime $deadline;
|
||||
|
||||
/**
|
||||
* Which steps must be taken during the job execution
|
||||
*
|
||||
* @var JobStep[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public array $steps = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->deadline = new \DateTime('now');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the profit of the job
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getProfit() : float
|
||||
public function getProfit()
|
||||
{
|
||||
return $this->value - $this->cost;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Scheduling
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -24,24 +24,8 @@ namespace phpOMS\Scheduling;
|
|||
*/
|
||||
final class ScheduleQueue
|
||||
{
|
||||
/**
|
||||
* Queue
|
||||
*
|
||||
* @var Job[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public array $queue = [];
|
||||
|
||||
/**
|
||||
* Get element from queue
|
||||
*
|
||||
* @param int $size Amount of elements to return
|
||||
* @param int $type Priority type to use for return
|
||||
*
|
||||
* @return Job[]
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function get(int $size = 1, int $type = PriorityMode::FIFO) : array
|
||||
{
|
||||
$jobs = [];
|
||||
|
|
@ -119,33 +103,11 @@ final class ScheduleQueue
|
|||
return $jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert new element into queue
|
||||
*
|
||||
* @param int $id Element id
|
||||
* @param Job $job Element to add
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function insert(int $id, Job $job) : void
|
||||
{
|
||||
$this->queue[$id] = $job;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop elements from the queue.
|
||||
*
|
||||
* This also removes the elements from the queue
|
||||
*
|
||||
* @param int $size Amount of elements to return
|
||||
* @param int $type Priority type to use for return
|
||||
*
|
||||
* @return Job[]
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function pop(int $size = 1, int $type = PriorityMode::FIFO) : array
|
||||
{
|
||||
$jobs = $this->get($size, $type);
|
||||
|
|
@ -156,15 +118,6 @@ final class ScheduleQueue
|
|||
return $jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the hold counter of an element
|
||||
*
|
||||
* @param int $id Id of the element (0 = all elements)
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function bumpHold(int $id = 0) : void
|
||||
{
|
||||
if ($id === 0) {
|
||||
|
|
@ -176,16 +129,6 @@ final class ScheduleQueue
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the priority of an element
|
||||
*
|
||||
* @param int $id Id of the element (0 = all elements)
|
||||
* @param float $priority Priority to increase by
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function adjustPriority(int $id = 0, float $priority = 0.1) : void
|
||||
{
|
||||
if ($id === 0) {
|
||||
|
|
@ -197,16 +140,7 @@ final class ScheduleQueue
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element from the queue
|
||||
*
|
||||
* @param int $id Id of the element
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function remove(int $id) : void
|
||||
public function remove(string $id) : void
|
||||
{
|
||||
unset($this->queue[$id]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Knapsack
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -106,7 +106,7 @@ class Backpack implements BackpackInterface
|
|||
public function addItem(ItemInterface $item, int | float $quantity = 1) : void
|
||||
{
|
||||
$this->items[] = ['item' => $item, 'quantity' => $quantity];
|
||||
$this->value += $item->getValue() * $quantity;
|
||||
$this->cost += $item->getCost() * $quantity;
|
||||
$this->value += $item->getValue() * $quantity;
|
||||
$this->cost += $item->getCost() * $quantity;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Knapsack
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Knapsack
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Knapsack
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Knapsack
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -49,7 +49,7 @@ class Item implements ItemInterface
|
|||
public string $name = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Cosntructor.
|
||||
*
|
||||
* @param float $value Value of the item
|
||||
* @param float $cost Cost of the item
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Knapsack
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Maze
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -81,7 +81,7 @@ class MazeGenerator
|
|||
if (!empty($neighbors)) {
|
||||
--$n;
|
||||
|
||||
$next = $neighbors[\array_rand($neighbors, 1)];
|
||||
$next = $neighbors[\mt_rand(0, \count($neighbors) - 1)];
|
||||
$unvisited[$next[0] + 1][$next[1] + 1] = false;
|
||||
|
||||
if ($next[0] === $pos[0]) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -80,9 +80,9 @@ class GeneticOptimization
|
|||
*
|
||||
* @example See unit test for example use case
|
||||
*
|
||||
* @param array<array> $population List of all elements with their parameters (i.e. list of "objects" as arrays).
|
||||
* @param array<array> $population List of all elements with ther parameters (i.e. list of "objects" as arrays).
|
||||
* The constraints are defined as array values.
|
||||
* @param \Closure $fitness Fitness function calculates score/feasibility of solution
|
||||
* @param \Closure $fitness Fitness function calculates score/feasability of solution
|
||||
* @param \Closure $mutate Mutation function to change the parameters of an "object"
|
||||
* @param \Closure $crossover Crossover function to exchange parameter values between "objects".
|
||||
* Sometimes single parameters can be exchanged but sometimes interdependencies exist between parameters which is why this function is required.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -40,7 +40,7 @@ class SimulatedAnnealing
|
|||
return $x;
|
||||
}
|
||||
|
||||
// can be many things, e.g. swapping parameters, increasing/decreasing, random generation
|
||||
// can be many things, e.g. swapping parameters, increasing/decrising, random generation
|
||||
public static function neighbor(array $generation, $parameterCount)
|
||||
{
|
||||
$newGeneration = $generation;
|
||||
|
|
@ -57,17 +57,17 @@ class SimulatedAnnealing
|
|||
*/
|
||||
|
||||
// Simulated Annealing algorithm
|
||||
// @todo allow to create a solution space (currently all solutions need to be in space)
|
||||
// @todo currently only replacing generations, not altering them
|
||||
// @todo allow to create a solution space (currently all soluctions need to be in space)
|
||||
// @todo: currently only replacing generations, not altering them
|
||||
/**
|
||||
* Perform optimization
|
||||
*
|
||||
* @example See unit test for example use case
|
||||
*
|
||||
* @param array $space List of all elements with their parameters (i.e. list of "objects" as arrays).
|
||||
* @param array $space List of all elements with ther parameters (i.e. list of "objects" as arrays).
|
||||
* The constraints are defined as array values.
|
||||
* @param int $initialTemperature Starting temperature
|
||||
* @param \Closure $costFunction Fitness function calculates score/feasibility of solution
|
||||
* @param \Closure $costFunction Fitness function calculates score/feasability of solution
|
||||
* @param \Closure $neighbor Neighbor function to find a new solution/neighbor
|
||||
* @param float $coolingRate Rate at which cooling takes place
|
||||
* @param int $iterations Number of iterations
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Optimization
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -54,7 +54,7 @@ class Path
|
|||
private array $expandedNodes = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Cosntructor.
|
||||
*
|
||||
* @param Grid $grid Grid this path belongs to
|
||||
*
|
||||
|
|
@ -152,7 +152,7 @@ class Path
|
|||
}
|
||||
|
||||
/**
|
||||
* Find nodes in between two nodes.
|
||||
* Find nodes in bettween two nodes.
|
||||
*
|
||||
* The path may only contain the jump points or pivot points.
|
||||
* In order to get every node it needs to be expanded.
|
||||
|
|
@ -190,7 +190,7 @@ class Path
|
|||
|
||||
if ($e2 > -$dy) {
|
||||
$err -= $dy;
|
||||
$x0 += $sx;
|
||||
$x0 += $sx;
|
||||
}
|
||||
|
||||
if ($e2 < $dx) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\PathFinding
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -74,37 +74,4 @@ final class Elo
|
|||
'elo' => (int) \max($eloNew, $this->MIN_ELO),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate an approximated win probability based on elo points.
|
||||
*
|
||||
* @param int $elo1 Elo of the player we want to calculate the win probability for
|
||||
* @param int $elo2 Opponent elo
|
||||
* @param bool $canDraw Is a draw possible?
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function winProbability(int $elo1, int $elo2, bool $canDraw = false) : float
|
||||
{
|
||||
return $canDraw
|
||||
? -1.0 // @todo implement
|
||||
: 1 / (1 + \pow(10, ($elo2 - $elo1) / 400));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate an approximated draw probability based on elo points.
|
||||
*
|
||||
* @param int $elo1 Elo of the player we want to calculate the win probability for
|
||||
* @param int $elo2 Opponent elo
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function drawProbability(int $elo1, int $elo2) : float
|
||||
{
|
||||
return -1.0; // @todo implement
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -102,7 +102,7 @@ final class Glicko1
|
|||
}
|
||||
|
||||
/**
|
||||
* Calculate the glicko-1 elo
|
||||
* Calcualte the glicko-1 elo
|
||||
*
|
||||
* @param int $elo Current player "elo"
|
||||
* @param int $rdOld Current player deviation (RD)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
@ -25,6 +25,8 @@ use phpOMS\Math\Solver\Root\Bisection;
|
|||
* @see https://en.wikipedia.org/wiki/Glicko_rating_system
|
||||
* @see http://www.glicko.net/glicko/glicko2.pdf
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo: implement
|
||||
*/
|
||||
final class Glicko2
|
||||
{
|
||||
|
|
@ -91,7 +93,7 @@ final class Glicko2
|
|||
public int $MIN_RD = 50;
|
||||
|
||||
/**
|
||||
* Calculate the glicko-2 elo
|
||||
* Calcualte the glicko-2 elo
|
||||
*
|
||||
* @example $glicko->elo(1500, 200, 0.06, [1,0,0], [1400,1550,1700], [30,100,300]) // 1464, 151, 0.059
|
||||
*
|
||||
|
|
@ -119,7 +121,7 @@ final class Glicko2
|
|||
|
||||
// Step 0:
|
||||
$rdOld /= self::Q;
|
||||
$elo = ($elo - $this->DEFAULT_ELO) / self::Q;
|
||||
$elo = ($elo - $this->DEFAULT_ELO) / self::Q;
|
||||
|
||||
foreach ($oElo as $idx => $value) {
|
||||
$oElo[$idx] = ($value - $this->DEFAULT_ELO) / self::Q;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Microsoft
|
||||
|
|
@ -22,93 +22,25 @@ use phpOMS\Math\Stochastic\Distribution\NormalDistribution;
|
|||
* @package phpOMS\Algorithm\Rating
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @see https://www.moserware.com/assets/computing-your-skill/The%20Math%20Behind%20TrueSkill.pdf
|
||||
* @since 1.0.0
|
||||
* @see https://www.moserware.com/assets/computing-your-skill/The%20Math%20Behind%20TrueSkill.pdf
|
||||
*
|
||||
* @todo Implement https://github.com/sublee/trueskill/blob/master/trueskill/__init__.py
|
||||
* https://github.com/Karaka-Management/phpOMS/issues/337
|
||||
* @todo implement https://github.com/sublee/trueskill/blob/master/trueskill/__init__.py
|
||||
*/
|
||||
// phpcs:ignoreFile
|
||||
class TrueSkill
|
||||
{
|
||||
public const DEFAULT_MU = 25;
|
||||
public int $DEFAULT_MU = 25;
|
||||
|
||||
public const DEFAULT_SIGMA = 25 / 3;
|
||||
public float $DEFAULT_SIGMA = 25 / 3;
|
||||
|
||||
public const DEFAULT_BETA = 25 / 3 / 2;
|
||||
public float $DEFAULT_BETA = 25 / 3 / 2;
|
||||
|
||||
public const DEFAULT_TAU = 25 / 3 / 100;
|
||||
public float $DEFAULT_TAU = 25 / 3 / 100;
|
||||
|
||||
public const DEFAULT_DRAW_PROBABILITY = 0.1;
|
||||
public float $DEFAULT_DRAW_PROBABILITY = 0.1;
|
||||
|
||||
private float $mu = 0.0;
|
||||
|
||||
private float $sigma = 0.0;
|
||||
|
||||
private float $beta = 0.0;
|
||||
|
||||
private float $tau = 0.0;
|
||||
|
||||
private float $drawProbability = 0.0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param null|float $mu Mu
|
||||
* @param null|float $sigma Sigma
|
||||
* @param null|float $beta Beta
|
||||
* @param null|float $tau Tau
|
||||
* @param null|float $drawProbability Draw probability
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(
|
||||
?float $mu = null,
|
||||
?float $sigma = null,
|
||||
?float $beta = null,
|
||||
?float $tau = null,
|
||||
?float $drawProbability = null)
|
||||
public function __construct()
|
||||
{
|
||||
$this->mu = $mu ?? self::DEFAULT_MU;
|
||||
$this->sigma = $sigma ?? self::DEFAULT_SIGMA;
|
||||
$this->beta = $beta ?? self::DEFAULT_BETA;
|
||||
$this->tau = $tau ?? self::DEFAULT_TAU;
|
||||
$this->drawProbability = $drawProbability ?? self::DEFAULT_DRAW_PROBABILITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate win probability
|
||||
*
|
||||
* @param array $team1 Team 1
|
||||
* @param array $team2 Team 2
|
||||
* @param float $drawMargin Draw margin
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function winProbability(array $team1, array $team2, float $drawMargin = 0.0) : float
|
||||
{
|
||||
$sigmaSum = 0.0;
|
||||
$mu1 = 0.0;
|
||||
foreach ($team1 as $player) {
|
||||
$mu1 += $player->mu;
|
||||
$sigmaSum += $player->sigma * $player->sigma;
|
||||
}
|
||||
|
||||
$mu2 = 0.0;
|
||||
foreach ($team2 as $player) {
|
||||
$mu2 += $player->mu;
|
||||
$sigmaSum += $player->sigma * $player->sigma;
|
||||
}
|
||||
|
||||
$deltaMu = $mu1 - $mu2;
|
||||
|
||||
return NormalDistribution::getCdf(
|
||||
($deltaMu - $drawMargin) / \sqrt((\count($team1) + \count($team2)) * ($this->beta * $this->beta) + $sigmaSum),
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
// Draw margin = epsilon
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpOMS\Algorithm\Rating;
|
||||
|
||||
/**
|
||||
* Elo rating calculation using Elo rating
|
||||
*
|
||||
* @package phpOMS\Algorithm\Rating
|
||||
* @license OMS License 2.0
|
||||
* @link https://jingga.app
|
||||
* @see https://en.wikipedia.org/wiki/Elo_rating_system
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class TrueSkillFactoryGraph
|
||||
{
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* PHP Version 8.2
|
||||
* PHP Version 8.1
|
||||
*
|
||||
* @package phpOMS\Algorithm\Sort;
|
||||
* @copyright Dennis Eichhorn
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user