Element-wise operations: Difference between revisions
→{{header|Go}}: added version with flat representation |
|||
Line 494: | Line 494: | ||
841 961 1369) |
841 961 1369) |
||
</lang> And similarly for <tt>+</tt>, <tt>-</tt>, <tt>%</tt> (division), and <tt>^</tt> . |
</lang> And similarly for <tt>+</tt>, <tt>-</tt>, <tt>%</tt> (division), and <tt>^</tt> . |
||
=={{header|Mathematica}}== |
|||
<lang Mathematica>S = 10 ; M = {{7, 11, 13}, {17 , 19, 23} , {29, 31, 37}}; |
|||
M + S |
|||
M - S |
|||
M * S |
|||
M / S |
|||
M ^ S |
|||
M + M |
|||
M - M |
|||
M * M |
|||
M / M |
|||
M ^ M |
|||
Gives: |
|||
->{{17, 21, 23}, {27, 29, 33}, {39, 41, 47}} |
|||
->{{-3, 1, 3}, {7, 9, 13}, {19, 21, 27}} |
|||
->{{70, 110, 130}, {170, 190, 230}, {290, 310, 370}} |
|||
->{{7/10, 11/10, 13/10}, {17/10, 19/10, 23/10}, {29/10, 31/10, 37/10}} |
|||
->{{282475249, 25937424601, 137858491849}, {2015993900449, |
|||
6131066257801, 41426511213649}, {420707233300201, 819628286980801, |
|||
4808584372417849}} |
|||
->{{14, 22, 26}, {34, 38, 46}, {58, 62, 74}} |
|||
->{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}} |
|||
->{{49, 121, 169}, {289, 361, 529}, {841, 961, 1369}} |
|||
->{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}} |
|||
->{{823543, 285311670611, 302875106592253}, {827240261886336764177, |
|||
1978419655660313589123979, |
|||
20880467999847912034355032910567}, {2567686153161211134561828214731016126483469, |
|||
17069174130723235958610643029059314756044734431, |
|||
10555134955777783414078330085995832946127396083370199442517}}</lang> |
|||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
Line 505: | Line 539: | ||
subMs(A,s)=A-matrix(#A[,1],#A,i,j,s); |
subMs(A,s)=A-matrix(#A[,1],#A,i,j,s); |
||
powMs(A,s)=matrix(#A[,1],#A,i,j,A[i,j]^s);</lang> |
powMs(A,s)=matrix(#A[,1],#A,i,j,A[i,j]^s);</lang> |
||
=={{header|Perl 6}}== |
=={{header|Perl 6}}== |
||
Perl 6 already implements this and other metaoperators as higher-order functions (cross, zip, reduce, triangle, etc.) that are usually accessed through a meta-operator syntactic sugar that is productive over all appropriate operators, including user-defined ones. In this case, a dwimmy element-wise operator (generically known as a "hyper") is indicated by surrounding the operator with double angle quotes. Hypers dwim on the pointy end with cyclic APL semantics as necessary. You can turn the quote the other way to suppress dwimmery on that end. In this case we could have used <tt>»op»</tt> instead of <tt>«op»</tt> since the short side is always on the right.<lang perl6>my @a = |
Perl 6 already implements this and other metaoperators as higher-order functions (cross, zip, reduce, triangle, etc.) that are usually accessed through a meta-operator syntactic sugar that is productive over all appropriate operators, including user-defined ones. In this case, a dwimmy element-wise operator (generically known as a "hyper") is indicated by surrounding the operator with double angle quotes. Hypers dwim on the pointy end with cyclic APL semantics as necessary. You can turn the quote the other way to suppress dwimmery on that end. In this case we could have used <tt>»op»</tt> instead of <tt>«op»</tt> since the short side is always on the right.<lang perl6>my @a = |
Revision as of 08:18, 11 January 2012
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
Similar to Matrix multiplication and Matrix transposition, the task is to implement basic element-wise matrix-matrix and scalar-matrix operations, which can be referred to in other, higher-order tasks. Implement addition, subtraction, multiplication, division and exponentiation.
Extend the task if necessary to include additional basic operations, which should not require their own specialised task. A reference implementation in Common Lisp is included.
ALGOL 68
Note: This specimen retains the original D coding style.
<lang algol68>#!/usr/local/bin/a68g --script #
MODE SCALAR = REAL; FORMAT scalar fmt = $g(0, 2)$;
MODE MATRIX = [3, 3]SCALAR; FORMAT vector fmt = $"("n(2 UPB LOC MATRIX - 2 LWB LOC MATRIX)(f(scalar fmt)", ")f(scalar fmt)")"$; FORMAT matrix fmt = $"("n(1 UPB LOC MATRIX - 1 LWB LOC MATRIX)(f(vector fmt)","l" ")f(vector fmt)")"$;
PROC elementwise op = (PROC(SCALAR, SCALAR)SCALAR op, MATRIX a, UNION(SCALAR, MATRIX) b)MATRIX: (
[LWB a:UPB a, 2 LWB a:2 UPB a]SCALAR out; CASE b IN (SCALAR b): FOR i FROM LWB out TO UPB out DO FOR j FROM 2 LWB out TO 2 UPB out DO out[i, j]:=op(a[i, j], b) OD OD, (MATRIX b): FOR i FROM LWB out TO UPB out DO FOR j FROM 2 LWB out TO 2 UPB out DO out[i, j]:=op(a[i, j], b[i, j]) OD OD ESAC; out
);
PROC plus = (SCALAR a, b)SCALAR: a+b,
minus = (SCALAR a, b)SCALAR: a-b, times = (SCALAR a, b)SCALAR: a*b, div = (SCALAR a, b)SCALAR: a/b, pow = (SCALAR a, b)SCALAR: a**b;
main:(
SCALAR scalar := 10; MATRIX matrix = (( 7, 11, 13), (17, 19, 23), (29, 31, 37));
printf(($f(matrix fmt)";"l$, elementwise op(plus, matrix, scalar), elementwise op(minus, matrix, scalar), elementwise op(times, matrix, scalar), elementwise op(div, matrix, scalar), elementwise op(pow, matrix, scalar),
elementwise op(plus, matrix, matrix), elementwise op(minus, matrix, matrix), elementwise op(times, matrix, matrix), elementwise op(div, matrix, matrix), elementwise op(pow, matrix, matrix) ))
)</lang> Output:
((17.00, 21.00, 23.00), (27.00, 29.00, 33.00), (39.00, 41.00, 47.00)); ((-3.00, 1.00, 3.00), (7.00, 9.00, 13.00), (19.00, 21.00, 27.00)); ((70.00, 110.00, 130.00), (170.00, 190.00, 230.00), (290.00, 310.00, 370.00)); ((.70, 1.10, 1.30), (1.70, 1.90, 2.30), (2.90, 3.10, 3.70)); ((282475249.00, 25937424601.00, 137858491849.00), (2015993900449.00, 6131066257800.99, 41426511213648.90), (420707233300200.00, 819628286980799.00, 4808584372417840.00)); ((14.00, 22.00, 26.00), (34.00, 38.00, 46.00), (58.00, 62.00, 74.00)); ((.00, .00, .00), (.00, .00, .00), (.00, .00, .00)); ((49.00, 121.00, 169.00), (289.00, 361.00, 529.00), (841.00, 961.00, 1369.00)); ((1.00, 1.00, 1.00), (1.00, 1.00, 1.00), (1.00, 1.00, 1.00)); ((823543.00, 285311670611.00, 302875106592253.00), (827240261886340000000.00, 1978419655660300000000000.00, 20880467999847700000000000000000.00), (2567686153161210000000000000000000000000000.00, 17069174130723200000000000000000000000000000000.00, 10555134955777600000000000000000000000000000000000000000000.00));
Common Lisp
Element-wise matrix-matrix operations. Matrices are represented as 2D-arrays. <lang lisp>(defun element-wise-matrix (fn A B)
(let* ((len (array-total-size A)) (m (car (array-dimensions A))) (n (cadr (array-dimensions A))) (C (make-array `(,m ,n) :initial-element 0.0d0))) (loop for i from 0 to (1- len) do (setf (row-major-aref C i) (funcall fn (row-major-aref A i) (row-major-aref B i)))) C))
- A.+B, A.-B, A.*B, A./B, A.^B.
(defun m+ (A B) (element-wise-matrix #'+ A B)) (defun m- (A B) (element-wise-matrix #'- A B)) (defun m* (A B) (element-wise-matrix #'* A B)) (defun m/ (A B) (element-wise-matrix #'/ A B)) (defun m^ (A B) (element-wise-matrix #'expt A B))</lang>
Elementwise scalar-matrix operations. <lang lisp>(defun element-wise-scalar (fn A c)
(let* ((len (array-total-size A)) (m (car (array-dimensions A))) (n (cadr (array-dimensions A))) (B (make-array `(,m ,n) :initial-element 0.0d0))) (loop for i from 0 to (1- len) do (setf (row-major-aref B i) (funcall fn (row-major-aref A i) c))) B))
- c.+A, A.-c, c.*A, A./c, A.^c.
(defun .+ (c A) (element-wise-scalar #'+ A c)) (defun .- (A c) (element-wise-scalar #'- A c)) (defun .* (c A) (element-wise-scalar #'* A c)) (defun ./ (A c) (element-wise-scalar #'/ A c)) (defun .^ (A c) (element-wise-scalar #'expt A c))</lang>
C
Matrices are 2D double arrays. <lang c>#include <math.h>
- define for_i for(i = 0; i < h; i++)
- define for_j for(j = 0; j < w; j++)
- define _M double**
- define OPM(name, _op_) \
void eop_##name(_M a, _M b, _M c, int w, int h){int i,j;\ for_i for_j c[i][j] = a[i][j] _op_ b[i][j];} OPM(add, +);OPM(sub, -);OPM(mul, *);OPM(div, /);
- define OPS(name, res) \
void eop_s_##name(_M a, double s, _M b, int w, int h) {double x;int i,j;\ for_i for_j {x = a[i][j]; b[i][j] = res;}} OPS(mul, x*s);OPS(div, x/s);OPS(add, x+s);OPS(sub, x-s);OPS(pow, pow(x, s));</lang>
D
The vector power operator is not enabled yet: <lang d>import std.stdio;
T[][] elementwiseMat(string op, T, U)(T[][] A, U B) if (is(U == T) || is(U == T[][])) {
static if (is(U == T[][])) assert(A.length == B.length); if (!A.length) return null; auto R = new typeof(return)(A.length, A[0].length);
foreach (r, row; A) static if (is(U == T)) { R[r][] = mixin("row[] " ~ op ~ "B"); } else { assert(row.length == B[r].length); R[r][] = mixin("row[] " ~ op ~ "B[r][]"); }
return R;
}
void main() {
auto scalar = 10; auto matrix = [[7, 11, 13], [17, 19, 23], [29, 31, 37]];
writeln(elementwiseMat!q{ + }(matrix, scalar)); writeln(elementwiseMat!q{ - }(matrix, scalar)); writeln(elementwiseMat!q{ * }(matrix, scalar)); writeln(elementwiseMat!q{ / }(matrix, scalar)); //writeln(elementwiseMat!q{ ^^ }(matrix, scalar)); writeln();
writeln(elementwiseMat!q{ + }(matrix, matrix)); writeln(elementwiseMat!q{ - }(matrix, matrix)); writeln(elementwiseMat!q{ * }(matrix, matrix)); writeln(elementwiseMat!q{ / }(matrix, matrix)); //writeln(elementwiseMat!q{ ^^ }(matrix, matrix));
}</lang> Output:
[[17, 21, 23], [27, 29, 33], [39, 41, 47]] [[-3, 1, 3], [7, 9, 13], [19, 21, 27]] [[70, 110, 130], [170, 190, 230], [290, 310, 370]] [[0, 1, 1], [1, 1, 2], [2, 3, 3]] [[14, 22, 26], [34, 38, 46], [58, 62, 74]] [[0, 0, 0], [0, 0, 0], [0, 0, 0]] [[49, 121, 169], [289, 361, 529], [841, 961, 1369]] [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
Go
2D representation
<lang go>package main
import (
"fmt" "math"
)
type matrix [][]float64 type binaryFunc64 func(float64, float64) float64
func like(m matrix) matrix {
cols := len(m[0]) r := make([][]float64, len(m)) all := make([]float64, len(m)*cols) for i := range r { r[i] = all[i*cols : (i+1)*cols] } return r
}
func elementWiseMM(m1, m2 matrix, f binaryFunc64) matrix {
z := like(m1) for rx, row := range m1 { for cx, ele := range row { z[rx][cx] = f(ele, m2[rx][cx]) } } return z
}
func elementWiseMS(m matrix, s float64, f binaryFunc64) matrix {
z := like(m) for rx, row := range m { for cx, ele := range row { z[rx][cx] = f(ele, s) } } return z
}
func add(a, b float64) float64 { return a + b } func sub(a, b float64) float64 { return a - b } func mul(a, b float64) float64 { return a * b } func div(a, b float64) float64 { return a / b } func exp(a, b float64) float64 { return math.Pow(a, b) }
func ewmmAdd(m1, m2 matrix) matrix { return elementWiseMM(m1, m2, add) } func ewmmSub(m1, m2 matrix) matrix { return elementWiseMM(m1, m2, sub) } func ewmmMul(m1, m2 matrix) matrix { return elementWiseMM(m1, m2, mul) } func ewmmDiv(m1, m2 matrix) matrix { return elementWiseMM(m1, m2, div) } func ewmmExp(m1, m2 matrix) matrix { return elementWiseMM(m1, m2, exp) }
func ewmsAdd(m matrix, s float64) matrix { return elementWiseMS(m, s, add) } func ewmsSub(m matrix, s float64) matrix { return elementWiseMS(m, s, sub) } func ewmsMul(m matrix, s float64) matrix { return elementWiseMS(m, s, mul) } func ewmsDiv(m matrix, s float64) matrix { return elementWiseMS(m, s, div) } func ewmsExp(m matrix, s float64) matrix { return elementWiseMS(m, s, exp) }
func main() {
m1 := matrix{{3, 1, 4}, {1, 5, 9}} m2 := matrix{{2, 7, 1}, {8, 2, 8}} fmt.Println("m1:") m1.print() fmt.Println("m2:") m2.print() fmt.Println("m1 + m2:") ewmmAdd(m1, m2).print() fmt.Println("m1 - m2:") ewmmSub(m1, m2).print() fmt.Println("m1 * m2:") ewmmMul(m1, m2).print() fmt.Println("m1 / m2:") ewmmDiv(m1, m2).print() fmt.Println("m1 ^ m2:") ewmmExp(m1, m2).print() s := .5 fmt.Println("s:", s) fmt.Println("m1 + s") ewmsAdd(m1, s).print() fmt.Println("m1 - s:") ewmsSub(m1, s).print() fmt.Println("m1 * s:") ewmsMul(m1, s).print() fmt.Println("m1 / s:") ewmsDiv(m1, s).print() fmt.Println("m1 ^ s:") ewmsExp(m1, s).print()
}
func (m matrix) print() {
const f = "%6.3f " for _, r := range m { for _, e := range r { fmt.Printf(f, e) } fmt.Println() }
}</lang> Output:
m1: 3.000 1.000 4.000 1.000 5.000 9.000 m2: 2.000 7.000 1.000 8.000 2.000 8.000 m1 + m2: 5.000 8.000 5.000 9.000 7.000 17.000 m1 - m2: 1.000 -6.000 3.000 -7.000 3.000 1.000 m1 * m2: 6.000 7.000 4.000 8.000 10.000 72.000 m1 / m2: 1.500 0.143 4.000 0.125 2.500 1.125 m1 ^ m2: 9.000 1.000 4.000 1.000 25.000 43046721.000 s: 0.5 m1 + s 3.500 1.500 4.500 1.500 5.500 9.500 m1 - s: 2.500 0.500 3.500 0.500 4.500 8.500 m1 * s: 1.500 0.500 2.000 0.500 2.500 4.500 m1 / s: 6.000 2.000 8.000 2.000 10.000 18.000 m1 ^ s: 1.732 1.000 2.000 1.000 2.236 3.000
Flat representation
As described at Matrix_transposition#Flat_representation, the flat representation really shines here. The elements can be addressed efficiently without regard to rows and columns. <lang go>package main
import (
"fmt" "math"
)
type matrix struct {
ele []float64 stride int
}
func matrixFromRows(rows [][]float64) *matrix {
if len(rows) == 0 { return &matrix{nil, 0} } m := &matrix{make([]float64, len(rows)*len(rows[0])), len(rows[0])} for rx, row := range rows { copy(m.ele[rx*m.stride:(rx+1)*m.stride], row) } return m
}
func like(m *matrix) *matrix {
return &matrix{make([]float64, len(m.ele)), m.stride}
}
func (m *matrix) print(heading string) {
if heading > "" { fmt.Print("\n", heading, "\n") } for e := 0; e < len(m.ele); e += m.stride { fmt.Printf("%6.3f ", m.ele[e:e+m.stride]) fmt.Println() }
}
type binaryFunc64 func(float64, float64) float64
func elementWiseMM(m1, m2 *matrix, f binaryFunc64) *matrix {
z := like(m1) for i, m1e := range m1.ele { z.ele[i] = f(m1e, m2.ele[i]) } return z
}
func elementWiseMS(m *matrix, s float64, f binaryFunc64) *matrix {
z := like(m) for i, e := range m.ele { z.ele[i] = f(e, s) } return z
}
func add(a, b float64) float64 { return a + b } func sub(a, b float64) float64 { return a - b } func mul(a, b float64) float64 { return a * b } func div(a, b float64) float64 { return a / b } func exp(a, b float64) float64 { return math.Pow(a, b) }
func ewmmAdd(m1, m2 *matrix) *matrix { return elementWiseMM(m1, m2, add) } func ewmmSub(m1, m2 *matrix) *matrix { return elementWiseMM(m1, m2, sub) } func ewmmMul(m1, m2 *matrix) *matrix { return elementWiseMM(m1, m2, mul) } func ewmmDiv(m1, m2 *matrix) *matrix { return elementWiseMM(m1, m2, div) } func ewmmExp(m1, m2 *matrix) *matrix { return elementWiseMM(m1, m2, exp) }
func ewmsAdd(m *matrix, s float64) *matrix { return elementWiseMS(m, s, add) } func ewmsSub(m *matrix, s float64) *matrix { return elementWiseMS(m, s, sub) } func ewmsMul(m *matrix, s float64) *matrix { return elementWiseMS(m, s, mul) } func ewmsDiv(m *matrix, s float64) *matrix { return elementWiseMS(m, s, div) } func ewmsExp(m *matrix, s float64) *matrix { return elementWiseMS(m, s, exp) }
func main() {
m1 := matrixFromRows([][]float64{{3, 1, 4}, {1, 5, 9}}) m2 := matrixFromRows([][]float64{{2, 7, 1}, {8, 2, 8}}) m1.print("m1:") m2.print("m2:") ewmmAdd(m1, m2).print("m1 + m2:") ewmmSub(m1, m2).print("m1 - m2:") ewmmMul(m1, m2).print("m1 * m2:") ewmmDiv(m1, m2).print("m1 / m2:") ewmmExp(m1, m2).print("m1 ^ m2:") s := .5 fmt.Println("\ns:", s) ewmsAdd(m1, s).print("m1 + s:") ewmsSub(m1, s).print("m1 - s:") ewmsMul(m1, s).print("m1 * s:") ewmsDiv(m1, s).print("m1 / s:") ewmsExp(m1, s).print("m1 ^ s:")
}</lang>
J
Solution: J's arithmetical primitives act elementwise by default (in J parlance, such operations are known as "scalar" or "rank zero", which means they generalize to high-order arrays transparently, operating elementwise). Thus: <lang j> scalar =: 10
vector =: 2 3 5 matrix =: 3 3 $ 7 11 13 17 19 23 29 31 37
scalar * scalar
100
scalar * vector
20 30 50
scalar * matrix 70 110 130
170 190 230 290 310 370
vector * vector
4 9 25
vector * matrix 14 22 26 51 57 69
145 155 185
matrix * matrix 49 121 169
289 361 529 841 961 1369</lang> And similarly for +, -, % (division), and ^ .
K
<lang K> scalar: 10
vector: 2 3 5 matrix: 3 3 # 7 11 13 17 19 23 29 31 37
scalar * scalar
100
scalar * vector
20 30 50
scalar * matrix
(70 110 130
170 190 230 290 310 370) vector * vector
4 9 25
vector * matrix
(14 22 26
51 57 69 145 155 185) matrix * matrix
(49 121 169
289 361 529 841 961 1369)
</lang> And similarly for +, -, % (division), and ^ .
Mathematica
<lang Mathematica>S = 10 ; M = {{7, 11, 13}, {17 , 19, 23} , {29, 31, 37}}; M + S M - S M * S M / S M ^ S
M + M M - M M * M M / M M ^ M
Gives:
->{{17, 21, 23}, {27, 29, 33}, {39, 41, 47}} ->{{-3, 1, 3}, {7, 9, 13}, {19, 21, 27}} ->{{70, 110, 130}, {170, 190, 230}, {290, 310, 370}} ->{{7/10, 11/10, 13/10}, {17/10, 19/10, 23/10}, {29/10, 31/10, 37/10}} ->{{282475249, 25937424601, 137858491849}, {2015993900449,
6131066257801, 41426511213649}, {420707233300201, 819628286980801, 4808584372417849}}
->{{14, 22, 26}, {34, 38, 46}, {58, 62, 74}} ->{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}} ->{{49, 121, 169}, {289, 361, 529}, {841, 961, 1369}} ->{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}} ->{{823543, 285311670611, 302875106592253}, {827240261886336764177,
1978419655660313589123979, 20880467999847912034355032910567}, {2567686153161211134561828214731016126483469, 17069174130723235958610643029059314756044734431, 10555134955777783414078330085995832946127396083370199442517}}</lang>
PARI/GP
GP already implements element-wise matrix-matrix addition and subtraction and element-wise scalar-matrix multiplication and division. Other element-wise matrix-matrix functions: <lang parigp>multMM(A,B)=matrix(#A[,1],#A,i,j,A[i,j]*B[i,j]); divMM(A,B)=matrix(#A[,1],#A,i,j,A[i,j]/B[i,j]); powMM(A,B)=matrix(#A[,1],#A,i,j,A[i,j]^B[i,j]);</lang>
Other element-wise scalar-matrix functions: <lang parigp>addMs(A,s)=A+matrix(#A[,1],#A,i,j,s); subMs(A,s)=A-matrix(#A[,1],#A,i,j,s); powMs(A,s)=matrix(#A[,1],#A,i,j,A[i,j]^s);</lang>
Perl 6
Perl 6 already implements this and other metaoperators as higher-order functions (cross, zip, reduce, triangle, etc.) that are usually accessed through a meta-operator syntactic sugar that is productive over all appropriate operators, including user-defined ones. In this case, a dwimmy element-wise operator (generically known as a "hyper") is indicated by surrounding the operator with double angle quotes. Hypers dwim on the pointy end with cyclic APL semantics as necessary. You can turn the quote the other way to suppress dwimmery on that end. In this case we could have used »op» instead of «op» since the short side is always on the right.<lang perl6>my @a =
[1,2,3], [4,5,6], [7,8,9];
sub msay(@x) {
.perl.say for @x; say ;
}
msay @a «+» @a; msay @a «-» @a; msay @a «*» @a; msay @a «/» @a; msay @a «+» [1,2,3]; msay @a «-» [1,2,3]; msay @a «*» [1,2,3]; msay @a «/» [1,2,3]; msay @a «+» 2; msay @a «-» 2; msay @a «*» 2; msay @a «/» 2;</lang> Output:
[2, 4, 6] [8, 10, 12] [14, 16, 18] [0, 0, 0] [0, 0, 0] [0, 0, 0] [1, 4, 9] [16, 25, 36] [49, 64, 81] [1/1, 1/1, 1/1] [1/1, 1/1, 1/1] [1/1, 1/1, 1/1] [2, 3, 4] [6, 7, 8] [10, 11, 12] [0, 1, 2] [2, 3, 4] [4, 5, 6] [1, 2, 3] [8, 10, 12] [21, 24, 27] [1/1, 2/1, 3/1] [2/1, 5/2, 3/1] [7/3, 8/3, 3/1] [3, 4, 5] [6, 7, 8] [9, 10, 11] [-1, 0, 1] [2, 3, 4] [5, 6, 7] [2, 4, 6] [8, 10, 12] [14, 16, 18] [1/2, 1/1, 3/2] [2/1, 5/2, 3/1] [7/2, 4/1, 9/2]
In addition to calling the underlying higher-order functions directly, it's supposed to be possible to name a function like &[«+»] to get the first example above, but current implementations as of 2011-06 do not yet support that.
PL/I
Any arithmetic operation can be applied to elements of arrays. These examples iillustrate element-by-element multiplication, but addition, subtraction, division, and exponentiation can also be written. <lang PL/I> declare (matrix(3,3), vector(3), scalar) fixed; declare (m(3,3), v(3) fixed;
m = scalar * matrix; m = vector * matrix; m = matrix * matrix;
v = scalar * vector; v = vector * vector; </lang>
PicoLisp
<lang PicoLisp>(de elementWiseMatrix (Fun Mat1 Mat2)
(mapcar '((L1 L2) (mapcar Fun L1 L2)) Mat1 Mat2) )
(de elementWiseScalar (Fun Mat Scalar)
(elementWiseMatrix Fun Mat (circ (circ Scalar))) )</lang>
Test:
(let (S 10 M '((7 11 13) (17 19 23) (29 31 37))) (println (elementWiseScalar + M S)) (println (elementWiseScalar - M S)) (println (elementWiseScalar * M S)) (println (elementWiseScalar / M S)) (println (elementWiseScalar ** M S)) (prinl) (println (elementWiseMatrix + M M)) (println (elementWiseMatrix - M M)) (println (elementWiseMatrix * M M)) (println (elementWiseMatrix / M M)) (println (elementWiseMatrix ** M M)) )
Output:
((17 21 23) (27 29 33) (39 41 47)) ((-3 1 3) (7 9 13) (19 21 27)) ((70 110 130) (170 190 230) (290 310 370)) ((0 1 1) (1 1 2) (2 3 3)) ((282475249 25937424601 137858491849) (2015993900449 6131066257801 ... ((14 22 26) (34 38 46) (58 62 74)) ((0 0 0) (0 0 0) (0 0 0)) ((49 121 169) (289 361 529) (841 961 1369)) ((1 1 1) (1 1 1) (1 1 1)) ((823543 285311670611 302875106592253) (827240261886336764177 ...
Python
<lang python>>>> import random >>> from operator import add, sub, mul, floordiv >>> from pprint import pprint as pp >>> >>> def ewise(matrix1, matrix2, op): return [[op(e1,e2) for e1,e2 in zip(row1, row2)] for row1,row2 in zip(matrix1, matrix2)]
>>> m,n = 3,4 # array dimensions >>> a0 = [[random.randint(1,9) for y in range(n)] for x in range(m)] >>> a1 = [[random.randint(1,9) for y in range(n)] for x in range(m)] >>> pp(a0); pp(a1) [[7, 8, 7, 4], [4, 9, 4, 1], [2, 3, 6, 4]] [[4, 5, 1, 6], [6, 8, 3, 4], [2, 2, 6, 3]] >>> pp(ewise(a0, a1, add)) [[11, 13, 8, 10], [10, 17, 7, 5], [4, 5, 12, 7]] >>> pp(ewise(a0, a1, sub)) [[3, 3, 6, -2], [-2, 1, 1, -3], [0, 1, 0, 1]] >>> pp(ewise(a0, a1, mul)) [[28, 40, 7, 24], [24, 72, 12, 4], [4, 6, 36, 12]] >>> pp(ewise(a0, a1, floordiv)) [[1, 1, 7, 0], [0, 1, 1, 0], [1, 1, 1, 1]] >>> pp(ewise(a0, a1, pow)) [[2401, 32768, 7, 4096], [4096, 43046721, 64, 1], [4, 9, 46656, 64]] >>> pp(ewise(a0, a1, lambda x, y:2*x - y)) [[10, 11, 13, 2], [2, 10, 5, -2], [2, 4, 6, 5]] >>> >>> def s_ewise(scalar1, matrix1, op): return [[op(scalar1, e1) for e1 in row1] for row1 in matrix1]
>>> scalar = 10 >>> a0 [[7, 8, 7, 4], [4, 9, 4, 1], [2, 3, 6, 4]] >>> for op in ( add, sub, mul, floordiv, pow, lambda x, y:2*x - y ): print("%10s :" % op.__name__, s_ewise(scalar, a0, op))
add : [[17, 18, 17, 14], [14, 19, 14, 11], [12, 13, 16, 14]] sub : [[3, 2, 3, 6], [6, 1, 6, 9], [8, 7, 4, 6]] mul : [[70, 80, 70, 40], [40, 90, 40, 10], [20, 30, 60, 40]] floordiv : [[1, 1, 1, 2], [2, 1, 2, 10], [5, 3, 1, 2]] pow : [[10000000, 100000000, 10000000, 10000], [10000, 1000000000, 10000, 10], [100, 1000, 1000000, 10000]] <lambda> : [[13, 12, 13, 16], [16, 11, 16, 19], [18, 17, 14, 16]]
>>> </lang>
Tcl
<lang tcl>package require Tcl 8.5 proc alias {name args} {uplevel 1 [list interp alias {} $name {} {*}$args]}
- Engine for elementwise operations between matrices
proc elementwiseMatMat {lambda A B} {
set C {} foreach rA $A rB $B {
set rC {} foreach vA $rA vB $rB { lappend rC [apply $lambda $vA $vB] } lappend C $rC
} return $C
}
- Lift some basic math ops
alias m+ elementwiseMatMat {{a b} {expr {$a+$b}}} alias m- elementwiseMatMat {{a b} {expr {$a-$b}}} alias m* elementwiseMatMat {{a b} {expr {$a*$b}}} alias m/ elementwiseMatMat {{a b} {expr {$a/$b}}} alias m** elementwiseMatMat {{a b} {expr {$a**$b}}}
- Engine for elementwise operations between a matrix and a scalar
proc elementwiseMatSca {lambda A b} {
set C {} foreach rA $A {
set rC {} foreach vA $rA { lappend rC [apply $lambda $vA $b] } lappend C $rC
} return $C
}
- Lift some basic math ops
alias .+ elementwiseMatSca {{a b} {expr {$a+$b}}} alias .- elementwiseMatSca {{a b} {expr {$a-$b}}} alias .* elementwiseMatSca {{a b} {expr {$a*$b}}} alias ./ elementwiseMatSca {{a b} {expr {$a/$b}}} alias .** elementwiseMatSca {{a b} {expr {$a**$b}}}</lang>