Cofactor Matrices

18

1

The cofactor matrix is the transpose of the Adjugate Matrix. The elements of this matrix are the cofactors of the original matrix.

The cofactor enter image description here (i.e. the element of the cofactor matrix at row i and column j) is the determinant of the submatrix formed by deleting the ith row and jth column from the original matrix, multiplied by (-1)^(i+j).

For example, for the matrix

enter image description here

The element of the cofactor matrix at row 1 and column 2 is:

enter image description here

You can find info on what the determinant of a matrix is and how to calculate them here.

Challenge

Your goal is to output the cofactor matrix of an input matrix.

Note: Built-ins that evaluate cofactor matrices, or adjugate matrices, or determinants or anything similar are allowed.

Input

The matrix may be inputed as a command line argument, as a function parameter, in STDIN or in any way that is most appropriate for the language you use.

The matrix will be formatted as a list of lists, each sublist corresponding to one row, which contains factors ordered from left to right. Rows are ordered from top to bottom in the list.

For example, the matrix

a b
c d

will be represented by [[a,b],[c,d]].

You may replace the square brackets and commas with something else if it fits your language and is sensible (e.g. ((a;b);(c;d)))

Matrices will only contain integers (which can be negative).

Matrices will always be square (i.e. same number of rows and columns).

You may assume that the input will always be correct (i.e. no formatting problem, nothing other than integers, no empty matrix).

Output

The resulting cofactor matrix may be outputed to STDOUT, returned from a function, written to a file, or anything similar that naturally suits the language you use.

The cofactor matrix must be formatted in the exact same way the input matrices are given, e.g. [[d,-c],[-b,a]]. If you read a string, then you must return/output a string in which the matrix is formatted exactly like in the input. If you use something like e.g. a list of lists as input, then you must return a list of lists too.

Test cases

  • Input: [[1]]

Output: [[1]]

  • Input: [[1,2],[3,4]]

Output: [[4,-3],[-2,1]]

  • Input: [[-3,2,-5],[-1,0,-2],[3,-4,1]]

Output: [[-8,-5,4],[18,12,-6],[-4,-1,2]]

  • Input: [[3,-2,7,5,0],[1,-1,42,12,-10],[7,7,7,7,7],[1,2,3,4,5],[-3,14,-1,5,-9]]

Output:

[[9044,-13580,-9709,23982,-9737],[-1981,1330,3689,-3444,406],[14727,7113,2715,-9792,414],[-28448,-2674,-707,16989,14840],[-2149,2569,-2380,5649,-3689]]

Scoring

This is so the shortest answer in bytes wins.

Fatalize

Posted 2015-12-16T13:14:29.523

Reputation: 32 976

2I am not sure how to interpret the cofactor matrix must be formatted in the exact same way the input matrices are given for function submissions that get input from arguments and return a value. Do we read/return actual matrices or their string representations? – Dennis – 2015-12-16T22:51:45.680

1In short: if you read a string, then you must return/output a string in which the matrix is formatted exactly like in the input. If you use something like e.g. a list of lists, then you must return a list of lists too. – Fatalize – 2015-12-17T08:15:51.167

Does a 1x1 matrix really have a cofactor matrix? – Liam – 2015-12-18T07:11:55.027

Also your penultimate test case seems to be the adjugate matrix (the transpose of what it should be), unless I'm mistaken. – Liam – 2015-12-18T07:36:54.803

@ICanHazHats Correct, I fixed it, thanks. – Fatalize – 2015-12-18T08:35:44.857

Answers

1

J, 29 bytes

3 :'<.0.5+|:(-/ .**%.)1e_9+y'

Same epsilon/inverse/determinant trick. From right to left:

  • 1e_9+ adds an epsilon,
  • (-/ .**%.) is determinant (-/ .*) times inverse (%.),
  • |: transposes,
  • <.0.5+ rounds.

Lynn

Posted 2015-12-16T13:14:29.523

Reputation: 55 648

5

Matlab, 42 33 bytes

Using an anonymous function:

