1 /*
  2     Copyright 2008-2024
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 13 
 14     You can redistribute it and/or modify it under the terms of the
 15 
 16       * GNU Lesser General Public License as published by
 17         the Free Software Foundation, either version 3 of the License, or
 18         (at your option) any later version
 19       OR
 20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 21 
 22     JSXGraph is distributed in the hope that it will be useful,
 23     but WITHOUT ANY WARRANTY; without even the implied warranty of
 24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25     GNU Lesser General Public License for more details.
 26 
 27     You should have received a copy of the GNU Lesser General Public License and
 28     the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/>
 29     and <https://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 /*global JXG: true, define: true*/
 33 /*jslint nomen: true, plusplus: true*/
 34 
 35 /**
 36  * @fileoverview In this file the namespace Math.Poly is defined, which holds algorithms to create and
 37  * manipulate polynomials.
 38  */
 39 
 40 import JXG from "../jxg.js";
 41 import Mat from "./math.js";
 42 import Type from "../utils/type.js";
 43 
 44 /**
 45  * The JXG.Math.Poly namespace holds algorithms to create and manipulate polynomials.
 46  * @name JXG.Math.Poly
 47  * @exports Mat.Poly as JXG.Math.Poly
 48  * @namespace
 49  */
 50 Mat.Poly = {};
 51 
 52 /**
 53  * Define a polynomial ring over R.
 54  * @class
 55  * @name JXG.Math.Poly.Ring
 56  * @param {Array} variables List of indeterminates.
 57  */
 58 Mat.Poly.Ring = function (variables) {
 59     /**
 60      * A list of variables in this polynomial ring.
 61      * @type Array
 62      */
 63     this.vars = variables;
 64 };
 65 
 66 JXG.extend(
 67     Mat.Poly.Ring.prototype,
 68     /** @lends JXG.Math.Poly.Ring.prototype */ {
 69         // nothing yet.
 70     }
 71 );
 72 
 73 /**
 74  * Define a monomial over the polynomial ring <tt>ring</tt>.
 75  * @class
 76  * @name JXG.Math.Poly.Monomial
 77  * @param {JXG.Math.Poly.Ring} ring
 78  * @param {Number} coefficient
 79  * @param {Array} exponents An array of exponents, corresponding to ring
 80  */
 81 Mat.Poly.Monomial = function (ring, coefficient, exponents) {
 82     var i;
 83 
 84     if (!Type.exists(ring)) {
 85         throw new Error("JSXGraph error: In JXG.Math.Poly.monomial missing parameter 'ring'.");
 86     }
 87 
 88     if (!Type.isArray(exponents)) {
 89         exponents = [];
 90     }
 91 
 92     exponents = exponents.slice(0, ring.vars.length);
 93 
 94     for (i = exponents.length; i < ring.vars.length; i++) {
 95         exponents.push(0);
 96     }
 97 
 98     /**
 99      * A polynomial ring.
100      * @type JXG.Math.Poly.Ring
101      */
102     this.ring = ring;
103 
104     /**
105      * The monomial's coefficient
106      * @type Number
107      */
108     this.coefficient = coefficient || 0;
109 
110     /**
111      * Exponent vector, the order depends on the order of the variables
112      * in the ring definition.
113      * @type Array
114      */
115     this.exponents = Type.deepCopy(exponents);
116 };
117 
118 JXG.extend(
119     Mat.Poly.Monomial.prototype,
120     /** @lends JXG.Math.Poly.Monomial.prototype */ {
121         /**
122          * Creates a deep copy of the monomial.
123          *
124          * @returns {JXG.Math.Poly.Monomial}
125          *
126          * @memberof JXG.Math.Poly.Monomial
127          */
128         copy: function () {
129             return new Mat.Poly.Monomial(this.ring, this.coefficient, this.exponents);
130         },
131 
132         /**
133          * Print the monomial.
134          * @returns {String} String representation of the monomial
135 
136          * @memberof JXG.Math.Poly.Monomial
137          */
138         print: function () {
139             var s = [],
140                 i;
141 
142             for (i = 0; i < this.ring.vars.length; i++) {
143                 s.push(this.ring.vars[i] + "^" + this.exponents[i]);
144             }
145 
146             return this.coefficient + "*" + s.join("*");
147         }
148     }
149 );
150 
151 /**
152  * A polynomial is a sum of monomials.
153  * @class
154  * @name JXG.Math.Poly.Polynomial
155  * @param {JXG.Math.Poly.Ring} ring A polynomial ring.
156  * @param {String} str TODO String representation of the polynomial, will be parsed.
157  */
158 Mat.Poly.Polynomial = function (ring, str) {
159     var parse = function () {},
160         mons;
161 
162     if (!Type.exists(ring)) {
163         throw new Error(
164             "JSXGraph error: In JXG.Math.Poly.polynomial missing parameter 'ring'."
165         );
166     }
167 
168     if (Type.exists(str) && Type.isString(str)) {
169         mons = parse(str);
170     } else {
171         mons = [];
172     }
173 
174     /**
175      * A polynomial ring.
176      * @type JXG.Math.Poly.Ring
177      */
178     this.ring = ring;
179 
180     /**
181      * List of monomials.
182      * @type Array
183      */
184     this.monomials = mons;
185 };
186 
187 JXG.extend(
188     Mat.Poly.Polynomial.prototype,
189     /** @lends JXG.Math.Poly.Polynomial.prototype */ {
190         /**
191          * Find a monomial with the given signature, i.e. exponent vector.
192          * @param {Array} sig An array of numbers
193          * @returns {Number} The index of the first monomial with the given signature, or -1
194          * if no monomial could be found.
195          * @memberof JXG.Math.Poly.Polynomial
196          */
197         findSignature: function (sig) {
198             var i;
199 
200             for (i = 0; i < this.monomials.length; i++) {
201                 if (Type.cmpArrays(this.monomials[i].exponents, sig)) {
202                     return i;
203                 }
204             }
205 
206             return -1;
207         },
208 
209         /**
210          * Adds a monomial to the polynomial. Checks the existing monomials for the added
211          * monomial's signature and just adds the coefficient if one is found.
212          * @param {JXG.Math.Poly.Monomial} m
213          * @param {Number} factor Either <tt>1</tt> or <tt>-1</tt>.
214          * @memberof JXG.Math.Poly.Polynomial
215          */
216         addSubMonomial: function (m, factor) {
217             var i;
218 
219             i = this.findSignature(m.exponents);
220             if (i > -1) {
221                 this.monomials[i].coefficient += factor * m.coefficient;
222             } else {
223                 m.coefficient *= factor;
224                 this.monomials.push(m);
225             }
226         },
227 
228         /**
229          * Adds another polynomial or monomial to this one and merges them by checking for the
230          * signature of each new monomial in the existing monomials.
231          * @param {JXG.Math.Poly.Polynomial|JXG.Math.Poly.Monomial} mp
232          * @memberof JXG.Math.Poly.Polynomial
233          */
234         add: function (mp) {
235             var i;
236 
237             if (Type.exists(mp) && mp.ring === this.ring) {
238                 if (Type.isArray(mp.exponents)) {
239                     // mp is a monomial
240                     this.addSubMonomial(mp, 1);
241                 } else {
242                     // mp is a polynomial
243                     for (i = 0; i < mp.monomials.length; i++) {
244                         this.addSubMonomial(mp.monomials[i], 1);
245                     }
246                 }
247             } else {
248                 throw new Error(
249                     "JSXGraph error: In JXG.Math.Poly.polynomial.add either summand is undefined or rings don't match."
250                 );
251             }
252         },
253 
254         /**
255          * Subtracts another polynomial or monomial from this one and merges them by checking for the
256          * signature of each new monomial in the existing monomials.
257          * @param {JXG.Math.Poly.Polynomial|JXG.Math.Poly.Monomial} mp
258          * @memberof JXG.Math.Poly.Polynomial
259          */
260         sub: function (mp) {
261             var i;
262 
263             if (Type.exists(mp) && mp.ring === this.ring) {
264                 if (Type.isArray(mp.exponents)) {
265                     // mp is a monomial
266                     this.addSubMonomial(mp, -1);
267                 } else {
268                     // mp is a polynomial
269                     for (i = 0; i < mp.monomials.length; i++) {
270                         this.addSubMonomial(mp.monomials[i], -1);
271                     }
272                 }
273             } else {
274                 throw new Error(
275                     "JSXGraph error: In JXG.Math.Poly.polynomial.sub either summand is undefined or rings don't match."
276                 );
277             }
278         },
279 
280         /**
281          * Creates a deep copy of the polynomial.
282          * @returns {JXG.Math.Poly.Polynomial}
283          * @memberof JXG.Math.Poly.Polynomial
284          */
285         copy: function () {
286             var i, p;
287 
288             p = new Mat.Poly.Polynomial(this.ring);
289 
290             for (i = 0; i < this.monomials.length; i++) {
291                 p.monomials.push(this.monomials[i].copy());
292             }
293             return p;
294         },
295 
296         /**
297          * Prints the polynomial.
298          * @returns {String} A string representation of the polynomial.
299          * @memberof JXG.Math.Poly.Polynomial
300          */
301         print: function () {
302             var s = [],
303                 i;
304 
305             for (i = 0; i < this.monomials.length; i++) {
306                 s.push("(" + this.monomials[i].print() + ")");
307             }
308 
309             return s.join("+");
310         }
311     }
312 );
313 
314 export default Mat.Poly;
315