Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640

641

642

643

644

645

646

647

648

649

650

651

652

653

654

655

656

657

658

659

660

661

662

663

664

665

666

667

668

669

670

671

672

673

674

675

676

677

678

679

680

681

682

683

684

685

686

687

688

689

690

691

692

693

694

695

696

697

698

699

700

701

702

703

704

705

706

707

708

709

710

711

712

713

714

715

716

717

718

719

720

721

722

723

724

725

726

727

728

729

730

731

732

733

734

735

736

737

738

739

740

741

742

743

744

745

746

747

748

749

750

751

752

753

754

755

756

757

758

759

760

761

762

763

764

765

766

767

768

769

770

771

772

773

774

775

776

777

778

779

780

781

782

783

784

785

786

787

788

789

790

791

792

793

794

795

796

797

798

799

800

801

802

803

804

805

806

807

808

809

810

811

812

813

814

815

816

817

818

819

820

821

822

823

824

825

826

827

828

829

830

831

832

833

834

835

836

837

838

839

840

841

842

843

844

845

846

847

848

849

850

851

852

853

854

855

856

857

858

859

860

861

862

863

864

865

866

867

868

869

870

871

872

873

874

875

876

877

878

879

880

881

882

883

884

885

886

887

888

889

890

891

892

893

894

895

896

897

898

899

900

901

902

903

904

905

906

907

908

909

910

911

912

913

914

915

916

917

918

919

920

921

922

923

924

925

926

927

928

929

930

931

932

933

934

935

936

937

938

939

940

941

942

943

944

945

946

947

948

949

950

951

952

953

954

955

956

957

958

959

960

961

962

963

964

965

966

967

968

969

970

971

972

973

974

975

976

977

978

979

980

981

982

983

984

985

986

987

988

r""" 

Filtered Modules With Basis 

 

A *filtered module with basis* over a ring `R` means 

(for the purpose of this code) a filtered `R`-module `M` 

with filtration `(F_i)_{i \in I}` (typically `I = \NN`) 

endowed with a basis `(b_j)_{j \in J}` of `M` and a partition 

`J = \bigsqcup_{i \in I} J_i` of the set `J` (it is allowed 

that some `J_i` are empty) such that for every `n \in I`, 

the subfamily `(b_j)_{j \in U_n}`, where 

`U_n = \bigcup_{i \leq n} J_i`, is a basis of the 

`R`-submodule `F_n`. 

 

For every `i \in I`, the `R`-submodule of `M` spanned by 

`(b_j)_{j \in J_i}` is called the `i`-*th graded component* 

(aka the `i`-*th homogeneous component*) of the filtered 

module with basis `M`; the elements of this submodule are 

referred to as *homogeneous elements of degree* `i`. 

 

See the class documentation 

:class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis` 

for further details. 

""" 

#***************************************************************************** 

# Copyright (C) 2014 Travis Scrimshaw <tscrim at ucdavis.edu> 

# 

# Distributed under the terms of the GNU General Public License (GPL) 

# http://www.gnu.org/licenses/ 

#****************************************************************************** 

 

from sage.categories.filtered_modules import FilteredModulesCategory 

from sage.misc.abstract_method import abstract_method 

 

class FilteredModulesWithBasis(FilteredModulesCategory): 

