Skip to content

Commit

Permalink
Shortest path without color
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed May 5, 2022
1 parent 9690e85 commit 6088b49
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 175 deletions.
12 changes: 3 additions & 9 deletions src/Model/Bug/Step.php
Expand Up @@ -42,15 +42,9 @@ public function __clone()

public function getUniqueNodeId(): string
{
$places = $this->places;
ksort($places);
$colorValues = $this->color->getValues();
ksort($colorValues);

return md5(serialize([
'places' => $places,
'color' => $colorValues,
]));
ksort($this->places);

return md5(serialize($this->places));
}

public function setColor(ColorInterface $color): void
Expand Down
6 changes: 2 additions & 4 deletions src/Reducer/DispatcherTemplate.php
Expand Up @@ -8,7 +8,7 @@

abstract class DispatcherTemplate implements DispatcherInterface
{
protected const MIN_PAIR_LENGTH = 2; // 3 steps
protected const MIN_STEPS = 3;

protected MessageBusInterface $messageBus;

Expand All @@ -21,7 +21,7 @@ public function dispatch(BugInterface $bug): int
{
$steps = $bug->getSteps();

if (count($steps) < $this->minSteps()) {
if (count($steps) < self::MIN_STEPS) {
return 0;
}

Expand All @@ -41,6 +41,4 @@ protected function maxPairs(array $steps): int
{
return ceil(sqrt(count($steps)));
}

abstract protected function minSteps(): int;
}
12 changes: 1 addition & 11 deletions src/Reducer/Random/RandomDispatcher.php
Expand Up @@ -14,21 +14,11 @@ protected function getPairs(array $steps): array

while (count($pairs) < $maxPairs) {
$pair = array_rand(range(0, $length - 1), 2);
if ($pair[1] - $pair[0] >= static::MIN_PAIR_LENGTH && !in_array($pair, $pairs)) {
if (!in_array($pair, $pairs)) {
$pairs[] = $pair;
}
}

return $pairs;
}

protected function minSteps(): int
{
return 3;
}

protected function maxPairs(array $steps): int
{
return count($steps) <= 3 ? 1 : parent::maxPairs($steps);
}
}
9 changes: 1 addition & 8 deletions src/Reducer/Split/SplitDispatcher.php
Expand Up @@ -17,16 +17,9 @@ protected function getPairs(array $steps): array
$range[] = $length - 1;
}
for ($i = 0; $i < count($range) - 1; ++$i) {
if ($range[$i + 1] - $range[$i] >= static::MIN_PAIR_LENGTH) {
$pairs[] = [$range[$i], $range[$i + 1]];
}
$pairs[] = [$range[$i], $range[$i + 1]];
}

return $pairs;
}

protected function minSteps(): int
{
return 5;
}
}
10 changes: 1 addition & 9 deletions src/Resources/config/services.php
Expand Up @@ -45,8 +45,6 @@
use Tienvx\Bundle\MbtBundle\Repository\BugRepositoryInterface;
use Tienvx\Bundle\MbtBundle\Repository\TaskRepository;
use Tienvx\Bundle\MbtBundle\Repository\TaskRepositoryInterface;
use Tienvx\Bundle\MbtBundle\Service\AStar\PetrinetDomainLogic;
use Tienvx\Bundle\MbtBundle\Service\AStar\PetrinetDomainLogicInterface;
use Tienvx\Bundle\MbtBundle\Service\Bug\BugHelper;
use Tienvx\Bundle\MbtBundle\Service\Bug\BugHelperInterface;
use Tienvx\Bundle\MbtBundle\Service\Bug\BugNotifierInterface;
Expand Down Expand Up @@ -247,16 +245,10 @@
->set(ShortestPathStepsBuilder::class)
->args([
service(PetrinetHelperInterface::class),
service(PetrinetDomainLogicInterface::class),
])
->alias(StepsBuilderInterface::class, ShortestPathStepsBuilder::class)

->set(PetrinetDomainLogic::class)
->args([
service(GuardedTransitionServiceInterface::class),
service(MarkingHelperInterface::class),
])
->alias(PetrinetDomainLogicInterface::class, PetrinetDomainLogic::class)
->alias(StepsBuilderInterface::class, ShortestPathStepsBuilder::class)

