Verify Eigenpairs

21

In this challenge, you will be given a square matrix A, a vector v, and a scalar λ. You will be required to determine if (λ, v) is an eigenpair corresponding to A; that is, whether or not Av = λv.

Dot Product

The dot product of two vectors is the sum of element-wise multiplication. For example, the dot product of the following two vectors is:

(1, 2, 3) * (4, 5, 6) = 1*4 + 2*5 + 3*6 = 32

Note that the dot product is only defined between two vectors of the same length.

Matrix-Vector Multiplication

A matrix is a 2D grid of values. An m x n matrix has m rows and n columns. We can imagine an m x n matrix as m vectors of length n (if we take the rows).

Matrix-Vector multiplication is defined between an m x n matrix and a size-n vector. If we multiply an m x n matrix and a size-n vector, we obtain a size-m vector. The i-th value in the result vector is the dot product of the i-th row of the matrix and the original vector.

Example

        1 2 3 4 5
Let A = 3 4 5 6 7
        5 6 7 8 9

        1
        3
Let v = 5
        7
        9

If we multiply the matrix and the vector Av = x, we get the following:

x1 = AT1 * v /* AT1 means the first row of A; A1 would be the first column */ = (1,2,3,4,5) * (1,3,5,7,9) = 1*1 + 2*3 + 3*5 + 4*7 + 5*9 = 1+6+15+28+45 = 95

x2 = AT2 * v = (3,4,5,6,7) * (1,3,5,7,9) = 3*1 + 4*3 + 5*5 + 6*7 + 7*9 = 3+12+25+42+63 = 145

x3 = AT3 * v = (5,6,7,8,9) * (1,3,5,7,9) = 5*1 + 6*3 + 7*5 + 8*7 + 9*9 = 5+18+35+56+81 = 195

So, we get Av = x = (95, 145, 195).

Scalar Multiplication

Multiplication of a scalar (a single number) and a vector is simply element-wise multiplication. For example, 3 * (1, 2, 3) = (3, 6, 9). It's fairly straightforward.

Eigenvalues and Eigenvectors

Given the matrix A, we say that λ is an eigenvalue corresponding to v and v is an eigenvector corresponding to λ if and only if Av = λv. (Where Av is matrix-vector multiplication and λv is scalar multiplication).

(λ, v) is an eigenpair.

Challenge Specifications

Input

Input will consist of a matrix, a vector, and a scalar. These can be taken in any order in any reasonable format.

Output

Output will be a truthy/falsy value; truthy if and only if the scalar and the vector are an eigenpair with the matrix specified.

Rules

  • Standard loopholes apply
  • If a built-in for verifying an eigenpair exists in your language, you may not use it.
  • You may assume that all numbers are integers

Test Cases

 MATRIX  VECTOR  EIGENVALUE
 2 -3 -1    3
 1 -2 -1    1    1    ->    TRUE
 1 -3  0    0

 2 -3 -1    1
 1 -2 -1    1    -2   ->    TRUE
 1 -3  0    1

 1  6  3    1
 0 -2  0    0    4    ->    TRUE
 3  6  1    1

 1  0 -1    2
-1  1  1    1    7    ->    FALSE
 1  0  0    0

-4 3    1    
 2 1    2    2    ->    TRUE

2    1    2    ->    TRUE

I will add a 4x4 later.

Unreadable Test Cases that are easier for testing

HyperNeutrino

Posted 2017-04-13T13:59:17.273

Reputation: 26 575

Related. – Martin Ender – 2017-04-13T14:07:19.277

@MartinEnder Thanks. I originally had a similar challenge for arbitrary sized matrices where you were meant to calculate a basis for each unique eigenspace but that's in the sandbox still because it seems too confusing. – HyperNeutrino – 2017-04-13T14:08:47.100

If inputs can have have other dimensions than 3x3, you should cover some of that in your test cases. – Martin Ender – 2017-04-13T14:22:07.903

Also while the test case format is very readable, it's a pain to copy, because (just looking at a byte stream) the three arguments are all interleaved. – Martin Ender – 2017-04-13T14:22:38.677

