deploy awal
This commit is contained in:
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitc99e1ebe1b175553975f215ab50693d2::getLoader();
|
||||
Vendored
+579
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
+359
@@ -0,0 +1,359 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array()) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
);
|
||||
Vendored
+67
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'abede361264e2ae69ec1eee813a101af' => $vendorDir . '/markbaker/complex/classes/src/functions/abs.php',
|
||||
'21a5860fbef5be28db5ddfbc3cca67c4' => $vendorDir . '/markbaker/complex/classes/src/functions/acos.php',
|
||||
'1546e3f9d127f2a9bb2d1b6c31c26ef1' => $vendorDir . '/markbaker/complex/classes/src/functions/acosh.php',
|
||||
'd2516f7f4fba5ea5905f494b4a8262e0' => $vendorDir . '/markbaker/complex/classes/src/functions/acot.php',
|
||||
'4511163d560956219b96882c0980b65e' => $vendorDir . '/markbaker/complex/classes/src/functions/acoth.php',
|
||||
'c361f5616dc2a8da4fa3e137077cd4ea' => $vendorDir . '/markbaker/complex/classes/src/functions/acsc.php',
|
||||
'02d68920fc98da71991ce569c91df0f6' => $vendorDir . '/markbaker/complex/classes/src/functions/acsch.php',
|
||||
'88e19525eae308b4a6aa3419364875d3' => $vendorDir . '/markbaker/complex/classes/src/functions/argument.php',
|
||||
'60e8e2d0827b58bfc904f13957e51849' => $vendorDir . '/markbaker/complex/classes/src/functions/asec.php',
|
||||
'13d2f040713999eab66c359b4d79871d' => $vendorDir . '/markbaker/complex/classes/src/functions/asech.php',
|
||||
'838ab38beb32c68a79d3cd2c007d5a04' => $vendorDir . '/markbaker/complex/classes/src/functions/asin.php',
|
||||
'bb28eccd0f8f008333a1b3c163d604ac' => $vendorDir . '/markbaker/complex/classes/src/functions/asinh.php',
|
||||
'9e483de83558c98f7d3feaa402c78cb3' => $vendorDir . '/markbaker/complex/classes/src/functions/atan.php',
|
||||
'36b74b5b765ded91ee58c8ee3c0e85e3' => $vendorDir . '/markbaker/complex/classes/src/functions/atanh.php',
|
||||
'05c15ee9510da7fd6bf6136f436500c0' => $vendorDir . '/markbaker/complex/classes/src/functions/conjugate.php',
|
||||
'd3208dfbce2505e370788f9f22f6785f' => $vendorDir . '/markbaker/complex/classes/src/functions/cos.php',
|
||||
'141cf1fb3a3046f8b64534b0ebab33ca' => $vendorDir . '/markbaker/complex/classes/src/functions/cosh.php',
|
||||
'be660df75fd0dbe7fa7c03b7434b3294' => $vendorDir . '/markbaker/complex/classes/src/functions/cot.php',
|
||||
'01e31ea298a51bc9e91517e3ce6b9e76' => $vendorDir . '/markbaker/complex/classes/src/functions/coth.php',
|
||||
'803ddd97f7b1da68982a7b087c3476f6' => $vendorDir . '/markbaker/complex/classes/src/functions/csc.php',
|
||||
'3001cdfd101ec3c32da34ee43c2e149b' => $vendorDir . '/markbaker/complex/classes/src/functions/csch.php',
|
||||
'77b2d7629ef2a93fabb8c56754a91051' => $vendorDir . '/markbaker/complex/classes/src/functions/exp.php',
|
||||
'4a4471296dec796c21d4f4b6552396a9' => $vendorDir . '/markbaker/complex/classes/src/functions/inverse.php',
|
||||
'c3e9897e1744b88deb56fcdc39d34d85' => $vendorDir . '/markbaker/complex/classes/src/functions/ln.php',
|
||||
'a83cacf2de942cff288de15a83afd26d' => $vendorDir . '/markbaker/complex/classes/src/functions/log2.php',
|
||||
'6a861dacc9ee2f3061241d4c7772fa21' => $vendorDir . '/markbaker/complex/classes/src/functions/log10.php',
|
||||
'4d2522d968c8ba78d6c13548a1b4200e' => $vendorDir . '/markbaker/complex/classes/src/functions/negative.php',
|
||||
'fd587ca933fc0447fa5ab4843bdd97f7' => $vendorDir . '/markbaker/complex/classes/src/functions/pow.php',
|
||||
'383ef01c62028fc78cd4388082fce3c2' => $vendorDir . '/markbaker/complex/classes/src/functions/rho.php',
|
||||
'150fbd1b95029dc47292da97ecab9375' => $vendorDir . '/markbaker/complex/classes/src/functions/sec.php',
|
||||
'549abd9bae174286d660bdaa07407c68' => $vendorDir . '/markbaker/complex/classes/src/functions/sech.php',
|
||||
'6bfbf5eaea6b17a0ed85cb21ba80370c' => $vendorDir . '/markbaker/complex/classes/src/functions/sin.php',
|
||||
'22efe13f1a497b8e199540ae2d9dc59c' => $vendorDir . '/markbaker/complex/classes/src/functions/sinh.php',
|
||||
'e90135ab8e787795a509ed7147de207d' => $vendorDir . '/markbaker/complex/classes/src/functions/sqrt.php',
|
||||
'bb0a7923ffc6a90919cd64ec54ff06bc' => $vendorDir . '/markbaker/complex/classes/src/functions/tan.php',
|
||||
'2d302f32ce0fd4e433dd91c5bb404a28' => $vendorDir . '/markbaker/complex/classes/src/functions/tanh.php',
|
||||
'24dd4658a952171a4ee79218c4f9fd06' => $vendorDir . '/markbaker/complex/classes/src/functions/theta.php',
|
||||
'e49b7876281d6f5bc39536dde96d1f4a' => $vendorDir . '/markbaker/complex/classes/src/operations/add.php',
|
||||
'47596e02b43cd6da7700134fd08f88cf' => $vendorDir . '/markbaker/complex/classes/src/operations/subtract.php',
|
||||
'883af48563631547925fa4c3b48ead07' => $vendorDir . '/markbaker/complex/classes/src/operations/multiply.php',
|
||||
'f190e3308e6ca23234a2875edc985c03' => $vendorDir . '/markbaker/complex/classes/src/operations/divideby.php',
|
||||
'ac9e33ce6841aa5bf5d16d465a2f03a7' => $vendorDir . '/markbaker/complex/classes/src/operations/divideinto.php',
|
||||
'3af723442581d6c310bf44543f9f5c60' => $vendorDir . '/markbaker/matrix/classes/src/Functions/adjoint.php',
|
||||
'd803221834c8b57fec95debb5406a797' => $vendorDir . '/markbaker/matrix/classes/src/Functions/antidiagonal.php',
|
||||
'4714cafbd3be4c72c274a25eae9396bb' => $vendorDir . '/markbaker/matrix/classes/src/Functions/cofactors.php',
|
||||
'89719dc7c77436609d1c1c31f0797b8f' => $vendorDir . '/markbaker/matrix/classes/src/Functions/determinant.php',
|
||||
'c28af79ec7730859d83f2d4310b8dd0b' => $vendorDir . '/markbaker/matrix/classes/src/Functions/diagonal.php',
|
||||
'c5d82bf1ac485e445f911e55789ab4e6' => $vendorDir . '/markbaker/matrix/classes/src/Functions/identity.php',
|
||||
'0d2d594de24a247f7a33499e933aa21e' => $vendorDir . '/markbaker/matrix/classes/src/Functions/inverse.php',
|
||||
'f37c25880804a014ef40c8bffbab1b10' => $vendorDir . '/markbaker/matrix/classes/src/Functions/minors.php',
|
||||
'd6e4e42171df0dbea253b3067fefda38' => $vendorDir . '/markbaker/matrix/classes/src/Functions/trace.php',
|
||||
'2c9b19fa954fd3e6fcc7e7a1383caddd' => $vendorDir . '/markbaker/matrix/classes/src/Functions/transpose.php',
|
||||
'0a538fc9b897450ec362480ebbebe94f' => $vendorDir . '/markbaker/matrix/classes/src/Operations/add.php',
|
||||
'f0843f7f4089ec2343c7445544356385' => $vendorDir . '/markbaker/matrix/classes/src/Operations/directsum.php',
|
||||
'ad3e8c29aa16d134661a414265677b61' => $vendorDir . '/markbaker/matrix/classes/src/Operations/subtract.php',
|
||||
'8d37dad4703fab45bfec9dd0bbf3278e' => $vendorDir . '/markbaker/matrix/classes/src/Operations/multiply.php',
|
||||
'4888a6f58c08148ebe17682f9ce9b2a8' => $vendorDir . '/markbaker/matrix/classes/src/Operations/divideby.php',
|
||||
'eef6fa3879d3efa347cd24d5eb348f85' => $vendorDir . '/markbaker/matrix/classes/src/Operations/divideinto.php',
|
||||
);
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
|
||||
'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'),
|
||||
'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'),
|
||||
'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
|
||||
);
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInitc99e1ebe1b175553975f215ab50693d2
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitc99e1ebe1b175553975f215ab50693d2', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitc99e1ebe1b175553975f215ab50693d2', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitc99e1ebe1b175553975f215ab50693d2::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInitc99e1ebe1b175553975f215ab50693d2::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
}, null, null);
|
||||
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||
$requireFile($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInitc99e1ebe1b175553975f215ab50693d2
|
||||
{
|
||||
public static $files = array (
|
||||
'abede361264e2ae69ec1eee813a101af' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/abs.php',
|
||||
'21a5860fbef5be28db5ddfbc3cca67c4' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acos.php',
|
||||
'1546e3f9d127f2a9bb2d1b6c31c26ef1' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acosh.php',
|
||||
'd2516f7f4fba5ea5905f494b4a8262e0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acot.php',
|
||||
'4511163d560956219b96882c0980b65e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acoth.php',
|
||||
'c361f5616dc2a8da4fa3e137077cd4ea' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsc.php',
|
||||
'02d68920fc98da71991ce569c91df0f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsch.php',
|
||||
'88e19525eae308b4a6aa3419364875d3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/argument.php',
|
||||
'60e8e2d0827b58bfc904f13957e51849' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asec.php',
|
||||
'13d2f040713999eab66c359b4d79871d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asech.php',
|
||||
'838ab38beb32c68a79d3cd2c007d5a04' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asin.php',
|
||||
'bb28eccd0f8f008333a1b3c163d604ac' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asinh.php',
|
||||
'9e483de83558c98f7d3feaa402c78cb3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atan.php',
|
||||
'36b74b5b765ded91ee58c8ee3c0e85e3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atanh.php',
|
||||
'05c15ee9510da7fd6bf6136f436500c0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/conjugate.php',
|
||||
'd3208dfbce2505e370788f9f22f6785f' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cos.php',
|
||||
'141cf1fb3a3046f8b64534b0ebab33ca' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cosh.php',
|
||||
'be660df75fd0dbe7fa7c03b7434b3294' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cot.php',
|
||||
'01e31ea298a51bc9e91517e3ce6b9e76' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/coth.php',
|
||||
'803ddd97f7b1da68982a7b087c3476f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csc.php',
|
||||
'3001cdfd101ec3c32da34ee43c2e149b' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csch.php',
|
||||
'77b2d7629ef2a93fabb8c56754a91051' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/exp.php',
|
||||
'4a4471296dec796c21d4f4b6552396a9' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/inverse.php',
|
||||
'c3e9897e1744b88deb56fcdc39d34d85' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/ln.php',
|
||||
'a83cacf2de942cff288de15a83afd26d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log2.php',
|
||||
'6a861dacc9ee2f3061241d4c7772fa21' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log10.php',
|
||||
'4d2522d968c8ba78d6c13548a1b4200e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/negative.php',
|
||||
'fd587ca933fc0447fa5ab4843bdd97f7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/pow.php',
|
||||
'383ef01c62028fc78cd4388082fce3c2' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/rho.php',
|
||||
'150fbd1b95029dc47292da97ecab9375' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sec.php',
|
||||
'549abd9bae174286d660bdaa07407c68' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sech.php',
|
||||
'6bfbf5eaea6b17a0ed85cb21ba80370c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sin.php',
|
||||
'22efe13f1a497b8e199540ae2d9dc59c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sinh.php',
|
||||
'e90135ab8e787795a509ed7147de207d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sqrt.php',
|
||||
'bb0a7923ffc6a90919cd64ec54ff06bc' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tan.php',
|
||||
'2d302f32ce0fd4e433dd91c5bb404a28' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tanh.php',
|
||||
'24dd4658a952171a4ee79218c4f9fd06' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/theta.php',
|
||||
'e49b7876281d6f5bc39536dde96d1f4a' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/add.php',
|
||||
'47596e02b43cd6da7700134fd08f88cf' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/subtract.php',
|
||||
'883af48563631547925fa4c3b48ead07' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/multiply.php',
|
||||
'f190e3308e6ca23234a2875edc985c03' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideby.php',
|
||||
'ac9e33ce6841aa5bf5d16d465a2f03a7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideinto.php',
|
||||
'3af723442581d6c310bf44543f9f5c60' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/adjoint.php',
|
||||
'd803221834c8b57fec95debb5406a797' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/antidiagonal.php',
|
||||
'4714cafbd3be4c72c274a25eae9396bb' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/cofactors.php',
|
||||
'89719dc7c77436609d1c1c31f0797b8f' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/determinant.php',
|
||||
'c28af79ec7730859d83f2d4310b8dd0b' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/diagonal.php',
|
||||
'c5d82bf1ac485e445f911e55789ab4e6' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/identity.php',
|
||||
'0d2d594de24a247f7a33499e933aa21e' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/inverse.php',
|
||||
'f37c25880804a014ef40c8bffbab1b10' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/minors.php',
|
||||
'd6e4e42171df0dbea253b3067fefda38' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/trace.php',
|
||||
'2c9b19fa954fd3e6fcc7e7a1383caddd' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/transpose.php',
|
||||
'0a538fc9b897450ec362480ebbebe94f' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/add.php',
|
||||
'f0843f7f4089ec2343c7445544356385' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/directsum.php',
|
||||
'ad3e8c29aa16d134661a414265677b61' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/subtract.php',
|
||||
'8d37dad4703fab45bfec9dd0bbf3278e' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/multiply.php',
|
||||
'4888a6f58c08148ebe17682f9ce9b2a8' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/divideby.php',
|
||||
'eef6fa3879d3efa347cd24d5eb348f85' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/divideinto.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'P' =>
|
||||
array (
|
||||
'Psr\\SimpleCache\\' => 16,
|
||||
'PhpOffice\\PhpSpreadsheet\\' => 25,
|
||||
),
|
||||
'M' =>
|
||||
array (
|
||||
'Matrix\\' => 7,
|
||||
),
|
||||
'C' =>
|
||||
array (
|
||||
'Complex\\' => 8,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Psr\\SimpleCache\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
|
||||
),
|
||||
'PhpOffice\\PhpSpreadsheet\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet',
|
||||
),
|
||||
'Matrix\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src',
|
||||
),
|
||||
'Complex\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitc99e1ebe1b175553975f215ab50693d2::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitc99e1ebe1b175553975f215ab50693d2::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInitc99e1ebe1b175553975f215ab50693d2::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
Vendored
+338
@@ -0,0 +1,338 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "markbaker/complex",
|
||||
"version": "1.5.0",
|
||||
"version_normalized": "1.5.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MarkBaker/PHPComplex.git",
|
||||
"reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/c3131244e29c08d44fefb49e0dd35021e9e39dd2",
|
||||
"reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
|
||||
"phpcompatibility/php-compatibility": "^9.0",
|
||||
"phpdocumentor/phpdocumentor": "2.*",
|
||||
"phploc/phploc": "^4.0|^5.0|^6.0|^7.0",
|
||||
"phpmd/phpmd": "2.*",
|
||||
"phpunit/phpunit": "^4.8.35|^5.0|^6.0|^7.0",
|
||||
"sebastian/phpcpd": "2.*",
|
||||
"squizlabs/php_codesniffer": "^3.4.0"
|
||||
},
|
||||
"time": "2020-08-26T19:47:57+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"classes/src/functions/abs.php",
|
||||
"classes/src/functions/acos.php",
|
||||
"classes/src/functions/acosh.php",
|
||||
"classes/src/functions/acot.php",
|
||||
"classes/src/functions/acoth.php",
|
||||
"classes/src/functions/acsc.php",
|
||||
"classes/src/functions/acsch.php",
|
||||
"classes/src/functions/argument.php",
|
||||
"classes/src/functions/asec.php",
|
||||
"classes/src/functions/asech.php",
|
||||
"classes/src/functions/asin.php",
|
||||
"classes/src/functions/asinh.php",
|
||||
"classes/src/functions/atan.php",
|
||||
"classes/src/functions/atanh.php",
|
||||
"classes/src/functions/conjugate.php",
|
||||
"classes/src/functions/cos.php",
|
||||
"classes/src/functions/cosh.php",
|
||||
"classes/src/functions/cot.php",
|
||||
"classes/src/functions/coth.php",
|
||||
"classes/src/functions/csc.php",
|
||||
"classes/src/functions/csch.php",
|
||||
"classes/src/functions/exp.php",
|
||||
"classes/src/functions/inverse.php",
|
||||
"classes/src/functions/ln.php",
|
||||
"classes/src/functions/log2.php",
|
||||
"classes/src/functions/log10.php",
|
||||
"classes/src/functions/negative.php",
|
||||
"classes/src/functions/pow.php",
|
||||
"classes/src/functions/rho.php",
|
||||
"classes/src/functions/sec.php",
|
||||
"classes/src/functions/sech.php",
|
||||
"classes/src/functions/sin.php",
|
||||
"classes/src/functions/sinh.php",
|
||||
"classes/src/functions/sqrt.php",
|
||||
"classes/src/functions/tan.php",
|
||||
"classes/src/functions/tanh.php",
|
||||
"classes/src/functions/theta.php",
|
||||
"classes/src/operations/add.php",
|
||||
"classes/src/operations/subtract.php",
|
||||
"classes/src/operations/multiply.php",
|
||||
"classes/src/operations/divideby.php",
|
||||
"classes/src/operations/divideinto.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Complex\\": "classes/src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@lange.demon.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "PHP Class for working with complex numbers",
|
||||
"homepage": "https://github.com/MarkBaker/PHPComplex",
|
||||
"keywords": [
|
||||
"complex",
|
||||
"mathematics"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
|
||||
"source": "https://github.com/MarkBaker/PHPComplex/tree/1.5.0"
|
||||
},
|
||||
"install-path": "../markbaker/complex"
|
||||
},
|
||||
{
|
||||
"name": "markbaker/matrix",
|
||||
"version": "1.2.3",
|
||||
"version_normalized": "1.2.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MarkBaker/PHPMatrix.git",
|
||||
"reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/44bb1ab01811116f01fe216ab37d921dccc6c10d",
|
||||
"reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.6.0|^7.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||
"phpcompatibility/php-compatibility": "dev-master",
|
||||
"phploc/phploc": "^4",
|
||||
"phpmd/phpmd": "dev-master",
|
||||
"phpunit/phpunit": "^5.7|^6.0|7.0",
|
||||
"sebastian/phpcpd": "^3.0",
|
||||
"squizlabs/php_codesniffer": "^3.0@dev"
|
||||
},
|
||||
"time": "2021-01-26T14:36:01+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"classes/src/Functions/adjoint.php",
|
||||
"classes/src/Functions/antidiagonal.php",
|
||||
"classes/src/Functions/cofactors.php",
|
||||
"classes/src/Functions/determinant.php",
|
||||
"classes/src/Functions/diagonal.php",
|
||||
"classes/src/Functions/identity.php",
|
||||
"classes/src/Functions/inverse.php",
|
||||
"classes/src/Functions/minors.php",
|
||||
"classes/src/Functions/trace.php",
|
||||
"classes/src/Functions/transpose.php",
|
||||
"classes/src/Operations/add.php",
|
||||
"classes/src/Operations/directsum.php",
|
||||
"classes/src/Operations/subtract.php",
|
||||
"classes/src/Operations/multiply.php",
|
||||
"classes/src/Operations/divideby.php",
|
||||
"classes/src/Operations/divideinto.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Matrix\\": "classes/src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@lange.demon.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "PHP Class for working with matrices",
|
||||
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
||||
"keywords": [
|
||||
"mathematics",
|
||||
"matrix",
|
||||
"vector"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
|
||||
"source": "https://github.com/MarkBaker/PHPMatrix/tree/1.2.3"
|
||||
},
|
||||
"install-path": "../markbaker/matrix"
|
||||
},
|
||||
{
|
||||
"name": "phpoffice/phpspreadsheet",
|
||||
"version": "1.12.0",
|
||||
"version_normalized": "1.12.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
||||
"reference": "f79611d6dc1f6b7e8e30b738fc371b392001dbfd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/f79611d6dc1f6b7e8e30b738fc371b392001dbfd",
|
||||
"reference": "f79611d6dc1f6b7e8e30b738fc371b392001dbfd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlreader": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-zlib": "*",
|
||||
"markbaker/complex": "^1.4",
|
||||
"markbaker/matrix": "^1.2",
|
||||
"php": "^7.1",
|
||||
"psr/simple-cache": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dompdf/dompdf": "^0.8.3",
|
||||
"friendsofphp/php-cs-fixer": "^2.16",
|
||||
"jpgraph/jpgraph": "^4.0",
|
||||
"mpdf/mpdf": "^8.0",
|
||||
"phpcompatibility/php-compatibility": "^9.3",
|
||||
"phpunit/phpunit": "^7.5",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"tecnickcom/tcpdf": "^6.3"
|
||||
},
|
||||
"suggest": {
|
||||
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
|
||||
"jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
|
||||
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
||||
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
|
||||
},
|
||||
"time": "2020-04-27T08:12:48+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maarten Balliauw",
|
||||
"homepage": "https://blog.maartenballiauw.be"
|
||||
},
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"homepage": "https://markbakeruk.net"
|
||||
},
|
||||
{
|
||||
"name": "Franck Lefevre",
|
||||
"homepage": "https://rootslabs.net"
|
||||
},
|
||||
{
|
||||
"name": "Erik Tilt"
|
||||
},
|
||||
{
|
||||
"name": "Adrien Crivelli"
|
||||
}
|
||||
],
|
||||
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
||||
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
||||
"keywords": [
|
||||
"OpenXML",
|
||||
"excel",
|
||||
"gnumeric",
|
||||
"ods",
|
||||
"php",
|
||||
"spreadsheet",
|
||||
"xls",
|
||||
"xlsx"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
||||
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.12.0"
|
||||
},
|
||||
"install-path": "../phpoffice/phpspreadsheet"
|
||||
},
|
||||
{
|
||||
"name": "psr/simple-cache",
|
||||
"version": "1.0.1",
|
||||
"version_normalized": "1.0.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/simple-cache.git",
|
||||
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
||||
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"time": "2017-10-23T01:57:42+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\SimpleCache\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interfaces for simple caching",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"caching",
|
||||
"psr",
|
||||
"psr-16",
|
||||
"simple-cache"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/simple-cache/tree/master"
|
||||
},
|
||||
"install-path": "../psr/simple-cache"
|
||||
}
|
||||
],
|
||||
"dev": false,
|
||||
"dev-package-names": []
|
||||
}
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'codeigniter/framework',
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => 'c54282bd3ecbc74a33f404e18b245dac50f42049',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => false,
|
||||
),
|
||||
'versions' => array(
|
||||
'codeigniter/framework' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => 'c54282bd3ecbc74a33f404e18b245dac50f42049',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'markbaker/complex' => array(
|
||||
'pretty_version' => '1.5.0',
|
||||
'version' => '1.5.0.0',
|
||||
'reference' => 'c3131244e29c08d44fefb49e0dd35021e9e39dd2',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../markbaker/complex',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'markbaker/matrix' => array(
|
||||
'pretty_version' => '1.2.3',
|
||||
'version' => '1.2.3.0',
|
||||
'reference' => '44bb1ab01811116f01fe216ab37d921dccc6c10d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../markbaker/matrix',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'phpoffice/phpspreadsheet' => array(
|
||||
'pretty_version' => '1.12.0',
|
||||
'version' => '1.12.0.0',
|
||||
'reference' => 'f79611d6dc1f6b7e8e30b738fc371b392001dbfd',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/simple-cache' => array(
|
||||
'pretty_version' => '1.0.1',
|
||||
'version' => '1.0.1.0',
|
||||
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/simple-cache',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 70100)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
Vendored
+156
@@ -0,0 +1,156 @@
|
||||
PHPComplex
|
||||
==========
|
||||
|
||||
---
|
||||
|
||||
PHP Class for handling Complex numbers
|
||||
|
||||
Master: [](http://travis-ci.org/MarkBaker/PHPComplex)
|
||||
|
||||
Develop: [](http://travis-ci.org/MarkBaker/PHPComplex)
|
||||
|
||||
[](https://xkcd.com/2028/)
|
||||
|
||||
---
|
||||
|
||||
The library currently provides the following operations:
|
||||
|
||||
- addition
|
||||
- subtraction
|
||||
- multiplication
|
||||
- division
|
||||
- division by
|
||||
- division into
|
||||
|
||||
together with functions for
|
||||
|
||||
- theta (polar theta angle)
|
||||
- rho (polar distance/radius)
|
||||
- conjugate
|
||||
* negative
|
||||
- inverse (1 / complex)
|
||||
- cos (cosine)
|
||||
- acos (inverse cosine)
|
||||
- cosh (hyperbolic cosine)
|
||||
- acosh (inverse hyperbolic cosine)
|
||||
- sin (sine)
|
||||
- asin (inverse sine)
|
||||
- sinh (hyperbolic sine)
|
||||
- asinh (inverse hyperbolic sine)
|
||||
- sec (secant)
|
||||
- asec (inverse secant)
|
||||
- sech (hyperbolic secant)
|
||||
- asech (inverse hyperbolic secant)
|
||||
- csc (cosecant)
|
||||
- acsc (inverse cosecant)
|
||||
- csch (hyperbolic secant)
|
||||
- acsch (inverse hyperbolic secant)
|
||||
- tan (tangent)
|
||||
- atan (inverse tangent)
|
||||
- tanh (hyperbolic tangent)
|
||||
- atanh (inverse hyperbolic tangent)
|
||||
- cot (cotangent)
|
||||
- acot (inverse cotangent)
|
||||
- coth (hyperbolic cotangent)
|
||||
- acoth (inverse hyperbolic cotangent)
|
||||
- sqrt (square root)
|
||||
- exp (exponential)
|
||||
- ln (natural log)
|
||||
- log10 (base-10 log)
|
||||
- log2 (base-2 log)
|
||||
- pow (raised to the power of a real number)
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Usage
|
||||
|
||||
To create a new complex object, you can provide either the real, imaginary and suffix parts as individual values, or as an array of values passed passed to the constructor; or a string representing the value. e.g
|
||||
|
||||
```
|
||||
$real = 1.23;
|
||||
$imaginary = -4.56;
|
||||
$suffix = 'i';
|
||||
|
||||
$complexObject = new Complex\Complex($real, $imaginary, $suffix);
|
||||
```
|
||||
or
|
||||
```
|
||||
$real = 1.23;
|
||||
$imaginary = -4.56;
|
||||
$suffix = 'i';
|
||||
|
||||
$arguments = [$real, $imaginary, $suffix];
|
||||
|
||||
$complexObject = new Complex\Complex($arguments);
|
||||
```
|
||||
or
|
||||
```
|
||||
$complexString = '1.23-4.56i';
|
||||
|
||||
$complexObject = new Complex\Complex($complexString);
|
||||
```
|
||||
|
||||
Complex objects are immutable: whenever you call a method or pass a complex value to a function that returns a complex value, a new Complex object will be returned, and the original will remain unchanged.
|
||||
This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Complex result).
|
||||
|
||||
## Performing Mathematical Operations
|
||||
|
||||
To perform mathematical operations with Complex values, you can call the appropriate method against a complex value, passing other values as arguments
|
||||
|
||||
```
|
||||
$complexString1 = '1.23-4.56i';
|
||||
$complexString2 = '2.34+5.67i';
|
||||
|
||||
$complexObject = new Complex\Complex($complexString1);
|
||||
echo $complexObject->add($complexString2);
|
||||
```
|
||||
or pass all values to the appropriate function
|
||||
```
|
||||
$complexString1 = '1.23-4.56i';
|
||||
$complexString2 = '2.34+5.67i';
|
||||
|
||||
echo Complex\add($complexString1, $complexString2);
|
||||
```
|
||||
If you want to perform the same operation against multiple values (e.g. to add three or more complex numbers), then you can pass multiple arguments to any of the operations.
|
||||
|
||||
You can pass these arguments as Complex objects, or as an array or string that will parse to a complex object.
|
||||
|
||||
## Using functions
|
||||
|
||||
When calling any of the available functions for a complex value, you can either call the relevant method for the Complex object
|
||||
```
|
||||
$complexString = '1.23-4.56i';
|
||||
|
||||
$complexObject = new Complex\Complex($complexString);
|
||||
echo $complexObject->sinh();
|
||||
```
|
||||
or you can call the function as you would in procedural code, passing the Complex object as an argument
|
||||
```
|
||||
$complexString = '1.23-4.56i';
|
||||
|
||||
$complexObject = new Complex\Complex($complexString);
|
||||
echo Complex\sinh($complexObject);
|
||||
```
|
||||
When called procedurally using the function, you can pass in the argument as a Complex object, or as an array or string that will parse to a complex object.
|
||||
```
|
||||
$complexString = '1.23-4.56i';
|
||||
|
||||
echo Complex\sinh($complexString);
|
||||
```
|
||||
|
||||
In the case of the `pow()` function (the only implemented function that requires an additional argument) you need to pass both arguments when calling the function procedurally
|
||||
|
||||
```
|
||||
$complexString = '1.23-4.56i';
|
||||
|
||||
$complexObject = new Complex\Complex($complexString);
|
||||
echo Complex\pow($complexObject, 2);
|
||||
```
|
||||
or pass the additional argument when calling the method
|
||||
```
|
||||
$complexString = '1.23-4.56i';
|
||||
|
||||
$complexObject = new Complex\Complex($complexString);
|
||||
echo $complexObject->pow(2);
|
||||
```
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
*
|
||||
* Autoloader for Complex classes
|
||||
*
|
||||
* @package Complex
|
||||
* @copyright Copyright (c) 2014 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
class Autoloader
|
||||
{
|
||||
/**
|
||||
* Register the Autoloader with SPL
|
||||
*
|
||||
*/
|
||||
public static function Register()
|
||||
{
|
||||
if (function_exists('__autoload')) {
|
||||
// Register any existing autoloader function with SPL, so we don't get any clashes
|
||||
spl_autoload_register('__autoload');
|
||||
}
|
||||
// Register ourselves with SPL
|
||||
return spl_autoload_register(['Complex\\Autoloader', 'Load']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Autoload a class identified by name
|
||||
*
|
||||
* @param string $pClassName Name of the object to load
|
||||
*/
|
||||
public static function Load($pClassName)
|
||||
{
|
||||
if ((class_exists($pClassName, false)) || (strpos($pClassName, 'Complex\\') !== 0)) {
|
||||
// Either already loaded, or not a Complex class request
|
||||
return false;
|
||||
}
|
||||
|
||||
$pClassFilePath = __DIR__ . DIRECTORY_SEPARATOR .
|
||||
'src' . DIRECTORY_SEPARATOR .
|
||||
str_replace(['Complex\\', '\\'], ['', '/'], $pClassName) .
|
||||
'.php';
|
||||
|
||||
if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
|
||||
// Can't load
|
||||
return false;
|
||||
}
|
||||
require($pClassFilePath);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
include_once __DIR__ . '/Autoloader.php';
|
||||
|
||||
\Complex\Autoloader::Register();
|
||||
|
||||
|
||||
abstract class FilesystemRegexFilter extends RecursiveRegexIterator
|
||||
{
|
||||
protected $regex;
|
||||
public function __construct(RecursiveIterator $it, $regex)
|
||||
{
|
||||
$this->regex = $regex;
|
||||
parent::__construct($it, $regex);
|
||||
}
|
||||
}
|
||||
|
||||
class FilenameFilter extends FilesystemRegexFilter
|
||||
{
|
||||
// Filter files against the regex
|
||||
public function accept()
|
||||
{
|
||||
return (!$this->isFile() || preg_match($this->regex, $this->getFilename()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$srcFolder = __DIR__ . DIRECTORY_SEPARATOR . 'src';
|
||||
$srcDirectory = new RecursiveDirectoryIterator($srcFolder);
|
||||
|
||||
$filteredFileList = new FilenameFilter($srcDirectory, '/(?:php)$/i');
|
||||
$filteredFileList = new FilenameFilter($filteredFileList, '/^(?!.*(Complex|Exception)\.php).*$/i');
|
||||
|
||||
foreach (new RecursiveIteratorIterator($filteredFileList) as $file) {
|
||||
if ($file->isFile()) {
|
||||
include_once $file;
|
||||
}
|
||||
}
|
||||
+390
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Class for the management of Complex numbers
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Complex Number object.
|
||||
*
|
||||
* @package Complex
|
||||
*
|
||||
* @method float abs()
|
||||
* @method Complex acos()
|
||||
* @method Complex acosh()
|
||||
* @method Complex acot()
|
||||
* @method Complex acoth()
|
||||
* @method Complex acsc()
|
||||
* @method Complex acsch()
|
||||
* @method float argument()
|
||||
* @method Complex asec()
|
||||
* @method Complex asech()
|
||||
* @method Complex asin()
|
||||
* @method Complex asinh()
|
||||
* @method Complex atan()
|
||||
* @method Complex atanh()
|
||||
* @method Complex conjugate()
|
||||
* @method Complex cos()
|
||||
* @method Complex cosh()
|
||||
* @method Complex cot()
|
||||
* @method Complex coth()
|
||||
* @method Complex csc()
|
||||
* @method Complex csch()
|
||||
* @method Complex exp()
|
||||
* @method Complex inverse()
|
||||
* @method Complex ln()
|
||||
* @method Complex log2()
|
||||
* @method Complex log10()
|
||||
* @method Complex negative()
|
||||
* @method Complex pow(int|float $power)
|
||||
* @method float rho()
|
||||
* @method Complex sec()
|
||||
* @method Complex sech()
|
||||
* @method Complex sin()
|
||||
* @method Complex sinh()
|
||||
* @method Complex sqrt()
|
||||
* @method Complex tan()
|
||||
* @method Complex tanh()
|
||||
* @method float theta()
|
||||
* @method Complex add(...$complexValues)
|
||||
* @method Complex subtract(...$complexValues)
|
||||
* @method Complex multiply(...$complexValues)
|
||||
* @method Complex divideby(...$complexValues)
|
||||
* @method Complex divideinto(...$complexValues)
|
||||
*/
|
||||
class Complex
|
||||
{
|
||||
/**
|
||||
* @constant Euler's Number.
|
||||
*/
|
||||
const EULER = 2.7182818284590452353602874713526624977572;
|
||||
|
||||
/**
|
||||
* @constant Regexp to split an input string into real and imaginary components and suffix
|
||||
*/
|
||||
const NUMBER_SPLIT_REGEXP =
|
||||
'` ^
|
||||
( # Real part
|
||||
[-+]?(\d+\.?\d*|\d*\.?\d+) # Real value (integer or float)
|
||||
([Ee][-+]?[0-2]?\d{1,3})? # Optional real exponent for scientific format
|
||||
)
|
||||
( # Imaginary part
|
||||
[-+]?(\d+\.?\d*|\d*\.?\d+) # Imaginary value (integer or float)
|
||||
([Ee][-+]?[0-2]?\d{1,3})? # Optional imaginary exponent for scientific format
|
||||
)?
|
||||
( # Imaginary part is optional
|
||||
([-+]?) # Imaginary (implicit 1 or -1) only
|
||||
([ij]?) # Imaginary i or j - depending on whether mathematical or engineering
|
||||
)
|
||||
$`uix';
|
||||
|
||||
/**
|
||||
* @var float $realPart The value of of this complex number on the real plane.
|
||||
*/
|
||||
protected $realPart = 0.0;
|
||||
|
||||
/**
|
||||
* @var float $imaginaryPart The value of of this complex number on the imaginary plane.
|
||||
*/
|
||||
protected $imaginaryPart = 0.0;
|
||||
|
||||
/**
|
||||
* @var string $suffix The suffix for this complex number (i or j).
|
||||
*/
|
||||
protected $suffix;
|
||||
|
||||
|
||||
/**
|
||||
* Validates whether the argument is a valid complex number, converting scalar or array values if possible
|
||||
*
|
||||
* @param mixed $complexNumber The value to parse
|
||||
* @return array
|
||||
* @throws Exception If the argument isn't a Complex number or cannot be converted to one
|
||||
*/
|
||||
private static function parseComplex($complexNumber)
|
||||
{
|
||||
// Test for real number, with no imaginary part
|
||||
if (is_numeric($complexNumber)) {
|
||||
return [$complexNumber, 0, null];
|
||||
}
|
||||
|
||||
// Fix silly human errors
|
||||
$complexNumber = str_replace(
|
||||
['+-', '-+', '++', '--'],
|
||||
['-', '-', '+', '+'],
|
||||
$complexNumber
|
||||
);
|
||||
|
||||
// Basic validation of string, to parse out real and imaginary parts, and any suffix
|
||||
$validComplex = preg_match(
|
||||
self::NUMBER_SPLIT_REGEXP,
|
||||
$complexNumber,
|
||||
$complexParts
|
||||
);
|
||||
|
||||
if (!$validComplex) {
|
||||
// Neither real nor imaginary part, so test to see if we actually have a suffix
|
||||
$validComplex = preg_match('/^([\-\+]?)([ij])$/ui', $complexNumber, $complexParts);
|
||||
if (!$validComplex) {
|
||||
throw new Exception('Invalid complex number');
|
||||
}
|
||||
// We have a suffix, so set the real to 0, the imaginary to either 1 or -1 (as defined by the sign)
|
||||
$imaginary = 1;
|
||||
if ($complexParts[1] === '-') {
|
||||
$imaginary = 0 - $imaginary;
|
||||
}
|
||||
return [0, $imaginary, $complexParts[2]];
|
||||
}
|
||||
|
||||
// If we don't have an imaginary part, identify whether it should be +1 or -1...
|
||||
if (($complexParts[4] === '') && ($complexParts[9] !== '')) {
|
||||
if ($complexParts[7] !== $complexParts[9]) {
|
||||
$complexParts[4] = 1;
|
||||
if ($complexParts[8] === '-') {
|
||||
$complexParts[4] = -1;
|
||||
}
|
||||
} else {
|
||||
// ... or if we have only the real and no imaginary part
|
||||
// (in which case our real should be the imaginary)
|
||||
$complexParts[4] = $complexParts[1];
|
||||
$complexParts[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Return real and imaginary parts and suffix as an array, and set a default suffix if user input lazily
|
||||
return [
|
||||
$complexParts[1],
|
||||
$complexParts[4],
|
||||
!empty($complexParts[9]) ? $complexParts[9] : 'i'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function __construct($realPart = 0.0, $imaginaryPart = null, $suffix = 'i')
|
||||
{
|
||||
if ($imaginaryPart === null) {
|
||||
if (is_array($realPart)) {
|
||||
// We have an array of (potentially) real and imaginary parts, and any suffix
|
||||
list ($realPart, $imaginaryPart, $suffix) = array_values($realPart) + [0.0, 0.0, 'i'];
|
||||
} elseif ((is_string($realPart)) || (is_numeric($realPart))) {
|
||||
// We've been given a string to parse to extract the real and imaginary parts, and any suffix
|
||||
list($realPart, $imaginaryPart, $suffix) = self::parseComplex($realPart);
|
||||
}
|
||||
}
|
||||
|
||||
if ($imaginaryPart != 0.0 && empty($suffix)) {
|
||||
$suffix = 'i';
|
||||
} elseif ($imaginaryPart == 0.0 && !empty($suffix)) {
|
||||
$suffix = '';
|
||||
}
|
||||
|
||||
// Set parsed values in our properties
|
||||
$this->realPart = (float) $realPart;
|
||||
$this->imaginaryPart = (float) $imaginaryPart;
|
||||
$this->suffix = strtolower($suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the real part of this complex number
|
||||
*
|
||||
* @return Float
|
||||
*/
|
||||
public function getReal()
|
||||
{
|
||||
return $this->realPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the imaginary part of this complex number
|
||||
*
|
||||
* @return Float
|
||||
*/
|
||||
public function getImaginary()
|
||||
{
|
||||
return $this->imaginaryPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the suffix of this complex number
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function getSuffix()
|
||||
{
|
||||
return $this->suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a real value, false if a complex value
|
||||
*
|
||||
* @return Bool
|
||||
*/
|
||||
public function isReal()
|
||||
{
|
||||
return $this->imaginaryPart == 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a complex value, false if a real value
|
||||
*
|
||||
* @return Bool
|
||||
*/
|
||||
public function isComplex()
|
||||
{
|
||||
return !$this->isReal();
|
||||
}
|
||||
|
||||
public function format()
|
||||
{
|
||||
$str = "";
|
||||
if ($this->imaginaryPart != 0.0) {
|
||||
if (\abs($this->imaginaryPart) != 1.0) {
|
||||
$str .= $this->imaginaryPart . $this->suffix;
|
||||
} else {
|
||||
$str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix;
|
||||
}
|
||||
}
|
||||
if ($this->realPart != 0.0) {
|
||||
if (($str) && ($this->imaginaryPart > 0.0)) {
|
||||
$str = "+" . $str;
|
||||
}
|
||||
$str = $this->realPart . $str;
|
||||
}
|
||||
if (!$str) {
|
||||
$str = "0.0";
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->format();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the argument is a valid complex number, converting scalar or array values if possible
|
||||
*
|
||||
* @param mixed $complex The value to validate
|
||||
* @return Complex
|
||||
* @throws Exception If the argument isn't a Complex number or cannot be converted to one
|
||||
*/
|
||||
public static function validateComplexArgument($complex)
|
||||
{
|
||||
if (is_scalar($complex) || is_array($complex)) {
|
||||
$complex = new Complex($complex);
|
||||
} elseif (!is_object($complex) || !($complex instanceof Complex)) {
|
||||
throw new Exception('Value is not a valid complex number');
|
||||
}
|
||||
|
||||
return $complex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reverse of this complex number
|
||||
*
|
||||
* @return Complex
|
||||
*/
|
||||
public function reverse()
|
||||
{
|
||||
return new Complex(
|
||||
$this->imaginaryPart,
|
||||
$this->realPart,
|
||||
($this->realPart == 0.0) ? null : $this->suffix
|
||||
);
|
||||
}
|
||||
|
||||
public function invertImaginary()
|
||||
{
|
||||
return new Complex(
|
||||
$this->realPart,
|
||||
$this->imaginaryPart * -1,
|
||||
($this->imaginaryPart == 0.0) ? null : $this->suffix
|
||||
);
|
||||
}
|
||||
|
||||
public function invertReal()
|
||||
{
|
||||
return new Complex(
|
||||
$this->realPart * -1,
|
||||
$this->imaginaryPart,
|
||||
($this->imaginaryPart == 0.0) ? null : $this->suffix
|
||||
);
|
||||
}
|
||||
|
||||
protected static $functions = [
|
||||
'abs',
|
||||
'acos',
|
||||
'acosh',
|
||||
'acot',
|
||||
'acoth',
|
||||
'acsc',
|
||||
'acsch',
|
||||
'argument',
|
||||
'asec',
|
||||
'asech',
|
||||
'asin',
|
||||
'asinh',
|
||||
'atan',
|
||||
'atanh',
|
||||
'conjugate',
|
||||
'cos',
|
||||
'cosh',
|
||||
'cot',
|
||||
'coth',
|
||||
'csc',
|
||||
'csch',
|
||||
'exp',
|
||||
'inverse',
|
||||
'ln',
|
||||
'log2',
|
||||
'log10',
|
||||
'negative',
|
||||
'pow',
|
||||
'rho',
|
||||
'sec',
|
||||
'sech',
|
||||
'sin',
|
||||
'sinh',
|
||||
'sqrt',
|
||||
'tan',
|
||||
'tanh',
|
||||
'theta',
|
||||
];
|
||||
|
||||
protected static $operations = [
|
||||
'add',
|
||||
'subtract',
|
||||
'multiply',
|
||||
'divideby',
|
||||
'divideinto',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns the result of the function call or operation
|
||||
*
|
||||
* @return Complex|float
|
||||
* @throws Exception|\InvalidArgumentException
|
||||
*/
|
||||
public function __call($functionName, $arguments)
|
||||
{
|
||||
$functionName = strtolower(str_replace('_', '', $functionName));
|
||||
|
||||
// Test for function calls
|
||||
if (in_array($functionName, self::$functions, true)) {
|
||||
$functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
|
||||
return $functionName($this, ...$arguments);
|
||||
}
|
||||
// Test for operation calls
|
||||
if (in_array($functionName, self::$operations, true)) {
|
||||
$functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
|
||||
return $functionName($this, ...$arguments);
|
||||
}
|
||||
throw new Exception('Function or Operation does not exist');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Exception.
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex abs() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the absolute value (modulus) of a complex number.
|
||||
* Also known as the rho of the complex number, i.e. the distance/radius
|
||||
* from the centrepoint to the representation of the number in polar coordinates.
|
||||
*
|
||||
* This function is a synonym for rho()
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return float The absolute (or rho) value of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*
|
||||
* @see rho
|
||||
*
|
||||
*/
|
||||
function abs($complex)
|
||||
{
|
||||
return rho($complex);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex acos() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse cosine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse cosine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function acos($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
$square = clone $complex;
|
||||
$square = multiply($square, $complex);
|
||||
$invsqrt = new Complex(1.0);
|
||||
$invsqrt = subtract($invsqrt, $square);
|
||||
$invsqrt = sqrt($invsqrt);
|
||||
$adjust = new Complex(
|
||||
$complex->getReal() - $invsqrt->getImaginary(),
|
||||
$complex->getImaginary() + $invsqrt->getReal()
|
||||
);
|
||||
$log = ln($adjust);
|
||||
|
||||
return new Complex(
|
||||
$log->getImaginary(),
|
||||
-1 * $log->getReal()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex acosh() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic cosine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse hyperbolic cosine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function acosh($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal() && ($complex->getReal() > 1)) {
|
||||
return new Complex(\acosh($complex->getReal()));
|
||||
}
|
||||
|
||||
$acosh = acos($complex)
|
||||
->reverse();
|
||||
if ($acosh->getReal() < 0.0) {
|
||||
$acosh = $acosh->invertReal();
|
||||
}
|
||||
|
||||
return $acosh;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex acot() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse cotangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse cotangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function acot($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
return atan(inverse($complex));
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex acoth() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic cotangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse hyperbolic cotangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function acoth($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
return atanh(inverse($complex));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex acsc() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse cosecant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse cosecant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function acsc($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
return INF;
|
||||
}
|
||||
|
||||
return asin(inverse($complex));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex acsch() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic cosecant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse hyperbolic cosecant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function acsch($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
return INF;
|
||||
}
|
||||
|
||||
return asinh(inverse($complex));
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex argument() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the argument of a complex number.
|
||||
* Also known as the theta of the complex number, i.e. the angle in radians
|
||||
* from the real axis to the representation of the number in polar coordinates.
|
||||
*
|
||||
* This function is a synonym for theta()
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return float The argument (or theta) value of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*
|
||||
* @see theta
|
||||
*/
|
||||
function argument($complex)
|
||||
{
|
||||
return theta($complex);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex asec() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse secant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse secant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function asec($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
return INF;
|
||||
}
|
||||
|
||||
return acos(inverse($complex));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex asech() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic secant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse hyperbolic secant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function asech($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
return INF;
|
||||
}
|
||||
|
||||
return acosh(inverse($complex));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex asin() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse sine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse sine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function asin($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
$square = multiply($complex, $complex);
|
||||
$invsqrt = new Complex(1.0);
|
||||
$invsqrt = subtract($invsqrt, $square);
|
||||
$invsqrt = sqrt($invsqrt);
|
||||
$adjust = new Complex(
|
||||
$invsqrt->getReal() - $complex->getImaginary(),
|
||||
$invsqrt->getImaginary() + $complex->getReal()
|
||||
);
|
||||
$log = ln($adjust);
|
||||
|
||||
return new Complex(
|
||||
$log->getImaginary(),
|
||||
-1 * $log->getReal()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex asinh() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic sine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse hyperbolic sine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function asinh($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal() && ($complex->getReal() > 1)) {
|
||||
return new Complex(\asinh($complex->getReal()));
|
||||
}
|
||||
|
||||
$asinh = clone $complex;
|
||||
$asinh = $asinh->reverse()
|
||||
->invertReal();
|
||||
$asinh = asin($asinh);
|
||||
return $asinh->reverse()
|
||||
->invertImaginary();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex atan() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
//include_once 'Math/Complex.php';
|
||||
//include_once 'Math/ComplexOp.php';
|
||||
|
||||
/**
|
||||
* Returns the inverse tangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse tangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function atan($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal()) {
|
||||
return new Complex(\atan($complex->getReal()));
|
||||
}
|
||||
|
||||
$t1Value = new Complex(-1 * $complex->getImaginary(), $complex->getReal());
|
||||
$uValue = new Complex(1, 0);
|
||||
|
||||
$d1Value = clone $uValue;
|
||||
$d1Value = subtract($d1Value, $t1Value);
|
||||
$d2Value = add($t1Value, $uValue);
|
||||
$uResult = $d1Value->divideBy($d2Value);
|
||||
$uResult = ln($uResult);
|
||||
|
||||
return new Complex(
|
||||
(($uResult->getImaginary() == M_PI) ? -M_PI : $uResult->getImaginary()) * -0.5,
|
||||
$uResult->getReal() * 0.5,
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex atanh() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic tangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse hyperbolic tangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function atanh($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal()) {
|
||||
$real = $complex->getReal();
|
||||
if ($real >= -1.0 && $real <= 1.0) {
|
||||
return new Complex(\atanh($real));
|
||||
} else {
|
||||
return new Complex(\atanh(1 / $real), (($real < 0.0) ? M_PI_2 : -1 * M_PI_2));
|
||||
}
|
||||
}
|
||||
|
||||
$iComplex = clone $complex;
|
||||
$iComplex = $iComplex->invertImaginary()
|
||||
->reverse();
|
||||
return atan($iComplex)
|
||||
->invertReal()
|
||||
->reverse();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex conjugate() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the complex conjugate of a complex number
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The conjugate of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function conjugate($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
return new Complex(
|
||||
$complex->getReal(),
|
||||
-1 * $complex->getImaginary(),
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex cos() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the cosine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The cosine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function cos($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal()) {
|
||||
return new Complex(\cos($complex->getReal()));
|
||||
}
|
||||
|
||||
return conjugate(
|
||||
new Complex(
|
||||
\cos($complex->getReal()) * \cosh($complex->getImaginary()),
|
||||
\sin($complex->getReal()) * \sinh($complex->getImaginary()),
|
||||
$complex->getSuffix()
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex cosh() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic cosine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The hyperbolic cosine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function cosh($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal()) {
|
||||
return new Complex(\cosh($complex->getReal()));
|
||||
}
|
||||
|
||||
return new Complex(
|
||||
\cosh($complex->getReal()) * \cos($complex->getImaginary()),
|
||||
\sinh($complex->getReal()) * \sin($complex->getImaginary()),
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex cot() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the cotangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The cotangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function cot($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
return new Complex(INF);
|
||||
}
|
||||
|
||||
return inverse(tan($complex));
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex coth() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic cotangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The hyperbolic cotangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function coth($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
return inverse(tanh($complex));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex csc() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the cosecant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The cosecant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function csc($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
return INF;
|
||||
}
|
||||
|
||||
return inverse(sin($complex));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex csch() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic cosecant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The hyperbolic cosecant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function csch($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
return INF;
|
||||
}
|
||||
|
||||
return inverse(sinh($complex));
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex exp() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the exponential of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The exponential of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function exp($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if (($complex->getReal() == 0.0) && (\abs($complex->getImaginary()) == M_PI)) {
|
||||
return new Complex(-1.0, 0.0);
|
||||
}
|
||||
|
||||
$rho = \exp($complex->getReal());
|
||||
|
||||
return new Complex(
|
||||
$rho * \cos($complex->getImaginary()),
|
||||
$rho * \sin($complex->getImaginary()),
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex inverse() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the inverse of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The inverse of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function inverse($complex)
|
||||
{
|
||||
$complex = clone Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
throw new \InvalidArgumentException('Division by zero');
|
||||
}
|
||||
|
||||
return $complex->divideInto(1.0);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex ln() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the natural logarithm of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The natural logarithm of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
|
||||
*/
|
||||
function ln($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
|
||||
return new Complex(
|
||||
\log(rho($complex)),
|
||||
theta($complex),
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex log10() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the common logarithm (base 10) of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The common logarithm (base 10) of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
|
||||
*/
|
||||
function log10($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
|
||||
throw new \InvalidArgumentException();
|
||||
} elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
|
||||
return new Complex(\log10($complex->getReal()), 0.0, $complex->getSuffix());
|
||||
}
|
||||
|
||||
return ln($complex)
|
||||
->multiply(\log10(Complex::EULER));
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex log2() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the base-2 logarithm of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The base-2 logarithm of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
|
||||
*/
|
||||
function log2($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
|
||||
throw new \InvalidArgumentException();
|
||||
} elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
|
||||
return new Complex(\log($complex->getReal(), 2), 0.0, $complex->getSuffix());
|
||||
}
|
||||
|
||||
return ln($complex)
|
||||
->multiply(\log(Complex::EULER, 2));
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex negative() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the negative of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return float The negative value of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*
|
||||
* @see rho
|
||||
*
|
||||
*/
|
||||
function negative($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
return new Complex(
|
||||
-1 * $complex->getReal(),
|
||||
-1 * $complex->getImaginary(),
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex pow() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns a complex number raised to a power.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @param float|integer $power The power to raise this value to
|
||||
* @return Complex The complex argument raised to the real power.
|
||||
* @throws Exception If the power argument isn't a valid real
|
||||
*/
|
||||
function pow($complex, $power)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if (!is_numeric($power)) {
|
||||
throw new Exception('Power argument must be a real number');
|
||||
}
|
||||
|
||||
if ($complex->getImaginary() == 0.0 && $complex->getReal() >= 0.0) {
|
||||
return new Complex(\pow($complex->getReal(), $power));
|
||||
}
|
||||
|
||||
$rValue = \sqrt(($complex->getReal() * $complex->getReal()) + ($complex->getImaginary() * $complex->getImaginary()));
|
||||
$rPower = \pow($rValue, $power);
|
||||
$theta = $complex->argument() * $power;
|
||||
if ($theta == 0) {
|
||||
return new Complex(1);
|
||||
}
|
||||
|
||||
return new Complex($rPower * \cos($theta), $rPower * \sin($theta), $complex->getSuffix());
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex rho() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the rho of a complex number.
|
||||
* This is the distance/radius from the centrepoint to the representation of the number in polar coordinates.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return float The rho value of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function rho($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
return \sqrt(
|
||||
($complex->getReal() * $complex->getReal()) +
|
||||
($complex->getImaginary() * $complex->getImaginary())
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex sec() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the secant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The secant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function sec($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
return inverse(cos($complex));
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex sech() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic secant of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The hyperbolic secant of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function sech($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
return inverse(cosh($complex));
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex sin() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the sine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The sine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function sin($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal()) {
|
||||
return new Complex(\sin($complex->getReal()));
|
||||
}
|
||||
|
||||
return new Complex(
|
||||
\sin($complex->getReal()) * \cosh($complex->getImaginary()),
|
||||
\cos($complex->getReal()) * \sinh($complex->getImaginary()),
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex sinh() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic sine of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The hyperbolic sine of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function sinh($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal()) {
|
||||
return new Complex(\sinh($complex->getReal()));
|
||||
}
|
||||
|
||||
return new Complex(
|
||||
\sinh($complex->getReal()) * \cos($complex->getImaginary()),
|
||||
\cosh($complex->getReal()) * \sin($complex->getImaginary()),
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex sqrt() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the square root of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The Square root of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function sqrt($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
$theta = theta($complex);
|
||||
$delta1 = \cos($theta / 2);
|
||||
$delta2 = \sin($theta / 2);
|
||||
$rho = \sqrt(rho($complex));
|
||||
|
||||
return new Complex($delta1 * $rho, $delta2 * $rho, $complex->getSuffix());
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex tan() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the tangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The tangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function tan($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->isReal()) {
|
||||
return new Complex(\tan($complex->getReal()));
|
||||
}
|
||||
|
||||
$real = $complex->getReal();
|
||||
$imaginary = $complex->getImaginary();
|
||||
$divisor = 1 + \pow(\tan($real), 2) * \pow(\tanh($imaginary), 2);
|
||||
if ($divisor == 0.0) {
|
||||
throw new \InvalidArgumentException('Division by zero');
|
||||
}
|
||||
|
||||
return new Complex(
|
||||
\pow(sech($imaginary)->getReal(), 2) * \tan($real) / $divisor,
|
||||
\pow(sec($real)->getReal(), 2) * \tanh($imaginary) / $divisor,
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex tanh() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic tangent of a complex number.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return Complex The hyperbolic tangent of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
* @throws \InvalidArgumentException If function would result in a division by zero
|
||||
*/
|
||||
function tanh($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
$real = $complex->getReal();
|
||||
$imaginary = $complex->getImaginary();
|
||||
$divisor = \cos($imaginary) * \cos($imaginary) + \sinh($real) * \sinh($real);
|
||||
if ($divisor == 0.0) {
|
||||
throw new \InvalidArgumentException('Division by zero');
|
||||
}
|
||||
|
||||
return new Complex(
|
||||
\sinh($real) * \cosh($real) / $divisor,
|
||||
0.5 * \sin(2 * $imaginary) / $divisor,
|
||||
$complex->getSuffix()
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex theta() function
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Returns the theta of a complex number.
|
||||
* This is the angle in radians from the real axis to the representation of the number in polar coordinates.
|
||||
*
|
||||
* @param Complex|mixed $complex Complex number or a numeric value.
|
||||
* @return float The theta value of the complex argument.
|
||||
* @throws Exception If argument isn't a valid real or complex number.
|
||||
*/
|
||||
function theta($complex)
|
||||
{
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($complex->getReal() == 0.0) {
|
||||
if ($complex->isReal()) {
|
||||
return 0.0;
|
||||
} elseif ($complex->getImaginary() < 0.0) {
|
||||
return M_PI / -2;
|
||||
}
|
||||
return M_PI / 2;
|
||||
} elseif ($complex->getReal() > 0.0) {
|
||||
return \atan($complex->getImaginary() / $complex->getReal());
|
||||
} elseif ($complex->getImaginary() < 0.0) {
|
||||
return -(M_PI - \atan(\abs($complex->getImaginary()) / \abs($complex->getReal())));
|
||||
}
|
||||
|
||||
return M_PI - \atan($complex->getImaginary() / \abs($complex->getReal()));
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex addition operation
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Adds two or more complex numbers
|
||||
*
|
||||
* @param array of string|integer|float|Complex $complexValues The numbers to add
|
||||
* @return Complex
|
||||
*/
|
||||
function add(...$complexValues)
|
||||
{
|
||||
if (count($complexValues) < 2) {
|
||||
throw new \Exception('This function requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$base = array_shift($complexValues);
|
||||
$result = clone Complex::validateComplexArgument($base);
|
||||
|
||||
foreach ($complexValues as $complex) {
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($result->isComplex() && $complex->isComplex() &&
|
||||
$result->getSuffix() !== $complex->getSuffix()) {
|
||||
throw new Exception('Suffix Mismatch');
|
||||
}
|
||||
|
||||
$real = $result->getReal() + $complex->getReal();
|
||||
$imaginary = $result->getImaginary() + $complex->getImaginary();
|
||||
|
||||
$result = new Complex(
|
||||
$real,
|
||||
$imaginary,
|
||||
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex division operation
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Divides two or more complex numbers
|
||||
*
|
||||
* @param array of string|integer|float|Complex $complexValues The numbers to divide
|
||||
* @return Complex
|
||||
*/
|
||||
function divideby(...$complexValues)
|
||||
{
|
||||
if (count($complexValues) < 2) {
|
||||
throw new \Exception('This function requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$base = array_shift($complexValues);
|
||||
$result = clone Complex::validateComplexArgument($base);
|
||||
|
||||
foreach ($complexValues as $complex) {
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($result->isComplex() && $complex->isComplex() &&
|
||||
$result->getSuffix() !== $complex->getSuffix()) {
|
||||
throw new Exception('Suffix Mismatch');
|
||||
}
|
||||
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
|
||||
throw new \InvalidArgumentException('Division by zero');
|
||||
}
|
||||
|
||||
$delta1 = ($result->getReal() * $complex->getReal()) +
|
||||
($result->getImaginary() * $complex->getImaginary());
|
||||
$delta2 = ($result->getImaginary() * $complex->getReal()) -
|
||||
($result->getReal() * $complex->getImaginary());
|
||||
$delta3 = ($complex->getReal() * $complex->getReal()) +
|
||||
($complex->getImaginary() * $complex->getImaginary());
|
||||
|
||||
$real = $delta1 / $delta3;
|
||||
$imaginary = $delta2 / $delta3;
|
||||
|
||||
$result = new Complex(
|
||||
$real,
|
||||
$imaginary,
|
||||
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex division operation
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Divides two or more complex numbers
|
||||
*
|
||||
* @param array of string|integer|float|Complex $complexValues The numbers to divide
|
||||
* @return Complex
|
||||
*/
|
||||
function divideinto(...$complexValues)
|
||||
{
|
||||
if (count($complexValues) < 2) {
|
||||
throw new \Exception('This function requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$base = array_shift($complexValues);
|
||||
$result = clone Complex::validateComplexArgument($base);
|
||||
|
||||
foreach ($complexValues as $complex) {
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($result->isComplex() && $complex->isComplex() &&
|
||||
$result->getSuffix() !== $complex->getSuffix()) {
|
||||
throw new Exception('Suffix Mismatch');
|
||||
}
|
||||
if ($result->getReal() == 0.0 && $result->getImaginary() == 0.0) {
|
||||
throw new \InvalidArgumentException('Division by zero');
|
||||
}
|
||||
|
||||
$delta1 = ($complex->getReal() * $result->getReal()) +
|
||||
($complex->getImaginary() * $result->getImaginary());
|
||||
$delta2 = ($complex->getImaginary() * $result->getReal()) -
|
||||
($complex->getReal() * $result->getImaginary());
|
||||
$delta3 = ($result->getReal() * $result->getReal()) +
|
||||
($result->getImaginary() * $result->getImaginary());
|
||||
|
||||
$real = $delta1 / $delta3;
|
||||
$imaginary = $delta2 / $delta3;
|
||||
|
||||
$result = new Complex(
|
||||
$real,
|
||||
$imaginary,
|
||||
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex multiplication operation
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Multiplies two or more complex numbers
|
||||
*
|
||||
* @param array of string|integer|float|Complex $complexValues The numbers to multiply
|
||||
* @return Complex
|
||||
*/
|
||||
function multiply(...$complexValues)
|
||||
{
|
||||
if (count($complexValues) < 2) {
|
||||
throw new \Exception('This function requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$base = array_shift($complexValues);
|
||||
$result = clone Complex::validateComplexArgument($base);
|
||||
|
||||
foreach ($complexValues as $complex) {
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($result->isComplex() && $complex->isComplex() &&
|
||||
$result->getSuffix() !== $complex->getSuffix()) {
|
||||
throw new Exception('Suffix Mismatch');
|
||||
}
|
||||
|
||||
$real = ($result->getReal() * $complex->getReal()) -
|
||||
($result->getImaginary() * $complex->getImaginary());
|
||||
$imaginary = ($result->getReal() * $complex->getImaginary()) +
|
||||
($result->getImaginary() * $complex->getReal());
|
||||
|
||||
$result = new Complex(
|
||||
$real,
|
||||
$imaginary,
|
||||
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the complex subtraction operation
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Complex;
|
||||
|
||||
/**
|
||||
* Subtracts two or more complex numbers
|
||||
*
|
||||
* @param array of string|integer|float|Complex $complexValues The numbers to subtract
|
||||
* @return Complex
|
||||
*/
|
||||
function subtract(...$complexValues)
|
||||
{
|
||||
if (count($complexValues) < 2) {
|
||||
throw new \Exception('This function requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$base = array_shift($complexValues);
|
||||
$result = clone Complex::validateComplexArgument($base);
|
||||
|
||||
foreach ($complexValues as $complex) {
|
||||
$complex = Complex::validateComplexArgument($complex);
|
||||
|
||||
if ($result->isComplex() && $complex->isComplex() &&
|
||||
$result->getSuffix() !== $complex->getSuffix()) {
|
||||
throw new Exception('Suffix Mismatch');
|
||||
}
|
||||
|
||||
$real = $result->getReal() - $complex->getReal();
|
||||
$imaginary = $result->getImaginary() - $complex->getImaginary();
|
||||
|
||||
$result = new Complex(
|
||||
$real,
|
||||
$imaginary,
|
||||
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"name": "markbaker/complex",
|
||||
"type": "library",
|
||||
"description": "PHP Class for working with complex numbers",
|
||||
"keywords": ["complex", "mathematics"],
|
||||
"homepage": "https://github.com/MarkBaker/PHPComplex",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@lange.demon.co.uk"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^5.6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35|^5.0|^6.0|^7.0",
|
||||
"phpdocumentor/phpdocumentor":"2.*",
|
||||
"phpmd/phpmd": "2.*",
|
||||
"sebastian/phpcpd": "2.*",
|
||||
"phploc/phploc": "^4.0|^5.0|^6.0|^7.0",
|
||||
"squizlabs/php_codesniffer": "^3.4.0",
|
||||
"phpcompatibility/php-compatibility": "^9.0",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Complex\\": "classes/src/"
|
||||
},
|
||||
"files": [
|
||||
"classes/src/functions/abs.php",
|
||||
"classes/src/functions/acos.php",
|
||||
"classes/src/functions/acosh.php",
|
||||
"classes/src/functions/acot.php",
|
||||
"classes/src/functions/acoth.php",
|
||||
"classes/src/functions/acsc.php",
|
||||
"classes/src/functions/acsch.php",
|
||||
"classes/src/functions/argument.php",
|
||||
"classes/src/functions/asec.php",
|
||||
"classes/src/functions/asech.php",
|
||||
"classes/src/functions/asin.php",
|
||||
"classes/src/functions/asinh.php",
|
||||
"classes/src/functions/atan.php",
|
||||
"classes/src/functions/atanh.php",
|
||||
"classes/src/functions/conjugate.php",
|
||||
"classes/src/functions/cos.php",
|
||||
"classes/src/functions/cosh.php",
|
||||
"classes/src/functions/cot.php",
|
||||
"classes/src/functions/coth.php",
|
||||
"classes/src/functions/csc.php",
|
||||
"classes/src/functions/csch.php",
|
||||
"classes/src/functions/exp.php",
|
||||
"classes/src/functions/inverse.php",
|
||||
"classes/src/functions/ln.php",
|
||||
"classes/src/functions/log2.php",
|
||||
"classes/src/functions/log10.php",
|
||||
"classes/src/functions/negative.php",
|
||||
"classes/src/functions/pow.php",
|
||||
"classes/src/functions/rho.php",
|
||||
"classes/src/functions/sec.php",
|
||||
"classes/src/functions/sech.php",
|
||||
"classes/src/functions/sin.php",
|
||||
"classes/src/functions/sinh.php",
|
||||
"classes/src/functions/sqrt.php",
|
||||
"classes/src/functions/tan.php",
|
||||
"classes/src/functions/tanh.php",
|
||||
"classes/src/functions/theta.php",
|
||||
"classes/src/operations/add.php",
|
||||
"classes/src/operations/subtract.php",
|
||||
"classes/src/operations/multiply.php",
|
||||
"classes/src/operations/divideby.php",
|
||||
"classes/src/operations/divideinto.php"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"style": [
|
||||
"phpcs --report-width=200 --report=summary,full -n"
|
||||
],
|
||||
"mess": [
|
||||
"phpmd classes/src/ xml codesize,unusedcode,design,naming -n"
|
||||
],
|
||||
"lines": [
|
||||
"phploc classes/src/ -n"
|
||||
],
|
||||
"cpd": [
|
||||
"phpcpd classes/src/ -n"
|
||||
],
|
||||
"versions": [
|
||||
"phpcs --report-width=200 --report=summary,full classes/src/ --standard=PHPCompatibility --runtime-set testVersion 5.6- -n"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
use Complex\Complex as Complex;
|
||||
|
||||
include('../classes/Bootstrap.php');
|
||||
|
||||
echo 'Create', PHP_EOL;
|
||||
|
||||
$x = new Complex(123);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123, 456);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(array(123,456,'j'));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex('1.23e-4--2.34e-5i');
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
|
||||
echo PHP_EOL, 'Add', PHP_EOL;
|
||||
|
||||
$x = new Complex(123);
|
||||
$x->add(456);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456);
|
||||
$x->add(789.012);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->add(new Complex(-987.654, -32.1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->add(-987.654);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->add(new Complex(0, 1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->add(new Complex(0, -1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
|
||||
echo PHP_EOL, 'Subtract', PHP_EOL;
|
||||
|
||||
$x = new Complex(123);
|
||||
$x->subtract(456);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456);
|
||||
$x->subtract(789.012);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->subtract(new Complex(-987.654, -32.1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->subtract(-987.654);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->subtract(new Complex(0, 1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->subtract(new Complex(0, -1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
|
||||
echo PHP_EOL, 'Multiply', PHP_EOL;
|
||||
|
||||
$x = new Complex(123);
|
||||
$x->multiply(456);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456);
|
||||
$x->multiply(789.012);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->multiply(new Complex(-987.654, -32.1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->multiply(-987.654);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->multiply(new Complex(0, 1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->multiply(new Complex(0, -1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
|
||||
echo PHP_EOL, 'Divide By', PHP_EOL;
|
||||
|
||||
$x = new Complex(123);
|
||||
$x->divideBy(456);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456);
|
||||
$x->divideBy(789.012);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->divideBy(new Complex(-987.654, -32.1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->divideBy(-987.654);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->divideBy(new Complex(0, 1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->divideBy(new Complex(0, -1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
|
||||
echo PHP_EOL, 'Divide Into', PHP_EOL;
|
||||
|
||||
$x = new Complex(123);
|
||||
$x->divideInto(456);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456);
|
||||
$x->divideInto(789.012);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->divideInto(new Complex(-987.654, -32.1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(123.456, 78.90);
|
||||
$x->divideInto(-987.654);
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->divideInto(new Complex(0, 1));
|
||||
echo $x, PHP_EOL;
|
||||
|
||||
$x = new Complex(-987.654, -32.1);
|
||||
$x->divideInto(new Complex(0, -1));
|
||||
echo $x, PHP_EOL;
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Complex;
|
||||
|
||||
include('../classes/Bootstrap.php');
|
||||
|
||||
echo 'Function Examples', PHP_EOL;
|
||||
|
||||
$functions = array(
|
||||
'abs',
|
||||
'acos',
|
||||
'acosh',
|
||||
'acsc',
|
||||
'acsch',
|
||||
'argument',
|
||||
'asec',
|
||||
'asech',
|
||||
'asin',
|
||||
'asinh',
|
||||
'conjugate',
|
||||
'cos',
|
||||
'cosh',
|
||||
'csc',
|
||||
'csch',
|
||||
'exp',
|
||||
'inverse',
|
||||
'ln',
|
||||
'log2',
|
||||
'log10',
|
||||
'rho',
|
||||
'sec',
|
||||
'sech',
|
||||
'sin',
|
||||
'sinh',
|
||||
'sqrt',
|
||||
'theta'
|
||||
);
|
||||
|
||||
for ($real = -3.5; $real <= 3.5; $real += 0.5) {
|
||||
for ($imaginary = -3.5; $imaginary <= 3.5; $imaginary += 0.5) {
|
||||
foreach ($functions as $function) {
|
||||
$complexFunction = __NAMESPACE__ . '\\' . $function;
|
||||
$complex = new Complex($real, $imaginary);
|
||||
try {
|
||||
echo $function, '(', $complex, ') = ', $complexFunction($complex), PHP_EOL;
|
||||
} catch (\Exception $e) {
|
||||
echo $function, '(', $complex, ') ERROR: ', $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
echo PHP_EOL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Complex\Complex as Complex;
|
||||
|
||||
include('../classes/Bootstrap.php');
|
||||
|
||||
$values = [
|
||||
new Complex(123),
|
||||
new Complex(456, 123),
|
||||
new Complex(0.0, 456),
|
||||
];
|
||||
|
||||
foreach ($values as $value) {
|
||||
echo $value, PHP_EOL;
|
||||
}
|
||||
|
||||
echo 'Addition', PHP_EOL;
|
||||
|
||||
$result = \Complex\add(...$values);
|
||||
echo '=> ', $result, PHP_EOL;
|
||||
|
||||
echo PHP_EOL;
|
||||
|
||||
echo 'Subtraction', PHP_EOL;
|
||||
|
||||
$result = \Complex\subtract(...$values);
|
||||
echo '=> ', $result, PHP_EOL;
|
||||
|
||||
echo PHP_EOL;
|
||||
|
||||
echo 'Multiplication', PHP_EOL;
|
||||
|
||||
$result = \Complex\multiply(...$values);
|
||||
echo '=> ', $result, PHP_EOL;
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2017` `Mark Baker`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
name: main
|
||||
on: [ push, pull_request ]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- '5.6'
|
||||
- '7.0'
|
||||
- '7.1'
|
||||
- '7.2'
|
||||
- '7.3'
|
||||
- '7.4'
|
||||
|
||||
name: PHP ${{ matrix.php-version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
|
||||
coverage: none
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }}
|
||||
|
||||
- name: Setup problem matchers for PHP
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
|
||||
- name: Setup problem matchers for PHPUnit
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
- name: Test with PHPUnit
|
||||
run: ./vendor/bin/phpunit
|
||||
|
||||
phpcs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 7.4
|
||||
extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
|
||||
coverage: none
|
||||
tools: cs2pr
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Code style with PHP_CodeSniffer
|
||||
run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr --graceful-warnings --colorize
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 7.4
|
||||
extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
|
||||
coverage: pcov
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Coverage
|
||||
run: |
|
||||
./vendor/bin/phpunit --coverage-text
|
||||
Vendored
+207
@@ -0,0 +1,207 @@
|
||||
PHPMatrix
|
||||
==========
|
||||
|
||||
---
|
||||
|
||||
PHP Class for handling Matrices
|
||||
|
||||
[](http://travis-ci.org/MarkBaker/PHPMatrix)
|
||||
|
||||
[](https://xkcd.com/184/)
|
||||
|
||||
Matrix Transform
|
||||
|
||||
---
|
||||
|
||||
This library currently provides the following operations:
|
||||
|
||||
- addition
|
||||
- direct sum
|
||||
- subtraction
|
||||
- multiplication
|
||||
- division (using [A].[B]<sup>-1</sup>)
|
||||
- division by
|
||||
- division into
|
||||
|
||||
together with functions for
|
||||
|
||||
- adjoint
|
||||
- antidiagonal
|
||||
- cofactors
|
||||
- determinant
|
||||
- diagonal
|
||||
- identity
|
||||
- inverse
|
||||
- minors
|
||||
- trace
|
||||
- transpose
|
||||
- solve
|
||||
|
||||
Given Matrices A and B, calculate X for A.X = B
|
||||
|
||||
and classes for
|
||||
|
||||
- Decomposition
|
||||
- LU Decomposition with partial row pivoting,
|
||||
|
||||
such that [P].[A] = [L].[U] and [A] = [P]<sup>|</sup>.[L].[U]
|
||||
- QR Decomposition
|
||||
|
||||
such that [A] = [Q].[R]
|
||||
|
||||
## TO DO
|
||||
|
||||
- power() function
|
||||
- Decomposition
|
||||
- Cholesky Decomposition
|
||||
- EigenValue Decomposition
|
||||
- EigenValues
|
||||
- EigenVectors
|
||||
|
||||
---
|
||||
|
||||
# Usage
|
||||
|
||||
To create a new Matrix object, provide an array as the constructor argument
|
||||
|
||||
```php
|
||||
$grid = [
|
||||
[16, 3, 2, 13],
|
||||
[ 5, 10, 11, 8],
|
||||
[ 9, 6, 7, 12],
|
||||
[ 4, 15, 14, 1],
|
||||
];
|
||||
|
||||
$matrix = new Matrix\Matrix($grid);
|
||||
```
|
||||
The `Builder` class provides helper methods for creating specific matrices, specifically an identity matrix of a specified size; or a matrix of a specified dimensions, with every cell containing a set value.
|
||||
```php
|
||||
$matrix = Matrix\Builder::createFilledMatrix(1, 5, 3);
|
||||
```
|
||||
Will create a matrix of 5 rows and 3 columns, filled with a `1` in every cell; while
|
||||
```php
|
||||
$matrix = Matrix\Builder::createIdentityMatrix(3);
|
||||
```
|
||||
will create a 3x3 identity matrix.
|
||||
|
||||
|
||||
Matrix objects are immutable: whenever you call a method or pass a grid to a function that returns a matrix value, a new Matrix object will be returned, and the original will remain unchanged. This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Matrix result).
|
||||
|
||||
## Performing Mathematical Operations
|
||||
|
||||
To perform mathematical operations with Matrices, you can call the appropriate method against a matrix value, passing other values as arguments
|
||||
|
||||
```php
|
||||
$matrix1 = new Matrix\Matrix([
|
||||
[2, 7, 6],
|
||||
[9, 5, 1],
|
||||
[4, 3, 8],
|
||||
]);
|
||||
$matrix2 = new Matrix\Matrix([
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9],
|
||||
]);
|
||||
|
||||
var_dump($matrix1->multiply($matrix2)->toArray());
|
||||
```
|
||||
or pass all values to the appropriate function
|
||||
```php
|
||||
$matrix1 = new Matrix\Matrix([
|
||||
[2, 7, 6],
|
||||
[9, 5, 1],
|
||||
[4, 3, 8],
|
||||
]);
|
||||
$matrix2 = new Matrix\Matrix([
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9],
|
||||
]);
|
||||
|
||||
var_dump(Matrix\multiply($matrix1, $matrix2)->toArray());
|
||||
```
|
||||
You can pass in the arguments as Matrix objects, or as arrays.
|
||||
|
||||
If you want to perform the same operation against multiple values (e.g. to add three or more matrices), then you can pass multiple arguments to any of the operations.
|
||||
|
||||
## Using functions
|
||||
|
||||
When calling any of the available functions for a matrix value, you can either call the relevant method for the Matrix object
|
||||
```php
|
||||
$grid = [
|
||||
[16, 3, 2, 13],
|
||||
[ 5, 10, 11, 8],
|
||||
[ 9, 6, 7, 12],
|
||||
[ 4, 15, 14, 1],
|
||||
];
|
||||
|
||||
$matrix = new Matrix\Matrix($grid);
|
||||
|
||||
echo $matrix->trace();
|
||||
```
|
||||
or you can call the function as you would in procedural code, passing the Matrix object as an argument
|
||||
```php
|
||||
$grid = [
|
||||
[16, 3, 2, 13],
|
||||
[ 5, 10, 11, 8],
|
||||
[ 9, 6, 7, 12],
|
||||
[ 4, 15, 14, 1],
|
||||
];
|
||||
|
||||
$matrix = new Matrix\Matrix($grid);
|
||||
echo Matrix\trace($matrix);
|
||||
```
|
||||
When called procedurally using the function, you can pass in the argument as a Matrix object, or as an array.
|
||||
```php
|
||||
$grid = [
|
||||
[16, 3, 2, 13],
|
||||
[ 5, 10, 11, 8],
|
||||
[ 9, 6, 7, 12],
|
||||
[ 4, 15, 14, 1],
|
||||
];
|
||||
|
||||
echo Matrix\trace($grid);
|
||||
```
|
||||
As an alternative, it is also possible to call the method directly from the `Functions` class.
|
||||
```php
|
||||
$grid = [
|
||||
[16, 3, 2, 13],
|
||||
[ 5, 10, 11, 8],
|
||||
[ 9, 6, 7, 12],
|
||||
[ 4, 15, 14, 1],
|
||||
];
|
||||
|
||||
$matrix = new Matrix\Matrix($grid);
|
||||
echo Matrix\Functions::trace($matrix);
|
||||
```
|
||||
Used this way, methods must be called statically, and the argument must be the Matrix object, and cannot be an array.
|
||||
|
||||
## Decomposition
|
||||
|
||||
The library also provides classes for matrix decomposition. You can access these using
|
||||
```php
|
||||
$grid = [
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
];
|
||||
|
||||
$matrix = new Matrix\Matrix($grid);
|
||||
|
||||
$decomposition = new Matrix\Decomposition\QR($matrix);
|
||||
$Q = $decomposition->getQ();
|
||||
$R = $decomposition->getR();
|
||||
```
|
||||
|
||||
or alternatively us the `Decomposition` factory, identifying which form of decomposition you want to use
|
||||
```php
|
||||
$grid = [
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
];
|
||||
|
||||
$matrix = new Matrix\Matrix($grid);
|
||||
|
||||
$decomposition = Matrix\Decomposition\Decomposition::decomposition(Matrix\Decomposition\Decomposition::QR, $matrix);
|
||||
$Q = $decomposition->getQ();
|
||||
$R = $decomposition->getR();
|
||||
```
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
# required: PHP 5.3+ and zlib extension
|
||||
|
||||
// ini option check
|
||||
if (ini_get('phar.readonly')) {
|
||||
echo "php.ini: set the 'phar.readonly' option to 0 to enable phar creation\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// output name
|
||||
$pharName = 'Matrix.phar';
|
||||
|
||||
// target folder
|
||||
$sourceDir = __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;
|
||||
|
||||
// default meta information
|
||||
$metaData = array(
|
||||
'Author' => 'Mark Baker <mark@lange.demon.co.uk>',
|
||||
'Description' => 'PHP Class for working with Matrix numbers',
|
||||
'Copyright' => 'Mark Baker (c) 2013-' . date('Y'),
|
||||
'Timestamp' => time(),
|
||||
'Version' => '0.1.0',
|
||||
'Date' => date('Y-m-d')
|
||||
);
|
||||
|
||||
// cleanup
|
||||
if (file_exists($pharName)) {
|
||||
echo "Removed: {$pharName}\n";
|
||||
unlink($pharName);
|
||||
}
|
||||
|
||||
echo "Building phar file...\n";
|
||||
|
||||
// the phar object
|
||||
$phar = new Phar($pharName, null, 'Matrix');
|
||||
$phar->buildFromDirectory($sourceDir);
|
||||
$phar->setStub(
|
||||
<<<'EOT'
|
||||
<?php
|
||||
spl_autoload_register(function ($className) {
|
||||
include 'phar://' . $className . '.php';
|
||||
});
|
||||
|
||||
try {
|
||||
Phar::mapPhar();
|
||||
} catch (PharException $e) {
|
||||
error_log($e->getMessage());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
include 'phar://functions/sqrt.php';
|
||||
|
||||
__HALT_COMPILER();
|
||||
EOT
|
||||
);
|
||||
$phar->setMetadata($metaData);
|
||||
$phar->compressFiles(Phar::GZ);
|
||||
|
||||
echo "Complete.\n";
|
||||
|
||||
exit();
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Class for the creating "special" Matrices
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Matrix Builder class.
|
||||
*
|
||||
* @package Matrix
|
||||
*/
|
||||
class Builder
|
||||
{
|
||||
/**
|
||||
* Create a new matrix of specified dimensions, and filled with a specified value
|
||||
* If the column argument isn't provided, then a square matrix will be created
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int $rows
|
||||
* @param int|null $columns
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createFilledMatrix($value, $rows, $columns = null)
|
||||
{
|
||||
if ($columns === null) {
|
||||
$columns = $rows;
|
||||
}
|
||||
|
||||
$rows = Matrix::validateRow($rows);
|
||||
$columns = Matrix::validateColumn($columns);
|
||||
|
||||
return new Matrix(
|
||||
array_fill(
|
||||
0,
|
||||
$rows,
|
||||
array_fill(
|
||||
0,
|
||||
$columns,
|
||||
$value
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new identity matrix of specified dimensions
|
||||
* This will always be a square matrix, with the number of rows and columns matching the provided dimension
|
||||
*
|
||||
* @param int $dimensions
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createIdentityMatrix($dimensions)
|
||||
{
|
||||
$grid = static::createFilledMatrix(null, $dimensions)->toArray();
|
||||
|
||||
for ($x = 0; $x < $dimensions; ++$x) {
|
||||
$grid[$x][$x] = 1;
|
||||
}
|
||||
|
||||
return new Matrix($grid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Decomposition;
|
||||
|
||||
use Matrix\Exception;
|
||||
use Matrix\Matrix;
|
||||
|
||||
class Decomposition
|
||||
{
|
||||
const LU = 'LU';
|
||||
const QR = 'QR';
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function decomposition($type, Matrix $matrix)
|
||||
{
|
||||
switch (strtoupper($type)) {
|
||||
case self::LU:
|
||||
return new LU($matrix);
|
||||
case self::QR:
|
||||
return new QR($matrix);
|
||||
default:
|
||||
throw new Exception('Invalid Decomposition');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Decomposition;
|
||||
|
||||
use Matrix\Exception;
|
||||
use Matrix\Matrix;
|
||||
|
||||
class LU
|
||||
{
|
||||
private $luMatrix;
|
||||
private $rows;
|
||||
private $columns;
|
||||
|
||||
private $pivot = [];
|
||||
|
||||
public function __construct(Matrix $matrix)
|
||||
{
|
||||
$this->luMatrix = $matrix->toArray();
|
||||
$this->rows = $matrix->rows;
|
||||
$this->columns = $matrix->columns;
|
||||
|
||||
$this->buildPivot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lower triangular factor.
|
||||
*
|
||||
* @return Matrix Lower triangular factor
|
||||
*/
|
||||
public function getL()
|
||||
{
|
||||
$lower = [];
|
||||
|
||||
$columns = min($this->rows, $this->columns);
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
for ($column = 0; $column < $columns; ++$column) {
|
||||
if ($row > $column) {
|
||||
$lower[$row][$column] = $this->luMatrix[$row][$column];
|
||||
} elseif ($row === $column) {
|
||||
$lower[$row][$column] = 1.0;
|
||||
} else {
|
||||
$lower[$row][$column] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($lower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upper triangular factor.
|
||||
*
|
||||
* @return Matrix Upper triangular factor
|
||||
*/
|
||||
public function getU()
|
||||
{
|
||||
$upper = [];
|
||||
|
||||
$rows = min($this->rows, $this->columns);
|
||||
for ($row = 0; $row < $rows; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
if ($row <= $column) {
|
||||
$upper[$row][$column] = $this->luMatrix[$row][$column];
|
||||
} else {
|
||||
$upper[$row][$column] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($upper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return pivot permutation vector.
|
||||
*
|
||||
* @return Matrix Pivot matrix
|
||||
*/
|
||||
public function getP()
|
||||
{
|
||||
$pMatrix = [];
|
||||
|
||||
$pivots = $this->pivot;
|
||||
$pivotCount = count($pivots);
|
||||
foreach ($pivots as $row => $pivot) {
|
||||
$pMatrix[$row] = array_fill(0, $pivotCount, 0);
|
||||
$pMatrix[$row][$pivot] = 1;
|
||||
}
|
||||
|
||||
return new Matrix($pMatrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return pivot permutation vector.
|
||||
*
|
||||
* @return array Pivot vector
|
||||
*/
|
||||
public function getPivot()
|
||||
{
|
||||
return $this->pivot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the matrix nonsingular?
|
||||
*
|
||||
* @return bool true if U, and hence A, is nonsingular
|
||||
*/
|
||||
public function isNonsingular()
|
||||
{
|
||||
for ($diagonal = 0; $diagonal < $this->columns; ++$diagonal) {
|
||||
if ($this->luMatrix[$diagonal][$diagonal] === 0.0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function buildPivot()
|
||||
{
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
$this->pivot[$row] = $row;
|
||||
}
|
||||
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
$luColumn = $this->localisedReferenceColumn($column);
|
||||
|
||||
$this->applyTransformations($column, $luColumn);
|
||||
|
||||
$pivot = $this->findPivot($column, $luColumn);
|
||||
if ($pivot !== $column) {
|
||||
$this->pivotExchange($pivot, $column);
|
||||
}
|
||||
|
||||
$this->computeMultipliers($column);
|
||||
|
||||
unset($luColumn);
|
||||
}
|
||||
}
|
||||
|
||||
private function localisedReferenceColumn($column)
|
||||
{
|
||||
$luColumn = [];
|
||||
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
$luColumn[$row] = &$this->luMatrix[$row][$column];
|
||||
}
|
||||
|
||||
return $luColumn;
|
||||
}
|
||||
|
||||
private function applyTransformations($column, array $luColumn)
|
||||
{
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
$luRow = $this->luMatrix[$row];
|
||||
// Most of the time is spent in the following dot product.
|
||||
$kmax = min($row, $column);
|
||||
$sValue = 0.0;
|
||||
for ($kValue = 0; $kValue < $kmax; ++$kValue) {
|
||||
$sValue += $luRow[$kValue] * $luColumn[$kValue];
|
||||
}
|
||||
$luRow[$column] = $luColumn[$row] -= $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
private function findPivot($column, array $luColumn)
|
||||
{
|
||||
$pivot = $column;
|
||||
for ($row = $column + 1; $row < $this->rows; ++$row) {
|
||||
if (abs($luColumn[$row]) > abs($luColumn[$pivot])) {
|
||||
$pivot = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return $pivot;
|
||||
}
|
||||
|
||||
private function pivotExchange($pivot, $column)
|
||||
{
|
||||
for ($kValue = 0; $kValue < $this->columns; ++$kValue) {
|
||||
$tValue = $this->luMatrix[$pivot][$kValue];
|
||||
$this->luMatrix[$pivot][$kValue] = $this->luMatrix[$column][$kValue];
|
||||
$this->luMatrix[$column][$kValue] = $tValue;
|
||||
}
|
||||
|
||||
$lValue = $this->pivot[$pivot];
|
||||
$this->pivot[$pivot] = $this->pivot[$column];
|
||||
$this->pivot[$column] = $lValue;
|
||||
}
|
||||
|
||||
private function computeMultipliers($diagonal)
|
||||
{
|
||||
if (($diagonal < $this->rows) && ($this->luMatrix[$diagonal][$diagonal] != 0.0)) {
|
||||
for ($row = $diagonal + 1; $row < $this->rows; ++$row) {
|
||||
$this->luMatrix[$row][$diagonal] /= $this->luMatrix[$diagonal][$diagonal];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function pivotB(Matrix $B)
|
||||
{
|
||||
$X = [];
|
||||
foreach ($this->pivot as $rowId) {
|
||||
$row = $B->getRows($rowId + 1)->toArray();
|
||||
$X[] = array_pop($row);
|
||||
}
|
||||
|
||||
return $X;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve A*X = B.
|
||||
*
|
||||
* @param Matrix $B a Matrix with as many rows as A and any number of columns
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return Matrix X so that L*U*X = B(piv,:)
|
||||
*/
|
||||
public function solve(Matrix $B)
|
||||
{
|
||||
if ($B->rows !== $this->rows) {
|
||||
throw new Exception('Matrix row dimensions are not equal');
|
||||
}
|
||||
|
||||
if ($this->rows !== $this->columns) {
|
||||
throw new Exception('LU solve() only works on square matrices');
|
||||
}
|
||||
|
||||
if (!$this->isNonsingular()) {
|
||||
throw new Exception('Can only perform operation on singular matrix');
|
||||
}
|
||||
|
||||
// Copy right hand side with pivoting
|
||||
$nx = $B->columns;
|
||||
$X = $this->pivotB($B);
|
||||
|
||||
// Solve L*Y = B(piv,:)
|
||||
for ($k = 0; $k < $this->columns; ++$k) {
|
||||
for ($i = $k + 1; $i < $this->columns; ++$i) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Solve U*X = Y;
|
||||
for ($k = $this->columns - 1; $k >= 0; --$k) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X[$k][$j] /= $this->luMatrix[$k][$k];
|
||||
}
|
||||
for ($i = 0; $i < $k; ++$i) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($X);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Decomposition;
|
||||
|
||||
use Matrix\Exception;
|
||||
use Matrix\Matrix;
|
||||
|
||||
class QR
|
||||
{
|
||||
private $qrMatrix;
|
||||
private $rows;
|
||||
private $columns;
|
||||
|
||||
private $rDiagonal = [];
|
||||
|
||||
public function __construct(Matrix $matrix)
|
||||
{
|
||||
$this->qrMatrix = $matrix->toArray();
|
||||
$this->rows = $matrix->rows;
|
||||
$this->columns = $matrix->columns;
|
||||
|
||||
$this->decompose();
|
||||
}
|
||||
|
||||
public function getHouseholdVectors()
|
||||
{
|
||||
$householdVectors = [];
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
if ($row >= $column) {
|
||||
$householdVectors[$row][$column] = $this->qrMatrix[$row][$column];
|
||||
} else {
|
||||
$householdVectors[$row][$column] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($householdVectors);
|
||||
}
|
||||
|
||||
public function getQ()
|
||||
{
|
||||
$qGrid = [];
|
||||
|
||||
$rowCount = $this->rows;
|
||||
for ($k = $this->columns - 1; $k >= 0; --$k) {
|
||||
for ($i = 0; $i < $this->rows; ++$i) {
|
||||
$qGrid[$i][$k] = 0.0;
|
||||
}
|
||||
$qGrid[$k][$k] = 1.0;
|
||||
if ($this->columns > $this->rows) {
|
||||
$qGrid = array_slice($qGrid, 0, $this->rows);
|
||||
}
|
||||
|
||||
for ($j = $k; $j < $this->columns; ++$j) {
|
||||
if (isset($this->qrMatrix[$k], $this->qrMatrix[$k][$k]) && $this->qrMatrix[$k][$k] != 0.0) {
|
||||
$s = 0.0;
|
||||
for ($i = $k; $i < $this->rows; ++$i) {
|
||||
$s += $this->qrMatrix[$i][$k] * $qGrid[$i][$j];
|
||||
}
|
||||
$s = -$s / $this->qrMatrix[$k][$k];
|
||||
for ($i = $k; $i < $this->rows; ++$i) {
|
||||
$qGrid[$i][$j] += $s * $this->qrMatrix[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array_walk(
|
||||
$qGrid,
|
||||
function (&$row) use ($rowCount) {
|
||||
$row = array_reverse($row);
|
||||
$row = array_slice($row, 0, $rowCount);
|
||||
}
|
||||
);
|
||||
|
||||
return new Matrix($qGrid);
|
||||
}
|
||||
|
||||
public function getR()
|
||||
{
|
||||
$rGrid = [];
|
||||
|
||||
for ($row = 0; $row < $this->columns; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
if ($row < $column) {
|
||||
$rGrid[$row][$column] = isset($this->qrMatrix[$row][$column]) ? $this->qrMatrix[$row][$column] : 0.0;
|
||||
} elseif ($row === $column) {
|
||||
$rGrid[$row][$column] = isset($this->rDiagonal[$row]) ? $this->rDiagonal[$row] : 0.0;
|
||||
} else {
|
||||
$rGrid[$row][$column] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->columns > $this->rows) {
|
||||
$rGrid = array_slice($rGrid, 0, $this->rows);
|
||||
}
|
||||
|
||||
return new Matrix($rGrid);
|
||||
}
|
||||
|
||||
private function hypo($a, $b)
|
||||
{
|
||||
if (abs($a) > abs($b)) {
|
||||
$r = $b / $a;
|
||||
$r = abs($a) * sqrt(1 + $r * $r);
|
||||
} elseif ($b != 0.0) {
|
||||
$r = $a / $b;
|
||||
$r = abs($b) * sqrt(1 + $r * $r);
|
||||
} else {
|
||||
$r = 0.0;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* QR Decomposition computed by Householder reflections.
|
||||
*/
|
||||
private function decompose()
|
||||
{
|
||||
for ($k = 0; $k < $this->columns; ++$k) {
|
||||
// Compute 2-norm of k-th column without under/overflow.
|
||||
$norm = 0.0;
|
||||
for ($i = $k; $i < $this->rows; ++$i) {
|
||||
$norm = $this->hypo($norm, $this->qrMatrix[$i][$k]);
|
||||
}
|
||||
if ($norm != 0.0) {
|
||||
// Form k-th Householder vector.
|
||||
if ($this->qrMatrix[$k][$k] < 0.0) {
|
||||
$norm = -$norm;
|
||||
}
|
||||
for ($i = $k; $i < $this->rows; ++$i) {
|
||||
$this->qrMatrix[$i][$k] /= $norm;
|
||||
}
|
||||
$this->qrMatrix[$k][$k] += 1.0;
|
||||
// Apply transformation to remaining columns.
|
||||
for ($j = $k + 1; $j < $this->columns; ++$j) {
|
||||
$s = 0.0;
|
||||
for ($i = $k; $i < $this->rows; ++$i) {
|
||||
$s += $this->qrMatrix[$i][$k] * $this->qrMatrix[$i][$j];
|
||||
}
|
||||
$s = -$s / $this->qrMatrix[$k][$k];
|
||||
for ($i = $k; $i < $this->rows; ++$i) {
|
||||
$this->qrMatrix[$i][$j] += $s * $this->qrMatrix[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->rDiagonal[$k] = -$norm;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFullRank()
|
||||
{
|
||||
for ($j = 0; $j < $this->columns; ++$j) {
|
||||
if ($this->rDiagonal[$j] == 0.0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Least squares solution of A*X = B.
|
||||
*
|
||||
* @param Matrix $B a Matrix with as many rows as A and any number of columns
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return Matrix matrix that minimizes the two norm of Q*R*X-B
|
||||
*/
|
||||
public function solve(Matrix $B)
|
||||
{
|
||||
if ($B->rows !== $this->rows) {
|
||||
throw new Exception('Matrix row dimensions are not equal');
|
||||
}
|
||||
|
||||
if (!$this->isFullRank()) {
|
||||
throw new Exception('Can only perform this operation on a full-rank matrix');
|
||||
}
|
||||
|
||||
// Compute Y = transpose(Q)*B
|
||||
$Y = $this->getQ()->transpose()
|
||||
->multiply($B);
|
||||
// Solve R*X = Y;
|
||||
return $this->getR()->inverse()
|
||||
->multiply($Y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Exception.
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Matrix;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
||||
+337
@@ -0,0 +1,337 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
class Functions
|
||||
{
|
||||
/**
|
||||
* Calculate the adjoint of the matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose adjoint we wish to calculate
|
||||
* @return Matrix
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function getAdjoint(Matrix $matrix)
|
||||
{
|
||||
return self::transpose(
|
||||
self::getCofactors($matrix)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the adjoint of this matrix
|
||||
* The adjugate, classical adjoint, or adjunct of a square matrix is the transpose of its cofactor matrix.
|
||||
* The adjugate has sometimes been called the "adjoint", but today the "adjoint" of a matrix normally refers
|
||||
* to its corresponding adjoint operator, which is its conjugate transpose.
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose adjoint we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function adjoint(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Adjoint can only be calculated for a square matrix');
|
||||
}
|
||||
|
||||
return self::getAdjoint($matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the cofactors of the matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose cofactors we wish to calculate
|
||||
* @return Matrix
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function getCofactors(Matrix $matrix)
|
||||
{
|
||||
$cofactors = self::getMinors($matrix);
|
||||
$dimensions = $matrix->rows;
|
||||
|
||||
$cof = 1;
|
||||
for ($i = 0; $i < $dimensions; ++$i) {
|
||||
$cofs = $cof;
|
||||
for ($j = 0; $j < $dimensions; ++$j) {
|
||||
$cofactors[$i][$j] *= $cofs;
|
||||
$cofs = -$cofs;
|
||||
}
|
||||
$cof = -$cof;
|
||||
}
|
||||
|
||||
return new Matrix($cofactors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cofactors of this matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose cofactors we wish to calculate
|
||||
* @return Matrix
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function cofactors(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Cofactors can only be calculated for a square matrix');
|
||||
}
|
||||
|
||||
return self::getCofactors($matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Matrix $matrix
|
||||
* @param int $row
|
||||
* @param int $column
|
||||
* @return float
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function getDeterminantSegment(Matrix $matrix, $row, $column)
|
||||
{
|
||||
$tmpMatrix = $matrix->toArray();
|
||||
unset($tmpMatrix[$row]);
|
||||
array_walk(
|
||||
$tmpMatrix,
|
||||
function (&$row) use ($column) {
|
||||
unset($row[$column]);
|
||||
}
|
||||
);
|
||||
|
||||
return self::getDeterminant(new Matrix($tmpMatrix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the determinant of the matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose determinant we wish to calculate
|
||||
* @return float
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function getDeterminant(Matrix $matrix)
|
||||
{
|
||||
$dimensions = $matrix->rows;
|
||||
$determinant = 0;
|
||||
|
||||
switch ($dimensions) {
|
||||
case 1:
|
||||
$determinant = $matrix->getValue(1, 1);
|
||||
break;
|
||||
case 2:
|
||||
$determinant = $matrix->getValue(1, 1) * $matrix->getValue(2, 2) -
|
||||
$matrix->getValue(1, 2) * $matrix->getValue(2, 1);
|
||||
break;
|
||||
default:
|
||||
for ($i = 1; $i <= $dimensions; ++$i) {
|
||||
$det = $matrix->getValue(1, $i) * self::getDeterminantSegment($matrix, 0, $i - 1);
|
||||
if (($i % 2) == 0) {
|
||||
$determinant -= $det;
|
||||
} else {
|
||||
$determinant += $det;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $determinant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the determinant of this matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose determinant we wish to calculate
|
||||
* @return float
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function determinant(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Determinant can only be calculated for a square matrix');
|
||||
}
|
||||
|
||||
return self::getDeterminant($matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the diagonal of this matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose diagonal we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function diagonal(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Diagonal can only be extracted from a square matrix');
|
||||
}
|
||||
|
||||
$dimensions = $matrix->rows;
|
||||
$grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
|
||||
->toArray();
|
||||
|
||||
for ($i = 0; $i < $dimensions; ++$i) {
|
||||
$grid[$i][$i] = $matrix->getValue($i + 1, $i + 1);
|
||||
}
|
||||
|
||||
return new Matrix($grid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the antidiagonal of this matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose antidiagonal we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function antidiagonal(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Anti-Diagonal can only be extracted from a square matrix');
|
||||
}
|
||||
|
||||
$dimensions = $matrix->rows;
|
||||
$grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
|
||||
->toArray();
|
||||
|
||||
for ($i = 0; $i < $dimensions; ++$i) {
|
||||
$grid[$i][$dimensions - $i - 1] = $matrix->getValue($i + 1, $dimensions - $i);
|
||||
}
|
||||
|
||||
return new Matrix($grid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identity matrix
|
||||
* The identity matrix, or sometimes ambiguously called a unit matrix, of size n is the n × n square matrix
|
||||
* with ones on the main diagonal and zeros elsewhere
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose identity we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function identity(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Identity can only be created for a square matrix');
|
||||
}
|
||||
|
||||
$dimensions = $matrix->rows;
|
||||
|
||||
return Builder::createIdentityMatrix($dimensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the inverse of this matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose inverse we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function inverse(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Inverse can only be calculated for a square matrix');
|
||||
}
|
||||
|
||||
$determinant = self::getDeterminant($matrix);
|
||||
if ($determinant == 0.0) {
|
||||
throw new Exception('Inverse can only be calculated for a matrix with a non-zero determinant');
|
||||
}
|
||||
|
||||
if ($matrix->rows == 1) {
|
||||
return new Matrix([[1 / $matrix->getValue(1, 1)]]);
|
||||
}
|
||||
|
||||
return self::getAdjoint($matrix)
|
||||
->multiply(1 / $determinant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the minors of the matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose minors we wish to calculate
|
||||
* @return array[]
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected static function getMinors(Matrix $matrix)
|
||||
{
|
||||
$minors = $matrix->toArray();
|
||||
$dimensions = $matrix->rows;
|
||||
if ($dimensions == 1) {
|
||||
return $minors;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $dimensions; ++$i) {
|
||||
for ($j = 0; $j < $dimensions; ++$j) {
|
||||
$minors[$i][$j] = self::getDeterminantSegment($matrix, $i, $j);
|
||||
}
|
||||
}
|
||||
|
||||
return $minors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minors of the matrix
|
||||
* The minor of a matrix A is the determinant of some smaller square matrix, cut down from A by removing one or
|
||||
* more of its rows or columns.
|
||||
* Minors obtained by removing just one row and one column from square matrices (first minors) are required for
|
||||
* calculating matrix cofactors, which in turn are useful for computing both the determinant and inverse of
|
||||
* square matrices.
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose minors we wish to calculate
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function minors(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Minors can only be calculated for a square matrix');
|
||||
}
|
||||
|
||||
return new Matrix(self::getMinors($matrix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the trace of this matrix
|
||||
* The trace is defined as the sum of the elements on the main diagonal (the diagonal from the upper left to the lower right)
|
||||
* of the matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose trace we wish to calculate
|
||||
* @return float
|
||||
* @throws Exception
|
||||
**/
|
||||
public static function trace(Matrix $matrix)
|
||||
{
|
||||
if (!$matrix->isSquare()) {
|
||||
throw new Exception('Trace can only be extracted from a square matrix');
|
||||
}
|
||||
|
||||
$dimensions = $matrix->rows;
|
||||
$result = 0;
|
||||
for ($i = 1; $i <= $dimensions; ++$i) {
|
||||
$result += $matrix->getValue($i, $i);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transpose of this matrix
|
||||
*
|
||||
* @param Matrix $matrix The matrix whose transpose we wish to calculate
|
||||
* @return Matrix
|
||||
**/
|
||||
public static function transpose(Matrix $matrix)
|
||||
{
|
||||
$array = array_values(array_merge([null], $matrix->toArray()));
|
||||
$grid = call_user_func_array(
|
||||
'array_map',
|
||||
$array
|
||||
);
|
||||
|
||||
return new Matrix($grid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix adjoint() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the adjoint of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The new matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function adjoint($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::adjoint($matrix);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix antidiagonal() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the antidiagonal of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The new matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function antidiagonal($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::antidiagonal($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix cofactors() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the cofactors of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The new matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function cofactors($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::cofactors($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix determinant() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the determinant of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return float Matrix determinant
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function determinant($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::determinant($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix diagonal() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the diagonal of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The new matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function diagonal($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::diagonal($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix identity() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the identity of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The identity matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function identity($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::identity($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix inverse() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the inverse of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The new matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function inverse($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::inverse($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix minors() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the minors of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The new matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function minors($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::minors($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix trace() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the trace of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return float The trace of the matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function trace($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::trace($matrix);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix transpose() function
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
/**
|
||||
* Returns the transpose of a matrix or an array.
|
||||
*
|
||||
* @param Matrix|array $matrix Matrix or an array to treat as a matrix.
|
||||
* @return Matrix The transposed matrix
|
||||
* @throws Exception If argument isn't a valid matrix or array.
|
||||
*/
|
||||
function transpose($matrix)
|
||||
{
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Must be Matrix or array');
|
||||
}
|
||||
|
||||
return Functions::transpose($matrix);
|
||||
}
|
||||
+423
@@ -0,0 +1,423 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Class for the management of Matrices
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Generator;
|
||||
use Matrix\Decomposition\LU;
|
||||
use Matrix\Decomposition\QR;
|
||||
|
||||
/**
|
||||
* Matrix object.
|
||||
*
|
||||
* @package Matrix
|
||||
*
|
||||
* @property-read int $rows The number of rows in the matrix
|
||||
* @property-read int $columns The number of columns in the matrix
|
||||
* @method Matrix antidiagonal()
|
||||
* @method Matrix adjoint()
|
||||
* @method Matrix cofactors()
|
||||
* @method float determinant()
|
||||
* @method Matrix diagonal()
|
||||
* @method Matrix identity()
|
||||
* @method Matrix inverse()
|
||||
* @method Matrix pseudoInverse()
|
||||
* @method Matrix minors()
|
||||
* @method float trace()
|
||||
* @method Matrix transpose()
|
||||
* @method Matrix add(...$matrices)
|
||||
* @method Matrix subtract(...$matrices)
|
||||
* @method Matrix multiply(...$matrices)
|
||||
* @method Matrix divideby(...$matrices)
|
||||
* @method Matrix divideinto(...$matrices)
|
||||
* @method Matrix directsum(...$matrices)
|
||||
*/
|
||||
class Matrix
|
||||
{
|
||||
protected $rows;
|
||||
protected $columns;
|
||||
protected $grid = [];
|
||||
|
||||
/*
|
||||
* Create a new Matrix object from an array of values
|
||||
*
|
||||
* @param array $grid
|
||||
*/
|
||||
final public function __construct(array $grid)
|
||||
{
|
||||
$this->buildFromArray(array_values($grid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new Matrix object from an array of values
|
||||
*
|
||||
* @param array $grid
|
||||
*/
|
||||
protected function buildFromArray(array $grid)
|
||||
{
|
||||
$this->rows = count($grid);
|
||||
$columns = array_reduce(
|
||||
$grid,
|
||||
function ($carry, $value) {
|
||||
return max($carry, is_array($value) ? count($value) : 1);
|
||||
}
|
||||
);
|
||||
$this->columns = $columns;
|
||||
|
||||
array_walk(
|
||||
$grid,
|
||||
function (&$value) use ($columns) {
|
||||
if (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
$value = array_pad(array_values($value), $columns, null);
|
||||
}
|
||||
);
|
||||
|
||||
$this->grid = $grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a row number is a positive integer
|
||||
*
|
||||
* @param int $row
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function validateRow($row)
|
||||
{
|
||||
if ((!is_numeric($row)) || (intval($row) < 1)) {
|
||||
throw new Exception('Invalid Row');
|
||||
}
|
||||
|
||||
return (int)$row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a column number is a positive integer
|
||||
*
|
||||
* @param int $column
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function validateColumn($column)
|
||||
{
|
||||
if ((!is_numeric($column)) || (intval($column) < 1)) {
|
||||
throw new Exception('Invalid Column');
|
||||
}
|
||||
|
||||
return (int)$column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a row number falls within the set of rows for this matrix
|
||||
*
|
||||
* @param int $row
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function validateRowInRange($row)
|
||||
{
|
||||
$row = static::validateRow($row);
|
||||
if ($row > $this->rows) {
|
||||
throw new Exception('Requested Row exceeds matrix size');
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a column number falls within the set of columns for this matrix
|
||||
*
|
||||
* @param int $column
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function validateColumnInRange($column)
|
||||
{
|
||||
$column = static::validateColumn($column);
|
||||
if ($column > $this->columns) {
|
||||
throw new Exception('Requested Column exceeds matrix size');
|
||||
}
|
||||
|
||||
return $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new matrix as a subset of rows from this matrix, starting at row number $row, and $rowCount rows
|
||||
* A $rowCount value of 0 will return all rows of the matrix from $row
|
||||
* A negative $rowCount value will return rows until that many rows from the end of the matrix
|
||||
*
|
||||
* Note that row numbers start from 1, not from 0
|
||||
*
|
||||
* @param int $row
|
||||
* @param int $rowCount
|
||||
* @return static
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getRows($row, $rowCount = 1)
|
||||
{
|
||||
$row = $this->validateRowInRange($row);
|
||||
if ($rowCount === 0) {
|
||||
$rowCount = $this->rows - $row + 1;
|
||||
}
|
||||
|
||||
return new static(array_slice($this->grid, $row - 1, (int)$rowCount));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new matrix as a subset of columns from this matrix, starting at column number $column, and $columnCount columns
|
||||
* A $columnCount value of 0 will return all columns of the matrix from $column
|
||||
* A negative $columnCount value will return columns until that many columns from the end of the matrix
|
||||
*
|
||||
* Note that column numbers start from 1, not from 0
|
||||
*
|
||||
* @param int $column
|
||||
* @param int $columnCount
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getColumns($column, $columnCount = 1)
|
||||
{
|
||||
$column = $this->validateColumnInRange($column);
|
||||
if ($columnCount < 1) {
|
||||
$columnCount = $this->columns + $columnCount - $column + 1;
|
||||
}
|
||||
|
||||
$grid = [];
|
||||
for ($i = $column - 1; $i < $column + $columnCount - 1; ++$i) {
|
||||
$grid[] = array_column($this->grid, $i);
|
||||
}
|
||||
|
||||
return (new static($grid))->transpose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new matrix as a subset of rows from this matrix, dropping rows starting at row number $row,
|
||||
* and $rowCount rows
|
||||
* A negative $rowCount value will drop rows until that many rows from the end of the matrix
|
||||
* A $rowCount value of 0 will remove all rows of the matrix from $row
|
||||
*
|
||||
* Note that row numbers start from 1, not from 0
|
||||
*
|
||||
* @param int $row
|
||||
* @param int $rowCount
|
||||
* @return static
|
||||
* @throws Exception
|
||||
*/
|
||||
public function dropRows($row, $rowCount = 1)
|
||||
{
|
||||
$this->validateRowInRange($row);
|
||||
if ($rowCount === 0) {
|
||||
$rowCount = $this->rows - $row + 1;
|
||||
}
|
||||
|
||||
$grid = $this->grid;
|
||||
array_splice($grid, $row - 1, (int)$rowCount);
|
||||
|
||||
return new static($grid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new matrix as a subset of columns from this matrix, dropping columns starting at column number $column,
|
||||
* and $columnCount columns
|
||||
* A negative $columnCount value will drop columns until that many columns from the end of the matrix
|
||||
* A $columnCount value of 0 will remove all columns of the matrix from $column
|
||||
*
|
||||
* Note that column numbers start from 1, not from 0
|
||||
*
|
||||
* @param int $column
|
||||
* @param int $columnCount
|
||||
* @return static
|
||||
* @throws Exception
|
||||
*/
|
||||
public function dropColumns($column, $columnCount = 1)
|
||||
{
|
||||
$this->validateColumnInRange($column);
|
||||
if ($columnCount < 1) {
|
||||
$columnCount = $this->columns + $columnCount - $column + 1;
|
||||
}
|
||||
|
||||
$grid = $this->grid;
|
||||
array_walk(
|
||||
$grid,
|
||||
function (&$row) use ($column, $columnCount) {
|
||||
array_splice($row, $column - 1, (int)$columnCount);
|
||||
}
|
||||
);
|
||||
|
||||
return new static($grid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value from this matrix, from the "cell" identified by the row and column numbers
|
||||
* Note that row and column numbers start from 1, not from 0
|
||||
*
|
||||
* @param int $row
|
||||
* @param int $column
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getValue($row, $column)
|
||||
{
|
||||
$row = $this->validateRowInRange($row);
|
||||
$column = $this->validateColumnInRange($column);
|
||||
|
||||
return $this->grid[$row - 1][$column - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Generator that will yield each row of the matrix in turn as a vector matrix
|
||||
* or the value of each cell if the matrix is a column vector
|
||||
*
|
||||
* @return Generator|Matrix[]|mixed[]
|
||||
*/
|
||||
public function rows()
|
||||
{
|
||||
foreach ($this->grid as $i => $row) {
|
||||
yield $i + 1 => ($this->columns == 1)
|
||||
? $row[0]
|
||||
: new static([$row]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Generator that will yield each column of the matrix in turn as a vector matrix
|
||||
* or the value of each cell if the matrix is a row vector
|
||||
*
|
||||
* @return Generator|Matrix[]|mixed[]
|
||||
*/
|
||||
public function columns()
|
||||
{
|
||||
for ($i = 0; $i < $this->columns; ++$i) {
|
||||
yield $i + 1 => ($this->rows == 1)
|
||||
? $this->grid[0][$i]
|
||||
: new static(array_column($this->grid, $i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify if the row and column dimensions of this matrix are equal,
|
||||
* i.e. if it is a "square" matrix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSquare()
|
||||
{
|
||||
return $this->rows == $this->columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify if this matrix is a vector
|
||||
* i.e. if it comprises only a single row or a single column
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isVector()
|
||||
{
|
||||
return $this->rows == 1 || $this->columns == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matrix as a 2-dimensional array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve A*X = B.
|
||||
*
|
||||
* @param Matrix $B Right hand side
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return Matrix ... Solution if A is square, least squares solution otherwise
|
||||
*/
|
||||
public function solve(Matrix $B)
|
||||
{
|
||||
if ($this->columns === $this->rows) {
|
||||
return (new LU($this))->solve($B);
|
||||
}
|
||||
|
||||
return (new QR($this))->solve($B);
|
||||
}
|
||||
|
||||
protected static $getters = [
|
||||
'rows',
|
||||
'columns',
|
||||
];
|
||||
|
||||
/**
|
||||
* Access specific properties as read-only (no setters)
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($propertyName)
|
||||
{
|
||||
$propertyName = strtolower($propertyName);
|
||||
|
||||
// Test for function calls
|
||||
if (in_array($propertyName, self::$getters)) {
|
||||
return $this->$propertyName;
|
||||
}
|
||||
|
||||
throw new Exception('Property does not exist');
|
||||
}
|
||||
|
||||
protected static $functions = [
|
||||
'antidiagonal',
|
||||
'adjoint',
|
||||
'cofactors',
|
||||
'determinant',
|
||||
'diagonal',
|
||||
'identity',
|
||||
'inverse',
|
||||
'minors',
|
||||
'trace',
|
||||
'transpose',
|
||||
];
|
||||
|
||||
protected static $operations = [
|
||||
'add',
|
||||
'subtract',
|
||||
'multiply',
|
||||
'divideby',
|
||||
'divideinto',
|
||||
'directsum',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns the result of the function call or operation
|
||||
*
|
||||
* @param string $functionName
|
||||
* @param mixed[] $arguments
|
||||
* @return Matrix|float
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __call($functionName, $arguments)
|
||||
{
|
||||
$functionName = strtolower(str_replace('_', '', $functionName));
|
||||
|
||||
if (in_array($functionName, self::$functions, true) || in_array($functionName, self::$operations, true)) {
|
||||
$functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
|
||||
if (is_callable($functionName)) {
|
||||
$arguments = array_values(array_merge([$this], $arguments));
|
||||
return call_user_func_array($functionName, $arguments);
|
||||
}
|
||||
}
|
||||
throw new Exception('Function or Operation does not exist');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix addition operation
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Matrix\Operators\Addition;
|
||||
|
||||
/**
|
||||
* Adds two or more matrices
|
||||
*
|
||||
* @param array<int, mixed> $matrixValues The matrices to add
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
function add(...$matrixValues)
|
||||
{
|
||||
if (count($matrixValues) < 2) {
|
||||
throw new Exception('Addition operation requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$matrix = array_shift($matrixValues);
|
||||
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Addition arguments must be Matrix or array');
|
||||
}
|
||||
|
||||
$result = new Addition($matrix);
|
||||
|
||||
foreach ($matrixValues as $matrix) {
|
||||
$result->execute($matrix);
|
||||
}
|
||||
|
||||
return $result->result();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix direct sum operation
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Matrix\Operators\DirectSum;
|
||||
|
||||
/**
|
||||
* Adds two or more matrices
|
||||
*
|
||||
* @param array<int, mixed> $matrixValues The matrices to add
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
function directsum(...$matrixValues)
|
||||
{
|
||||
if (count($matrixValues) < 2) {
|
||||
throw new Exception('DirectSum operation requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$matrix = array_shift($matrixValues);
|
||||
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('DirectSum arguments must be Matrix or array');
|
||||
}
|
||||
|
||||
$result = new DirectSum($matrix);
|
||||
|
||||
foreach ($matrixValues as $matrix) {
|
||||
$result->execute($matrix);
|
||||
}
|
||||
|
||||
return $result->result();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix division operation
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Matrix\Operators\Division;
|
||||
|
||||
/**
|
||||
* Divides two or more matrix numbers
|
||||
*
|
||||
* @param array<int, mixed> $matrixValues The matrices to divide
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
function divideby(...$matrixValues)
|
||||
{
|
||||
if (count($matrixValues) < 2) {
|
||||
throw new Exception('Division operation requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$matrix = array_shift($matrixValues);
|
||||
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Division arguments must be Matrix or array');
|
||||
}
|
||||
|
||||
$result = new Division($matrix);
|
||||
|
||||
foreach ($matrixValues as $matrix) {
|
||||
$result->execute($matrix);
|
||||
}
|
||||
|
||||
return $result->result();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix division operation
|
||||
*
|
||||
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Matrix\Operators\Division;
|
||||
|
||||
/**
|
||||
* Divides two or more matrix numbers
|
||||
*
|
||||
* @param array<int, mixed> $matrixValues The numbers to divide
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
function divideinto(...$matrixValues)
|
||||
{
|
||||
if (count($matrixValues) < 2) {
|
||||
throw new Exception('Division operation requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$matrix = array_pop($matrixValues);
|
||||
$matrixValues = array_reverse($matrixValues);
|
||||
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Division arguments must be Matrix or array');
|
||||
}
|
||||
|
||||
$result = new Division($matrix);
|
||||
|
||||
foreach ($matrixValues as $matrix) {
|
||||
$result->execute($matrix);
|
||||
}
|
||||
|
||||
return $result->result();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix multiplication operation
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Matrix\Operators\Multiplication;
|
||||
|
||||
/**
|
||||
* Multiplies two or more matrices
|
||||
*
|
||||
* @param array<int, mixed> $matrixValues The matrices to multiply
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
function multiply(...$matrixValues)
|
||||
{
|
||||
if (count($matrixValues) < 2) {
|
||||
throw new Exception('Multiplication operation requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$matrix = array_shift($matrixValues);
|
||||
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Multiplication arguments must be Matrix or array');
|
||||
}
|
||||
|
||||
$result = new Multiplication($matrix);
|
||||
|
||||
foreach ($matrixValues as $matrix) {
|
||||
$result->execute($matrix);
|
||||
}
|
||||
|
||||
return $result->result();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Function code for the matrix subtraction operation
|
||||
*
|
||||
* @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace Matrix;
|
||||
|
||||
use Matrix\Operators\Subtraction;
|
||||
|
||||
/**
|
||||
* Subtracts two or more matrices
|
||||
*
|
||||
* @param array<int, mixed> $matrixValues The matrices to subtract
|
||||
* @return Matrix
|
||||
* @throws Exception
|
||||
*/
|
||||
function subtract(...$matrixValues)
|
||||
{
|
||||
if (count($matrixValues) < 2) {
|
||||
throw new Exception('Subtraction operation requires at least 2 arguments');
|
||||
}
|
||||
|
||||
$matrix = array_shift($matrixValues);
|
||||
|
||||
if (is_array($matrix)) {
|
||||
$matrix = new Matrix($matrix);
|
||||
}
|
||||
if (!$matrix instanceof Matrix) {
|
||||
throw new Exception('Subtraction arguments must be Matrix or array');
|
||||
}
|
||||
|
||||
$result = new Subtraction($matrix);
|
||||
|
||||
foreach ($matrixValues as $matrix) {
|
||||
$result->execute($matrix);
|
||||
}
|
||||
|
||||
return $result->result();
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Operators;
|
||||
|
||||
use Matrix\Matrix;
|
||||
use Matrix\Exception;
|
||||
|
||||
class Addition extends Operator
|
||||
{
|
||||
/**
|
||||
* Execute the addition
|
||||
*
|
||||
* @param mixed $value The matrix or numeric value to add to the current base value
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
* @return $this The operation object, allowing multiple additions to be chained
|
||||
**/
|
||||
public function execute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$value = new Matrix($value);
|
||||
}
|
||||
|
||||
if (is_object($value) && ($value instanceof Matrix)) {
|
||||
return $this->addMatrix($value);
|
||||
} elseif (is_numeric($value)) {
|
||||
return $this->addScalar($value);
|
||||
}
|
||||
|
||||
throw new Exception('Invalid argument for addition');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the addition for a scalar
|
||||
*
|
||||
* @param mixed $value The numeric value to add to the current base value
|
||||
* @return $this The operation object, allowing multiple additions to be chained
|
||||
**/
|
||||
protected function addScalar($value)
|
||||
{
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
$this->matrix[$row][$column] += $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the addition for a matrix
|
||||
*
|
||||
* @param Matrix $value The numeric value to add to the current base value
|
||||
* @return $this The operation object, allowing multiple additions to be chained
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
**/
|
||||
protected function addMatrix(Matrix $value)
|
||||
{
|
||||
$this->validateMatchingDimensions($value);
|
||||
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
$this->matrix[$row][$column] += $value->getValue($row + 1, $column + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Operators;
|
||||
|
||||
use Matrix\Matrix;
|
||||
use Matrix\Exception;
|
||||
|
||||
class DirectSum extends Operator
|
||||
{
|
||||
/**
|
||||
* Execute the addition
|
||||
*
|
||||
* @param mixed $value The matrix or numeric value to add to the current base value
|
||||
* @return $this The operation object, allowing multiple additions to be chained
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
*/
|
||||
public function execute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$value = new Matrix($value);
|
||||
}
|
||||
|
||||
if ($value instanceof Matrix) {
|
||||
return $this->directSumMatrix($value);
|
||||
}
|
||||
|
||||
throw new Exception('Invalid argument for addition');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the direct sum for a matrix
|
||||
*
|
||||
* @param Matrix $value The numeric value to concatenate/direct sum with the current base value
|
||||
* @return $this The operation object, allowing multiple additions to be chained
|
||||
**/
|
||||
private function directSumMatrix($value)
|
||||
{
|
||||
$originalColumnCount = count($this->matrix[0]);
|
||||
$originalRowCount = count($this->matrix);
|
||||
$valColumnCount = $value->columns;
|
||||
$valRowCount = $value->rows;
|
||||
$value = $value->toArray();
|
||||
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
$this->matrix[$row] = array_merge($this->matrix[$row], array_fill(0, $valColumnCount, 0));
|
||||
}
|
||||
|
||||
$this->matrix = array_merge(
|
||||
$this->matrix,
|
||||
array_fill(0, $valRowCount, array_fill(0, $originalColumnCount, 0))
|
||||
);
|
||||
|
||||
for ($row = $originalRowCount; $row < $originalRowCount + $valRowCount; ++$row) {
|
||||
array_splice(
|
||||
$this->matrix[$row],
|
||||
$originalColumnCount,
|
||||
$valColumnCount,
|
||||
$value[$row - $originalRowCount]
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Operators;
|
||||
|
||||
use \Matrix\Matrix;
|
||||
use \Matrix\Functions;
|
||||
use Matrix\Exception;
|
||||
|
||||
class Division extends Multiplication
|
||||
{
|
||||
/**
|
||||
* Execute the division
|
||||
*
|
||||
* @param mixed $value The matrix or numeric value to divide the current base value by
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
* @return $this The operation object, allowing multiple divisions to be chained
|
||||
**/
|
||||
public function execute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$value = new Matrix($value);
|
||||
}
|
||||
|
||||
if (is_object($value) && ($value instanceof Matrix)) {
|
||||
try {
|
||||
$value = Functions::inverse($value);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('Division can only be calculated using a matrix with a non-zero determinant');
|
||||
}
|
||||
|
||||
return $this->multiplyMatrix($value);
|
||||
} elseif (is_numeric($value)) {
|
||||
return $this->multiplyScalar(1 / $value);
|
||||
}
|
||||
|
||||
throw new Exception('Invalid argument for division');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Operators;
|
||||
|
||||
use Matrix\Matrix;
|
||||
use \Matrix\Builder;
|
||||
use Matrix\Exception;
|
||||
|
||||
class Multiplication extends Operator
|
||||
{
|
||||
/**
|
||||
* Execute the multiplication
|
||||
*
|
||||
* @param mixed $value The matrix or numeric value to multiply the current base value by
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
* @return $this The operation object, allowing multiple multiplications to be chained
|
||||
**/
|
||||
public function execute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$value = new Matrix($value);
|
||||
}
|
||||
|
||||
if (is_object($value) && ($value instanceof Matrix)) {
|
||||
return $this->multiplyMatrix($value);
|
||||
} elseif (is_numeric($value)) {
|
||||
return $this->multiplyScalar($value);
|
||||
}
|
||||
|
||||
throw new Exception('Invalid argument for multiplication');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the multiplication for a scalar
|
||||
*
|
||||
* @param mixed $value The numeric value to multiply with the current base value
|
||||
* @return $this The operation object, allowing multiple mutiplications to be chained
|
||||
**/
|
||||
protected function multiplyScalar($value)
|
||||
{
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
$this->matrix[$row][$column] *= $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the multiplication for a matrix
|
||||
*
|
||||
* @param Matrix $value The numeric value to multiply with the current base value
|
||||
* @return $this The operation object, allowing multiple mutiplications to be chained
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
**/
|
||||
protected function multiplyMatrix(Matrix $value)
|
||||
{
|
||||
$this->validateReflectingDimensions($value);
|
||||
|
||||
$newRows = $this->rows;
|
||||
$newColumns = $value->columns;
|
||||
$matrix = Builder::createFilledMatrix(0, $newRows, $newColumns)
|
||||
->toArray();
|
||||
for ($row = 0; $row < $newRows; ++$row) {
|
||||
for ($column = 0; $column < $newColumns; ++$column) {
|
||||
$columnData = $value->getColumns($column + 1)->toArray();
|
||||
foreach ($this->matrix[$row] as $key => $valueData) {
|
||||
$matrix[$row][$column] += $valueData * $columnData[$key][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->matrix = $matrix;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Operators;
|
||||
|
||||
use Matrix\Matrix;
|
||||
use Matrix\Exception;
|
||||
|
||||
abstract class Operator
|
||||
{
|
||||
/**
|
||||
* Stored internally as a 2-dimension array of values
|
||||
*
|
||||
* @property mixed[][] $matrix
|
||||
**/
|
||||
protected $matrix;
|
||||
|
||||
/**
|
||||
* Number of rows in the matrix
|
||||
*
|
||||
* @property integer $rows
|
||||
**/
|
||||
protected $rows;
|
||||
|
||||
/**
|
||||
* Number of columns in the matrix
|
||||
*
|
||||
* @property integer $columns
|
||||
**/
|
||||
protected $columns;
|
||||
|
||||
/**
|
||||
* Create an new handler object for the operation
|
||||
*
|
||||
* @param Matrix $matrix The base Matrix object on which the operation will be performed
|
||||
*/
|
||||
public function __construct(Matrix $matrix)
|
||||
{
|
||||
$this->rows = $matrix->rows;
|
||||
$this->columns = $matrix->columns;
|
||||
$this->matrix = $matrix->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the dimensions of the matrices being operated on to see if they are valid for addition/subtraction
|
||||
*
|
||||
* @param Matrix $matrix The second Matrix object on which the operation will be performed
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function validateMatchingDimensions(Matrix $matrix)
|
||||
{
|
||||
if (($this->rows != $matrix->rows) || ($this->columns != $matrix->columns)) {
|
||||
throw new Exception('Matrices have mismatched dimensions');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the dimensions of the matrices being operated on to see if they are valid for multiplication/division
|
||||
*
|
||||
* @param Matrix $matrix The second Matrix object on which the operation will be performed
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function validateReflectingDimensions(Matrix $matrix)
|
||||
{
|
||||
if ($this->columns != $matrix->rows) {
|
||||
throw new Exception('Matrices have mismatched dimensions');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the result of the operation
|
||||
*
|
||||
* @return Matrix
|
||||
*/
|
||||
public function result()
|
||||
{
|
||||
return new Matrix($this->matrix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Matrix\Operators;
|
||||
|
||||
use Matrix\Matrix;
|
||||
use Matrix\Exception;
|
||||
|
||||
class Subtraction extends Operator
|
||||
{
|
||||
/**
|
||||
* Execute the subtraction
|
||||
*
|
||||
* @param mixed $value The matrix or numeric value to subtract from the current base value
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
* @return $this The operation object, allowing multiple subtractions to be chained
|
||||
**/
|
||||
public function execute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$value = new Matrix($value);
|
||||
}
|
||||
|
||||
if (is_object($value) && ($value instanceof Matrix)) {
|
||||
return $this->subtractMatrix($value);
|
||||
} elseif (is_numeric($value)) {
|
||||
return $this->subtractScalar($value);
|
||||
}
|
||||
|
||||
throw new Exception('Invalid argument for subtraction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the subtraction for a scalar
|
||||
*
|
||||
* @param mixed $value The numeric value to subtracted from the current base value
|
||||
* @return $this The operation object, allowing multiple additions to be chained
|
||||
**/
|
||||
protected function subtractScalar($value)
|
||||
{
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
$this->matrix[$row][$column] -= $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the subtraction for a matrix
|
||||
*
|
||||
* @param Matrix $value The numeric value to subtract from the current base value
|
||||
* @return $this The operation object, allowing multiple subtractions to be chained
|
||||
* @throws Exception If the provided argument is not appropriate for the operation
|
||||
**/
|
||||
protected function subtractMatrix(Matrix $value)
|
||||
{
|
||||
$this->validateMatchingDimensions($value);
|
||||
|
||||
for ($row = 0; $row < $this->rows; ++$row) {
|
||||
for ($column = 0; $column < $this->columns; ++$column) {
|
||||
$this->matrix[$row][$column] -= $value->getValue($row + 1, $column + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "markbaker/matrix",
|
||||
"type": "library",
|
||||
"description": "PHP Class for working with matrices",
|
||||
"keywords": ["matrix", "vector", "mathematics"],
|
||||
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@lange.demon.co.uk"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^5.6.0|^7.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7|^6.0|7.0",
|
||||
"phpmd/phpmd": "dev-master",
|
||||
"sebastian/phpcpd": "^3.0",
|
||||
"phploc/phploc": "^4",
|
||||
"squizlabs/php_codesniffer": "^3.0@dev",
|
||||
"phpcompatibility/php-compatibility": "dev-master",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Matrix\\": "classes/src/"
|
||||
},
|
||||
"files": [
|
||||
"classes/src/Functions/adjoint.php",
|
||||
"classes/src/Functions/antidiagonal.php",
|
||||
"classes/src/Functions/cofactors.php",
|
||||
"classes/src/Functions/determinant.php",
|
||||
"classes/src/Functions/diagonal.php",
|
||||
"classes/src/Functions/identity.php",
|
||||
"classes/src/Functions/inverse.php",
|
||||
"classes/src/Functions/minors.php",
|
||||
"classes/src/Functions/trace.php",
|
||||
"classes/src/Functions/transpose.php",
|
||||
"classes/src/Operations/add.php",
|
||||
"classes/src/Operations/directsum.php",
|
||||
"classes/src/Operations/subtract.php",
|
||||
"classes/src/Operations/multiply.php",
|
||||
"classes/src/Operations/divideby.php",
|
||||
"classes/src/Operations/divideinto.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"MatrixTest\\": "unitTests/classes/src/"
|
||||
},
|
||||
"files": [
|
||||
"classes/src/Functions/adjoint.php",
|
||||
"classes/src/Functions/antidiagonal.php",
|
||||
"classes/src/Functions/cofactors.php",
|
||||
"classes/src/Functions/determinant.php",
|
||||
"classes/src/Functions/diagonal.php",
|
||||
"classes/src/Functions/identity.php",
|
||||
"classes/src/Functions/inverse.php",
|
||||
"classes/src/Functions/minors.php",
|
||||
"classes/src/Functions/trace.php",
|
||||
"classes/src/Functions/transpose.php",
|
||||
"classes/src/Operations/add.php",
|
||||
"classes/src/Operations/directsum.php",
|
||||
"classes/src/Operations/subtract.php",
|
||||
"classes/src/Operations/multiply.php",
|
||||
"classes/src/Operations/divideby.php",
|
||||
"classes/src/Operations/divideinto.php"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"style": "phpcs --standard=PSR2 --report-width=200 --report=summary,full classes/src/ unitTests/classes/src -n",
|
||||
"test": "phpunit -c phpunit.xml.dist",
|
||||
"mess": "phpmd classes/src/ xml codesize,unusedcode,design,naming -n",
|
||||
"lines": "phploc classes/src/ -n",
|
||||
"cpd": "phpcpd classes/src/ -n",
|
||||
"versions": "phpcs --report-width=200 --report=summary,full classes/src/ --standard=PHPCompatibility --runtime-set testVersion 5.6- -n",
|
||||
"coverage": "phpunit -c phpunit.xml.dist --coverage-text --coverage-html ./build/coverage"
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$grid1 = [
|
||||
[1, 3, 2],
|
||||
[2, 3, 1],
|
||||
];
|
||||
|
||||
$grid2 = [
|
||||
[1, 6],
|
||||
[0, 1],
|
||||
];
|
||||
|
||||
$matrix = new Matrix\Matrix($grid1);
|
||||
|
||||
$new = $matrix->directsum(new Matrix\Matrix($grid2));
|
||||
|
||||
var_dump($new);
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"timeout": 1,
|
||||
"source": {
|
||||
"directories": [
|
||||
"classes\/src"
|
||||
]
|
||||
},
|
||||
"logs": {
|
||||
"text": "build/infection/text.log",
|
||||
"summary": "build/infection/summary.log",
|
||||
"debug": "build/infection/debug.log",
|
||||
"perMutator": "build/infection/perMutator.md"
|
||||
},
|
||||
"mutators": {
|
||||
"@default": true
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user