13
$\begingroup$
comp1a = Flatten[Join[{{0 + 0 i}}, {comp1}]];
Flatten[comp1a[[1 ;; 6]]]

This creates a list of complex values -> comp1a

The first 6 terms in the list are:

{0, -2.04375 + 1.33694 I, -1.0492 + 3.3731 I, -4.95694 + 1.01694 I, 4.61625 - 4.52896 I, 6.66754 - 4.1488 I}

Then I try to pass the list to;

ExternalEvaluate["Python", "import numpy as np; timhist = np.fft.ifft(comp1a); timehist.tolist()"]

and the result is;

Failure Message:"name 'comp1a' is not defined
Tag:PythonError

My question is how do I feed a list developed in Mathematica to a python function called externally

$\endgroup$
8
$\begingroup$

This will not work. Python does not know what mylist is:

mylist = {1, 2, 3, 4};
ExternalEvaluate["Python", "sum(mylist)"]

You must get the value of mylist into Python somehow. This could be done with string replacement:

ExternalEvaluate["Python", "sum(" <>
  StringReplace[ToString[mylist], {"{" -> "[", "}" -> "]"}]
  <> ")"]

... though as Jason .B noted in the comments, it's much simpler to write this as a TemplateExpression:

ExternalEvaluate["Python", "sum(<* mylist *>)"]

For complex numbers, you'll need to rewrite them as a complex type first before you can feed them to Python:

createcomplex[z_?NumericQ] := 
 "complex(" <> ToString[Re[z]] <> "," <> ToString[Im[z]] <> ")"

createcomplex[-2.7 + 3.5 I]
(* result: "complex(-2.7,3.5)" *)

Or more simply, using templates:

toPyComplexStr[z_?NumericQ] := 
 TemplateApply["complex(<* Re[z] *>, <* Im[z] *>)", z]

There is however, a better way in the documentation which doesn't depend on text substitution and it uses an external session:

session = StartExternalSession["Python"];
ExternalEvaluate[session, <|
  "Command" -> "sum",
  "Arguments" -> {NumericArray[{1 + I, 2.3 - I, 5.7 - 2.3 I, 7}, 
     "ComplexReal32"]}
  |>]
(* result: 16. - 2.3 I *)

Let's use it for your problem:

session = StartExternalSession["Python"];
result = Last@
  ExternalEvaluate[
   session, {"import numpy as np", <|"Command" -> "np.fft.ifft", 
     "Arguments" -> {NumericArray[{0, -2.04375 + 1.33694 I, -1.0492 + 
          3.3731 I, -4.95694 + 1.01694 I, 4.61625 - 4.52896 I, 
         6.66754 - 4.1488 I}, "ComplexReal32"]}|>}]
Normal[result]
(* result: {0.538983 - 0.491797 I, -1.01814 - 2.38259 I, -1.15996 + 0.0605042 I, 
 0.650033 + 0.10651 I, -1.85749 + 0.939762 I, 2.84658 + 1.76761 I} *)

... and notice that this result matches up with InverseFourier if you use FourierParameters -> {1, -1}:

InverseFourier[{0, -2.04375 + 1.33694 I, -1.0492 + 3.3731 I, -4.95694 + 1.01694 I, 4.61625 - 4.52896 I, 6.66754 - 4.1488 I}, 
  FourierParameters -> {1, -1}]

(* result: {0.538983 - 0.491797 I, -1.01814 - 2.38259 I, -1.15996 + 0.0605042 I, 
 0.650033 + 0.10651 I, -1.85749 + 0.939762 I, 2.84658 + 1.76761 I} *)
| improve this answer | |
$\endgroup$
  • $\begingroup$ try ExternalEvaluate["Python", "sum(<* mylist *>)"] $\endgroup$ – Jason B. Jul 24 at 18:28
  • $\begingroup$ Thanks Jason, that's a TemplateExpression right? $\endgroup$ – flinty Jul 24 at 18:30
  • $\begingroup$ That seems to be the case. I usually forget what the syntax every time, and scramble around for the chat log where I learned it. Now I know it has a name, and it's listed in the details section for ExternalEvaluate $\endgroup$ – Jason B. Jul 24 at 18:34
  • $\begingroup$ Thanks Jason. Your expression works for Real values. Now I just need to convert things to work with complex numbers $\endgroup$ – tom houston Jul 24 at 18:35
  • 1
    $\begingroup$ @tomhouston - look at the last bit of code in this answer. If you create a complex-valued NumericArray you can pass it into python (using the short or long syntax) and it will be typed correctly. $\endgroup$ – Jason B. Jul 24 at 18:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.