/* * iemmatrix * * objects for manipulating simple matrices * mostly refering to matlab/octave matrix functions * * Copyright (c) 2005, Franz Zotter * IEM, Graz, Austria * * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. * */ #include "iemmatrix.h" typedef enum { FILL_SUBMATRIX, FILL_INDEXED_ELEMENTS, DONT_FILL_JUST_PASS } FillStyle; static t_class *mtx_fill_class; typedef struct _MTXfill_ MTXfill; struct _MTXfill_ { t_object x_obj; int size; int rows; int columns; int fill_startcol; int fill_startrow; int *index; int index_size; int num_idcs_used; int max_index; FillStyle fill_type; t_outlet *list_outlet; t_atom *list_out; }; static void deleteMTXFill (MTXfill *mtx_fill_obj) { if (mtx_fill_obj->list_out) freebytes (mtx_fill_obj->list_out, sizeof(t_atom)*(mtx_fill_obj->size+2)); if (mtx_fill_obj->index) freebytes (mtx_fill_obj->index, sizeof(int)*(mtx_fill_obj->index_size)); } static void setListConstFloat (int size, t_float f, t_atom *y) { for(;size--;y++) SETFLOAT(y,f); } static void copyList (int size, t_atom *x, t_atom *y) { while(size--) *y++=*x++; } static int copyNonZeroAtomsToIntegerArrayMax (int *size, t_atom *x, int *y) { int idx; int n = *size; int max = atom_getint(x); *size = 0; for (;n--;x++) { idx = atom_getint (x); if (idx) { size[0]++; *y++ = idx; max = (idx > max)?idx:max; } } return max; } static void writeIndexedValuesIntoMatrix (int n, int *idx, t_atom *x, t_atom *y) { for (;n--;idx++,x++) if (*idx) y[*idx-1] = *x; } static void writeFloatIndexedIntoMatrix (int n, int *idx, t_float f, t_atom *y) { for (;n--;idx++) if (*idx) SETFLOAT(&y[*idx-1], f); } static void mTXFillIndexMatrix (MTXfill *mtx_fill_obj, t_symbol *s, int argc, t_atom *argv) { int rows = atom_getint (argv++); int columns = atom_getint (argv++); int size = rows * columns; int list_size = argc - 2; int *idx = mtx_fill_obj->index; /* size check */ if (!size) { mtx_fill_obj->fill_type = DONT_FILL_JUST_PASS; return; } if (list_size == 0) { if ((rows<1) || (columns<1)){ post("mtx_fill: row and column indices must be >0"); mtx_fill_obj->fill_type = DONT_FILL_JUST_PASS; return; } mtx_fill_obj->fill_startrow = rows; mtx_fill_obj->fill_startcol = columns; mtx_fill_obj->fill_type = FILL_SUBMATRIX; } else if (list_sizefill_type = DONT_FILL_JUST_PASS; return; } else { if (size > mtx_fill_obj->index_size) { if (!idx) idx = (int *) getbytes (sizeof (int) * (size + 2)); else idx = (int *) resizebytes (idx, sizeof (int) * (mtx_fill_obj->index_size+2), sizeof (t_atom) * (size + 2)); mtx_fill_obj->index_size = size; mtx_fill_obj->index = idx; } mtx_fill_obj->max_index = copyNonZeroAtomsToIntegerArrayMax (&size, argv++, idx); mtx_fill_obj->num_idcs_used = size; if (!size) mtx_fill_obj->fill_type = DONT_FILL_JUST_PASS; else mtx_fill_obj->fill_type = FILL_INDEXED_ELEMENTS; } } static void *newMTXFill (t_symbol *s, int argc, t_atom *argv) { MTXfill *mtx_fill_obj = (MTXfill *) pd_new (mtx_fill_class); mtx_fill_obj->size = 0; mtx_fill_obj->fill_startrow = 1; mtx_fill_obj->fill_startcol = 1; mtx_fill_obj->fill_type = DONT_FILL_JUST_PASS; error("[mtx_fill]: this object _might_ change in the future!"); if (argc) { if (atom_getsymbol(argv)==gensym("matrix")) mTXFillIndexMatrix (mtx_fill_obj, s, argc-1, argv+1); else pd_error(mtx_fill_obj, "mtx_fill: creation argument must be 'matrix ' for submatrix filling or 'matrix rows columns [...]' for indexed filling with scalar/matrices"); } mtx_fill_obj->list_outlet = outlet_new (&mtx_fill_obj->x_obj, gensym("matrix")); inlet_new(&mtx_fill_obj->x_obj, &mtx_fill_obj->x_obj.ob_pd, gensym("matrix"),gensym("fill_mtx")); inlet_new(&mtx_fill_obj->x_obj, &mtx_fill_obj->x_obj.ob_pd, gensym("matrix"),gensym("index")); return ((void *) mtx_fill_obj); } static void mTXBigMatrix (MTXfill *mtx_fill_obj, t_symbol *s, int argc, t_atom *argv) { int rows = atom_getint (argv); int columns = atom_getint (argv+1); int size = rows * columns; int list_size = argc - 2; t_atom *list_out = mtx_fill_obj->list_out; /* size check */ if (!size) { post("mtx_fill: invalid dimensions"); return; } else if (list_sizesize) { if (!list_out) list_out = (t_atom *) getbytes (sizeof (t_atom) * (size + 2)); else list_out = (t_atom *) resizebytes (list_out, sizeof (t_atom) * (mtx_fill_obj->size+2), sizeof (t_atom) * (size + 2)); } mtx_fill_obj->size = size; mtx_fill_obj->columns = columns; mtx_fill_obj->rows = rows; mtx_fill_obj->list_out = list_out; memcpy(list_out,argv,argc*sizeof(t_atom)); } static void mTXFillBang (MTXfill *mtx_fill_obj) { if (mtx_fill_obj->list_out) outlet_anything(mtx_fill_obj->list_outlet, gensym("matrix"), mtx_fill_obj->size+2, mtx_fill_obj->list_out); } static void writeFillMatrixIntoList (int fillrows, const int fillcols, int columns, t_atom *x, t_atom *y) { for (;fillrows--;x+=fillcols,y+=columns) copyList(fillcols, x, y); } static void mTXFillScalar (MTXfill *mtx_fill_obj, t_float f) { t_atom *list_out = mtx_fill_obj->list_out; int rows = mtx_fill_obj->rows; int columns = mtx_fill_obj->columns; switch (mtx_fill_obj->fill_type) { case FILL_SUBMATRIX: post("mtx_fill: scalar fill for submatrices not supported yet"); return; break; case FILL_INDEXED_ELEMENTS: if (mtx_fill_obj->max_index > mtx_fill_obj->size) { post("mtx_fill: index matrix index exceeds matrix borders"); return; } if (mtx_fill_obj->size == 0) { post("mtx_fill: no matrix defined for filling"); return; } /* main part */ writeFloatIndexedIntoMatrix (mtx_fill_obj->num_idcs_used, mtx_fill_obj->index, f,list_out+2); default: mTXFillBang(mtx_fill_obj); } } static void mTXFillMatrix (MTXfill *mtx_fill_obj, t_symbol *s, int argc, t_atom *argv) { int fill_rows = atom_getint (argv++); int fill_columns = atom_getint (argv++); int fill_size = fill_rows * fill_columns; int list_size = argc - 2; int rows = mtx_fill_obj->rows; int columns = mtx_fill_obj->columns; t_atom *fill_mtx = argv; t_atom *list_out = mtx_fill_obj->list_out; int stopcol = mtx_fill_obj->fill_startcol+fill_columns-1; int stoprow = mtx_fill_obj->fill_startrow+fill_rows-1; if (mtx_fill_obj->fill_type == DONT_FILL_JUST_PASS) { mTXFillBang(mtx_fill_obj); return; } /* size check */ if (!list_size) { post("mtx_fill: invalid dimensions"); return; } switch (mtx_fill_obj->fill_type) { case FILL_SUBMATRIX: if (list_size < fill_size) { post("mtx_fill: sparse matrix not yet supported: use \"mtx_check\""); return; } if ((stopcol > columns) || (stoprow > rows)) { post("mtx_fill: fill matrix index exceeds matrix borders"); return; } break; case FILL_INDEXED_ELEMENTS: if (list_size < mtx_fill_obj->num_idcs_used) { post("mtx_fill: fill matrix smaller than indexing vector"); return; } else if (mtx_fill_obj->max_index > mtx_fill_obj->size) { post("mtx_fill: index matrix index exceeds matrix borders"); return; } break; case DONT_FILL_JUST_PASS: break; } if (mtx_fill_obj->size == 0) { post("mtx_fill: no matrix defined for filling"); return; } /* main part */ switch (mtx_fill_obj->fill_type) { case FILL_SUBMATRIX: list_out += columns * (mtx_fill_obj->fill_startrow-1) + mtx_fill_obj->fill_startcol-1; writeFillMatrixIntoList (fill_rows, fill_columns, columns, fill_mtx, list_out+2); break; case FILL_INDEXED_ELEMENTS: writeIndexedValuesIntoMatrix (mtx_fill_obj->num_idcs_used, mtx_fill_obj->index, fill_mtx,list_out+2); break; case DONT_FILL_JUST_PASS: break; } mTXFillBang(mtx_fill_obj); } void mtx_fill_setup (void) { mtx_fill_class = class_new (gensym("mtx_fill"), (t_newmethod) newMTXFill, (t_method) deleteMTXFill, sizeof (MTXfill), CLASS_DEFAULT, A_GIMME, 0); class_addbang (mtx_fill_class, (t_method) mTXFillBang); class_addmethod (mtx_fill_class, (t_method) mTXFillMatrix, gensym("matrix"), A_GIMME,0); class_addmethod (mtx_fill_class, (t_method) mTXBigMatrix, gensym("fill_mtx"), A_GIMME,0); class_addmethod (mtx_fill_class, (t_method) mTXFillIndexMatrix, gensym("index"), A_GIMME,0); class_addfloat (mtx_fill_class, (t_method) mTXFillScalar); } void iemtx_fill_setup(void){ mtx_fill_setup(); }