Matrix

M

Michael Ulm

Paul said:
Michael Ulm wrote:

/ ...

I think the writers of the Matrix class realized this, and didn't bother
to include an assignment operator on the ground that it wouldn't have any
general utility.

Then they would have been wrong. The lack of the []= operator has been a
major PITA for me, as I often need matrix functions (FWIW I'm a
mathematician, working on applications of artificial inteligence).
The implementations of many higher level matrix operations needs the
assignment operator. Try implementing a SVD algorithm without it.


In Ruby, it's trivial to add it.

Granted, it is easy to add it. But the implementation is not the
problem; it's the small and subtle nuisances that are introduced when
you add a method to a standard class. You'd have to make sure to get
the syntax just right, you must ensure that every module that needs
is will get access to it without violating the DRY principle etc.

Maybe you are better organized and all these subtleties just come
natural to you. For me it's a pain.

Regards,

Michael

--
Michael Ulm
R&D Team
ISIS Information Systems Austria
tel: +43 2236 27551-219, fax: +43 2236 21081
e-mail: (e-mail address removed)
Visit our Website: www.isis-papyrus.com

---------------------------------------------------------------
This e-mail is only intended for the recipient and not legally
binding. Unauthorised use, publication, reproduction or
disclosure of the content of this e-mail is not permitted.
This email has been checked for known viruses, but ISIS accepts
no responsibility for malicious or inappropriate content.
---------------------------------------------------------------
 
M

Michael Ulm

Dave said:
Michael said:
I think he's trying to say, that there is no rational reason for
leaving out the []= operator, and I agree.



The benefit is that you can assume no other code is modifying your matrix.

n = Matrix.I(2)
some_function(n)
p n # same as before

It's a good feature.

You are right, this is a somewhat useful feature (I've been bitten often
enough by mutated Arrays). However, this only works as long as some_function
is not a third party application (or calls a third party library).

So it's a balance of conveniences. For me, the usefulness of []= far
outweighs any advantages of the present implementation.
[]= would be useful, too, but I think to keep the immutability a better
addition that provides the same functionality could be provided; a
modified_at(x,y,value) method or something, but naming it is hard.

Then the whole Matrix would have to be copied to change one value --
goodbye performance.

Regards,

Michael

--
Michael Ulm
R&D Team
ISIS Information Systems Austria
tel: +43 2236 27551-219, fax: +43 2236 21081
e-mail: (e-mail address removed)
Visit our Website: www.isis-papyrus.com

---------------------------------------------------------------
This e-mail is only intended for the recipient and not legally
binding. Unauthorised use, publication, reproduction or
disclosure of the content of this e-mail is not permitted.
This email has been checked for known viruses, but ISIS accepts
no responsibility for malicious or inappropriate content.
---------------------------------------------------------------
 
V

Verno Miller

Michael said:
Dave said:
n = Matrix.I(2)
some_function(n)
p n # same as before

It's a good feature.

You are right, this is a somewhat useful feature (I've been bitten often
enough by mutated Arrays). However, this only works as long as
some_function
is not a third party application (or calls a third party library).

So it's a balance of conveniences. For me, the usefulness of []= far
outweighs any advantages of the present implementation.
[]= would be useful, too, but I think to keep the immutability a better
addition that provides the same functionality could be provided; a
modified_at(x,y,value) method or something, but naming it is hard.

Then the whole Matrix would have to be copied to change one value --
goodbye performance.


