This is an automated email from the ASF dual-hosted git repository. baunsgaard pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/systemml.git
The following commit(s) were added to refs/heads/master by this push: new 67439d8 [SYSTEMDS-310] Python Bindings Extension 67439d8 is described below commit 67439d8939077c0597cb09dc1ba85192c3a8fed7 Author: Julia Le <julia...@student.tugraz.at> AuthorDate: Tue Jun 23 11:10:26 2020 +0200 [SYSTEMDS-310] Python Bindings Extension Extend Python API with more operations: - rev, t, order, cholesky, trigonometric ops (sin, cos, tan, asin, acos, atan, sinh, cosh, tanh) Also including Test cases and Docs update. Closes #975. --- .github/workflows/python.yml | 1 - docs/api/python/api/matrix/data_gen.html | 1 + docs/api/python/api/matrix/matrix.html | 53 +++++++++++ docs/api/python/api/operator/operation_node.html | 99 +++++++++++++++++++++ docs/api/python/genindex.html | 41 ++++++++- docs/api/python/objects.inv | Bin 1335 -> 1390 bytes docs/api/python/searchindex.js | 2 +- src/main/python/systemds/matrix/data_gen.py | 1 + src/main/python/systemds/matrix/matrix.py | 64 +++++++++++++ .../python/systemds/operator/operation_node.py | 87 ++++++++++++++++++ src/main/python/tests/test_matrix_cholesky.py | 74 +++++++++++++++ src/main/python/tests/test_matrix_order.py | 71 +++++++++++++++ src/main/python/tests/test_matrix_reverse.py | 66 ++++++++++++++ src/main/python/tests/test_matrix_transpose.py | 66 ++++++++++++++ src/main/python/tests/test_matrix_trigonometric.py | 75 ++++++++++++++++ 15 files changed, 696 insertions(+), 5 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index dbfe2b3..59edfa0 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -95,4 +95,3 @@ jobs: python tests/onnx_systemds/test_models/model_generate.py python -m unittest discover -s tests -p 'test_*.py' echo "Exit Status: " $? - diff --git a/docs/api/python/api/matrix/data_gen.html b/docs/api/python/api/matrix/data_gen.html index a35f55e..f066555 100644 --- a/docs/api/python/api/matrix/data_gen.html +++ b/docs/api/python/api/matrix/data_gen.html @@ -209,6 +209,7 @@ <dl class="field-list simple"> <dt class="field-odd">Parameters</dt> <dd class="field-odd"><ul class="simple"> +<li><p><strong>sds_context</strong> – SystemDS context</p></li> <li><p><strong>rows</strong> – number of rows</p></li> <li><p><strong>cols</strong> – number of cols</p></li> <li><p><strong>min</strong> – min value for cells</p></li> diff --git a/docs/api/python/api/matrix/matrix.html b/docs/api/python/api/matrix/matrix.html index f169528..8e6fabb 100644 --- a/docs/api/python/api/matrix/matrix.html +++ b/docs/api/python/api/matrix/matrix.html @@ -209,6 +209,19 @@ on need, or a path pointing to a matrix.</p> </dd></dl> <dl class="py method"> +<dt id="systemds.matrix.Matrix.cholesky"> +<code class="sig-name descname">cholesky</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">safe</span><span class="p">:</span> <span class="n">bool</span> <span class="o">=</span> <span class="default_value">False</span></em><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.matrix.Matrix.cholesky" title="Permalink to this definition">¶</a></dt> +<dd><p>Computes the Cholesky decomposition of a symmetric, positive definite matrix</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><p><strong>safe</strong> – default value is False, if flag is True additional checks to ensure</p> +</dd> +</dl> +<p>that the matrix is symmetric positive definite are applied, if False, checks will be skipped +:return: the OperationNode representing this operation</p> +</dd></dl> + +<dl class="py method"> <dt id="systemds.matrix.Matrix.code_line"> <code class="sig-name descname">code_line</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">var_name</span><span class="p">:</span> <span class="n">str</span></em>, <em class="sig-param"><span class="n">unnamed_input_vars</span><span class="p">:</span> <span class="n">Sequence<span class="p">[</span>str<span class="p">]</span></span></em>, <em class="sig-param"><span class="n">named_input_vars</span><span class="p">:</span> <span class="n">Dict<span class="p">[< [...] <dd><p>Generates the DML code line equal to the intended action of this node.</p> @@ -245,6 +258,24 @@ all operations are only building the DAG without actually executing (lazy evalua </dd></dl> <dl class="py method"> +<dt id="systemds.matrix.Matrix.order"> +<code class="sig-name descname">order</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">by</span><span class="p">:</span> <span class="n">int</span> <span class="o">=</span> <span class="default_value">1</span></em>, <em class="sig-param"><span class="n">decreasing</span><span class="p">:</span> <span class="n">bool</span> <span class="o">=</span> <span class="default_value">False</span></em>, <em class="sig-param"><span class="n">index_return</span><span class= [...] +<dd><p>Sort by a column of the matrix X in increasing/decreasing order and returns either the index or data</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>by</strong> – sort matrix by this column number</p></li> +<li><p><strong>decreasing</strong> – If true the matrix will be sorted in decreasing order</p></li> +<li><p><strong>index_return</strong> – If true, the index numbers will be returned</p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p>the OperationNode representing this operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> <dt id="systemds.matrix.Matrix.pass_python_data_to_prepared_script"> <code class="sig-name descname">pass_python_data_to_prepared_script</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">jvm</span><span class="p">:</span> <span class="n">py4j.java_gateway.JVMView</span></em>, <em class="sig-param"><span class="n">var_name</span><span class="p">:</span> <span class="n">str</span></em>, <em class="sig-param"><span class="n">prepared_script</span><span class="p">:</span> <span class="n">py4j.java_gateway.JavaObject</span></em><span [...] <dd><p>Passes data from python to the prepared script object.</p> @@ -259,6 +290,28 @@ all operations are only building the DAG without actually executing (lazy evalua </dl> </dd></dl> +<dl class="py method"> +<dt id="systemds.matrix.Matrix.rev"> +<code class="sig-name descname">rev</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.matrix.Matrix.rev" title="Permalink to this definition">¶</a></dt> +<dd><p>Reverses the rows in a matrix</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p>the OperationNode representing this operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt id="systemds.matrix.Matrix.t"> +<code class="sig-name descname">t</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.matrix.Matrix.t" title="Permalink to this definition">¶</a></dt> +<dd><p>Transposes the input matrix</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p>the OperationNode representing this operation</p> +</dd> +</dl> +</dd></dl> + </dd></dl> </div> diff --git a/docs/api/python/api/operator/operation_node.html b/docs/api/python/api/operator/operation_node.html index f78dde8..71cda46 100644 --- a/docs/api/python/api/operator/operation_node.html +++ b/docs/api/python/api/operator/operation_node.html @@ -230,6 +230,39 @@ Therefore errors will not immediately be recognized while constructing an sequen </dd></dl> <dl class="py method"> +<dt id="systemds.operator.OperationNode.acos"> +<code class="sig-name descname">acos</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.acos" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate arccos.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt id="systemds.operator.OperationNode.asin"> +<code class="sig-name descname">asin</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.asin" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate arcsin.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt id="systemds.operator.OperationNode.atan"> +<code class="sig-name descname">atan</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.atan" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate arctan.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> <dt id="systemds.operator.OperationNode.code_line"> <code class="sig-name descname">code_line</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">var_name</span><span class="p">:</span> <span class="n">str</span></em>, <em class="sig-param"><span class="n">unnamed_input_vars</span><span class="p">:</span> <span class="n">Sequence<span class="p">[</span>str<span class="p">]</span></span></em>, <em class="sig-param"><span class="n">named_input_vars</span><span class="p">:</span> <span class="n">Dict<span class="p">[< [...] <dd><p>Generates the DML code line equal to the intended action of this node.</p> @@ -266,6 +299,28 @@ all operations are only building the DAG without actually executing (lazy evalua </dd></dl> <dl class="py method"> +<dt id="systemds.operator.OperationNode.cos"> +<code class="sig-name descname">cos</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.cos" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate cos.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt id="systemds.operator.OperationNode.cosh"> +<code class="sig-name descname">cosh</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.cosh" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate cos.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> <dt id="systemds.operator.OperationNode.get_lineage_trace"> <code class="sig-name descname">get_lineage_trace</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → str<a class="headerlink" href="#systemds.operator.OperationNode.get_lineage_trace" title="Permalink to this definition">¶</a></dt> <dd><p>Get the lineage trace for this node.</p> @@ -306,6 +361,28 @@ all operations are only building the DAG without actually executing (lazy evalua </dd></dl> <dl class="py method"> +<dt id="systemds.operator.OperationNode.sin"> +<code class="sig-name descname">sin</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.sin" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate sin.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt id="systemds.operator.OperationNode.sinh"> +<code class="sig-name descname">sinh</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.sinh" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate sin.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> <dt id="systemds.operator.OperationNode.sum"> <code class="sig-name descname">sum</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">axis</span><span class="p">:</span> <span class="n">int</span> <span class="o">=</span> <span class="default_value">None</span></em><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.sum" title="Permalink to this definition">¶</a></dt> <dd><p>Calculate sum of matrix.</p> @@ -320,6 +397,28 @@ all operations are only building the DAG without actually executing (lazy evalua </dd></dl> <dl class="py method"> +<dt id="systemds.operator.OperationNode.tan"> +<code class="sig-name descname">tan</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.tan" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate tan.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt id="systemds.operator.OperationNode.tanh"> +<code class="sig-name descname">tanh</code><span class="sig-paren">(</span><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.tanh" title="Permalink to this definition">¶</a></dt> +<dd><p>Calculate tan.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><cite>OperationNode</cite> representing operation</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> <dt id="systemds.operator.OperationNode.var"> <code class="sig-name descname">var</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">axis</span><span class="p">:</span> <span class="n">int</span> <span class="o">=</span> <span class="default_value">None</span></em><span class="sig-paren">)</span> → systemds.operator.operation_node.OperationNode<a class="headerlink" href="#systemds.operator.OperationNode.var" title="Permalink to this definition">¶</a></dt> <dd><p>Calculate variance of matrix.</p> diff --git a/docs/api/python/genindex.html b/docs/api/python/genindex.html index 15b010b..0abd3a3 100644 --- a/docs/api/python/genindex.html +++ b/docs/api/python/genindex.html @@ -197,6 +197,7 @@ | <a href="#P"><strong>P</strong></a> | <a href="#R"><strong>R</strong></a> | <a href="#S"><strong>S</strong></a> + | <a href="#T"><strong>T</strong></a> | <a href="#V"><strong>V</strong></a> </div> @@ -221,12 +222,18 @@ <td style="width: 33%; vertical-align: top;"><ul> <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.abs">abs() (systemds.operator.OperationNode method)</a> </li> - </ul></td> - <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.acos">acos() (systemds.operator.OperationNode method)</a> +</li> <li><a href="api/script_building/script.html#systemds.script_building.script.DMLScript.add_code">add_code() (systemds.script_building.script.DMLScript method)</a> </li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> <li><a href="api/script_building/script.html#systemds.script_building.script.DMLScript.add_input_from_python">add_input_from_python() (systemds.script_building.script.DMLScript method)</a> </li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.asin">asin() (systemds.operator.OperationNode method)</a> +</li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.atan">atan() (systemds.operator.OperationNode method)</a> +</li> </ul></td> </tr></table> @@ -241,6 +248,8 @@ <h2 id="C">C</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="api/matrix/matrix.html#systemds.matrix.Matrix.cholesky">cholesky() (systemds.matrix.Matrix method)</a> +</li> <li><a href="api/context/systemds_context.html#systemds.context.SystemDSContext.close">close() (systemds.context.SystemDSContext method)</a> </li> <li><a href="api/matrix/matrix.html#systemds.matrix.Matrix.code_line">code_line() (systemds.matrix.Matrix method)</a> @@ -261,6 +270,10 @@ <li><a href="api/script_building/dag.html#systemds.script_building.dag.DAGNode.compute">(systemds.script_building.dag.DAGNode method)</a> </li> </ul></li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.cos">cos() (systemds.operator.OperationNode method)</a> +</li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.cosh">cosh() (systemds.operator.OperationNode method)</a> +</li> <li><a href="api/utils/helpers.html#systemds.utils.helpers.create_params_string">create_params_string() (in module systemds.utils.helpers)</a> </li> </ul></td> @@ -410,9 +423,11 @@ <td style="width: 33%; vertical-align: top;"><ul> <li><a href="api/onnx_systemds/convert.html#systemds.onnx_systemds.convert.onnx2systemds">onnx2systemds() (in module systemds.onnx_systemds.convert)</a>, <a href="onnx_systemds/onnx_systemds.html#systemds.onnx_systemds.convert.onnx2systemds">[1]</a> </li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode">OperationNode (class in systemds.operator)</a> +</li> </ul></td> <td style="width: 33%; vertical-align: top;"><ul> - <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode">OperationNode (class in systemds.operator)</a> + <li><a href="api/matrix/matrix.html#systemds.matrix.Matrix.order">order() (systemds.matrix.Matrix method)</a> </li> <li><a href="api/script_building/dag.html#systemds.script_building.dag.OutputType">OutputType (class in systemds.script_building.dag)</a> </li> @@ -450,6 +465,8 @@ </li> <li><a href="api/onnx_systemds/util.html#systemds.onnx_systemds.util.resolve_systemds_root">resolve_systemds_root() (in module systemds.onnx_systemds.util)</a> </li> + <li><a href="api/matrix/matrix.html#systemds.matrix.Matrix.rev">rev() (systemds.matrix.Matrix method)</a> +</li> </ul></td> </tr></table> @@ -458,6 +475,10 @@ <td style="width: 33%; vertical-align: top;"><ul> <li><a href="api/matrix/data_gen.html#systemds.matrix.data_gen.seq">seq() (in module systemds.matrix.data_gen)</a> </li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.sin">sin() (systemds.operator.OperationNode method)</a> +</li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.sinh">sinh() (systemds.operator.OperationNode method)</a> +</li> <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.sum">sum() (systemds.operator.OperationNode method)</a> </li> <li> @@ -544,6 +565,20 @@ </ul></td> </tr></table> +<h2 id="T">T</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="api/matrix/matrix.html#systemds.matrix.Matrix.t">t() (systemds.matrix.Matrix method)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.tan">tan() (systemds.operator.OperationNode method)</a> +</li> + <li><a href="api/operator/operation_node.html#systemds.operator.OperationNode.tanh">tanh() (systemds.operator.OperationNode method)</a> +</li> + </ul></td> +</tr></table> + <h2 id="V">V</h2> <table style="width: 100%" class="indextable genindextable"><tr> <td style="width: 33%; vertical-align: top;"><ul> diff --git a/docs/api/python/objects.inv b/docs/api/python/objects.inv index 9a16f1f..98244a3 100644 Binary files a/docs/api/python/objects.inv and b/docs/api/python/objects.inv differ diff --git a/docs/api/python/searchindex.js b/docs/api/python/searchindex.js index 3159e47..b74caf6 100644 --- a/docs/api/python/searchindex.js +++ b/docs/api/python/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["api/context/systemds_context","api/matrix/data_gen","api/matrix/federated","api/matrix/matrix","api/onnx_systemds/convert","api/onnx_systemds/onnx_helper","api/onnx_systemds/operator_gen","api/onnx_systemds/render","api/onnx_systemds/util","api/operator/algorithms","api/operator/operation_node","api/script_building/dag","api/script_building/script","api/utils/converters","api/utils/helpers","getting_started/install","getting_started/simple_examples","guide/alg [...] \ No newline at end of file +Search.setIndex({docnames:["api/context/systemds_context","api/matrix/data_gen","api/matrix/federated","api/matrix/matrix","api/onnx_systemds/convert","api/onnx_systemds/onnx_helper","api/onnx_systemds/operator_gen","api/onnx_systemds/render","api/onnx_systemds/util","api/operator/algorithms","api/operator/operation_node","api/script_building/dag","api/script_building/script","api/utils/converters","api/utils/helpers","getting_started/install","getting_started/simple_examples","guide/alg [...] \ No newline at end of file diff --git a/src/main/python/systemds/matrix/data_gen.py b/src/main/python/systemds/matrix/data_gen.py index c9daa03..f450e5e 100644 --- a/src/main/python/systemds/matrix/data_gen.py +++ b/src/main/python/systemds/matrix/data_gen.py @@ -68,6 +68,7 @@ def rand(sds_context: SystemDSContext, rows: int, cols: int, lambd: Union[float, int] = 1) -> OperationNode: """Generates a matrix filled with random values + :param sds_context: SystemDS context :param rows: number of rows :param cols: number of cols :param min: min value for cells diff --git a/src/main/python/systemds/matrix/matrix.py b/src/main/python/systemds/matrix/matrix.py index 926de61..5df09ac 100644 --- a/src/main/python/systemds/matrix/matrix.py +++ b/src/main/python/systemds/matrix/matrix.py @@ -83,3 +83,67 @@ class Matrix(OperationNode): def _is_numpy(self) -> bool: return self._np_array is not None + + def rev(self) -> OperationNode: + """ Reverses the rows in a matrix + + :return: the OperationNode representing this operation + """ + + self._is_numpy() + return OperationNode(self.sds_context, 'rev', [self]) + + def order(self, by: int = 1, decreasing: bool = False, + index_return: bool = False) -> OperationNode: + """ Sort by a column of the matrix X in increasing/decreasing order and returns either the index or data + + :param by: sort matrix by this column number + :param decreasing: If true the matrix will be sorted in decreasing order + :param index_return: If true, the index numbers will be returned + :return: the OperationNode representing this operation + """ + + self._is_numpy() + + cols = self._np_array.shape[1] + if by > cols: + raise IndexError("Index {i} is out of bounds for axis 1 with size {c}".format(i=by, c=cols)) + + named_input_nodes = {'target': self, 'by': by, 'decreasing': str(decreasing).upper(), + 'index.return': str(index_return).upper()} + + return OperationNode(self.sds_context, 'order', [], named_input_nodes=named_input_nodes) + + def t(self) -> OperationNode: + """ Transposes the input matrix + + :return: the OperationNode representing this operation + """ + + self._is_numpy() + return OperationNode(self.sds_context, 't', [self]) + + def cholesky(self, safe: bool = False) -> OperationNode: + """ Computes the Cholesky decomposition of a symmetric, positive definite matrix + + :param safe: default value is False, if flag is True additional checks to ensure + that the matrix is symmetric positive definite are applied, if False, checks will be skipped + :return: the OperationNode representing this operation + """ + + self._is_numpy() + + # check square dimension + if self._np_array.shape[0] != self._np_array.shape[1]: + raise ValueError("Last 2 dimensions of the array must be square") + + if safe: + # check if mat is positive definite + if not np.all(np.linalg.eigvals(self._np_array) > 0): + raise ValueError("Matrix is not positive definite") + + # check if mat is symmetric + if not np.allclose(self._np_array, self._np_array.transpose()): + raise ValueError("Matrix is not symmetric") + + return OperationNode(self.sds_context, 'cholesky', [self]) diff --git a/src/main/python/systemds/operator/operation_node.py b/src/main/python/systemds/operator/operation_node.py index 8af6537..76d06e7 100644 --- a/src/main/python/systemds/operator/operation_node.py +++ b/src/main/python/systemds/operator/operation_node.py @@ -211,6 +211,77 @@ class OperationNode(DAGNode): """ return OperationNode(self.sds_context, 'abs', [self]) + def sin(self) -> 'OperationNode': + """Calculate sin. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'sin', [self]) + + def cos(self) -> 'OperationNode': + """Calculate cos. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'cos', [self]) + + def tan(self) -> 'OperationNode': + """Calculate tan. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'tan', [self]) + + def asin(self) -> 'OperationNode': + """Calculate arcsin. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'asin', [self]) + + def acos(self) -> 'OperationNode': + """Calculate arccos. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'acos', [self]) + + def atan(self) -> 'OperationNode': + """Calculate arctan. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'atan', [self]) + + def sinh(self) -> 'OperationNode': + """Calculate sin. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'sinh', [self]) + + def cosh(self) -> 'OperationNode': + """Calculate cos. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'cosh', [self]) + + def tanh(self) -> 'OperationNode': + """Calculate tan. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'tanh', [self]) + ''' + def rev(self) -> 'OperationNode': + """Calculate tan. + + :return: `OperationNode` representing operation + """ + return OperationNode(self.sds_context, 'rev', [self]) + ''' + def moment(self, moment, weights: DAGNode = None) -> 'OperationNode': # TODO write tests self._check_matrix_op() @@ -219,3 +290,19 @@ class OperationNode(DAGNode): unnamed_inputs.append(weights) unnamed_inputs.append(moment) return OperationNode(self.sds_context, 'moment', unnamed_inputs, output_type=OutputType.DOUBLE) + + def lm(self, y: DAGNode, **kwargs) -> 'OperationNode': + self._check_matrix_op() + + if self._np_array.size == 0: + raise ValueError("Found array with 0 feature(s) (shape={s}) while a minimum of 1 is required." + .format(s=self._np_array.shape)) + + if y._np_array.size == 0: + raise ValueError("Found array with 0 feature(s) (shape={s}) while a minimum of 1 is required." + .format(s=y._np_array.shape)) + + params_dict = {'X': self, 'y': y} + params_dict.update(kwargs) + + return OperationNode(self.sds_context, 'lm', named_input_nodes=params_dict) \ No newline at end of file diff --git a/src/main/python/tests/test_matrix_cholesky.py b/src/main/python/tests/test_matrix_cholesky.py new file mode 100644 index 0000000..ba17b3b --- /dev/null +++ b/src/main/python/tests/test_matrix_cholesky.py @@ -0,0 +1,74 @@ +# ------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# ------------------------------------------------------------- + +import unittest + +import numpy as np +from systemds.context import SystemDSContext +from systemds.matrix import Matrix + +np.random.seed(7) +shape = np.random.randint(1, 100) +A = np.random.rand(shape, shape) +# set A = MM^T and A is a positive definite matrix +A = np.matmul(A, A.transpose()) + +m1 = -np.random.rand(shape, shape) +m2 = np.asarray([[4, 9], [1, 4]]) +m3 = np.random.rand(shape, shape + 1) + +class TestCholesky(unittest.TestCase): + + sds: SystemDSContext = None + + @classmethod + def setUpClass(cls): + cls.sds = SystemDSContext() + + @classmethod + def tearDownClass(cls): + cls.sds.close() + + def test_basic1(self): + L = Matrix(self.sds, A).cholesky().compute() + self.assertTrue(np.allclose(L, np.linalg.cholesky(A))) + + def test_basic2(self): + L = Matrix(self.sds, A).cholesky().compute() + # L * L.H = A + self.assertTrue(np.allclose(A, np.dot(L, L.T.conj()))) + + def test_pos_def(self): + with self.assertRaises(ValueError) as context: + Matrix(self.sds, m1).cholesky(safe=True).compute() + + def test_symmetric_matrix(self): + np.linalg.cholesky(m2) + with self.assertRaises(ValueError) as context: + Matrix(self.sds, m2).cholesky(safe=True).compute() + + def test_asymetric_dim(self): + with self.assertRaises(ValueError) as context: + Matrix(self.sds, m3).cholesky().compute() + + +if __name__ == "__main__": + unittest.main(exit=False) diff --git a/src/main/python/tests/test_matrix_order.py b/src/main/python/tests/test_matrix_order.py new file mode 100644 index 0000000..9dc6e8d --- /dev/null +++ b/src/main/python/tests/test_matrix_order.py @@ -0,0 +1,71 @@ +# ------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# ------------------------------------------------------------- + +import unittest +import random + +import numpy as np +from systemds.context import SystemDSContext +from systemds.matrix import Matrix + +np.random.seed(7) + +shape = (random.randrange(1, 25), random.randrange(1, 25)) +m = np.random.rand(shape[0], shape[1]) +mx = np.random.rand(1, shape[1]) +my = np.random.rand(shape[0], 1) +by = random.randrange(1, np.size(m, 1)+1) + +class TestOrder(unittest.TestCase): + + sds: SystemDSContext = None + + @classmethod + def setUpClass(cls): + cls.sds = SystemDSContext() + + @classmethod + def tearDownClass(cls): + cls.sds.close() + + def test_basic(self): + o = Matrix(self.sds, m).order(by=by, decreasing=False, index_return=False).compute() + s = m[np.argsort(m[:, by-1])] + self.assertTrue(np.allclose(o, s)) + + def test_index(self): + o = Matrix(self.sds, m).order(by=by, decreasing=False, index_return=True).compute() + s = np.argsort(m[:, by - 1]) + 1 + self.assertTrue(np.allclose(np.transpose(o), s)) + + def test_out_of_bounds(self): + by_max = np.size(m, 1) + 2 + with self.assertRaises(IndexError) as context: + Matrix(self.sds, m).order(by=by_max).compute() + + def test_decreasing(self): + o = Matrix(self.sds, m).order(by=by, decreasing=True, index_return=True).compute() + s = np.argsort(-m[:, by - 1]) + 1 + self.assertTrue(np.allclose(np.transpose(o), s)) + + +if __name__ == "__main__": + unittest.main(exit=False) diff --git a/src/main/python/tests/test_matrix_reverse.py b/src/main/python/tests/test_matrix_reverse.py new file mode 100644 index 0000000..cad4e35 --- /dev/null +++ b/src/main/python/tests/test_matrix_reverse.py @@ -0,0 +1,66 @@ +# ------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# ------------------------------------------------------------- + +import unittest +import random + +import numpy as np +from systemds.context import SystemDSContext +from systemds.matrix import Matrix + +np.random.seed(7) + +shape = (random.randrange(1, 25), random.randrange(1, 25)) +m = np.random.rand(shape[0], shape[1]) +mx = np.random.rand(1, shape[1]) +my = np.random.rand(shape[0], 1) + +class TestReverse(unittest.TestCase): + + sds: SystemDSContext = None + + @classmethod + def setUpClass(cls): + cls.sds = SystemDSContext() + + @classmethod + def tearDownClass(cls): + cls.sds.close() + + def test_basic(self): + Matrix(self.sds, m) + r = Matrix(self.sds, m).rev().compute() + self.assertTrue(np.allclose(r, np.flip(m, 0))) + + def test_empty(self): + m_empty = np.asarray([[]]) + r = Matrix(self.sds, np.asarray(m_empty)).rev().compute() + self.assertTrue(np.allclose(r, m_empty)) + + def test_x_axis(self): + self.assertTrue(np.allclose(Matrix(self.sds, mx).rev().compute(), mx)) + + def test_y_axis(self): + self.assertTrue(np.allclose(Matrix(self.sds, my).rev().compute(), np.flip(my, 0))) + + +if __name__ == "__main__": + unittest.main(exit=False) diff --git a/src/main/python/tests/test_matrix_transpose.py b/src/main/python/tests/test_matrix_transpose.py new file mode 100644 index 0000000..6481bb7 --- /dev/null +++ b/src/main/python/tests/test_matrix_transpose.py @@ -0,0 +1,66 @@ +# ------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# ------------------------------------------------------------- + +import unittest +import random + +import numpy as np +from systemds.context import SystemDSContext +from systemds.matrix import Matrix + +np.random.seed(7) + +shape = (random.randrange(1, 25), random.randrange(1, 25)) +m = np.random.rand(shape[0], shape[1]) +mx = np.random.rand(1, shape[1]) +my = np.random.rand(shape[0], 1) + +class TestTranspose(unittest.TestCase): + + sds: SystemDSContext = None + + @classmethod + def setUpClass(cls): + cls.sds = SystemDSContext() + + @classmethod + def tearDownClass(cls): + cls.sds.close() + + def test_basic(self): + trans = Matrix(self.sds, m).t().compute() + self.assertTrue(np.allclose(trans, np.transpose(m))) + + def test_empty(self): + trans = Matrix(self.sds, np.asarray([])).t().compute() + self.assertTrue(np.allclose(trans, np.asarray([]))) + + def test_row(self): + trans = Matrix(self.sds, mx).t().compute() + self.assertTrue(np.allclose(trans, np.transpose(mx))) + + def test_col(self): + trans = Matrix(self.sds, my).t().compute() + self.assertTrue(np.allclose(trans, np.transpose(my))) + + +if __name__ == "__main__": + unittest.main(exit=False) diff --git a/src/main/python/tests/test_matrix_trigonometric.py b/src/main/python/tests/test_matrix_trigonometric.py new file mode 100644 index 0000000..86bc363 --- /dev/null +++ b/src/main/python/tests/test_matrix_trigonometric.py @@ -0,0 +1,75 @@ +#------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +#------------------------------------------------------------- + +import unittest + +import numpy as np +from systemds.context import SystemDSContext +from systemds.matrix import Matrix + +dim = 5 +m1 = np.array(np.random.randint(100, size=dim * dim) + 1.01, dtype=np.double) +m1.shape = (dim, dim) +m2 = np.random.choice(np.arange(0.01, 1, 0.1), size=(dim,dim)) +s = 3.02 + +class TestTrigonometricOp(unittest.TestCase): + + sds: SystemDSContext = None + + @classmethod + def setUpClass(cls): + cls.sds = SystemDSContext() + + @classmethod + def tearDownClass(cls): + cls.sds.close() + + def test_sin(self): + self.assertTrue(np.allclose(Matrix(self.sds, m1).sin().compute(), np.sin(m1))) + + def test_cos(self): + self.assertTrue(np.allclose(Matrix(self.sds, m1).cos().compute(), np.cos(m1))) + + def test_tan(self): + self.assertTrue(np.allclose(Matrix(self.sds, m1).tan().compute(), np.tan(m1))) + + def test_asin(self): + self.assertTrue(np.allclose(Matrix(self.sds, m2).asin().compute(), np.arcsin(m2))) + + def test_acos(self): + self.assertTrue(np.allclose(Matrix(self.sds, m2).acos().compute(), np.arccos(m2))) + + def test_atan(self): + self.assertTrue(np.allclose(Matrix(self.sds, m2).atan().compute(), np.arctan(m2))) + + def test_sinh(self): + self.assertTrue(np.allclose(Matrix(self.sds, m1).sinh().compute(), np.sinh(m1))) + + def test_cosh(self): + self.assertTrue(np.allclose(Matrix(self.sds, m1).cosh().compute(), np.cosh(m1))) + + def test_tanh(self): + self.assertTrue(np.allclose(Matrix(self.sds, m1).tanh().compute(), np.tanh(m1))) + + +if __name__ == "__main__": + unittest.main(exit=False)