@MartinEnder Alright, I'll add a 2x2 and 4x4 test test case and link to a pastebin with more (un)readable(?) I/O. – HyperNeutrino – 2017-04-13T14:23:15.593

So can we assume that the input is at least 2x2? Can it be 1x1? – Martin Ender – 2017-04-13T14:38:52.223

I looked through this question and understood less about it afterwards :) – caird coinheringaahing – 2017-04-13T14:39:02.310

@ThisGuy Eigensystems are probably just on the other side of what you can reasonably learn from the specification of a PPCG challenge if you're not familiar with it beforehand. It's not a terribly difficult concept though, so if you read up on it on Wikipedia or some other online resources, the challenge should be clear quite quickly. – Martin Ender – 2017-04-13T14:40:22.227

@ThisGuy Don't worry, it took me a few months to get up to this point. The core of the challenge is really just checking if a matrix times a vector is the same as a number times that vector. – HyperNeutrino – 2017-04-13T14:44:32.067

1@HyperNeutrino yeah that doesn't help... Don't try to explain it to me: I'm at high school studying maths for GCSE so its just lost on me. – caird coinheringaahing – 2017-04-13T14:46:03.110

@MartinEnder No, I'll add a 1x1. – HyperNeutrino – 2017-04-13T14:48:06.473

1@user00001 If you need help, eigenpair-aphrase it for you. :P – mbomb007 – 2017-04-27T21:49:33.173

Answers

11

Jelly, 5 bytes

æ.⁵⁼×

This is a triadic, full program.

Try it online!

How it works

æ.⁵⁼×  Main link
       Left argument:  v (eigenvector)
       Right argument: λ (eigenvalue)
       Third argument: A (matrix)

  ⁵    Third; yield A.
æ.     Take the dot product of v and A, yielding Av.
    ×  Multiply v and λ component by component, yielding λv.
   ⁼   Test the results to the left and to the right for equality.

Dennis

Posted 2017-04-13T13:59:17.273

Reputation: 196 637

ockquote>

_> this is too short :P Nice answer

– HyperNeutrino – 2017-04-13T18:54:46.917

6That's crazy talk! :P – Dennis – 2017-04-13T19:12:31.177

You write something, and think "nothing could be shorter!". Then MATL comes along and halves your code size. Then Jelly comes along and halves that >_> – HyperNeutrino – 2017-04-14T03:13:59.997

@HyperNeutrino Don't compare apples to oranges. Golfing languages have as little as one byte per operation, something normal languages rarely have. The spec has three operations (two multiplications and an equality), and allowing for an extra byte to duplicate v one could expect as little as four bytes. – Sanchises – 2017-04-14T08:07:33.387

2I like how both Jelly and MATL use two bytes for matrix multiplication, which means that this answer really shows how good Jelly is at taking input, all else being equal. – Sanchises – 2017-04-14T08:09:15.597

13

Mathematica, 10 bytes

#2.#==#3#&

Takes input like {vector, matrix, scalar} and returns a boolean.

Martin Ender

Posted 2017-04-13T13:59:17.273

Reputation: 184 808

1ockquote>

_> this was too easy for Mathematica. +1 :P

– HyperNeutrino – 2017-04-13T14:16:22.360

9@HyperNeutrino And now we wait for MATL... – Martin Ender – 2017-04-13T14:19:06.337

2Well MATL has appeared >_> – HyperNeutrino – 2017-04-13T14:37:05.130

1One of those moments when you think nothing can be shorter and MATL pops up suddenly :) – Mr. Xcoder – 2017-04-13T19:29:36.480

@Mr.Xcoder And then Jelly shows up. – Steadybox – 2017-04-13T23:14:11.800

Suppose we're waiting for 05AB1E now @Steadybox – Mr. Xcoder – 2017-04-14T04:24:12.137

11

MATL, 7 bytes

*i2GY*=

Inputs in order: l,v,A.

Explanation:

*  % implicitly get l and v, multiply.
i  % get A
2G % get second input, i.e., v again
Y* % perform matrix multiplication
=  % test equality of both multiplications

Surprisingly long answer, if you ask me, mostly because I needed a way to get all the input correctly. I do not think that less than 5 bytes is possible, but it would be cool if someone found a 5 or 6 byte solution.

