Hermitian matrix?

18

1

Note that this challenge requires no handling or understanding of complex numbers.

Given a non-empty square matrix where every element is a two-element (Re,Im) integer list, determine (giving any truthy/falsy values or any two consistent values) whether this represents a Hermitian matrix.

Note that the input is a 3D array of integers; not a 2D array of complex numbers. If your language cannot take a 3D array directly, you may take a flat list (and the n×n or n×n×2 shape if that helps).

A matrix is Hermitian if it equals its own conjugate transpose. In other words, if you flip it across its top-left to bottom-right diagonal and negate the second element of all the two-element leaf-lists, it is identical to the input matrix. Note that the order of flipping and negating is irrelevant, so you may negate first, and flip afterwards.

Walk-though example

This example uses JSON with superfluous white-space to ease reading:

[[ [2, 0] , [2, 1] , [4, 0] ],
 [ [2,-1] , [3, 0] , [0, 1] ],
 [ [4, 0] , [0,-1] , [1, 0] ]]

Transpose (flip across NW—SE diagonal):

[[ [2, 0] , [2,-1] , [4, 0] ],
 [ [2, 1] , [3, 0] , [0,-1] ],
 [ [4, 0] , [0, 1] , [1, 0] ]]

Negate second elements of leaf-lists:

[[ [2, 0] , [2, 1] , [4, 0] ],
 [ [2,-1] , [3, 0] , [0, 1] ],
 [ [4, 0] , [0,-1] , [1, 0] ]]

As this is identical to the input, the matrix is Hermitian.

Test cases

Hermitian

[[[2,0],[2,1],[4,0]],[[2,-1],[3,0],[0,1]],[[4,0],[0,-1],[1,0]]]

[[[1,0],[2,0]],[[2,0],[1,0]]]

[[[1,0],[2,-3]],[[2,3],[1,0]]]

[[[42,0]]]

Non-Hermitian

[[[2,0],[2,1],[4,0]],[[2,-1],[3,0],[0,1]],[[4,0],[0,-1],[1,-1]]]

[[[0,1],[0,2]],[[0,2],[0,1]]]

[[[1,0],[2,3]],[[2,3],[1,0]]]

[[[3,2]]]

Adám

Posted 2018-02-26T13:01:52.547

Reputation: 37 779

@LuisMendo I'm still thinking. Any ideas? – Adám – 2018-02-26T14:38:23.277

For the record, a new Meta-post. (I haven't voted to close, but I see someone has, so I'm curious what the community thinks about this).

– Stewie Griffin – 2018-02-26T15:06:08.997

@LuisMendo What do other challenges do when 3+D arrays are required? – Adám – 2018-02-26T15:11:38.563

@LuisMendo Then I don't need to specify anything more, do I? – Adám – 2018-02-26T15:36:32.250

5@Adám I would make it as explicit as possible, but it's up to you. Flexibility in input and output formats is usually desired, but cannot be inferred by default, specially when you say the input is a 3D array of real numbers; not a 2D array of complex numbers. It's not clear how broad your concept of 3D array input format is – Luis Mendo – 2018-02-26T16:04:57.793

@WheatWizard every element is a two-element (Re,Im) integer list – Adám – 2018-02-26T16:47:18.447

3@Adám Can a pair of 2D matrices (one for real part, one for imaginary part) be taken as input? – dylnan – 2018-02-26T16:53:08.747

1@dylnan No. Input has to be a single structure representing some sort of 3-dimensionality where the leaf dimension contains the Re-Im pairs. – Adám – 2018-02-26T18:55:36.687

@LuisMendo What's unclear about the output? – Adám – 2018-02-26T18:56:13.547

@LuisMendo OK, I've updated output. I don't know how to fix input. Any ideas? How about JSON? – Adám – 2018-02-26T19:13:54.220

@Adam My idea would be to leave it flexible as usual, and to clearly state that in the challenge. For example, I don’t see why complex input should be forbidden (but of course keep that restriction if you have a reason). At least I would allow a flat array with shape specified separately, or two separate matrices, or of course a 3D array directly – Luis Mendo – 2018-02-26T19:45:22.683

@LuisMendo You don't need shape, though, as the last dimension is always length 2, and the first two dimensions have same length. Anyway, added. – Adám – 2018-02-26T19:47:45.780

@LuisMendo No. Added. – Adám – 2018-02-26T20:08:19.937

Answers

10

