aboutsummaryrefslogtreecommitdiff
path: root/gfsm/src/pd_automaton.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfsm/src/pd_automaton.c')
-rw-r--r--gfsm/src/pd_automaton.c765
1 files changed, 765 insertions, 0 deletions
diff --git a/gfsm/src/pd_automaton.c b/gfsm/src/pd_automaton.c
new file mode 100644
index 0000000..47ce4cd
--- /dev/null
+++ b/gfsm/src/pd_automaton.c
@@ -0,0 +1,765 @@
+/*=============================================================================*\
+ * File: pd_automaton.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * 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.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * 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.
+ *=============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pd_automaton.h>
+#include <pd_io.h>
+#include <m_pd.h>
+
+/*--------------------------------------------------------------------
+ * DEBUG
+ *--------------------------------------------------------------------*/
+//#define PDFSM_DEBUG 1
+
+/*=====================================================================
+ * Structures and Types
+ *=====================================================================*/
+static t_class *pd_gfsm_automaton_pd_class;
+static t_class *pd_gfsm_automaton_obj_class;
+
+/*=====================================================================
+ * pd_gfsm_automaton_pd: Methods
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_pd: new()
+ */
+static void *pd_gfsm_automaton_pd_new(t_symbol *name)
+{
+ t_pd_gfsm_automaton_pd *x = (t_pd_gfsm_automaton_pd *)pd_new(pd_gfsm_automaton_pd_class);
+
+ //-- debug
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_pd_new() called; name=%s ; x=%p\n", name->s_name, x);
+#endif
+
+ //-- defaults
+ x->x_refcnt = 0;
+ x->x_name = name;
+ x->x_automaton = gfsm_automaton_new();
+
+ //-- bindings
+ if (name != &s_) pd_bind((t_pd*)x, name);
+
+ return (void *)x;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_pd: free()
+ */
+static void pd_gfsm_automaton_pd_free(t_pd_gfsm_automaton_pd *x)
+{
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_pd_free() called ; x=%p", x);
+#endif
+
+ if (x->x_automaton) gfsm_automaton_free(x->x_automaton);
+ x->x_automaton = NULL;
+
+ /* unbind the symbol of the name of hashtable in pd's global namespace */
+ if (x->x_name != &s_) pd_unbind((t_pd*)x, x->x_name);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_pd: setup()
+ */
+void pd_gfsm_automaton_pd_setup(void)
+{
+ //-- class
+ pd_gfsm_automaton_pd_class = class_new(gensym("pd_gfsm_automaton_pd"),
+ (t_newmethod)pd_gfsm_automaton_pd_new,
+ (t_method)pd_gfsm_automaton_pd_free,
+ sizeof(t_pd_gfsm_automaton_pd),
+ CLASS_PD,
+ A_DEFSYM,
+ A_NULL);
+}
+
+/*=====================================================================
+ * Utilities
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_pd_find()
+ */
+t_pd_gfsm_automaton_pd *pd_gfsm_automaton_pd_find(t_symbol *name)
+{
+ if (name != &s_)
+ return (t_pd_gfsm_automaton_pd*)pd_findbyclass(name,pd_gfsm_automaton_pd_class);
+ return NULL;
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_pd_get()
+ */
+t_pd_gfsm_automaton_pd *pd_gfsm_automaton_pd_get(t_symbol *name)
+{
+ t_pd_gfsm_automaton_pd *x = pd_gfsm_automaton_pd_find(name);
+ if (!x) {
+ x = (t_pd_gfsm_automaton_pd*)pd_gfsm_automaton_pd_new(name);
+ x->x_refcnt = 0;
+ }
+ return x;
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_pd: release()
+ */
+void pd_gfsm_automaton_pd_release(t_pd_gfsm_automaton_pd *x)
+{
+ if (x) {
+ if (x->x_refcnt) --x->x_refcnt;
+ if (!x->x_refcnt) pd_gfsm_automaton_pd_free(x);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_symbol()
+ */
+void pd_gfsm_automaton_obj_outlet_symbol(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_symbol *val)
+{
+ SETSYMBOL(x->x_argv, val);
+ outlet_anything(x->x_valout, sel, 1, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_symbol()
+ */
+void pd_gfsm_automaton_obj_outlet_symbol_float(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_symbol *sym, t_float f)
+{
+ SETSYMBOL(x->x_argv, sym);
+ SETFLOAT(x->x_argv+1, f);
+ outlet_anything(x->x_valout, sel, 2, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_float()
+ */
+void pd_gfsm_automaton_obj_outlet_float(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_float f)
+{
+ SETFLOAT(x->x_argv, f);
+ outlet_anything(x->x_valout, sel, 1, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_float_2()
+ */
+void pd_gfsm_automaton_obj_outlet_float_2(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_float f1, t_float f2)
+{
+ SETFLOAT(x->x_argv , f1);
+ SETFLOAT(x->x_argv+1, f2);
+ outlet_anything(x->x_valout, sel, 2, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_bang()
+ */
+void pd_gfsm_automaton_obj_outlet_bang(t_pd_gfsm_automaton_obj *x, t_symbol *sel)
+{
+ SETSYMBOL(x->x_argv, &s_bang);
+ outlet_anything(x->x_valout, sel, 1, x->x_argv);
+}
+
+
+
+/*=====================================================================
+ * pd_gfsm_automaton_obj: Methods
+ *=====================================================================*/
+
+/*=====================================================================
+ * Constructors, etc.
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: new
+ */
+static void *pd_gfsm_automaton_obj_new(t_symbol *name)
+{
+ t_pd_gfsm_automaton_obj *x =
+ (t_pd_gfsm_automaton_obj *)pd_new(pd_gfsm_automaton_obj_class);
+
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_obj_new() called: name=%s ; x=%p",
+ (name ? name->s_name : "(null)"),
+ x);
+#endif
+
+ //-- defaults
+ //x->x_automaton_pd = NULL;
+
+ //-- bindings
+ x->x_automaton_pd = pd_gfsm_automaton_pd_get(name);
+ x->x_automaton_pd->x_refcnt++;
+
+ //-- outlets
+ x->x_valout = outlet_new(&x->x_obj, &s_anything); //-- value outlet
+
+ return (void *)x;
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: free
+ */
+static void pd_gfsm_automaton_obj_free(t_pd_gfsm_automaton_obj *x)
+{
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_obj_free() called: x=%p", x);
+#endif
+
+ pd_gfsm_automaton_pd_release(x->x_automaton_pd);
+
+ //-- do we need to do this?
+ outlet_free(x->x_valout);
+}
+
+/*=====================================================================
+ * automaton_obj: Basic Accessors
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: automaton
+ */
+static void pd_gfsm_automaton_obj_automaton(t_pd_gfsm_automaton_obj *x, t_symbol *name)
+{
+ if (name != x->x_automaton_pd->x_name) {
+ pd_gfsm_automaton_pd_release(x->x_automaton_pd);
+ x->x_automaton_pd = pd_gfsm_automaton_pd_get(name);
+ ++x->x_automaton_pd->x_refcnt;
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("automaton"), name);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: size()
+ */
+static void pd_gfsm_automaton_obj_size(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ if (argc > 0) {
+ gfsmStateId n = (gfsmStateId)atom_getfloatarg(0,argc,argv);
+ gfsm_automaton_reserve(x->x_automaton_pd->x_automaton, n);
+ }
+ pd_gfsm_automaton_obj_outlet_float
+ (x, sel, (t_float)gfsm_automaton_n_states(x->x_automaton_pd->x_automaton));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: clear()
+ */
+static void pd_gfsm_automaton_obj_clear(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_clear(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("clear"));
+}
+
+/*=====================================================================
+ * automaton_obj: flags
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: root()
+ */
+static void pd_gfsm_automaton_obj_root(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ gfsmStateId q0;
+ if (argc > 0) {
+ q0 = (gfsmStateId)atom_getintarg(0,argc,argv);
+ gfsm_automaton_set_root(x->x_automaton_pd->x_automaton, q0);
+ } else {
+ q0 = gfsm_automaton_get_root(x->x_automaton_pd->x_automaton);
+ }
+
+ if (q0==gfsmNoState) pd_gfsm_automaton_obj_outlet_bang(x, sel);
+ else pd_gfsm_automaton_obj_outlet_float(x, sel, (t_float)q0);
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: weighted()
+ */
+static void pd_gfsm_automaton_obj_weighted(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ if (argc > 0)
+ x->x_automaton_pd->x_automaton->flags.is_weighted = atom_getboolarg(0,argc,argv);
+ pd_gfsm_automaton_obj_outlet_float
+ (x, sel, (t_float)(x->x_automaton_pd->x_automaton->flags.is_weighted));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: transducer()
+ */
+static void pd_gfsm_automaton_obj_transducer(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ if (argc > 0)
+ x->x_automaton_pd->x_automaton->flags.is_transducer = atom_getboolarg(0,argc,argv);
+ pd_gfsm_automaton_obj_outlet_float
+ (x, sel, (t_float)(x->x_automaton_pd->x_automaton->flags.is_transducer));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: semiring()
+ */
+static void pd_gfsm_automaton_obj_semiring(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ t_symbol *srsym;
+ if (argc > 0) {
+ srsym = atom_getsymbolarg(0,argc,argv);
+ gfsm_automaton_set_semiring_type(x->x_automaton_pd->x_automaton,
+ gfsm_sr_name_to_type(srsym->s_name));
+ }
+ srsym = gensym(gfsm_sr_type_to_name(x->x_automaton_pd->x_automaton->sr->type));
+ pd_gfsm_automaton_obj_outlet_symbol(x, sel, srsym);
+}
+
+/*=====================================================================
+ * automaton_obj: state properties
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: final()
+ */
+static void pd_gfsm_automaton_obj_final(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ gboolean ans = FALSE;
+ t_float qf = atom_getfloatarg(0,argc,argv);
+ if (qf<0) qf = -qf;
+ if (argc > 1) {
+ ans = atom_getboolarg(1,argc,argv);
+ gfsm_automaton_set_final_state(x->x_automaton_pd->x_automaton, (gfsmStateId)qf, ans);
+ } else {
+ ans = gfsm_automaton_is_final_state(x->x_automaton_pd->x_automaton, (gfsmStateId)qf);
+ }
+ pd_gfsm_automaton_obj_outlet_float_2(x, sel, qf, (t_float)ans);
+}
+
+
+/*=====================================================================
+ * automaton_obj: states & arcs
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: add_state()
+ */
+static void pd_gfsm_automaton_obj_add_state(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ gfsmStateId id;
+ if (argc>0) id = (gfsmStateId)atom_getfloatarg(0,argc,argv);
+ else id = gfsmNoState;
+
+ id = gfsm_automaton_ensure_state(x->x_automaton_pd->x_automaton, id);
+ pd_gfsm_automaton_obj_outlet_float(x, sel, (t_float)id);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: add_arc()
+ */
+static void pd_gfsm_automaton_obj_add_arc(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ t_float qsrc=0, qdst=0;
+ t_float clo=0, chi=0;
+ t_float w=0;
+ if (argc < 2) {
+ error("gfsm_automaton: add_arc(): not enough arguments!");
+ return;
+ }
+ switch (argc) {
+ case 5: //-- +from, +to, +lo, +hi, +weight
+ w = atom_getfloat(argv+4);
+ case 4: //-- +from, +to, +lo, +hi, -weight
+ chi = atom_getfloat(argv+3);
+ case 3: //-- +from, +to, +lo, -hi, -weight
+ clo = atom_getfloat(argv+2);
+ case 2: //-- +from, +to, -lo, -hi, -weight
+ default:
+ qdst = atom_getfloat(argv+1);
+ qsrc = atom_getfloat(argv);
+
+ if (qdst<0) qdst = -qdst;
+ if (qsrc<0) qsrc = -qsrc;
+ break;
+ }
+
+ gfsm_automaton_add_arc(x->x_automaton_pd->x_automaton,
+ (gfsmStateId)qsrc,
+ (gfsmStateId)qdst,
+ (gfsmLabelId)clo,
+ (gfsmLabelId)chi,
+ (gfsmWeight)w);
+
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_obj_add_arc(): node(qsrc=%ld).out_degree=%u",
+ qsrc,
+ gfsm_automaton_out_degree(x->x_automaton_pd->x_automaton, qsrc));
+#endif
+
+ //-- output
+ SETFLOAT(x->x_argv , (t_float)qsrc);
+ SETFLOAT(x->x_argv+1, (t_float)qdst);
+ SETFLOAT(x->x_argv+2, (t_float)clo);
+ SETFLOAT(x->x_argv+3, (t_float)chi);
+ SETFLOAT(x->x_argv+4, (t_float)w);
+ outlet_anything(x->x_valout, sel, 5, x->x_argv);
+}
+
+/*=====================================================================
+ * automaton_obj: Text I/O
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: print()
+ */
+static void pd_gfsm_automaton_obj_print(t_pd_gfsm_automaton_obj *x)
+{
+ gfsmError *errp = NULL;
+ gfsmIOHandle *ioh = pd_gfsm_console_handle_new();
+ gfsm_automaton_print_handle(x->x_automaton_pd->x_automaton,
+ ioh, NULL,NULL,NULL, &errp);
+ if (errp) {
+ error("gfsm_automaton: print(): Error: %s\n", errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_console_handle_free(ioh);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("print"));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: load_txt()
+ */
+static void pd_gfsm_automaton_obj_load_txt(t_pd_gfsm_automaton_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_compile_filename(x->x_automaton_pd->x_automaton, s->s_name, &errp);
+ if (errp) {
+ error("gfsm_automaton: load_txt(%s): Error: %s\n", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("load"), s);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: save_txt()
+ */
+static void pd_gfsm_automaton_obj_save_txt(t_pd_gfsm_automaton_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_print_filename(x->x_automaton_pd->x_automaton, s->s_name, &errp);
+ if (errp) {
+ error("gfsm_automaton: save_txt(%s): Error: %s\n", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("save"), s);
+}
+
+
+/*=====================================================================
+ * automaton_obj: Binary I/O
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: load_bin()
+ */
+static void pd_gfsm_automaton_obj_load_bin(t_pd_gfsm_automaton_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_load_bin_filename(x->x_automaton_pd->x_automaton, s->s_name, &errp);
+ if (errp) {
+ error("gfsm_automaton: load_bin(%s): Error: %s\n", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("load_bin"), s);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: save_bin()
+ */
+static void pd_gfsm_automaton_obj_save_bin(t_pd_gfsm_automaton_obj *x, t_symbol *s, t_float zlevel)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_save_bin_filename(x->x_automaton_pd->x_automaton, s->s_name, (int)zlevel, &errp);
+ if (errp) {
+ error("gfsm_automaton: save_bin(%s,%d): Error: %s\n", s->s_name, (int)zlevel, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol_float(x, gensym("save_bin"), s, (int)zlevel);
+}
+
+
+/*=====================================================================
+ * automaton_obj: info
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: info()
+ */
+static void pd_gfsm_automaton_obj_info(t_pd_gfsm_automaton_obj *x)
+{
+ gfsmAutomaton *fsm = x->x_automaton_pd->x_automaton;
+ guint n_eps_i, n_eps_o, n_eps_io;
+
+#define bool2char(b) ((b) ? 'y' : 'n')
+
+ post("-- GFSM Automaton Info --");
+ post("%-24s: %s", "Name", x->x_automaton_pd->x_name->s_name);
+ post("%-24s: %s", "Semiring", gfsm_sr_type_to_name(fsm->sr->type));
+ post("%-24s: %c", "Transducer?", bool2char(gfsm_automaton_is_transducer(fsm)));
+ post("%-24s: %c", "Weighted?", bool2char(gfsm_automaton_is_weighted(fsm)));
+ post("%-24s: %c", "Deterministic?", bool2char(fsm->flags.is_deterministic));
+ post("%-24s: %s", "Sort Mode", gfsm_arc_sortmode_to_name(gfsm_automaton_sortmode(fsm)));
+ if (fsm->root_id == gfsmNoState)
+ post("%-24s: %s", "Initial state", "(none)");
+ else
+ post("%-24s: %u", "Initial state", fsm->root_id);
+ post("%-24s: %u", "# of states", gfsm_automaton_n_states(fsm));
+ post("%-24s: %u", "# of final states", gfsm_automaton_n_final_states(fsm));
+ post("%-24s: %u", "# of arcs", gfsm_automaton_n_arcs_full(fsm, &n_eps_i, &n_eps_o, &n_eps_io));
+ post("%-24s: %u", "# of i/o epsilon arcs", n_eps_io);
+ post("%-24s: %u", "# of input epsilon arcs", n_eps_i);
+ post("%-24s: %u", "# of output epsilon arcs", n_eps_o);
+ post("%-24s: %c", "cyclic?", bool2char(gfsm_automaton_is_cyclic(fsm)));
+ //...
+
+#undef bool2char
+
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("info"));
+}
+
+
+/*=====================================================================
+ * automaton_obj: draw
+ */
+
+/*--------------------------------------------------------------------
+ * automaton_obj: draw_dot()
+ */
+static void pd_gfsm_automaton_obj_draw_dot(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ t_pd_gfsm_alphabet_pd *ialph=NULL, *oalph=NULL, *salph=NULL;
+ t_symbol
+ *filename = atom_getsymbolarg(0,argc,argv),
+ *title = x->x_automaton_pd->x_name,
+ *fontname = NULL;
+ float
+ width=0,
+ height=0,
+ nodesep=0,
+ ranksep=0;
+ int fontsize=0;
+ gboolean
+ portrait=FALSE,
+ vertical=FALSE;
+ gfsmError *errp = NULL;
+ int i;
+
+ for (i=1; i < argc; i++) {
+ t_symbol *opt = atom_getsymbolarg(i,argc,argv);
+
+ //--debug
+ //post("gfsm_automaton: draw_dot: checking option '%s'", opt->s_name);
+
+ if (opt==gensym("ilabels")) {
+ if (ialph) pd_gfsm_alphabet_pd_release(ialph);
+ ialph = pd_gfsm_alphabet_pd_find(atom_getsymbolarg(++i,argc,argv));
+ if (ialph) ialph->x_refcnt++;
+ }
+ else if (opt==gensym("olabels")) {
+ if (oalph) pd_gfsm_alphabet_pd_release(oalph);
+ oalph = pd_gfsm_alphabet_pd_find(atom_getsymbolarg(++i,argc,argv));
+ if (oalph) oalph->x_refcnt++;
+ }
+ else if (opt==gensym("slabels")) {
+ if (salph) pd_gfsm_alphabet_pd_release(salph);
+ salph = pd_gfsm_alphabet_pd_find(atom_getsymbolarg(++i,argc,argv));
+ if (salph) salph->x_refcnt++;
+ }
+ else if (opt==gensym("title")) title = atom_getsymbolarg(++i,argc,argv);
+ else if (opt==gensym("width")) width = atom_getfloatarg(++i,argc,argv);
+ else if (opt==gensym("height")) height = atom_getfloatarg(++i,argc,argv);
+ else if (opt==gensym("fontsize")) fontsize = atom_getintarg(++i,argc,argv);
+ else if (opt==gensym("fontname")) fontname = atom_getsymbolarg(++i,argc,argv);
+ else if (opt==gensym("portrait")) portrait = atom_getboolarg(++i,argc,argv);
+ else if (opt==gensym("vertical")) vertical = atom_getboolarg(++i,argc,argv);
+ else if (opt==gensym("nodesep")) nodesep = atom_getfloatarg(++i,argc,argv);
+ else if (opt==gensym("ranksep")) ranksep = atom_getfloatarg(++i,argc,argv);
+ else {
+ char buf[64];
+ atom_string(argv+i, buf, 64);
+ error("gfsm_automaton: draw_dot: unknown option '%s' ignored", buf);
+ }
+ }
+
+ gfsm_automaton_draw_dot_filename_full(x->x_automaton_pd->x_automaton,
+ filename->s_name,
+ (ialph ? ialph->x_alphabet : NULL),
+ (oalph ? oalph->x_alphabet : NULL),
+ (salph ? salph->x_alphabet : NULL),
+ title->s_name,
+ width,
+ height,
+ fontsize,
+ (fontname ? fontname->s_name : NULL),
+ portrait,
+ vertical,
+ nodesep,
+ ranksep,
+ &errp);
+
+ if (errp) {
+ error("gfsm_automaton: draw_dot(%s): Error: %s\n", filename->s_name, errp->message);
+ g_error_free(errp);
+ }
+
+ //-- cleanup
+ if (ialph) pd_gfsm_alphabet_pd_release(ialph);
+ if (oalph) pd_gfsm_alphabet_pd_release(oalph);
+ if (salph) pd_gfsm_alphabet_pd_release(salph);
+
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("draw_dot"), filename);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: setup()
+ */
+static void pd_gfsm_automaton_obj_setup(void)
+{
+ //-- class
+ pd_gfsm_automaton_obj_class = class_new(gensym("gfsm_automaton"),
+ (t_newmethod)pd_gfsm_automaton_obj_new,
+ (t_method)pd_gfsm_automaton_obj_free,
+ sizeof(t_pd_gfsm_automaton_obj),
+ CLASS_DEFAULT,
+ A_DEFSYM,
+ A_NULL);
+
+ //-- methods: automaton
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_automaton,
+ gensym("automaton"),
+ A_DEFSYM, A_NULL);
+
+ //-- methods: flags
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_root,
+ gensym("root"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_weighted,
+ gensym("weighted"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_transducer,
+ gensym("transducer"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_semiring,
+ gensym("semiring"),
+ A_GIMME, A_NULL);
+
+ //-- methods: size
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_size,
+ gensym("size"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_clear,
+ gensym("clear"),
+ A_NULL);
+
+ //-- methods: state properties
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_final,
+ gensym("final"),
+ A_GIMME, A_NULL);
+
+ //-- methods: states & arcs
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_add_state,
+ gensym("add_state"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_add_arc,
+ gensym("add_arc"),
+ A_GIMME, //-- qsrc,qdst,clo,chi,weight
+ A_NULL);
+
+
+ //-- methods: I/O: text
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_print,
+ gensym("print"),
+ A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_load_txt,
+ gensym("load"),
+ A_SYMBOL, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_save_txt,
+ gensym("save"),
+ A_SYMBOL, A_NULL);
+
+ //-- methods: I/O: binary
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_load_bin,
+ gensym("load_bin"),
+ A_SYMBOL, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_save_bin,
+ gensym("save_bin"),
+ A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ //-- methods: info
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_info,
+ gensym("info"),
+ A_NULL);
+
+ //-- methods: draw
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_draw_dot,
+ gensym("draw_dot"),
+ A_GIMME, A_NULL);
+
+ //-- help symbol
+ class_sethelpsymbol(pd_gfsm_automaton_obj_class, gensym("gfsm_automaton-help.pd"));
+}
+
+
+/*=====================================================================
+ * automaton setup
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton: setup()
+ */
+void pd_gfsm_automaton_setup(void)
+{
+ pd_gfsm_automaton_pd_setup();
+ pd_gfsm_automaton_obj_setup();
+ pd_gfsm_algebra_setup(pd_gfsm_automaton_obj_class);
+}