->set(StepRunner::class)
->args([
Expand Down
11 changes: 0 additions & 11 deletions src/Service/AStar/PetrinetDomainLogicInterface.php

This file was deleted.

@@ -1,30 +1,28 @@
<?php

namespace Tienvx\Bundle\MbtBundle\Service\AStar;
namespace Tienvx\Bundle\MbtBundle\Service\Step\Builder;

use JMGQ\AStar\DomainLogicInterface;
use Petrinet\Model\TransitionInterface;
use SingleColorPetrinet\Model\PetrinetInterface;
use SingleColorPetrinet\Service\GuardedTransitionServiceInterface;
use Tienvx\Bundle\MbtBundle\Exception\RuntimeException;
use Tienvx\Bundle\MbtBundle\Model\Bug\Step;
use Tienvx\Bundle\MbtBundle\Service\Petrinet\MarkingHelperInterface;

class PetrinetDomainLogic implements PetrinetDomainLogicInterface
class PetrinetDomainLogic implements DomainLogicInterface
{
protected GuardedTransitionServiceInterface $transitionService;
protected MarkingHelperInterface $markingHelper;
protected ?PetrinetInterface $petrinet = null;
protected PetrinetInterface $petrinet;

public function __construct(
GuardedTransitionServiceInterface $transitionService,
MarkingHelperInterface $markingHelper
MarkingHelperInterface $markingHelper,
PetrinetInterface $petrinet
) {
$this->transitionService = $transitionService;
$this->markingHelper = $markingHelper;
}

public function setPetrinet(?PetrinetInterface $petrinet): void
{
$this->petrinet = $petrinet;
}

Expand All @@ -46,8 +44,8 @@ public function calculateEstimatedCost(mixed $fromNode, mixed $toNode): float|in
$tokensDiff += abs($toNode->getPlaces()[$place] - $fromNode->getPlaces()[$place]);
}
}
// Estimate it will took N transitions to move N tokens if color is the same, twice if color is not the same.
return $tokensDiff * (($fromNode->getColor()->getValues() != $toNode->getColor()->getValues()) + 1);
// Estimate it will took N transitions to move N tokens.
return $tokensDiff;
}

public function calculateRealCost(mixed $node, mixed $adjacent): float|int
Expand All @@ -62,10 +60,6 @@ public function getAdjacentNodes(mixed $node): iterable
throw new RuntimeException('The provided node is invalid');
}

if (!$this->petrinet instanceof PetrinetInterface) {
throw new RuntimeException('Petrinet is required');
}