r""" 

The category of filtered modules with a distinguished basis. 

 

A *filtered module with basis* over a ring `R` means 

(for the purpose of this code) a filtered `R`-module `M` 

with filtration `(F_i)_{i \in I}` (typically `I = \NN`) 

endowed with a basis `(b_j)_{j \in J}` of `M` and a partition 

`J = \bigsqcup_{i \in I} J_i` of the set `J` (it is allowed 

that some `J_i` are empty) such that for every `n \in I`, 

the subfamily `(b_j)_{j \in U_n}`, where 

`U_n = \bigcup_{i \leq n} J_i`, is a basis of the 

`R`-submodule `F_n`. 

 

For every `i \in I`, the `R`-submodule of `M` spanned by 

`(b_j)_{j \in J_i}` is called the `i`-*th graded component* 

(aka the `i`-*th homogeneous component*) of the filtered 

module with basis `M`; the elements of this submodule are 

referred to as *homogeneous elements of degree* `i`. 

The `R`-module `M` is the direct sum of its `i`-th graded 

components over all `i \in I`, and thus becomes a graded 

`R`-module with basis. 

Conversely, any graded `R`-module with basis canonically 

becomes a filtered `R`-module with basis (by defining 

`F_n = \bigoplus_{i \leq n} G_i` where `G_i` is the `i`-th 

graded component, and defining `J_i` as the indexing set 

of the basis of the `i`-th graded component). Hence, the 

notion of a filtered `R`-module with basis is equivalent 

to the notion of a graded `R`-module with basis. 

 

However, the *category* of filtered `R`-modules with basis is not 

the category of graded `R`-modules with basis. Indeed, the *morphisms* 

of filtered `R`-modules with basis are defined to be morphisms of 

`R`-modules which send each `F_n` of the domain to the corresponding 

`F_n` of the target; in contrast, the morphisms of graded `R`-modules 

with basis must preserve each homogeneous component. Also, 

the notion of a filtered algebra with basis differs from 

that of a graded algebra with basis. 

 

.. NOTE:: 

 

Currently, to make use of the functionality of this class, 

an instance of ``FilteredModulesWithBasis`` should fulfill 

the contract of a :class:`CombinatorialFreeModule` (most 

likely by inheriting from it). It should also have the 

indexing set `J` encoded as its ``_indices`` attribute, 

and ``_indices.subset(size=i)`` should yield the subset 

`J_i` (as an iterable). If the latter conditions are not 

satisfied, then :meth:`basis` must be overridden. 

 

.. NOTE:: 

 

One should implement a ``degree_on_basis`` method in the parent 

class in order to fully utilize the methods of this category. 

This might become a required abstract method in the future. 

 

EXAMPLES:: 

 

sage: C = ModulesWithBasis(ZZ).Filtered(); C 

Category of filtered modules with basis over Integer Ring 

sage: sorted(C.super_categories(), key=str) 

[Category of filtered modules over Integer Ring, 

Category of modules with basis over Integer Ring] 

sage: C is ModulesWithBasis(ZZ).Filtered() 

True 

 

TESTS:: 

 

sage: C = ModulesWithBasis(ZZ).Filtered() 

sage: TestSuite(C).run() 

sage: C = ModulesWithBasis(QQ).Filtered() 

sage: TestSuite(C).run() 

""" 

class ParentMethods: 

# TODO: which syntax do we prefer? 

# A.basis(degree = 3) 

# A.basis().subset(degree=3) 

 

# This is related to the following design question: 

# If F = (f_i)_{i\in I} is a family, should ``F.subset(degree = 3)`` 

# be the elements of F of degree 3 or those whose index is of degree 3? 

 

def basis(self, d=None): 

r""" 

Return the basis for (the ``d``-th homogeneous component 

of) ``self``. 

 

INPUT: 

 

- ``d`` -- (optional, default ``None``) nonnegative integer 

or ``None`` 

 

OUTPUT: 

 

If ``d`` is ``None``, returns the basis of the module. 

Otherwise, returns the basis of the homogeneous component 

of degree ``d`` (i.e., the subfamily of the basis of the 

whole module which consists only of the basis vectors 

lying in `F_d \setminus \bigcup_{i<d} F_i`). 

 

The basis is always returned as a family. 

 

EXAMPLES:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: A.basis(4) 

Lazy family (Term map from Partitions to An example of a 

filtered module with basis: the free module on partitions 

over Integer Ring(i))_{i in Partitions of the integer 4} 

 

Without arguments, the full basis is returned:: 

 

sage: A.basis() 

Lazy family (Term map from Partitions to An example of a 

filtered module with basis: the free module on partitions 

over Integer Ring(i))_{i in Partitions} 

sage: A.basis() 

Lazy family (Term map from Partitions to An example of a 

filtered module with basis: the free module on partitions 

over Integer Ring(i))_{i in Partitions} 

 

Checking this method on a filtered algebra. Note that this 

will typically raise a ``NotImplementedError`` when this 

feature is not implemented. :: 

 

sage: A = AlgebrasWithBasis(ZZ).Filtered().example() 

sage: A.basis(4) 

Traceback (most recent call last): 

... 

NotImplementedError: infinite set 

 

Without arguments, the full basis is returned:: 

 

sage: A.basis() 

Lazy family (Term map from Free abelian monoid indexed by 

{'x', 'y', 'z'} to An example of a filtered algebra with 

basis: the universal enveloping algebra of Lie algebra 

of RR^3 with cross product over Integer Ring(i))_{i in 

Free abelian monoid indexed by {'x', 'y', 'z'}} 

 

An example with a graded algebra:: 

 

sage: E.<x,y> = ExteriorAlgebra(QQ) 

sage: E.basis() 

Lazy family (Term map from Subsets of {0, 1} to 

The exterior algebra of rank 2 over Rational Field(i))_{i in 

Subsets of {0, 1}} 

""" 

if d is None: 

from sage.sets.family import Family 

return Family(self._indices, self.monomial) 

else: 

return self.homogeneous_component_basis(d) 

 

# TODO: Change `list(self._indices)` to `self._indices` and move 

# this fallback to the category of finite-dimensional filtered 

