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