Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Pol Dellaiera authored and Pol Dellaiera committed Dec 19, 2016
0 parents commit b9b00fe
Show file tree
Hide file tree
Showing 19 changed files with 1,311 additions and 0 deletions.
61 changes: 61 additions & 0 deletions .scrutinizer.yml
@@ -0,0 +1,61 @@
build:
environment:
php: '5.6'

filter:
paths:
- 'src/*'

tools:
external_code_coverage:
timeout: 600
php_mess_detector:
config:
code_size_rules: { cyclomatic_complexity: true, npath_complexity: true, excessive_method_length: true, excessive_class_length: true, excessive_parameter_list: true, excessive_public_count: true, too_many_fields: true, too_many_methods: true, excessive_class_complexity: true }
design_rules: { number_of_class_children: true, depth_of_inheritance: true, coupling_between_objects: true }
unused_code_rules: { unused_local_variable: true, unused_private_method: true, unused_formal_parameter: true }
naming_rules: { short_variable: true, long_variable: true, short_method: true, boolean_method_name: true }
controversial_rules: { camel_case_class_name: true, camel_case_property_name: true, camel_case_method_name: true, camel_case_parameter_name: true, camel_case_variable_name: true }
php_cs_fixer:
config:
level: all
fixers: { unused_use: true, phpdoc_params: true, braces: true, php_closing_tag: true }
php_analyzer:
config:
suspicious_code: { enabled: true, overriding_parameter: true, overriding_closure_use: true, parameter_closure_use_conflict: true, parameter_multiple_times: true, non_existent_class_in_instanceof_check: true, non_existent_class_in_catch_clause: true, assignment_of_null_return: true, non_commented_switch_fallthrough: true, non_commented_empty_catch_block: true, overriding_private_members: true, use_statement_alias_conflict: true, precedence_in_condition_assignment: true }
verify_php_doc_comments: { enabled: true, parameters: true, return: true, suggest_more_specific_types: true, ask_for_return_if_not_inferrable: true, ask_for_param_type_annotation: true }
loops_must_use_braces: { enabled: true }
simplify_boolean_return: { enabled: true }
phpunit_checks: { enabled: true }
reflection_fixes: { enabled: true }
use_statement_fixes: { enabled: true, order_alphabetically: true, remove_unused: true, preserve_multiple: false, preserve_blanklines: false }
parameter_reference_check: { enabled: false }
checkstyle: { enabled: false, no_trailing_whitespace: true, naming: { enabled: true, local_variable: '^[a-z][a-zA-Z0-9]*$', abstract_class_name: ^Abstract|Factory$, utility_class_name: 'Utils?$', constant_name: '^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$', property_name: '^[a-z][a-zA-Z0-9]*$', method_name: '^(?:[a-z]|__)[a-zA-Z0-9]*$', parameter_name: '^[a-z][a-zA-Z0-9]*$', interface_name: '^[A-Z][a-zA-Z0-9]*Interface$', type_name: '^[A-Z][a-zA-Z0-9]*$', exception_name: '^[A-Z][a-zA-Z0-9]*Exception$', isser_method_name: '^(?:is|has|should|may|supports)' } }
unreachable_code: { enabled: false }
check_access_control: { enabled: false }
typo_checks: { enabled: false }
check_variables: { enabled: false }
check_calls: { enabled: true, too_many_arguments: true, missing_argument: true, argument_type_checks: lenient }
dead_assignments: { enabled: false }
check_usage_context: { enabled: true, foreach: { value_as_reference: true, traversable: true } }
reflection_checks: { enabled: false }
precedence_checks: { enabled: true, assignment_in_condition: true, comparison_of_bit_result: true }
basic_semantic_checks: { enabled: false }
unused_code: { enabled: false }
deprecation_checks: { enabled: false }
useless_function_calls: { enabled: false }
metrics_lack_of_cohesion_methods: { enabled: false }
metrics_coupling: { enabled: true, stable_code: { namespace_prefixes: { }, classes: { } } }
doctrine_parameter_binding: { enabled: false }
doctrine_entity_manager_injection: { enabled: false }
symfony_request_injection: { enabled: false }
doc_comment_fixes: { enabled: false }
php_code_sniffer:
config:
standard: PSR2
sniffs: { psr2: { classes: { property_declaration_sniff: true }, methods: { method_declaration_sniff: true } } }
sensiolabs_security_checker: true
php_loc: true
php_pdepend: true
php_sim: true
php_changetracking: true
22 changes: 22 additions & 0 deletions .travis.yml
@@ -0,0 +1,22 @@
language: php

