From 5c239187e993a0a59d7cc29a3d6eff00a000c98b Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Fri, 31 Jul 2020 00:57:52 +0100 Subject: [PATCH 01/10] removal of duplicate definitions --- math.scad | 58 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/math.scad b/math.scad index 2262cac..5477512 100644 --- a/math.scad +++ b/math.scad @@ -857,7 +857,7 @@ function determinant(M) = // Description: // Returns true if A is a numeric matrix of height m and width n. If m or n // are omitted or set to undef then true is returned for any positive dimension. -// If `square` is true then the matrix is required to be square. Note if you +// If `square` is true then the matrix is required to be square. // specify m != n and require a square matrix then the result will always be false. // Arguments: // A = matrix to test @@ -1010,16 +1010,6 @@ function all(l, i=0, fail=false) = // count_true([[0,0], [1,0]]); // Returns 1. // count_true([[1,1], [1,1]]); // Returns 4. // count_true([[1,1], [1,1]], nmax=3); // Returns 3. -function count_true(l, nmax=undef, i=0, cnt=0) = - (i>=len(l) || (nmax!=undef && cnt>=nmax))? cnt : - count_true( - l=l, nmax=nmax, i=i+1, cnt=cnt+( - is_list(l[i])? count_true(l[i], nmax=nmax-cnt) : - (l[i]? 1 : 0) - ) - ); - - function count_true(l, nmax) = !is_list(l) ? !(!l) ? 1: 0 : let( c = [for( i = 0, @@ -1212,27 +1202,6 @@ function C_div(z1,z2) = // The polynomial is specified as p=[a_n, a_{n-1},...,a_1,a_0] // where a_n is the z^n coefficient. Polynomial coefficients are real. // The result is a number if `z` is a number and a complex number otherwise. - -// Note: this should probably be recoded to use division by [1,-z], which is more accurate -// and avoids overflow with large coefficients, but requires poly_div to support complex coefficients. -function polynomial(p, z, _k, _zk, _total) = - is_undef(_k) - ? assert( is_vector(p), "Input polynomial coefficients must be a vector." ) - let(p = _poly_trim(p)) - assert( is_finite(z) || is_vector(z,2), "The value of `z` must be a real or a complex number." ) - polynomial( p, - z, - len(p)-1, - is_num(z)? 1 : [1,0], - is_num(z) ? 0 : [0,0]) - : _k==0 - ? _total + +_zk*p[0] - : polynomial( p, - z, - _k-1, - is_num(z) ? _zk*z : C_times(_zk,z), - _total+_zk*p[_k]); - function polynomial(p,z,k,total) =      is_undef(k)    ?    assert( is_vector(p) , "Input polynomial coefficients must be a vector." ) @@ -1248,36 +1217,13 @@ function polynomial(p,z,k,total) = // Description: // Given a list of polynomials represented as real coefficient lists, with the highest degree coefficient first, // computes the coefficient list of the product polynomial. -function poly_mult(p,q) = - is_undef(q) ? - assert( is_list(p) - && []==[for(pi=p) if( !is_vector(pi) && pi!=[]) 0], - "Invalid arguments to poly_mult") - len(p)==2 ? poly_mult(p[0],p[1]) - : poly_mult(p[0], poly_mult(select(p,1,-1))) - : - _poly_trim( - [ - for(n = [len(p)+len(q)-2:-1:0]) - sum( [for(i=[0:1:len(p)-1]) - let(j = len(p)+len(q)- 2 - n - i) - if (j>=0 && j=0 && j Date: Fri, 31 Jul 2020 00:59:05 +0100 Subject: [PATCH 02/10] Minor edits in in_list --- arrays.scad | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arrays.scad b/arrays.scad index 365649a..8f8cb45 100644 --- a/arrays.scad +++ b/arrays.scad @@ -108,14 +108,16 @@ function slice(list,start,end) = // Arguments: // val = The simple value to search for. // list = The list to search. -// idx = If given, searches the given subindexes for matches for `val`. +// idx = If given, searches the given subindex for matches for `val`. // Example: // in_list("bar", ["foo", "bar", "baz"]); // Returns true. // in_list("bee", ["foo", "bar", "baz"]); // Returns false. // in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true. function in_list(val,list,idx=undef) = + assert( is_list(list) && (is_undef(idx) || is_finite(idx)), + "Invalid input." ) let( s = search([val], list, num_returns_per_match=1, index_col_num=idx)[0] ) - s==[] || s[0]==[] ? false + s==[] || s==[[]] ? false : is_undef(idx) ? val==list[s] : val==list[s][idx]; From 3b1d5672194c3a36d78a39331988142e3c4572d2 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Fri, 31 Jul 2020 01:03:32 +0100 Subject: [PATCH 03/10] Revert "Minor edits in in_list" This reverts commit 74cc246c75b97d2203544841ed5eaf717b59782b. --- arrays.scad | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arrays.scad b/arrays.scad index 8f8cb45..365649a 100644 --- a/arrays.scad +++ b/arrays.scad @@ -108,16 +108,14 @@ function slice(list,start,end) = // Arguments: // val = The simple value to search for. // list = The list to search. -// idx = If given, searches the given subindex for matches for `val`. +// idx = If given, searches the given subindexes for matches for `val`. // Example: // in_list("bar", ["foo", "bar", "baz"]); // Returns true. // in_list("bee", ["foo", "bar", "baz"]); // Returns false. // in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true. function in_list(val,list,idx=undef) = - assert( is_list(list) && (is_undef(idx) || is_finite(idx)), - "Invalid input." ) let( s = search([val], list, num_returns_per_match=1, index_col_num=idx)[0] ) - s==[] || s==[[]] ? false + s==[] || s[0]==[] ? false : is_undef(idx) ? val==list[s] : val==list[s][idx]; From 526c01109cc02c22f958f4130de642edba651d45 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Fri, 31 Jul 2020 15:52:35 +0100 Subject: [PATCH 04/10] Minor edits in in_list and transpose, removal of is_simple list --- arrays.scad | 78 +++++++++--------------------------------- tests/test_arrays.scad | 8 ----- 2 files changed, 16 insertions(+), 70 deletions(-) diff --git a/arrays.scad b/arrays.scad index 365649a..84f0425 100644 --- a/arrays.scad +++ b/arrays.scad @@ -18,20 +18,6 @@ // Section: List Query Operations -// Function: is_simple_list() -// Description: -// Returns true just when all elements of `list` are simple values. -// Usage: -// is_simple_list(list) -// Arguments: -// list = The list to check. -// Example: -// a = is_simple_list([3,4,5,6,7,8,9]); Returns: true -// b = is_simple_list([3,4,5,[6],7,8]); Returns: false -function is_simple_list(list) = - is_list(list) - && []==[for(e=list) if(is_list(e)) 0]; - // Function: select() // Description: @@ -73,9 +59,6 @@ function select(list, start, end=undef) = : concat([for (i = [s:1:l-1]) list[i]], [for (i = [0:1:e]) list[i]]) ; - - - // Function: slice() // Description: // Returns a slice of a list. The first item is index 0. @@ -101,24 +84,23 @@ function slice(list,start,end) = ) [for (i=[s:1:e-1]) if (e>s) list[i]]; - - // Function: in_list() // Description: Returns true if value `val` is in list `list`. When `val==NAN` the answer will be false for any list. // Arguments: // val = The simple value to search for. // list = The list to search. -// idx = If given, searches the given subindexes for matches for `val`. +// idx = If given, searches the given subindex for matches for `val`. // Example: // in_list("bar", ["foo", "bar", "baz"]); // Returns true. // in_list("bee", ["foo", "bar", "baz"]); // Returns false. // in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true. function in_list(val,list,idx=undef) = + assert( is_list(list) && (is_undef(idx) || is_finite(idx)), + "Invalid input." ) let( s = search([val], list, num_returns_per_match=1, index_col_num=idx)[0] ) - s==[] || s[0]==[] ? false + s==[] || s==[[]] ? false : is_undef(idx) ? val==list[s] : val==list[s][idx]; - // Function: min_index() @@ -209,7 +191,6 @@ function repeat(val, n, i=0) = [for (j=[1:1:n[i]]) repeat(val, n, i+1)]; - // Function: list_range() // Usage: // list_range(n, [s], [e]) @@ -249,7 +230,6 @@ function list_range(n=undef, s=0, e=undef, step=undef) = - // Section: List Manipulation // Function: reverse() @@ -315,8 +295,6 @@ function deduplicate(list, closed=false, eps=EPSILON) = : [for (i=[0:1:l-1]) if (i==end || !approx(list[i], list[(i+1)%l], eps)) list[i]]; - - // Function: deduplicate_indexed() // Usage: // new_idxs = deduplicate_indexed(list, indices, [closed], [eps]); @@ -351,8 +329,6 @@ function deduplicate_indexed(list, indices, closed=false, eps=EPSILON) = ]; - - // Function: repeat_entries() // Usage: // newlist = repeat_entries(list, N) @@ -390,8 +366,6 @@ function repeat_entries(list, N, exact = true) = : [for (val=reps_guess) round(val)] ) [for(i=[0:length-1]) each repeat(list[i],reps[i])]; - - // Function: list_set() @@ -431,7 +405,6 @@ function list_set(list=[],indices,values,dflt=0,minlen=0) = dflt , each repeat(dflt, minlen-max(indices)) ]; - // Function: list_insert() @@ -465,8 +438,6 @@ function list_insert(list, indices, values, _i=0) = ]; - - // Function: list_remove() // Usage: // list_remove(list, indices) @@ -489,8 +460,6 @@ function list_remove(list, indices) = if ( []==search(i,indices,1) ) list[i] ]; - - // Function: list_remove_values() // Usage: // list_remove_values(list,values,all=false) = @@ -560,8 +529,6 @@ function list_bset(indexset, valuelist, dflt=0) = ); - - // Section: List Length Manipulation // Function: list_shortest() @@ -574,7 +541,6 @@ function list_shortest(array) = min([for (v = array) len(v)]); - // Function: list_longest() // Description: // Returns the length of the longest sublist in a list of lists. @@ -624,7 +590,6 @@ function list_fit(array, length, fill) = : list_pad(array,length,fill); - // Section: List Shuffling and Sorting // Function: shuffle() @@ -679,6 +644,7 @@ function _sort_vectors2(arr) = ) concat( _sort_vectors2(lesser), equal, _sort_vectors2(greater) ); + // Sort a vector of vectors based on the first three entries of each vector // Lexicographic order, remaining entries of vector ignored function _sort_vectors3(arr) = @@ -706,7 +672,6 @@ function _sort_vectors3(arr) = ) concat( _sort_vectors3(lesser), equal, _sort_vectors3(greater) ); - // Sort a vector of vectors based on the first four entries of each vector // Lexicographic order, remaining entries of vector ignored function _sort_vectors4(arr) = @@ -737,7 +702,6 @@ function _sort_vectors4(arr) = && y[3]>pivot[3] )))))) y ] ) concat( _sort_vectors4(lesser), equal, _sort_vectors4(greater) ); - function _sort_general(arr, idx=undef) = @@ -755,7 +719,8 @@ function _sort_general(arr, idx=undef) = greater = [ for (i = [0:1:len(arr)-1]) if (compare[i] > 0) arr[i] ] ) concat(_sort_general(lesser,idx), equal, _sort_general(greater,idx)); - + + function _sort_general(arr, idx=undef) = (len(arr)<=1) ? arr : let( @@ -774,9 +739,6 @@ function _sort_general(arr, idx=undef) = concat(_sort_general(lesser,idx), equal, _sort_general(greater,idx)); - - - // Function: sort() // Usage: // sort(list, [idx]) @@ -809,7 +771,6 @@ function sort(list, idx=undef) = : _sort_general(list); - // Function: sortidx() // Description: // Given a list, calculates the sort order of the list, and returns @@ -853,6 +814,7 @@ function sortidx(list, idx=undef) = : // general case subindex(_sort_general(aug, idx=list_range(s=1,n=len(aug)-1)), 0); + function sortidx(list, idx=undef) = list==[] ? [] : let( size = array_dim(list), @@ -891,7 +853,6 @@ function unique(arr) = ]; - // Function: unique_count() // Usage: // unique_count(arr); @@ -908,8 +869,6 @@ function unique_count(arr) = [ select(arr,ind), deltas( concat(ind,[len(arr)]) ) ]; - - // Section: List Iteration Helpers // Function: idx() @@ -1104,8 +1063,6 @@ function set_union(a, b, get_indices=false) = ) [idxs, nset]; - - // Function: set_difference() // Usage: // s = set_difference(a, b); @@ -1125,7 +1082,6 @@ function set_difference(a, b) = [ for (i=idx(a)) if(found[i]==[]) a[i] ]; - // Function: set_intersection() // Usage: // s = set_intersection(a, b); @@ -1146,7 +1102,6 @@ function set_intersection(a, b) = - // Section: Array Manipulation // Function: add_scalar() @@ -1165,7 +1120,6 @@ function add_scalar(v,s) = is_finite(s) ? [for (x=v) is_list(x)? add_scalar(x,s) : is_finite(x) ? x+s: x] : v; - // Function: subindex() // Description: // For each array item, return the indexed subitem. @@ -1341,14 +1295,14 @@ function array_dim(v, depth=undef) = // Example: // transpose([3,4,5]); // Returns: [3,4,5] function transpose(arr) = - let( a0 = arr[0] ) - is_list(a0) - ? assert([for(a=arr) if(len(a)!=len(a0)) 1]==[], "The array is not a matrix." ) - [for (i=[0:1:len(a0)-1]) - [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] - : arr; - - + assert( is_list(arr) && len(arr)>0, "The array is not a vector neither a matrix." ) + is_list(arr[0]) + ? let( l0 = len(arr[0]) ) + assert([for(a=arr) if(!is_list(a) || len(a)!=l0) 1 ]==[], "The array is not a vector neither a matrix." ) + [for (i=[0:1:l0-1]) + [ for (j=[0:1:len(arr)-1]) arr[j][i] ] ] + : assert( is_vector(arr), "The array is not a vector neither a matrix." ) + arr; // vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/tests/test_arrays.scad b/tests/test_arrays.scad index f621cd0..cdaae36 100644 --- a/tests/test_arrays.scad +++ b/tests/test_arrays.scad @@ -3,14 +3,6 @@ include <../std.scad> // Section: List Query Operations -module test_is_simple_list() { - assert(is_simple_list([1,2,3,4])); - assert(is_simple_list([])); - assert(!is_simple_list([1,2,[3,4]])); -} -test_is_simple_list(); - - module test_select() { l = [3,4,5,6,7,8,9]; assert(select(l, 5, 6) == [8,9]); From 855c1da6f1eb89687ab2100103592912112d74de Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Fri, 31 Jul 2020 15:53:06 +0100 Subject: [PATCH 05/10] Minor doc edit --- common.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.scad b/common.scad index 37ba4af..dcb73cb 100644 --- a/common.scad +++ b/common.scad @@ -135,7 +135,7 @@ function is_list_of(list,pattern) = // is_consistent(list) // Description: // Tests whether input is a list of entries which all have the same list structure -// and are filled with finite numerical data. +// and are filled with finite numerical data. It returns `true`for the empty list. // Example: // is_consistent([3,4,5]); // Returns true // is_consistent([[3,4],[4,5],[6,7]]); // Returns true From 2da259c2cc3ca72bad07c21ede28b2ea42970799 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Sun, 2 Aug 2020 00:47:22 +0100 Subject: [PATCH 06/10] Minor is_matrix definition and format --- math.scad | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/math.scad b/math.scad index 4ae8722..5b4284a 100644 --- a/math.scad +++ b/math.scad @@ -240,7 +240,7 @@ function atanh(x) = // quant([9,10,10.4,10.5,11,12],3); // Returns: [9,9,9,12,12,12] // quant([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,9,9],[12,12,12]] function quant(x,y) = - assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero number.") + assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero integer.") is_list(x) ? [for (v=x) quant(v,y)] : assert( is_finite(x), "The input to quantize must be a number or a list of numbers.") @@ -272,7 +272,7 @@ function quant(x,y) = // quantdn([9,10,10.4,10.5,11,12],3); // Returns: [9,9,9,9,9,12] // quantdn([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,9,9],[9,9,12]] function quantdn(x,y) = - assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero number.") + assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero integer.") is_list(x) ? [for (v=x) quantdn(v,y)] : assert( is_finite(x), "The input to quantize must be a number or a list of numbers.") @@ -304,7 +304,7 @@ function quantdn(x,y) = // quantup([9,10,10.4,10.5,11,12],3); // Returns: [9,12,12,12,12,12] // quantup([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,12,12],[12,12,12]] function quantup(x,y) = - assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero number.") + assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero integer.") is_list(x) ? [for (v=x) quantup(v,y)] : assert( is_finite(x), "The input to quantize must be a number or a list of numbers.") @@ -778,22 +778,19 @@ function back_substitute(R, b, x=[],transpose = false) = let(n=len(R)) assert(is_vector(b,n) || is_matrix(b,n),str("R and b are not compatible in back_substitute ",n, len(b))) !is_vector(b) ? transpose([for(i=[0:len(b[0])-1]) back_substitute(R,subindex(b,i),transpose=transpose)]) : - transpose? - reverse(back_substitute( - [for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]], - reverse(b), x, false - )) : - len(x) == n ? x : - let( - ind = n - len(x) - 1 - ) - R[ind][ind] == 0 ? [] : - let( - newvalue = - len(x)==0? b[ind]/R[ind][ind] : - (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] - ) back_substitute(R, b, concat([newvalue],x)); - + transpose +    ? let( R = [for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]] ) + reverse( back_substitute( R, reverse(b), x ) )  + : len(x) == n ? x : + let( + ind = n - len(x) - 1 + ) + R[ind][ind] == 0 ? [] : + let( + newvalue = + len(x)==0? b[ind]/R[ind][ind] : + (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] + ) back_substitute(R, b, concat([newvalue],x)); // Function: det2() // Description: @@ -865,13 +862,16 @@ function determinant(M) = // n = optional width of matrix // square = set to true to require a square matrix. Default: false function is_matrix(A,m,n,square=false) = - is_list(A[0]) -    && ( let(v = A*A[0]) is_num(0*(v*v)) ) // a matrix of finite numbers + is_list(A) + && len(A)>0 + && is_vector(A[0]) +    && is_vector(A*A[0]) // a matrix of finite numbers     && (is_undef(n) || len(A[0])==n )     && (is_undef(m) || len(A)==m )     && ( !square || len(A)==len(A[0])); + // Section: Comparisons and Logic // Function: approx() @@ -1037,7 +1037,7 @@ function count_true(l, nmax) = // data[len(data)-1]. This function uses a symetric derivative approximation // for internal points, f'(t) = (f(t+h)-f(t-h))/2h. For the endpoints (when closed=false) the algorithm // uses a two point method if sufficient points are available: f'(t) = (3*(f(t+h)-f(t)) - (f(t+2*h)-f(t+h)))/2h. -// . +// // If `h` is a vector then it is assumed to be nonuniform, with h[i] giving the sampling distance // between data[i+1] and data[i], and the data values will be linearly resampled at each corner // to produce a uniform spacing for the derivative estimate. At the endpoints a single point method From 84fa648dc505398fd4d2ab95c7d457b4cacc7b62 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Sun, 2 Aug 2020 01:08:24 +0100 Subject: [PATCH 07/10] Revert "Minor is_matrix definition and format" This reverts commit 2da259c2cc3ca72bad07c21ede28b2ea42970799. --- math.scad | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/math.scad b/math.scad index 5b4284a..4ae8722 100644 --- a/math.scad +++ b/math.scad @@ -240,7 +240,7 @@ function atanh(x) = // quant([9,10,10.4,10.5,11,12],3); // Returns: [9,9,9,12,12,12] // quant([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,9,9],[12,12,12]] function quant(x,y) = - assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero integer.") + assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero number.") is_list(x) ? [for (v=x) quant(v,y)] : assert( is_finite(x), "The input to quantize must be a number or a list of numbers.") @@ -272,7 +272,7 @@ function quant(x,y) = // quantdn([9,10,10.4,10.5,11,12],3); // Returns: [9,9,9,9,9,12] // quantdn([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,9,9],[9,9,12]] function quantdn(x,y) = - assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero integer.") + assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero number.") is_list(x) ? [for (v=x) quantdn(v,y)] : assert( is_finite(x), "The input to quantize must be a number or a list of numbers.") @@ -304,7 +304,7 @@ function quantdn(x,y) = // quantup([9,10,10.4,10.5,11,12],3); // Returns: [9,12,12,12,12,12] // quantup([[9,10,10.4],[10.5,11,12]],3); // Returns: [[9,12,12],[12,12,12]] function quantup(x,y) = - assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero integer.") + assert(is_finite(y) && !approx(y,0,eps=1e-24), "The multiple must be a non zero number.") is_list(x) ? [for (v=x) quantup(v,y)] : assert( is_finite(x), "The input to quantize must be a number or a list of numbers.") @@ -778,19 +778,22 @@ function back_substitute(R, b, x=[],transpose = false) = let(n=len(R)) assert(is_vector(b,n) || is_matrix(b,n),str("R and b are not compatible in back_substitute ",n, len(b))) !is_vector(b) ? transpose([for(i=[0:len(b[0])-1]) back_substitute(R,subindex(b,i),transpose=transpose)]) : - transpose -    ? let( R = [for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]] ) - reverse( back_substitute( R, reverse(b), x ) )  - : len(x) == n ? x : - let( - ind = n - len(x) - 1 - ) - R[ind][ind] == 0 ? [] : - let( - newvalue = - len(x)==0? b[ind]/R[ind][ind] : - (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] - ) back_substitute(R, b, concat([newvalue],x)); + transpose? + reverse(back_substitute( + [for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]], + reverse(b), x, false + )) : + len(x) == n ? x : + let( + ind = n - len(x) - 1 + ) + R[ind][ind] == 0 ? [] : + let( + newvalue = + len(x)==0? b[ind]/R[ind][ind] : + (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] + ) back_substitute(R, b, concat([newvalue],x)); + // Function: det2() // Description: @@ -862,16 +865,13 @@ function determinant(M) = // n = optional width of matrix // square = set to true to require a square matrix. Default: false function is_matrix(A,m,n,square=false) = - is_list(A) - && len(A)>0 - && is_vector(A[0]) -    && is_vector(A*A[0]) // a matrix of finite numbers + is_list(A[0]) +    && ( let(v = A*A[0]) is_num(0*(v*v)) ) // a matrix of finite numbers     && (is_undef(n) || len(A[0])==n )     && (is_undef(m) || len(A)==m )     && ( !square || len(A)==len(A[0])); - // Section: Comparisons and Logic // Function: approx() @@ -1037,7 +1037,7 @@ function count_true(l, nmax) = // data[len(data)-1]. This function uses a symetric derivative approximation // for internal points, f'(t) = (f(t+h)-f(t-h))/2h. For the endpoints (when closed=false) the algorithm // uses a two point method if sufficient points are available: f'(t) = (3*(f(t+h)-f(t)) - (f(t+2*h)-f(t+h)))/2h. -// +// . // If `h` is a vector then it is assumed to be nonuniform, with h[i] giving the sampling distance // between data[i+1] and data[i], and the data values will be linearly resampled at each corner // to produce a uniform spacing for the derivative estimate. At the endpoints a single point method From 764420e71de0a2724dab4212e66674e5ffb73c51 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Sun, 2 Aug 2020 01:15:07 +0100 Subject: [PATCH 08/10] Minor edits in is_matrix --- math.scad | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/math.scad b/math.scad index 4ae8722..9c8e717 100644 --- a/math.scad +++ b/math.scad @@ -773,26 +773,26 @@ function _qr_factor(A,Q, column, m, n) = // You can supply a compatible matrix b and it will produce the solution for every column of b. Note that if you want to // solve Rx=b1 and Rx=b2 you must set b to transpose([b1,b2]) and then take the transpose of the result. If the matrix // is singular (e.g. has a zero on the diagonal) then it returns []. -function back_substitute(R, b, x=[],transpose = false) = +function back_substitute(R, b, transpose = false) = assert(is_matrix(R, square=true)) let(n=len(R)) assert(is_vector(b,n) || is_matrix(b,n),str("R and b are not compatible in back_substitute ",n, len(b))) - !is_vector(b) ? transpose([for(i=[0:len(b[0])-1]) back_substitute(R,subindex(b,i),transpose=transpose)]) : - transpose? - reverse(back_substitute( - [for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]], - reverse(b), x, false - )) : - len(x) == n ? x : - let( - ind = n - len(x) - 1 - ) - R[ind][ind] == 0 ? [] : - let( - newvalue = - len(x)==0? b[ind]/R[ind][ind] : - (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] - ) back_substitute(R, b, concat([newvalue],x)); + transpose + ? reverse(_back_substitute([for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]], + reverse(b))) + : _back_substitute(R,b); + +function _back_substitute(R, b, x=[]) = + let(n=len(R)) + len(x) == n ? x + : let(ind = n - len(x) - 1) + R[ind][ind] == 0 ? [] + : let( + newvalue = len(x)==0 + ? b[ind]/R[ind][ind] + : (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] + ) + _back_substitute(R, b, concat([newvalue],x)); // Function: det2() @@ -865,8 +865,10 @@ function determinant(M) = // n = optional width of matrix // square = set to true to require a square matrix. Default: false function is_matrix(A,m,n,square=false) = - is_list(A[0]) -    && ( let(v = A*A[0]) is_num(0*(v*v)) ) // a matrix of finite numbers + is_list(A) + && len(A)>0 + && is_vector(A[0]) +    && is_vector(A*A[0]) // a matrix of finite numbers     && (is_undef(n) || len(A[0])==n )     && (is_undef(m) || len(A)==m )     && ( !square || len(A)==len(A[0])); From e4bd6238b4399a53767be9a89105b32871486d2a Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 4 Aug 2020 00:08:23 +0100 Subject: [PATCH 09/10] Revert "Minor edits in is_matrix" This reverts commit 764420e71de0a2724dab4212e66674e5ffb73c51. --- math.scad | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/math.scad b/math.scad index 9c8e717..4ae8722 100644 --- a/math.scad +++ b/math.scad @@ -773,26 +773,26 @@ function _qr_factor(A,Q, column, m, n) = // You can supply a compatible matrix b and it will produce the solution for every column of b. Note that if you want to // solve Rx=b1 and Rx=b2 you must set b to transpose([b1,b2]) and then take the transpose of the result. If the matrix // is singular (e.g. has a zero on the diagonal) then it returns []. -function back_substitute(R, b, transpose = false) = +function back_substitute(R, b, x=[],transpose = false) = assert(is_matrix(R, square=true)) let(n=len(R)) assert(is_vector(b,n) || is_matrix(b,n),str("R and b are not compatible in back_substitute ",n, len(b))) - transpose - ? reverse(_back_substitute([for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]], - reverse(b))) - : _back_substitute(R,b); - -function _back_substitute(R, b, x=[]) = - let(n=len(R)) - len(x) == n ? x - : let(ind = n - len(x) - 1) - R[ind][ind] == 0 ? [] - : let( - newvalue = len(x)==0 - ? b[ind]/R[ind][ind] - : (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] - ) - _back_substitute(R, b, concat([newvalue],x)); + !is_vector(b) ? transpose([for(i=[0:len(b[0])-1]) back_substitute(R,subindex(b,i),transpose=transpose)]) : + transpose? + reverse(back_substitute( + [for(i=[0:n-1]) [for(j=[0:n-1]) R[n-1-j][n-1-i]]], + reverse(b), x, false + )) : + len(x) == n ? x : + let( + ind = n - len(x) - 1 + ) + R[ind][ind] == 0 ? [] : + let( + newvalue = + len(x)==0? b[ind]/R[ind][ind] : + (b[ind]-select(R[ind],ind+1,-1) * x)/R[ind][ind] + ) back_substitute(R, b, concat([newvalue],x)); // Function: det2() @@ -865,10 +865,8 @@ function determinant(M) = // n = optional width of matrix // square = set to true to require a square matrix. Default: false function is_matrix(A,m,n,square=false) = - is_list(A) - && len(A)>0 - && is_vector(A[0]) -    && is_vector(A*A[0]) // a matrix of finite numbers + is_list(A[0]) +    && ( let(v = A*A[0]) is_num(0*(v*v)) ) // a matrix of finite numbers     && (is_undef(n) || len(A[0])==n )     && (is_undef(m) || len(A)==m )     && ( !square || len(A)==len(A[0])); From e06519bbfb4026dd51e6518900f688c797149fc9 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Tue, 4 Aug 2020 00:38:36 +0100 Subject: [PATCH 10/10] changes to hide recursion args and avoid repetitive arg validations cumsum broken in two to hide recursion args and avoid repetitive arg validations. back_substitute changed to avoid repetitive arg validations in the recursion. minor change in deriv2 and deriv3 to avoid an unecessary call to is_matrix. change in is_matrix for better performance any() and all() broken in two to avoid repetitive arg validation in the recursion and to hide recursion args. change in polymult to call convolve break of poly_div in two to avoid repetitive arg validations in the recursion. --- math.scad | 143 +++++++++++++++++++++++-------------------- tests/test_math.scad | 12 ++-- 2 files changed, 82 insertions(+), 73 deletions(-) diff --git a/math.scad b/math.scad index f112c19..7e16bbe 100644 --- a/math.scad +++ b/math.scad @@ -84,7 +84,7 @@ function hypot(x,y,z=0) = // y = factorial(6); // Returns: 720 // z = factorial(9); // Returns: 362880 function factorial(n,d=0) = - assert(is_int(n) && is_int(d) && n>=0 && d>=0, "Factorial is not defined for negative numbers") + assert(is_int(n) && is_int(d) && n>=0 && d>=0, "Factorial is defined only for non negative integers") assert(d<=n, "d cannot be larger than n") product([1,for (i=[n:-1:d+1]) i]); @@ -164,7 +164,7 @@ function binomial_coefficient(n,k) = function lerp(a,b,u) = assert(same_shape(a,b), "Bad or inconsistent inputs to lerp") is_finite(u)? (1-u)*a + u*b : - assert(is_finite(u) || is_vector(u) || valid_range(u), "Input u to lerp must be a number, vector, or range.") + assert(is_finite(u) || is_vector(u) || valid_range(u), "Input u to lerp must be a number, vector, or valid range.") [for (v = u) (1-v)*a + v*b ]; @@ -387,12 +387,13 @@ function modang(x) = // modrange(90,270,360, step=-45); // Returns: [90,45,0,315,270] // modrange(270,90,360, step=-45); // Returns: [270,225,180,135,90] function modrange(x, y, m, step=1) = - assert( is_finite(x+y+step+m) && !approx(m,0), "Input must be finite numbers. The module value cannot be zero.") + assert( is_finite(x+y+step+m) && !approx(m,0), "Input must be finite numbers and the module value cannot be zero." ) let( a = posmod(x, m), b = posmod(y, m), - c = step>0? (a>b? b+m : b) : (a0? (a>b? b+m : b) + : (a=len(v) ? _total : _sum(v,_total+v[_i], _i+1); // cumsum([2,2,2]); // returns [2,4,6] // cumsum([1,2,3]); // returns [1,3,6] // cumsum([[1,2,3], [3,4,5], [5,6,7]]); // returns [[1,2,3], [4,6,8], [9,12,15]] -function cumsum(v,_i=0,_acc=[]) = +function cumsum(v) = + assert(is_consistent(v), "The input is not consistent." ) + _cumsum(v,_i=0,_acc=[]); + +function _cumsum(v,_i=0,_acc=[]) = _i==len(v) ? _acc : - cumsum( + _cumsum( v, _i+1, concat( _acc, @@ -598,7 +603,7 @@ function deltas(v) = // Description: // Returns the product of all entries in the given list. // If passed a list of vectors of same dimension, returns a vector of products of each part. -// If passed a list of square matrices, returns a the resulting product matrix. +// If passed a list of square matrices, returns the resulting product matrix. // Arguments: // v = The list to get the product of. // Example: @@ -606,7 +611,7 @@ function deltas(v) = // product([[1,2,3], [3,4,5], [5,6,7]]); // returns [15, 48, 105] function product(v) = assert( is_vector(v) || is_matrix(v) || ( is_matrix(v[0],square=true) && is_consistent(v)), - "Invalid input.") + "Invalid input.") _product(v, 1, v[0]); function _product(v, i=0, _tot) = @@ -691,9 +696,12 @@ function linear_solve(A,b) = zeros = [for(i=[0:mindim-1]) if (approx(R[i][i],0)) i] ) zeros != [] ? [] : - m=len(l) || succ)? succ : - any( l, - i+1, - succ = is_list(l[i]) ? any(l[i]) : !(!l[i]) - ); +function any(l) = + assert(is_list(l), "The input is not a list." ) + _any(l, i=0, succ=false); +function _any(l, i=0, succ=false) = + (i>=len(l) || succ)? succ : + _any( l, + i+1, + succ = is_list(l[i]) ? _any(l[i]) : !(!l[i]) + ); // Function: all() @@ -972,12 +982,15 @@ function any(l, i=0, succ=false) = // all([[0,0], [1,0]]); // Returns false. // all([[1,1], [1,1]]); // Returns true. function all(l, i=0, fail=false) = - (i>=len(l) || fail)? !fail : - all( l, - i+1, - fail = is_list(l[i]) ? !all(l[i]) : !l[i] - ) ; + assert( is_list(l), "The input is not a list." ) + _all(l, i=0, fail=false); +function _all(l, i=0, fail=false) = + (i>=len(l) || fail)? !fail : + _all( l, + i+1, + fail = is_list(l[i]) ? !_all(l[i]) : !l[i] + ) ; // Function: count_true() @@ -1195,12 +1208,12 @@ function C_div(z1,z2) = // where a_n is the z^n coefficient. Polynomial coefficients are real. // The result is a number if `z` is a number and a complex number otherwise. function polynomial(p,z,k,total) = - is_undef(k) - ? assert( is_vector(p) , "Input polynomial coefficients must be a vector." ) - assert( is_finite(z) || is_vector(z,2), "The value of `z` must be a real or a complex number." ) - polynomial( _poly_trim(p), z, 0, is_num(z) ? 0 : [0,0]) - : k==len(p) ? total - : polynomial(p,z,k+1, is_num(z) ? total*z+p[k] : C_times(total,z)+[p[k],0]); +    is_undef(k) +    ?   assert( is_vector(p) , "Input polynomial coefficients must be a vector." ) +        assert( is_finite(z) || is_vector(z,2), "The value of `z` must be a real or a complex number." ) +        polynomial( _poly_trim(p), z, 0, is_num(z) ? 0 : [0,0]) +    : k==len(p) ? total +    : polynomial(p,z,k+1, is_num(z) ? total*z+p[k] : C_times(total,z)+[p[k],0]); // Function: poly_mult() // Usage: @@ -1210,22 +1223,16 @@ function polynomial(p,z,k,total) = // Given a list of polynomials represented as real coefficient lists, with the highest degree coefficient first, // computes the coefficient list of the product polynomial. function poly_mult(p,q) = - is_undef(q) ? - assert( is_list(p) - && []==[for(pi=p) if( !is_vector(pi) && pi!=[]) 0], - "Invalid arguments to poly_mult") - len(p)==2 ? poly_mult(p[0],p[1]) - : poly_mult(p[0], poly_mult(select(p,1,-1))) - : - _poly_trim( - [ - for(n = [len(p)+len(q)-2:-1:0]) - sum( [for(i=[0:1:len(p)-1]) - let(j = len(p)+len(q)- 2 - n - i) - if (j>=0 && j