All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cc.redberry.core.solver.ExternalSolver Maven / Gradle / Ivy

Go to download

Redberry is an open source computer algebra system designed for tensor manipulation. It implements basic computer algebra system routines as well as complex tools for real computations in physics. This is Redberry core, which contains the implementation of the basic computer algebra routines and general-purpose transformations.

There is a newer version: 1.1.10
Show newest version
/*
 * Redberry: symbolic tensor computations.
 *
 * Copyright (c) 2010-2014:
 *   Stanislav Poslavsky   
 *   Bolotin Dmitriy       
 *
 * This file is part of Redberry.
 *
 * Redberry is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Redberry is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Redberry. If not, see .
 */
package cc.redberry.core.solver;

import cc.redberry.core.context.CC;
import cc.redberry.core.context.OutputFormat;
import cc.redberry.core.number.Complex;
import cc.redberry.core.tensor.Expression;
import cc.redberry.core.tensor.Product;
import cc.redberry.core.tensor.Tensor;
import cc.redberry.core.tensor.Tensors;
import cc.redberry.core.tensor.iterator.FromChildToParentIterator;
import cc.redberry.core.transformations.Transformation;
import cc.redberry.core.transformations.TransformationCollection;
import cc.redberry.core.transformations.substitutions.SubstitutionTransformation;
import cc.redberry.core.utils.THashMap;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Tools for solving a symbolic system with external systems (Maple or Mathematica).
 *
 * @author Dmitry Bolotin
 * @author Stanislav Poslavsky
 * @since 1.1.5
 */
public class ExternalSolver {

    /**
     * Solves a system of symbolic equations using Maplesoft Maple installation.
     *
     * @param reducedSystem      a system of symbolic equations
     * @param keepFreeParameters if {@code true} then each solutions family will be in the most general form, otherwise
     *                           some particular solution will be taken for each family of solutions
     * @param mapleBinDir        path to Maple bin directory
     * @param path               path to temporary directory
     * @return solution of {@code reducedSystem}
     * @throws IOException
     * @throws InterruptedException
     */
    public static Expression[][] solveSystemWithMaple(ReducedSystem reducedSystem,
                                                      boolean keepFreeParameters,
                                                      String mapleBinDir,
                                                      String path)
            throws IOException, InterruptedException {
        return solveSystemWithExternalProgram(MapleScriptCreator.INSTANCE, reducedSystem, keepFreeParameters, mapleBinDir, path);
    }


    /**
     * Solves a system of symbolic equations using Wolfram Mathematica installation.
     *
     * @param reducedSystem      a system of symbolic equations
     * @param keepFreeParameters if {@code true} then each solutions family will be in the most general form, otherwise
     *                           some particular solution will be taken for each family of solutions
     * @param mathematicaBinDir  path to directory with Mathematica executables
     * @param path               path to temporary directory
     * @return solution of {@code reducedSystem}
     * @throws IOException
     * @throws InterruptedException
     */
    public static Expression[][] solveSystemWithMathematica(ReducedSystem reducedSystem,
                                                            boolean keepFreeParameters,
                                                            String mathematicaBinDir,
                                                            String path)
            throws IOException, InterruptedException {
        return solveSystemWithExternalProgram(MathematicaScriptCreator.INSTANCE, reducedSystem, keepFreeParameters, mathematicaBinDir, path);
    }

