1# Licensed to the Apache Software Foundation (ASF) under one
2# or more contributor license agreements.  See the NOTICE file
3# distributed with this work for additional information
4# regarding copyright ownership.  The ASF licenses this file
5# to you under the Apache License, Version 2.0 (the
6# "License"); you may not use this file except in compliance
7# with the License.  You may obtain a copy of the License at
8#
9#   http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing,
12# software distributed under the License is distributed on an
13# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14# KIND, either express or implied.  See the License for the
15# specific language governing permissions and limitations
16# under the License.
17
18package AI::MXNet::NDArray::Slice;
19use strict;
20use warnings;
21use Mouse;
22use AI::MXNet::Base;
23use AI::MXNet::Function::Parameters;
24
25=head1 NAME
26
27    AI::MXNet::NDArray::Slice - A convenience class for slicing of the AI::MXNet::NDArray objects.
28=cut
29
30has parent => (is => 'ro', isa => 'AI::MXNet::NDArray', required => 1);
31has begin  => (is => 'ro', isa => 'Shape', required => 1);
32has end    => (is => 'ro', isa => 'Shape', required => 1);
33use overload
34    '.=' => \&set,
35    '='  => sub { $_[0] },
36    '""' => sub { my $self = $_[0]->sever; "$self" },
37    '**' => sub { my $self = $_[0]->sever; $self ** $_[1] },
38    '==' => sub { my $self = $_[0]->sever; $self == $_[1] },
39    '!=' => sub { my $self = $_[0]->sever; $self != $_[1] },
40    '+'  => sub { my $self = $_[0]->sever; $self +  $_[1] },
41    '*'  => sub { my $self = $_[0]->sever; $self *  $_[1] },
42    '-'  => sub { my $self = $_[0]->sever; $_[2] ? $_[1] - $self : $self - $_[1] },
43    '/'  => sub { my $self = $_[0]->sever; $_[2] ? $_[1] / $self : $self / $_[1] },
44    '+=' => sub { my ($self, $other) = @_; my $in = $self->sever; $self .= ($in+$_[1]) },
45    '-=' => sub { my ($self, $other) = @_; my $in = $self->sever; $self .= ($in-$_[1]) },
46    '*=' => sub { my ($self, $other) = @_; my $in = $self->sever; $self .= ($in*$_[1]) },
47    '/=' => sub { my ($self, $other) = @_; my $in = $self->sever; $self .= ($in/$_[1]) },
48    '**='=> sub { my ($self, $other) = @_; my $in = $self->sever; $self .= ($in**$_[1]) },
49    '>'  => sub { my $self = $_[0]->sever; return $_[2] ? $_[1] >  $self : $self >  $_[1] },
50    '>=' => sub { my $self = $_[0]->sever; return $_[2] ? $_[1] >= $self : $self >= $_[1] },
51    '<'  => sub { my $self = $_[0]->sever; return $_[2] ? $_[1] <  $self : $self <  $_[1] },
52    '<=' => sub { my $self = $_[0]->sever; return $_[2] ? $_[1] <= $self : $self <= $_[1] };
53
54method set(AcceptableInput $value, $reverse=)
55{
56    confess("set value must be defined") unless defined $value;
57    confess("${\ $self->parent } is not writable") unless $self->parent->writable;
58    my $shape = [ map {
59        my($begin, $end) = @$_;
60        ($end-$begin);
61    } zip($self->begin, $self->end) ];
62    if(ref $value)
63    {
64        if(blessed($value) and $value->isa('AI::MXNet::NDArray'))
65        {
66            $value = $value->as_in_context($self->parent->context);
67        }
68        elsif(blessed($value) and $value->isa('AI::MXNet::NDArray::Slice'))
69        {
70            $value = $value->sever->as_in_context($self->parent->context);
71        }
72        else
73        {
74            $value = AI::MXNet::NDArray->array($value, ctx => $self->parent->context);
75        }
76        confess("value $value does not match slice dim sizes [@$shape]")
77            if @{$value->shape} != @$shape;
78        for(zip($shape, $value->shape)) {
79                my ($dsize, $vdsize) = @$_;
80                confess("Slice [@$shape]  != $value given as value")
81                    if $dsize != $vdsize;
82        }
83        AI::MXNet::NDArray->_crop_assign(
84            $self->parent,
85            $value,
86            { out => $self->parent, begin => $self->begin, end => $self->end }
87        );
88    }
89    else
90    {
91        AI::MXNet::NDArray->_crop_assign_scalar(
92            $self->parent,
93            { "scalar" => $value, out => $self->parent, begin => $self->begin, end => $self->end }
94        );
95    }
96    return $self->parent;
97}
98
99method sever()
100{
101    return AI::MXNet::NDArray->crop(
102            $self->parent,
103            { begin => $self->begin, end => $self->end }
104    );
105}
106
107{
108    no warnings 'misc';
109    use attributes 'AI::MXNet::NDArray::Slice', \&AI::MXNet::NDArray::Slice::sever, 'lvalue';
110}
111
112sub notsupported  { confess("NDArray only support continuous slicing on axis 0"); }
113sub AUTOLOAD {
114    my $sub = $AI::MXNet::NDArray::Slice::AUTOLOAD;
115    $sub =~ s/.*:://;
116    my $self = shift;
117    return $self->sever->$sub(@_);
118}
119
1201;
121