| 272 | | # def _neg_(self): |
| 273 | | # """ |
| 274 | | # Default implementation of negation by trying to multiply by -1. |
| 275 | | # """ |
| 276 | | # return self._lmul_(-self.parent().base_ring().one(), self) |
| | 323 | def leading_support(self, cmp=None): |
| | 324 | r""" |
| | 325 | Returns the maximal element of the support of ``self``. Note |
| | 326 | that this may not be the term which actually appears first when |
| | 327 | ``self`` is printed. |
| | 328 | |
| | 329 | If the default ordering of the basis elements is not what is |
| | 330 | desired, a comparison function, ``cmp(x,y)``, can be provided. |
| | 331 | This should return a negative value if `x < y`, `0` if `x == y` |
| | 332 | and a positive value if `x > y`. |
| | 333 | |
| | 334 | EXAMPLES:: |
| | 335 | |
| | 336 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 337 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3) |
| | 338 | sage: x.leading_support() |
| | 339 | 3 |
| | 340 | sage: def cmp(x,y): return y-x |
| | 341 | sage: x.leading_support(cmp=cmp) |
| | 342 | 1 |
| | 343 | |
| | 344 | sage: s = SymmetricFunctions(QQ).schur() |
| | 345 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 346 | sage: f.leading_support() |
| | 347 | [3] |
| | 348 | """ |
| | 349 | return max_cmp(self.support(), cmp) |
| | 350 | |
| | 351 | |
| | 352 | def leading_item(self, cmp=None): |
| | 353 | r""" |
| | 354 | Returns the pair ``(k, c)`` where ``c`` * (the basis elt. indexed |
| | 355 | by ``k``) is the leading term of ``self``. |
| | 356 | |
| | 357 | 'leading term' means that the corresponding basis element is |
| | 358 | maximal. Note that this may not be the term which actually appears |
| | 359 | first when ``self`` is printed. If the default term ordering is not |
| | 360 | what is desired, a comparison function, ``cmp(x,y)``, can be |
| | 361 | provided. This should return a negative value if `x < y`, `0` if |
| | 362 | `x == y` and a positive value if `x > y`. |
| | 363 | |
| | 364 | EXAMPLES:: |
| | 365 | |
| | 366 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 367 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3) |
| | 368 | sage: x.leading_item() |
| | 369 | (3, 4) |
| | 370 | sage: def cmp(x,y): return y-x |
| | 371 | sage: x.leading_item(cmp=cmp) |
| | 372 | (1, 3) |
| | 373 | |
| | 374 | sage: s = SymmetricFunctions(QQ).schur() |
| | 375 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 376 | sage: f.leading_item() |
| | 377 | ([3], -5) |
| | 378 | """ |
| | 379 | k = self.leading_support(cmp=cmp) |
| | 380 | return k, self[k] |
| | 381 | |
| | 382 | def leading_monomial(self, cmp=None): |
| | 383 | r""" |
| | 384 | Returns the leading monomial of ``self``. |
| | 385 | |
| | 386 | This is the monomial whose corresponding basis element is |
| | 387 | maximal. Note that this may not be the term which actually appears |
| | 388 | first when ``self`` is printed. If the default term ordering is not |
| | 389 | what is desired, a comparison function, cmp(x,y), can be provided. |
| | 390 | This should return a negative value if x < y, 0 if x == y |
| | 391 | and a positive value if x > y. |
| | 392 | |
| | 393 | EXAMPLES:: |
| | 394 | |
| | 395 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 396 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) |
| | 397 | sage: x.leading_monomial() |
| | 398 | B[3] |
| | 399 | sage: def cmp(x,y): return y-x |
| | 400 | sage: x.leading_monomial(cmp=cmp) |
| | 401 | B[1] |
| | 402 | |
| | 403 | sage: s = SymmetricFunctions(QQ).schur() |
| | 404 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 405 | sage: f.leading_monomial() |
| | 406 | s[3] |
| | 407 | """ |
| | 408 | return self.parent().monomial( self.leading_support(cmp=cmp) ) |
| | 409 | |
| | 410 | def leading_coefficient(self, cmp=None): |
| | 411 | r""" |
| | 412 | Returns the leading coefficient of ``self``. |
| | 413 | |
| | 414 | This is the coefficient of the term whose corresponding basis element is |
| | 415 | maximal. Note that this may not be the term which actually appears |
| | 416 | first when ``self`` is printed. If the default term ordering is not |
| | 417 | what is desired, a comparison function, cmp(x,y), can be provided. |
| | 418 | This should return a negative value if x < y, 0 if x == y |
| | 419 | and a positive value if x > y. |
| | 420 | |
| | 421 | EXAMPLES:: |
| | 422 | |
| | 423 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X") |
| | 424 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) |
| | 425 | sage: x.leading_coefficient() |
| | 426 | 1 |
| | 427 | sage: def cmp(x,y): return y-x |
| | 428 | sage: x.leading_coefficient(cmp=cmp) |
| | 429 | 3 |
| | 430 | |
| | 431 | sage: s = SymmetricFunctions(QQ).schur() |
| | 432 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 433 | sage: f.leading_coefficient() |
| | 434 | -5 |
| | 435 | """ |
| | 436 | return self.leading_item(cmp=cmp)[1] |
| | 437 | |
| | 438 | def leading_term(self, cmp=None): |
| | 439 | r""" |
| | 440 | Returns the leading term of ``self``. |
| | 441 | |
| | 442 | This is the term whose corresponding basis element is |
| | 443 | maximal. Note that this may not be the term which actually appears |
| | 444 | first when ``self`` is printed. If the default term ordering is not |
| | 445 | what is desired, a comparison function, cmp(x,y), can be provided. |
| | 446 | This should return a negative value if x < y, 0 if x == y |
| | 447 | and a positive value if x > y. |
| | 448 | |
| | 449 | EXAMPLES:: |
| | 450 | |
| | 451 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 452 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) |
| | 453 | sage: x.leading_term() |
| | 454 | B[3] |
| | 455 | sage: def cmp(x,y): return y-x |
| | 456 | sage: x.leading_term(cmp=cmp) |
| | 457 | 3*B[1] |
| | 458 | |
| | 459 | sage: s = SymmetricFunctions(QQ).schur() |
| | 460 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 461 | sage: f.leading_term() |
| | 462 | -5*s[3] |
| | 463 | """ |
| | 464 | return self.parent().term(*self.leading_item(cmp=cmp)) |
| | 465 | |
| | 466 | def trailing_support(self, cmp=None): |
| | 467 | r""" |
| | 468 | Returns the minimal element of the support of ``self``. Note |
| | 469 | that this may not be the term which actually appears last when |
| | 470 | ``self`` is printed. |
| | 471 | |
| | 472 | If the default ordering of the basis elements is not what is |
| | 473 | desired, a comparison function, ``cmp(x,y)``, can be provided. |
| | 474 | This should return a negative value if `x < y`, `0` if `x == y` |
| | 475 | and a positive value if `x > y`. |
| | 476 | |
| | 477 | EXAMPLES:: |
| | 478 | |
| | 479 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 480 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3) |
| | 481 | sage: x.trailing_support() |
| | 482 | 1 |
| | 483 | sage: def cmp(x,y): return y-x |
| | 484 | sage: x.trailing_support(cmp=cmp) |
| | 485 | 3 |
| | 486 | |
| | 487 | sage: s = SymmetricFunctions(QQ).schur() |
| | 488 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 489 | sage: f.trailing_support() |
| | 490 | [1] |
| | 491 | """ |
| | 492 | return min_cmp(self.support(), cmp) |
| | 493 | |
| | 494 | def trailing_item(self, cmp=None): |
| | 495 | r""" |
| | 496 | Returns the pair (c, k) where c*self.parent().monomial(k) |
| | 497 | is the trailing term of ``self``. |
| | 498 | |
| | 499 | This is the monomial whose corresponding basis element is |
| | 500 | minimal. Note that this may not be the term which actually appears |
| | 501 | last when ``self`` is printed. If the default term ordering is not |
| | 502 | what is desired, a comparison function cmp(x,y), can be provided. |
| | 503 | This should return a negative value if x < y, 0 if x == y |
| | 504 | and a positive value if x > y. |
| | 505 | |
| | 506 | EXAMPLES:: |
| | 507 | |
| | 508 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 509 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) |
| | 510 | sage: x.trailing_item() |
| | 511 | (1, 3) |
| | 512 | sage: def cmp(x,y): return y-x |
| | 513 | sage: x.trailing_item(cmp=cmp) |
| | 514 | (3, 1) |
| | 515 | |
| | 516 | sage: s = SymmetricFunctions(QQ).schur() |
| | 517 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 518 | sage: f.trailing_item() |
| | 519 | ([1], 2) |
| | 520 | """ |
| | 521 | k = self.trailing_support(cmp=cmp) |
| | 522 | return k, self[k] |
| | 523 | |
| | 524 | def trailing_monomial(self, cmp=None): |
| | 525 | r""" |
| | 526 | Returns the trailing monomial of ``self``. |
| | 527 | |
| | 528 | This is the monomial whose corresponding basis element is |
| | 529 | minimal. Note that this may not be the term which actually appears |
| | 530 | last when ``self`` is printed. If the default term ordering is not |
| | 531 | what is desired, a comparison function cmp(x,y), can be provided. |
| | 532 | This should return a negative value if x < y, 0 if x == y |
| | 533 | and a positive value if x > y. |
| | 534 | |
| | 535 | EXAMPLES:: |
| | 536 | |
| | 537 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 538 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) |
| | 539 | sage: x.trailing_monomial() |
| | 540 | B[1] |
| | 541 | sage: def cmp(x,y): return y-x |
| | 542 | sage: x.trailing_monomial(cmp=cmp) |
| | 543 | B[3] |
| | 544 | |
| | 545 | sage: s = SymmetricFunctions(QQ).schur() |
| | 546 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 547 | sage: f.trailing_monomial() |
| | 548 | s[1] |
| | 549 | """ |
| | 550 | return self.parent().monomial( self.trailing_support(cmp=cmp) ) |
| | 551 | |
| | 552 | def trailing_coefficient(self, cmp=None): |
| | 553 | r""" |
| | 554 | Returns the trailing coefficient of ``self``. |
| | 555 | |
| | 556 | This is the coefficient of the monomial whose corresponding basis element is |
| | 557 | minimal. Note that this may not be the term which actually appears |
| | 558 | last when ``self`` is printed. If the default term ordering is not |
| | 559 | what is desired, a comparison function cmp(x,y), can be provided. |
| | 560 | This should return a negative value if x < y, 0 if x == y |
| | 561 | and a positive value if x > y. |
| | 562 | |
| | 563 | EXAMPLES:: |
| | 564 | |
| | 565 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 566 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) |
| | 567 | sage: x.trailing_coefficient() |
| | 568 | 3 |
| | 569 | sage: def cmp(x,y): return y-x |
| | 570 | sage: x.trailing_coefficient(cmp=cmp) |
| | 571 | 1 |
| | 572 | |
| | 573 | sage: s = SymmetricFunctions(QQ).schur() |
| | 574 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 575 | sage: f.trailing_coefficient() |
| | 576 | 2 |
| | 577 | """ |
| | 578 | |
| | 579 | return self.trailing_item(cmp=cmp)[1] |
| | 580 | |
| | 581 | def trailing_term(self, cmp=None): |
| | 582 | r""" |
| | 583 | Returns the trailing term of ``self``. |
| | 584 | |
| | 585 | This is the term whose corresponding basis element is |
| | 586 | minimal. Note that this may not be the term which actually appears |
| | 587 | last when ``self`` is printed. If the default term ordering is not |
| | 588 | what is desired, a comparison function cmp(x,y), can be provided. |
| | 589 | This should return a negative value if x < y, 0 if x == y |
| | 590 | and a positive value if x > y. |
| | 591 | |
| | 592 | EXAMPLES:: |
| | 593 | |
| | 594 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 595 | sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3) |
| | 596 | sage: x.trailing_term() |
| | 597 | 3*B[1] |
| | 598 | sage: def cmp(x,y): return y-x |
| | 599 | sage: x.trailing_term(cmp=cmp) |
| | 600 | B[3] |
| | 601 | |
| | 602 | sage: s = SymmetricFunctions(QQ).schur() |
| | 603 | sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] |
| | 604 | sage: f.trailing_term() |
| | 605 | 2*s[1] |
| | 606 | """ |
| | 607 | return self.parent().term( *self.trailing_item(cmp=cmp) ) |
| | 935 | class TriangularModuleMorphism(ModuleMorphismByLinearity): |
| | 936 | """ |
| | 937 | A class for triangular module morphisms; that is module morphisms |
| | 938 | from `X` to `Y` whose matrix in the distinguished basis of `X` and |
| | 939 | `Y` would be upper triangular with invertible elements on its |
| | 940 | diagonal. This currently assumes that `X` and `Y` have the same |
| | 941 | index set `I`. However, `I` needs not be finite. |
| | 942 | |
| | 943 | See :meth:`module_morphism` of ModulesWithBasis |
| | 944 | |
| | 945 | EXAMPLES:: |
| | 946 | |
| | 947 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis() |
| | 948 | sage: def ut(i): return sum(j*x[j] for j in range(i,4)) |
| | 949 | sage: import __main__; __main__.ut = ut |
| | 950 | sage: phi = X.module_morphism(ut, triangular="lower", codomain = X) |
| | 951 | sage: phi(x[2]) |
| | 952 | 2*B[2] + 3*B[3] |
| | 953 | sage: phi.preimage(x[2]) |
| | 954 | 1/2*B[2] - 1/2*B[3] |
| | 955 | sage: phi(phi.preimage(x[2])) |
| | 956 | B[2] |
| | 957 | """ |
| | 958 | |
| | 959 | def __init__(self, on_basis, domain, triangular = "upper", unitriangular=False, |
| | 960 | codomain = None, category = None, cmp = None, inverse = None, **keywords): |
| | 961 | """ |
| | 962 | INPUT: |
| | 963 | |
| | 964 | - ``domain``, ``codomain`` - two modules with basis `F` and `G` |
| | 965 | - ``on_basis`` - a function from the index set of the basis of `F` to the |
| | 966 | elements of `G` |
| | 967 | - ``unitriangular`` - boolean (default: False) |
| | 968 | - ``triangular`` - "upper" or "lower" (default: "upper") |
| | 969 | - "upper": if the `leading_support()` of the image of `F(i)` is `i`, or |
| | 970 | - "lower": if the `trailing_support()` of the image of `F(i)` is `i`. |
| | 971 | |
| | 972 | - ``cmp`` - an optional comparison function on the index set `I` of the basis |
| | 973 | (see :meth:`.leading_support` for details). |
| | 974 | |
| | 975 | Assumptions: |
| | 976 | |
| | 977 | - `F` and `G` have the same base ring `R` |
| | 978 | - Their respective bases `f` and `g` have the same index set `I` |
| | 979 | |
| | 980 | OUTPUT: |
| | 981 | The triangular module morphism from `F` to `G` which maps `f_\lambda` |
| | 982 | to `on_basis(\lambda)` and is extended by linearity. |
| | 983 | |
| | 984 | EXAMPLES:: |
| | 985 | |
| | 986 | sage: I = range(1,200) |
| | 987 | sage: X = CombinatorialFreeModule(QQ, I); X.rename("X"); x = X.basis() |
| | 988 | sage: Y = CombinatorialFreeModule(QQ, I); Y.rename("Y"); y = Y.basis() |
| | 989 | sage: f = Y.sum_of_monomials * divisors |
| | 990 | sage: phi = X.module_morphism(f, triangular="upper", unitriangular = True, codomain = Y) |
| | 991 | sage: phi(x[2]) |
| | 992 | B[1] + B[2] |
| | 993 | sage: phi(x[6]) |
| | 994 | B[1] + B[2] + B[3] + B[6] |
| | 995 | sage: phi(x[30]) |
| | 996 | B[1] + B[2] + B[3] + B[5] + B[6] + B[10] + B[15] + B[30] |
| | 997 | sage: phi.preimage(y[2]) |
| | 998 | -B[1] + B[2] |
| | 999 | sage: phi.preimage(y[6]) |
| | 1000 | B[1] - B[2] - B[3] + B[6] |
| | 1001 | sage: phi.preimage(y[30]) |
| | 1002 | -B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30] |
| | 1003 | sage: (phi^-1)(y[30]) |
| | 1004 | -B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30] |
| | 1005 | |
| | 1006 | TESTS:: |
| | 1007 | |
| | 1008 | sage: phi.__class__ |
| | 1009 | <class 'sage.categories.modules_with_basis.TriangularModuleMorphism'> |
| | 1010 | sage: TestSuite(phi).run() # known issue; see ModuleMorphism above |
| | 1011 | Failure in _test_category: |
| | 1012 | ... |
| | 1013 | The following tests failed: _test_category |
| | 1014 | """ |
| | 1015 | assert codomain is not None |
| | 1016 | assert domain.basis().keys() == codomain.basis().keys() |
| | 1017 | assert domain.base_ring() == codomain.base_ring() |
| | 1018 | if category is None: |
| | 1019 | category = ModulesWithBasis(domain.base_ring()) |
| | 1020 | if triangular == "upper": |
| | 1021 | self._dominant_item = attrcall("leading_item", cmp) |
| | 1022 | else: |
| | 1023 | self._dominant_item = attrcall("trailing_item", cmp) |
| | 1024 | # We store those two just be able to pass them down to the inverse function |
| | 1025 | self._triangular = triangular |
| | 1026 | self._cmp = cmp |
| | 1027 | |
| | 1028 | self._unitriangular = unitriangular |
| | 1029 | self._inverse = inverse |
| | 1030 | ModuleMorphismByLinearity.__init__(self, domain = domain, codomain = codomain, category = category) |
| | 1031 | self.on_basis = on_basis # should this be called on_basis (or _on_basis)? |
| | 1032 | |
| | 1033 | |
| | 1034 | def _on_basis(self, i): |
| | 1035 | """ |
| | 1036 | Returns the image, by self, of the basis element indexed by `i`. |
| | 1037 | |
| | 1038 | TESTS:: |
| | 1039 | |
| | 1040 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() |
| | 1041 | sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3]); y = Y.basis() |
| | 1042 | sage: f = lambda i: sum( y[j] for j in range(i,4) ) |
| | 1043 | sage: phi = X.module_morphism(f, triangular="lower", codomain = Y) |
| | 1044 | sage: phi._on_basis(2) |
| | 1045 | B[2] + B[3] |
| | 1046 | """ |
| | 1047 | return self.codomain()(self.on_basis(i)) |
| | 1048 | |
| | 1049 | def __invert__(self): |
| | 1050 | """ |
| | 1051 | Returns the triangular morphism which is the inverse of `self`. |
| | 1052 | |
| | 1053 | TESTS:: |
| | 1054 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() |
| | 1055 | sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3]); y = Y.basis() |
| | 1056 | sage: uut = lambda i: sum( y[j] for j in range(1,i+1)) # uni-upper |
| | 1057 | sage: ult = lambda i: sum( y[j] for j in range(i,4) ) # uni-lower |
| | 1058 | sage: ut = lambda i: sum(j*y[j] for j in range(1,i+1)) # upper |
| | 1059 | sage: lt = lambda i: sum(j*y[j] for j in range(i,4 )) # lower |
| | 1060 | sage: f_uut = X.module_morphism(uut, triangular="upper", unitriangular=True, codomain = Y) |
| | 1061 | sage: f_ult = X.module_morphism(ult, triangular="lower", unitriangular=True, codomain = Y) |
| | 1062 | sage: f_ut = X.module_morphism(ut, triangular="upper", codomain = Y) |
| | 1063 | sage: f_lt = X.module_morphism(lt, triangular="lower", codomain = Y) |
| | 1064 | sage: (~f_uut)(y[2]) |
| | 1065 | -B[1] + B[2] |
| | 1066 | sage: (~f_ult)(y[2]) |
| | 1067 | B[2] - B[3] |
| | 1068 | sage: (~f_ut)(y[2]) |
| | 1069 | -1/2*B[1] + 1/2*B[2] |
| | 1070 | sage: (~f_lt)(y[2]) |
| | 1071 | 1/2*B[2] - 1/2*B[3] |
| | 1072 | """ |
| | 1073 | if self._inverse is not None: |
| | 1074 | return self._inverse |
| | 1075 | return self.__class__( self._invert_on_basis, |
| | 1076 | domain = self.domain(), codomain = self.codomain(), |
| | 1077 | unitriangular = self._unitriangular, triangular = self._triangular, |
| | 1078 | cmp = self._cmp, |
| | 1079 | inverse = self, category = self.category_for()) |
| | 1080 | |
| | 1081 | def _invert_on_basis(self, i): |
| | 1082 | r""" |
| | 1083 | Returns the image, by the inverse of ``self``, of the basis element |
| | 1084 | indexed by ``i``. |
| | 1085 | |
| | 1086 | TESTS:: |
| | 1087 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() |
| | 1088 | sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3]); y = Y.basis() |
| | 1089 | sage: uut = lambda i: sum( y[j] for j in range(i,4) ) # uni-upper |
| | 1090 | sage: phi = X.module_morphism(uut, triangular=True, codomain = Y) |
| | 1091 | sage: phi._invert_on_basis(2) |
| | 1092 | B[2] - B[3] |
| | 1093 | """ |
| | 1094 | return self.preimage( self.codomain().monomial(i) ) |
| | 1095 | |
| | 1096 | def preimage(self, f): |
| | 1097 | """ |
| | 1098 | Returns the image of f by the inverse of ``self``. |
| | 1099 | |
| | 1100 | TESTS:: |
| | 1101 | sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() |
| | 1102 | sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3]); y = Y.basis() |
| | 1103 | sage: uut = lambda i: sum( y[j] for j in range(i,4) ) # uni-upper |
| | 1104 | sage: phi = X.module_morphism(uut, triangular=True, codomain = Y) |
| | 1105 | sage: phi.preimage(y[1] + y[2]) |
| | 1106 | B[1] - B[3] |
| | 1107 | """ |
| | 1108 | F = self.domain() |
| | 1109 | G = self.codomain() |
| | 1110 | map = self._on_basis |
| | 1111 | assert f in G |
| | 1112 | |
| | 1113 | remainder = f |
| | 1114 | |
| | 1115 | out = F.zero() |
| | 1116 | while not remainder.is_zero(): |
| | 1117 | (j,c) = self._dominant_item(remainder) |
| | 1118 | |
| | 1119 | s = map(j) |
| | 1120 | assert j == self._dominant_item(s)[0] |
| | 1121 | |
| | 1122 | if not self._unitriangular: |
| | 1123 | c /= s[j] |
| | 1124 | |
| | 1125 | remainder -= s._lmul_(c) |
| | 1126 | out += F.term(j, c) |
| | 1127 | |
| | 1128 | return out |
| | 1129 | |