# modules with basis when it is implemented and the MRO issues 

# are fixed (see trac #19397) 

def homogeneous_component_basis(self, d): 

""" 

Return a basis for the ``d``-th homogeneous component of ``self``. 

 

EXAMPLES:: 

 

sage: A = GradedModulesWithBasis(ZZ).example() 

sage: A.homogeneous_component_basis(4) 

Lazy family (Term map from Partitions to An example of a graded module with basis: 

the free module on partitions over Integer Ring(i))_{i in Partitions of the integer 4} 

 

sage: cat = GradedModulesWithBasis(ZZ) 

sage: C = CombinatorialFreeModule(ZZ, ['a', 'b'], category=cat) 

sage: C.degree_on_basis = lambda x: 1 if x == 'a' else 2 

sage: C.homogeneous_component_basis(1) 

Finite family {'a': B['a']} 

sage: C.homogeneous_component_basis(2) 

Finite family {'b': B['b']} 

""" 

from sage.sets.family import Family 

try: 

S = self._indices.subset(size=d) 

except (AttributeError, ValueError, TypeError): 

S = [i for i in list(self._indices) if self.degree_on_basis(i) == d] 

return Family(S, self.monomial) 

 

def homogeneous_component(self, d): 

""" 

Return the ``d``-th homogeneous component of ``self``. 

 

EXAMPLES:: 

 

sage: A = GradedModulesWithBasis(ZZ).example() 

sage: A.homogeneous_component(4) 

Degree 4 homogeneous component of An example of a graded module 

with basis: the free module on partitions over Integer Ring 

""" 

from sage.categories.modules_with_basis import ModulesWithBasis 

from sage.categories.filtered_algebras import FilteredAlgebras 

if self.base_ring() in FilteredAlgebras: 

raise NotImplementedError("this is only a natural module over" 

" the degree 0 component of the filtered" 

" algebra and coordinate rings are not" 

" yet implemented for submodules") 

category = ModulesWithBasis(self.category().base_ring()) 

M = self.submodule(self.homogeneous_component_basis(d), 

category=category, 

already_echelonized=True) 

M.rename("Degree {} homogeneous component of {}".format(d, self)) 

return M 

 

def graded_algebra(self): 

r""" 

Return the associated graded module to ``self``. 

 

See :class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra` 

for the definition and the properties of this. 

 

If the filtered module ``self`` with basis is called `A`, 

then this method returns `\operatorname{gr} A`. The method 

:meth:`to_graded_conversion` returns the canonical 

`R`-module isomorphism `A \to \operatorname{gr} A` induced 

by the basis of `A`, and the method 

:meth:`from_graded_conversion` returns the inverse of this 

isomorphism. The method :meth:`projection` projects 

elements of `A` onto `\operatorname{gr} A` according to 

their place in the filtration on `A`. 

 

.. WARNING:: 

 

When not overridden, this method returns the default 

implementation of an associated graded module -- 

namely, ``AssociatedGradedAlgebra(self)``, where 

``AssociatedGradedAlgebra`` is 

:class:`~sage.algebras.associated_graded.AssociatedGradedAlgebra`. 

But some instances of :class:`FilteredModulesWithBasis` 

override this method, as the associated graded module 

often is (isomorphic) to a simpler object (for instance, 

the associated graded module of a graded module can be 

identified with the graded module itself). Generic code 

that uses associated graded modules (such as the code 

of the :meth:`induced_graded_map` method below) should 

make sure to only communicate with them via the 

:meth:`to_graded_conversion`, 

:meth:`from_graded_conversion` and 

:meth:`projection` methods (in particular, 

do not expect there to be a conversion from ``self`` 

to ``self.graded_algebra()``; this currently does not 

work for Clifford algebras). Similarly, when 

overriding :meth:`graded_algebra`, make sure to 

accordingly redefine these three methods, unless their 

definitions below still apply to your case (this will 

happen whenever the basis of your :meth:`graded_algebra` 

has the same indexing set as ``self``, and the partition 

of this indexing set according to degree is the same as 

for ``self``). 

 

EXAMPLES:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: A.graded_algebra() 

Graded Module of An example of a filtered module with basis: 

the free module on partitions over Integer Ring 

""" 

from sage.algebras.associated_graded import AssociatedGradedAlgebra 

return AssociatedGradedAlgebra(self) 

 

# Maps 

 

def to_graded_conversion(self): 

