Re: outer product implementation

Muthiah Annamalai <[email protected]> Tue, 12 Sep 2006 17:40:06 -0500
Newsgroups gmane.comp.gnu.octave.sources
Message-ID <1158100806.21542.15.camel@localhost>
--=-Ulbj3VRcRR9ncYEYzVD9
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

David,
Thanks for the tip on inline functions & the code.
Im still not sure if what I did was inline functions, but
the code works correctly after I have integrated the code
you posted earlier. 

Im attaching the 3rd attempt to outer product implementation.

It can take 2 forms of functions AFAIK: ones by @ sign, 
and using function name as a string.

Now I cut off from the code a useless pre-invocation, as
this doesnt help anyway, 'cos Octave itself while creating
function objects bails out, when the function is invalid or
undefined.

Thanks,
Muthu

PS: Again attaching the code & test case.
PPS: David please let me know if I have missed attribution 
     and/or citation in comments.

On Mon, 2006-09-11 at 21:40 +0200, David Bateman wrote:
> Muthiah Annamalai wrote:
> 
> > David,
> > I think I didnt mention the kind of functionality I wanted: 
> > To evaluate functions when 
> > 
> > 1. Passed by @ sign
> > 2. Passed by function name (string)
> > 3. Passed by inline function code
> > 
> > 
> > Now the code you point out to me handles the inline function code.
> > 
> > But I was actually mentioning #2 in the list.
> > 
> 
> Check again. There is functionally no difference between inline and
> function handles in an oct-file (as in fact one class is derived from
> the other). So the function handles and inline functions are both
> handled by the first couple of lines. String args are handled by the
> rest of the code.
> 
> > I think I will have to use some way to load the function and 
> > get a octave_function handle to it, as feval() of this might
> > make the process slower than it need to be.
> > 
> > So Im working on adding the #2 and #3 using your suggested code in
> > (quad.cc).
> 
> Use the code in the message, as the code in quad.cc assumes that the
> function has a single input and output argument..
> 
> D.
> 
> > 
> > Thanks
> > Muthu
> 

--=-Ulbj3VRcRR9ncYEYzVD9
Content-Disposition: attachment; filename=outer.cpp
Content-Type: text/x-c++src; name=outer.cpp; charset=UTF-8
Content-Transfer-Encoding: 7bit

/* 
 *    (C) 2006, September, Muthiah Annamalai. <[email protected]>
 *    An implementation of the 'outer'-product function as specified in the
 *    octave-projects page, at www.octave.org.
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details. 
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include<iostream>
#include<octave/oct.h>
#include<octave/parse.h>
#include<octave/dynamic-ld.h>
#include<octave/oct-map.h>
#include<octave/oct-stream.h>
#include<octave/ov.h>
#include<octave/parse.h>

#include<octave/Matrix.h>
#include<octave/ov-cx-mat.h>
#include<octave/ov-list.h>
#include<octave/ov-base-mat.h>

#include<octave/quit.h>
#include<octave/error.h>

inline static bool is_vector(octave_value arg) {
	return ((arg.is_matrix_type()&& !arg.is_char_matrix() &&  (arg.columns()==1 || arg.rows()==1))? true : false);
}


DEFUN_DLD(outer,args,,
"-*- texinfo -*-\n"
"@deftypefn {Loadable Function} {@var{outer_product} =} outer (@var{x},@var{y})\n"
"@deftypefnx {Loadable Function} {@var{outer_product} =} outer (@var{x},@var{y},@var{@@f})\n"
"@deftypefnx {Loadable Function} {@var{outer_product} =} outer (@var{x},@var{y},@var{\"f\"})\n"
"\n"
"function outer(VecX,VecY,opt:function)\n"
"Return a @var{M}x@var{N} matrix with @var{f}(@var{x},@var{y}) evaluated at x,y position\n"
"for each @var{x},@var{y} in Vector @var{X},Vector @var{Y} respectively\n"
"If function is not provided, use '*' as default operation\n"
"A function can be provided using argument @var{f} \n"
"using reference operator (@@) or the name of function or inline functions.\n"
"\n"
"example: outer(@var{[1.0 2.0 3.0]},@var{[2.0 3.0 4.0]},@@gcd)\n"
"compute the 3x3 matrix with each element in it being the\n"
"GCD of the corresponding x and y elements of the matrix\n"
"\n"
"@end deftypefn\n"
"@seealso{}")
{
  int m=0,n=0,aLength=0;
  ColumnVector cv[2];
  bool function_present=false;
  octave_function *func=NULL;
  octave_value_list erval;
  const char *func_name=NULL;
  std::string func_n;

  bool is_commutative=false;

  aLength=args.length();

  if(aLength < 2)
    {
      error("Usage: outer(VecX,VecY,opt:function)");
      return erval;
    }

  if(!(is_vector(args(0)) || is_vector(args(1))))
    {
      error("Usage: outer(VecX,VecY,opt:function);\n Invalid argument arg- [1 or 2]Expected Row/Column Vector");
      return erval;
    }

   /*
   * hope to use commutativity of the operators someday
   */
  if(aLength>=3)
    {
      function_present=true;
      is_commutative=false;

     if(args(2).is_inline_function())
       {        
        std::string fname;
	func_n = unique_symbol_name ("__fcn_");
	fname = "function z = ";
	fname.append (func_n);
	fname.append ("(x, y) z = ");
	octave_stdout << "IS INLINE: "<< fname << std::endl;
	func = extract_function (args(0), "outer", func_n, fname,"(x, y); endfunction");
       }
     else if(args(2).is_function_handle())
       {
	func=args(2).function_value();	
       }
     else if ( args(2).is_string() )
       {
        std::string fname;
     	fname = "function z = ";
	fname.append (args(2).string_value());
	fname.append ("(x, y) z = ");
	octave_stdout << fname << std::endl;
	func=extract_function(args(2),"outer",args(2).string_value(), \
	                      fname,"(x,y); endfunction");
       }
     else
       {
         error("3rd Argument need to be a function. See 'help outer' for more details.");
         return octave_value(-1);
       }

    if (error_state || !func)
       {
          error("Cannot obtain function handle from inline or user-defined or dynamic loading.");
          return octave_value(-1);
       }
       
    }

  cv[0]=ColumnVector(args(0).vector_value());
  cv[1]=ColumnVector(args(1).vector_value());

  m=cv[0].length();
  n=cv[1].length();

  Matrix rmat(m,n);
  octave_value_list ovl;
  

  if(function_present && func!=NULL)
    {
      
      /* FIXME: <Vectorize Code>
       * Paul says do this thing as a single loop.
       * Iterate over Columns, taking one full column at a time, 
       * and save the result on the columns of the matrix.
       * Atleast this is possible for builtins that take arguments
       * over columns/rows, if not user defined functions.
       */
      for(int itr=0;itr<m;itr++)
	for(int icol=0;icol<n;icol++)
	  {

	    OCTAVE_QUIT;
	      
	    ovl(0)=cv[0].elem(itr);
	    ovl(1)=cv[1].elem(icol);

	    rmat.elem(itr,icol)=feval(func,ovl)(0).double_value();
	    if(error_state)
	      {
		error("Exception: while evaluating %s with arguments %g %g\n",func_name,cv[0].elem(itr),cv[1].elem(icol));
		return erval;
	      }
	  }
	  
      if(func_n.length() > 0)
      {
        // We have a string function name. Dealloc temp func
        clear_function (func_n);
       }
    }
  else
    {
      /* do a simple product */
      rmat=cv[0]*cv[1].transpose();
    }

  return octave_value(rmat);
}
/* Make command:
g++ -fpic outer.cpp -shared -o outer.oct -Wall -ggdb -Wall -Wunused -Wconversion -fno-exceptions -DDEBUG=1  `mkoctfile -p INCFLAGS` 
*/

--=-Ulbj3VRcRR9ncYEYzVD9
Content-Disposition: attachment; filename=outertest.m
Content-Type: text/x-octave; name=outertest.m; charset=UTF-8
Content-Transfer-Encoding: 7bit

#! /usr/bin/octave -q
%outer
disp('Help on Outer')
help outer
pause
disp('Product- testing ;-) Imean this * product')

outer([1 2],[1 2 3 4])
outer([1],[1 2 3])
outer([1 2 3],[1])
outer([1 2 3],[1 2 3])
%outer([1],[2]) %error this is caught.
pause

disp('Functions being Invoked')
pause

disp('Min')
outer(rand(1,10),rand(1,10),@min)
outer(rand(1,4),rand(1,4),"min")
outer(rand(1,2),rand(1,2),'min')


disp('IsEqual')
outer([1 2],[1 2 3 4],@isequal)

disp('Max')
outer([1],[1 2 3],@max)

disp('GCD ')
outer([1.0 2.0 3.0],[2.0 3.0 4.0],@gcd)
outer([1.0 2.0 3.0],[2.0 3.0 4.0],'gcd')
outer([14 20 35 40],[7],@gcd)


disp('Square Matrix')
outer([1:5],[1:5])

disp('One arg scalar other vector')
outer(3,[1:5])
outer([1:5],3)

disp('functions that dont return an argument! ')
try
  outer([14 20 35 40],[7],@disp) %functions that dont return an argument! 
catch
  disp('Exception')
end

disp('non-existent functions throw errors at Octave prompt itself.');
try
outer([14 20 35 40],[7],@bwand) %non-existent functions throw errors at Octave prompt itself.
catch
  disp('Exception')
end

try
disp('Both Scalar')
outer([1],[2]) %error 
catch
  disp('Exception')
end

--=-Ulbj3VRcRR9ncYEYzVD9
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Octave-sources mailing list
[email protected]
https://www.cae.wisc.edu/mailman/listinfo/octave-sources

--=-Ulbj3VRcRR9ncYEYzVD9--