|
From: <mw...@gm...> - 2011-01-12 15:50:08
|
Hi,
> Ethan Merritt <merritt@u.washington.edu> wrote:
> On Tuesday, January 11, 2011 12:37:42 pm mw...@gm... wrote:
>>> Ethan Merritt <merritt@u.washington.edu> wrote:
>>> On Tuesday, January 11, 2011 09:00:19 am mw...@gm... wrote:
>>>> Hi,
>>>>
>>>> I want to add finite summation to gnuplot, that is a function sum(a, b,
>>>> x, f), where a, b (int) are the summation boundary, x (double) is a
>>>> varialbe, f (string) is the name of the function to eveluate a term.
>>>> Example usage:
>>>>
>>>> f(n, x) = sin(n*x)
>>>> plot sum(1, 10, x, "f")
>>>
>>> That pair of commands does not seem to be compatible with your
>>> description. How is the code to know there is a second parameter to
>>> f()? And where would it get this second parameter from?
>>
>> sum requires its 4-th parameter to be the name of a 2 parametric
>> function. Before the call to f in sum, two values are pushed. I think I
>> missed the point of what you were trying to tell me.
>
> I guess I don't understand what you are trying to do.
>
> (1) I thought f was a string parameter passed to f_sum, containing the
> name of a user-defined function. But your code never pops it as a parameter
> and instead refers to it as a string constant "f". That may be just for
> debugging but it contradicts your definition of the sum() function so I'm
> not sure.
>
> (2) I still don't understand what is "n", or why you want to pass a second
> parameter to f.
> Are you thinking that you want an infinite class of functions f_n(x)?
> That would take a lot of work to support.
>
>> With your generous help I was able to get stuck a little bit later. I
> assume its related to your initial comment about the parameters of f. I
> thought, that I have to push two values (int n, cmplx x) onto the stack and
> then execute_at(..). I could verify (by calling pop()/more_on_stack()
> repediatly) that execute_at(..) doesn't pop values from the stack. In fact I
> believe that initially the stack containes two values (n, x) and then
> execute_at(..) adds another. Did I do it wrong? How can I pass n, x to the
> function if > not by pushing them?
>
> You either have to duplicate the relevant parts of f_calln(),
> or else you have to set up all the bookkeeping variables needed by
> f_calln() and call f_calln() itself to do the work.
Thank you again for pointing me into the right direction. I didn't realize
fast enought that I haven't explained enough, what I try to do, so let me
explain. I have implemented sum(a, b, "f") and sum(a, b, x, "g") in order to calculate finite sums:
# calculate a finite sum
f(n) = n
print sum(1, 10, "f") # -> 55
# calculate a finite sum with parameter x
# fourier coefficients of some square wave
fourier(k, x) = sin(3./2*k)/k * 2./3*cos(k*x)
s(x) = 1./2 + sumx(1, 100, x, "fourier")
plot s(x)
I hope this is sufficient to understand why I want a parameter x (so one can plot some square waves and other things.) As Mr. Bröker pointed out, there is a trick involving the tertinary operator '?' and recursion to sorta workaround. Originally I tried to plot the sum with '?' but I could only do so for 1..10, in case of 1..100 it said something about stack overflow.
I have added below a working patch but would like you to have a look at it. I have some things that are not clear to me, in particular:
* Do I have to free the values that I have gotten using pop?
* In what order do I have to push i and x befor the call to f(i, x). I thought that I have to push them from right to left but that seems to contradicts my testing, now I am very unsure about it (even though it seems to work correctly).
* Do I have to alloc memeory for the values I push on the stack befor the call to f(.)?
* This is only curiosity is arg in foo(union argument *arg) every used and if, what for?
I would also like you to take a look at my addition to gnuplot.doc and proofread it.
Finally it would be nice but not necessary if the function could be passed as 'f' instead of '"f", that is sum(1, 10, f), and even better as sum(n=[1:10], n) but I consider this as optional and very hard to do (at least with my knowledge).
Thank you again for your generous help without I would never have gone so far.
Thank you,
Micha Wiedenmann
--- eval.c.orig 2011-01-11 17:38:00.000000000 +0100
+++ eval.c 2011-01-12 16:19:05.000000000 +0100
@@ -176,6 +176,9 @@
{"atanh", f_atanh},
{"lambertw", f_lambertw}, /* HBB, from G.Kuhnle 20001107 */
+ {"sum", f_sum}, /* summation sum(a, b, "f") = \sum_{i=a}^b f(i) */
+ {"sumx", f_sumx}, /* summation sum(a, b, x, "f") = \sum_{i=a}^b f(i, x) (with parameter x) */
+
{"column", f_column}, /* for using */
{"valid", f_valid}, /* for using */
{"timecolumn", f_timecolumn}, /* for using */
@@ -689,6 +692,20 @@
return (*udv_ptr);
}
+struct udft_entry *
+get_udf_by_name(char *key)
+{
+ struct udft_entry *udf_ptr = first_udf;
+
+ while (udf_ptr) {
+ if (!strcmp(key, udf_ptr->udf_name))
+ return udf_ptr;
+
+ udf_ptr = udf_ptr->next_udf;
+ }
+
+ return NULL;
+}
static void update_plot_bounds __PROTO((void));
static void fill_gpval_axis __PROTO((AXIS_INDEX axis));
--- eval.h.orig 2011-01-11 17:38:21.000000000 +0100
+++ eval.h 2011-01-12 15:54:30.000000000 +0100
@@ -164,6 +164,7 @@
void apollo_pfm_catch __PROTO((void));
#endif
struct udvt_entry * add_udv_by_name __PROTO((char *key));
+struct udft_entry * get_udf_by_name __PROTO((char *key));
/* update GPVAL_ variables available to user */
void update_gpval_variables __PROTO((int from_plot_command));
--- specfun.c.orig 2011-01-11 17:37:27.000000000 +0100
+++ specfun.c 2011-01-12 16:14:28.000000000 +0100
@@ -49,6 +49,7 @@
#include "specfun.h"
#include "stdfn.h"
#include "util.h"
+#include "internal.h"
#define ITMAX 200
@@ -1933,3 +1934,130 @@
push(Gcomplex(&a, x, 0.0));
}
+/* Finite summation
+ *
+ * Calculate the finite sum(a, b, "f") = \sum_{i=a}^b f(i), where "f" is the
+ * name (a string) of f(i), a function taking one (integer) parameter i.
+ */
+void
+f_sum(union argument *arg)
+{
+ struct value tmp;
+ int a, b; // bounds [a, b]
+ struct cmplx ret;
+ int i;
+ struct udft_entry *udf;
+ union argument call_arg;
+
+ (void) arg; /* avoid -Wunused warning */
+
+ // pop function name
+ if (pop(&tmp)->type != STRING)
+ int_error(NO_CARET, "expecting a name of a function with 1 parameters as 3rd argument to sum");
+ if (!(udf = get_udf_by_name(tmp.v.string_val)))
+ int_error(NO_CARET, "No user-defined function %s", tmp.v.string_val);
+
+ // pop upper bound (b)
+ if (pop(&tmp)->type != INTGR)
+ int_warn(NO_CARET, "expecting an integer as 2nd argument to sum");
+ b = tmp.v.int_val;
+
+ // pop lower bound (a)
+ if (pop(&tmp)->type != INTGR)
+ int_warn(NO_CARET, "expecting an integer as 1st argument to sum");
+ a = tmp.v.int_val;
+
+ ret.real = 0;
+ ret.imag = 0;
+ for (i=a; i<=b; ++i) {
+
+ /* calculate f_i = f(i); */
+
+ push(Ginteger(&tmp, i));
+
+ call_arg.udf_arg = udf;
+ f_call(&call_arg);
+
+ pop(&tmp);
+ ret.real += real(&tmp);
+ ret.imag += imag(&tmp);
+ }
+
+ push(Gcomplex(&tmp, ret.real, ret.imag));
+
+}
+
+/* Finite summation (with free parameter x)
+ *
+ * Calculate the finite sum(a, b, x, "f") = \sum_{i=a}^b f(i, x), where "f" is the
+ * name (a string) of f(i, x), a function taking two parameters i (integer) and x
+ * (complex). Example usage:
+ *
+ * # fourier coefficients of some square wave
+ * fourier(k, x) = sin(3./2*k)/k * 2./3*cos(k*x)
+ * s(x) = 1./2 + sum(1, 10, x, "fourier")
+ * plot s(x)
+ */
+void
+f_sumx(union argument *arg)
+{
+ struct value tmp;
+ int a, b; // bounds [a, b]
+ struct cmplx x, ret;
+ int i;
+ udft_entry *udf;
+ union argument calln_arg;
+
+ // XXX is arg every used in any other function if so, what is it used for?
+ (void) arg; /* avoid -Wunused warning */
+
+ // XXX do I have to free the poped values?
+ // pop function name
+ if (pop(&tmp)->type != STRING)
+ int_error(NO_CARET, "expecting a name of a function with 2 parameters as 4th argument to sum");
+ if (!(udf = get_udf_by_name(tmp.v.string_val)))
+ int_error(NO_CARET, "No user-defined function %s", tmp.v.string_val);
+
+ // pop x
+ pop(&tmp);
+ x.real = real(&tmp);
+ x.imag = imag(&tmp);
+
+ // pop upper bound (b)
+ if (pop(&tmp)->type != INTGR)
+ int_warn(NO_CARET, "expecting an integer as 2nd argument to sum");
+ b = tmp.v.int_val;
+
+ // pop lower bound (a)
+ if (pop(&tmp)->type != INTGR)
+ int_warn(NO_CARET, "expecting an integer as 1st argument to sum");
+ a = tmp.v.int_val;
+
+ ret.real = 0;
+ ret.imag = 0;
+ for (i=a; i<=b; ++i) {
+
+ /* calculate f_i(x) = f(i, x); */
+
+ /* XXX in what order do I have to push?
+ * I thought that I would have to push from right to left but my
+ * testing contradicts that finding. I am very unsure about the order
+ * and need to understand this
+ */
+ // XXX do I have to malloc instead of pushing a temporary?
+ push(Ginteger(&tmp, i));
+ push(Gcomplex(&tmp, x.real, x.imag));
+ push(Ginteger(&tmp, 2)); // push argument count
+
+ calln_arg.udf_arg = udf;
+ f_calln(&calln_arg);
+
+ pop(&tmp);
+ ret.real += real(&tmp);
+ ret.imag += imag(&tmp);
+ }
+
+ push(Gcomplex(&tmp, ret.real, ret.imag));
+
+}
+
--- specfun.h.orig 2011-01-11 17:37:21.000000000 +0100
+++ specfun.h 2011-01-12 15:36:01.000000000 +0100
@@ -61,4 +61,7 @@
void f_inverse_erf __PROTO((union argument *x));
void f_lambertw __PROTO((union argument *x));
+void f_sum __PROTO((union argument *x));
+void f_sumx __PROTO((union argument *x));
+
#endif /* GNUPLOT_SPECFUN_H */
--- ../docs/gnuplot.doc.orig 2011-01-12 15:09:42.000000000 +0100
+++ ../docs/gnuplot.doc 2011-01-12 16:22:47.000000000 +0100
@@ -1091,6 +1091,30 @@
%sinh(x)@any@$sinh~x$, hyperbolic sine of $x$ in radians
The `sinh(x)` function returns the hyperbolic sine of its argument. `sinh`
expects its argument to be in radians.
+4 sum
+?expressions functions sum
+?functions sum
+?sum
+#sum(a, b, "f") & any & $\sum_{i=a}^b f(i)$, finite sum \\
+%sum(a, b, "f")@any@$sum(i=a..b, f(i)$, finite sum
+ The `sum(a, b, "f")` function calculates the finite sum \sum_{i=a}^b f(i),
+ where "f" is the name (a string) of f(i), a function taking one (integer)
+ parameter i. For example, `f(n)=n; print sum(1, 10, "f")` prints 55.
+4 sumx
+?expressions functions sumx
+?functions sumx
+?sumx
+#sumx(a, b, x, "f") & any & $\sum_{i=a}^b f(i, x)$, finite sum (with parameter $x$)\\
+%sumx(a, b, x, "f")@any@$sumx(i=a..b, f(i, x)$, finite sum (with parameter $x$)
+ The `sumx(a, b, x, "f")` function calculates the finite sum
+ \sum_{i=a}^b f(i, x), where "f" is the name (a string) of f(i, x), a function
+ taking two parameters i (integer) and x (complex).
+
+ Example:
+ # fourier coefficients of some square wave
+ fourier(k, x) = sin(3./2*k)/k * 2./3*cos(k*x)
+ s(x) = 1./2 + sumx(1, 10, x, "fourier")
+ plot s(x)
4 sqrt
?expressions functions sqrt
?functions sqrt
--
NEU: FreePhone - kostenlos mobil telefonieren und surfen!
Jetzt informieren: http://www.gmx.net/de/go/freephone
|