Basically, this calculates l*v==A*v.

Sanchises

Posted 2017-04-13T13:59:17.273

Reputation: 8 530

"Surprisingly long" I was expecting at least 20 bytes >_> nice answer though :P – HyperNeutrino – 2017-04-13T14:37:23.623

2Well, considering that the MATLAB answer would come in at 16 bytes @(A,v,l)A*v==v*l, this seems quite verbose, and I have a feeling 6 should be plenty if I get the input somewhat smarter. – Sanchises – 2017-04-13T14:39:24.050

Apparently it came in at 38 bytes but I'm pretty sure it can be golfed down. – HyperNeutrino – 2017-04-13T14:41:27.587

3@HyperNeutrino Added my own to make the previous comment true. (or truthy...?) – Sanchises – 2017-04-13T14:46:37.747

6

CJam, 15 bytes

q~W$f.*::+@@f*=

Takes input in the form vector scalar matrix.

Try it online!

Explanation

q~               e# Read and eval the input
  W$             e# Copy the bottom most value (the vector)
    f.*::+       e# Perform element-wise multiplication with each row of the matrix, then
                 e#   sum the results of each (ie dot product with each row) 
          @@     e# Move the resulting vector to the bottom of the stack
            f*   e# Element-wise multiplication of the scalar and the vector
              =  e# Check if the two vectors are equal

Business Cat

Posted 2017-04-13T13:59:17.273

Reputation: 8 927

5

MATLAB, 16 bytes

@(A,v,l)A*v==v*l

Rather trivial answer. Defines an anonymous function taking the inputs, and calculates element-wise equality of the resulting vectors. A single zero in a logical array makes an array falsey in MATLAB.

Sanchises

Posted 2017-04-13T13:59:17.273

Reputation: 8 530

Wasn't aware of the falseyness of e.g. [true,false], thanks for teaching me=) – flawr – 2017-04-13T15:30:47.490

1

@flawr See this answer by Suever (which is also applicable to MATLAB). Basically, an almost-but-not-quite (empty matrix [] is different) implicit all() is called on the input of if, while etc.

– Sanchises – 2017-04-13T15:38:13.517

2

MATLAB, 38 bytes

function r=f(m,v,s);r=isequal(m*v,s*v)

Returns 1 or 0.

MATLAB, 30 bytes

function r=f(m,v,s);r=m*v==s*v

Returns

1
1
1

as a truthy value. A falsy value is a similar vector with any or all values 0 instead of 1.

Steadybox

Posted 2017-04-13T13:59:17.273

Reputation: 15 798

I don't know MATLAB, but can the isequal function be shortened to ==? – HyperNeutrino – 2017-04-13T14:41:43.323

1@HyperNeutrino isequal would be needed if the output required true or false rather than a truthy or falsey value. As the challenge stands, == is indeed enough. – Sanchises – 2017-04-13T14:42:52.357

@HyperNeutrino It would return a vector containing the results of elementwise comparison of the two vectors. – Steadybox – 2017-04-13T14:43:16.597

Oh okay. Nice answer though! – HyperNeutrino – 2017-04-13T14:43:48.067

wouldn't an annonymous function be shorter? – Batman – 2017-04-13T23:36:53.867

2

C++, 225 203 bytes

Thanks to @Cort Ammon and @Julian Wolf for saving 22 bytes!

#import<vector>
#define F(v,i)for(i=0;i<v.size();++i)
using V=std::vector<float>;int f(std::vector<V>m,V v,float s){V p;int i,j;F(m,i){p.push_back(0);F(v,j)p[i]+=v[j]*m[i][j];}F(v,i)v[i]*=s;return v==p;}

Try it online!

Steadybox

Posted 2017-04-13T13:59:17.273

Reputation: 15 798

1using std::vector; could golf two bytes off this. It costs 18 bytes, but can remove 4 std::s, saving 20. – Cort Ammon – 2017-04-13T17:21:50.123

2better yet, using V=std::vector<float>; or similar – Julian Wolf – 2017-04-13T19:05:34.170

2

Python 2.7, 33 bytes

f=lambda m,s,e:all(m.dot(s)==e*s)