r""" 

Return the canonical `R`-module isomorphism 

`A \to \operatorname{gr} A` induced by the basis of `A` 

(where `A = ` ``self``). 

 

This is an isomorphism of `R`-modules. See 

the class documentation :class:`AssociatedGradedAlgebra`. 

 

.. SEEALSO:: 

 

:meth:`from_graded_conversion` 

 

EXAMPLES:: 

 

sage: A = Modules(QQ).WithBasis().Filtered().example() 

sage: p = -2 * A.an_element(); p 

-4*P[] - 4*P[1] - 6*P[2] 

sage: q = A.to_graded_conversion()(p); q 

-4*Bbar[[]] - 4*Bbar[[1]] - 6*Bbar[[2]] 

sage: q.parent() is A.graded_algebra() 

True 

""" 

base_one = self.base_ring().one() 

return self.module_morphism(diagonal=lambda x: base_one, 

codomain=self.graded_algebra()) 

 

def from_graded_conversion(self): 

r""" 

Return the inverse of the canonical `R`-module isomorphism 

`A \to \operatorname{gr} A` induced by the basis of `A` 

(where `A = ` ``self``). This inverse is an isomorphism 

`\operatorname{gr} A \to A`. 

 

This is an isomorphism of `R`-modules. See 

the class documentation :class:`AssociatedGradedAlgebra`. 

 

.. SEEALSO:: 

 

:meth:`to_graded_conversion` 

 

EXAMPLES:: 

 

sage: A = Modules(QQ).WithBasis().Filtered().example() 

sage: p = -2 * A.an_element(); p 

-4*P[] - 4*P[1] - 6*P[2] 

sage: q = A.to_graded_conversion()(p); q 

-4*Bbar[[]] - 4*Bbar[[1]] - 6*Bbar[[2]] 

sage: A.from_graded_conversion()(q) == p 

True 

sage: q.parent() is A.graded_algebra() 

True 

""" 

base_one = self.base_ring().one() 

return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, 

codomain=self) 

 

def projection(self, i): 

r""" 

Return the `i`-th projection `p_i : F_i \to G_i` (in the 

notations of the class documentation 

:class:`AssociatedGradedAlgebra`, where `A = ` ``self``). 

 

This method actually does not return the map `p_i` itself, 

but an extension of `p_i` to the whole `R`-module `A`. 

This extension is the composition of the `R`-module 

isomorphism `A \to \operatorname{gr} A` with the canonical 

projection of the graded `R`-module `\operatorname{gr} A` 

onto its `i`-th graded component `G_i`. The codomain of 

this map is `\operatorname{gr} A`, although its actual 

image is `G_i`. The map `p_i` is obtained from this map 

by restricting its domain to `F_i` and its image to `G_i`. 

 

EXAMPLES:: 

 

sage: A = Modules(ZZ).WithBasis().Filtered().example() 

sage: p = -2 * A.an_element(); p 

-4*P[] - 4*P[1] - 6*P[2] 

sage: q = A.projection(2)(p); q 

-6*Bbar[[2]] 

sage: q.parent() is A.graded_algebra() 

True 

sage: A.projection(3)(p) 

0 

""" 

base_zero = self.base_ring().zero() 

base_one = self.base_ring().one() 

grA = self.graded_algebra() 

proj = lambda x: (base_one if self.degree_on_basis(x) == i 

else base_zero) 

return self.module_morphism(diagonal=proj, codomain=grA) 

 

def induced_graded_map(self, other, f): 

