Python에서 Mathematica를 사용하는 방법

Sep 22 2020

다음 코드 줄을 사용하여 3D 지오메트리 ( ref ) 를 생성했습니다 . 입력은 edges, vd, vl및 ew다음 형식으로 파이썬에서 온

edges = [(1,2), (1,3), (1,4), (2,5), (2,6), (5,6), (3,4), (3,7), (6,7), (7,8), (2,9)];
vl = [1,2,3,4,5,6,7,8,9]
ew = {(1, 2) : 49.6, (1,3): 74.4, (1, 4) : 49.6, (2,5): 37.2, (2, 6) : 74.4, (5, 6): 49.6, 
     (3, 4) : 37.2, (3, 7):24.8, (6, 7) : 62, (7, 8) : 37.2, (2, 9) : 24.8}
vd = {1:[75., 25., 0], 2:[115., 45., 0], 3:[10., 5., 0], 4:[45., 0, 0], 
      5:[90., 60., 0], 6:[45., 55., 0], 7:[0, 25., 0], 8:[10., 50., 0], 9:[115.,  25.,0]}; 

위의 내용을 Mathematica에서 사용하는 입력 형식으로 수동으로 변환합니다. 이 수동 변환을 피하고 Python에서 Mathematica 코드를 직접 통합하고 실행하는 방법을 알고 싶습니다.

edges = {1 <-> 2, 1 <-> 3, 1 <-> 4, 2 <-> 5, 2 <-> 6, 5 <-> 6, 
   3 <-> 4, 3 <-> 7, 6 <-> 7, 7 <-> 8, 2 <-> 9};

vd = {{75., 25., 0}, {115., 45., 0}, {10., 5., 0}, {45., 0, 0}, 
  {90., 60., 0}, {45., 55., 0}, {0, 25., 0}, {10., 50., 0}, {115.,  25.,0}};

vl = Range[Length@vd];

