Hi,

I would like to put into the struct package 4 functions which I need
for myself and for something planned in the optim package. They do
some handling of many structure fields without interpreted loops.

- arefields: index of keys in a cell array valid as structure fields

- fields2cell: as struct2cell, but only named fields

- fieldempty: index of structure array entries where field is empty

- structcat: like cat for structures, but fills missing fields with []

They are attached for review, I could commit them if allowed. Also
attached is a script showing my motivation for having these functions.

Olaf
/*

Copyright (C) 2010 Olaf Till

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 3 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, see <http://www.gnu.org/licenses/>.

*/

#include <octave/oct.h>
#include <octave/ov-struct.h>

DEFUN_DLD (arefields, args, , 
  "-*- texinfo -*-\n\
@deftypefn {Loadable Function} {} arefields (@var{s}, @var{names})\n\
Return a logical vector indicating which of the strings in cell array @var{names} is a valid field name of structure @var{s}.\n\
@end deftypefn")
{
  std::string fname ("arefields");

  if (args.length () != 2)
    {
      print_usage ();
      return octave_value_list ();
    }

  Octave_map s = args(0).map_value ();
  if (error_state)
    {
      error ("%s: first argument must be a structure", fname.c_str ());
      return octave_value_list ();
    }

  Array<std::string> names = args(1).cellstr_value ();
  if (error_state)
    {
      error ("%s: second argument must be a cell array of strings",
	     fname.c_str ());
      return octave_value_list ();
    }

  dim_vector dims = names.dims ();
  if (dims.length () > 2 ||
      (dims(0) > 1 && dims(1) > 1))
    {
      error ("%s: second argument must be a one-dimensional cell array",
	     fname.c_str ());
      return octave_value_list ();
    }

  boolMatrix retval (dims);

  octave_idx_type n = names.length ();
  for (octave_idx_type i = 0; i < n; i++)
    {
      if (s.contains (names(i)))
	retval(i) = true;
      else
	retval(i) = false;
    }

  return octave_value (retval);
}
/*

Copyright (C) 2010 Olaf Till

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 3 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, see <http://www.gnu.org/licenses/>.

*/

#include <octave/oct.h>
#include <octave/ov-struct.h>

DEFUN_DLD (fieldempty, args, , 
  "-*- texinfo -*-\n\
@deftypefn {Loadable Function} {} fieldempty (@var{s}, @var{name})\n\
Returns a logical array with same dimensions as structure @var{s}, indicating where field @var{name} is empty.\n\
@end deftypefn")
{
  std::string fname ("fieldempty");

  if (args.length () != 2)
    {
      print_usage ();
      return octave_value_list ();
    }

  Octave_map s = args(0).map_value ();
  if (error_state)
    {
      error ("%s: first argument must be a structure", fname.c_str ());
      return octave_value_list ();
    }

  std::string name = args(1).string_value ();
  if (error_state)
    {
      error ("%s: second argument must be a string", fname.c_str ());
      return octave_value_list ();
    }

  if (! s.contains (name))
    {
      error ("%s: no such field", fname.c_str ());
      return octave_value_list ();
    }

  dim_vector sdims = s.dims ();

  boolNDArray retval (sdims);

  octave_idx_type numel = s.numel ();

  if (! numel)
    return octave_value (retval);

  Cell c (s.contents (name));

  for (octave_idx_type i = 0; i < numel; i++)
    {
      if (c(i).numel ())
	retval(i) = false;
      else
	retval(i) = true;
    }

  return octave_value (retval);
}
/*

Copyright (C) 2010 Olaf Till

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 3 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, see <http://www.gnu.org/licenses/>.

*/

#include <octave/oct.h>
#include <octave/ov-struct.h>