r""" 

Return the graded linear map between the associated graded 

modules of ``self`` and ``other`` canonically induced by 

the filtration-preserving map ``f : self -> other``. 

 

Let `A` and `B` be two filtered modules with basis, and let 

`(F_i)_{i \in I}` and `(G_i)_{i \in I}` be their 

filtrations. Let `f : A \to B` be a linear map which 

preserves the filtration (i.e., satisfies `f(F_i) \subseteq 

G_i` for all `i \in I`). Then, there is a canonically 

defined graded linear map 

`\operatorname{gr} f : \operatorname{gr} A \to 

\operatorname{gr} B` which satisfies 

 

.. MATH:: 

 

(\operatorname{gr} f) (p_i(a)) = p_i(f(a)) 

\qquad \text{for all } i \in I \text{ and } a \in F_i , 

 

where the `p_i` on the left hand side is the canonical 

projection from `F_i` onto the `i`-th graded component 

of `\operatorname{gr} A`, while the `p_i` on the right 

hand side is the canonical projection from `G_i` onto 

the `i`-th graded component of `\operatorname{gr} B`. 

 

INPUT: 

 

- ``other`` -- a filtered algebra with basis 

 

- ``f`` -- a filtration-preserving linear map from ``self`` 

to ``other`` (can be given as a morphism or as a function) 

 

OUTPUT: 

 

The graded linear map `\operatorname{gr} f`. 

 

EXAMPLES: 

 

**Example 1.** 

 

We start with the free `\QQ`-module with basis the set of all 

partitions:: 

 

sage: A = Modules(QQ).WithBasis().Filtered().example(); A 

An example of a filtered module with basis: the free module 

on partitions over Rational Field 

sage: M = A.indices(); M 

Partitions 

sage: p1, p2, p21, p321 = [A.basis()[Partition(i)] for i in [[1], [2], [2,1], [3,2,1]]] 

 

Let us define a map from ``A`` to itself which acts on the 

basis by sending every partition `\lambda` to the sum of 

the conjugates of all partitions `\mu` for which 

`\lambda / \mu` is a horizontal strip:: 

 

sage: def map_on_basis(lam): 

....: return A.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) 

....: for mu in lam.remove_horizontal_border_strip(k)]) 

sage: f = A.module_morphism(on_basis=map_on_basis, 

....: codomain=A) 

sage: f(p1) 

P[] + P[1] 

sage: f(p2) 

P[] + P[1] + P[1, 1] 

sage: f(p21) 

P[1] + P[1, 1] + P[2] + P[2, 1] 

sage: f(p21 - p1) 

-P[] + P[1, 1] + P[2] + P[2, 1] 

sage: f(p321) 

P[2, 1] + P[2, 1, 1] + P[2, 2] + P[2, 2, 1] 

+ P[3, 1] + P[3, 1, 1] + P[3, 2] + P[3, 2, 1] 

 

We now compute `\operatorname{gr} f` :: 

 

sage: grA = A.graded_algebra(); grA 

Graded Module of An example of a filtered module with basis: 

the free module on partitions over Rational Field 

sage: pp1, pp2, pp21, pp321 = [A.to_graded_conversion()(i) for i in [p1, p2, p21, p321]] 

sage: pp2 + 4 * pp21 

Bbar[[2]] + 4*Bbar[[2, 1]] 

sage: grf = A.induced_graded_map(A, f); grf 

Generic endomorphism of Graded Module of An example of a 

filtered module with basis: 

the free module on partitions over Rational Field 

sage: grf(pp1) 

Bbar[[1]] 

sage: grf(pp2 + 4 * pp21) 

Bbar[[1, 1]] + 4*Bbar[[2, 1]] 

 

**Example 2.** 

 

We shall now construct `\operatorname{gr} f` for a 

different map `f` out of the same ``A``; the new map 

`f` will lead into a graded algebra already, namely into 

the algebra of symmetric functions:: 

 

sage: h = SymmetricFunctions(QQ).h() 

sage: def map_on_basis(lam): # redefining map_on_basis 

....: return h.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) 

....: for mu in lam.remove_horizontal_border_strip(k)]) 

sage: f = A.module_morphism(on_basis=map_on_basis, 

....: codomain=h) # redefining f 

sage: f(p1) 

h[] + h[1] 

sage: f(p2) 

h[] + h[1] + h[1, 1] 

sage: f(A.zero()) 

0 

sage: f(p2 - 3*p1) 

-2*h[] - 2*h[1] + h[1, 1] 

 

The algebra ``h`` of symmetric functions in the `h`-basis 

is already graded, so its associated graded algebra is 

implemented as itself:: 

 

sage: grh = h.graded_algebra(); grh is h 

True 

sage: grf = A.induced_graded_map(h, f); grf 

Generic morphism: 

From: Graded Module of An example of a filtered 

module with basis: the free module on partitions 

over Rational Field 

To: Symmetric Functions over Rational Field 

in the homogeneous basis 

sage: grf(pp1) 

h[1] 

sage: grf(pp2) 

h[1, 1] 

sage: grf(pp321) 

h[3, 2, 1] 

sage: grf(pp2 - 3*pp1) 

-3*h[1] + h[1, 1] 

sage: grf(pp21) 

h[2, 1] 

sage: grf(grA.zero()) 

0 

 

**Example 3.** 

 

After having had a graded module as the codomain, let us try to 

have one as the domain instead. Our new ``f`` will go from ``h`` 

to ``A``:: 

 

sage: def map_on_basis(lam): # redefining map_on_basis 

....: return A.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) 

....: for mu in lam.remove_horizontal_border_strip(k)]) 

sage: f = h.module_morphism(on_basis=map_on_basis, 

....: codomain=A) # redefining f 

sage: f(h[1]) 

P[] + P[1] 

sage: f(h[2]) 

P[] + P[1] + P[1, 1] 

sage: f(h[1, 1]) 

P[1] + P[2] 

sage: f(h[2, 2]) 

P[1, 1] + P[2, 1] + P[2, 2] 

sage: f(h[3, 2, 1]) 

P[2, 1] + P[2, 1, 1] + P[2, 2] + P[2, 2, 1] 

+ P[3, 1] + P[3, 1, 1] + P[3, 2] + P[3, 2, 1] 

sage: f(h.one()) 

P[] 

sage: grf = h.induced_graded_map(A, f); grf 

Generic morphism: 

From: Symmetric Functions over Rational Field 

in the homogeneous basis 

To: Graded Module of An example of a filtered 

module with basis: the free module on partitions 

over Rational Field 

sage: grf(h[1]) 

Bbar[[1]] 

sage: grf(h[2]) 

Bbar[[1, 1]] 

sage: grf(h[1, 1]) 

Bbar[[2]] 

sage: grf(h[2, 2]) 

Bbar[[2, 2]] 

sage: grf(h[3, 2, 1]) 

Bbar[[3, 2, 1]] 

sage: grf(h.one()) 

Bbar[[]] 

 

**Example 4.** 

 

The construct `\operatorname{gr} f` also makes sense when `f` 

is a filtration-preserving map between graded modules. :: 

 

sage: def map_on_basis(lam): # redefining map_on_basis 

....: return h.sum_of_monomials([Partition(mu).conjugate() for k in range(sum(lam) + 1) 

....: for mu in lam.remove_horizontal_border_strip(k)]) 

sage: f = h.module_morphism(on_basis=map_on_basis, 

....: codomain=h) # redefining f 

sage: f(h[1]) 

h[] + h[1] 

sage: f(h[2]) 

h[] + h[1] + h[1, 1] 

sage: f(h[1, 1]) 

h[1] + h[2] 

sage: f(h[2, 1]) 

h[1] + h[1, 1] + h[2] + h[2, 1] 

sage: f(h.one()) 

h[] 

sage: grf = h.induced_graded_map(h, f); grf 

Generic endomorphism of Symmetric Functions over Rational 

Field in the homogeneous basis 

sage: grf(h[1]) 

h[1] 

sage: grf(h[2]) 

h[1, 1] 

sage: grf(h[1, 1]) 

h[2] 

sage: grf(h[2, 1]) 

h[2, 1] 

sage: grf(h.one()) 

h[] 

""" 

