
// JepSympy.java
// Andrew Davison, ad@coe.psu.ac.th, July 2023

/* Calls the Sympy module in Python. This is a 
   third-part module for  symbolic mathematics
   (https://www.sympy.org/).

   Examples include:
    * simplify, factor, substitute 
    * sums, products
    * derivative, integration
    * printing using ASCII art and mathML
    * limits
    * solving quadratic equations

  Usage:
     > compile JepSympy
     > run JepSympy 

  Based on Python test code in sympyTests.py
*/

import java.util.*;

import jep.*;
import jep.python.*;


public class JepSympy 
{

  public static void main(String[] args) 
                           throws JepException 
  {
    System.out.println("Starting Jep...");
    Interpreter jep = new SharedInterpreter();

    jep.exec("from sympy import *");
    jep.exec("x,y,n = symbols('x,y,n')");

    System.out.println("\nSimplify:");
    jep.exec("expr = (x + y) + (x - y)");
    String res = (String) jep.getValue("str(expr)");
                          // expression --> string
    System.out.println("  " + res);

    jep.exec("expr = 2*x + 3*x - sin(x) - 3*x + 42");
    res = (String) jep.getValue("str(simplify(expr))");
    System.out.println("  " + res);

    jep.exec("expr = x**2 - 2*x - 8");
    res = (String) jep.getValue("str(factor(expr))");
    System.out.println("\nfactors: " + res);

    jep.exec("expr = sin(x) + cos(y)");
    PyObject pyObj = (PyObject)
          jep.getValue("expr.subs({x:1, y:2}).n()");
                 // expression --> PyObject
    System.out.println("\nsubs: " + 
                  PyUtils.getDouble(pyObj.toString()));

    pyObj = (PyObject)
      jep.getValue("Sum(1/(n**2), (n, 1, oo)).doit()");
    System.out.println("\nsum: " + pyObj);

    pyObj = (PyObject)
          jep.getValue("Sum(1/(n**2), (n, 1, oo)).doit().evalf()");   // evaluate result
    System.out.println("sum eval: " + 
             PyUtils.getDouble(pyObj.toString()));

    jep.exec("expr = x**4 + x**3 + x**2 + x + 1");
    pyObj = (PyObject) jep.getValue("expr.diff(x)");
    System.out.println("\ndiff: " + pyObj);

    jep.exec("expr = exp(x)*sin(x) + exp(x)*cos(x)");
    pyObj = (PyObject) jep.getValue("integrate(expr,x)");
    System.out.println("\nindef integral: " + pyObj);

    pyObj = (PyObject) jep.getValue(
              "integrate(sin(x**2), (x, -oo, oo))");
    System.out.println("integral: " + pyObj);

    pyObj = (PyObject)
          jep.getValue("integrate(sin(x**2), (x, -oo, oo)).evalf()");  // evaluate
    System.out.println("integral eval: " +
        PyUtils.getDouble( pyObj.toString()));

    res = (String) jep.getValue("pretty(Integral(sqrt(1/x), x), use_unicode=False)");
    System.out.println("\npretty:\n" + res);  // fancy ASCII

    res = (String) jep.getValue("mathml(Integral(sqrt(1/x), x),  printer='presentation')");   // presentation MathML
    System.out.println("\nmathML:\n" + 
        "<math xmlns = 'http://www.w3.org/1998/Math/MathML'>\n" + 
        res + "\n</math>");

    List<?> roots = (List<?>) jep.getValue(
                        "solve(x**2 - 2, x)");
    System.out.println("\nroots: " + roots);
    for (Object root : roots) {
      PyObject po = (PyObject)
          jep.getValue(root+".evalf()");  // evaluate
      System.out.println("  " +
                      PyUtils.getDouble( po.toString()) );
    }

    jep.exec("a,b,c = symbols('a,b,c')");
    roots = (List<?>) jep.getValue(
            "solve(a*x**2 + b*x + c, x)");
    System.out.println("quad roots: " + roots);
    for (Object root : roots) {
      String sRoot = (String) jep.getValue(
         "pretty(" + root + ", use_unicode=False)");
      System.out.println("  " + sRoot);
    }

    jep.close();
  } // end of main()

} // end of JepSympy class