DEFUN_DLD (fields2cell, args, , 
  "-*- texinfo -*-\n\
@deftypefn {Loadable Function} {} fields2cell (@var{s}, @var{names})\n\
Works similarly to @code{struct2cell} (see there), but considers only fields given by the strings in cell array @var{names}. Returns an error if a field is missing in @var{s}.\n\
@end deftypefn")
{
  std::string fname ("fields2cell");

  if (args.length () != 2)
    {
      print_usage ();
      return octave_value_list ();
    }

  Octave_map s = args(0).map_value ();
  if (error_state)
    {
      error ("%s: first argument must be a structure", fname.c_str ());
      return octave_value_list ();
    }

  Array<std::string> names = args(1).cellstr_value ();
  if (error_state)
    {
      error ("%s: second argument must be a cell array of strings",
	     fname.c_str ());
      return octave_value_list ();
    }

  if (names.dims ().length () > 2 ||
      (names.dims ()(0) > 1 && names.dims ()(1) > 1))
    {
      error ("%s: second argument must be a one-dimensional cell array",
	     fname.c_str ());
      return octave_value_list ();
    }

  octave_idx_type n = names.length ();

  dim_vector sdims = s.dims ();

  octave_idx_type n_sdims = sdims.length ();

  dim_vector dims;
  if (sdims(n_sdims - 1) == 1)
    dims.resize (n_sdims);
  else
    dims.resize (++n_sdims);

  dims(0) = n;
  for (octave_idx_type i = 1; i < n_sdims; i++)
    dims(i) = sdims(i - 1);

  Cell retval (dims);

  octave_idx_type k = s.numel ();

  for (octave_idx_type i = 0; i < n; i++)
    {
      if (! s.contains (names(i)))
	{
	  error ("%s: some fields not present", fname.c_str ());
	  return octave_value_list ();
	}

      Cell tp = s.contents (names(i));

      octave_idx_type l = i;
      for (octave_idx_type j = 0; j < k; j++)
	{
	  retval(l) = tp(j);
	  l += n;
	}
    }

  return octave_value (retval);
}
/*

Copyright (C) 2009 John W. Eaton
Copyright (C) 2009 Jaroslav Hajek
Copyright (C) 2010 Olaf Till

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 3 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, see <http://www.gnu.org/licenses/>.

*/

// This code and the comments are taken and slightly modified from
// Octave-3.2.4, src/data.cc (do_cat()), src/ov.cc (do_cat_op ()),
// src/OPERATORS/op-struct.cc, src/ops.h, and oct-map.cc
// (Octave_map::concat ()).

#include <octave/oct.h>
#include <octave/ov-struct.h>

static octave_value
structcat_cat_op_fcn (const octave_value& v1, const octave_value& v2, 
		      const Array<octave_idx_type>& ra_idx)
{
  Octave_map retval;

  Octave_map m1 = v1.map_value ();
  Octave_map m2 = v2.map_value ();

  Cell c2 (m2.dims ());

  for (Octave_map::const_iterator pa = m1.begin (); pa != m1.end (); pa++)
    {
      Octave_map::const_iterator pb = m2.seek (m1.key(pa));

      if (pb == m2.end ())
	retval.assign (m1.key(pa),
		       m1.contents(pa).insert (c2, ra_idx));
      else
	retval.assign (m1.key(pa),
		       m1.contents(pa).insert (m2.contents(pb), ra_idx));
    }

  dim_vector dv1 (m1.dims ());

  for (Octave_map::const_iterator pa = m2.begin (); pa != m2.end (); pa++)
    {
      Octave_map::const_iterator pb = m1.seek (m2.key(pa));

      if (pb == m1.end ())
	{
	  Cell c1 (dv1);
	  retval.assign (m2.key(pa),
			 c1.insert (m2.contents(pa), ra_idx));
	}
    }

  return retval;
}


