File Coverage

blib/lib/Quantum/Superpositions/Lazy/Computation.pm
Criterion Covered Total %
statement 74 75 98.6
branch 12 14 85.7
condition 2 6 33.3
subroutine 16 16 100.0
pod 1 4 25.0
total 105 115 91.3


line stmt bran cond sub pod time code
1             package Quantum::Superpositions::Lazy::Computation;
2              
3             our $VERSION = '1.10';
4              
5 15     15   195 use v5.24;
  15         45  
6 15     15   73 use warnings;
  15         33  
  15         335  
7 15     15   59 use Moo;
  15         27  
  15         83  
8 15     15   9824 use Quantum::Superpositions::Lazy::Operation::Computational;
  15         46  
  15         515  
9 15     15   5153 use Quantum::Superpositions::Lazy::ComputedState;
  15         63  
  15         573  
10 15     15   113 use Quantum::Superpositions::Lazy::Util qw(is_collapsible get_iterator);
  15         26  
  15         814  
11 15     15   81 use Types::Common::Numeric qw(PositiveNum);
  15         29  
  15         124  
12 15     15   6003 use Types::Standard qw(ConsumerOf ArrayRef Str);
  15         31  
  15         110  
13 15     15   11053 use List::Util qw(product);
  15         32  
  15         830  
14              
15 15     15   88 use namespace::clean;
  15         28  
  15         87  
16              
17             with "Quantum::Superpositions::Lazy::Role::Collapsible";
18              
19             has "operation" => (
20             is => "ro",
21             isa => (ConsumerOf ["Quantum::Superpositions::Lazy::Role::Operation"])
22             ->plus_coercions(Str,
23             q{Quantum::Superpositions::Lazy::Operation::Computational->new(sign => $_)}
24             ),
25             coerce => 1,
26             required => 1,
27             );
28              
29             has "values" => (
30             is => "ro",
31             isa => ArrayRef->where(q{@$_ > 0}),
32             required => 1,
33             );
34              
35 379     379 1 675 sub weight_sum { 1 }
36              
37             sub collapse
38             {
39 30     30 0 425 my ($self) = @_;
40              
41             my @members = map {
42 30 100       74 (is_collapsible $_) ? $_->collapse : $_
  60         318  
43             } $self->values->@*;
44              
45 30         492 return $self->operation->run(@members);
46             }
47              
48             sub is_collapsed
49             {
50 2     2 0 4030 my ($self) = @_;
51              
52             # a single uncollapsed state means that the computation
53             # is not fully collapsed
54 2         10 foreach my $member ($self->values->@*) {
55 2 50 33     7 if (is_collapsible($member) && !$member->is_collapsed) {
56 2         10 return 0;
57             }
58             }
59 0         0 return 1;
60             }
61              
62             sub reset
63             {
64 11     11 0 453 my ($self) = @_;
65              
66 11         32 foreach my $member ($self->values->@*) {
67 22 50       47 if (is_collapsible $member) {
68 22         366 $member->reset;
69             }
70             }
71              
72 11         26 return $self;
73             }
74              
75             sub _cartesian_product
76             {
77 53     53   112 my ($self, $input_states, $sourced) = @_;
78              
79 53         91 my %states;
80 53         154 my $iterator = get_iterator $input_states->@*;
81              
82 53         129 while (my @params = $iterator->()) {
83 81065         99319 my @source = map { $_->[1] } @params;
  162144         266869  
84 81065         172527 my $result = $self->operation->run(@source);
85 81065         102516 my $probability = product map { $_->[0] } @params;
  162144         247892  
86              
87 81065 100       244512 if (exists $states{$result}) {
88 38348         59947 $states{$result}[0] += $probability;
89             }
90             else {
91 42717         166994 $states{$result} = [
92             $probability,
93             $result,
94             ];
95             }
96              
97 81065 100       139702 if ($sourced) {
98 65104         250400 push $states{$result}[2]->@*, \@source;
99             }
100             }
101              
102 53         28853 return [values %states];
103             }
104              
105             sub _build_complete_states
106             {
107 53     53   885 my ($self) = @_;
108              
109 53         80 my @input_states;
110 53         165 for my $value ($self->values->@*) {
111 109         149 my $local_states;
112              
113 109 100       254 if (is_collapsible $value) {
114 84         1425 my $total = $value->weight_sum;
115             $local_states = [
116             map {
117 84         516 [$_->weight / $total, $_->value]
  16126         99698  
118             } $value->states->@*
119             ];
120             }
121             else {
122 25         59 $local_states = [[1, $value]];
123             }
124              
125 109         693 push @input_states, $local_states;
126             }
127              
128 53         79 my $sourced = $Quantum::Superpositions::Lazy::global_sourced_calculations;
129 53         162 my $states = $self->_cartesian_product(\@input_states, $sourced);
130              
131 53 100       137 if ($sourced) {
132             return [
133             map {
134 6   33     105 Quantum::Superpositions::Lazy::ComputedState->new(
  37627         4901956  
135             weight => $_->[0],
136             value => $_->[1],
137             source => $_->[2] // $_->[1],
138             operation => $self->operation,
139             )
140             } $states->@*
141             ];
142             }
143             else {
144 47         6945 return $states;
145             }
146              
147             }
148              
149             1;
150              
151             __END__