여러 지점에서 함수를 평가하는 최적의 방법

Dec 12 2020

이것은 이전 질문에 대한 피기 백입니다. 매개 변수 공간 검색 루틴이 너무 빠릅니까?

여러 점에 대해 상징적 목록을 평가하는 빠른 방법을 찾고 있습니다. 그래서 다음과 같은 상징적 표현 목록이 있다고 가정 해 봅시다.

ListA={a*b*c>0, a*b*(c+1)>0, a*b*(c-1)>0, etc.}

및 형식의 튜플 목록

ListB={{1,1,1}, {1,1,2}, {1,2,1}, {1,2,2}< etc.}

ListB의 각 튜플에 대해 ListA를 평가하고 싶습니다.

ListA/.Thread[{a,b,c} -> ListB[[1]]]
ListA /.Thread[{a,b,c} -> ListB[[2]]]

이제 내 listA는 수만 점 이상을 가질 수 있으며 각 표현식은 100 줄을 넘을 수 있습니다. 내 ListB는 수천만 포인트 이상처럼 거대 할 수 있지만 각 튜플에는 ~ 5 개의 요소 만 있으며 대략 100-1000 튜플 크기로 청크했습니다. 내 질문은 이러한 유형의 교체 / 연결을 신속하게 수행하는 가장 좋은 방법은 무엇입니까?

내 첫 번째 시도가 사용 ParallelMap되었지만 여전히 오랜 시간이 걸렸습니다. 그런 다음 조사 Associations하고 이로 인해 시간이 단축되었지만 ListB의 각 요소를 교체하는 데는 여전히 1.5 ~ 2 초 정도 소요되므로 상당히 줄여야합니다. 다음은 참고 용 MWE입니다.

func = (-2^(1 - px) (-1 + px) px Coth[
       rx sx]^2 (-2 sx y Sech[sx (-rx + x^2 + y^2)]^2 + 
        2 sx y Sech[sx (rx + x^2 + y^2)]^2)^2 (Coth[
         rx sx] (-Tanh[sx (-rx + x^2 + y^2)] + 
          Tanh[sx (rx + x^2 + y^2)]))^(-2 + px) - 
    2^(1 - px) px Coth[
      rx sx] (Coth[
         rx sx] (-Tanh[sx (-rx + x^2 + y^2)] + 
          Tanh[sx (rx + x^2 + y^2)]))^(-1 + 
        px) (-2 sx Sech[sx (-rx + x^2 + y^2)]^2 + 
       2 sx Sech[sx (rx + x^2 + y^2)]^2 + 
       8 sx^2 y^2 Sech[sx (-rx + x^2 + y^2)]^2 Tanh[
         sx (-rx + x^2 + y^2)] - 
       8 sx^2 y^2 Sech[sx (rx + x^2 + y^2)]^2 Tanh[
         sx (rx + x^2 + y^2)]) + 
    2^-px (-1 + px) px Coth[
       rx sx]^2 (-2 sx y Sech[sx (-R - rx + x^2 + y^2)]^2 + 
        2 sx y Sech[sx (-R + rx + x^2 + y^2)]^2)^2 (Coth[
         rx sx] (-Tanh[sx (-R - rx + x^2 + y^2)] + 
          Tanh[sx (-R + rx + x^2 + y^2)]))^(-2 + px) + 
    2^-px px Coth[
      rx sx] (Coth[
         rx sx] (-Tanh[sx (-R - rx + x^2 + y^2)] + 
          Tanh[sx (-R + rx + x^2 + y^2)]))^(-1 + 
        px) (-2 sx Sech[sx (-R - rx + x^2 + y^2)]^2 + 
       2 sx Sech[sx (-R + rx + x^2 + y^2)]^2 + 
       8 sx^2 y^2 Sech[sx (-R - rx + x^2 + y^2)]^2 Tanh[
         sx (-R - rx + x^2 + y^2)] - 
       8 sx^2 y^2 Sech[sx (-R + rx + x^2 + y^2)]^2 Tanh[
         sx (-R + rx + x^2 + y^2)]) + 
    2^-px (-1 + px) px Coth[
       rx sx]^2 (-2 sx y Sech[sx (R - rx + x^2 + y^2)]^2 + 
        2 sx y Sech[sx (R + rx + x^2 + y^2)]^2)^2 (Coth[
         rx sx] (-Tanh[sx (R - rx + x^2 + y^2)] + 
          Tanh[sx (R + rx + x^2 + y^2)]))^(-2 + px) + 
    2^-px px Coth[
      rx sx] (Coth[
         rx sx] (-Tanh[sx (R - rx + x^2 + y^2)] + 
          Tanh[sx (R + rx + x^2 + y^2)]))^(-1 + 
        px) (-2 sx Sech[sx (R - rx + x^2 + y^2)]^2 + 
       2 sx Sech[sx (R + rx + x^2 + y^2)]^2 + 
       8 sx^2 y^2 Sech[sx (R - rx + x^2 + y^2)]^2 Tanh[
         sx (R - rx + x^2 + y^2)] - 
       8 sx^2 y^2 Sech[sx (R + rx + x^2 + y^2)]^2 Tanh[
         sx (R + rx + x^2 + y^2)]));