input: m=matrix, s=scalar, e=eigenvalue. M and s are numpy arrays

HonzaB

Posted 2017-04-13T13:59:17.273

Reputation: 121

2This looks good, but I think you need to include the byte count of import np for it to be valid – James – 2017-04-13T17:25:40.400

You can just import it as n. Also, where are m, s, and e coming from? you need to either input them or make a lambda function – HyperNeutrino – 2017-04-13T18:34:38.797

Thank you for your suggestions. This is my first code golf. This one caught my attention, but I don't really know all the rules yet. So it is better now? – HonzaB – 2017-04-13T18:49:22.577

Nice first answer! This is currently invalid because m, s, and e are not defined. However, if you remove the f= part and the entire last line, it's a valid anonymous function, and it's shorter. – HyperNeutrino – 2017-04-13T18:51:01.920

Done. What do you mean by not defined? – HonzaB – 2017-04-13T18:55:16.987

1Your previous print(m,s,e) statement would not have worked because the variables m, s, and e were not yet assigned/defined. Also, you can remove the space after the colon. Also, you can remove the as n part and just use numpy later on; since you only use it once, using the full name actually saves a byte. – HyperNeutrino – 2017-04-13T19:11:13.090

1Ok, I understand now. Thank you for the suggestions, squeezing every bit :) – HonzaB – 2017-04-13T19:24:23.627

2Shouldn't it be all instead of any? And I think s is the vector, not the scalar, unless I'm missing something – Luis Mendo – 2017-04-13T20:44:34.583

You could do m.dot(s). And I think it should be all as well. And I don't think the second set of parens around e*s is necessary. – Batman – 2017-04-13T23:38:25.430

@Dennis: Except that NumPy abridges repr representations by default for large arrays, and getting around that (for example, with numpy.set_printoptions) costs too many bytes. – user2357112 supports Monica – 2017-04-14T18:55:04.113

Yes, if the multiplication of m and s is not equal to e*s but some of the numbers on same positions are same, then any() wouldnt work I guess. Hence I put back .all(). – HonzaB – 2017-04-14T19:59:26.850

1I think you can get rid of 4 bytes by removing an extra space and using all() rather than .all(): f=lambda m,s,e:all(np.dot(m,s)==e*s), you're still using np.dot() rather than numpy.dot() so it's actually only -1 byte to get it working: f=lambda m,s,e:all(numpy.dot(m,s)==e*s) – Ben – 2017-04-15T17:33:36.400

1Trivial improvement: use m.dot(s) instead of numpy.dot(m,s), and get rid of the import numpy entirely. On Python 3, you can use m@s to reduce things further. – user2357112 supports Monica – 2017-04-27T18:33:25.533

2

Python 3, 96 70 bytes

No builtins for matrix-vector or scalar-vector multiplication!

lambda A,L,v:all(L*y==sum(i*j for i,j in zip(x,v))for x,y in zip(A,v))

Try it online!

-26 bytes by using zip thanks to @LeakyNun!

HyperNeutrino

Posted 2017-04-13T13:59:17.273

Reputation: 26 575

Try to use zip: f=lambda A,L,v:all(L*y==sum(i*j for i,j in zip(x,v))for x,y in zip(A,v))

– Leaky Nun – 2017-05-01T13:45:28.997

2

Julia, 17 bytes

(a,b,c)->a*b==b*c

Try it online!

Rɪᴋᴇʀ

Posted 2017-04-13T13:59:17.273

Reputation: 7 410

1

R, 30 25 bytes

s=pryr::f(all(a%*%v==λ*v))

Anonymous function, fairly straightforward. Returns TRUE or FALSE.

rturnbull

Posted 2017-04-13T13:59:17.273

Reputation: 3 689

1

05AB1E, 11 bytes

vy²*O})²³*Q

Try it online!

vy²*O})     # Vectorized product-sum.
       ²³*  # Vector * scalar.
          Q # Equivalence.

Magic Octopus Urn

Posted 2017-04-13T13:59:17.273

Reputation: 19 422

0

oK, 12 bytes

{y~z%+/y*+x}

This is a function, it takes in [matrix;vector;scalar].

