Fix for Issue #263

This commit is contained in:
Garth Minette 2020-09-06 17:15:08 -07:00
parent f07efed4bd
commit a9b8f5618a
3 changed files with 145 additions and 144 deletions

115
math.scad
View file

@ -712,6 +712,7 @@ function matrix_inverse(A) =
assert(is_matrix(A,square=true),"Input to matrix_inverse() must be a square matrix") assert(is_matrix(A,square=true),"Input to matrix_inverse() must be a square matrix")
linear_solve(A,ident(len(A))); linear_solve(A,ident(len(A)));
// Function: null_space() // Function: null_space()
// Usage: // Usage:
// null_space(A) // null_space(A)
@ -723,7 +724,7 @@ function null_space(A,eps=1e-12) =
let( let(
Q_R=qr_factor(transpose(A),pivot=true), Q_R=qr_factor(transpose(A),pivot=true),
R=Q_R[1], R=Q_R[1],
zrow = [for(i=idx(R)) if (is_zero(R[i],eps)) i] zrow = [for(i=idx(R)) if (all_zero(R[i],eps)) i]
) )
len(zrow)==0 len(zrow)==0
? [] ? []
@ -900,9 +901,9 @@ function norm_fro(A) =
// Section: Comparisons and Logic // Section: Comparisons and Logic
// Function: is_zero() // Function: all_zero()
// Usage: // Usage:
// is_zero(x); // all_zero(x);
// Description: // Description:
// Returns true if the number passed to it is approximately zero, to within `eps`. // Returns true if the 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, recursively checks if all items in the list are approximately zero.
@ -911,19 +912,19 @@ function norm_fro(A) =
// x = The value to check. // x = The value to check.
// eps = The maximum allowed variance. Default: `EPSILON` (1e-9) // eps = The maximum allowed variance. Default: `EPSILON` (1e-9)
// Example: // Example:
// is_zero(0); // Returns: true. // all_zero(0); // Returns: true.
// is_zero(1e-3); // Returns: false. // all_zero(1e-3); // Returns: false.
// is_zero([0,0,0]); // Returns: true. // all_zero([0,0,0]); // Returns: true.
// is_zero([0,0,1e-3]); // Returns: false. // all_zero([0,0,1e-3]); // Returns: false.
function is_zero(x, eps=EPSILON) = function all_zero(x, eps=EPSILON) =
is_list(x)? (x != [] && [for (xx=x) if(!is_zero(xx,eps=eps)) 1] == []) : is_list(x)? (x != [] && [for (xx=x) if(!all_zero(xx,eps=eps)) 1] == []) :
is_num(x)? approx(x,eps) : is_num(x)? approx(x,eps) :
false; false;
// Function: is_positive() // Function: all_positive()
// Usage: // Usage:
// is_positive(x); // all_positive(x);
// Description: // Description:
// Returns true if the number passed to it is greater than zero. // Returns true if the number passed to it is greater than zero.
// If passed a list, recursively checks if all items in the list are positive. // If passed a list, recursively checks if all items in the list are positive.
@ -931,22 +932,22 @@ function is_zero(x, eps=EPSILON) =
// Arguments: // Arguments:
// x = The value to check. // x = The value to check.
// Example: // Example:
// is_positive(-2); // Returns: false. // all_positive(-2); // Returns: false.
// is_positive(0); // Returns: false. // all_positive(0); // Returns: false.
// is_positive(2); // Returns: true. // all_positive(2); // Returns: true.
// is_positive([0,0,0]); // Returns: false. // all_positive([0,0,0]); // Returns: false.
// is_positive([0,1,2]); // Returns: false. // all_positive([0,1,2]); // Returns: false.
// is_positive([3,1,2]); // Returns: true. // all_positive([3,1,2]); // Returns: true.
// is_positive([3,-1,2]); // Returns: false. // all_positive([3,-1,2]); // Returns: false.
function is_positive(x) = function all_positive(x) =
is_list(x)? (x != [] && [for (xx=x) if(!is_positive(xx)) 1] == []) : is_list(x)? (x != [] && [for (xx=x) if(!all_positive(xx)) 1] == []) :
is_num(x)? x>0 : is_num(x)? x>0 :
false; false;
// Function: is_negative() // Function: all_negative()
// Usage: // Usage:
// is_negative(x); // all_negative(x);
// Description: // Description:
// Returns true if the number passed to it is less than zero. // Returns true if the number passed to it is less than zero.
// If passed a list, recursively checks if all items in the list are negative. // If passed a list, recursively checks if all items in the list are negative.
@ -954,23 +955,23 @@ function is_positive(x) =
// Arguments: // Arguments:
// x = The value to check. // x = The value to check.
// Example: // Example:
// is_negative(-2); // Returns: true. // all_negative(-2); // Returns: true.
// is_negative(0); // Returns: false. // all_negative(0); // Returns: false.
// is_negative(2); // Returns: false. // all_negative(2); // Returns: false.
// is_negative([0,0,0]); // Returns: false. // all_negative([0,0,0]); // Returns: false.
// is_negative([0,1,2]); // Returns: false. // all_negative([0,1,2]); // Returns: false.
// is_negative([3,1,2]); // Returns: false. // all_negative([3,1,2]); // Returns: false.
// is_negative([3,-1,2]); // Returns: false. // all_negative([3,-1,2]); // Returns: false.
// is_negative([-3,-1,-2]); // Returns: true. // all_negative([-3,-1,-2]); // Returns: true.
function is_negative(x) = function all_negative(x) =
is_list(x)? (x != [] && [for (xx=x) if(!is_negative(xx)) 1] == []) : is_list(x)? (x != [] && [for (xx=x) if(!all_negative(xx)) 1] == []) :
is_num(x)? x<0 : is_num(x)? x<0 :
false; false;
// Function: is_nonpositive() // Function: all_nonpositive()
// Usage: // Usage:
// is_nonpositive(x); // all_nonpositive(x);
// Description: // Description:
// Returns true if the number passed to it is less than or equal to zero. // Returns true if the 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. // If passed a list, recursively checks if all items in the list are nonpositive.
@ -978,23 +979,23 @@ function is_negative(x) =
// Arguments: // Arguments:
// x = The value to check. // x = The value to check.
// Example: // Example:
// is_nonpositive(-2); // Returns: true. // all_nonpositive(-2); // Returns: true.
// is_nonpositive(0); // Returns: true. // all_nonpositive(0); // Returns: true.
// is_nonpositive(2); // Returns: false. // all_nonpositive(2); // Returns: false.
// is_nonpositive([0,0,0]); // Returns: true. // all_nonpositive([0,0,0]); // Returns: true.
// is_nonpositive([0,1,2]); // Returns: false. // all_nonpositive([0,1,2]); // Returns: false.
// is_nonpositive([3,1,2]); // Returns: false. // all_nonpositive([3,1,2]); // Returns: false.
// is_nonpositive([3,-1,2]); // Returns: false. // all_nonpositive([3,-1,2]); // Returns: false.
// is_nonpositive([-3,-1,-2]); // Returns: true. // all_nonpositive([-3,-1,-2]); // Returns: true.
function is_nonpositive(x) = function all_nonpositive(x) =
is_list(x)? (x != [] && [for (xx=x) if(!is_nonpositive(xx)) 1] == []) : is_list(x)? (x != [] && [for (xx=x) if(!all_nonpositive(xx)) 1] == []) :
is_num(x)? x<=0 : is_num(x)? x<=0 :
false; false;
// Function: is_nonnegative() // Function: all_nonnegative()
// Usage: // Usage:
// is_nonnegative(x); // all_nonnegative(x);
// Description: // Description:
// Returns true if the number passed to it is greater than or equal to zero. // Returns true if the 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. // If passed a list, recursively checks if all items in the list are nonnegative.
@ -1002,17 +1003,17 @@ function is_nonpositive(x) =
// Arguments: // Arguments:
// x = The value to check. // x = The value to check.
// Example: // Example:
// is_nonnegative(-2); // Returns: false. // all_nonnegative(-2); // Returns: false.
// is_nonnegative(0); // Returns: true. // all_nonnegative(0); // Returns: true.
// is_nonnegative(2); // Returns: true. // all_nonnegative(2); // Returns: true.
// is_nonnegative([0,0,0]); // Returns: true. // all_nonnegative([0,0,0]); // Returns: true.
// is_nonnegative([0,1,2]); // Returns: true. // all_nonnegative([0,1,2]); // Returns: true.
// is_nonnegative([0,-1,-2]); // Returns: false. // all_nonnegative([0,-1,-2]); // Returns: false.
// is_nonnegative([3,1,2]); // Returns: true. // all_nonnegative([3,1,2]); // Returns: true.
// is_nonnegative([3,-1,2]); // Returns: false. // all_nonnegative([3,-1,2]); // Returns: false.
// is_nonnegative([-3,-1,-2]); // Returns: false. // all_nonnegative([-3,-1,-2]); // Returns: false.
function is_nonnegative(x) = function all_nonnegative(x) =
is_list(x)? (x != [] && [for (xx=x) if(!is_nonnegative(xx)) 1] == []) : is_list(x)? (x != [] && [for (xx=x) if(!all_nonnegative(xx)) 1] == []) :
is_num(x)? x>=0 : is_num(x)? x>=0 :
false; false;