parameters = {px, pz, R, rx, rz, sx, sz}
variables = {x, y, z}

Quantifier[coords_, params_] := 
 Function[Evaluate@Join[variables, parameters], Evaluate@(func > 0)][
  Sequence @@ Join[coords, params]]

SpaceA = Tuples[Range[-2, 2, 0.2], 3];

ListA = Quantifier[#1, parameters] & /@ SpaceA;
ListB = Tuples[Range[1, 4, 0.4], 7];
(*ListB contains~2 million elements*)

이제, 평가 ListA를 통해하는 ListB것처럼 계속 것

(AllTrue[ListA /. Thread[parameters -> #], TrueQ]) & /@ ListB
(*Careful running this, it will probably take a few months :( *)

내 문제는

ListA/.Thread[parameters->{1,1,1,1,1,1,1}]

2 초 정도 걸립니다. 따라서 ~ 2 백만 포인트 목록에 대해 이것을 반복하는 것은 1 세기가 걸릴 것입니다.

컴파일 된 함수가 유용할까요? 나는 컴파일 기능을 사용한 경험이 많지 않기 때문에 그것을 탐구하는 것이 유리한지 궁금합니다. 나는 통찰력에 감사드립니다!

최신 정보

@flinty 제안 덕분에 사용 With하면 할당 속도가 상당히 빨라집니다. 짧은 타이밍 실험은 다음과 같습니다.

여기서는 위의 MWE에 QuantifieroverSpace해당합니다 ListA.

ClearAll[\[Epsilon], px, pz, R, rx, rz, sx, sz]
ByteCount[QuantifieroverSpace]

With[{\[Epsilon] = 2, px = 1, pz = 5, R = 1, rx = 2, rz = 2, sx = 2, 
   sz = 2},
  Evaluate@AllTrue[QuantifieroverSpace, TrueQ]] // Timing

AllTrue[QuantifieroverSpace /. 
   Thread[{\[Epsilon], px, pz, R, rx, rz, sx, sz} -> {2, 1, 5, 1, 2, 
      2, 2, 2}], TrueQ] // Timing

(*126992696*)
(*{0.000026, False}*)

(*{2.08846, False}*)

따라서 With대신 사용 ReplaceAll하는 것이 훨씬 더 빠릅니다. 흥미 롭습니다. 내 검색 루틴에서 이것을 구현하고 얼마나 향상되는지 볼 것입니다.

업데이트 2

그래서 내 다음 문제는 인수의 With수에 모듈화 할의 첫 번째 인수가 필요하다는 것 입니다. 즉, {a = 1, b = 1, c = 1} 또는 {a = 1}과 같은 다른 번호. 내 첫 번째는 다음과 같은 일을하는 것입니다.

With[
     {Thread[SymbolList = ArrayofValues]}, 
     ...
     ]

그러나 mathematica는 예를 들어 변수의 값이 1이 되도록 ArrayofValues기호에 값을 할당하고 있습니다 .SymbolLista

init = MapThread[HoldForm[#1=#2]&, {SymbolList, ArrayofValues}];
With[
     Evaluate@ReleaseHold[init],
     ...
     ]

그러나 이것은 같은 일을하여 심볼에 값을 할당합니다. 흥미롭게도 mathematica는 여전히 with첫 번째 인수의 값을 사용 하여 표현식을 실행 하지만 기호에 값을 할당하면 할당을 취소하려는 경우 검색 루틴의 실행 속도가 느려집니다. 어떻게 든 Seting 할당을 중지해야 하지만 a=1변수 수에 동적으로 양식 을 유지해야 합니다.

업데이트 3

추가 조사를 통해 나는 왜 With그렇게 더 빠른지 알아 냈습니다 . 실제로 첫 번째 인수의 값을 표현식으로 대체하지 않기 때문입니다. 예를 들면

a = {l, s};
With[{l = 3, s = 12},
  Print[Evaluate[a]]
  ];

(*{l,s}*)

그래서 나는 큰 상징적 배열 내부의 매개 변수에 값을 할당하는 더 빠른 방법을 찾으려고 노력하고있는 원점으로 돌아 왔다고 생각합니다.

답변

1 SimonWoods Dec 13 2020 at 02:19

이것은 부분적인 답변이지만 ...

귀하의 기능은 매우 복잡하며, 속도를 높이는 것이 값을 제공하는 방법보다 더 중요 할 것입니다. Compile여기 당신의 친구입니다.

cfunc = Compile @@ {Join[variables, parameters], func, 
   CompilationTarget -> "C", "RuntimeOptions" -> "Speed", 
   RuntimeAttributes -> {Listable}}

RepeatedTiming[AllTrue[cfunc @@ Join[SpaceA // Transpose, ListB[[1]]], Positive]]
{0.0051, False}

단일 행에 대해 5ms에서 ListB더 현실적이기는하지만 여전히 오랜 시간이 걸립니다.