Phép nhân ma trận tượng trưng


26

Có rất nhiều cách khác nhau để giải thích nhân ma trận. Tôi sẽ gắn bó với một con số duy nhất vì tôi tin rằng hầu hết mọi người ở đây đều quen thuộc với nó (và con số này rất mô tả). Nếu bạn muốn biết thêm thông tin chi tiết, tôi khuyên bạn nên truy cập bài viết trên Wikipedia hoặc phần giải thích trên WolframMathWorld .

Giải thích đơn giản:

Giả sử bạn có hai ma trận AB , trong đó A là 3 nhân 2 và B là 2 nhân 3. Nếu bạn thực hiện phép nhân ma trận trên các ma trận này cho ma trận, thì AB hoặc BA, bạn sẽ nhận được kết quả dưới đây:

nhập mô tả hình ảnh ở đây

Thử thách:

Thực hiện phép nhân ma trận tượng trưng trong ngôn ngữ của bạn. Bạn sẽ lấy hai ma trận làm đầu vào, trong đó mỗi phần tử trong ma trận được biểu thị bằng ký tự ASCII không khoảng trắng (mã điểm 33-126). Bạn phải xuất sản phẩm của các ma trận này.

Các quy tắc liên quan đến đầu ra:

Một sản phẩm của hai mục sẽ không có bất kỳ ký hiệu nào ở giữa. Đó là ab, không a*b, a·b, times(a,b)hoặc một cái gì đó tương tự. Nó aa, không phải a^2.

Tổng các thuật ngữ nên có một khoảng trắng (mã ASCII điểm 32) ở giữa. Đó là a b, không a+b, plus(a,b)hoặc một cái gì đó tương tự.

Lý do cho hai quy tắc đó là: Tất cả các ký tự không phải khoảng trắng được phép làm biểu tượng trong ma trận, do đó sử dụng chúng làm biểu tượng toán học sẽ rất lộn xộn. Vì vậy, những gì bạn thường có thể viết như a*b+c*dsẽ được ab cd.

Bạn có thể chọn thứ tự của các điều khoản. ab cd, dc abcd bađang nói về mặt toán học như nhau, do đó bạn có thể chọn thứ tự ở đây quá. Thứ tự không cần nhất quán miễn là đúng về mặt toán học.

Các quy tắc liên quan đến định dạng ma trận:

Một ma trận có thể được nhập theo bất kỳ định dạng nào bạn thích, ngoại trừ một chuỗi không có dấu phân cách giữa các hàng (điều này là do đầu ra sẽ bị rối hoàn toàn). Cả hai ma trận phải được nhập vào cùng một định dạng. Tất cả các ví dụ dưới đây là những cách hợp lệ để nhập và xuất một ma trận.

"ab;cd"     <- This will look awful, but it's still accepted.

"a,b\nc,d"

[[a,b],[c,d]] 

[a, b]
[c, d]

Tôi biết rằng điều này cho phép rất nhiều định dạng sẽ trông lộn xộn, nhưng thách thức là về việc nhân ma trận, chứ không phải định dạng đầu ra.

Quy tắc chung:

  • Bạn có thể giả sử đầu vào hợp lệ. Phép nhân ma trận sẽ luôn luôn có thể với các kích thước đã cho.
  • Sẽ chỉ có hai ma trận.
  • Bạn có thể cho rằng các ma trận không trống
  • Các hàm tích hợp được chấp nhận (nhưng có thể hơi cồng kềnh do các yêu cầu định dạng).
  • Tất nhiên bạn có thể sử dụng các ký tự thoát trong đầu vào nếu cần thiết ( \'thay vì ').
  • Bất kỳ phương pháp đầu vào và đầu ra tiêu chuẩn là OK .

Các trường hợp thử nghiệm:

Hai ma trận đầu vào được hiển thị với một dòng trống ở giữa. Đầu ra được hiển thị sau Output:. Khi có hai ma trận đầu ra thì nó chỉ hiển thị các đầu ra khác sẽ được chấp nhận.

Trường hợp thử nghiệm số 1

Inputs:
[a]

[b]

Output:
[ab]
[ba]      <- Also OK

Trường hợp thử nghiệm # 2