    /**
     * Solves a system of symbolic equations using external program.
     *
     * @param scriptCreator      external engine
     * @param reducedSystem      a system of symbolic equations
     * @param keepFreeParameters if {@code true} then each solutions family will be in the most general form, otherwise
     *                           some particular solution will be taken for each family of solutions
     * @param path               path to temporary directory
     * @return solution of {@code reducedSystem}
     * @throws IOException
     * @throws InterruptedException
     */
    public static Expression[][] solveSystemWithExternalProgram(ExternalScriptCreator scriptCreator,
                                                                ReducedSystem reducedSystem,
                                                                boolean keepFreeParameters,
                                                                String programBinDir,
                                                                String path)
            throws IOException, InterruptedException {
        //create the general form of the inverse and system of linear equations
        final Expression[] equations = reducedSystem.equations.clone();

        /*in order to process equations with Maple we must to replace all tensors
        with indices (they are found only in scalar combinations) with some symbols*/

        //scalar tensor <-> symbol
        THashMap tensorSubstitutions = new THashMap<>();
        //all symbols will have names scalar1,scalar2, etc.

        //processing equations
        int i;
        for (i = 0; i < equations.length; ++i) {
            Expression eq = equations[i];
            //iterating over the whole equation
            FromChildToParentIterator iterator = new FromChildToParentIterator(eq);
            Tensor t;
            while ((t = iterator.next()) != null) {
                if (!(t instanceof Product) || t.getIndices().size() == 0)
                    continue;
                //scalars content
                Tensor[] scalars = ((Product) t).getContent().getScalars();
                for (Tensor scalar : scalars) {
                    if (!tensorSubstitutions.containsKey(scalar)) {
                        //map does not contains rule for current scalar (e.g. k_{i}*k^{i})
                        //adding new rule for the scalar, e.g. k_{i}*k^{i} = scalar2
                        tensorSubstitutions.put(scalar, CC.generateNewSymbol());
                    }
                }
            }
        }

        final Expression[] scalarSubs = new Expression[tensorSubstitutions.size()];
        i = -1;
        for (Map.Entry entry : tensorSubstitutions.entrySet())
            scalarSubs[++i] = Tensors.expression(entry.getKey(), entry.getValue());
        SubstitutionTransformation fullSub = new SubstitutionTransformation(scalarSubs, true);
        for (i = 0; i < equations.length; ++i)
            equations[i] = (Expression) fullSub.transform(equations[i]);


        /*if (scalarSubs.length != 0) {
            StringBuilder scalarsString = new StringBuilder().append('[');
            for (Expression sub : scalarSubs)
                scalarsString.append(sub).append(", ");
            scalarsString.deleteCharAt(scalarsString.length() - 1).deleteCharAt(scalarsString.length() - 1).append(']');
         System.out.println(scalarsString.toString());
        }*/

        /*System.out.println("Reduced solution: " + Arrays.toString(reducedSystem.generalSolutions));
        System.out.println();*/

        scriptCreator.createScript(equations, reducedSystem, path, keepFreeParameters);

        //cleaning previous output
        new File(path + "/equations." + scriptCreator.getScriptExtension() + "Out").delete();

        //running external program
        try {
            Process p = Runtime.getRuntime().exec(programBinDir + "/" + scriptCreator.getScriptExecutionCommand() + " " + path + "/equations." + scriptCreator.getScriptExtension());
            BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
            BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            String line;
            while ((line = bri.readLine()) != null)
                System.out.println(line);
            bri.close();
            while ((line = bre.readLine()) != null)
                System.out.println(line);
            bre.close();
            p.waitFor();
        } catch (IOException | InterruptedException ex) {
            throw new RuntimeException(ex);
        }

        //reading the produced output with the solution
        //allocating resulting coefficients array
        Expression[] coefficientsResults = new Expression[reducedSystem.unknownCoefficients.length];
        //no solutions
        if (!new File(path + "/equations." + scriptCreator.getScriptExtension() + "Out").exists()) {
            return new Expression[0][];
        }
        FileInputStream fstream = new FileInputStream(path + "/equations." + scriptCreator.getScriptExtension() + "Out");
        if (fstream.available() == 0)
            return null;
        DataInputStream in = new DataInputStream(fstream);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String strLine;
        i = -1;

        List solutions = new ArrayList<>();
        //reading resulting solutions from file
        while ((strLine = br.readLine()) != null) {
            if (strLine.equals("//solution")) {
                //solution parser
                Expression[] solution = reducedSystem.generalSolutions.clone();

                //substituting coefficients into general inverse form
                List zeroSubs = new ArrayList<>();
                for (Expression coef : coefficientsResults)
                    if (coef.isIdentity() && !keepFreeParameters)//if current coefficient is free parameter
                    {
                        zeroSubs.add(Tensors.expression(coef.get(0), Complex.ZERO));
                    } else {
                        for (int si = solution.length - 1; si >= 0; --si)
                            solution[si] = (Expression) coef.transform(solution[si]);
                    }
                if (!keepFreeParameters)
                    for (int si = solution.length - 1; si >= 0; --si)
                        solution[si] = (Expression) new TransformationCollection(zeroSubs).transform(solution[si]);


                //substituting the renamed tensors combinations
                for (Expression sub : scalarSubs)
                    for (int si = solution.length - 1; si >= 0; --si)
                        solution[si] = (Expression) sub.transpose().transform(solution[si]);
                solutions.add(solution);
                coefficientsResults = new Expression[reducedSystem.unknownCoefficients.length];
                i = -1;
            } else
                coefficientsResults[++i] = Tensors.parseExpression(strLine);
        }


        in.close();
        return solutions.toArray(new Expression[solutions.size()][]);
    }