DEFUN_DLD (structcat, args, , 
  "-*- texinfo -*-\n\
@deftypefn {Loadable Function} {} structcat (@var{dim}, @var{struct1}, @dots{}, @var{structn})\n\
Return the concatenation of N-d structures @var{struct1}, @dots{}, @var{structn} along dimension @var{dim}. Differently to @code{cat}, fields need not match --- missing fields get an empty matrix value. Without structure arguments, an empty structure array is returned.\n\
@end deftypefn")
{
  std::string fname ("structcat");

  octave_value retval;

  int n_args = args.length (); 

  if (n_args == 1)
    retval = Octave_map ();
  else if (n_args == 2)
    retval = args(1).map_value ();
  else if (n_args > 2)
    {
      octave_idx_type dim = args(0).int_value () - 1;

      if (error_state)
	{
	  error ("%s: expecting first argument to be a integer",
		 fname.c_str ());
	  return retval;
	}
  
      if (dim >= 0)
	{
 	  dim_vector  dv = args(1).dims ();
	  std::string result_type ("struct");

 	  for (int i = 2; i < args.length (); i++)
  	    {
 	      // Construct a dimension vector which holds the
	      // dimensions of the final array after concatenation.
      
	      if (! dv.concat (args(i).dims (), dim))
		{
		  // Dimensions do not match. 
		  error ("%s: dimension mismatch", fname.c_str ());
		  return retval;
		}
	      
	      if (args(i).class_name () != result_type)
		{
		  error ("%s: some argument not a structure",
			 fname.c_str ());
		  return retval;
		}
	    }

	  // The lines below might seem crazy, since we take a
	  // copy of the first argument, resize it to be empty and
	  // then resize it to be full. This is done since it
	  // means that there is no recopying of data, as would
	  // happen if we used a single resize.  It should be
	  // noted that resize operation is also significantly
	  // slower than the do_cat_op function, so it makes sense
	  // to have an empty matrix and copy all data.
	  //
	  // We might also start with a empty octave_value using
	  //   tmp = octave_value_typeinfo::lookup_type 
	  //                                (args(1).type_name());
	  // and then directly resize. However, for some types there might
	  // be some additional setup needed, and so this should be avoided.

	  octave_value tmp = args (1);
	  tmp = tmp.resize (dim_vector (0,0)).resize (dv);

	  if (error_state)
	    return retval;

	  int dv_len = dv.length ();
	  Array<octave_idx_type> ra_idx (dv_len, 0);

	  for (int j = 1; j < n_args; j++)
	    {
	      dim_vector dv_tmp = args (j).dims ();

	      if (! dv_tmp.all_zero ())
		{
		  tmp = structcat_cat_op_fcn (tmp, args(j), ra_idx);

		  if (error_state)
		    return retval;

		  if (dim >= dv_len)
		    {
		      if (j > 1)
			error ("%s: indexing error", fname.c_str ());
		      break;
		    }
		  else
		    ra_idx (dim) += (dim < dv_tmp.length () ? 
				     dv_tmp (dim) : 1);
		}
	    }
	  retval = tmp;

	  if (! error_state)
	    {
	      // Reshape, chopping trailing singleton dimensions
	      dv.chop_trailing_singletons ();
	      retval = retval.reshape (dv);
	    }
	}
      else
	error ("%s: invalid dimension argument", fname.c_str ());
    }
  else
    print_usage ();

  return retval;
}
### This demonstrates how configuration of corresponding properties for
### different items, stored in a structure, can be transformed into
### vectors, one for each property, without interpreted loops.

## configure properties 1, 2, and 3 for values v1, v2, v3, and v4

config.v1.property1 = true;
config.v1.property2 = 16;
config.v1.property3 = .5;

config.v2.property2 = 12;

config.v3.property1 = false;
config.v3.property3 = .2;

config.v4.property1 = true;

## define an order of values v1, v2, and v3 in each vector of a
## property; configuration for v4 is not used
v_order = {"v1", "v3", "v2"};

## check that all values have configuration entries
if (! all (arefields (config, v_order)))
  error ("not all items are configured");
endif

## turn the set of values at fields (v1, v3, v2) into a structure array
extracted_config = structcat (1, fields2cell (config, v_order){:});

## make vectors with default values for each property

## property1_default = false;
property2_default = 10;
property3_default = 1;

n = length (v_order);

property1 = false (n, 1);
property2 = property3 = zeros (n, 1);
property2(:) = property2_default;
property3(:) = property3_default;

## if a property is configured, replace the corresponding vector element
## with it
property1(! fieldempty (extracted_config, "property1")) = \
    [extracted_config.property1]
property2(! fieldempty (extracted_config, "property2")) = \
    [extracted_config.property2]
property3(! fieldempty (extracted_config, "property3")) = \
    [extracted_config.property3]
------------------------------------------------------------------------------
Virtualization is moving to the mainstream and overtaking non-virtualized
environment for deploying applications. Does it make network security 
easier or more difficult to achieve? Read this whitepaper to separate the 
two and get a better understanding.
http://p.sf.net/sfu/hp-phase2-d2d
_______________________________________________
Octave-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/octave-dev

Reply via email to