Inputs:
[a, b]
[1, 4] 
[y, {]

[%, 4, 1] 
[a, b, c]

Output:    
[a% ba, a4 bb, a1 bc] 
[1% 4a, 14 4b, 11 4c] 
[y% {a, y4 {b, y1 {c]

Trường hợp thử nghiệm # 3:

Inputs:
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 1, 2, 3]
[4, 5, 6, 7]

[a]
[b]
[c]
[d]

Output:
[1a 2b 3c 4d]
[5a 6b 7c 8d]
[9a 1b 2c 3d]
[4a 5b 6c 7d]

[d4 c3 b2 a1]      <-- Also OK
[d8 c7 b6 a5]
[1b 9a c2 3d]
[a4 b5 d7 6c]

Nếu phản hồi của bạn đối với các quy tắc về yêu cầu ab cdthay vì a*b+c*dlà: bạn nên tránh các định dạng đầu vào / đầu ra cồng kềnh , thì tôi muốn lưu ý rằng các định dạng đầu vào và đầu ra rất linh hoạt. Việc bạn không thể sử dụng *+cho các sản phẩm và khoản tiền có thể khiến việc sử dụng một công cụ tích hợp đơn giản trở nên khó khăn hơn, nhưng tôi không xem xét điều tiêu cực đó.


Đối với một hàm, việc lấy hai mảng 2D của chuỗi và trả về một chuỗi 2D có thể chấp nhận được không?
Dennis

Vâng, không vấn đề gì. Nhưng kích thước phải khớp, bạn không thể chuyển đổi đầu vào thứ hai. Điều đó có ý nghĩa không?
Stewie Griffin

Nó đã làm, cảm ơn đã làm rõ. Một câu hỏi cuối cùng: Tôi cũng có thể lấy một mảng các ký tự 2D làm đầu vào và trả về một chuỗi các chuỗi 2D không?
Dennis

@Dennis, tôi đã viết: "Cả hai ma trận phải được nhập vào cùng một định dạng." Tôi đã quên đề cập đến ma trận đầu ra ở đó, vì vậy tôi sẽ chỉ giữ nó như thế này. Các đầu vào phải có cùng định dạng nhưng bạn có thể có định dạng đầu ra khác. (Tôi không thực sự thích giải pháp đó, nhưng tôi không muốn thay đổi công cụ ngay bây giờ. Tôi nghĩ rằng đã có một câu trả lời có định dạng đầu vào và đầu ra khác nhau)
Stewie Griffin

Nếu bạn muốn nói câu trả lời của Ruby, tôi đã kiểm tra và câu trả lời đó cũng hoạt động tốt với các chuỗi thay vì các ký tự.
Dennis

Câu trả lời:


9

Haskell , 62 61 byte

e=[]:e
a!b=[unwords.zipWith(++)r<$>foldr(zipWith(:))e b|r<-a]

Hãy thử trực tuyến! Ví dụ sử dụng:

Prelude> [["a","b"],["c","e"]] ! [["f","g"],["h","i"]]
[["af bh","ag bi"],["cf eh","cg ei"]]

Tôi đã tìm thấy một cách để có được một transposehàm trong một byte ngắn hơn so với sử dụng nhập:

import Data.List;transpose
e=[]:e;foldr(zipWith(:))e

Phiên bản cũ có nhập: (62 byte)

import Data.List
a!b=[unwords.zipWith(++)r<$>transpose b|r<-a]

Hãy thử trực tuyến!

Đây là khá giống với câu trả lời của tôi để nhân ma trận không mang tính biểu tượng : a!b=[sum.zipWith(*)r<$>transpose b|r<-a], thay thế các nhân (*)với chuỗi nối (++)sumvới unwordsđó concatenates một danh sách các chuỗi với một không gian ở giữa. Việc nhập là cần thiết cho transposehàm, vì vậy tất cả trong tất cả các chuyển vị của ma trận thứ hai đều sử dụng tới một nửa số byte ...


Phiên bản cũ không nhập: (64 byte)

a![]=[];a!b=(unwords.zipWith(++)[h|h:_<-b]<$>a):a![s:t|_:s:t<-b]

Hãy thử trực tuyến!

Với việc nhập và transposehàm chiếm quá nhiều byte, tôi đã thử giải quyết tác vụ mà không cần nhập. Cho đến nay cách tiếp cận này hóa ra dài hơn hai byte, nhưng nó có thể dễ chơi hơn. Chỉnh sửa: Cách tiếp cận khác ở đầu bây giờ đánh bại việc nhập!

Việc hiểu danh sách [s:t|_:s:t<-b]có các đuôi không trống trong danh sách b, chỉ sử dụng [t|_:t<-b]để lấy đuôi sẽ ngắn hơn 4 byte (thậm chí đánh bại phiên bản nhập) nhưng nối thêm một hàng trống như ["","",""]ma trận mà tôi cho là không được phép.


6

Toán học, 36 byte

Inner[#<>#2&,##,StringRiffle@*List]&

Innerlà một khái quát của Mathicala's Dot(tức là sản phẩm ma trận / vectơ thông thường). Nó khái quát hóa sản phẩm dấu chấm bằng cách cho phép bạn cung cấp hai hàm fg, sẽ được sử dụng thay cho phép nhân và phép cộng thông thường. Chúng tôi sẽ thay thế phép nhân bằng #<>#2&(kết hợp hai ký tự thành một chuỗi) và bổ sung StringRiffle@*List, trước tiên kết hợp tất cả các phép triệu hồi trong một danh sách, sau đó StringRifflenối chúng lại với nhau bằng khoảng trắng.

Người ta có khả năng có thể sử dụng Dottoán tử .và sau đó chuyển đổi kết quả, nhưng rắc rối là những thứ như "a"*"a"sẽ ngay lập tức bị biến thành "a"^2(tương tự đối với các khoản tiền), sẽ gây khó chịu khi phải tách ra một lần nữa.


6

Ruby, 61 byte

->a,b{a.map{|x|b.transpose.map{|y|x.zip(y).map(&:join)*' '}}}

Chạy mẫu:

main(0):007> ->a,b{a.map{|x|b.transpose.map{|y|x.zip(y).map(&:join)*' '}}}[[[?a, ?b], [?1, ?4], [?y, ?{]], [[?%, ?4, ?1], [?a, ?b, ?c]]]
=> [["a% ba", "a4 bb", "a1 bc"], ["1% 4a", "14 4b", "11 4c"], ["y% {a", "y4 {b", "y1 {c"]]
->a,b{
a.map{|x|            # for each row of a
b.transpose.map{|y|  # and for each column of b
x.zip(y)             # match up corresponding elements
.map(&:join)         # join each pair together
*' '                 # join the entire thing on space
}}}

4

Clojure, 53 byte

#(for[a %](for[b(apply map vector %2)](map str a b)))

Chạy với đối số [["a" "b"]["c" "e"]][["f" "g"]["h" "i"]]trả về ((("af" "bh") ("ag" "bi")) (("cf" "eh") ("cg" "ei"))). Điều này thực sự ngắn hơn phiên bản số .


3

APL Dyalog , 10 byte

Đưa ma trận của các ký tự làm đối số trái và phải. Trả về ma trận danh sách các ký tự. (APL đại diện cho chuỗi dưới dạng danh sách các ký tự.)

{∊⍺' '⍵}.,

Dùng thử trực tuyến!

Sản phẩm bên trong thông thường có trong APL +.×, nhưng việc cộng và nhân có thể là bất kỳ chức năng nào, đặc biệt:

Bổ sung đã được thay thế bằng
{ một hàm ẩn danh:  danh sách
 dẹt
⍺ ' ' ⍵bao gồm đối số bên trái, khoảng trắng và đối số bên phải
}

Phép nhân đã được thay thế bằng phép nối, ,


2

Thạch , 7 byte

Z;"þK€€

Đây là một liên kết dyadic lấy BA làm đối số (theo thứ tự đó) và trả về AB . Đầu vào và đầu ra ở dạng mảng 2D của chuỗi, thực sự là mảng 3D của các ký tự. Một byte nữa có thể được lưu bằng cách lấy các mảng ký tự 2D làm đầu vào. Tôi không chắc nếu điều đó được cho phép.

Hãy thử trực tuyến!

Thật khó để xác định Jelly làm gì dưới mui xe khi có liên quan đến chuỗi, vì nó có rất nhiều sự phân tách trước khi in. Đây là cách Jelly đại diện cho đầu vào và đầu ra trong nội bộ.

Làm thế nào nó hoạt động

Z;"þK€€  Dyadic link. Left argument: B. Right argument: A

Z        Zip/transpose B.
 ;"þ     Table vectorized concatenation; for each row in B' and each row in A,
         concatenate the corresponding strings.
    K€€  Join the arrays that correspond to the rows of A by spaces.

2

Prolog,> 256 byte

Tôi đang sử dụng {_ | _} là một findall / 3, _ [_, _] là một số arg / 3 và sum (_) là một số tổng hợp. Tất cả chúng có thể được sử dụng bên trong là / 2:

*(X, Y, Z) :- functor(Y, matrice, _), L is len(X[1]), L =:= len(Y), !,
   M is len(X), N is len(Y[1]),
   Z is { { sum({ X[J,K] * Y[K,I] | between(1,L,K) })
                                  | between(1,N,I) }
                                  | between(1,M,J) }.

Cùng với các định nghĩa bổ sung cho các vị từ đã nói ở trên và không chuẩn là / 2 có thể trả về nhiều hơn số, chắc chắn> 256 byte.


1

JavaScript (ES6), 65 byte

(a,b)=>a.map(c=>b[0].map((_,j)=>c.map((e,i)=>e+b[i][j]).join` `))

Lấy đầu vào là hai mảng ký tự 2D và trả về một chuỗi các chuỗi 2D. Thêm 10 byte để hỗ trợ đầu vào dưới dạng hai mảng 1D của chuỗi.


1

Bình thường, 14 byte

clQmj;sMCd*QCE

Một chương trình lấy đầu vào của hai danh sách các ký tự hai chiều được phân tách bằng dòng mới và in ra một danh sách các chuỗi hai chiều.

Bộ kiểm tra

Làm thế nào nó hoạt động

[Giải thích đến sau]


1

Pip , 17 byte

{Y Zb{a._JsMy}Ma}

Đây là một hàm lấy hai danh sách các chuỗi (ký tự đơn) lồng nhau và trả về một danh sách các chuỗi lồng nhau. Hãy thử trực tuyến! (với hai trường hợp thử nghiệm).

Giải trình

Đối số cho một {}chức năng -delimited được gán cho biến cục bộ ađể e. Đối số đầu tiên của hàm lambda được biểu diễn bởi _.

{               }  Define a function:
   Zb              Zip rows of b, transposing it
 Y                 Yank into global variable y for access in nested function
     {       }Ma   To the rows of a, map this function:
           My       To the rows of y (i.e. columns of b), map this function:
      a._           Concatenate, itemwise, the current row of a and row of y
         Js         Join the resulting list on space
                   The result of the outer map operation is returned
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.