grA = self.graded_algebra() 

grB = other.graded_algebra() 

from sage.categories.graded_modules_with_basis import GradedModulesWithBasis 

cat = GradedModulesWithBasis(self.base_ring()) 

from_gr = self.from_graded_conversion() 

def on_basis(m): 

i = grA.degree_on_basis(m) 

lifted_img_of_m = f(from_gr(grA.monomial(m))) 

return other.projection(i)(lifted_img_of_m) 

return grA.module_morphism(on_basis=on_basis, 

codomain=grB, category=cat) 

# If we could assume that the projection of the basis 

# element of ``self`` indexed by an index ``m`` is the 

# basis element of ``grA`` indexed by ``m``, then this 

# could go faster: 

# 

# def on_basis(m): 

# i = grA.degree_on_basis(m) 

# return grB.projection(i)(f(self.monomial(m))) 

# return grA.module_morphism(on_basis=on_basis, 

# codomain=grB, category=cat) 

# 

# But this assumption might come back to bite us in the 

# ass one day. What do you think? 

 

class ElementMethods: 

 

def is_homogeneous(self): 

r""" 

Return whether the element ``self`` is homogeneous. 

 

EXAMPLES:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: x=A(Partition((3,2,1))) 

sage: y=A(Partition((4,4,1))) 

sage: z=A(Partition((2,2,2))) 

sage: (3*x).is_homogeneous() 

True 

sage: (x - y).is_homogeneous() 

False 

sage: (x+2*z).is_homogeneous() 

True 

 

Here is an example with a graded algebra:: 

 

sage: S = NonCommutativeSymmetricFunctions(QQ).S() 

sage: (x, y) = (S[2], S[3]) 

sage: (3*x).is_homogeneous() 

True 

sage: (x^3 - y^2).is_homogeneous() 

True 

sage: ((x + y)^2).is_homogeneous() 

False 

 

Let us now test a filtered algebra (but remember that the 

notion of homogeneity now depends on the choice of a 

basis, or at least on a definition of homogeneous 

components):: 

 

sage: A = AlgebrasWithBasis(QQ).Filtered().example() 

sage: x,y,z = A.algebra_generators() 

sage: (x*y).is_homogeneous() 

True 

sage: (y*x).is_homogeneous() 

False 

sage: A.one().is_homogeneous() 

True 

sage: A.zero().is_homogeneous() 

True 

sage: (A.one()+x).is_homogeneous() 

False 

""" 

degree_on_basis = self.parent().degree_on_basis 

degree = None 

for m in self.support(): 

if degree is None: 

degree = degree_on_basis(m) 

else: 

if degree != degree_on_basis(m): 

return False 

return True 

 

@abstract_method(optional=True) 

def degree_on_basis(self, m): 