View file

@ -100,104 +100,104 @@ module test_is_matrix() {
test_is_matrix(); test_is_matrix();
module test_is_zero() { module test_all_zero() {
assert(is_zero(0)); assert(all_zero(0));
assert(is_zero([0,0,0])); assert(all_zero([0,0,0]));
assert(is_zero([[0,0,0],[0,0]])); assert(all_zero([[0,0,0],[0,0]]));
assert(is_zero([EPSILON/2,EPSILON/2,EPSILON/2])); assert(all_zero([EPSILON/2,EPSILON/2,EPSILON/2]));
assert(!is_zero(1e-3)); assert(!all_zero(1e-3));
assert(!is_zero([0,0,1e-3])); assert(!all_zero([0,0,1e-3]));
assert(!is_zero([EPSILON*10,0,0])); assert(!all_zero([EPSILON*10,0,0]));
assert(!is_zero([0,EPSILON*10,0])); assert(!all_zero([0,EPSILON*10,0]));
assert(!is_zero([0,0,EPSILON*10])); assert(!all_zero([0,0,EPSILON*10]));
assert(!is_zero(true)); assert(!all_zero(true));
assert(!is_zero(false)); assert(!all_zero(false));
assert(!is_zero(INF)); assert(!all_zero(INF));
assert(!is_zero(-INF)); assert(!all_zero(-INF));
assert(!is_zero(NAN)); assert(!all_zero(NAN));
assert(!is_zero("foo")); assert(!all_zero("foo"));
assert(!is_zero([])); assert(!all_zero([]));
assert(!is_zero([0:1:2])); assert(!all_zero([0:1:2]));
} }
test_is_zero(); test_all_zero();
module test_is_positive() { module test_all_positive() {
assert(!is_positive(-2)); assert(!all_positive(-2));
assert(!is_positive(0)); assert(!all_positive(0));
assert(is_positive(2)); assert(all_positive(2));
assert(!is_positive([0,0,0])); assert(!all_positive([0,0,0]));
assert(!is_positive([0,1,2])); assert(!all_positive([0,1,2]));
assert(is_positive([3,1,2])); assert(all_positive([3,1,2]));
assert(!is_positive([3,-1,2])); assert(!all_positive([3,-1,2]));
assert(!is_positive([])); assert(!all_positive([]));
assert(!is_positive(true)); assert(!all_positive(true));
assert(!is_positive(false)); assert(!all_positive(false));
assert(!is_positive("foo")); assert(!all_positive("foo"));
assert(!is_positive([0:1:2])); assert(!all_positive([0:1:2]));
} }
test_is_positive(); test_all_positive();
module test_is_negative() { module test_all_negative() {
assert(is_negative(-2)); assert(all_negative(-2));
assert(!is_negative(0)); assert(!all_negative(0));
assert(!is_negative(2)); assert(!all_negative(2));
assert(!is_negative([0,0,0])); assert(!all_negative([0,0,0]));
assert(!is_negative([0,1,2])); assert(!all_negative([0,1,2]));
assert(!is_negative([3,1,2])); assert(!all_negative([3,1,2]));
assert(!is_negative([3,-1,2])); assert(!all_negative([3,-1,2]));
assert(is_negative([-3,-1,-2])); assert(all_negative([-3,-1,-2]));
assert(!is_negative([-3,1,-2])); assert(!all_negative([-3,1,-2]));
assert(is_negative([[-5,-7],[-3,-1,-2]])); assert(all_negative([[-5,-7],[-3,-1,-2]]));
assert(!is_negative([[-5,-7],[-3,1,-2]])); assert(!all_negative([[-5,-7],[-3,1,-2]]));
assert(!is_negative([])); assert(!all_negative([]));
assert(!is_negative(true)); assert(!all_negative(true));
assert(!is_negative(false)); assert(!all_negative(false));
assert(!is_negative("foo")); assert(!all_negative("foo"));
assert(!is_negative([0:1:2])); assert(!all_negative([0:1:2]));
} }
test_is_negative(); test_all_negative();
module test_is_nonpositive() { module test_all_nonpositive() {
assert(is_nonpositive(-2)); assert(all_nonpositive(-2));
assert(is_nonpositive(0)); assert(all_nonpositive(0));
assert(!is_nonpositive(2)); assert(!all_nonpositive(2));
assert(is_nonpositive([0,0,0])); assert(all_nonpositive([0,0,0]));
assert(!is_nonpositive([0,1,2])); assert(!all_nonpositive([0,1,2]));
assert(is_nonpositive([0,-1,-2])); assert(all_nonpositive([0,-1,-2]));
assert(!is_nonpositive([3,1,2])); assert(!all_nonpositive([3,1,2]));
assert(!is_nonpositive([3,-1,2])); assert(!all_nonpositive([3,-1,2]));
assert(!is_nonpositive([])); assert(!all_nonpositive([]));
assert(!is_nonpositive(true)); assert(!all_nonpositive(true));
assert(!is_nonpositive(false)); assert(!all_nonpositive(false));
assert(!is_nonpositive("foo")); assert(!all_nonpositive("foo"));
assert(!is_nonpositive([0:1:2])); assert(!all_nonpositive([0:1:2]));
} }
test_is_nonpositive(); test_all_nonpositive();
module test_is_nonnegative() { module test_all_nonnegative() {
assert(!is_nonnegative(-2)); assert(!all_nonnegative(-2));
assert(is_nonnegative(0)); assert(all_nonnegative(0));
assert(is_nonnegative(2)); assert(all_nonnegative(2));
assert(is_nonnegative([0,0,0])); assert(all_nonnegative([0,0,0]));
assert(is_nonnegative([0,1,2])); assert(all_nonnegative([0,1,2]));
assert(is_nonnegative([3,1,2])); assert(all_nonnegative([3,1,2]));
assert(!is_nonnegative([3,-1,2])); assert(!all_nonnegative([3,-1,2]));
assert(!is_nonnegative([-3,-1,-2])); assert(!all_nonnegative([-3,-1,-2]));
assert(!is_nonnegative([[-5,-7],[-3,-1,-2]])); assert(!all_nonnegative([[-5,-7],[-3,-1,-2]]));
assert(!is_nonnegative([[-5,-7],[-3,1,-2]])); assert(!all_nonnegative([[-5,-7],[-3,1,-2]]));
assert(!is_nonnegative([[5,7],[3,-1,2]])); assert(!all_nonnegative([[5,7],[3,-1,2]]));
assert(is_nonnegative([[5,7],[3,1,2]])); assert(all_nonnegative([[5,7],[3,1,2]]));
assert(!is_nonnegative([])); assert(!all_nonnegative([]));
assert(!is_nonnegative(true)); assert(!all_nonnegative(true));
assert(!is_nonnegative(false)); assert(!all_nonnegative(false));
assert(!is_nonnegative("foo")); assert(!all_nonnegative("foo"));
assert(!is_nonnegative([0:1:2])); assert(!all_nonnegative([0:1:2]));
} }
test_is_nonnegative(); test_all_nonnegative();
module test_approx() { module test_approx() {
@ -975,7 +975,7 @@ module test_null_space(){
function nullcheck(A,dim) = function nullcheck(A,dim) =
let(v=null_space(A)) let(v=null_space(A))
len(v)==dim && is_zero(A*transpose(v),eps=1e-12); len(v)==dim && all_zero(A*transpose(v),eps=1e-12);
A = [[-1, 2, -5, 2],[-3,-1,3,-3],[5,0,5,0],[3,-4,11,-4]]; A = [[-1, 2, -5, 2],[-3,-1,3,-3],[5,0,5,0],[3,-4,11,-4]];
assert(nullcheck(A,1)); assert(nullcheck(A,1));

View file

@ -8,7 +8,7 @@
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,419]; BOSL_VERSION = [2,0,420];
// Section: BOSL Library Version Functions // Section: BOSL Library Version Functions