diff --git a/arrays.scad b/arrays.scad index 4f1c317..d5e03a5 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) @@ -494,8 +465,6 @@ function list_remove(list, indices) = ]; - - // Function: list_remove_values() // Usage: // list_remove_values(list,values,all=false) = @@ -565,8 +534,6 @@ function list_bset(indexset, valuelist, dflt=0) = ); - - // Section: List Length Manipulation // Function: list_shortest() @@ -579,7 +546,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. @@ -629,7 +595,6 @@ function list_fit(array, length, fill) = : list_pad(array,length,fill); - // Section: List Shuffling and Sorting // Function: shuffle() @@ -684,6 +649,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) = @@ -711,7 +677,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) = @@ -742,7 +707,6 @@ function _sort_vectors4(arr) = && y[3]>pivot[3] )))))) y ] ) concat( _sort_vectors4(lesser), equal, _sort_vectors4(greater) ); - function _sort_general(arr, idx=undef) = @@ -760,7 +724,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( @@ -779,9 +744,6 @@ function _sort_general(arr, idx=undef) = concat(_sort_general(lesser,idx), equal, _sort_general(greater,idx)); - - - // Function: sort() // Usage: // sort(list, [idx]) @@ -814,7 +776,6 @@ function sort(list, idx=undef) = : _sort_general(list); - // Function: sortidx() // Description: // Given a list, calculates the sort order of the list, and returns @@ -858,6 +819,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), @@ -896,7 +858,6 @@ function unique(arr) = ]; - // Function: unique_count() // Usage: // unique_count(arr); @@ -913,8 +874,6 @@ function unique_count(arr) = [ select(arr,ind), deltas( concat(ind,[len(arr)]) ) ]; - - // Section: List Iteration Helpers // Function: idx() @@ -1109,8 +1068,6 @@ function set_union(a, b, get_indices=false) = ) [idxs, nset]; - - // Function: set_difference() // Usage: // s = set_difference(a, b); @@ -1130,7 +1087,6 @@ function set_difference(a, b) = [ for (i=idx(a)) if(found[i]==[]) a[i] ]; - // Function: set_intersection() // Usage: // s = set_intersection(a, b); @@ -1151,7 +1107,6 @@ function set_intersection(a, b) = - // Section: Array Manipulation // Function: add_scalar() @@ -1170,7 +1125,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() // Usage: // subindex(M, idx) @@ -1346,14 +1300,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/common.scad b/common.scad index d8941ee..eebd141 100644 --- a/common.scad +++ b/common.scad @@ -140,7 +140,7 @@ function _list_pattern(list) = // 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 diff --git a/math.scad b/math.scad index e9b8579..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() @@ -971,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() @@ -999,16 +1013,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, @@ -1204,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: @@ -1219,35 +1223,15 @@ 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=0 && j // 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]); diff --git a/tests/test_math.scad b/tests/test_math.scad index e5b1a41..91e662f 100644 --- a/tests/test_math.scad +++ b/tests/test_math.scad @@ -913,23 +913,21 @@ test_qr_factor(); module test_poly_mult(){ assert_equal(poly_mult([3,2,1],[4,5,6,7]),[12,23,32,38,20,7]); - assert_equal(poly_mult([3,2,1],[0]),[0]); -// assert_equal(poly_mult([3,2,1],[]),[]); assert_equal(poly_mult([[1,2],[3,4],[5,6]]), [15,68,100,48]); + assert_equal(poly_mult([3,2,1],[0]),[0]); assert_equal(poly_mult([[1,2],[0],[5,6]]), [0]); -// assert_equal(poly_mult([[1,2],[],[5,6]]), []); - assert_equal(poly_mult([[3,4,5],[0,0,0]]),[0]); -// assert_equal(poly_mult([[3,4,5],[0,0,0]]),[]); + assert_equal(poly_mult([[3,4,5],[0,0,0]]), [0]); + assert_equal(poly_mult([[0],[0,0,0]]),[0]); } test_poly_mult(); module test_poly_div(){ assert_equal(poly_div(poly_mult([4,3,3,2],[2,1,3]), [2,1,3]),[[4,3,3,2],[0]]); -// assert_equal(poly_div(poly_mult([4,3,3,2],[2,1,3]), [2,1,3]),[[4,3,3,2],[]]); assert_equal(poly_div([1,2,3,4],[1,2,3,4,5]), [[], [1,2,3,4]]); assert_equal(poly_div(poly_add(poly_mult([1,2,3,4],[2,0,2]), [1,1,2]), [1,2,3,4]), [[2,0,2],[1,1,2]]); assert_equal(poly_div([1,2,3,4], [1,-3]), [[1,5,18],[58]]); + assert_equal(poly_div([0], [1,-3]), [[0],[0]]); } test_poly_div(); @@ -942,4 +940,4 @@ module test_poly_add(){ } test_poly_add(); -// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap +// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap \ No newline at end of file