r""" 

Return the degree of the basis element indexed by ``m`` 

in ``self``. 

 

EXAMPLES:: 

 

sage: A = GradedModulesWithBasis(QQ).example() 

sage: A.degree_on_basis(Partition((2,1))) 

3 

sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) 

10 

""" 

 

def homogeneous_degree(self): 

r""" 

The degree of a nonzero homogeneous element ``self`` in the 

filtered module. 

 

.. NOTE:: 

 

This raises an error if the element is not homogeneous. 

To compute the maximum of the degrees of the homogeneous 

summands of a (not necessarily homogeneous) element, use 

:meth:`maximal_degree` instead. 

 

EXAMPLES:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: x = A(Partition((3,2,1))) 

sage: y = A(Partition((4,4,1))) 

sage: z = A(Partition((2,2,2))) 

sage: x.degree() 

6 

sage: (x + 2*z).degree() 

6 

sage: (y - x).degree() 

Traceback (most recent call last): 

... 

ValueError: element is not homogeneous 

 

An example in a graded algebra:: 

 

sage: S = NonCommutativeSymmetricFunctions(QQ).S() 

sage: (x, y) = (S[2], S[3]) 

sage: x.homogeneous_degree() 

2 

sage: (x^3 + 4*y^2).homogeneous_degree() 

6 

sage: ((1 + x)^3).homogeneous_degree() 

Traceback (most recent call last): 

... 

ValueError: element is not homogeneous 

 

Let us now test a filtered algebra (but remember that the 

notion of homogeneity now depends on the choice of a 

basis):: 

 

sage: A = AlgebrasWithBasis(QQ).Filtered().example() 

sage: x,y,z = A.algebra_generators() 

sage: (x*y).homogeneous_degree() 

2 

sage: (y*x).homogeneous_degree() 

Traceback (most recent call last): 

... 

ValueError: element is not homogeneous 

sage: A.one().homogeneous_degree() 

0 

 

TESTS:: 

 

sage: S = NonCommutativeSymmetricFunctions(QQ).S() 

sage: S.zero().degree() 

Traceback (most recent call last): 

... 

ValueError: the zero element does not have a well-defined degree 

""" 

if not self.support(): 

raise ValueError("the zero element does not have a well-defined degree") 

if not self.is_homogeneous(): 

raise ValueError("element is not homogeneous") 

return self.parent().degree_on_basis(self.leading_support()) 

 

# default choice for degree; will be overridden as necessary 

degree = homogeneous_degree 

 

def maximal_degree(self): 

""" 

The maximum of the degrees of the homogeneous components 

of ``self``. 

 

This is also the smallest `i` such that ``self`` belongs 

to `F_i`. Hence, it does not depend on the basis of the 

parent of ``self``. 

 

.. SEEALSO:: :meth:`homogeneous_degree` 

 

EXAMPLES: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: x = A(Partition((3,2,1))) 

sage: y = A(Partition((4,4,1))) 

sage: z = A(Partition((2,2,2))) 

sage: x.maximal_degree() 

6 

sage: (x + 2*z).maximal_degree() 

6 

sage: (y - x).maximal_degree() 

9 

sage: (3*z).maximal_degree() 

6 

 

Now, we test this on a graded algebra:: 

 

sage: S = NonCommutativeSymmetricFunctions(QQ).S() 

sage: (x, y) = (S[2], S[3]) 

sage: x.maximal_degree() 

2 

sage: (x^3 + 4*y^2).maximal_degree() 

6 

sage: ((1 + x)^3).maximal_degree() 

6 

 

Let us now test a filtered algebra:: 

 

sage: A = AlgebrasWithBasis(QQ).Filtered().example() 

sage: x,y,z = A.algebra_generators() 

sage: (x*y).maximal_degree() 

2 

sage: (y*x).maximal_degree() 

2 

sage: A.one().maximal_degree() 

0 

sage: A.zero().maximal_degree() 

Traceback (most recent call last): 

... 

ValueError: the zero element does not have a well-defined degree 

sage: (A.one()+x).maximal_degree() 

1 

 

TESTS:: 

 

sage: S = NonCommutativeSymmetricFunctions(QQ).S() 

sage: S.zero().degree() 

Traceback (most recent call last): 

... 

ValueError: the zero element does not have a well-defined degree 

""" 

if self.is_zero(): 

raise ValueError("the zero element does not have a well-defined degree") 

degree_on_basis = self.parent().degree_on_basis 

return max(degree_on_basis(m) for m in self.support()) 

 

def homogeneous_component(self, n): 

