Share your ideas for the JMP Scripting Unsession at Discovery Summit by September 17th. We hope to see you there!
Choose Language Hide Translation Bar
0 Kudos

Stronger built-in library functions for Matrices

Function 1: Ability to find common and uncommon elements between matrices
I am unaware of an inbuilt function that is capable of determining the common and uncommon elements between two or more matrices when they have uneven # of elements. The only way I am aware of achieving this in JSL is as follows other than actuallly throwing the data into data tables. 

 

A = Associative Array(Random Index(10,6)); 
Show(A); 
B = Associative Array(Random Index(10,6)); 
Show(B); 

Intersection = A ; 
Intersection << Intersect(B); 
Print(Intersection << Get Keys);

 The approach demonstrated @gzmorgan0  below applies only for matrices with same # of elements 

Function 2: Ability to sort a matrix while retaining the position of the elements (https://community.jmp.com/t5/Discussions/Sort-a-matrix/m-p/85678#M38246)

Tracking Number: 7612697963

Defect ID: S1491719, S1491732

9 Comments
Super User

You should investigate the loc() function for matrices. If you want to find non-"common" values use loc( A != B ) or loc( Abs(A-B) >0 );

Also look up Compare Data Tables 

A = Random Index(10,6); 
Show(A); 
B = Random Index(10,6); 
Show(B); 

show(loc(A==B));

//Repeat 10 times
For (i=1, i<=10, i++,
	X = J(5,3,RandomInteger(1,10));
	Y = J(5,3,RandomInteger(1,10));
	show(X, Y, Loc( X-Y ==0), Loc(X==Y));
);

//Note be careful if the values are "floating" numbers 5 might be stored as 5.000000001 or 4.999999999
//you might want to use Loc( Abs(X-Y) < 1e-32) some "fuzz factor"

 

Level VIII

@gzmorgan0,
        Thank you for your response. I tried your advice and here is my take : 

 

Clear Log(); Clear Globals(); 

A = Random Index(10,6); 
Show(A); 
B = Random Index(10,6); 
Show(B); 

show(loc(A==B));
show(loc(A!=B)); 

Results of Run: 

 

image.png

Common elements are 2,4,7 and 9 . However the above returns only the positions where the elements are the same in the respective positions 

Uncommon elements are in positions 2,3,4 and 5 which again is not the uncommon elements between the two matrices but just positions where elements are not same. 

 

 

Super User

Your original post stated "I am unaware of an inbuilt function that is capable of determining the common and uncommon elements between two or more matrices."

 

Each element in a matrix consists of a value and a position. Hence,  I used the loc() function to find common amd uncommon elements.  Your post would have been more precise if you had requested common and uncommon values.

 

Note, in case you are interested you can use the indices to get common and uncommon values as well as matched matrices and unmatched matrices.

A= [2,3,4,7,8,9];
B= [2,4,5,6,7,9];
m_idx = loc(A==B);
u_idx = loc(A!=B);

m_mat  = A[m_idx];
u_matA = A[u_idx];
u_matB = B[u_idx];

show(m_mat, u_matA, u_matB);

//or you can give a match or empty or unmatched and empty


x = J(5,4,RandomInteger(1,4));
y = J(5,4,RandomInteger(1,4));

e_mat  = J(5,4,empty());
m_idx2 = loc(x==y);
u_idx2 = loc(x!=y);
matched_mat = e_mat;
matched_mat[m_idx2] = x[m_idx2];
unmatched_x = e_mat;
unmatched_y = e_mat;
unmatched_x[u_idx2] = x[u_idx2];
unmatched_y[u_idx2] = y[u_idx2];
show(x, y, matched_mat,unmatched_x,unmatched_y);

However, matrices are numeric.  For JSLC v2, we provided several functions where JMP 13 had limitations: The two we use most often are (1) LCombine() that finds the union or intersection of lists of objects or matrices. The lists can contain strings, expressions, etc. (2)LFunc()  that allows a usr to define a function that is applied to each element in the list, for example, Contains() so the user is not required to script a for loop.

 

 

 

 

Level VIII

@gzmorgan0
      What does JSLC stand for ? 

Super User

JSL Companion,  Applications of the JMP Scripting Language, 2nd Edition.

Level VIII

@gzmorgan0,
        Thank you. Also an update to our previous conversation, I don't think the approach you recommend would work if the matrices had different # of rows or # of columns depending on whether it is a row vector or a column vector, would it ? 

Level VIII

In R, the same is achieved by : 

 

RSample.png


In Matlab, this is achieved by: 

MatlabSample.jpg

Super User

@uday_guntupalli I think your suggestion suggestion of an IsMember() function, or Intersect is a good one. However, your example only refers to matrices, numeric values. This would be a good function for lists of any type object.  Long time wishlist items include: union and intersection of sets, and the ability to apply string and list functions to each item in a list. The associated scripts for JSL Companion 2nd edition, included the code for functions for union and intersection, Like and one we call LFunc. You can make a script of commonly used custom functions and include them with the code Include( "mypath/myfuncs.jsl" ); . Then just use them in your script. It would be nice to have some of these features built-in.  Below is a description of LFunc and Like and  and the results of using those functions on your example.  The script that defines these two functions with extensive comments and examples is named JSLC_CustomListFunctions.jsl Regarding your request for original locations, for a column sorted matrixs a simple modification of Ian's sort and use of the Rank() function shoudl give you what you want today.

 

 Functions defined here, are:

  •  LFunc( mylist, expr); where expression is like expr(Substr(x,1,1)).
  • Like(SourceStr,SearchStr); both arguments are text/strings. The second argument uses % and * as wild cards. Note this a simplified Regex.

LFunc can save writing for-loops, Like can save looking up the REGEX syntax.

A = {5,3,4,2};
B = {2,4,4,4,6,8};

_xx = LFunc(A, expr(Loc(B,x)));          //returns {[], [], [2, 3, 4], [1]}
_yy = LFunc(A, expr(Contains(B,x)>0 ) ); //returns {0, 0, 1, 1}
_zz = LFunc(B, expr(Contains(A,x)));     //returns {4, 3, 3, 3, 0, 0}

  

LFUNC

//------LFunc-------------------------------------------------------------------   
Lfunc = Function( {xList, fExpr/*ex. Expr(Contains(x,"h"))*/},
	{x = {}, i = 1, errCode = 0, errStr = "\!NError bad argument", newExpr},
	If( !Is List( xList ),
		errCode = 1
	);
	If(
		Type( Name Expr( fExpr ) ) == "Name", 
 //if Name then JMP does not recognize the function
			tmp = Trim( Char( Name Expr( fExpr ) ) );
  //extract the function and check if it is contained in the global namespace, if not error!
			If( Namespace( "global" ) << Contains( Word( 1, tmp, ":(" ) ) == 0,
				errCode = errCode + 2
			);,
		Type( Name Expr( fExpr ) ) != "Expression", errCode = errCode + 2
	); 
 //catches typos, returns Name if not a valid function
	//catches typos, returns Name if not a valid function
	If( !Is Expr( Name Expr( fExpr ) ),
		errCode = errCode + 2
	);   //catches syntax
	If(
		!errCode,
			For( i = 1, i <= N Items( xList ), i++,
				newExpr = Substitute( Name Expr( fExpr ), Expr( x ), xList[i] );
				Insert Into( x, Try( newExpr, Empty() ) );
			),
		errCode == 1, Write( errStr || "(1) not a list \!N" ),
		errCode == 2, Write( errStr || "(2) not a valid expression \!N" ),
		errCode == 3, Write( errStr || "s (1) is not a list and (2) is not a valid expression \!N" )
	);
	x//return x
	;
); //End Lfunc
//------------------------------------------------------------------------------   

 

Staff

@gzmorgan0 I really like this LFunc function.