Python으로 구현된 JSL 함수 만들기최근에 저는 Python 팁과 요령에 관해 내부 JMP 강연을 했습니다. 특히 제가 생각하기에 강력하다고 생각하는 한 가지 팁이 있으므로 이를 여러분과 공유하고 싶습니다. Python 함수에 대한 호출을 래핑하는 JSL 함수를 만드는 것입니다. 즉, 이는 Python으로 작성할 수 있지만 JSL 인터페이스가 제공되는 유틸리티 코드입니다. 설명을 쉽게 하기 위해 두 개체를 가져와 함께 추가한 다음 해당 호출을 JSL 함수로 래핑하는 간단한 Python 함수를 구현했습니다. 세 가지 다른 유형의 데이터(숫자, 문자열, 목록)와 두 Python 개체를 함께 추가하는 함수로 시작합니다.
Names Default to Here(1);
one = 1;
two = 2;
author = "Paul Nelson";
devel = "Developer: ";
list1 = { 1, 3, 5, 7 };
list2 = { 2, 4, 6, 8 };
Python Submit("\[
def plus(a,b):
print(a, b)
return a+b
]\");
"+" 연산자를 지원하는 모든 Python 개체는 이 Python 함수로 처리될 수 있습니다.
// Python Execute is an underutilized gem. You can send a list
// of inputs and get a list of results and execute code all in one
// JSL statement.
Python Execute( {one, two}, {result}, "result = plus(one,two)" );
show(result);
결과:
result = plus(one,two)
/*:
1.0
2.0
result = 3;
이것은 일이 재미있어지는 곳입니다! 특히 Python에서 정의한 plus() 함수를 래핑하는 JSL 함수입니다.
// create a JSL function that wraps the the Python function
blow_mind = Function( {first, second}, // parameters
{pyresult}, // local variables
Python Execute( {first, second}, {pyresult}, "pyresult = plus(first,second)");
Return( pyresult ); // value to return
); // end of the definition
// Call the Python function through our JSL function. Good way to extend JSL
// using code written in Python. Could be useful for add-ins.
// Notice the same Python function handling different types of Python objects.
show( blow_mind(devel, author) );
show( blow_mind(list1, list2) );
결과 제공:
//:*/
pyresult = plus(first,second)
/*:
Developer:
Paul Nelson
blow_mind(devel, author) = "Developer: Paul Nelson";
//:*/
pyresult = plus(first,second)
/*:
[1, 3, 5, 7]
[2, 4, 6, 8]
blow_mind(list1, list2) = {1, 3, 5, 7, 2, 4, 6, 8};
우리의 간단한 plus() 함수는 숫자 값의 합은 물론 JSL 함수로 호출할 수 있는 문자열과 목록의 연결도 처리했습니다. JSL 코드의 나머지 부분은 실제로 호출된 내용이 Python에서 발생했다는 사실을 다행히도 인식하지 못합니다.
첨부된 전체 파일입니다.
JSL로 계속 코딩하고 싶지만 특정 함수의 경우 Python으로 작성하는 쉬운 방법이 있다는 것을 알고 있습니다. 그렇다면 Python에서 해당 기능을 구현하는 JSL 함수를 어떻게 생성합니까?
자동화 및 스크립팅Re: Python으로 구현된 JSL 함수 만들기향상된 Python 지원 @Paul_Nelson 에 감사드립니다!
Python Selenium을 사용한 브라우저 스크립팅은 다음을 보여줍니다.
// 1: navigate to jmp.com
nav = Function( {url}, {rc},
Python Execute( {url}, {rc},
"\[
try:
driver.get(url)
rc = "ok"
except Exception as e:
rc = repr(e)
]\" );
return(rc);
);
rc = nav( "https://www.jmp.com/" );
if( rc != "ok", throw("nav: "||char(rc)));
마지막 두 줄은 웹 브라우저가 JMP 웹 사이트를 탐색하도록 래퍼 함수를 호출합니다. JSL 함수는 Paul의 예와 정확히 동일한 방식으로 작동합니다.
Re: Python으로 구현된 JSL 함수 만들기여러 반환 값을 사용하는 전역, 여러 줄 Regex 검색
Add Custom Functions(
New Custom Function(
"hogi",
"Regex",
Function({input, pattern},
SubstituteInto(input,"\!n"," ","\!r", " ") ;
Python Send( input );
Python Send( pattern );
error = Python Submit( "\[
import re
print(input)
matches = re.findall(pattern,input)
]\" );
matches = Python Get( matches );
),
<<DESCRIPTION></DESCRIPTION>Re: Python으로 구현된 JSL 함수 만들기@hogi 에 관한 참고 사항 저는 Function()에 return(matches);이 있어야 한다고 생각합니다. 성명.
또한 Python Execute()를 사용하면 보내기와 받기를 수행할 필요가 없어집니다.
Add Custom Functions(
New Custom Function(
"hogi",
"Regex",
Function({input, pattern},
SubstituteInto(input,"\!n"," ","\!r", " ") ;
Python Execute( {input, pattern}, {matches}, "\[
import re
matches = re.findall(pattern,input)
]\" );
return( matches);
),
<Re: Python으로 구현된 JSL 함수 만들기아, 그렇죠. Python Execute , 훨씬 더 좋습니다 
JSL 함수에서 마지막 표현식은 return() 을 묶지 않은 경우에도 반환 값입니다.
Re: Python으로 구현된 JSL 함수 생성저는 Python에 능숙하지 않지만, xxhash와 같은 몇 가지 Python 라이브러리를 사용하고 싶습니다.
메모리 사용에 대한 질문이 있습니다. 이런 방식으로 Python을 JSL-함수-래핑하고 래핑된 Python 코드에서 Python 객체가 생성되면 JSL 래퍼 함수에 대한 호출이 함수가 호출될 때마다 *새로운* 영구 Python 객체를 생성할까요(예: 함수를 수천만 번 호출하면 메모리를 사용)?
(예:) jmpstart.jsl 코드에서 명명된 Python 객체를 한 번 만들고 프로시저 내에서 해당 객체 하나를 참조하면 어떻게 될까요? 이렇게 하는 게 더 나을까요?
아래는 xxhash로 하려는 일의 예입니다. (참고로 저는 jmpstart.jsl 스크립트에서 xxhash를 Python 환경으로 가져옵니다. JSL이 8바이트 정수를 지원하지 않기 때문에 이 함수에서 JSL float를 내보내는 데 막혔습니다...)
Add Custom Functions(
New Custom Function(
"Global",
"xxhash64",
Function( {str},
{digest},
Python Execute( {str}, {digest}, "digest = xxhash.xxh64( str ).hexdigest()" );
Return( Hex To Number( digest ) );
)
)
)
Re: Python으로 구현된 JSL 함수 생성PS. Hex 다이제스트가 잘못된 IEEE float인 경우가 약 0.8%나 되어서 이 코드가 형편없다는 것을 알아챘습니다. 그래서 프로시저에서 JSL 누락 값이 반환됩니다. 그런데도 저는 여전히 표시된 대로 메모리 관리에 대해 궁금합니다.
Re: Python으로 구현된 JSL 함수 생성hashlib와 base64는 모두 Python 내장 라이브러리입니다.
저는 어제 이 사례를 구체적으로 살펴보려고 했습니다. 최악의 경우 JMP가 실행되는 전체 시간 동안 digest에 대한 단일 참조가 '누출'될 것이라고 말씀드릴 수 있습니다. JMP가 종료되면 Python이 종료되면서 해당 변수가 해제됩니다. Python Set() 코드는 digest 변수를 생성하여 Python 환경의 globals() 사전에 배치합니다. 이를 통해 Python Get()이 이름으로 값을 조회하고 JSL에 값을 반환할 수 있습니다. Python Execute()는 기본적으로 Python Send/Set(), Python Submit(), Python Get()에 대한 편의 함수입니다. 따라서 사전에 digest 에 대한 참조가 있지만 Python Execute()가 범위를 벗어나면 사전만이 참조를 보유해야 합니다. 두 번째 루프에서 값이 새 값으로 덮어쓰이므로 이전 참조가 해제되어 가비지 수집이 해당 메모리를 반환할 수 있습니다.
Re: Python으로 구현된 JSL 함수 생성고맙습니다 폴. 기억에 관해서는 제가 바랐던 것이었습니다. hashlib과 base64를 살펴보겠습니다.
배경: 저는 8바이트 해시를 원했고, JSL 네이티브 MD5 함수를 사용하여 8바이트로 잘라낸 해시를 작성했습니다. 하지만 제 문자열 입력에서는 해시가 클러스터링되는 것 같습니다. 누군가 xxhash64를 매우 무작위로 분포된 해시 값으로 추천했습니다. 그래서 저는 그것을 사용했고 잘 분포된 해시를 제공하는 것 같았습니다.
언급했듯이 xxhash64는 longint를 방출할 수 있지만, 저는 그것을 JSL로 전달할 수 없습니다. 저는 결과를 JSL BLOB로 전달할 수 있지만, JMP는 제가 해시를 사용하고자 하는 LINK ID로 BLOBS를 사용할 수 없게 합니다. 원래 질문과는 약간 다르지만, 만약 생각이 있다면, 정말 감사하겠습니다.
Re: Python으로 구현된 JSL 함수 생성P.S. 16진수의 문자열 값을 내 링크 ID로 사용할 수도 있지만, 나는 작고 빠른 것을 갈망했습니다. 나는 ~8000만 개의 행이 있는 테이블을 다루고 있습니다.
Re: Python으로 구현된 JSL 함수 생성@john_madden JMP의 64비트 배정밀도 숫자는 -2^52 .. 2^52의 부호 있는 정수를 보관할 수 있습니다. hextonumber를 사용하면 16진수 해시의 13진수 숫자를 보관하고 잘못된 부동 소수점 숫자에 대한 질문을 피할 수 있다고 생각합니다. 하지만 52비트로는 충분하지 않을 것입니다.
저도 이 동네에서 놀았는데, 이 생일 공격 테이블이 유용하다는 걸 알았습니다. 저는 파일의 해시를 사용하여 고유 키를 만들고 얼마나 많은 비트가 필요한지 알고 싶었습니다. 테이블에서 64비트 해시 테이블에 6,100,000개의 항목을 추가하면 충돌 확률이 1/1,000,000이라는 걸 알 수 있습니다.
내 사용 사례에서 파일 서버의 디스크는 1e11이고 일반적인 파일은 1e4 또는 1e7개 파일로 제한됩니다. 64비트 해시는 너무 작고 96이면 괜찮을 것입니다. 물론 256으로 했습니다...

Re: Python으로 구현된 JSL 함수 생성안녕 크레이그. 참 좋네요! 256비트 값에 어떤 JMP 유형을 사용하시나요?
여담이지만, 개발자들이 언젠가 JSL에 MD5보다 더 현대적인 해시 함수를 추가해줬으면 좋겠습니다.
Re: Python으로 구현된 JSL 함수 생성제가 시도한 최신 방법은 괜찮은 것 같습니다.
"Accepts a string as input, and returns a JSL floating point number that encodes a 'nearly'-64-bit hash of the string. The hash is generated using the Python xxhash package with the default (0) seed.<BR />Python returns the 64-bit hash as a 16-character hexadecimal string. If the bits 2-12 are 11111111111, they are changed to 01111111111 before being processed further by JSL.<BR />This avoids generating an IEEE 754 floating point value of NaN or ∞, which JSL would interpret as Missing.<BR />This trick cuts the number of possible floating point exponent values<BR />from 2048 to 2046, resulting in a hash with 2^63 * 2046 possible values (= 1.89e22).<BR />For 10 million different inputs, this should yield a collision probability of roughly 1 in 380 milion<BR />according to Craige's reference if I calculcated right. On my M3 Max MacBook Pro, the routine takes around 26 μsec per iteration with random strings of length 11.
Names Default To Here( 1 );
Add Custom Functions(
New Custom Function(
"Global",
"xxhash64",
Function( {str},
{digest},
Python Execute( {str}, {digest}, "digest = xxhash.xxh64( str ).hexdigest()", echo( 0 ) );
startChars = Substr( digest, 1, 3 );
Hex To Number(
Match( startChars,
"7ff", "3ff" || Substr( digest, 4, 13 ),
"fff", "bff" || Substr( digest, 4, 13 ),
digest
)
);
)
) << Description(
"Accepts a string as input, and returns a JSL floating point number that encodes a 'nearly'-64-bit hash of the string.
Python must have already been initialized as follows:
Python Execute( {}, {},
\!"
import jmputils
jmputils.jpip('install', 'numpy pandas scikit-learn xxhash')
import jmp
import numpy
import pandas as pd
import xxhash
\!""
) //
<<PROTOTYPE></PROTOTYPE>Re: Python으로 구현된 JSL 함수 생성제 추측으로는 크레이그는 16진수 문자열이나 base64로 인코딩된 숫자를 사용하고 있을 겁니다.
Python 통합의 장점 중 하나는 JMP가 '따라잡아' 더 현대적인 해시 함수를 제공할 필요가 없다는 것입니다. Python을 통해 힘을 얻을 수 있습니다. hashlib과 base64를 언급하는 이유 중 하나는 그것들이 Python 표준 라이브러리의 일부이기 때문에 모든 JMP 사용자가 외부 패키지를 설치하지 않고도 사용할 수 있기 때문입니다.
Re: Python으로 구현된 JSL 함수 생성@존_매든 - you want <SPAN class="token number">2</SPAN><SPAN class="token operator">^</SPAN><SPAN class="token number">52</SPAN> <SPAN class="token operator">*</SPAN> <SPAN class="token number">2046</SPAN> rather than <SPAN class="token number">2</SPAN><SPAN class="token operator">^</SPAN><SPAN class="token number">63</SPAN> <SPAN class="token operator">*</SPAN> <SPAN class="token number">2046</SPAN> . Or just use the 64 bit row.
오래전에 JSL 문자열이 메모리에 보관되는 방식을 알고 있었습니다. 제 기억으로는 24자 정도에서 성능이 크게 변경되었습니다. 96비트 버전을 사용하고 24자리 16진수 이하로 유지해야 할 수도 있습니다. 10,000,000개의 문자열의 경우 16GB 머신에서 공간은 1/4GB입니다. 오류가 발생할 확률은 1e-6에서 1e-15로 줄었습니다. 운이 없었다면 전혀 운이 없었을 것입니다 - https://quoteinvestigator.com/2020/09/02/bad-luck/ .
I'm working with python/django/postgresql currently and I store the hex digits as a database key...a 64 character string gives me the 256 bits.
Re: Python으로 구현된 JSL 함수 생성다시 한번, Paul과 Craige에게 감사드립니다. 우연히도, Python 통합 덕분에 저는 이제 Python을 시도하고 배우기에 충분히 흥분했습니다. 여기 있는 IT 동료들이 제 JSL 코드 중 일부를 이해하고 싶어하고 Python과 동등한 것이 무엇인지 항상 묻기 때문입니다. 이 모든 작업에 대해 Paul에게 매우 감사드립니다.
위 스크립트에서 해시 값의 개수 계산도 수정해야 합니다. 제 생각에는 2^64 - 2^63 정도로, 제가 말한 것보다 훨씬 적은 것 같습니다.
해시 값을 저장하는 것과 관련해서, 너무 귀엽게 굴지 말라고 설득했습니다. 16진수 문자만 저장하는 게 결국 더 낫다는 확신을 갖게 해준 것 같습니다. 거대한 테이블에서 조인을 몇 번 해보고 16진수 문자열 열이나 부동 소수점 열에 조인하든, 링크 ID로 문자열이나 부동 소수점을 사용하든 속도에 실제로 차이가 나는지 확인해야 할 것 같습니다.
나중에 큰 JMP 테이블을 RDB로 내보내면 그때 longint로 변환할 수 있을 겁니다.
Re: Python으로 구현된 JSL 함수 생성크레이그가 해시 값의 개수에 관해 말했는데, 당신 말이 전적으로 맞고 저는 다시 혼란스러웠고 당신의 글을 읽지 못했습니다. 2^52 * 2046이 맞습니다.