How about using an alternative to subclassing (similar to the
"Alternative to inheriting from Array",
http://www.bigbold.com/snippets/posts/show/2573 )?
 
J

Just Another Victim of the Ambient Morality

Michael Ulm said:
Just said:
As far as I can tell, matrices are no different. Your example shows
that 1 is immutable but references to it can be re-assigned, so you can
do:

n = 3
n = n + 1


Matrices are no different and, so, you can do:


n = Matrix.scalar(2, 3)
n = n + Matrix.I(2)


In both cases, the "number" types are immutable but the references
to them are not, as you say. They both work exactly the same way. What
are you trying to say?

I think he's trying to say, that there is no rational reason for
leaving out the []= operator, and I agree.

Well, yeah, I got that. It's just that he spent this whole paragraph
on a rationale that wasn't true so I was wondering what he was really
trying to get at for his rationale...
 
J

Just Another Victim of the Ambient Morality

Michael Ulm said:
Dave said:
Michael said:
I think he's trying to say, that there is no rational reason for
leaving out the []= operator, and I agree.

The benefit is that you can assume no other code is modifying your
matrix.

n = Matrix.I(2)
some_function(n)
p n # same as before

It's a good feature.

You are right, this is a somewhat useful feature (I've been bitten often
enough by mutated Arrays). However, this only works as long as
some_function
is not a third party application (or calls a third party library).

Why do you think this? A method doesn't have to be third party to
modify the passed in object...

[]= would be useful, too, but I think to keep the immutability a better
addition that provides the same functionality could be provided; a
modified_at(x,y,value) method or something, but naming it is hard.

Then the whole Matrix would have to be copied to change one value --
goodbye performance.

This is (apparently) true for all "number" types, including complex
numbers and matrices. Performance is not a priority. I suspect that
performance was never a priority in Ruby, either. The fact it is trivial
to add your own in-place modifier probably contributed to its obsence...
 
M

MonkeeSage

Just said:
Well, yeah, I got that. It's just that he spent this whole paragraph
on a rationale that wasn't true so I was wondering what he was really
trying to get at for his rationale...

My rationale? Erm, the rationale stated by _others_ was that a matrix
(as a value) is immutable, therefore the implementation of a matrix (as
a data structure) should be immutable. But that makes no sense.

r ----------
| n0 n1 n2
| n3 n4 n5
| n6 n7 n8

What makes n0-n... special and different from just plain old n = 1?
Yes, r is a unit, but that just means that when n... is changed then r
is now a new value unit; you don't need to do that by constructing a
whole new matrix, you can do the same thing by changing members of r in
place. The _value_ of r at any given time is immutable, the data
structure that represents r need not be.

Given r:

r = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]

Which is better?

def new_matrix(k, x, y, value)
out = []
k.each_with_index { |m, row|
out << []
m.each_with_index { |n, col|
if row == x and col == y
out[-1] << value
else
out[-1] << n
end
}
}
out
end
r = new_matrix(r, 2, 2, r[0][0])
r # => [[0, 1, 2], [3, 4, 5], [6, 7, 0]]

Or:

r[2][2] = r[0][0]
r # => [[0, 1, 2], [3, 4, 5], [6, 7, 0]]

Duh! The answer is obvious.

I do like Dave's idea about having a named method to do the in place
modification, though; that would make sure You Really Mean It and
eliminate the typo where you meant == but actually wrote =.

Ps. Paul gave another rationale: usefulness. That makes sense (though
its truth was contested). Dave also gave another rationale:
predictability. That makes sense too. But the immutability of the value
of a matrix as a rationale for disallowing destructive assignment to
members doesn't make sense.
 
J

Just Another Victim of the Ambient Morality

MonkeeSage said:
My rationale? Erm, the rationale stated by _others_ was that a matrix
(as a value) is immutable, therefore the implementation of a matrix (as
a data structure) should be immutable. But that makes no sense.

I think the rationale might be that the implementation of all "number"
types are immutable and matrices are a "number" type and should, therefore,
be immutable as well...

r ----------
| n0 n1 n2
| n3 n4 n5
| n6 n7 n8

What makes n0-n... special and different from just plain old n = 1?
Yes, r is a unit, but that just means that when n... is changed then r
is now a new value unit; you don't need to do that by constructing a
whole new matrix, you can do the same thing by changing members of r in
place. The _value_ of r at any given time is immutable, the data
structure that represents r need not be.

Okay, I think I'm beginning to see the distinction you're trying to
make between something "as a value" and "as a data structure." If I
understand you correctly, describing something as being "immutable" "as a
value" is meaningless. The term "immutable" only has meaning when you
apply it to an object (what you call a data structure).

Given r:

r = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]

Which is better?

def new_matrix(k, x, y, value)
out = []
k.each_with_index { |m, row|
out << []
m.each_with_index { |n, col|
if row == x and col == y
out[-1] << value
else
out[-1] << n
end
}
}
out
end
r = new_matrix(r, 2, 2, r[0][0])
r # => [[0, 1, 2], [3, 4, 5], [6, 7, 0]]

Or:

r[2][2] = r[0][0]
r # => [[0, 1, 2], [3, 4, 5], [6, 7, 0]]

Duh! The answer is obvious.

So obvious that no one denies its utility. No one...

Ps. Paul gave another rationale: usefulness. That makes sense (though
its truth was contested). Dave also gave another rationale:
predictability. That makes sense too. But the immutability of the value
of a matrix as a rationale for disallowing destructive assignment to
members doesn't make sense.

Again, you're using this weird distinction of value that doesn't seem
useful here. It's not just the value of 2 that's immutable, the object
itself is immutable. Matrices are the same...
 
M

MonkeeSage

Just said:
Okay, I think I'm beginning to see the distinction you're trying to
make between something "as a value" and "as a data structure." If I
understand you correctly, describing something as being "immutable" "as a
value" is meaningless. The term "immutable" only has meaning when you
apply it to an object (what you call a data structure).

Ok, I was being ambiguous. I'm dumb though, so don't blame me. ;) I was
using "immutable" in the sense of mathematical identity (like numbers
and constants are immutable, but variables aren't) -- r1 can never _be_
r2, just like 1 can never be 2. By "as a value" I was meaning any
particular matrix considered in this mathematical sense of identity.
And by "as a data structure" I was meaning the implementation of a
matrix "container" in ruby (apart from any specific matrices). So the
"value" of the "data structure" r is mathematically "immutable"; but
the "data structure" itself need not be immutable (in the programming
language sense of object mutability). Anyhow, as I said, I'm dense;
sorry for not being more clear. I shouldn't have eaten all that glue as
a child. :)

Regards,
Jordan
 
R

Rick DeNatale

Hmm, I guess I wasn't clear, because that was my point (and another
person also didn't understand me). My point was that n can be
destructively altered by assignment, but its value (1) cannot be.

There is a very important distinction between variables and values,
that trips up a lot of programmers, and particularly programmers
coming to a uniformly object based language like Ruby.

I started a detailed reply here but it morphed into a blog article:
http://talklikeaduck.denhaven2.com/articles/2006/09/13/on-variables-values-and-objects

I hope it helps someone.
 
M

Martin DeMello

I do like Dave's idea about having a named method to do the in place
modification, though; that would make sure You Really Mean It and
eliminate the typo where you meant == but actually wrote =.

Paul Graham had an excellent rationale for allowing this sort of thing
in one of his essays on language design :

Hackability
----------------

There is one thing more important than brevity to a hacker: being able
to do what you want. In the history of programming languages a
surprising amount of effort has gone into preventing programmers from
doing things considered to be improper. This is a dangerously
presumptuous plan. How can the language designer know what the
programmer is going to need to do? I think language designers would do
better to consider their target user to be a genius who will need to
do things they never anticipated, rather than a bumbler who needs to
be protected from himself. The bumbler will shoot himself in the foot
anyway. You may save him from referring to variables in another
package, but you can't save him from writing a badly designed program
to solve the wrong problem, and taking forever to do it.

Good programmers often want to do dangerous and unsavory things. By
unsavory I mean things that go behind whatever semantic facade the
language is trying to present: getting hold of the internal
representation of some high-level abstraction, for example. Hackers
like to hack, and hacking means getting inside things and second
guessing the original designer.

Let yourself be second guessed. When you make any tool, people use it
in ways you didn't intend, and this is especially true of a highly
articulated tool like a programming language. Many a hacker will want
to tweak your semantic model in a way that you never imagined. I say,
let them; give the programmer access to as much internal stuff as you
can without endangering runtime systems like the garbage collector.

In Common Lisp I have often wanted to iterate through the fields of a
struct-- to comb out references to a deleted object, for example, or
find fields that are uninitialized. I know the structs are just
vectors underneath. And yet I can't write a general purpose function
that I can call on any struct. I can only access the fields by name,
because that's what a struct is supposed to mean.

A hacker may only want to subvert the intended model of things once or
twice in a big program. But what a difference it makes to be able to.

-- http://www.paulgraham.com/popular.html
 
J

Jason Nordwick

Paul said:
In essence, this article advocates anarchy. The counter-evidence is to ask
which languages persist, and which fade away. Free-form languages,
languages that let you do whatever you please, tend to have short lives or
are quickly rendered incomprehensible because of the very freedoms that
originally made them appealing (Perl).

This seems to describe Ruby, and many here are very proud of how Ruby lets you redo any primative. I'm confused. Are you saying that Ruby doesn't allow something?
The longest-lived, most useful
languages have the strictest syntax and the fewest built-in dodges.
Example? mathematical notation.

Mathematical notation is extremely strict and slow to change.

Every book has their own mathematical notation. Beyond basic addition a (even then not always well defined when people leave out the vector notation and essentially vectorize the plus operator implicitly). Many math books are notorious for their poor notation and in lacking rigor.

Apart from
some recent window dressing, the last significant change was the adoption
of Liebniz' Calculus notation over that used by Newton in the late 17th
century. Consequently, mathematical notation has the widest audience of any
formal symbolic language. And programs that purport to be able to fluently
read and write mathematical notation are in great demand and fetch high
prices (Mathematica, Maple, Matlab, IDL).

APL is its successor J is essentially defined by Iverson as executable notation, yet APL has almost died off (not a positive in my view), and J -- despite fixing APLs worst misfeatures -- has never really gathered that big of a following. Lisp continues to outlive APL, even if on life support, yet it is hard to classify as strict or loose. In syntax it may be very strict, but in semantics it is very loose.

