[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Help with [] for defined types

From: Paul Kienzle
Subject: Re: Help with [] for defined types
Date: Thu, 8 Jul 2004 07:17:41 -0400

On Jul 8, 2004, at 5:50 AM, David Bateman wrote:


I've basically written most of the code for a CATOP function with a
binary lookup table similar to BINOP functions

According to Paul Kienzle <address@hidden> (on 07/08/04):
dispatch could be extended so that it searches the entire
argument list for the given type.   0.0I wouldn't want to try
to support a specific list of types since octave makes
heavy use of dynamic interpretation of the argument list.

I don't want to create a type hierarchy like matlab, perl, etc.,
but what do we do when someone uses:

        cat(sparse(), full(), galois())

In this case, obviously it is galois, but somehow 3rd party
types would need to negotiate what to use.  Not very pretty.

What I suggest is that this is implemented as

        cat(cat(sparse(),full()), galois())

with the proviso on memory you discuss below. The first cat would promote the
sparse matrix to a full() as defined by the function

NDArray concat (const Sparse& ra, const NDArray& rb, Array<int>& ra_idx)

and the second similarly to a Galois type as

galois concat (const NDArray& ra, const galois& rb, Array<int>& ra_idx)

It is assumed that the first argument is already resized to the final
dimension and the make_unique is NOT called so that the data in ra is
in fact altered in the return matrix. This is proviso is needed to
prevent multiple copies of the block being made. Thus the function
concat is a little dangerous as it alters the input arguments. However
as I expect it will only be used in Fcat and the "[]" operator I don't
think this is an issue. In the case of a promotion of ra to a different
type, then the data in ra must be copied.

Also not pretty is defining pairwise ops between types from
different packages.


This is a restatement of the type explosion problem.  I guess it will
work out that the types which care about each other will either
have each other as prereqs or be part of the same package.

It is only the case of promotion of the return type that will cause
problems, and frankly this is a case that will arrive due to lazy coding
of the dot-m files, so it doesn't bother me if that case is slightly
inefficient. The funny thing is that  cat(galois(), full(), sparse())
would be much much efficient that cat(sparse(), full(), galois()) due
to the fact that there would be no promotion needed.

The simplicity of only defining binary ops makes me feel that the
performance hit for the type promotion is a small price to pay. The
pay off of the binary operator approach is the easily defined dependency
on promotion of the types.

Okay, so the idea is that if you are really concerned, then
use explicit conversion.  E.g.,

         [ mytype(data); data; data; mytypestuff ]

I'm not sure this would work for something like complex, since
1+0i is real.  Maybe we need an explicit complex() constructor?

For efficiency you want to walk the whole arg list to []
and determine the final type and dimensions before
building anything.

Yeah, I know, I found out the hard way. I have a working version of CATOP that doesn't determine the final size initially and just walks the list. It is twice as slow with 2 like sized args, 4 times as slow with 3 like size args, etc. In any case it was a good learning experience and I've mostly rewritten the CATOP stuff to initialize the matrix first. I had to define
a resize function as part of the octave_value class that also promotes
scalars to matrices. So the core of Fcat becomes

          octave_value tmp (args(1));
          tmp.resize (dv);
          Array<int> ra_idx (dv.length (), 0);
          for (int i = 2; i < n_args; i++)
              dim_vector dv_tmp = args (i-1).dims ();
              ra_idx (dim) += (dim > dv_tmp.length () ? 1 : dv_tmp (dim));
              tmp = do_cat_op (tmp, args (i), ra_idx);
              if (error_state)
                return retval;
          retval = tmp;

The tricky bit again is to decide what type to assign
when two different user types are being used
simultaneously.  I guess that's a problem for the
user type installer to deal with.

This is where the binary definition of the CATOP makes sense. All of this
is determined by an appropriate lookup table. This is why I prefer the
binary operator approach, with preallocation of the memory.

Okay.  Only other detail you might want to consider is
an eventual implementation of types in m-files.  Is this
going to be possible/convenient, and maybe compatible?

Paul Kienzle

reply via email to

[Prev in Thread] Current Thread [Next in Thread]