@(A)round(inv(A+eps)'*det(A+eps))

Input and output are matrices (2D numeric arrays).

eps is added in case the matrix is singular. It is "removed" using round (the true result is guaranteed to be an integer).

Example:

>> @(A)round(inv(A+eps)'*det(A+eps))
ans = 
    @(A)round(inv(A+eps)'*det(A+eps))
>> ans([-3,2,-5; -1,0,-2; 3,-4,1])
ans =
-8    -5     4
18    12    -6
-4    -1     2

Example with singular matrix:

>> @(A)round(inv(A+eps)'*det(A+eps))
ans = 
    @(A)round(inv(A+eps)*det(A+eps)')
>> ans([1,0 ; 0,0])
ans =
     0     0
     0     1

Or try it online in Octave.

Luis Mendo

Posted 2015-12-16T13:14:29.523

Reputation: 87 464

Matlab definitely feels like "the right tool for the job" in this challenge – Fatalize – 2015-12-16T14:55:01.700

Wait until someone posts a Mathematica answer... it probably has a builtin for this :-) – Luis Mendo – 2015-12-16T14:56:10.027

2However I do have a concern that I haven't talked about in the challenge: this answer assumes that the input matrix is invertible. Using your code on say [1,0 ; 0,0] gives an error when it should output [0,0 ; 0,1] – Fatalize – 2015-12-16T14:58:46.117

Hm. You're right. I hadn't thought of that – Luis Mendo – 2015-12-16T15:02:45.960

Corrected! With a dirty trick, I admit – Luis Mendo – 2015-12-16T15:45:03.657

1Since you are returning from a function, I don't think you should need mat2str: "resulting cofactor matrix may be... returned from a function" – FryAmTheEggman – 2015-12-16T15:47:25.730

1@FryAmTheEggman Thanks! But "The cofactor matrix must be formatted in the exact same way the input matrices are given". That's why I think I need mat2str – Luis Mendo – 2015-12-16T15:52:59.887

Can you explain a bit more to non-Matlab people like me what the eps and fix commands do? Sounds like you tell Matlab to add a small epsilon to the matrix and fix magically removes its effects afterwards, but is there a guarantee that it always yields exactly the correct cofactor matrix? – Fatalize – 2015-12-16T15:53:01.867

1@Fatalize Yes, it's that. eps is about 1e-16. So it makes the matrix non-singular (but very ill-conditioned). The result is not exactly integer; so fix (round towards zero) fixes that. This works provided the error doesn't exceed .5. I'm afraid there are no guarantees. For very large integers it might fail. I said it was a dirty trick :-P – Luis Mendo – 2015-12-16T15:55:06.320

1@Fatalize for clarity, could you say whether mat2str is needed here? To me it feels like since this is a function, the input actually is the unformatted matrix. Like if you try f=... then do f(f(...)) this won't work, but removing mat2str makes that work fine. – FryAmTheEggman – 2015-12-16T16:39:27.337

@FryAmTheEggman Now I see what you mean. Yes, without mat2str, the function output could be used as a new input. Let's wait for @Fatalize's clarification – Luis Mendo – 2015-12-16T16:48:32.890

WHY NOT MATL??? PS: The ' is in the wrong position, I think. – flawr – 2015-12-16T19:43:38.263

@flawr I didn't include much of linear algebra in MATL :-) Thanks for the correction! – Luis Mendo – 2015-12-16T23:55:12.873

4

Mathematica, 27 35 bytes

Thread[Det[#+x]Inverse[#+x]]/.x->0&

alephalpha

Posted 2015-12-16T13:14:29.523

Reputation: 23 988

Does this work for non-invertible matrices, e.g. [[1,0],[0,0]]? – Fatalize – 2015-12-16T15:53:45.043

@FryAmTheEggman That doesn't seem to work. – LegionMammal978 – 2015-12-16T23:00:10.670

3

R, 121 94 bytes

function(A)t(outer(1:(n=NROW(A)),1:n,Vectorize(function(i,j)(-1)^(i+j)*det(A[-i,-j,drop=F]))))

This is an absurdly long function that accepts an object of class matrix and returns another such object. To call it, assign it to a variable.

Ungolfed:

cofactor <- function(A) {
    # Get the number of rows (and columns, since A is guaranteed to
    # be square) of the input matrix A
    n <- NROW(A)

    # Define a function that accepts two indices i,j and returns the
    # i,j cofactor
    C <- function(i, j) {
        # Since R loves to drop things into lower dimensions whenever
        # possible, ensure that the minor obtained by column deletion
        # is still a matrix object by adding the drop = FALSE option
        a <- A[-i, -j, drop = FALSE]

        (-1)^(i+j) * det(a)
    }

    # Obtain the adjugate matrix by vectorizing the function C over
    # the indices of A
    adj <- outer(1:n, 1:n, Vectorize(C))

    # Transpose to obtain the cofactor matrix
    t(adj)
}

Alex A.

Posted 2015-12-16T13:14:29.523

Reputation: 23 761

80 bytes using mapply instead of outer and Vectorize – Giuseppe – 2017-09-17T19:15:19.537

2

GAP, 246 Bytes

You can tell this is good coding by the triple nested for-loops.

It's pretty straightforward. GAP doesn't really have the same tools to deal with matrices that other math oriented languages do. The only thing really used here is the built in determinant operator.

f:=function(M)local A,B,i,j,v;A:=StructuralCopy(M);if not Size(M)=1 then for i in [1..Size(M)] do for j in [1..Size(M)] do B:=StructuralCopy(M);for v in B do Remove(v,j);od;Remove(B,i);A[i][j]:= (-1)^(i+j)*DeterminantMat(B);od;od;fi;Print(A);end;

ungolfed:

f:=function(M)
    local A,B,i,j,v;
    A:=StructuralCopy(M);
    if not Size(M)=1 then
        for i in [1..Size(M)] do
            for j in [1..Size(M)] do
                B:=StructuralCopy(M);
                for v in B do
                    Remove(v,j);
                od;
                Remove(B,i);
                 A[i][j]:= (-1)^(i+j)*DeterminantMat(B);
            od;
        od;
    fi;
    Print(A);
end;

Liam

Posted 2015-12-16T13:14:29.523

Reputation: 3 035

1

Verbosity v2, 196 bytes

IncludeTypePackage<Matrix>
IncludeTypePackage<OutputSystem>
print=OutputSystem:NewOutput<DEFAULT>
input=Matrix:Adjugate<ARGV0>
input=Matrix:Transpose<input>
OutputSystem:DisplayAsText<print;input>

Try it online!

NB: Doesn't currently work on TIO, awaiting a pull. Should work offline

Takes input in the form ((a b)(c d)) to represent

$$ \bigg[ \begin{matrix} a \: b \\ c \: d \end{matrix} \bigg] $$

Despite having a builtin for the adjugate, Verbosity's verbosity still cripples it. Fairly basic how it works, just transposes the adjugate of the input.

caird coinheringaahing

Posted 2015-12-16T13:14:29.523

Reputation: 13 702