This does not work in k for the same reasons that 3.0~3 gives 0 as a result.


The following works in k, with 14 bytes:

{(y*z)~+/y*+x}

zgrep

Posted 2017-04-13T13:59:17.273

Reputation: 1 291

0

Python, 26 bytes

lambda a,b,c:c*b==a.dot(b)

a and b are numpy arrays, c is an integer.

Try it online!

Rɪᴋᴇʀ

Posted 2017-04-13T13:59:17.273

Reputation: 7 410

2Are the parens around c*b actually necessary? – xnor – 2017-04-14T06:08:32.743

@xnor thanks, fixed. – Rɪᴋᴇʀ – 2017-04-14T14:22:08.480

This only works for small arrays, since NumPy abridges large array string representations. – user2357112 supports Monica – 2017-04-27T18:34:05.377

@user2357112 example? I'm not sure what you mean. – Rɪᴋᴇʀ – 2017-04-27T18:35:07.633

If c*b has more than 1000 elements, NumPy will replace most of the elements with .... Demo.

– user2357112 supports Monica – 2017-04-27T18:37:27.123

@user2357112 fixed. – Rɪᴋᴇʀ – 2017-04-27T18:48:17.780

== doesn't work like you're thinking for NumPy arrays. Here, it will produce a vector of elementwise comparison results. – user2357112 supports Monica – 2017-04-27T19:00:11.380

@user2357112 it returns [True, True, True], which is a truthy value. It's a valid result. – Rɪᴋᴇʀ – 2017-04-27T19:12:44.310

@Riker: It's not actually truthy; a list looking like that would be truthy, but the result is a NumPy array, and it will outright throw a TypeError if you try to interpret it as a boolean. Also, even if it were a list, it would then be truthy regardless of whether the input was a valid eigenpair. – user2357112 supports Monica – 2017-04-27T19:15:06.477

@user2357112 I've gotten confirmation from OP that the method of output was acceptable, and that the list will be shorter than 1k (so my original answer also works). – Rɪᴋᴇʀ – 2017-04-27T20:49:45.767

Related scoring meta post – mbomb007 – 2017-04-27T22:07:26.600

0

Axiom, 27 bytes

f(a,b,c)==(a*b=c*b)@Boolean

exercises

(17) -> m:=matrix[[2,-3,-1],[1,-2,-1],[1,-3,0] ]; v:=matrix[[3],[1],[0]];
(18) -> f(m,v,1)
   (18)  true

(19) -> m:=matrix[[2,-3,-1],[1,-2,-1],[1,-3,0] ]; v:=matrix[[1],[1],[1]];
(20) -> f(m,v,-2)
   (20)  true

(21) -> m:=matrix[[1,6,3],[0,-2,0],[3,6,1] ]; v:=matrix[[1],[0],[1]];
(22) -> f(m,v,4)
   (22)  true

(23) -> m:=matrix[[1,0,-1],[-1,1,1],[1,0,0] ]; v:=matrix[[2],[1],[0]];
(24) -> f(m,v,7)
   (24)  false

(25) -> m:=matrix[[-4,3],[2,1] ]; v:=matrix[[1],[2]];
(26) -> f(m,v,2)
   (26)  true

(27) -> f(2,1,2)
   (27)  true

RosLuP

Posted 2017-04-13T13:59:17.273

Reputation: 3 036

I haven't seen this language before, nice answer! What does the @Boolean do? – HyperNeutrino – 2017-04-14T16:54:06.050

(a=b)@Boolean would mean "choose among allowed =operator(type1,type2) the one its result is Boolean"; in few words "a=b" has to be Boolean – RosLuP – 2017-04-14T18:24:21.730

0

Clojure, 60 bytes

#(=(set(map(fn[a v](apply -(* v %3)(map * a %2)))% %2))#{0})

This checks that all deltas are zero, thus collapsing into the set of zero. Calling example:

(def f #(=(set(map(fn[a v](apply -(* v %3)(map * a %2)))% %2))#{0}))
(f [[1 6 3][0 -2 0][3 6 1]] [1 0 1] 4)

NikoNyrh

Posted 2017-04-13T13:59:17.273

Reputation: 2 361