    public static interface ExternalScriptCreator {
        void createScript(Expression[] equations, ReducedSystem reducedSystem, String path, boolean keepFreeParams) throws IOException;

        String getScriptExecutionCommand();

        String getScriptExtension();
    }

    public static final class MathematicaScriptCreator implements ExternalScriptCreator {
        public static final MathematicaScriptCreator INSTANCE = new MathematicaScriptCreator();

        private MathematicaScriptCreator() {
        }

        @Override
        public void createScript(Expression[] equations, ReducedSystem reducedSystem, String path, boolean keepFreeParams) throws IOException {
            //creating file with Mathematica code to solve the system of equations
            FileOutputStream output = new FileOutputStream(path + "/equations.mathematica");
            PrintStream file = new PrintStream(output);

            file.append("$equations = {\n");
            int i;
            for (i = 0; ; i++) {
                file.append(equations[i].toString(OutputFormat.WolframMathematica).replace("=", "=="));
                if (i == equations.length - 1)
                    break;
                file.append(",\n");
            }
            file.append("\n};\n");

            file.append("$coefficients = {");
            for (i = 0; ; i++) {
                file.append(reducedSystem.unknownCoefficients[i].toString(OutputFormat.WolframMathematica));
                if (i == reducedSystem.unknownCoefficients.length - 1)
                    break;
                file.append(',');
            }
            file.append(" };\n");

            file.append("$result = Solve[$equations,$coefficients];\n");
            file.append("If[Length[$result] != 0, ");
            file.append("$result = Simplify[$result];\n");
            file.append("$stream = OpenWrite[\"" + path + "/equations.mathematicaOut\"];\n");
            file.append("For[$solution = 1, $solution <= Length[$result], ++$solution, ");
            file.append("$tempResult = $result[[$solution]];");
            file.append("$found = $tempResult[[All, 1]];\n");
            if (!keepFreeParams)
                file.append("For[$i = 1, $i <= Length[$coefficients], ++$i,If[!MemberQ[$found, $coefficients[[$i]]], $tempResult = $tempResult/.{$coefficients[[$i]] -> 0}; AppendTo[$tempResult, $coefficients[[$i]] -> 0];]];\n");
            else
                file.append("For[$i = 1, $i <= Length[$coefficients], ++$i,If[!MemberQ[$found, $coefficients[[$i]]], AppendTo[$tempResult, $coefficients[[$i]] -> $coefficients[[$i]]];]];\n");
            file.append("$tempResult = Simplify[$tempResult];\n");

//            file.append("left = Array[Function[x,Coefficient[equations[[x, 1]], #] & /@ coefficients], Length[equations]];\n");
//            file.append("right = equations[[All, 2]];\n");
//            file.append("result = LinearSolve[left, right]\n");

//            file.append("For[i = 1, i <= Length[coefficients], ++i, WriteString[stream, StringReplace[ToString[coefficients[[i]] == result[[i]] // InputForm], {\"==\" -> \"=\", \"^\" -> \"**\"}] <> If[i != Length[coefficients], \"\\n\", \"\"]]];\n");
            file.append("For[$i = 1, $i <= Length[$coefficients], ++$i, WriteString[$stream, StringReplace[ToString[$tempResult[[$i]] // InputForm], {\"->\" -> \"=\", \"^\" -> \"**\"}] <> If[$i != Length[$coefficients], \"\\n\", \"\"]]];\n");
            file.append("WriteString[$stream, \"\n//solution\n\"];");
            file.append("];");
            file.append("Close[$stream];");
            file.append("];");
            output.close();
            file.close();
        }