""" 

Return the homogeneous component of degree ``n`` of the 

element ``self``. 

 

Let `m` be an element of a filtered `R`-module `M` with 

basis. Then, `m` can be uniquely written in the form 

`m = \sum_{i \in I} m_i`, where each `m_i` is a 

homogeneous element of degree `i`. For `n \in I`, we 

define the homogeneous component of degree `n` of the 

element `m` to be `m_n`. 

 

EXAMPLES:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: x = A.an_element(); x 

2*P[] + 2*P[1] + 3*P[2] 

sage: x.homogeneous_component(-1) 

0 

sage: x.homogeneous_component(0) 

2*P[] 

sage: x.homogeneous_component(1) 

2*P[1] 

sage: x.homogeneous_component(2) 

3*P[2] 

sage: x.homogeneous_component(3) 

0 

 

sage: A = ModulesWithBasis(ZZ).Graded().example() 

sage: x = A.an_element(); x 

2*P[] + 2*P[1] + 3*P[2] 

sage: x.homogeneous_component(-1) 

0 

sage: x.homogeneous_component(0) 

2*P[] 

sage: x.homogeneous_component(1) 

2*P[1] 

sage: x.homogeneous_component(2) 

3*P[2] 

sage: x.homogeneous_component(3) 

0 

 

sage: A = AlgebrasWithBasis(ZZ).Filtered().example() 

sage: G = A.algebra_generators() 

sage: g = A.an_element() - 2 * G['x'] * G['y']; g 

U['x']^2*U['y']^2*U['z']^3 - 2*U['x']*U['y'] 

+ 2*U['x'] + 3*U['y'] + 1 

sage: g.homogeneous_component(-1) 

0 

sage: g.homogeneous_component(0) 

1 

sage: g.homogeneous_component(2) 

-2*U['x']*U['y'] 

sage: g.homogeneous_component(5) 

0 

sage: g.homogeneous_component(7) 

U['x']^2*U['y']^2*U['z']^3 

sage: g.homogeneous_component(8) 

0 

 

TESTS: 

 

Check that this really returns ``A.zero()`` and not a plain ``0``:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: x = A.an_element() 

sage: x.homogeneous_component(3).parent() is A 

True 

""" 

degree_on_basis = self.parent().degree_on_basis 

return self.parent().sum_of_terms((i, c) 

for (i, c) in self 

if degree_on_basis(i) == n) 

 

def truncate(self, n): 

""" 

Return the sum of the homogeneous components of degree 

strictly less than ``n`` of ``self``. 

 

See :meth:`homogeneous_component` for the notion of a 

homogeneous component. 

 

EXAMPLES:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: x = A.an_element(); x 

2*P[] + 2*P[1] + 3*P[2] 

sage: x.truncate(0) 

0 

sage: x.truncate(1) 

2*P[] 

sage: x.truncate(2) 

2*P[] + 2*P[1] 

sage: x.truncate(3) 

2*P[] + 2*P[1] + 3*P[2] 

 

sage: A = ModulesWithBasis(ZZ).Graded().example() 

sage: x = A.an_element(); x 

2*P[] + 2*P[1] + 3*P[2] 

sage: x.truncate(0) 

0 

sage: x.truncate(1) 

2*P[] 

sage: x.truncate(2) 

2*P[] + 2*P[1] 

sage: x.truncate(3) 

2*P[] + 2*P[1] + 3*P[2] 

 

sage: A = AlgebrasWithBasis(ZZ).Filtered().example() 

sage: G = A.algebra_generators() 

sage: g = A.an_element() - 2 * G['x'] * G['y']; g 

U['x']^2*U['y']^2*U['z']^3 - 2*U['x']*U['y'] 

+ 2*U['x'] + 3*U['y'] + 1 

sage: g.truncate(-1) 

0 

sage: g.truncate(0) 

0 

sage: g.truncate(2) 

2*U['x'] + 3*U['y'] + 1 

sage: g.truncate(3) 

-2*U['x']*U['y'] + 2*U['x'] + 3*U['y'] + 1 

sage: g.truncate(5) 

-2*U['x']*U['y'] + 2*U['x'] + 3*U['y'] + 1 

sage: g.truncate(7) 

-2*U['x']*U['y'] + 2*U['x'] + 3*U['y'] + 1 

sage: g.truncate(8) 

U['x']^2*U['y']^2*U['z']^3 - 2*U['x']*U['y'] 

+ 2*U['x'] + 3*U['y'] + 1 

 

TESTS: 

 

Check that this really return ``A.zero()`` and not a plain ``0``:: 

 

sage: A = ModulesWithBasis(ZZ).Filtered().example() 

sage: x = A.an_element() 

sage: x.truncate(0).parent() is A 

True 

""" 

degree_on_basis = self.parent().degree_on_basis 

return self.parent().sum_of_terms((i, c) for (i, c) in self 

if degree_on_basis(i) < n)