Matrix

MonkeeSage wrote:

/ …

Anyhow, I don’t really care if []= is there by default, I can add it if
I want it; but I just don’t understand why “a matrix [as a value] is
immutable” means that []= shouldn’t be there regarding the data
structure.

You might as well ask why there is no formal method to change the third
digit of an integer in class Fixnum. The reply would be that integers
are
ordinarily dealt with in their entirety, and for special needs, the user
of
the class can write custom code to deal with the border cases, but
there’s
no point in trying to include all the marginal utilities in the formal
class definition.

Most matrix operations operate on matrices as units. Here’s an example,
a
matrix from my library, responsible for rotating objects in three-space:


class RotationMatrix

ToRad = Math::PI / 180.0
ToDeg = 180.0 / Math::PI

perspective depth cue for 3D -> 2D transformation

PerspectiveDepth = 10.0

angular constant for anaglyphic rotation

AnaglyphScale = 0.03

populate 3D matrix with values for x,y,z rotations

def populate_matrix(xa,ya,za)

  # create trig values
  sx = Math.sin(xa * ToRad);
  cx = Math.cos(xa * ToRad);
  sy = Math.sin(ya * ToRad);
  cy = Math.cos(ya * ToRad);
  sz = Math.sin(za * ToRad);
  cz = Math.cos(za * ToRad);

  # build rotation matrix
  @rot_mat =
  [
     [
        cy * cx - sy * sx * sz,
        - cy * sx - cx * sy * sz,
        cz * sy
     ],
     [
        sx * cz,
        cz * cx,
        sz
     ],
     [
        - cx * sy - sx * sz * cy,
        sx * sy - sz * cx * cy,
        cz * cy
     ]
  ]

end

add perspective to 2D points

and perform anaglyph position change if specified

def convert_3d_to_2d(x,y,z,anaglyph_flag)
x = (x * (PerspectiveDepth + z))/PerspectiveDepth
x += z * anaglyph_flag * AnaglyphScale if anaglyph_flag
y = (y * (PerspectiveDepth + z))/PerspectiveDepth
return x,y
end

rotate a 3D point using matrix values

then project into 2D space

def rotate_convert(v,anaglyph_flag)
z = @rot_mat[0][0] * v.z + @rot_mat[0][1] * v.y + @rot_mat[0][2] *
v.x
y = @rot_mat[1][0] * v.z + @rot_mat[1][1] * v.y + @rot_mat[1][2] *
v.x
x = @rot_mat[2][0] * v.z + @rot_mat[2][1] * v.y + @rot_mat[2][2] *
v.x
x,y = convert_3d_to_2d(x,y,z,anaglyph_flag)
return x,y
end
end


In this case, the matrix at the heart of the class is the most
economical
way to accomplish the mathematical objective, and there’s really no
point
in being able to change any of its constituent parts, once it has been
constructed. It would be very easy to modify any single array cell, but
there’s simply no point.

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.

Just Another Victim of the Ambient M. wrote:

relationships to be defined and applied (e.g., canonical
n + 2 (i.e., creating new references every time the data changes), just

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

Regards,

Michael


Michael U.
R&D Team
ISIS Information Systems Austria
tel: +43 2236 27551-219, fax: +43 2236 21081
e-mail: [email protected]
Visit our Website: www.isis-papyrus.com

Michael U. 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.

Michael U. wrote:

n = Matrix.scalar(2, 3)
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.

[]= 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.

Cheers,
Dave

Dave B. wrote:

If you want a matrix-like data structure (rather than a mathematical
matrix), why not use an array of arrays?

Because then I’d have to write all the matrix functions to go along with
them.

Paul L. wrote:

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 U.
R&D Team
ISIS Information Systems Austria
tel: +43 2236 27551-219, fax: +43 2236 21081
e-mail: [email protected]
Visit our Website: www.isis-papyrus.com

Dave B. wrote:

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 U.
R&D Team
ISIS Information Systems Austria
tel: +43 2236 27551-219, fax: +43 2236 21081
e-mail: [email protected]
Visit our Website: www.isis-papyrus.com

William C. wrote:

Dave B. wrote:

If you want a matrix-like data structure (rather than a mathematical
matrix), why not use an array of arrays?

Because then I’d have to write all the matrix functions to go along with
them.

Or NMatrix then:

http://narray.rubyforge.org/

Cheers,
Dave

Michael U. wrote:

Dave B. wrote:

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”,
BigBold - Informasi Tentang Bisnis dan Marketing )?

“Michael U.” [email protected] wrote in message
news:[email protected]

A mathematical matrix is just a dimensional arrangement of data into
can thus be destructively altered by assignment with the result that it
n = 3
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…

“Michael U.” [email protected] wrote in message
news:[email protected]

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…

Dave B. [email protected] writes:

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.

n.freeze can ensure immutability.

It is just incovenient that []= is not defined, I still don’t buy the
matrices
are immutable concept argument.

Cheers,


Surendra S.
http://ssinghi.kreeti.com, http://www.kreeti.com
Read my blog at: http://cuttingtheredtape.blogspot.com/
,----
| Great wits are sure to madness near allied,
| And thin partitions do their bounds divide.
|
| (John Dryden, Absalom and Achitophel, 1681)
`----

Hi,
Paul L. [email protected] writes:

digit of an integer in class Fixnum.
irb(main):001:0> x=“hello”
=> “hello”
irb(main):002:0> x[0] = ‘w’
=> “w”
irb(main):003:0> x
=> “wello”

Why is the above allowed? By the same argument, shouldn’t strings be
immutable.

Most matrix operations operate on matrices as units. Here’s an example, a
matrix from my library, responsible for rotating objects in three-space:

I don’t agree, the only example which I have heard is people talking
about
matrix rotation, what about scaling matrices, there are several other
matrix
operations.

def convert_3d_to_2d(x,y,z,anaglyph_flag)
x = (x * (PerspectiveDepth + z))/PerspectiveDepth
x += z * anaglyph_flag * AnaglyphScale if anaglyph_flag
y = (y * (PerspectiveDepth + z))/PerspectiveDepth

Ruby should allow these operations in place, what if you want to scale
just
one row?

Is there any guarantee, the implementation of matrix won’t change, and
@rows
will be there forever?

Cheers,


Surendra S.
http://ssinghi.kreeti.com, http://www.kreeti.com
Read my blog at: http://cuttingtheredtape.blogspot.com/
,----
| Great wits are sure to madness near allied,
| And thin partitions do their bounds divide.
|
| (John Dryden, Absalom and Achitophel, 1681)
`----

Just Another Victim of the Ambient M. wrote:

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.

“MonkeeSage” [email protected] wrote in message
news:[email protected]

Just Another Victim of the Ambient M. wrote:

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.

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…

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).

def new_matrix(k, x, y, value)
}
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…

Michael U. wrote:

/ …

Maybe you are better organized and all these subtleties just come
natural to you.

That would be nice if it were true. But I actually don’t modify
individual
matrix cells, I operate on matrices as units.

For me it’s a pain.

You could always subclass Matrix and then get into the habit of
requiring
your subclass instead of the original.

class LiberalMatrix < Matrix
def []=(x,y,v)
@rows[x][y] = v
end
end

As suggested by others.

Just Another Victim of the Ambient M. wrote:

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. :wink: 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. :slight_smile:

Regards,
Jordan

On 9/12/06, MonkeeSage [email protected] wrote:

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.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 9/13/06, MonkeeSage [email protected] wrote:

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.

Being Popular

Rick DeNatale wrote:

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.

Thanks Rick, that did help. The point about side-effects dovetails with
Dave’s point about predictability.

Regards,
Jordan