vcoords = MapIndexed[#2[[1]] -> # &, vd];
ew = {1 \[UndirectedEdge] 2 -> 49.6, 1 \[UndirectedEdge] 3 -> 74.4, 
 1 \[UndirectedEdge] 4 -> 49.6, 2 \[UndirectedEdge] 5 -> 37.2, 
 2 \[UndirectedEdge] 6 -> 74.4, 5 \[UndirectedEdge] 6 -> 49.6, 
 3 \[UndirectedEdge] 4 -> 37.2, 3 \[UndirectedEdge] 7 -> 24.8, 
 6 \[UndirectedEdge] 7 -> 62, 7 \[UndirectedEdge] 8 -> 37.2, 
 2 \[UndirectedEdge] 9 -> 24.8}

g3d = Graph3D[vl, edges, VertexCoordinates -> vcoords, 
  EdgeWeight -> ew, VertexLabels -> Placed["Name", Center], 
  EdgeLabels -> {e_ :> Placed["EdgeWeight", Center]}, 
  VertexSize -> .3, VertexStyle -> Red]
vars3d = Array[Through[{x, y, z}@#] &, Length @ vd];

λ = 1/100.;

obj3d = Total[(Norm[vars3d[[First@#]] - vars3d[[Last@#]]] - # /. ew)^2 & /@ 
  EdgeList[g3d]] +  λ Total[Norm /@ (vars3d - vd)];

lbnd = 0;
ubnd = 500;

solution3d = Last@Minimize[{obj3d, And @@ Thread[lbnd <= Join @@ vars3d <= ubnd]}, 
    Join @@ vars3d];

edgeLengths3d = # -> Norm[vars3d[[First@#]] - vars3d[[Last@#]]] /. 
     solution3d & /@ EdgeList[g3d];

Grid[Prepend[{#, # /. ew, # /. edgeLengths3d} & /@ 
   EdgeList[g3d], {"edge", "EdgeWeight", "Edge Length"}], 
 Dividers -> All]

진행 방법에 대한 제안과 Python의 Mathematica 인터페이스가 정말 도움이 될 것입니다.

편집 : 아래 게시 된 답변은 .NET을 사용하여 Python에서 입력 인수를 전달하는 데 도움이됩니다 PythonExpression. 다음으로 파이썬 스크립트에서 이러한 Mathematica 표현식을 평가하고 싶습니다. 아래 의견에 따라 wolframclient를 설치하고 다음을 수행했습니다.

from wolframclient.evaluation import WolframLanguageSession
session = WolframLanguageSession()
from wolframclient.language import wlexpr
session.evaluate(wlexpr('')) # I would like to know how to inclide Mathematica expressions here

EDIT2 : 할 수 있습니까

session.evaluate(wlexpr(
'edges = {1 <-> 2, 1 <-> 3, 1 <-> 4, 2 <-> 5, 2 <-> 6, 5 <-> 6, 3 <-> 4, 3 <-> 7, 6 <-> 7, 7 <-> 8, 2 <-> 9};'

'vd = {{75., 25., 0}, {115., 45., 0}, {10., 5., 0}, {45., 0, 0},{90., 60., 0}, {45., 55., 0}, {0, 25., 0}, {10., 50., 0}, {115.,  25.,0}};'

'vl = Range[Length@vd];'))

나는 시도했다.

from wolframclient.evaluation import WolframLanguageSession
session = WolframLanguageSession()
from wolframclient.language import wlexpr


session.evaluate(wlexpr(
'edges = {1 <-> 2, 1 <-> 3, 1 <-> 4, 2 <-> 5, 2 <-> 6, 5 <-> 6, 3 <-> 4, 3 <-> 7, 6 <-> 7, 7 <-> 8, 2 <-> 9};'

'vd = {{75., 25., 0}, {115., 45., 0}, {10., 5., 0}, {45., 0, 0},{90., 60., 0}, {45., 55., 0}, {0, 25., 0}, {10., 50., 0}, {115.,  25.,0}};'

'vl = Range[Length@vd];'
'vcoords = MapIndexed[#2[[1]] -> # &, vd];'
'ew = {1 \[UndirectedEdge] 2 -> 49.6, 1 \[UndirectedEdge] 3 -> 74.4,'
'1 \[UndirectedEdge] 4 -> 49.6, 2 \[UndirectedEdge] 5 -> 37.2,'
'2 \[UndirectedEdge] 6 -> 74.4, 5 \[UndirectedEdge] 6 -> 49.6,'
'3 \[UndirectedEdge] 4 -> 37.2, 3 \[UndirectedEdge] 7 -> 24.8,'
'6 \[UndirectedEdge] 7 -> 62, 7 \[UndirectedEdge] 8 -> 37.2,'
'2 \[UndirectedEdge] 9 -> 24.8};'

'g3d = Graph3D[vl, edges, VertexCoordinates -> vcoords,EdgeWeight -> ew, VertexLabels -> Placed["Name", Center],'
'EdgeLabels -> {e_ :> Placed["EdgeWeight", Center]},'
'VertexSize -> .3, VertexStyle -> Red];'

'vars3d = Array[Through[{x, y, z}@#] &, Length @ vd];'
'λ = 1/100.;'
'obj3d = Total[(Norm[vars3d[[First@#]] - vars3d[[Last@#]]] - # /. ew)^2 & /@EdgeList[g3d]] +  λ Total[Norm /@ (vars3d - vd)];'
'lbnd = 0;'
'ubnd = 500;'

'solution3d = Last@Minimize[{obj3d, And @@ Thread[lbnd <= Join @@ vars3d <= ubnd]},Join @@ vars3d];'

'edgeLengths3d = # -> Norm[vars3d[[First@#]] - vars3d[[Last@#]]] /.solution3d & /@ EdgeList[g3d];'

'Grid[Prepend[{#, # /. ew, # /. edgeLengths3d} & /@EdgeList[g3d], {"edge", "EdgeWeight", "Edge Length"}],Dividers -> All];'

'z1 = Values[solution3d] // Partition[#, 3] &;'

'theFile = File["op.txt"];'

'Export[theFile, z1, "Table"];'
    ))

하지만 다음과 같은 오류가 발생합니다.

String expected at position 1 in StringForm[MessageName[General, msgl], $MessageList]. Undefined message MessageName[Message, msgl] with arguments {$MessageList} The problem may be unbounded. Specifying a value for MaxIterations greater than 5000 may improve the solution. String expected at position 1 in StringForm[MessageName[General, msgl], $MessageList].
Undefined message MessageName[Message, msgl] with arguments {$MessageList} String expected at position 1 in StringForm[MessageName[General, msgl], $MessageList].
Further output of MessageName[StringForm, string] will be suppressed during this calculation.
The problem may be unbounded. Specifying a value for MaxIterations greater than 5000 may improve the solution.
String expected at position 1 in StringForm[MessageName[General, msgl], $MessageList]. Undefined message MessageName[Message, msgl] with arguments {$MessageList} The problem may be unbounded. Specifying a value for MaxIterations greater than 5000 may improve the solution. String expected at position 1 in StringForm[MessageName[General, msgl], $MessageList].
Undefined message MessageName[Message, msgl] with arguments {$MessageList} String expected at position 1 in StringForm[MessageName[General, msgl], $MessageList].
Further output of MessageName[StringForm, string] will be suppressed during this calculation.
The problem may be unbounded. Specifying a value for MaxIterations greater than 5000 may improve the solution.

이 문제를 어떻게 해결할 수 있는지 제안 해 주시겠습니까? 아래와 같이 MMA 노트북에서 같은 표현을 실행하는데 문제가 없었습니다.

답변

3 M.R. Sep 23 2020 at 02:06

Mathematica에서 원하는 작업을 수행하는 한 가지 방법이 있습니다.

첫째, "PythonExpression"을 사용하면 가져 오기 / 내보내기에 편리 할 수 ​​있습니다.

{edges,vl,ew,vd}=ImportString[#,"PythonExpression"]&/@ {"[(1,2),(1,3),(1,4),(2,5),(2,6),(5,6),(3,4),(3,7),(6,7),(7,8),(2,9)]",
"[1,2,3,4,5,6,7,8,9]","{(1,2):49.6,(1,3):74.4,(1,4):49.6,(2,5):37.2,(2,6):74.4,(5,6):49.6,(3,4):37.2,(3,7):24.8,(6,7):62,(7,8):37.2,(2,9):24.8}",
"{1:[75.,25.,0],2:[115.,45.,0],3:[10.,5.,0],4:[45.,0,0],5:[90.,60.,0],6:[45.,55.,0],7:[0,25.,0],8:[10.,50.,0],9:[115.,25.,0]}"};

불행히도 그래프는 아직 연관성과 작동하지 않으므로 목록이 필요하며 모서리는 UndirectedEdge또는 DirectedEdge다음 과 같은 기호를 사용해야합니다 .

edges = UndirectedEdge @@@ edges; vcoords = List @@ vd; 
ew = Normal @ KeyMap[UndirectedEdge @@ # &,ew];
g3d = Graph3D[vl, edges, VertexCoordinates -> vcoords, 
      EdgeWeight->ew, VertexLabels->Placed["Name",Center], 
      EdgeLabels->{e_:>Placed["EdgeWeight",Center]}, VertexSize->.5, BaseStyle->16]

계산은 거의 작동했지만 가장자리를 규칙으로 만들어야했습니다.

vars3d = Array[Through[{x, y, z}@#] &, Length@vd];
\[Lambda] = 1/100.; lbnd = 0; ubnd = 500;
obj3d = Total[(Norm[vars3d[[First@#]] - vars3d[[Last@#]]] - # /. (Rule @@@ ew))^2 & /@ EdgeList[g3d]] + \[Lambda] * Total[Norm /@ (vars3d - Values@vd)];
solution3d = Last @ Minimize[{obj3d, And @@ Thread[lbnd <= Join @@ vars3d <= ubnd]}, Join @@ vars3d]

그런 다음 잘 작동합니다.

edgeLengths3d = # -> Norm[vars3d[[First@#]] - vars3d[[Last@#]]] /. 
     solution3d & /@ EdgeList[g3d];
ResourceFunction["PrettyGrid"][{#, # /. ew, # /. edgeLengths3d} & /@ 
  EdgeList[g3d],  "ColumnHeadings" -> {"edge", "EdgeWeight", "Edge Length"}]

2 DanielHuber Sep 25 2020 at 17:47

죄송합니다. 제가 착각하여 Python의 MMA를 사용하고 싶은 것을 기억하지 못했습니다. ExternalEvaluate [ "Python", str]은 Python이 아닌 MMA 명령입니다.

Python에서 MMA 입력을 제공하는 방법은 "https://reference.wolfram.com/language/workflow/EvaluateAWolframLanguageExpressionFromPython.html"에 설명되어 있습니다.

Python을 시작한 후 Python에서 실행합니다.

from wolframclient.evaluation import WolframLanguageSession

session = WolframLanguageSession()

from wolframclient.language import wlexpr

session.evaluate(wlexpr('myCommandString'))

여기서 myCommandString은 Mathematica 문이있는 문자열입니다. 예 : Python :

myCommandString="a=1;b=2;a+b" 

또는 이것을 여러 줄로 원할 경우 :

myCommandString="a=1;"

myCommandString=myCommandString+"b=2;"

myCommandString=myCommandString+"a+b"

도움이 되었기를 바랍니다.

1 DorianB. Sep 25 2020 at 16:51

여러 줄에 걸쳐있는 코드 블록이있는 경우 .m 파일에 넣고 Getpython의 파일 에 넣는 것이 유용 할 수 있습니다 . 예를 들면 다음과 같습니다.

먼저 파일을 만들고 평가할 Wolfram 언어 코드를 작성합니다. 파일을 /tmp/test.m.

이제 Python에서 :

from wolframclient.evaluation import WolframLanguageSession
from wolframclient.language import wl

# important note: the session is automatically closed.
with WolframLanguageSession() as s:
    s.evaluate(wl.Get('/tmp/test.m'))

닫는 것을 잊지 마십시오. WolframLanguageSession그렇지 않으면 고아 커널을 얻게됩니다 (자세한 내용은 여기 ).

보시다시피 평가 단계는 이제 한 줄에 맞습니다. 좋아하는 편집기에서 코드를 자유롭게 업데이트 할 수 있습니다. 이것이 바로 제가 초기 코드로했던 일입니다. 저는 방금 두 개의 누락 된 세미콜론을 추가하고 나중에 수행 할 결과를 내보냈습니다.

내 /tmp/test.m파일 은 다음과 같습니다 .

edges = {1 <-> 2, 1 <-> 3, 1 <-> 4, 2 <-> 5, 2 <-> 6, 5 <-> 6, 
   3 <-> 4, 3 <-> 7, 6 <-> 7, 7 <-> 8, 2 <-> 9};

vd = {{75., 25., 0}, {115., 45., 0}, {10., 5., 0}, {45., 0, 0}, {90., 
    60., 0}, {45., 55., 0}, {0, 25., 0}, {10., 50., 0}, {115., 25., 
    0}};

vl = Range[Length@vd];

vcoords = MapIndexed[#2[[1]] -> # &, vd];
ew = {1 \[UndirectedEdge] 2 -> 49.6, 1 \[UndirectedEdge] 3 -> 74.4, 
  1 \[UndirectedEdge] 4 -> 49.6, 2 \[UndirectedEdge] 5 -> 37.2, 
  2 \[UndirectedEdge] 6 -> 74.4, 5 \[UndirectedEdge] 6 -> 49.6, 
  3 \[UndirectedEdge] 4 -> 37.2, 3 \[UndirectedEdge] 7 -> 24.8, 
  6 \[UndirectedEdge] 7 -> 62, 7 \[UndirectedEdge] 8 -> 37.2, 
  2 \[UndirectedEdge] 9 -> 24.8};

g3d = Graph3D[vl, edges, VertexCoordinates -> vcoords, 
  EdgeWeight -> ew, VertexLabels -> Placed["Name", Center], 
  EdgeLabels -> {e_ :> Placed["EdgeWeight", Center]}, 
  VertexSize -> .3, VertexStyle -> Red];
vars3d = Array[Through[{x, y, z}@#] &, Length@vd];

\[Lambda] = 1/100.;

obj3d = Total[(Norm[vars3d[[First@#]] - vars3d[[Last@#]]] - # /. 
         ew)^2 & /@ EdgeList[g3d]] + \[Lambda] Total[
     Norm /@ (vars3d - vd)];

lbnd = 0;
ubnd = 500;

solution3d = 
  Last@Minimize[{obj3d, 
     And @@ Thread[lbnd <= Join @@ vars3d <= ubnd]}, Join @@ vars3d];

edgeLengths3d = # -> Norm[vars3d[[First@#]] - vars3d[[Last@#]]] /. 
     solution3d & /@ EdgeList[g3d];

z1 = Values[solution3d] // Partition[#, 3] &;
Export["/tmp/result.txt", z1, "Table"];
```