git:
depth: 1

cache:
directories:
- $HOME/.cache/composer
- $HOME/.composer/cache

php:
- 5.6
- 7.1

install:
- composer install

script:
- composer phpunit

after_success:
- composer scrutinizer
165 changes: 165 additions & 0 deletions README.md
@@ -0,0 +1,165 @@
## PHPartition
[![Build Status](https://travis-ci.org/drupol/phpartition.svg?branch=master)](https://travis-ci.org/drupol/phpartition) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/drupol/phpartition/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/drupol/phpartition/?branch=master) [![Dependency Status](https://www.versioneye.com/user/projects/58551f4d4d6466004c28cc8f/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/58551f4d4d6466004c28cc8f)

In number theory and computer science, the partition problem is the task of deciding whether a given multiset S of items can be partitioned into multiple balanced subsets.

## Requirements

* PHP >= 5.6,
* (optional) [PHPUnit](https://phpunit.de/) to run tests.

## Example

```php
<?php

include "./vendor/autoload.php";

$data = array(1, 5, 5, 11, 6, 7, 9, 3);
$size = 3;

$greedy = new \drupol\phpartition\Algorithm\Greedy();
$greedy->setData($data);
$greedy->setPartition($size);
$result = $greedy->getResult();

// $result is:
/*
* Array
(
[0] => Array
(
[0] => 9
[1] => 5
[2] => 1
)

[1] => Array
(
[0] => 7
[1] => 6
[2] => 3
)

[2] => Array
(
[0] => 11
[1] => 5
)
)
*/


$simple = new \drupol\phpartition\Algorithm\Simple();
$simple->setData($data);
$simple->setPartition($size);
$result = $simple->getResult();

// $result is:
/*
* Array
(
[0] => Array
(
[0] => 5
[1] => 11
)

[1] => Array
(
[0] => 1
[1] => 7
[2] => 3
)

[2] => Array
(
[0] => 5
[1] => 6
[2] => 9
)
)
*/
```
You may also pass objects or array but then, you'll have to define how to access their value.

```php
<?php

include "./vendor/autoload.php";

$data = array(
array(
'item' => 'anything A',
'weight' => 1,
),
array(
'item' => 'anything B',
'weight' => 2,
),
array(
'item' => 'anything C',
'weight' => 3,
),
array(
'item' => 'anything D',
'weight' => 4,
),
);
$size = 2;

$greedy = new \drupol\phpartition\Algorithm\Greedy();
$greedy->setData($data);
$greedy->setPartition($size);
$greedy->setItemAccessCallback(function($item) {
return $item['weight'];
});
$result = $greedy->getResult();

// $result is
/*
* Array
(
[0] => Array
(
[0] => Array
(
[item] => anything C
[weight] => 3
)

[1] => Array
(
[item] => anything B
[weight] => 2
)

)

[1] => Array
(
[0] => Array
(
[item] => anything D
[weight] => 4
)

[1] => Array
(
[item] => anything A
[weight] => 1
)

)

)
*/
```

## TODO

- Implement Complete Karmarkar-Karp (CKK) algorithm,
- Tests,
- Documentation,
- Tests coverage.

45 changes: 45 additions & 0 deletions composer.json
@@ -0,0 +1,45 @@
{
"name": "drupol/phpartition",
"description": "Partition problem for balanced arrays splitting made easy.",
"type": "library",
"homepage": "https://github.com/drupol/phpartition",
"keywords": ["math", "numbers", "statistics", "partition", "greedy", "karmarkar", "karp"],
"license": "GPL-2.0+",
"support": {
"issues": "https://github.com/drupol/phpartition/issues",
"source": "https://github.com/drupol/phpartition"
},
"authors": [
{
"name": "Pol Dellaiera",
"email": "pol.dellaiera@protonmail.com"
}
],
"require-dev": {
"phpunit/phpunit": "^5.6",
"mockery/mockery": "^0.9",
"squizlabs/php_codesniffer": "^2.0",
"satooshi/php-coveralls": "^1.0",
"phpunit/php-code-coverage": "^4.0",
"codacy/coverage": "dev-master",
"scrutinizer/ocular": "^1.3"
},
"scripts": {
"phpcs": "./vendor/bin/phpcs --ignore=vendor .",
"phpcbf": "./vendor/bin/phpcbf --ignore=vendor .",
"phpunit": "./vendor/bin/phpunit --coverage-clover build/logs/clover.xml -c tests/phpunit.xml tests",
"codacy": "./vendor/bin/codacycoverage clover build/logs/clover.xml",
"coveralls": "./vendor/bin/coveralls",
"scrutinizer": "./vendor/bin/ocular code-coverage:upload --format=php-clover build/logs/clover.xml"
},
"autoload": {
"psr-4": {
"drupol\\phpartition\\": "src/",
"drupol\\phpartition\\Tests\\": "tests/src/"
}
},
"require": {
"alphazygma/combinatorics": "^1.0",
"oefenweb/statistics": "^1.1"
}
}
75 changes: 75 additions & 0 deletions src/Algorithm/BruteForce.php
@@ -0,0 +1,75 @@
<?php

namespace drupol\phpartition\Algorithm;

use drupol\phpartition\BasePartitionAlgorithm;
use drupol\phpartition\PartitionAlgorithmInterface;
use drupol\phpartition\Subset;
use Math\Combinatorics\Permutation;

/**
* Class BruteForce.
*
* @package drupol\phpartition\Algorithm
*/
class BruteForce extends BasePartitionAlgorithm implements PartitionAlgorithmInterface {

/**
* @return array
*/
public function getResult() {
$permutation = new Permutation();
$this->dataset->sortByValue('ASC');

$partitionSize = ($this->getPartition() > $this->dataset->count()) ? $this->dataset->count() : $this->getPartition();

for ($p=$partitionSize; $p > 1; $p--) {
$best = $this->dataset->getWeight();
$target = ($best)/ $p;
$goodSubset = array();
$maxSize = floor($this->dataset->count() / $p);

for ($i = 1; $i <= $maxSize; $i++) {
foreach ($permutation->getPermutations($this->dataset->getItems(), $i) as $subset) {
$x = 0;
foreach ($subset as $item) {
$x += $item->getValue();
if (abs($x - $target) - abs($best - $target) < 0) {
$best = $x;
$goodSubset = $subset;
}
}
}
}

$subset = new Subset();
$subset->setAlgo($this);
$subset->addItems($goodSubset);
$this->getSubsetContainer()->insert($subset);
$this->dataset->deleteItems($goodSubset);
}

$subset = new Subset();
$subset->setAlgo($this);
$subset->addItems($this->dataset->getItems());
$this->getSubsetContainer()->insert($subset);

return $this->getSubsetContainer()->getSubsetsAndItemsAsArray();
}

/**
* @param \drupol\phpartition\Subset $subset
*
* @return int|mixed
*/
public function getSubsetWeight(Subset $subset) {
$sum = 0;

foreach ($subset->getItems() as $item) {
$sum += $item->getValue();
}

return $sum;
}

}

0 comments on commit b9b00fe

Please sign in to comment.