1 /*
2 	This program is free software; you can redistribute it and/or
3 	modify it under the terms of the GNU General Public License
4 	as published by the Free Software Foundation; either version 2
5 	of the License, or (at your option) any later version.
6 
7 	This program is distributed in the hope that it will be useful,
8 	but WITHOUT ANY WARRANTY; without even the implied warranty of
9 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 	GNU General Public License for more details.
11 
12 	You should have received a copy of the GNU General Public License
13 	along with this program; if not, write to the Free Software
14 	Foundation, Inc., 51 Franklin Street, Fifth Floor,
15 	Boston, MA  02110-1301, USA.
16 
17 	---
18 	Copyright (C) 2011 - 2015, Simon Hampe <simon.hampe@googlemail.com>
19 
20 	---
21 	Copyright (c) 2016-2021
22 	Ewgenij Gawrilow, Michael Joswig, and the polymake team
23 	Technische Universität Berlin, Germany
24 	https://polymake.org
25 
26 	Implements the addition of two morphisms.
27 	*/
28 
29 #include "polymake/client.h"
30 #include "polymake/Matrix.h"
31 #include "polymake/Rational.h"
32 #include "polymake/Vector.h"
33 #include "polymake/tropical/refine.h"
34 
35 namespace polymake { namespace tropical {
36 
37 /*
38  * @brief Takes a morphism and a Cycle whose support is equal to f's [[DOMAIN]]
39  * and returns f as a morphism on that cycle.
40  * @param Morphism f
41  * @param Cycle X
42  * @param bool need_to_refine Whether the cycle needs to be refined or it is
43  * already fine in f's [[DOMAIN]].
44  * @tparam Addition Min or Max
45  * @return Morphism The "refined" morphism
46  */
47 template <typename Addition>
refine_domain(BigObject f,BigObject cycle,bool need_to_refine)48 BigObject refine_domain(BigObject f, BigObject cycle, bool need_to_refine)
49 {
50   BigObject oldDomain = f.give("DOMAIN");
51   bool has_matrix = f.exists("MATRIX");
52   RefinementResult r = refinement(cycle, oldDomain,  false, !has_matrix,false,need_to_refine,false);
53 
54   BigObject nDomain = r.complex;
55   if (has_matrix) {
56     Matrix<Rational> matrix = f.give("MATRIX");
57     Vector<Rational> translate = f.give("TRANSLATE");
58     return BigObject("Morphism", mlist<Addition>(),
59                      "DOMAIN", nDomain,
60                      "MATRIX", matrix,
61                      "TRANSLATE", translate);
62   }
63 
64   Matrix<Rational> rayRep = r.rayRepFromY;
65   Matrix<Rational> linRep = r.linRepFromY;
66 
67   Matrix<Rational> vertex_values = f.give("VERTEX_VALUES");
68   Matrix<Rational> lineality_values = f.give("LINEALITY_VALUES");
69   Matrix<Rational> total_values = T( vertex_values / lineality_values);
70   Int target_dim = std::max(vertex_values.cols(), lineality_values.cols());
71 
72   Matrix<Rational> ndom_vertices = nDomain.give("SEPARATED_VERTICES");
73   Matrix<Rational> ndom_lineality = nDomain.give("LINEALITY_SPACE");
74 
75   Matrix<Rational> rValues(0,target_dim);
76   Matrix<Rational> lValues(0,target_dim);
77 
78   for (Int v = 0; v < ndom_vertices.rows(); ++v) {
79     rValues /= total_values * rayRep.row(v);
80   }
81 
82   for (Int l = 0; l < ndom_lineality.rows(); ++l) {
83     lValues /= total_values * linRep.row(l);
84   }
85 
86   return BigObject("Morphism", mlist<Addition>(),
87                    "DOMAIN", nDomain,
88                    "VERTEX_VALUES", rValues,
89                    "LINEALITY_VALUES", lValues);
90 }
91 
92 /**
93    @brief Computes the sum of two morphisms (which should be defined on the same support)
94    @param BigObject f A Morphism object
95    @param BigObject g A Morphism object, whose DOMAIN has the same support as f's DOMAIN and whose image has the same ambient dimension as f's image
96    @return BigObject A Morphism object representing f+g
97 */
98 template <typename Addition>
add_morphisms(BigObject f,BigObject g)99 BigObject add_morphisms(BigObject f, BigObject g)
100 {
101   // First we treat the special case where both are global
102   bool f_global = f.exists("MATRIX");
103   bool g_global = g.exists("MATRIX");
104   Matrix<Rational> sum_matrix;
105   Vector<Rational> sum_translate;
106   if (f_global && g_global) {
107     Matrix<Rational> fmatrix = f.give("MATRIX");
108     Vector<Rational> ftranslate = f.give("TRANSLATE");
109     Matrix<Rational> gmatrix = g.give("MATRIX");
110     Vector<Rational> gtranslate = g.give("TRANSLATE");
111 
112     sum_matrix = fmatrix + gmatrix;
113     sum_translate = ftranslate + gtranslate;
114   }
115 
116   // First we homogenize where necessary
117   BigObject fDomain = f.give("DOMAIN");
118   BigObject gDomain = g.give("DOMAIN");
119 
120   // Then compute the common refinement of the domains
121   RefinementResult r = refinement(fDomain,gDomain,false,false,false,true,false);
122   BigObject nDomain = r.complex;
123 
124   // If the map is given by a matrix, we're done
125   if (f_global && g_global) {
126     return BigObject("Morphism", mlist<Addition>(),
127                      "MATRIX", sum_matrix,
128                      "TRANSLATE", sum_translate,
129                      "DOMAIN", nDomain);
130   }
131 
132   // Otherwise, compute values on the new domain
133   BigObject f_refined = refine_domain<Addition>(f, nDomain, false);
134   BigObject g_refined = refine_domain<Addition>(g, nDomain, false);
135 
136   Matrix<Rational> fref_vert = f_refined.give("VERTEX_VALUES");
137   Matrix<Rational> gref_vert = g_refined.give("VERTEX_VALUES");
138   Matrix<Rational> fref_lin  = f_refined.give("LINEALITY_VALUES");
139   Matrix<Rational> gref_lin  = g_refined.give("LINEALITY_VALUES");
140 
141   return BigObject("Morphism", mlist<Addition>(),
142                    "DOMAIN", nDomain,
143                    "VERTEX_VALUES", fref_vert + gref_vert,
144                    "LINEALITY_VALUES", fref_lin + gref_lin);
145 }
146 
147 UserFunctionTemplate4perl("# @category Morphisms"
148                           "# Computes the sum of two morphisms. Both [[DOMAIN]]s should have the same support"
149                           "# and the target spaces should have the same ambient dimension"
150                           "# The domain of the result will be the common refinement of the two domains."
151                           "# @param Morphism f"
152                           "# @param Morphism g"
153                           "# @return Morphism",
154                           "add_morphisms<Addition>(Morphism<Addition>, Morphism<Addition>)");
155 } }
156