R, 71 48 47 bytes

function(A)all(Conj(t(B<-A[,,1]+A[,,2]*1i))==B)

Takes a 3D array of real numbers, make a 2D array of imaginary numbers, transpose, conjugate and compare.

Thanks to @Giuseppe for reducing the byte count by an astounding 23 bytes, and to @Vlo for the final 1!

Try it online!

Example:

> A <- array(c(2,2,4,2,3,0,4,0,1,0,-1,0,1,0,-1,0,1,0),dim=c(3,3,2))
> A
, , 1

     [,1] [,2] [,3]
[1,]    2    2    4
[2,]    2    3    0
[3,]    4    0    1

, , 2

     [,1] [,2] [,3]
[1,]    0    1    0
[2,]   -1    0    1
[3,]    0   -1    0

> f <- function(A)all(Conj(t(B<-A[,,1]+A[,,2]*1i))==B)
> f(A)
[1] TRUE

plannapus

Posted 2018-02-26T13:01:52.547

Reputation: 8 610

1B=A[,,1]+A[,,2]*1i should save a few bytes. – Giuseppe – 2018-02-26T14:59:56.140

@GIuseppe arf I thought i tried that but apparently not. Thanks! – plannapus – 2018-02-26T15:00:58.300

1Also, isSymmetric exists and works for Hermitian complex matrices but the 1x1 case is tricky since [ drops attributes and it results in a complex rather than a matrix – Giuseppe – 2018-02-26T15:02:09.823

2function(A)all(Conj(t(B<-A[,,1]+A[,,2]*1i))==B) In-line assignment saves 1. – Vlo – 2018-02-27T15:53:41.883

7

Octave, 39 34 31 bytes

@(x)(y=x(:,:,1)+j*x(:,:,2))==y'

Try it online!

Saved 3 bytes thanks to Luis Mendo who informed me about the clarifications in the challenge text.

Explanation:

In MATLAB and Octave, ' is the conjugate complex transpose, not the "regular" transpose.

We create a variable y inline that's the first layer of the 3D matrix plus the second layer multiplied with the complex unit j, i.e. a complex matrix where the real term is the first "layer", and the imaginary is the second "layer". We then check if it equals itself complex conjugate transposed.

This will output a matrix containing only 1 if true, and a matrix containing at least one 0 if false. These are considered true and false in Octave (Proof).

Stewie Griffin

Posted 2018-02-26T13:01:52.547

Reputation: 43 471

6

Python 2, 50 bytes

lambda m:[[[a,-b]for a,b in l]for l in zip(*m)]==m

Try it online!

TFeld

Posted 2018-02-26T13:01:52.547

Reputation: 19 246

5

APL (Dyalog Unicode), 22 15 9 7 bytes

⍉≡⊢∘-\¨

Try it online!

Tacit prefix function.

Thanks to Adám for 7 bytes on the Dfn, and to both Adám and ErikTheOutgolfer for putting up with my stupidity helping me find the tacit version.

Thanks to ngn for 2 bytes on the tacit version.

How?

⍉≡⊢∘-\¨ ⍝ Anonymous tacit function.
      ¨ ⍝ Apply to each element of the argument:
     \  ⍝ Cumulative reduction, using
  ⊢∘-   ⍝ Ignore the first element, then negate the second
 ≡      ⍝ And match
⍉       ⍝ To the argument's transposition.

J. Sallé

Posted 2018-02-26T13:01:52.547

Reputation: 3 233

5

Wolfram Language (Mathematica), 45 34 33 26 21 18 bytes

#==#&[#.{1,I}]&

Try it online!

Jonathan Frech

Posted 2018-02-26T13:01:52.547

Reputation: 6 681

34 bytes: Try it online!

– JungHwan Min – 2018-02-26T16:21:03.467

@alephalpha Thanks a lot; I know that 0xf3c7 is the transpose operator, but what is 0xf3c8? – Jonathan Frech – 2018-02-26T17:53:38.670

1

@alephalpha There is also 0xf3c9 (Wolfram Documentation).

– Jonathan Frech – 2018-02-26T18:00:51.880

4

Java 8, 137 136 134 126 119 116 bytes

m->{int r=1,l=m.length,i=l*l,j,k;for(;i-->0;)r=m[j=i/l][k=i%l][0]!=m[k][j][0]|m[j][k][1]!=-m[k][j][1]?0:r;return r;}

-3 bytes thanks to @ceilingcat.

Returns 1 if Hermitian, 0 otherwise.

Explanation:

Try it online.

m->{                 // Method with 3D integer-array as parameter and boolean return-type
  int r=1,           //  Flag-integer `r`, starting at 1
      l=m.length,    //  The size of the 3D input array
      i=l*l,j,k;     //  Index-integers
  for(;i-->0;)       //  Loop over the rows and columns
    r=m[j=i/l][k=i%l][0]!=m[k][j][0]
                     //   If the first numbers diagonally aren't equal,
      |m[j][k][1]!=-m[k][j][1]?
                     //   or the second numbers aren't negatives of each other:
       0             //    Set the flag `r` to 0
      :              //   Else:
       r;            //    Leave the flag `r` the same
  return r;}         //  Return the flag `r`

Kevin Cruijssen

Posted 2018-02-26T13:01:52.547

Reputation: 67 575

3

Jelly,  6  5 bytes

Z×Ø+⁼

A monadic link returning 1 for a Hermitian input and 0 otherwise.

Try it online!

How?

Z×Ø+⁼ - Link: list of lists of lists, M
Z     - transpose
  Ø+  - literal = [1,-1]
 ×    - multiply (vectorises)
    ⁼ - equal to M?

Jonathan Allan

Posted 2018-02-26T13:01:52.547

Reputation: 67 804

I believe modern Jelly has Ø+. – lirtosiast – 2018-12-11T14:15:23.793

@lirtosiast indeed you are correct, updated to use it; thanks! – Jonathan Allan – 2018-12-11T19:02:05.997

3

Haskell, 50 bytes

-7 bytes thanks to H.PWiz.

(==)<*>map(map((0-)<$>)).foldr(zipWith(:))e
e=[]:e

Try it online!

totallyhuman

Posted 2018-02-26T13:01:52.547

Reputation: 15 378

3

J, 14 bytes

[:(+-:|:)j./"1

Try it online!

Explanation

[:(+-:|:)j./"1  Input: 3d array
         j./"1  Reduce by complex combine at rank 1
[:              Cap, operate on the 2d array of complex values
   +              Conjugate
      |:          Transpose
    -:            Match?

miles

Posted 2018-02-26T13:01:52.547

Reputation: 15 654

Also 14: -:0 2|:(,-)/"1 – FrownyFrog – 2018-02-27T07:58:15.197

2

05AB1E, 9 bytes

øεεX®‚*]Q

Try it online!

Explanation

ø           # transpose
 ε          # apply to each 2-d array
  ε         # apply to each pair
   X®‚*     # multiply by [1,-1]
       ]    # end apply(s)
        Q   # compare to input for equality

Emigna

Posted 2018-02-26T13:01:52.547

Reputation: 50 798

2

Ruby, 46 bytes

->m{m.transpose.map{|l|l.map{|a,b|[a,-b]}}==m}

Try it online!

Port of my Python answer

TFeld

Posted 2018-02-26T13:01:52.547

Reputation: 19 246

1

Husk, 7 bytes

=¹mmṀ_T

Try it online!

How?

Note that should work instead of mm , but there's an annoying bug that prevents me from using it :(

=¹mmṀ_T – Full program. Takes input from Command line args, as a list of lists of tuples.
  m   T – For each list in the input's tranpose...
   mṀ_  – ... Negate the last value of each tuple they contain.
=¹      – Check whether this is the same as the input.

Mr. Xcoder

Posted 2018-02-26T13:01:52.547

Reputation: 39 774

1

Perl 5, -a0 48 bytes

Old counting: 50 bytes (+2 for a0). Not bad for a language that has no builtin transpose (I'm not jealous at all, no sirree)

Give the input matrix on STDIN with , between the real and imaginary part, so e.g.:

2,0 2,1 4,0
2,-1 3,0 0,1
4,0 0,-1 1,0

Will print 1 for hermitian, nothing otherwise

#!/usr/bin/perl -a0
say@F~~[map/(\S+,)(\S+)/gc?$1.-$2:(),(/.+/g)x@F]

Try it online!

Ton Hospel

Posted 2018-02-26T13:01:52.547

Reputation: 14 114

1

C (gcc), 107 103 100 bytes

  • Saved four bytes thanks to Steadybox; golfed A[0] to *A twice.
  • Saved three bytes thanks to ceilingcat.
j,k,r;f(A,s)int***A;{for(r=0,j=s;j--;)for(k=s;k--;)r|=*A[j][k]-*A[k][j]|A[j][k][1]+A[k][j][1];A=!r;}

Try it online!

Jonathan Frech

Posted 2018-02-26T13:01:52.547

Reputation: 6 681

103 bytes – Steadybox – 2018-02-26T15:53:36.763

@Steadybox Thanks a lot. Funny ... A few hours ago I had exactly this golf in mind -- dereferencing instead of indexing -- but simply forgot ... – Jonathan Frech – 2018-02-26T16:06:28.587

@ceilingcat Thank you. – Jonathan Frech – 2019-08-01T00:04:25.637

1

JavaScript (ES6), 53 bytes

Saved 2 bytes thanks to @Neil

Returns false for Hermitian or true for non-Hermitian.

m=>m.some((r,y)=>r.some(([a,b],x)=>m[x][y]!=a+[,-b]))

Try it online!

Arnauld

Posted 2018-02-26T13:01:52.547

Reputation: 111 334

Save 3 bytes on https://codegolf.stackexchange.com/a/156714 - f=([c,...s],p='')=>c?p+c+f(s,p+''):p.

– Neil – 2018-02-28T00:44:45.073

0

C,  111   110  108 bytes

Thanks to @Jonathan Frech for saving a byte and thanks to @ceilingcat for saving two bytes!

i,j,r;f(A,n)int*A;{for(r=i=0;i<n*2;i+=2)for(j=n*2;j;r|=A[i*n+j]-A[j*n+i]|A[i*n-~j]+A[j*n-~i])j-=2;return!r;}

Try it online!

C (gcc),  106  104 bytes

i,j,r;f(A,n)int*A;{for(r=i=0;i<n*2;i+=2)for(j=n*2;j;r|=A[i*n+j]-A[j*n+i]|A[i*n-~j]+A[j*n-~i])j-=2;A=!r;}

Try it online!

Steadybox

Posted 2018-02-26T13:01:52.547

Reputation: 15 798

I think r|=...|... works as well as r+=...||.... – Jonathan Frech – 2018-02-26T15:37:07.740

@JonathanFrech Yes, it does. Thanks! – Steadybox – 2018-02-26T15:38:55.090

0

Actually, 13 bytes

┬⌠⌠Çá╫k⌡M⌡Mß=

Try it online!

How it works?

This submission actually makes use of complex numbers. If taking input as a matrix of complex entries was allowed, then it would be 8 bytes.

┬⌠⌠Çá╫k⌡M⌡Mß=  –> Full program.
┬              –> Transpose.
 ⌠       ⌡M    –> For each list in the input's transpose do the following:
  ⌠    ⌡M         –> For each two-element list of the form [a, b]...
   Ç              –> Turn it into a complex number (a+bi).
    á             –> Find its complex conjugate: Push (a-bi).
     ╫k           –> Push [Re(N), Im(N)], so [a, -b].
           ß=  –> Check whether the result equals the input.

Mr. Xcoder

Posted 2018-02-26T13:01:52.547

Reputation: 39 774

0

Pyth, 9 bytes

qCmm,hk_e

Explanation:

qCmm,hk_ekdQQ  Autofill variables
    ,hk_ek     [a,-b]...
  mm      dQ    ...for each [a,b] in the input (m...Q)'s rows (m...d).
 C             Transpose.
q           Q  Is this result equal to the original?

Test suite.

Steven H.

Posted 2018-02-26T13:01:52.547

Reputation: 2 841

Your answer is actually 9 bytes... A 9-byte alternative: qCmm*V_B1. – Mr. Xcoder – 2018-02-27T06:32:36.953

I golfed off one byte as I was making the submission, from qCmm.e_Fbk... apparently I forgot to edit the byte count in the final submission. @Mr.Xcoder I fixed it regardless, thanks for the catch! – Steven H. – 2018-02-27T16:12:30.870

0

Actually, 13 bytes

;┬⌠⌠d±@q⌡M⌡M=

Try it online!

Explanation:

;┬⌠⌠d±@q⌡M⌡M=
;              make a copy
 ┬             transpose copy
  ⌠⌠d±@q⌡M⌡M   for each row:
   ⌠d±@q⌡M       for each cell in row:
    d              remove last element from list
     ±             swap sign
      @q           insert at end of list
            =  compare equality with original

Mego

Posted 2018-02-26T13:01:52.547

Reputation: 32 998