Language longevity seems to be based on the more nebulous but very real world impact the language makes on its ability to add libraries and functionality without making the language too complex. Perl failed, but C with its simple libraries seems to continue.

-j
 
M

M. Edward (Ed) Borasky

Paul said:
Mathematical notation is extremely strict and slow to change. Apart from
some recent window dressing, the last significant change was the adoption
of Liebniz' Calculus notation over that used by Newton in the late 17th
century.

Ah, but a variant of Newton's notation is still in wide use for ordinary
differential equations:

y'(x) = y(x); y(0) = 1

Consequently, mathematical notation has the widest audience of any
formal symbolic language. And programs that purport to be able to fluently
read and write mathematical notation are in great demand and fetch high
prices (Mathematica, Maple, Matlab, IDL).

I wouldn't call Matlab a "symbolic" language, unless it's changed a lot
over the years. And concerning the high prices, there are two or three
open-source Matlab-like environments, Octave being the most well known.
For purely numerical computing with an emphasis on statistics, there is,
of course, R as well.

In the symbolic realm, there is Axiom and Maxima, both open source, in
the general-purpose category. In addition, there are a number of
open-source high-speed special-purpose tools like GiNaC, Pari, GAP, and
Singular.

And let's not forget TeX and mathematical typesetting and the notions of
"literate programming" and "reproducible research". I know there are
some high-priced commercial tools to do this, but most everybody I know
uses things like LyX, TeXmacs, noweb and such rather than "the
high-priced spread". (or Word.) :)

Finally, I think there's a formal symbolic language with a wider
audience than mathematics. Can you guess what it is? I'll give you a
hint -- Google for "lilypond". :)
 
M

M. Edward (Ed) Borasky

Jason said:
Language longevity seems to be based on the more nebulous but very real
world impact the language makes on its ability to add libraries and
functionality without making the language too complex. Perl failed, but
C with its simple libraries seems to continue.
In what sense(s) has Perl "failed?" I still use it almost daily, and
will continue to do so until I'm paid to use something else.
 
J

Jason Nordwick

I haven't seen a new Perl project started in a long time. All Perl work I see being done is legacy code. If Perl 6 is as complex as it appears it is going to be, I think the language will be on life support.

-j
 
M

MonkeeSage

It's interesting that the most syntactically simple and absolute
languages, e.g., dialects of Lisp and ML, are usually the most
reflective and expressive.

let anarchy = higher-level-order in
programming languages;;

;)
 
Z

znmeb

Quoting Paul Lutus said:
I hope for an eventual decent open-source symbolic math processor. There was
one (the name of which escapes me at the moment), but it is presently
abandonware.

The only one that is more or less abandoned that I recall is MuPAD, and that was
abandoned by the community because the developer refused to open the package up.
The base version is/was free as in beer but the full version was free in neither
sense.

Axiom is decidedly active; check out

http://wiki.axiom-developer.org/FrontPage

and

http://portal.axiom-developer.org/
I am personally spoiled by Mathematica, and, not being a particularly
skilled mathematician, perhaps to a fault.

Depending on the type of physicist you are, there are quite a few open-source
specialty packages. And while not strictly open source, if you're a teacher or
a student, you can usually get software on an "academic license". It's free to
other academics but they expect industrial users to pay for it. In my area,
computer performance modeling, there is a lot of "academic-licensed" software
but only a few good ones are truly open source. Which is why I went down the
Ruby path in the first place for Rameau.

http://rubyforge.org/cgi-bin/viewvc.cgi/Rameau/?root=cougar
I wouldn't have guessed musical notation without help, but I agree, it meets
the definition, and, until the invention of the car radio, it was more
widely used than mathematical notation. :)

Actually, just about every middle class home in America had a piano before radio
and the phonograph. I think there are still a lot more people who can read music
than there are who can read a PDE textbook. :)
 
D

Dido Sevilla

I believe you missed one: Maxima.

http://maxima.sourceforge.net/

It is ultimately descended from MACSYMA, which is the most venerable
of all computer algebra systems, and from what I can see it's
definitely not abandoned (considering that the last official release
was in 2005). I've used it and it's probably the closest Free
alternative to Mathematica or Maple.
 
Z

znmeb

Quoting Dido Sevilla said:
I believe you missed one: Maxima.

http://maxima.sourceforge.net/

It is ultimately descended from MACSYMA, which is the most venerable
of all computer algebra systems, and from what I can see it's
definitely not abandoned (considering that the last official release
was in 2005). I've used it and it's probably the closest Free
alternative to Mathematica or Maple.
I actually noted Maxima in my first post. I think Maxima is a good bit simpler
than Axiom, if that matters ... a shorter learning curve for Maxima. But I
think Axiom is ultimately more powerful. Both are indeed active.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top