1 // 2 // Semigroups package for GAP 3 // Copyright (C) 2016 James D. Mitchell 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 #ifndef SEMIGROUPS_SRC_CONVERTER_H_ 20 #define SEMIGROUPS_SRC_CONVERTER_H_ 21 22 // Inclusion of <cstdef> appears to be required to prevent travis from issuing 23 // the warning: 24 // 25 // /usr/include/c++/5/cstddef:51:11: error: ‘::max_align_t’ has not been 26 // declared 27 // 28 // according to: 29 // 30 // https://stackoverflow.com/questions/35110786/how-to-fix-the-error-max-align-t 31 32 #include <cstddef> 33 34 #include <algorithm> 35 #include <vector> 36 37 #include "src/compiled.h" 38 39 #include "pkg.h" 40 #include "semigroups-debug.h" 41 42 #include "libsemigroups/element.hpp" 43 #include "libsemigroups/semiring.hpp" 44 45 using libsemigroups::Bipartition; 46 using libsemigroups::BooleanMat; 47 using libsemigroups::Element; 48 using libsemigroups::NaturalSemiring; 49 using libsemigroups::PartialPerm; 50 using libsemigroups::PBR; 51 using libsemigroups::ProjectiveMaxPlusMatrix; 52 using libsemigroups::Semiring; 53 using libsemigroups::SemiringWithThreshold; 54 using libsemigroups::Transformation; 55 using libsemigroups::UNDEFINED; 56 using libsemigroups::detail::MatrixOverSemiringBase; 57 58 //////////////////////////////////////////////////////////////////////////////// 59 // Abstract base class 60 //////////////////////////////////////////////////////////////////////////////// 61 62 class Converter { 63 public: ~Converter()64 virtual ~Converter() {} 65 virtual Element* convert(Obj, size_t) const = 0; 66 virtual Obj unconvert(Element const*) const = 0; 67 }; 68 69 //////////////////////////////////////////////////////////////////////////////// 70 // Transformations 71 //////////////////////////////////////////////////////////////////////////////// 72 73 template <typename T> 74 class TransConverter : public Converter { 75 public: convert(Obj o,size_t n)76 Transformation<T>* convert(Obj o, size_t n) const override { 77 SEMIGROUPS_ASSERT(IS_TRANS(o)); 78 79 std::vector<T> x; 80 x.reserve(n); 81 82 size_t i = 0; 83 if (TNUM_OBJ(o) == T_TRANS2) { 84 UInt2* pto2 = ADDR_TRANS2(o); 85 for (i = 0; i < std::min((size_t) DEG_TRANS2(o), n); i++) { 86 x.push_back(pto2[i]); 87 } 88 } else if (TNUM_OBJ(o) == T_TRANS4) { 89 UInt4* pto4 = ADDR_TRANS4(o); 90 for (i = 0; i < std::min((size_t) DEG_TRANS4(o), n); i++) { 91 x.push_back(pto4[i]); 92 } 93 } else { 94 // in case of future changes to transformations in GAP 95 SEMIGROUPS_ASSERT(false); 96 } 97 98 for (; i < n; i++) { 99 x.push_back(i); 100 } 101 return new Transformation<T>(x); 102 } 103 unconvert(Element const * x)104 Obj unconvert(Element const* x) const override { 105 auto xx = static_cast<Transformation<T> const*>(x); 106 Obj o = NEW_TRANS(xx->degree()); 107 108 T* pto = reinterpret_cast<T*>(static_cast<Obj*>(ADDR_OBJ(o) + 3)); 109 for (T i = 0; i < xx->degree(); i++) { 110 pto[i] = (*xx)[i]; 111 } 112 return o; 113 } 114 }; 115 116 //////////////////////////////////////////////////////////////////////////////// 117 // Partial perms 118 //////////////////////////////////////////////////////////////////////////////// 119 120 template <typename T> 121 class PPermConverter : public Converter { 122 public: convert(Obj o,size_t n)123 PartialPerm<T>* convert(Obj o, size_t n) const override { 124 SEMIGROUPS_ASSERT(IS_PPERM(o)); 125 126 std::vector<T> x; 127 x.reserve(n); 128 129 size_t i = 0; 130 if (TNUM_OBJ(o) == T_PPERM2) { 131 UInt2* pto2 = ADDR_PPERM<UInt2>(o); 132 for (i = 0; i < std::min((size_t) DEG_PPERM2(o), n); i++) { 133 if (pto2[i] == 0) { 134 x.push_back(UNDEFINED); 135 } else { 136 x.push_back(pto2[i] - 1); 137 } 138 } 139 } else if (TNUM_OBJ(o) == T_PPERM4) { 140 UInt4* pto4 = ADDR_PPERM<UInt4>(o); 141 for (i = 0; i < std::min((size_t) DEG_PPERM4(o), n); i++) { 142 if (pto4[i] == 0) { 143 x.push_back(UNDEFINED); 144 } else { 145 x.push_back(pto4[i] - 1); 146 } 147 } 148 } else { 149 // in case of future changes to partial perms in GAP 150 SEMIGROUPS_ASSERT(false); 151 } 152 153 for (; i < n; i++) { 154 x.push_back(UNDEFINED); 155 } 156 return new PartialPerm<T>(x); 157 } 158 159 // similar to FuncDensePartialPermNC in gap/src/pperm.c unconvert(Element const * x)160 Obj unconvert(Element const* x) const override { 161 auto xx = static_cast<PartialPerm<T> const*>(x); 162 T deg = xx->degree(); 163 164 // remove trailing 0s 165 while (deg > 0 && (*xx)[deg - 1] == UNDEFINED) { 166 deg--; 167 } 168 169 Obj o = NEW_PPERM(deg); 170 T* pto = reinterpret_cast<T*>(static_cast<Obj*>(ADDR_OBJ(o)) + 2) + 1; 171 172 for (T i = 0; i < deg; i++) { 173 if ((*xx)[i] == UNDEFINED) { 174 pto[i] = 0; 175 } else { 176 pto[i] = (*xx)[i] + 1; 177 } 178 } 179 return o; 180 } 181 182 private: 183 // FIXME this isn't right it depends on the codegree only and not the degree NEW_PPERM(size_t deg)184 inline Obj NEW_PPERM(size_t deg) const { 185 if (deg < 65536) { 186 return NEW_PPERM2(deg); 187 } else { 188 return NEW_PPERM4(deg); 189 } 190 } 191 192 template <typename UIntT> ADDR_PPERM(Obj x)193 inline UIntT* ADDR_PPERM(Obj x) const { 194 return reinterpret_cast<UIntT*>(static_cast<Obj*>(ADDR_OBJ(x)) + 2) + 1; 195 } 196 }; 197 198 //////////////////////////////////////////////////////////////////////////////// 199 // Bipartitions 200 //////////////////////////////////////////////////////////////////////////////// 201 202 class BipartConverter : public Converter { 203 public: 204 Bipartition* convert(Obj o, size_t n) const override; 205 Obj unconvert(Element const* x) const override; 206 }; 207 208 //////////////////////////////////////////////////////////////////////////////// 209 // Matrices over semirings 210 //////////////////////////////////////////////////////////////////////////////// 211 212 template <class TSubclass> 213 class MatrixOverSemiringConverter : public Converter { 214 public: ~MatrixOverSemiringConverter()215 ~MatrixOverSemiringConverter() { 216 delete _semiring; 217 } 218 MatrixOverSemiringConverter(Semiring<int64_t> * semiring,Obj gap_zero,Obj gap_type)219 MatrixOverSemiringConverter(Semiring<int64_t>* semiring, 220 Obj gap_zero, 221 Obj gap_type) 222 : _semiring(semiring), _gap_zero(gap_zero), _gap_type(gap_type) {} 223 convert(Obj o,size_t n)224 MatrixOverSemiringBase<int64_t, TSubclass>* convert(Obj o, 225 size_t n) const override { 226 assert(CALL_1ARGS(IsMatrixOverSemiring, o) == True); 227 assert(IS_PLIST(ELM_PLIST(o, 1))); 228 229 size_t m = LEN_PLIST(ELM_PLIST(o, 1)); 230 231 std::vector<int64_t> matrix; 232 matrix.reserve(m); 233 234 for (size_t i = 0; i < m; i++) { 235 Obj row = ELM_PLIST(o, i + 1); 236 for (size_t j = 0; j < m; j++) { 237 Obj entry = ELM_PLIST(row, j + 1); 238 if (EQ(_gap_zero, entry)) { 239 matrix.push_back(_semiring->zero()); 240 } else { 241 matrix.push_back(INT_INTOBJ(entry)); 242 } 243 } 244 } 245 return new TSubclass(matrix, _semiring); 246 } 247 unconvert(Element const * x)248 Obj unconvert(Element const* x) const override { 249 TSubclass const* xx(static_cast<TSubclass const*>(x)); 250 size_t n = xx->degree(); 251 252 Obj plist = NEW_PLIST(T_PLIST, n + 2); 253 254 if (_gap_type == NTPMatrixType) { 255 NaturalSemiring* semiring = static_cast<NaturalSemiring*>(_semiring); 256 SET_LEN_PLIST(plist, n + 2); 257 SET_ELM_PLIST(plist, n + 1, INTOBJ_INT(semiring->threshold())); 258 SET_ELM_PLIST(plist, n + 2, INTOBJ_INT(semiring->period())); 259 } else if (_gap_type == TropicalMaxPlusMatrixType 260 || _gap_type == TropicalMinPlusMatrixType) { 261 SemiringWithThreshold* semiring 262 = static_cast<SemiringWithThreshold*>(_semiring); 263 SET_LEN_PLIST(plist, n + 1); 264 SET_ELM_PLIST(plist, n + 1, INTOBJ_INT(semiring->threshold())); 265 } else { 266 SET_LEN_PLIST(plist, n); 267 } 268 269 for (size_t i = 0; i < n; i++) { 270 Obj row = NEW_PLIST_IMM(T_PLIST_CYC, n); 271 SET_LEN_PLIST(row, n); 272 for (size_t j = 0; j < n; j++) { 273 int64_t entry = xx->at(i * n + j); 274 if (entry == _semiring->zero()) { 275 SET_ELM_PLIST(row, j + 1, _gap_zero); 276 } else { 277 SET_ELM_PLIST(row, j + 1, INTOBJ_INT(entry)); 278 } 279 } 280 SET_ELM_PLIST(plist, i + 1, row); 281 CHANGED_BAG(plist); 282 } 283 SET_TYPE_POSOBJ(plist, _gap_type); 284 RetypeBag(plist, T_POSOBJ); 285 CHANGED_BAG(plist); 286 return plist; 287 } 288 289 protected: 290 Semiring<int64_t>* _semiring; 291 Obj _gap_zero; 292 Obj _gap_type; 293 }; 294 295 //////////////////////////////////////////////////////////////////////////////// 296 // Boolean matrices 297 //////////////////////////////////////////////////////////////////////////////// 298 299 class BoolMatConverter : public Converter { 300 public: 301 BooleanMat* convert(Obj o, size_t n) const override; 302 Obj unconvert(Element const* x) const override; 303 }; 304 305 //////////////////////////////////////////////////////////////////////////////// 306 // Partitioned binary relations (PBRs) 307 //////////////////////////////////////////////////////////////////////////////// 308 309 class PBRConverter : public Converter { 310 public: 311 PBR* convert(Obj o, size_t n) const override; 312 Obj unconvert(Element const* x) const override; 313 314 private: 315 Obj get_gap_type(size_t deg) const; 316 }; 317 318 #endif // SEMIGROUPS_SRC_CONVERTER_H_ 319