Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions lib/Value/Matrix.pm
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,14 @@ Examples:

element : Real/Complex/Fraction value when passed the same number of arguments as the degree of the Matrix.
If passed more than n arguments, null. If the degree of the Matrix is n and C<element> is passed
k arguments with k < n, then this produces the corresponding degree (n-k) tensor.
k arguments with k < n, then this produces the corresponding degree (n-k) tensor.

=head3 Update values (these need to be added)

replace(value, [ i, j, ... ])
For a degree n matrix, the array reference for the second entry should have n elements.
The entry at that location will be replaced with value.

see C<change_matrix_entry()> in MatrixReduce and L<https://wiki.openwebwork.org/moodle/mod/forum/discuss.php?d=2970>

=head3 Advanced
Expand Down Expand Up @@ -1342,7 +1346,50 @@ sub element {
return $M->extract(@_);
}

# @@@ assign @@@
=head3 C<replace>

Replace an entry with a new element and return the replaced element.

Usage:

$A = Matrix([ [ 1, 2, 3 ], [ 4, 5, 6 ] ]);
$A->replace(7, [ 2, 1 ]);
# Now $A is the matrix [ [ 1, 2, 3 ], [ 7, 5, 6 ] ]

# Also, the method returns the value that is replaced.
$x = $A->replace(8, [ 1, 3 ]);
# Now $A is [ [ 1, 2, 8 ], [ 7, 5, 6 ] ] and $x is 3.

# It is also OK to specify the indices as an array instead of an array reference
$A->replace(7, 2, 1);

=cut

sub replace {
my ($self, $value, @indices) = @_;
$value = Value::makeValue($value) unless Value::isValue($value);
$self->Error('Cannot replace a matrix entry with a Formula') if Value::isFormula($value);
my $dim = $self->degree;
@indices = @{ $indices[0] } if (ref $indices[0] eq 'ARRAY');
$self->Error("There should be $dim indices") unless $dim == @indices;
my $data = $self->{data};
my $i = pop(@indices) - 1;

for (my $n = 0; @indices; $n++) {
my $j = shift(@indices) - 1;
$self->Error('The ' . $self->NameForNumber($n + 1) . ' index is outside of the array bounds')
if $j < 0 || $j >= scalar(@$data);
$data = $data->[$j]->{data};
}
$self->Error('The last index is outside of the array bounds')
if $i < 0 || $i >= scalar(@$data);
$self->Error('The new entry value should be ' . $data->[$i]->showType . ' not ' . $value->showType)
unless $value->type eq $data->[$i]->type;
my $old = $data->[$i];
$data->[$i] = $value;
return $old;
}

# @@@ removeRow, removeColumn @@@
# @@@ Minor @@@

Expand Down
31 changes: 31 additions & 0 deletions t/math_objects/matrix.t
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,37 @@ subtest 'Extract a column' => sub {
}, qr/Column must be a positive integer/, 'Test that an error is thrown for passing a non-positive integer';
};

subtest 'Replace a value' => sub {
my $A = Matrix([ 1, 2, 3 ]);
my $B = Matrix([ [ 1, 2, 3 ], [ 4, 5, 6 ] ]);
my $C = Matrix([ [ 1, 2, 3 ], [ 4, 5, 6 ] ]);
my $D = Matrix([ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ]);

is $A->replace(9, [2]), 2, 'Replace an element from a degree 1 matrix, returning replaced element';
is $A->TeX, Matrix([ 1, 9, 3 ])->TeX, 'Replace an element from a degree 1 matrix';
is $B->replace(9, [ 2, 1 ]), 4, 'Replace an element from a degree 2 matrix, returning replaced element';
is $B->TeX, Matrix([ [ 1, 2, 3 ], [ 9, 5, 6 ] ])->TeX, 'Replace an element from a degree 2 matrix';
is $C->replace(9, 2, 1), 4, 'Replace an element from a degree 2 matrix, returning replaced element';
is $C->TeX, Matrix([ [ 1, 2, 3 ], [ 9, 5, 6 ] ])->TeX, 'Replace an element from a degree 2 matrix';
is $D->replace(9, [ 2, 1, 2 ]), 6, 'Replace an element from a degree 3 matrix, returning replaced element';
is $D->TeX, Matrix([ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 9 ], [ 7, 8 ] ] ])->TeX,
'Replace an element from a degree 3 matrix';

like dies {
$B->replace(10, [ 1, 2, 3 ]);
}, qr/There should be 2 indices/, 'Check correct number of indices passed';
like dies {
$B->replace(10, [ 3, 1 ]);
}, qr/The first index is outside of the array bounds/, 'Check index is within bounds';
like dies {
$B->replace(Point(1, 2), [ 2, 1 ]);
}, qr/The new entry value should be a Number not a Point/, 'Check replaced value has the same type';
like dies {
$B->replace(Formula('x'), [ 2, 1 ]);
}, qr/Cannot replace a matrix entry with a Formula/, 'Check replaced value is not a Formula';

};

subtest 'Construct an identity matrix' => sub {
my $I = Value::Matrix->I(3);
my $B = Matrix([ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ] ]);
Expand Down
Loading