        @Override
        public String getScriptExecutionCommand() {
            return "MathematicaScript -script";
        }

        @Override
        public String getScriptExtension() {
            return "mathematica";
        }
    }

    public static final class MapleScriptCreator implements ExternalScriptCreator {
        public static final MapleScriptCreator INSTANCE = new MapleScriptCreator();

        private MapleScriptCreator() {
        }

        @Override
        public void createScript(Expression[] equations, ReducedSystem reducedSystem, String path, boolean keepFreeParams) throws IOException {
            //creating file with Maple code to solve the system of equations
            FileOutputStream output = new FileOutputStream(path + "/equations.maple");
            PrintStream file = new PrintStream(output);
            file.append("with(StringTools):\n");
            file.append("ans:=array([");
            int i;
            for (i = 0; i < reducedSystem.unknownCoefficients.length; ++i)
                if (i == reducedSystem.unknownCoefficients.length - 1)
                    file.append(reducedSystem.unknownCoefficients[i].toString(OutputFormat.Maple));
                else
                    file.append(reducedSystem.unknownCoefficients[i].toString(OutputFormat.Maple) + ",");
            file.append("]):\n");

            file.println("eq:=array(1.." + equations.length + "):");
            for (i = 0; i < equations.length; i++)
                file.println("eq[" + (i + 1) + "]:=" + equations[i].toString(OutputFormat.Maple) + ":");

            file.print("Result := solve(simplify({seq(eq[i],i=1.." + equations.length + ")}),[");
            for (i = 0; i < reducedSystem.unknownCoefficients.length; ++i)
                if (i == reducedSystem.unknownCoefficients.length - 1)
                    file.append(reducedSystem.unknownCoefficients[i].toString(OutputFormat.Maple));
                else
                    file.append(reducedSystem.unknownCoefficients[i].toString(OutputFormat.Maple) + ",");
            file.append("],explicit=true):\n");
            file.append("if nops(Result) <> 0 then\n");
            file.append("Result:= factor(Result);\n");
            file.println("file:=fopen(\"" + path + "/equations.mapleOut\",WRITE):");
            file.append("for maple_positionInResult from 1 to nops(Result) do\n");
            file.append("for maple_counter from 1 to " + reducedSystem.unknownCoefficients.length + " do\n");
            file.append("temp1 := SubstituteAll(convert(lhs(Result[maple_positionInResult][maple_counter]), string), \"^\", \"**\");\n");
            file.append("temp1 := SubstituteAll(convert(lhs(Result[maple_positionInResult][maple_counter]), string), \"(\", \"[\");\n");
            file.append("temp1 := SubstituteAll(convert(lhs(Result[maple_positionInResult][maple_counter]), string), \")\", \"]\");\n");
            file.append("temp2 := SubstituteAll(convert(rhs(Result[maple_positionInResult][maple_counter]), string), \"^\", \"**\");\n");
            file.append("fprintf(file,\"%s=%s\\n\",temp1,temp2);\n");
            file.append("od:\n");
            file.append("fprintf(file,\"//solution\\n\");\n");
            file.append("od:\n");
            file.append("end if;\n");
            file.append("fclose(file):");
            output.close();
            file.close();
        }

        @Override
        public String getScriptExecutionCommand() {
            return "maple";
        }

        @Override
        public String getScriptExtension() {
            return "maple";
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy