[genius] Thu Jul 23 18:35:28 2009 Jiri (George) Lebl <jirka 5z com>



commit 094e9ebf94ad32dbf63c773386d45758c5182aa9
Author: Jiri (George) Lebl <jirka 5z com>
Date:   Thu Jul 23 18:36:57 2009 -0500

    Thu Jul 23 18:35:28 2009  Jiri (George) Lebl <jirka 5z com>
    
    	* src/parse.y, src/eval.c, src/dict.c, src/structs.h: Add an optional
    	  list of extra_dict parameters to function definition.  In this
    	  case the subst dance never happens and those variables are added to
    	  extra dict at function definition time.
    
    	* lib/*/*.gel: Use local where appropriate and the [] extra dict
    	  definition where appropriate
    
    	* src/testscope.gel, src/geniustests.txt: update test suite
    
    	* src/geniustest.pl: fix colors

 ChangeLog                          |   14 +++++++
 NEWS                               |    4 ++
 lib/calculus/differentiation.gel   |    9 ++++
 lib/calculus/fourier.gel           |   52 +++++++++++++-------------
 lib/calculus/integration.gel       |    4 +-
 lib/calculus/limits.gel            |    9 +++-
 lib/calculus/sums_products.gel     |    4 ++
 lib/equation_solving/diffeqs.gel   |    2 +
 lib/equation_solving/find_root.gel |    4 ++
 lib/library-strings.c              |   16 ++++----
 lib/linear_algebra/misc.gel        |    3 +
 lib/misc/misc.gel                  |    3 +-
 lib/symbolic/differentiation.gel   |    3 +
 src/eval.c                         |   60 ++++++++++++++++++++++++++---
 src/geniustest.pl                  |    4 +-
 src/geniustests.txt                |    3 +
 src/parse.y                        |   63 +++++++++++++++++++++++++++++--
 src/parseutil.c                    |   73 ++++++++++++++++++++++++++----------
 src/parseutil.h                    |    5 ++-
 src/structs.h                      |    4 ++
 src/testscope.gel                  |   17 ++++++++
 21 files changed, 285 insertions(+), 71 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 5fc2172..94093c8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Thu Jul 23 18:35:28 2009  Jiri (George) Lebl <jirka 5z com>
+
+	* src/parse.y, src/eval.c, src/dict.c, src/structs.h: Add an optional
+	  list of extra_dict parameters to function definition.  In this
+	  case the subst dance never happens and those variables are added to
+	  extra dict at function definition time.
+
+	* lib/*/*.gel: Use local where appropriate and the [] extra dict
+	  definition where appropriate
+
+	* src/testscope.gel, src/geniustests.txt: update test suite
+
+	* src/geniustest.pl: fix colors
+
 Thu Jul 23 16:28:59 2009  Jiri (George) Lebl <jirka 5z com>
 
 	* src/dict.c, src/eval.c: remove some forgotten debug prints
diff --git a/NEWS b/NEWS
index d2581e1..1c3f825 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Changes to 1.0.7
+
+FIXME
+
 Changes to 1.0.6
 
 * Draw grid and x/y axis on lineplots in gray, much better readability
diff --git a/lib/calculus/differentiation.gel b/lib/calculus/differentiation.gel
index 37730f3..10b934f 100644
--- a/lib/calculus/differentiation.gel
+++ b/lib/calculus/differentiation.gel
@@ -30,6 +30,7 @@
 function OneSidedThreePointFormula(f,x0,h) =
 # This has error term max(f''')h^2/3
 	(
+	local *;
 # check arguments
 ## check types
 	if not IsFunctionOrIdentifier(f) then
@@ -49,6 +50,7 @@ SetHelp("OneSidedThreePointFormula","calculus","Compute one-sided derivative usi
 function TwoSidedThreePointFormula(f,x0,h) =
 # This has error term max(f''')h^2/6
 	(
+	local *;
 # check arguments
 ## check types
 	if not IsFunctionOrIdentifier(f) then
@@ -67,6 +69,7 @@ SetHelp("TwoSidedThreePointFormula","calculus","Compute two-sided derivative usi
 function OneSidedFivePointFormula(f,x0,h) =
 # This has error term max(f''''')h^4/5
 	(
+	local *;
 # check arguments
 ## check types
 	if not IsFunctionOrIdentifier(f) then
@@ -85,6 +88,7 @@ SetHelp("OneSidedFivePointFormula","calculus","Compute one-sided derivative usin
 function TwoSidedFivePointFormula(f,x0,h) =
 # This has error term max(f''''')h^4/30
 	(
+	local *;
 # check arguments
 ## check types
 	if(not IsFunctionOrIdentifier(f)) then
@@ -109,6 +113,7 @@ parameter DerivativeNumberOfTries=100;
 # Simple test for differentiability
 function IsDifferentiable(f,x0) =
 (
+	local *;
 	# differentiable functions have to be continuous and left and right derivatives must
 	# be equal
 	IsContinuous (f, x0) and
@@ -121,6 +126,7 @@ SetHelp("IsDifferentiable","calculus","Test for differentiability by approximati
 function NumericalDerivative(f,x0) =
 # returns f'(x0)
 (
+    local *;
     # FIXME: perhaps check differentiability first, but then we're doing so many limits already
     NumericalLimitAtInfinity (`(n)=(TwoSidedFivePointFormula(f,x0,2.0^(-n))),
 			      Identity,
@@ -134,6 +140,7 @@ NDerivative = NumericalDerivative
 
 function NumericalLeftDerivative(f,x0) =
 (
+    local *;
     NumericalLimitAtInfinity (`(n)=(OneSidedFivePointFormula(f,x0,-(2.0^(-n)))),
 			      Identity,
 			      DerivativeTolerance,
@@ -144,6 +151,7 @@ SetHelp("NumericalLeftDerivative","calculus","Attempt to calculate numerical lef
 
 function NumericalRightDerivative(f,x0) =
 (
+    local *;
     NumericalLimitAtInfinity (`(n)=(OneSidedFivePointFormula(f,x0,2.0^(-n))),
 			      Identity,
 			      DerivativeTolerance,
@@ -154,6 +162,7 @@ SetHelp("NumericalRightDerivative","calculus","Attempt to calculate numerical ri
 
 function Derivative(f,x0) =
 (
+	local *;
 	df = SymbolicDerivativeTry (f);
 	if IsNull(df) then
 		NumericalDerivative (f, x0)
diff --git a/lib/calculus/fourier.gel b/lib/calculus/fourier.gel
index f65a15f..c15a3aa 100644
--- a/lib/calculus/fourier.gel
+++ b/lib/calculus/fourier.gel
@@ -2,6 +2,7 @@
 # 
 function NumericalFourierSeriesFunction(f,L,N) =
 	(
+	local *;
 # check arguments
 	if not IsFunctionOrIdentifier(f) then
 		(error("NumericalFourierSeriesFunction: argument f must be a function");bailout)
@@ -14,7 +15,7 @@ function NumericalFourierSeriesFunction(f,L,N) =
 
 	FourierSeriesFunction(c@(1),c@(2),L)
 )
-SetHelp("NumericalFourierSeriesFunction","calculus","FIXME");
+SetHelp("NumericalFourierSeriesFunction","calculus","Return a function which is the fourier series of f with half-period L with coefficients up to N computed numerically");
 
 function FourierSeriesFunction(a,b,L) =
 	(
@@ -24,7 +25,7 @@ function FourierSeriesFunction(a,b,L) =
 	else if not (IsReal(L) and L > 0) then
 		(error("FourierSeriesFunction: argument L must be a positive real value");bailout);
 
-	`(x) = (
+	`(x)[a,b,L] = (
 		if not IsNull(a) then (
 			val = a@(1)/2 + sum n = 2 to elements(a) do
 				a@(n) * cos(x*(n-1)*pi/L)
@@ -40,10 +41,11 @@ function FourierSeriesFunction(a,b,L) =
 		val
 	)
 )
-SetHelp("FourierSeries","calculus","FIXME");
+SetHelp("FourierSeriesFunction","calculus","Return a function which is a Fourier series with the coefficients given by the vectors a (sines) and b (cosines).  Note that a@(1) is the constant coefficient!");
 
 function NumericalFourierSeriesCoefficients(f,L,N) =
 	(
+	local *;
 # check arguments
 	if not IsFunctionOrIdentifier(f) then
 		(error("NumericalFourierSeriesCoefficients: argument f must be a function");bailout)
@@ -56,18 +58,17 @@ function NumericalFourierSeriesCoefficients(f,L,N) =
 	b = .;
 
 	a@(1) = (1/L)*NumericalIntegral(f,-L,L);
-	__fs_L = L;
-	__fs_f = f;
-	for __fs_n = 1 to N do (
-		a@(__fs_n+1) = (1/L)*NumericalIntegral(`(x)=((__fs_f call (x))*cos(x*__fs_n*pi/__fs_L)),-L,L);
-		b@(__fs_n) = (1/L)*NumericalIntegral(`(x)=((__fs_f call (x))*sin(x*__fs_n*pi/__fs_L)),-L,L)
+	for n = 1 to N do (
+		a@(n+1) = (1/L)*NumericalIntegral(`(x)[f,L,n]=(local *;(f call (x))*cos(x*n*pi/L)),-L,L);
+		b@(n) = (1/L)*NumericalIntegral(`(x)[f,L,n]=(local *;(f call (x))*sin(x*n*pi/L)),-L,L)
 	);
 	`[a,b]
 )
-SetHelp("NumericalFourierSeriesCoefficients","calculus","FIXME");
+SetHelp("NumericalFourierSeriesCoefficients","calculus","Numerically compute the coefficients for a Fourier series with half-period L up to the Nth coefficient.");
 
 function NumericalFourierSineSeriesCoefficients(f,L,N) =
 	(
+	local *;
 # check arguments
 	if not IsFunctionOrIdentifier(f) then
 		(error("NumericalFourierSineSeriesCoefficients: argument f must be a function");bailout)
@@ -78,17 +79,16 @@ function NumericalFourierSineSeriesCoefficients(f,L,N) =
 
 	b = .;
 
-	__fs_L = L;
-	__fs_f = f;
-	for __fs_n = 1 to N do (
-		b@(__fs_n) = (2/L)*NumericalIntegral(`(x)=((__fs_f call (x))*sin(x*__fs_n*pi/__fs_L)),0,L)
+	for n = 1 to N do (
+		b@(n) = (2/L)*NumericalIntegral(`(x)[f,L,n]=(local *;(f call (x))*sin(x*n*pi/L)),0,L)
 	);
 	b
 )
-SetHelp("NumericalFourierSineSeriesCoefficients","calculus","FIXME");
+SetHelp("NumericalFourierSineSeriesCoefficients","calculus","Numerically compute the coefficients for a sine Fourier series for a function on [0,L] up to the Nth coefficient.");
 
 function NumericalFourierCosineSeriesCoefficients(f,L,N) =
 	(
+	local *;
 # check arguments
 	if not IsFunctionOrIdentifier(f) then
 		(error("NumericalFourierCosineSeriesCoefficients: argument f must be a function");bailout)
@@ -99,16 +99,13 @@ function NumericalFourierCosineSeriesCoefficients(f,L,N) =
 
 	a = .;
 
-	__fs_L = L;
-	__fs_f = f;
-
 	a@(1) = (1/L)*NumericalIntegral(f,-L,L);
-	for __fs_n = 1 to N do (
-		a@(__fs_n+1) = (1/L)*NumericalIntegral(`(x)=((__fs_f call (x))*cos(x*__fs_n*pi/__fs_L)),-L,L)
+	for n = 1 to N do (
+		a@(n+1) = (1/L)*NumericalIntegral(`(x)[f,L,n]=(local *;(f call (x))*cos(x*n*pi/L)),-L,L)
 	);
 	a
 )
-SetHelp("NumericalFourierCosineSeriesCoefficients","calculus","FIXME");
+SetHelp("NumericalFourierCosineSeriesCoefficients","calculus","Numerically compute the coefficients for a cosine Fourier series for a function on [0,L] up to the Nth coefficient.");
 
 function PeriodicExtension(f,a,b) =
 (
@@ -118,14 +115,15 @@ function PeriodicExtension(f,a,b) =
 	else if not (IsReal(a) and IsReal(b) and b > a) then
 		(error("PeriodicExtension: arguments a, b must be a real, b > a");bailout);
 
-	`(x) = (
+	`(x)[f,a,b] = (
+		local *;
 		#This is pretty stupid, but simplest way to do this
 		while x > b do x = x-(b-a);
 		while x < a do x = x+(b-a);
 		(f call (x))
 	)
 )
-SetHelp("PeriodicExtension","calculus","FIXME");
+SetHelp("PeriodicExtension","calculus","Return a function which is the periodic extension of f defined on the interval [a,b]");
 
 function EvenPeriodicExtension(f,L) =
 	(
@@ -135,7 +133,8 @@ function EvenPeriodicExtension(f,L) =
 	else if not (IsReal(L) and L > 0) then
 		(error("EvenPeriodicExtension: argument L must be a positive real value");bailout);
 
-	`(x) = (
+	`(x)[f,L] = (
+		local *;
 		#This is pretty stupid, but simplest way to do this
 		while x > L do x = x-2*L;
 		while x < -L do x = x+2*L;
@@ -143,7 +142,7 @@ function EvenPeriodicExtension(f,L) =
 		if x >= 0 then (f call (x)) else (f call (-x))
 	)
 )
-SetHelp("EvenPeriodicExtension","calculus","FIXME");
+SetHelp("EvenPeriodicExtension","calculus","Return a function which is the even periodic extension of f defined on the interval [0,L]");
 
 function OddPeriodicExtension(f,L) =
 (
@@ -153,7 +152,8 @@ function OddPeriodicExtension(f,L) =
 	else if not (IsReal(L) and L > 0) then
 		(error("OddPeriodicExtension: argument L must be a positive real value");bailout);
 
-	`(x) = (
+	`(x)[f,L] = (
+		local *;
 		#This is pretty stupid, but simplest way to do this
 		while x > L do x = x-2*L;
 		while x < -L do x = x+2*L;
@@ -161,4 +161,4 @@ function OddPeriodicExtension(f,L) =
 		if x >= 0 then (f call (x)) else -(f call (-x))
 	)
 )
-SetHelp("OddPeriodicExtension","calculus","FIXME");
+SetHelp("OddPeriodicExtension","calculus","Return a function which is the odd periodic extension of f defined on the interval [0,L]");
diff --git a/lib/calculus/integration.gel b/lib/calculus/integration.gel
index abcc489..39cf3e6 100644
--- a/lib/calculus/integration.gel
+++ b/lib/calculus/integration.gel
@@ -26,6 +26,7 @@
 SetHelp ("CompositeSimpsonsRuleTolerance", "calculus", "Integration of f by Composite Simpson's Rule on the interval [a,b] with the number of steps calculated by the fourth derivative bound and the desired tolerance")
 function CompositeSimpsonsRuleTolerance(f,a,b,FourthDerivativeBound,Tolerance) =
 (
+	local *;
 	# Error term = max(f'''')*h^4*(b-a)/180,
 	# where h=(b-a)/n
 	n = ceil(|FourthDerivativeBound*(b-a)^5 / (180*Tolerance)|^(1/4));
@@ -41,6 +42,7 @@ function CompositeSimpsonsRuleTolerance(f,a,b,FourthDerivativeBound,Tolerance) =
 SetHelp ("MidpointRule", "calculus", "Integration by midpoint rule")
 function MidpointRule(f,a,b,n) =
 (
+  local *;
   if(not IsFunction(f)) then
 	(error("MidpointRule: argument 1 must be a function");bailout)
   else if(not IsReal(a) or not IsReal(b)) then
@@ -63,4 +65,4 @@ SetHelp ("NumericalIntegralFunction", "parameters", "The function used for numer
 parameter NumericalIntegralFunction = `CompositeSimpsonsRule
 
 SetHelp ("NumericalIntegral", "calculus", "Integration by rule set in NumericalIntegralFunction of f from a to b using NumericalIntegralSteps steps")
-function NumericalIntegral(f,a,b) = (NumericalIntegralFunction call (f,a,b,NumericalIntegralSteps))
+function NumericalIntegral(f,a,b) = (local *;NumericalIntegralFunction call (f,a,b,NumericalIntegralSteps))
diff --git a/lib/calculus/limits.gel b/lib/calculus/limits.gel
index 899d024..9f717bc 100644
--- a/lib/calculus/limits.gel
+++ b/lib/calculus/limits.gel
@@ -29,6 +29,7 @@ function NumericalLimitAtInfinity(_f,step_fun,tolerance,successive_for_success,N
 #FIXME: should have a way of dealing with +infinity, -infinity, and
 # bounded oscillation (like sin(x))
 (
+    local *;
     current_limit = _f(step_fun(1));
     number_of_consecutive_differences_within_tolerance = 0;
     for i = 2 to N do (
@@ -62,8 +63,9 @@ parameter ContinuousNumberOfTries=100;
 SetHelp ("LeftLimit", "calculus", "Calculate the left limit of a real-valued function at x0")
 function LeftLimit(f,x0) =
 (
+	local *;
 	NumericalLimitAtInfinity (f,
-				  `(n)=(x0-2.0^(-n)),
+				  `(n)[x0]=(x0-2.0^(-n)),
 				  ContinuousTolerance,
 				  ContinuousSFS,
 				  ContinuousNumberOfTries)
@@ -72,8 +74,9 @@ function LeftLimit(f,x0) =
 SetHelp ("RightLimit", "calculus", "Calculate the right limit of a real-valued function at x0")
 function RightLimit(f,x0) =
 (
+	local *;
 	NumericalLimitAtInfinity (f,
-				  `(n)=(x0+2.0^(-n)),
+				  `(n)[x0]=(x0+2.0^(-n)),
 				  ContinuousTolerance,
 				  ContinuousSFS,
 				  ContinuousNumberOfTries)
@@ -82,6 +85,7 @@ function RightLimit(f,x0) =
 SetHelp ("Limit", "calculus", "Calculate the limit of a real-valued function at x0.  Tries to calculate both left and right limits.")
 function Limit(f,x0) =
 (
+	local *;
 	LeftLim = LeftLimit(f,x0);
 	RightLim = RightLimit(f,x0);
 	if ( not IsNull(LeftLim) and
@@ -93,6 +97,7 @@ function Limit(f,x0) =
 SetHelp ("IsContinuous", "calculus", "Try and see if a real-valued function is continuous at x0 by calculating the limit there")
 function IsContinuous(f,x0) =
 (
+    local *;
     l = Limit(f,x0);
     not IsNull(l) and |l-f(x0)| < ContinuousTolerance
 )
diff --git a/lib/calculus/sums_products.gel b/lib/calculus/sums_products.gel
index 0fc1844..6fec783 100644
--- a/lib/calculus/sums_products.gel
+++ b/lib/calculus/sums_products.gel
@@ -11,6 +11,7 @@ parameter SumProductNumberOfTries=10000;
 #calculate an infinite sum until the new terms stop making a difference
 SetHelp("InfiniteSum","calculus","Try to calculate an infinite sum for a single parameter function");
 function InfiniteSum (func, start, inc) = (
+	local *;
 	if not IsValue(start) or not IsValue(inc) then
 		(error("InfiniteSum: start,inc arguments not values");bailout)
 	else if not IsFunction(func) then
@@ -36,6 +37,7 @@ function InfiniteSum (func, start, inc) = (
 #calculate an infinite sum until the new terms stop making a difference
 SetHelp("InfiniteSum2","calculus","Try to calculate an infinite sum for a double parameter function with func(arg,n)");
 function InfiniteSum2(func,arg,start,inc) = (
+	local *;
 	if not IsValue(start) or not IsValue(inc) then
 		(error("InfiniteSum2: start,inc arguments not values");bailout)
 	else if not IsFunction(func) then
@@ -61,6 +63,7 @@ function InfiniteSum2(func,arg,start,inc) = (
 #calculate an infinite product until the new terms stop making a difference
 SetHelp("InfiniteProduct","calculus","Try to calculate an infinite product for a single parameter function");
 function InfiniteProduct (func, start, inc) = (
+	local *;
 	if not IsValue(start) or not IsValue(inc) then
 		(error("InfiniteProduct: start,inc arguments not values");bailout)
 	else if not IsFunction(func) then
@@ -86,6 +89,7 @@ function InfiniteProduct (func, start, inc) = (
 #calculate an infinite product until the new terms stop making a difference
 SetHelp("InfiniteProduct2","calculus","Try to calculate an infinite product for a double parameter function with func(arg,n)");
 function InfiniteProduct2(func,arg,start,inc) = (
+	local *;
 	if not IsValue(start) or not IsValue(inc) then
 		(error("InfiniteProduct2: start,inc arguments not values");bailout)
 	else if not IsFunction(func) then
diff --git a/lib/equation_solving/diffeqs.gel b/lib/equation_solving/diffeqs.gel
index 2e65089..40bbabb 100644
--- a/lib/equation_solving/diffeqs.gel
+++ b/lib/equation_solving/diffeqs.gel
@@ -5,6 +5,7 @@
 SetHelp ("EulersMethod", "equation_solving",
          "Use classical Euler's method to numerically solve y'=f(x,y) for initial x0,y0 going to x1 with n increments, returns y at x1")
 function EulersMethod(f,x0,y0,x1,n) = (
+	local *;
 	# Note we can't check the 2 arguments, FIXME
 	if not IsFunction(f) then
 		(error("EulersMethod: f must be a function of two arguments");bailout)
@@ -27,6 +28,7 @@ function EulersMethod(f,x0,y0,x1,n) = (
 SetHelp ("RungeKutta", "equation_solving",
          "Use classical non-adaptive Runge-Kutta of fourth order method to numerically solve y'=f(x,y) for initial x0,y0 going to x1 with n increments, returns y at x1")
 function RungeKutta(f,x0,y0,x1,n) = (
+	local *;
 	# Note we can't check the 2 arguments, FIXME
 	if not IsFunction(f) then
 		(error("RungeKutta: f must be a function of two arguments");bailout)
diff --git a/lib/equation_solving/find_root.gel b/lib/equation_solving/find_root.gel
index 8e59bf9..b78dfcb 100644
--- a/lib/equation_solving/find_root.gel
+++ b/lib/equation_solving/find_root.gel
@@ -24,6 +24,7 @@ SetHelp ("FindRootBisection", "equation_solving",
          "Find root of a function using the bisection method")
 function FindRootBisection(f,a,b,TOL,N) =
 	(
+	local *;
 # check arguments
 ## check types
 	if(not IsFunction(f)) then
@@ -59,6 +60,7 @@ SetHelp ("FindRootSecant", "equation_solving",
          "Find root of a function using the secant method")
 function FindRootSecant(f,a,b,TOL,N) =
 	(
+	local *;
 # check arguments
 ## check types
 	if(not IsFunction(f)) then
@@ -94,6 +96,7 @@ SetHelp ("FindRootFalsePosition", "equation_solving",
          "Find root of a function using the method of false position")
 function FindRootFalsePosition(f,a,b,TOL,N) =
 	(
+	local *;
 # check arguments
 ## check types
 	if(not IsFunction(f)) then
@@ -131,6 +134,7 @@ SetHelp ("FindRootMullersMethod", "equation_solving",
          "Find root of a function using the Muller's method")
 function FindRootMullersMethod(f,x1,x2,x3,TOL,N) =
 	(
+	local *;
 # check arguments
 ## check types
 	if(not IsFunction(f)) then
diff --git a/lib/library-strings.c b/lib/library-strings.c
index 533eda0..f28b39b 100644
--- a/lib/library-strings.c
+++ b/lib/library-strings.c
@@ -180,8 +180,8 @@ char *fake = N_("Calculate the nth triangular number");
 char *fake = N_("Calculate permutations");
 char *fake = N_("Integration of f by Composite Simpson's Rule on the interval [a,b] with the number of steps calculated by the fourth derivative bound and the desired tolerance");
 char *fake = N_("Attempt to calculate derivative by trying first symbolically and then numerically");
-char *fake = N_("FIXME");
-char *fake = N_("FIXME");
+char *fake = N_("Return a function which is the even periodic extension of f defined on the interval [0,L]");
+char *fake = N_("Return a function which is a Fourier series with the coefficients given by the vectors a (sines) and b (cosines).  Note that a@(1) is the constant coefficient!");
 char *fake = N_("Try to calculate an infinite product for a single parameter function");
 char *fake = N_("Try to calculate an infinite product for a double parameter function with func(arg,n)");
 char *fake = N_("Try to calculate an infinite sum for a single parameter function");
@@ -192,18 +192,18 @@ char *fake = N_("Calculate the left limit of a real-valued function at x0");
 char *fake = N_("Calculate the limit of a real-valued function at x0.  Tries to calculate both left and right limits.");
 char *fake = N_("Integration by midpoint rule");
 char *fake = N_("Attempt to calculate numerical derivative");
-char *fake = N_("FIXME");
-char *fake = N_("FIXME");
-char *fake = N_("FIXME");
-char *fake = N_("FIXME");
+char *fake = N_("Numerically compute the coefficients for a cosine Fourier series for a function on [0,L] up to the Nth coefficient.");
+char *fake = N_("Numerically compute the coefficients for a Fourier series with half-period L up to the Nth coefficient.");
+char *fake = N_("Return a function which is the fourier series of f with half-period L with coefficients up to N computed numerically");
+char *fake = N_("Numerically compute the coefficients for a sine Fourier series for a function on [0,L] up to the Nth coefficient.");
 char *fake = N_("Integration by rule set in NumericalIntegralFunction of f from a to b using NumericalIntegralSteps steps");
 char *fake = N_("Attempt to calculate numerical left derivative");
 char *fake = N_("Attempt to calculate the limit of f(step_fun(i)) as i goes from 1 to N");
 char *fake = N_("Attempt to calculate numerical right derivative");
-char *fake = N_("FIXME");
+char *fake = N_("Return a function which is the odd periodic extension of f defined on the interval [0,L]");
 char *fake = N_("Compute one-sided derivative using five point formula");
 char *fake = N_("Compute one-sided derivative using three-point formula");
-char *fake = N_("FIXME");
+char *fake = N_("Return a function which is the periodic extension of f defined on the interval [a,b]");
 char *fake = N_("Calculate the right limit of a real-valued function at x0");
 char *fake = N_("Compute two-sided derivative using five-point formula");
 char *fake = N_("Compute two-sided derivative using three-point formula");
diff --git a/lib/linear_algebra/misc.gel b/lib/linear_algebra/misc.gel
index 8386143..7697cfc 100644
--- a/lib/linear_algebra/misc.gel
+++ b/lib/linear_algebra/misc.gel
@@ -1,5 +1,6 @@
 SetHelp("ApplyOverMatrix", "matrix", "Apply a function over all entries of a matrix and return a matrix of the results")
 function ApplyOverMatrix(a,func) = (
+	local *;
 	if(not IsMatrix(a)) then
 		(error("ApplyOverMatrix: argument 1 must be a matrix");bailout)
 	else if(not IsFunction(func)) then
@@ -15,6 +16,7 @@ function ApplyOverMatrix(a,func) = (
 
 SetHelp("ApplyOverMatrix2", "matrix", "Apply a function over all entries of 2 matrices (or 1 value and 1 matrix) and return a matrix of the results")
 function ApplyOverMatrix2(a,b,func) = (
+	local *;
 	if(not IsMatrix(a) and not IsMatrix(b)) then
 		(error("ApplyOverMatrix2: argument 1 or 2 must be a matrix");bailout)
 	else if(not IsFunction(func)) then
@@ -151,6 +153,7 @@ Adjugate = adj
 
 SetHelp("MinimizeFunction","functions","Find the first value where f(x)=0");
 function MinimizeFunction(func,x,incr) = (
+	local *;
 	if(not IsValue(x) or not IsValue(incr)) then
 		(error("MinimizeFunction: x,incr arguments not values");bailout)
 	else if(not IsFunction(func)) then
diff --git a/lib/misc/misc.gel b/lib/misc/misc.gel
index 4064d36..194ca5a 100644
--- a/lib/misc/misc.gel
+++ b/lib/misc/misc.gel
@@ -5,10 +5,11 @@ SetHelp("string","basic","Make a string");
 function string(s) = s + ""
 
 SetHelp("Compose","basic","Compose two functions")
-function Compose(f,g) = `(x)=f(g(x))
+function Compose(f,g) = (`(x)[f,g]=(local *;f(g(x))))
 
 SetHelp("ComposePower","basic","Compose a function with itself n times, passing x as argument, and returning x if n == 0")
 function ComposePower(f,n,x) = (
+	local *;
 	for k=1 to n do
 		x = f call (x);
 	x
diff --git a/lib/symbolic/differentiation.gel b/lib/symbolic/differentiation.gel
index 9c5f0df..d928e7c 100644
--- a/lib/symbolic/differentiation.gel
+++ b/lib/symbolic/differentiation.gel
@@ -1,5 +1,6 @@
 function SymbolicNthDerivative(f,n) =
 (
+	local *;
 	if not IsFunction(f) then
 		(error("SymbolicNthDerivative: argument 1 must be a function");bailout)
 	else if not IsNonNegativeInteger(n) then
@@ -18,6 +19,7 @@ SetHelp("SymbolicNthDerivative","symbolic","Attempt to symbolically differentiat
 
 function SymbolicNthDerivativeTry(f,n) =
 (
+	local *;
 	if not IsFunction(f) then
 		(error("SymbolicNthDerivativeTry: argument 1 must be a function");bailout)
 	else if not IsNonNegativeInteger(n) then
@@ -36,6 +38,7 @@ SetHelp("SymbolicNthDerivativeTry","symbolic","Attempt to symbolically different
 
 function SymbolicTaylorApproximationFunction(f,x0,n) =
 (
+	local f,df,c,n,k;
 	if not IsFunction(f) then
 		(error("SymbolicTaylorApproximationFunction: argument 1 must be a function");bailout)
 	else if not IsValue(x0) then
diff --git a/src/eval.c b/src/eval.c
index fd5c92d..aca3f90 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2646,6 +2646,8 @@ function_finish_bin_op (GelCtx *ctx, GelETree *n, int nargs, GelETree *la, GelET
 	n->func.func = f;
 	n->func.func->context = -1;
 
+	/* FIXME: never on subst list maybe? but only when not adding random expression! */
+
 	return TRUE;
 }
 
@@ -2761,6 +2763,8 @@ function_uni_op (GelCtx *ctx, GelETree *n, GelETree *l)
 	n->func.func = f;
 	n->func.func->context = -1;
 
+	n->func.func->never_on_subst_list = 1;
+
 	return TRUE;
 }
 
@@ -2819,6 +2823,8 @@ gel_function_from_function (GelEFunc *func, GelETree *l)
 	n->func.func = f;
 	n->func.func->context = -1;
 
+	n->func.func->never_on_subst_list = 1;
+
 	return n;
 }
 
@@ -3311,7 +3317,8 @@ iter_do_var(GelCtx *ctx, GelETree *n, GelEFunc *f)
 					    f->extra_dict);
 		n->func.func->context = -1;
 		n->func.func->vararg = f->vararg;
-		if (f->on_subst_list &&
+		if ( ! f->never_on_subst_list &&
+		    f->on_subst_list &&
 		    d_curcontext () != 0)
 			d_put_on_subst_list (n->func.func);
 	} else if(f->type == GEL_BUILTIN_FUNC) {
@@ -6662,7 +6669,9 @@ gel_get_ids_for_extradict (GSList *toklist, GSList *args, GSList *locals, GelETr
 		if (g_slist_find (args, n->id.id) == NULL &&
 		    g_slist_find (locals, n->id.id) == NULL &&
 		    g_slist_find (toklist, n->id.id) == NULL) {
-			toklist = g_slist_prepend (toklist, n->id.id);
+			GelEFunc *f = d_lookup_global (n->id.id);
+			if (f != NULL && f->context > 0)
+				toklist = g_slist_prepend (toklist, n->id.id);
 		}
 	} else if (n->type == GEL_SPACER_NODE) {
 		toklist = gel_get_ids_for_extradict (toklist, args, locals, n->sp.arg);
@@ -6740,6 +6749,37 @@ gel_subst_local_vars (GSList *funclist, GSList **toklist)
 	return funclist;
 }
 
+static GSList *
+build_extradict (GSList *funclist, GSList *toklist)
+{
+	GSList *li;
+
+	for (li = toklist; li != NULL; li = li->next) {
+		GelToken *id = li->data;
+		GelEFunc *func = d_lookup_global (id);
+		if G_LIKELY (func != NULL) {
+			GelEFunc *f = d_copyfunc (func);
+			if ( ! f->on_subst_list)
+				f->context = -1;
+			funclist = g_slist_prepend (funclist, f);
+		} else {
+			char *similar = gel_similar_possible_ids (id->token);
+			if (similar != NULL) {
+				gel_errorout (_("Variable '%s' used uninitialized, "
+						"perhaps you meant %s."),
+					      id->token,
+					      similar);
+
+				g_free (similar);
+			} else {
+				gel_errorout (_("Variable '%s' used uninitialized"),
+					      id->token);
+			}
+		}
+	}
+	return funclist;
+}
+
 static gboolean
 iter_eval_etree(GelCtx *ctx)
 {
@@ -6860,10 +6900,18 @@ iter_eval_etree(GelCtx *ctx)
 
 		case GEL_FUNCTION_NODE:
 			EDEBUG(" FUNCTION NODE");
-			if (n->func.func != NULL &&
-			    (n->func.func->type == GEL_USER_FUNC ||
-			     n->func.func->type == GEL_VARIABLE_FUNC) &&
-			    d_curcontext () != 0) {
+			if (n->func.func->never_on_subst_list) {
+				if (n->func.func->built_subst_dict) {
+					n->func.func->extra_dict = build_extradict (n->func.func->extra_dict,
+										    n->func.func->subst_dict);
+					n->func.func->built_subst_dict = 0;
+					g_slist_free (n->func.func->subst_dict);
+					n->func.func->subst_dict = NULL;
+				}
+			} else if (n->func.func != NULL &&
+				   (n->func.func->type == GEL_USER_FUNC ||
+				    n->func.func->type == GEL_VARIABLE_FUNC) &&
+				   d_curcontext () != 0) {
 				d_put_on_subst_list (n->func.func);
 			}
 			WHACK_SAVEDN_POP;
diff --git a/src/geniustest.pl b/src/geniustest.pl
index 1e8b88e..a52f468 100755
--- a/src/geniustest.pl
+++ b/src/geniustest.pl
@@ -38,7 +38,7 @@ while(<TESTS>) {
 		print " (should be)=$shd\n";
 		print " (reported)=$rep\n";
 		if($rep ne $shd) {
-			print "\e[01:31mERROR!\e[0m\n";
+			print "\e[01;31mERROR!\e[0m\n";
 			$errors++;
 			$errorinputs = $errorinputs . "\n$command";
 		}
@@ -47,7 +47,7 @@ while(<TESTS>) {
 		print " (should be)=$shd\n";
 		print " (reported)=\n";
 		if($shd ne "") {
-			print "\e[01:31mERROR! NO OUTPUT\e[0m\n";
+			print "\e[01;31mERROR! NO OUTPUT\e[0m\n";
 			$errors++;
 			$errorinputs = $errorinputs . "\n$command";
 		}
diff --git a/src/geniustests.txt b/src/geniustests.txt
index bebcb3c..3b420c6 100644
--- a/src/geniustests.txt
+++ b/src/geniustests.txt
@@ -466,6 +466,8 @@ ones(2,2).-1							[0,0;0,0]
 sum n in ColumnsOf([1,2;3,4]) do n				[3;7]
 sum n in RowsOf([1,2;3,4]) do n					[4,6]
 function f(x) = `(l) = x+l; k=f(2);k(11)			13
+function f(x) = `(l)[x] = x+l; k=f(2);k(11)			13
+function f(x) = `(l)[] = x+l; k=f(2);k(11)			(x+11)
 function f(a,b,c...) = c ; f()					f()
 function f(a,b,c...) = c ; f(1)					f(1)
 function f(a,b,c...) = c ; f(1,2)+1				((null)+1)
@@ -941,6 +943,7 @@ a=7;(function f(x)=(b=9));f(8);UserVariables()			[f,a]
 a=7;(function f(x)=(b=9));f(8);UndefineAll();UserVariables()+0	((null)+0)
 parameter FloatPrecision = 888					(parameter FloatPrecision = 888)
 parameter foo = 888						888
+y=9;(function g(x)[y]=(y+1));y=0;g(0)				10
 load "nullspacetest.gel"					true
 load "longtest.gel"						true
 load "testprec.gel"						true
diff --git a/src/parse.y b/src/parse.y
index dfe26a9..5f54e8d 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -286,20 +286,75 @@ anyequals:	EQUALS
 	;
 
 funcdef:	'(' identlist ')' anyequals expr %prec FUNCTION {
-			if ( ! gp_push_func (FALSE /* vararg */)) {
+			if ( ! gp_push_func (FALSE /* vararg */,
+					     TRUE /* arguments */,
+					     FALSE /* extradict */,
+					     FALSE /* never_subst */)) {
 				SYNTAX_ERROR;
 			}
 						}
 	|	'(' identlist THREEDOTS ')' anyequals expr %prec FUNCTION {
-			if ( ! gp_push_func (TRUE /* vararg */)) {
+			if ( ! gp_push_func (TRUE /* vararg */,
+					     TRUE /* arguments */,
+					     FALSE /* extradict */,
+					     FALSE /* never_subst */)) {
 				SYNTAX_ERROR;
 			}
 							}
 	|	'(' ')' anyequals expr %prec FUNCTION {
-			if ( ! gp_push_marker (GEL_EXPRLIST_START_NODE)) {
+			if ( ! gp_push_func (FALSE /* vararg */,
+					     FALSE /* arguments */,
+					     FALSE /* extradict */,
+					     FALSE /* never_subst */)) {
 				SYNTAX_ERROR;
 			}
-			if ( ! gp_push_func (FALSE /* vararg */)) {
+					}
+	|	'(' identlist ')' '[' identlist ']' anyequals expr %prec FUNCTION {
+			if ( ! gp_push_func (FALSE /* vararg */,
+					     TRUE /* arguments */,
+					     TRUE /* extradict */,
+					     TRUE /* never_subst */)) {
+				SYNTAX_ERROR;
+			}
+						}
+	|	'(' identlist THREEDOTS ')' '[' identlist ']' anyequals expr %prec FUNCTION {
+			if ( ! gp_push_func (TRUE /* vararg */,
+					     TRUE /* arguments */,
+					     TRUE /* extradict */,
+					     TRUE /* never_subst */)) {
+				SYNTAX_ERROR;
+			}
+							}
+	|	'(' ')' '[' identlist ']' anyequals expr %prec FUNCTION {
+			if ( ! gp_push_func (FALSE /* vararg */,
+					     FALSE /* arguments */,
+					     TRUE /* extradict */,
+					     TRUE /* never_subst */)) {
+				SYNTAX_ERROR;
+			}
+					}
+	;
+	|	'(' identlist ')' '[' ']' anyequals expr %prec FUNCTION {
+			if ( ! gp_push_func (FALSE /* vararg */,
+					     TRUE /* arguments */,
+					     FALSE /* extradict */,
+					     TRUE /* never_subst */)) {
+				SYNTAX_ERROR;
+			}
+						}
+	|	'(' identlist THREEDOTS ')' '[' ']' anyequals expr %prec FUNCTION {
+			if ( ! gp_push_func (TRUE /* vararg */,
+					     TRUE /* arguments */,
+					     FALSE /* extradict */,
+					     TRUE /* never_subst */)) {
+				SYNTAX_ERROR;
+			}
+							}
+	|	'(' ')' '[' ']' anyequals expr %prec FUNCTION {
+			if ( ! gp_push_func (FALSE /* vararg */,
+					     FALSE /* arguments */,
+					     FALSE /* extradict */,
+					     TRUE /* never_subst */)) {
 				SYNTAX_ERROR;
 			}
 					}
diff --git a/src/parseutil.c b/src/parseutil.c
index 5d2ad7f..b6ddc70 100644
--- a/src/parseutil.c
+++ b/src/parseutil.c
@@ -38,12 +38,13 @@ extern GSList *gel_parsestack;
 
 
 gboolean
-gp_push_func (gboolean vararg)
+gp_push_func (gboolean vararg, gboolean arguments, gboolean extradict, gboolean never_subst)
 {
 	GelETree * tree;
 	GelETree * val;
 	GSList * list = NULL;
-	int i = 0;
+	GSList * elist = NULL;
+	int argnum = 0;
 	gboolean local_all = FALSE;
 	GSList *local_idents = NULL;
 	
@@ -59,34 +60,66 @@ gp_push_func (gboolean vararg)
 		return FALSE;
 	}
 
-	for(;;) {
-		tree = gel_stack_pop(&gel_parsestack);
-		if(tree && tree->type==GEL_EXPRLIST_START_NODE) {
-			gel_freetree(tree);
-			break;
+	if (extradict) {
+		for (;;) {
+			tree = gel_stack_pop (&gel_parsestack);
+			if (tree != NULL &&
+			    tree->type == GEL_EXPRLIST_START_NODE) {
+				gel_freetree (tree);
+				break;
+			}
+			/*we have gone all the way to the top and haven't found a
+			  marker or tree is not an ident node*/
+			if G_UNLIKELY (tree == NULL ||
+				       tree->type != GEL_IDENTIFIER_NODE) {
+				if (tree != NULL) gel_freetree(tree);
+				g_slist_free (elist); 
+				g_slist_free (local_idents);
+				return FALSE;
+			}
+			elist = g_slist_prepend (elist, tree->id.id);
+			gel_freetree (tree);
 		}
-		/*we have gone all the way to the top and haven't found a
-		  marker or tree is not an ident node*/
-		if G_UNLIKELY (tree == NULL ||
-			       tree->type != GEL_IDENTIFIER_NODE) {
-			if(tree) gel_freetree(tree);
-			g_slist_free(list); 
-			g_slist_free (local_idents);
-			return FALSE;
+	}
+
+	if (arguments) {
+		for (;;) {
+			tree = gel_stack_pop (&gel_parsestack);
+			if (tree != NULL &&
+			    tree->type == GEL_EXPRLIST_START_NODE) {
+				gel_freetree (tree);
+				break;
+			}
+			/*we have gone all the way to the top and haven't found a
+			  marker or tree is not an ident node*/
+			if G_UNLIKELY (tree == NULL ||
+				       tree->type != GEL_IDENTIFIER_NODE) {
+				if (tree != NULL) gel_freetree(tree);
+				g_slist_free (list); 
+				g_slist_free (elist); 
+				g_slist_free (local_idents);
+				return FALSE;
+			}
+			list = g_slist_prepend (list, tree->id.id);
+			gel_freetree (tree);
+			argnum++;
 		}
-		list = g_slist_prepend(list,tree->id.id);
-		gel_freetree(tree);
-		i++;
 	}
-	
+
 	GEL_GET_NEW_NODE(tree);
 
 	tree->type = GEL_FUNCTION_NODE;
-	tree->func.func = d_makeufunc(NULL,val,list,i, NULL);
+	tree->func.func = d_makeufunc(NULL,val,list,argnum, NULL);
 	tree->func.func->context = -1;
 	tree->func.func->vararg = vararg;
 	tree->func.func->local_all = local_all ? 1 : 0;
 	tree->func.func->local_idents = local_idents;
+	tree->func.func->never_on_subst_list = never_subst ? 1 : 0;
+
+	if (never_subst) {
+		tree->func.func->built_subst_dict = 1;
+		tree->func.func->subst_dict = elist;
+	}
 
 	gel_stack_push(&gel_parsestack,tree);
 
diff --git a/src/parseutil.h b/src/parseutil.h
index f753790..1d035e2 100644
--- a/src/parseutil.h
+++ b/src/parseutil.h
@@ -23,7 +23,10 @@
 
 #include "extra.h"
 
-gboolean gp_push_func (gboolean vararg) GEL_WEAK_FUNC;
+gboolean gp_push_func (gboolean vararg,
+		       gboolean arguments,
+		       gboolean extradict,
+		       gboolean never_subst) GEL_WEAK_FUNC;
 gboolean gp_prepare_push_param (gboolean setfunc) GEL_WEAK_FUNC;
 gboolean gp_prepare_push_region_sep (void) GEL_WEAK_FUNC;
 
diff --git a/src/structs.h b/src/structs.h
index 2ef214b..fee271d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -121,6 +121,10 @@ struct _GelEFunc {
 	/* if true, we must take this off the subst list for a context pop,
 	 * before we free the function */
 	guint32 on_subst_list:1;
+
+	/* never put on a substlist, have a set extradict */
+	guint32 never_on_subst_list:1;
+
 	guint32 vararg:1;
 	guint32 propagate_mod:1;
 	guint32 no_mod_all_args:1;
diff --git a/src/testscope.gel b/src/testscope.gel
index 829ab89..8c29e8c 100644
--- a/src/testscope.gel
+++ b/src/testscope.gel
@@ -139,5 +139,22 @@ function ff() = (
 );
 ff();
 
+A = 1;
+function f(x) = (
+	A = 8;
+	function g(y)[A] = A+5;
+	g
+);
+h = f(0);
+if h(0) != 8+5 then (error("single explicit subst lookup failed");exit());
+
+A = 1;
+function f(x) = (
+	A = 8;
+	function g(y)[] = A+5;
+	g
+);
+h = f(0);
+if h(0) != 1+5 then (error("single explicit non-subst lookup failed");exit());
 
 print("true");



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]