5

Here's a simple example. Suppose we want to find the off-diagonal matrix of m:

m={{1,2},{3,4}}

This can be solved fairly simply by extracting a list of the diagonal elements, re-creating the diagonal matrix from these, and removing them from the full matrix to get the off-diagonal elements:

m - DiagonalMatrix[Diagonal[m]]  

to get

{{0,2},{3,0}}

Now, this was a fairly simple solution to the given problem, but what I'm wondering is if there is a way to write something akin to

(Identity - DiagonalMatrix@Diagonal)[m]  

To get the same result. In this simple example, not much would be gained by doing this, but I just thought it could be interesting in more complicated problems and help make the code resemble more closely the underlying mathematics in some cases.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
Steve
  • 1,153
  • 7
  • 17
  • 1
    # - DiagonalMatrix[Diagonal[#]] &[m] ? Of course you can add Identity[#] at the beginning. – Kuba Feb 18 '14 at 20:39
  • This is pretty neat, I've only really used the pure function #& stuff for making special Sort and Order functions previously, but this is quite nice and shows I've not been using them enough. Not quite what I had in mind, but this question is more out of curiosity than absolute necessity. – Steve Feb 18 '14 at 20:41
  • 4
    Also look at Composition for chaining long functions. It will greatly improve the clarity of your code. – rm -rf Feb 18 '14 at 20:45
  • Also tried Map[Identity - DiagonalMatrix@Diagonal, m] unsuccessfully – Steve Feb 18 '14 at 20:45
  • In regards to Composition, thanks, that could prove useful for readability with complex functions Identity[m] - Composition[DiagonalMatrix, Diagonal][m] does work – Steve Feb 18 '14 at 20:49
  • It seems that (at least in the case of some) functions can operate linearly over lists, which is sort of the converse problem to this one; e.g. Abs[{-1,3,-5}]={1,3,5} (As opposed to ~5.92 if it tried to interpret the action of Abs acting on the vector {-1,3,-5} to give, perhaps, the L2-norm; Norm[{-1,3-5},2] accomplishes this of course) – Steve Feb 18 '14 at 21:07
  • 6
    You should look at Through too, e.g. Through[(f + g + h)[x]] gives f[x] + g[x] + h[x]. – Simon Woods Feb 18 '14 at 21:32
  • Through seems like the most promising thing so far, but I can't quite make it work for this problem. Any idea how to implement it with the given example? – Steve Feb 18 '14 at 21:44
  • 1
    @Steve It doesn't work for two reasons: @ doesn't denote function composition, but function application (use Composition for function composition) and because Through only goes in one level while here we actually have an expression of the form (a + (-1)*b), not of a simpler form a-b. I'm afraid there's no easy and simple solution to your problem other than building pure functions as in (Identity[#] - DiagonalMatrix@Diagonal[#]) &[m]. – Szabolcs Feb 18 '14 at 22:42
  • If it is just about readability in the front end, you can wrap some heads around every operator, define some operatorApply, and define neat layouts for both – Rojo Feb 18 '14 at 22:51
  • 2
    Following Rojo's idea, you can do operatorApply[f_[x__]] := Replace[f, s_Symbol :> s[x], {0, Infinity}, Heads -> False]. See where this goes wrong: operatorApply[(Sin + 1)[x]] transforms to Sin[x]+1, all is fine. Now what about operatorApply[(Sin + Pi)[x]]? You get Pi[x] + Sin[x], wrong! This is probably why it's not a built-in function. I don't see a good way around this problem, i.e. it's not a problem with my implementation but an inherent problem to the idea: it's not possible to distinguish functions from other symbols, e.g. constants. – Szabolcs Feb 18 '14 at 23:35
  • @Szabolcs as to constants, there's the Constant attribute. But the idea included some operator wrapper symbol too, to make things more robust – Rojo Feb 19 '14 at 01:05
  • 1
    @Rojo I wasn't referring to your idea. I was trying to explain why I believe that such a function was not built into Mathematica. There are just too many potential problems and too many situations where people can shoot themselves into the foot. This one with Pi was just one example. There are plenty more situations where something like operatorApply wouldn't fit well into the system. There's a number of exceptions that would need to be implemented, such as Function, Composition, InterpolatingFunction, ParametricFunction and probably other things I haven't though of. – Szabolcs Feb 19 '14 at 01:41
  • @Rojo Also, there are user defined SubValue functions, which I do use regularly. E.g. consider fun[One][x_]:=x; fun[Two][x_]:=x^2, where One/Two are symbols setting some option. There's no way to tell that One is not a function and no way to tell that fun[One] is a function. Generally, we come back to the point that it's impossible to reliably tell what is a function and what isn't. – Szabolcs Feb 19 '14 at 01:44

1 Answers1

0

In version 10 we can use the new shorthand notation for Composition to write

Through@(Identity + Minus@*DiagonalMatrix@*Diagonal)[m]

(* {{0, 2}, {3, 0}} *)

As noted in the comments, Through@(a - b)[x] won't work the way we'd like because a - b is represented internally as a + (-1)*b. Composing with Minus gets around this problem.

Simon Rochester
  • 6,211
  • 1
  • 28
  • 40