From dbd6fe7006c8108a9fec7c5157fd2fe8156ea21c Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Mon, 25 May 2026 11:42:50 -0700 Subject: [PATCH 1/3] method to set a particular entry in a matrix to a value --- lib/Value/Matrix.pm | 49 +++++++++++++++++++++++++++++++++++++++-- t/math_objects/matrix.t | 28 +++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/lib/Value/Matrix.pm b/lib/Value/Matrix.pm index 5b1892cdd..839512d3d 100644 --- a/lib/Value/Matrix.pm +++ b/lib/Value/Matrix.pm @@ -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 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) + set(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 in MatrixReduce and L =head3 Advanced @@ -1342,7 +1346,48 @@ sub element { return $M->extract(@_); } -# @@@ assign @@@ +=head3 C + +Set a specific element to some value. + +Usage: + + $A = Matrix([ [ 1, 2, 3 ], [ 4, 5, 6 ] ]); + $A->set(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->set(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->set(7, 2, 1); + +=cut + +sub set { + my ($self, $value, @indices) = @_; + $value = Value::makeValue($value) unless Value::isValue($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 @@@ diff --git a/t/math_objects/matrix.t b/t/math_objects/matrix.t index 32dfe3d45..48db06a65 100644 --- a/t/math_objects/matrix.t +++ b/t/math_objects/matrix.t @@ -215,6 +215,34 @@ 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 'Set 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->set(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->set(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->set(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->set(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->set(10, [ 1, 2, 3 ]); + }, qr/There should be 2 indices/, 'Check correct number of indices passed'; + like dies { + $B->set(10, [ 3, 1 ]); + }, qr/The first index is outside of the array bounds/, 'Check index is within bounds'; + like dies { + $B->set(Point(1, 2), [ 2, 1 ]); + }, qr/The new entry value should be a Number not a Point/, 'Check replaced value has the same type'; + +}; + subtest 'Construct an identity matrix' => sub { my $I = Value::Matrix->I(3); my $B = Matrix([ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ] ]); From 381d69f07fae9347c1aa087282128b0d09e76166 Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Thu, 28 May 2026 19:58:26 -0700 Subject: [PATCH 2/3] change name of method from 'set' ro 'replace' --- lib/Value/Matrix.pm | 14 +++++++------- t/math_objects/matrix.t | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/Value/Matrix.pm b/lib/Value/Matrix.pm index 839512d3d..5395fc433 100644 --- a/lib/Value/Matrix.pm +++ b/lib/Value/Matrix.pm @@ -117,7 +117,7 @@ Examples: =head3 Update values (these need to be added) - set(value, [ i, j, ... ]) + 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. @@ -1346,26 +1346,26 @@ sub element { return $M->extract(@_); } -=head3 C +=head3 C -Set a specific element to some value. +Replace an entry with a new element and return the replaced element. Usage: $A = Matrix([ [ 1, 2, 3 ], [ 4, 5, 6 ] ]); - $A->set(7, [ 2, 1 ]); + $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->set(8, [ 1, 3 ]); + $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->set(7, 2, 1); + $A->replace(7, 2, 1); =cut -sub set { +sub replace { my ($self, $value, @indices) = @_; $value = Value::makeValue($value) unless Value::isValue($value); my $dim = $self->degree; diff --git a/t/math_objects/matrix.t b/t/math_objects/matrix.t index 48db06a65..a455b0f98 100644 --- a/t/math_objects/matrix.t +++ b/t/math_objects/matrix.t @@ -215,30 +215,30 @@ 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 'Set a value' => sub { +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->set(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->set(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->set(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->set(9, [ 2, 1, 2 ]), 6, 'Replace an element from a degree 3 matrix, returning replaced element'; + 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->set(10, [ 1, 2, 3 ]); + $B->replace(10, [ 1, 2, 3 ]); }, qr/There should be 2 indices/, 'Check correct number of indices passed'; like dies { - $B->set(10, [ 3, 1 ]); + $B->replace(10, [ 3, 1 ]); }, qr/The first index is outside of the array bounds/, 'Check index is within bounds'; like dies { - $B->set(Point(1, 2), [ 2, 1 ]); + $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'; }; From 79912b0fd5acad8ece316bd4fe1659ecd5790652 Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Thu, 28 May 2026 20:03:35 -0700 Subject: [PATCH 3/3] check that matrix replace method is not used with a Formula --- lib/Value/Matrix.pm | 8 +++++--- t/math_objects/matrix.t | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/Value/Matrix.pm b/lib/Value/Matrix.pm index 5395fc433..3cb15be14 100644 --- a/lib/Value/Matrix.pm +++ b/lib/Value/Matrix.pm @@ -1368,20 +1368,22 @@ Usage: 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") + $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") + $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) + $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; diff --git a/t/math_objects/matrix.t b/t/math_objects/matrix.t index a455b0f98..6e6e2390b 100644 --- a/t/math_objects/matrix.t +++ b/t/math_objects/matrix.t @@ -240,6 +240,9 @@ subtest 'Replace a value' => sub { 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'; };