From 934b3c7b04e74166519b64d2af30128e0e416e24 Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Sat, 30 Oct 2021 17:47:17 -0400 Subject: [PATCH] make all_zero, etc, non-recursive, just work on vectors --- comparisons.scad | 110 ++++++++++++++++++------------------ tests/test_comparisons.scad | 6 +- tests/test_linalg.scad | 2 +- 3 files changed, 58 insertions(+), 60 deletions(-) diff --git a/comparisons.scad b/comparisons.scad index e78d189..bd2a25c 100644 --- a/comparisons.scad +++ b/comparisons.scad @@ -6,7 +6,7 @@ ////////////////////////////////////////////////////////////////////// -// Section: Comparing lists to zero +// Section: List comparison operations // Function: approx() // Usage: @@ -34,7 +34,7 @@ function approx(a,b,eps=EPSILON) = // x = all_zero(x, [eps]); // Description: // Returns true if the finite number passed to it is approximately zero, to within `eps`. -// If passed a list, recursively checks if all items in the list are approximately zero. +// If passed a list returns true if all its entries are approximately zero. // Otherwise, returns false. // Arguments: // x = The value to check. @@ -45,17 +45,16 @@ function approx(a,b,eps=EPSILON) = // c = all_zero([0,0,0]); // Returns: true. // d = all_zero([0,0,1e-3]); // Returns: false. function all_zero(x, eps=EPSILON) = - is_finite(x)? approx(x,eps) : - is_list(x)? (x != [] && [for (xx=x) if(!all_zero(xx,eps=eps)) 1] == []) : - false; + is_finite(x)? abs(x)eps) 1] == []; // Function: all_nonzero() // Usage: // test = all_nonzero(x, [eps]); // Description: -// Returns true if the finite number passed to it is not almost zero, to within `eps`. -// If passed a list, recursively checks if all items in the list are not almost zero. +// Returns true if the finite number passed to it is different from zero by `eps`. +// If passed a list returns true if all the entries of the list are different from zero by `eps`. // Otherwise, returns false. // Arguments: // x = The value to check. @@ -67,20 +66,20 @@ function all_zero(x, eps=EPSILON) = // d = all_nonzero([0,0,1e-3]); // Returns: false. // e = all_nonzero([1e-3,1e-3,1e-3]); // Returns: true. function all_nonzero(x, eps=EPSILON) = - is_finite(x)? !approx(x,eps) : - is_list(x)? (x != [] && [for (xx=x) if(!all_nonzero(xx,eps=eps)) 1] == []) : - false; + is_finite(x)? abs(x)>eps : + is_vector(x) && [for (xx=x) if(abs(xx)0 : - is_list(x)? (x != [] && [for (xx=x) if(!all_positive(xx)) 1] == []) : - false; +function all_positive(x,eps=0) = + is_num(x)? x>eps : + is_vector(x) && [for (xx=x) if(xx<=0) 1] == []; // Function: all_negative() // Usage: -// test = all_negative(x); +// test = all_negative(x, [eps]); // Description: // Returns true if the finite number passed to it is less than zero. // If passed a list, recursively checks if all items in the list are negative. // Otherwise, returns false. // Arguments: // x = The value to check. +// eps = tolerance. Default: 0 // Example: // a = all_negative(-2); // Returns: true. // b = all_negative(0); // Returns: false. @@ -113,21 +112,21 @@ function all_positive(x) = // f = all_negative([3,1,2]); // Returns: false. // g = all_negative([3,-1,2]); // Returns: false. // h = all_negative([-3,-1,-2]); // Returns: true. -function all_negative(x) = - is_num(x)? x<0 : - is_list(x)? (x != [] && [for (xx=x) if(!all_negative(xx)) 1] == []) : - false; +function all_negative(x, eps=0) = + is_num(x)? x<-eps : + is_vector(x) && [for (xx=x) if(xx>=-eps) 1] == []; // Function: all_nonpositive() // Usage: -// all_nonpositive(x); +// all_nonpositive(x, [eps]); // Description: // Returns true if the finite number passed to it is less than or equal to zero. // If passed a list, recursively checks if all items in the list are nonpositive. -// Otherwise, returns false. +// Otherwise, returns false. // Arguments: // x = The value to check. +// eps = tolerance. Default: 0 // Example: // a = all_nonpositive(-2); // Returns: true. // b = all_nonpositive(0); // Returns: true. @@ -137,21 +136,21 @@ function all_negative(x) = // f = all_nonpositive([3,1,2]); // Returns: false. // g = all_nonpositive([3,-1,2]); // Returns: false. // h = all_nonpositive([-3,-1,-2]); // Returns: true. -function all_nonpositive(x) = - is_num(x)? x<=0 : - is_list(x)? (x != [] && [for (xx=x) if(!all_nonpositive(xx)) 1] == []) : - false; +function all_nonpositive(x,eps=0) = + is_num(x)? x<=eps : + is_vector(x) && [for (xx=x) if(xx>eps) 1] == []; // Function: all_nonnegative() // Usage: -// all_nonnegative(x); +// all_nonnegative(x, [eps]); // Description: // Returns true if the finite number passed to it is greater than or equal to zero. // If passed a list, recursively checks if all items in the list are nonnegative. // Otherwise, returns false. // Arguments: // x = The value to check. +// eps = tolerance. Default: 0 // Example: // a = all_nonnegative(-2); // Returns: false. // b = all_nonnegative(0); // Returns: true. @@ -162,10 +161,9 @@ function all_nonpositive(x) = // g = all_nonnegative([3,1,2]); // Returns: true. // h = all_nonnegative([3,-1,2]); // Returns: false. // i = all_nonnegative([-3,-1,-2]); // Returns: false. -function all_nonnegative(x) = - is_num(x)? x>=0 : - is_list(x)? (x != [] && [for (xx=x) if(!all_nonnegative(xx)) 1] == []) : - false; +function all_nonnegative(x,eps=0) = + is_num(x)? x>=-eps : + is_vector(x) && [for (xx=x) if(xx<-eps) 1] == []; // Function: all_equal() @@ -280,30 +278,6 @@ function compare_lists(a, b) = cmps==[]? (len(a)-len(b)) : cmps[0]; -// Function: list_smallest() -// Usage: -// small = list_smallest(list, k) -// Description: -// Returns a set of the k smallest items in list in arbitrary order. The items must be -// mutually comparable with native OpenSCAD comparison operations. You will get "undefined operation" -// errors if you provide invalid input. -// Arguments: -// list = list to process -// k = number of items to return -function list_smallest(list, k) = - assert(is_list(list)) - assert(is_finite(k) && k>=0, "k must be nonnegative") - let( - v = list[rand_int(0,len(list)-1,1)[0]], - smaller = [for(li=list) if(li= k ? [ each smaller, for(i=[1:k-len(smaller)]) v ] : - len(smaller) > k ? list_smallest(smaller, k) : - let( bigger = [for(li=list) if(li>v) li ] ) - concat(smaller, equal, list_smallest(bigger, k-len(smaller) -len(equal))); - // Section: Dealing with duplicate list entries @@ -780,3 +754,27 @@ function group_data(groups, values) = ]; +// Function: list_smallest() +// Usage: +// small = list_smallest(list, k) +// Description: +// Returns a set of the k smallest items in list in arbitrary order. The items must be +// mutually comparable with native OpenSCAD comparison operations. You will get "undefined operation" +// errors if you provide invalid input. +// Arguments: +// list = list to process +// k = number of items to return +function list_smallest(list, k) = + assert(is_list(list)) + assert(is_finite(k) && k>=0, "k must be nonnegative") + let( + v = list[rand_int(0,len(list)-1,1)[0]], + smaller = [for(li=list) if(li= k ? [ each smaller, for(i=[1:k-len(smaller)]) v ] : + len(smaller) > k ? list_smallest(smaller, k) : + let( bigger = [for(li=list) if(li>v) li ] ) + concat(smaller, equal, list_smallest(bigger, k-len(smaller) -len(equal))); + diff --git a/tests/test_comparisons.scad b/tests/test_comparisons.scad index 68a6357..a38b4f1 100644 --- a/tests/test_comparisons.scad +++ b/tests/test_comparisons.scad @@ -145,7 +145,7 @@ test_deduplicate_indexed(); module test_all_zero() { assert(all_zero(0)); assert(all_zero([0,0,0])); - assert(all_zero([[0,0,0],[0,0]])); + assert(!all_zero([[0,0,0],[0,0]])); assert(all_zero([EPSILON/2,EPSILON/2,EPSILON/2])); assert(!all_zero(1e-3)); assert(!all_zero([0,0,1e-3])); @@ -215,7 +215,7 @@ module test_all_negative() { assert(!all_negative([3,-1,2])); assert(all_negative([-3,-1,-2])); assert(!all_negative([-3,1,-2])); - assert(all_negative([[-5,-7],[-3,-1,-2]])); + assert(!all_negative([[-5,-7],[-3,-1,-2]])); assert(!all_negative([[-5,-7],[-3,1,-2]])); assert(!all_negative([])); assert(!all_negative(true)); @@ -256,7 +256,7 @@ module test_all_nonnegative() { assert(!all_nonnegative([[-5,-7],[-3,-1,-2]])); assert(!all_nonnegative([[-5,-7],[-3,1,-2]])); assert(!all_nonnegative([[5,7],[3,-1,2]])); - assert(all_nonnegative([[5,7],[3,1,2]])); + assert(!all_nonnegative([[5,7],[3,1,2]])); assert(!all_nonnegative([])); assert(!all_nonnegative(true)); assert(!all_nonnegative(false)); diff --git a/tests/test_linalg.scad b/tests/test_linalg.scad index 08f2060..2582eef 100644 --- a/tests/test_linalg.scad +++ b/tests/test_linalg.scad @@ -136,7 +136,7 @@ module test_null_space(){ function nullcheck(A,dim) = let(v=null_space(A)) - len(v)==dim && all_zero(A*transpose(v),eps=1e-12); + len(v)==dim && all_zero(flatten(A*transpose(v)),eps=1e-12); A = [[-1, 2, -5, 2],[-3,-1,3,-3],[5,0,5,0],[3,-4,11,-4]]; assert(nullcheck(A,1));