$adjacents = [];
$marking = $this->markingHelper->getMarking($this->petrinet, $node->getPlaces(), $node->getColor());
foreach ($this->transitionService->getEnabledTransitions($this->petrinet, $marking) as $transition) {
Expand Down
58 changes: 44 additions & 14 deletions src/Service/Step/Builder/ShortestPathStepsBuilder.php
Expand Up @@ -4,24 +4,31 @@

use Generator;
use JMGQ\AStar\AStar;
use RuntimeException;
use SingleColorPetrinet\Model\PetrinetInterface;
use SingleColorPetrinet\Service\GuardedTransitionServiceInterface;
use Tienvx\Bundle\MbtBundle\Exception\ExceptionInterface;
use Tienvx\Bundle\MbtBundle\Exception\OutOfRangeException;
use Tienvx\Bundle\MbtBundle\Model\Bug\Step;
use Tienvx\Bundle\MbtBundle\Model\Bug\StepInterface;
use Tienvx\Bundle\MbtBundle\Model\BugInterface;
use Tienvx\Bundle\MbtBundle\Service\AStar\PetrinetDomainLogicInterface;
use Tienvx\Bundle\MbtBundle\Service\Petrinet\MarkingHelperInterface;
use Tienvx\Bundle\MbtBundle\Service\Petrinet\PetrinetHelperInterface;

class ShortestPathStepsBuilder implements StepsBuilderInterface
{
protected PetrinetHelperInterface $petrinetHelper;
protected PetrinetDomainLogicInterface $petrinetDomainLogic;
protected GuardedTransitionServiceInterface $transitionService;
protected MarkingHelperInterface $markingHelper;

public function __construct(
PetrinetHelperInterface $petrinetHelper,
PetrinetDomainLogicInterface $petrinetDomainLogic
GuardedTransitionServiceInterface $transitionService,
MarkingHelperInterface $markingHelper
) {
$this->petrinetHelper = $petrinetHelper;
$this->petrinetDomainLogic = $petrinetDomainLogic;
$this->transitionService = $transitionService;
$this->markingHelper = $markingHelper;
}

/**
Expand All @@ -30,23 +37,46 @@ public function __construct(
public function create(BugInterface $bug, int $from, int $to): Generator
{
yield from array_slice($bug->getSteps(), 0, $from);
yield from $this->getSteps($bug, $from, $to);
yield from array_slice($bug->getSteps(), $to + 1);
$petrinet = $this->petrinetHelper->build($bug->getTask()->getModelRevision());
$shortestSteps = $this->getShortestSteps($bug->getSteps(), $from, $to, $petrinet);
$lastStep = end($shortestSteps);
reset($shortestSteps);
yield from $shortestSteps;
yield from $this->getRemainingSteps(array_slice($bug->getSteps(), $to + 1), $lastStep, $petrinet);
}

protected function getSteps(BugInterface $bug, int $from, int $to): iterable
protected function getShortestSteps(array $steps, int $from, int $to, PetrinetInterface $petrinet): iterable
{
$fromStep = $bug->getSteps()[$from] ?? null;
$toStep = $bug->getSteps()[$to] ?? null;
$fromStep = $steps[$from] ?? null;
$toStep = $steps[$to] ?? null;

if (!$fromStep instanceof StepInterface || !$toStep instanceof StepInterface) {
throw new OutOfRangeException('Can not create new steps using invalid range');
throw new OutOfRangeException('Can not create shortest steps between invalid range');
}

$this->petrinetDomainLogic->setPetrinet($this->petrinetHelper->build($bug->getTask()->getModelRevision()));

yield from (new AStar($this->petrinetDomainLogic))->run($fromStep, $toStep);
return (new AStar(new PetrinetDomainLogic($this->transitionService, $this->markingHelper, $petrinet)))->run(
$fromStep,
$toStep
);
}

$this->petrinetDomainLogic->setPetrinet(null);
protected function getRemainingSteps(array $steps, StepInterface $lastStep, PetrinetInterface $petrinet): iterable
{
$marking = $this->markingHelper->getMarking($petrinet, $lastStep->getPlaces(), $lastStep->getColor());
foreach ($steps as $step) {
if (!$step instanceof StepInterface) {
throw new OutOfRangeException('Remaining steps contains invalid step');
}
$transition = $petrinet->getTransitionById($step->getTransition());
if (!$this->transitionService->isEnabled($transition, $marking)) {
throw new RuntimeException('Can not connect remaining steps');
}
$this->transitionService->fire($transition, $marking);
yield new Step(
$this->markingHelper->getPlaces($marking),
$marking->getColor(),
$step->getTransition()
);
}
}
}
11 changes: 3 additions & 8 deletions tests/Model/Bug/StepTest.php
Expand Up @@ -55,24 +55,19 @@ public function testClone(): void
/**
* @dataProvider nodeIdProvider
*/
public function testGetUniqueNodeId(?array $places, ?ColorInterface $color, string $id): void
public function testGetUniqueNodeId(?array $places, string $id): void
{
if ($places) {
$this->step->setPlaces($places);
}
if ($color) {
$this->step->setColor($color);
}
$this->assertSame($id, $this->step->getUniqueNodeId());
}

public function nodeIdProvider(): array
{
return [
[null, null, 'f179bfa0d0b5b6751e353f049461eda8'],
[null, new Color(['key1' => 'value1']), 'e13d72c92c38781375d3a400df07d43a'],
[[0 => 2, 1 => 1], null, 'e1b90c9311d5bd1d7fc90fd43d9bd49f'],
[[0 => 1, 1 => 1], new Color(['key2' => 'value2']), '61a579e02eb3ae787ef03ad40feb9a7d'],
[null, '89fefb193877ee62e29d1da5975dcc47'],
[[0 => 2, 1 => 1], '02878487ecf2302bf7ba2cc919514889'],
];
}

Expand Down
1 change: 0 additions & 1 deletion tests/Reducer/DispatcherTestCase.php
Expand Up @@ -56,7 +56,6 @@ protected function assertMessage(int $length): Callback
}

return $message->getBugId() === $this->bug->getId() &&
$message->getFrom() + 2 <= $message->getTo() &&
$length === $message->getLength();
});
}
Expand Down
4 changes: 1 addition & 3 deletions tests/Reducer/Random/RandomDispatcherTest.php
Expand Up @@ -28,9 +28,7 @@ public function stepsProvider(): array
[0, []],
[1, []],
[2, []],
[3, [
[0, 2],
]],
[3, range(1, 2)],
[4, range(1, 2)],
[5, range(1, 3)],
[6, range(1, 3)],
Expand Down
12 changes: 10 additions & 2 deletions tests/Reducer/Split/SplitDispatcherTest.php
Expand Up @@ -28,15 +28,21 @@ public function stepsProvider(): array
[0, []],
[1, []],
[2, []],
[3, []],
[4, []],
[3, [
[0, 2],
]],
[4, [
[0, 2],
[2, 3],
]],
[5, [
[0, 2],
[2, 4],
]],
[6, [
[0, 2],
[2, 4],
[4, 5],
]],
[7, [
[0, 3],
Expand All @@ -45,6 +51,7 @@ public function stepsProvider(): array
[8, [
[0, 3],
[3, 6],
[6, 7],
]],
[9, [
[0, 3],
Expand All @@ -60,6 +67,7 @@ public function stepsProvider(): array
[0, 3],
[3, 6],
[6, 9],
[9, 10],
]],
[12, [
[0, 3],
Expand Down

0 comments on commit 6088b49

Please sign in to comment.