|
From: Nikita Z. <coo...@ma...> - 2018-03-07 14:41:17
|
Hello. I'm writing gnuplot plugin, which allowes gnuplot to guide qalculate. https://github.com/nick87720z/gnuplot-qalc-plugin I have question about some mean of variadic function arguments or as alternative - generating of gnuplot functions by plugin with arbitrary name/args. And second - about plugin finalization by gnuplot_fini(). However, i have trouble due to lack of any mean to have variadic arguments - neither by itself, not by array argument. I is not problem, to return value with type DATABLOCK. But if i try to use array of values - i get "unsupported array operation" error in both when i create "array arr = [.......]" and try to run some function with it, or when for experiment i tried to return ARRAY, filling it for test with INTGR values. Why i search for variadic arguments: in my plugin are functions - to load function via text formula (takes name and expression str arguments), delete (by name), list (using fictive argument, as gnuplot doesn't allow to create functions with void arguments) and execute functions... this is what i'm about. Exec function actually takes two parameters: - name_or_id (accepts both string and position in list, which should be got for that) - numeric argument. For now, due to disluck, it supports only single arguments. Even without variadic arguments - would be enough to have ability to just generate gnuplot function - so, that if i run (for example): gnuplot> qalc_hyperbola = qalc_ufunc_new('qalc_hyperbola', '1/x') ...it could be called by just (lvalue has only name, without (x,y,etc)). gnuplot> print qalc_hyperbola(4.5) # or gnuplot> plot qalc_hyperbola(x) And another question: example plugin declares gnuplot_init() and gnuplot_fini(), but doesn't define. I copied declaration without change and defined both, but only gnuplot_init() is called automatically. As for fini(), i had to add exported qalc_fini(), which should be run by command before to quit gnuplot. Source file external.c has mention about argument, which gnuplot_init() gets, that it should be freed later. I added it to qalc_fini() - is it right usage? (i remember, i had buch if memory leaks from gnuplot side, might be due to this) |
|
From: sfeam <eam...@gm...> - 2018-03-07 18:40:00
|
On Wednesday, 07 March 2018 19:40:58 Nikita Zlobin via gnuplot-info wrote: > Hello. > I'm writing gnuplot plugin, which allowes gnuplot to guide qalculate. > https://github.com/nick87720z/gnuplot-qalc-plugin > > I have question about some mean of variadic function arguments or as > alternative - generating of gnuplot functions by plugin with arbitrary > name/args. And second - about plugin finalization by gnuplot_fini(). > > However, i have trouble due to lack of any mean to have variadic > arguments - neither by itself, not by array argument. I is not problem, > to return value with type DATABLOCK. But if i try to use array of > values - i get "unsupported array operation" error in both when i > create "array arr = [.......]" and try to run some function with it, or > when for experiment i tried to return ARRAY, filling it for test with > INTGR values. Gnuplot's array data type is relatively new. The only operations currently implemented that take an array argument are the cardinality operator |Array| and the evaluate-an-element operator Array[element]. Rather than teach every piece of the evaluation code about arrays, the current implementation simply refuses to pass an array argument to other operations. This restriction could be relaxed if there is a coherent plan to guide how arrays are handled (see below). It is a good idea to use arrays to pass variadic arguments. I can see how that would be useful for plugin functions even though gnuplot's own code does not need the mechanism. The tricky part is that the internal implementation of expression evaluation uses pass-by-value rather than pass-by-reference. This is impractical for arrays (see long comment in eval.c about ARRAY_COPY_ON_REFERENCE). This limitation means there must be strict limitations on when or if the content of the array may be altered by a function. > Why i search for variadic arguments: in my plugin are functions - to > load function via text formula (takes name and expression str > arguments), delete (by name), list (using fictive argument, as gnuplot > doesn't allow to create functions with void arguments) and execute > functions... this is what i'm about. > > Exec function actually takes two parameters: > - name_or_id (accepts both > string and position in list, which should be got for that) > - numeric argument. If I understand your proposal, for your purpose it might be possible to treat the array contents as immutable. Is that correct? I am not sure how best to enforce that in the code. > For now, due to disluck, it supports only single arguments. Even > without variadic arguments - would be enough to have ability to > just generate gnuplot function - so, that if i run (for example): > gnuplot> qalc_hyperbola = qalc_ufunc_new('qalc_hyperbola', '1/x') > ...it could be called by just (lvalue has only name, without (x,y,etc)). > gnuplot> print qalc_hyperbola(4.5) # or > gnuplot> plot qalc_hyperbola(x) I do not fully understand this part of your description. > And another question: example plugin declares gnuplot_init() and > gnuplot_fini(), but doesn't define. I copied declaration without change > and defined both, but only gnuplot_init() is called automatically. I think those two definitions were included only as examples of how you might declare a plugin function prototype. As you say, the example code does not actually use them. > [snip] Gnuplot's built-in operations do not know what to do with an array argument, but if you want to experiment with passing a single array as a variable argument to your plugin it might be sufficient to change the int_error call in f_call() to int_warn. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/internal.c b/src/internal.c index b77ce4d..8eebc03 100644 --- a/src/internal.c +++ b/src/internal.c @@ -166,7 +166,7 @@ f_call(union argument *x) (void) pop(&(udf->dummy_values[0])); if (udf->dummy_values[0].type == ARRAY) - int_error(NO_CARET, "f_call: unsupported array operation"); + int_warn(NO_CARET, "f_call: unsupported array operation"); if (udf->dummy_num != 1) int_error(NO_CARET, "function %s requires %d variables", udf->udf_name, udf->dummy_num); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Or maybe not. I will experiment a bit. cheers, Ethan |
|
From: Nikita Z. <coo...@ma...> - 2018-03-08 21:22:26
|
Somehow discussion moved out of mailing list. Last time i got email
without any field like to or cc, containing mailing list address. And
replied out of it without carry (it was automatically set _to_ to
sfeam's email).
In Wed, 07 Mar 2018 16:40:45 -0800
sfeam <eam...@gm...> wrote:
> Given the current implementation, it is not possible to return an
> array from an expression. The closest I can see is to pass an array
> in and replace the individual entries. Because it is passed by
> reference, the changes will be visible to the rest of the program.
> Of course you must free any strings or datablocks before your replace
> them.
The biggest trouble is lack of any doc about api, even in headers (that
was heppy to find mention in external.c, that object, passed to
gnuplot_init must be freed, and i did it in fini func, i still don't
get crash due to double free, which would likely happen, be i
misunderstood.
> > Yeah, i thinked deeper about was i wrote - i would express it a bit
> > different: what if same function, exported by plugin, can be
> > imported several times - with different names and arguments number?
> >
> > I was self in doubt before, because had not idea, in what form it
> > may be implemented. In other words, any importable plugin symbol
> > may have several gnuplot-side faces, or aliases, with different
> > name and args amount. This would make variadic arguments even less
> > needed. Plugin-side code should get different argn parameter,
> > depending on used face.
>
> Yes, I think that is possible without changing the current code.
I already discovered it :) One thing, that caused me to check it - that
when i repeated import command with same arguments, it did not complain.
I guess, this feature would be even more convenient for cases, when
plugin has one API-level function, which serves to call dynamically
defined functions, taking name and arguments, but with one note:
For now this has to be implemented by following sequence (example):
> import plugin_func_exec_1a(f_id, a1) from "plugin:func_exec"
> import plugin_func_exec_2a(f_id, a1, a2) from "plugin:func_exec"
> import plugun_func_exec_3a(f_id, a1, a2, a3) from "plugin:func_exec"
> r = plugin_func_add('f1', '1/x')
> r = plugin_func_add('f2', 'x^2 / sin(y)')
> r = plugin_func_add('f3', 'expr1')
> plugin_f1(x) = plugin_func_exec1a('f1', x)
> plugin_f2(x,y) = plugin_func_exec2a('f2', x, y)
> plugin_f3(x,y,z) = plugin_func_exec3a('f3', x, y, z)
or for simplicity
> plugin_f4(x) = plugin_func_exec3a('f4', x, 0, 0)
(I omit essential calls to load definitions to plugin, lets guess it is
done)
Here each dynamic function, defined in gnuplot, needs backend func,
which will pass f_id to plugin. The later case, with 'f4', will pass
more args, than function needs, though it doesn't look critical… better
more than less. But another technical issue, is that there are 2
virtual calls before real one.
However there might be another approach, with just 1 virtual call:
> import plugin_f1(='f1', x) from "plugin2:func_exec"
> import plugin_f2(='f2', x,y) from "plugin2:func_exec"
> import plugin_f3(='f3', x, =3.28, y, =0, =V) from "plugin2:func_exec"
(all numbers are from inhead /dev/random)
This variant relies on default value substitution. These virtuals will
call real aggregator with 2, 3 and 6 arguments respectively (and plugin
will get respective argn), but interface for gnuplot cli interface side
will be: plugin_f1(x), plugin_f2(x,y) and plugin_f3(x,y).
Only one virtual calls, yet with some positions prefilled. Substitution
of middle arguments, as in 3rd, would allow to define more
specific virtuals for one plugin-side virtual... it is hard for me to
guess all possible cases, where this particular feature (in 3rd case)
mey be useful. One thing, that only visited my head, is for 3d
function, when first function drawes surface with all arguments, and
second has some argument static, for example to draw slice, which will
be visible with another color (some case, when give them feature, and
they will find use for it). By preceding defaults with '=' it is
possible to use variables as values, not as placeholders.
> Here is a more polished version of the patch.
> It allows an array to be passed, but only if it is being passed
> as the sole argument to an external function (i.e. a plugin).
> I've tested this a bit.
> Please let my know if it is useful for your work.
> It can probably be added to the gnuplot development version
> if it is useful for a real-world application.
>
> Ethan
>
Due to above, i don't know, what approach is better... another
unclearance, due to lack of api doc - how value array defines its end?
Whilc for datasetarray it is NULL-terminated pointers array, for array
of struct value's it would be something else. Is it INVALID_VALUE
|
|
From: Ethan A M. <eam...@gm...> - 2018-03-09 04:23:13
|
On Friday, 09 March 2018 02:22:10 Nikita Zlobin via gnuplot-info wrote:
> Somehow discussion moved out of mailing list. Last time i got email
> without any field like to or cc, containing mailing list address. And
> replied out of it without carry (it was automatically set _to_ to
> sfeam's email).
>
> In Wed, 07 Mar 2018 16:40:45 -0800
> sfeam <eam...@gm...> wrote:
> > Given the current implementation, it is not possible to return an
> > array from an expression. The closest I can see is to pass an array
> > in and replace the individual entries. Because it is passed by
> > reference, the changes will be visible to the rest of the program.
> > Of course you must free any strings or datablocks before your replace
> > them.
> The biggest trouble is lack of any doc about api, even in headers (that
> was heppy to find mention in external.c, that object, passed to
> gnuplot_init must be freed, and i did it in fini func, i still don't
> get crash due to double free, which would likely happen, be i
> misunderstood.
I sympathize with the lack of documentation. There is never enough :-)
Up until now the primary use of the plugin mechanism was to allow
gnuplot to call into existing 3rd-party math libraries.
It's great that you are interested in doing something entirely different,
but so far as I know you are the first person to try it.
So you get to be the guinea pig. Also there isn't much of documentation
on how to do it because, well, you are the first to try it.
Your suggestions and questions have already been useful.
For example the project probably should put more thought into
what headers, example source files, documentation, or additional tools
might go into a "developer's package". Where a particular distribution
might choose to install these is another question, but that's for them
to decide.
> due to lack of api doc - how value array defines its end?
> Whilc for datasetarray it is NULL-terminated pointers array, for array
> of struct value's it would be something else. Is it INVALID_VALUE?
Each user variable is described by a structure (eval.h)
/* user-defined variable table entry */
typedef struct udvt_entry {
struct udvt_entry *next_udv; /* pointer to next value in linked list */
char *udv_name; /* name of this value entry */
t_value udv_value; /* value it has */
} udvt_entry;
This structure holds the variable's name and its current value.
The value is held in a structure (gp_types.h)
typedef struct value {
enum DATA_TYPES type;
union {
intgr_t int_val;
struct cmplx cmplx_val;
char *string_val;
char **data_array;
struct value *value_array;
} v;
} t_value;
In the case of an array variable
type = ARRAY
value_array[0].int_val = size_of_array
and
value_array is allocated to hold (size_of_array + 1) values,
each of which may be INTGR, CMPLX, or STRING
Ethan
|