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

""" 

Coerce actions 

""" 

  

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

# Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu> 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 2 of the License, or 

# (at your option) any later version. 

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

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

from __future__ import absolute_import 

  

import operator 

  

from cpython.int cimport * 

from cpython.number cimport * 

from cysignals.signals cimport sig_check 

  

from .element cimport parent, coercion_model, Element, ModuleElement 

from .parent cimport Parent 

from .coerce_exceptions import CoercionException 

from sage.categories.action cimport InverseAction, PrecomposedAction 

from sage.arith.long cimport integer_check_long 

  

  

cdef _record_exception(): 

coercion_model._record_exception() 

  

cdef inline an_element(R): 

if isinstance(R, Parent): 

return R.an_element() 

else: 

for x in ([(1, 2)], "abc", 10.5, 10): 

try: 

return R(x) 

except Exception: 

pass 

  

cdef class LAction(Action): 

"""Action calls _l_action of the actor.""" 

def __init__(self, G, S): 

Action.__init__(self, G, S, True, operator.mul) 

cpdef _call_(self, g, a): 

return g._l_action(a) # a * g 

  

  

cdef class RAction(Action): 

"""Action calls _r_action of the actor.""" 

def __init__(self, G, S): 

Action.__init__(self, G, S, False, operator.mul) 

cpdef _call_(self, a, g): 

return g._r_action(a) # g * a 

  

  

# In the code below, I take the convention that g is acting on a. 

  

cdef class GenericAction(Action): 

  

cdef _codomain 

  

def __init__(self, Parent G, S, is_left, bint check=True): 

""" 

TESTS: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, 

for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

sage: M = MatrixSpace(ZZ,2) 

sage: sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) 

Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps 

  

sage: Z6 = Zmod(6) 

sage: sage.structure.coerce_actions.GenericAction(QQ, Z6, True) 

Traceback (most recent call last): 

... 

NotImplementedError: Action not implemented. 

  

This will break if we tried to use it:: 

  

sage: sage.structure.coerce_actions.GenericAction(QQ, Z6, True, check=False) 

Left action by Rational Field on Ring of integers modulo 6 

  

""" 

Action.__init__(self, G, S, is_left, operator.mul) 

if check: 

res = self.act(G.an_element(), S.an_element()) 

if res is None: 

raise CoercionException 

_codomain = parent(res) 

  

def codomain(self): 

""" 

Returns the "codomain" of this action, i.e. the Parent in which the 

result elements live. Typically, this should be the same as the 

acted upon set. 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, for 

otherwise they could be garbage collected, giving rise to random 

errors (see :trac:`18157`). :: 

  

  

sage: M = MatrixSpace(ZZ,2) 

sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) 

sage: A.codomain() 

Set P^1(QQ) of all cusps 

  

sage: S3 = SymmetricGroup(3) 

sage: QQxyz = QQ['x,y,z'] 

sage: A = sage.structure.coerce_actions.ActOnAction(S3, QQxyz, False) 

sage: A.codomain() 

Multivariate Polynomial Ring in x, y, z over Rational Field 

  

""" 

if self._codomain is None: 

self._codomain = parent(self.act(an_element(self.G), 

an_element(self.underlying_set()))) 

return self._codomain 

  

  

cdef class ActOnAction(GenericAction): 

""" 

Class for actions defined via the _act_on_ method. 

""" 

cpdef _call_(self, a, b): 

""" 

TESTS:: 

  

sage: G = SymmetricGroup(3) 

sage: R.<x,y,z> = QQ[] 

sage: A = sage.structure.coerce_actions.ActOnAction(G, R, False) 

sage: A._call_(x^2 + y - z, G((1,2))) 

y^2 + x - z 

sage: A._call_(x+2*y+3*z, G((1,3,2))) 

2*x + 3*y + z 

  

sage: type(A) 

<... 'sage.structure.coerce_actions.ActOnAction'> 

""" 

if self._is_left: 

return (<Element>a)._act_on_(b, True) 

else: 

return (<Element>b)._act_on_(a, False) 

  

cdef class ActedUponAction(GenericAction): 

""" 

Class for actions defined via the _acted_upon_ method. 

""" 

cpdef _call_(self, a, b): 

""" 

TESTS:: 

  

sage: M = MatrixSpace(ZZ,2) 

sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) 

sage: A.act(matrix(ZZ, 2, [1,0,2,-1]), Cusp(1,2)) 

Infinity 

sage: A._call_(matrix(ZZ, 2, [1,0,2,-1]), Cusp(1,2)) 

Infinity 

  

sage: type(A) 

<... 'sage.structure.coerce_actions.ActedUponAction'> 

""" 

if self._is_left: 

return (<Element>b)._acted_upon_(a, False) 

else: 

return (<Element>a)._acted_upon_(b, True) 

  

def detect_element_action(Parent X, Y, bint X_on_left, X_el=None, Y_el=None): 

r""" 

Returns an action of X on Y or Y on X as defined by elements X, if any. 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, 

for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import detect_element_action 

sage: ZZx = ZZ['x'] 

sage: M = MatrixSpace(ZZ,2) 

sage: detect_element_action(ZZx, ZZ, False) 

Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring 

sage: detect_element_action(ZZx, QQ, True) 

Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring 

sage: detect_element_action(Cusps, M, False) 

Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps 

sage: detect_element_action(Cusps, M, True), 

(None,) 

sage: detect_element_action(ZZ, QQ, True), 

(None,) 

  

TESTS: 

  

This test checks that the issue in :trac:`7718` has been fixed:: 

  

sage: class MyParent(Parent): 

....: def an_element(self): 

....: pass 

....: 

sage: A = MyParent() 

sage: detect_element_action(A, ZZ, True) 

Traceback (most recent call last): 

... 

RuntimeError: an_element() for <__main__.MyParent object at ...> returned None 

""" 

cdef Element x 

if X_el is None or (parent(X_el) is not X): 

x = an_element(X) 

else: 

x = X_el 

if x is None: 

raise RuntimeError("an_element() for %s returned None" % X) 

if Y_el is None or (parent(Y_el) is not Y): 

y = an_element(Y) 

else: 

y = Y_el 

if y is None: 

if isinstance(Y, Parent): 

raise RuntimeError("an_element() for %s returned None" % Y) 

else: 

return # don't know how to make elements of this type... 

if isinstance(x, ModuleElement) and isinstance(y, Element): 

# Elements defining _lmul_ and _rmul_ 

try: 

return (RightModuleAction if X_on_left else LeftModuleAction)(Y, X, y, x) 

except CoercionException as msg: 

_record_exception() 

try: 

# Elements defining _act_on_ 

if x._act_on_(y, X_on_left) is not None: 

return ActOnAction(X, Y, X_on_left, False) 

except CoercionException: 

_record_exception() 

if isinstance(Y, Parent): 

try: 

# Elements defining _acted_upon_ 

if x._acted_upon_(y, X_on_left) is not None: 

return ActedUponAction(Y, X, not X_on_left, False) 

except CoercionException: 

_record_exception() 

  

  

cdef class ModuleAction(Action): 

""" 

Module action. 

  

.. SEEALSO:: 

  

This is an abstract class, one must actually instantiate a 

:class:`LeftModuleAction` or a :class:`RightModuleAction`. 

  

INPUT: 

  

- ``G`` -- the actor, an instance of :class:`~sage.structure.parent.Parent`. 

- ``S`` -- the object that is acted upon. 

- ``g`` -- optional, an element of ``G``. 

- ``a`` -- optional, an element of ``S``. 

- ``check`` -- if True (default), then there will be no consistency tests 

performed on sample elements. 

  

NOTE: 

  

By default, the sample elements of ``S`` and ``G`` are obtained from 

:meth:`~sage.structure.parent.Parent.an_element`, which relies on the 

implementation of an ``_an_element_()`` method. This is not always 

awailable. But usually, the action is only needed when one already 

*has* two elements. Hence, by :trac:`14249`, the coercion model will 

pass these two elements to the :class:`ModuleAction` constructor. 

  

The actual action is implemented by the ``_rmul_`` or ``_lmul_`` 

function on its elements. We must, however, be very particular about 

what we feed into these functions, because they operate under the 

assumption that the inputs lie exactly in the base ring and may 

segfault otherwise. Thus we handle all possible base extensions 

manually here. 

  

""" 

def __init__(self, G, S, g=None, a=None, check=True): 

""" 

This creates an action of an element of a module by an element of its 

base ring. The simplest example to keep in mind is R acting on the 

polynomial ring R[x]. 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, 

for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

  

sage: from sage.structure.coerce_actions import LeftModuleAction 

sage: ZZx = ZZ['x'] 

sage: QQx = QQ['x'] 

sage: QQy = QQ['y'] 

sage: ZZxy = ZZ['x']['y'] 

sage: LeftModuleAction(ZZ, ZZx) 

Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring 

sage: LeftModuleAction(ZZ, QQx) 

Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Rational Field 

sage: LeftModuleAction(QQ, ZZx) 

Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring 

sage: LeftModuleAction(QQ, ZZxy) 

Left scalar multiplication by Rational Field on Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Integer Ring 

  

The following tests against a problem that was relevant during work on 

:trac:`9944`:: 

  

sage: R.<x> = PolynomialRing(ZZ) 

sage: S.<x> = PolynomialRing(ZZ, sparse=True) 

sage: 1/R.0 

1/x 

sage: 1/S.0 

1/x 

  

""" 

Action.__init__(self, G, S, not isinstance(self, RightModuleAction), operator.mul) 

if not isinstance(G, Parent): 

# only let Parents act 

raise TypeError("Actor must be a parent.") 

base = S.base() 

if base is S or base is None: 

# The right thing to do is a normal multiplication 

raise CoercionException("Best viewed as standard multiplication") 

# Objects are implemented with the assumption that 

# _lmul_/_rmul_ are given an element of the base ring 

if G is not base: 

# first we try the easy case of coercing G to the base ring of S 

self.connecting = base._internal_coerce_map_from(G) 

if self.connecting is None: 

# otherwise, we try and find a base extension 

from sage.categories.pushout import pushout 

# this may raise a type error, which we propagate 

self.extended_base = pushout(G, S) 

# make sure the pushout actually gave a correct base extension of S 

if self.extended_base.base() != pushout(G, base): 

raise CoercionException("Actor must be coercible into base.") 

else: 

self.connecting = self.extended_base.base()._internal_coerce_map_from(G) 

if self.connecting is None: 

# this may happen if G is, say, int rather than a parent 

# TODO: let python types be valid actions 

raise CoercionException("Missing connecting morphism") 

  

# Don't waste time if our connecting morphisms happen to be the identity. 

if self.connecting is not None and self.connecting.codomain() is G: 

self.connecting = None 

  

if self.extended_base is not None and self.extended_base is S: 

self.extended_base = None 

  

# At this point, we can assert it is safe to call _Xmul_ 

the_ring = G if self.connecting is None else self.connecting.codomain() 

the_set = S if self.extended_base is None else self.extended_base 

assert the_ring is the_set.base(), "BUG in coercion model\n Apparently there are two versions of\n %s\n in the cache."%the_ring 

  

if not check: 

return 

if g is None: 

g = G.an_element() 

if parent(g) is not G: 

raise CoercionException("The parent of %s is not %s but %s"%(g,G,parent(g))) 

if a is None: 

a = S.an_element() 

if parent(a) is not S: 

raise CoercionException("The parent of %s is not %s but %s"%(a,S,parent(a))) 

if not isinstance(g, Element) or not isinstance(a, ModuleElement): 

raise CoercionException("not an Element acting on a ModuleElement") 

res = self.act(g, a) 

if parent(res) is not the_set: 

# In particular we will raise an error if res is None 

raise CoercionException("Result is None or has wrong parent.") 

  

  

def _repr_name_(self): 

""" 

The default name of this action type, which is has a sane default. 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the 

coercion model. For this test, we need to strongly reference the 

domains, for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import LeftModuleAction, RightModuleAction 

sage: ZZx = ZZ['x'] 

sage: A = LeftModuleAction(ZZ, ZZx); A 

Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring 

sage: A._repr_name_() 

'scalar multiplication' 

  

sage: GF5 = GF(5) 

sage: GF5t = GF5[['t']] 

sage: RightModuleAction(GF5, GF5t) 

Right scalar multiplication by Finite Field of size 5 on Power Series Ring in t over Finite Field of size 5 

  

""" 

return "scalar multiplication" 

  

def codomain(self): 

""" 

The codomain of self, which may or may not be equal to the domain. 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, 

for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import LeftModuleAction 

sage: ZZxyz = ZZ['x,y,z'] 

sage: A = LeftModuleAction(QQ, ZZxyz) 

sage: A.codomain() 

Multivariate Polynomial Ring in x, y, z over Rational Field 

""" 

if self.extended_base is not None: 

return self.extended_base 

return self.underlying_set() 

  

def domain(self): 

""" 

The domain of self, which is the module that is being acted on. 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, 

for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import LeftModuleAction 

sage: ZZxyz = ZZ['x,y,z'] 

sage: A = LeftModuleAction(QQ, ZZxyz) 

sage: A.domain() 

Multivariate Polynomial Ring in x, y, z over Integer Ring 

""" 

return self.underlying_set() 

  

def __invert__(self): 

""" 

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, for 

otherwise they could be garbage collected, giving rise to random 

errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import RightModuleAction 

  

sage: ZZx = ZZ['x'] 

sage: x = ZZx.gen() 

sage: QQx = QQ['x'] 

sage: A = ~RightModuleAction(QQ, QQx); A 

Right inverse action by Rational Field on Univariate Polynomial Ring in x over Rational Field 

sage: A(x, 2) 

1/2*x 

  

sage: A = ~RightModuleAction(QQ, ZZx); A 

Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring 

sage: A.codomain() 

Univariate Polynomial Ring in x over Rational Field 

sage: A(x, 2) 

1/2*x 

  

sage: A = ~RightModuleAction(ZZ, ZZx); A 

Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring 

with precomposition on right by Natural morphism: 

From: Integer Ring 

To: Rational Field 

sage: A.codomain() 

Univariate Polynomial Ring in x over Rational Field 

sage: A(x, 2) 

1/2*x 

  

sage: GF5x = GF(5)['x'] 

sage: A = ~RightModuleAction(ZZ, GF5x); A 

Right inverse action by Finite Field of size 5 on Univariate Polynomial Ring in x over Finite Field of size 5 

with precomposition on right by Natural morphism: 

From: Integer Ring 

To: Finite Field of size 5 

sage: A(x, 2) 

3*x 

  

sage: GF5xy = GF5x['y'] 

sage: A = ~RightModuleAction(ZZ, GF5xy); A 

Right inverse action by Finite Field of size 5 on Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Finite Field of size 5 

with precomposition on right by Natural morphism: 

From: Integer Ring 

To: Finite Field of size 5 

  

sage: ZZy = ZZ['y'] 

sage: ZZxyzw = ZZx['y']['z']['w'] 

sage: A = ~RightModuleAction(ZZy, ZZxyzw); A 

Right inverse action by Fraction Field of Univariate Polynomial Ring in y 

over Univariate Polynomial Ring in x 

over Integer Ring 

on Univariate Polynomial Ring in w 

over Univariate Polynomial Ring in z 

over Univariate Polynomial Ring in y 

over Univariate Polynomial Ring in x 

over Integer Ring 

with precomposition on right by Conversion via FractionFieldElement map: 

From: Univariate Polynomial Ring in y over Integer Ring 

To: Fraction Field of Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Integer Ring 

  

TESTS: 

  

See :trac:`19521`:: 

  

sage: Q.<y> = SR.subring(no_variables=True)[[]] 

sage: (y / 1).parent() 

Power Series Ring in y over Symbolic Constants Subring 

sage: R.<x> = SR.subring(no_variables=True)[] 

sage: cm = sage.structure.element.get_coercion_model() 

sage: cm.explain(x, 1, operator.truediv) 

Action discovered. 

Right inverse action by Symbolic Constants Subring on Univariate Polynomial Ring in x over Symbolic Constants Subring 

with precomposition on right by Coercion map: 

From: Integer Ring 

To: Symbolic Constants Subring 

Result lives in Univariate Polynomial Ring in x over Symbolic Constants Subring 

Univariate Polynomial Ring in x over Symbolic Constants Subring 

""" 

K = self.G._pseudo_fraction_field() 

if K is self.G: 

return InverseAction(self) 

else: 

# Try to find a suitable ring between G and R in which to compute 

# the inverse. 

from sage.categories.pushout import construction_tower, pushout 

R = self.G if self.connecting is None else self.connecting.codomain() 

K = pushout(self.G._pseudo_fraction_field(), R) 

if K is None: 

K = R._pseudo_fraction_field() 

  

# Suppose we have parents of a construction tower 

# A -> B -> C <- D <- E -> F <- G -> H, 

# where the arrows specify the direction of coercion (i.e. 

# A -> B means A coerces to B). Note that B = FA(A), C = FB(B), ... 

# As we want to find a "smallest" parent with some properties, 

# we need the order 

# A, B, E, D, C, G, F, H 

# for our search. Thus the elements connected with a <- have to 

# be reversed. See code below. 

tower = [] 

reversed_part = [] 

for Fi, Ri in reversed(construction_tower(K)): 

if Fi is not None and Fi.coercion_reversed: 

reversed_part.append((Fi, Ri)) 

else: 

tower.append((Fi, Ri)) 

if reversed_part: 

tower += reversed(reversed_part) 

reversed_part = [] 

assert(not reversed_part) 

for _, Ri in tower: 

if not Ri.has_coerce_map_from(self.G): 

continue 

Ki = Ri._pseudo_fraction_field() 

if Ki is Ri: 

K = Ki 

break 

module_action = type(self)(K, self.codomain()) 

connecting = K.coerce_map_from(self.G) 

left, right = (connecting, None) if self._is_left else (None, connecting) 

return PrecomposedAction(InverseAction(module_action), left, right) 

  

  

cdef class LeftModuleAction(ModuleAction): 

  

cpdef _call_(self, g, a): 

""" 

A left module action is an action that takes the ring element as the 

first argument (the left side) and the module element as the second 

argument (the right side). 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, 

for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import LeftModuleAction 

sage: R.<x> = QQ['x'] 

sage: A = LeftModuleAction(ZZ, R) 

sage: A(5, x+1) 

5*x + 5 

sage: R.<x> = ZZ['x'] 

sage: A = LeftModuleAction(QQ, R) 

sage: A(1/2, x+1) 

1/2*x + 1/2 

sage: A._call_(1/2, x+1) # safe only when arguments have exactly the correct parent 

1/2*x + 1/2 

""" 

# The way we are called, we know for sure that a is a 

# ModuleElement and that g is an Element. 

# If we change a or g, we need to explicitly check this, 

# which explains the <?> casts below. 

if self.connecting is not None: 

g = <Element?>self.connecting._call_(g) 

if self.extended_base is not None: 

a = <ModuleElement?>self.extended_base(a) 

return (<ModuleElement>a)._rmul_(<Element>g) # g * a 

  

  

cdef class RightModuleAction(ModuleAction): 

cpdef _call_(self, a, g): 

""" 

A right module action is an action that takes the module element as the 

first argument (the left side) and the ring element as the second 

argument (the right side). 

  

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the domains, 

for otherwise they could be garbage collected, giving rise to 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import RightModuleAction 

sage: R.<x> = QQ['x'] 

sage: A = RightModuleAction(ZZ, R) 

sage: A(x+5, 2) 

2*x + 10 

sage: A._call_(x+5, 2) # safe only when arguments have exactly the correct parent 

2*x + 10 

""" 

# The way we are called, we know for sure that a is a 

# ModuleElement and that g is an Element. 

# If we change a or g, we need to explicitly check this, 

# which explains the <?> casts below. 

if self.connecting is not None: 

g = <Element?>self.connecting._call_(g) 

if self.extended_base is not None: 

a = <ModuleElement?>self.extended_base(a) 

return (<ModuleElement>a)._lmul_(<Element>g) # a * g 

  

  

cdef class IntegerAction(Action): 

""" 

Abstract base class representing some action by integers on 

something. Here, "integer" is defined loosely in the "duck typing" 

sense. 

  

INPUT: 

  

- ``Z`` -- a type or parent representing integers 

  

For the other arguments, see :class:`Action`. 

  

.. NOTE:: 

  

This class is used internally in Sage's coercion model. Outside 

of the coercion model, special precautions are needed to prevent 

domains of the action from being garbage collected. 

""" 

def __init__(self, Z, S, is_left, op): 

if isinstance(Z, type): 

from sage.structure.parent import Set_PythonType 

Z = Set_PythonType(Z) 

super().__init__(Z, S, is_left, op) 

  

def __invert__(self): 

""" 

EXAMPLES:: 

  

sage: from sage.structure.coerce_actions import IntegerMulAction 

sage: act = IntegerMulAction(ZZ, CDF) 

sage: ~act 

Traceback (most recent call last): 

... 

TypeError: actions by ZZ cannot be inverted 

""" 

raise TypeError("actions by ZZ cannot be inverted") 

  

  

cdef class IntegerMulAction(IntegerAction): 

r""" 

Implement the action `n \cdot a = a + a + ... + a` via repeated 

doubling. 

  

Both addition and negation must be defined on the set `M`. 

  

INPUT: 

  

- ``Z`` -- a type or parent representing integers 

  

- ``M`` -- a ``ZZ``-module 

  

- ``m`` -- (optional) an element of ``M`` 

  

EXAMPLES:: 

  

sage: from sage.structure.coerce_actions import IntegerMulAction 

sage: R.<x> = QQ['x'] 

sage: act = IntegerMulAction(ZZ, R) 

sage: act(5, x) 

5*x 

sage: act(0, x) 

0 

sage: act(-3, x-1) 

-3*x + 3 

""" 

def __init__(self, Z, M, is_left=True, m=None): 

if m is None: 

m = M.an_element() 

test = m + (-m) # make sure addition and negation is allowed 

super().__init__(Z, M, is_left, operator.mul) 

  

cpdef _call_(self, nn, a): 

""" 

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the field 

``GF(101)``, for otherwise it could be garbage collected, giving rise 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import IntegerMulAction 

sage: GF101 = GF(101) 

sage: act = IntegerMulAction(ZZ, GF101) 

sage: act(3, 9) 

27 

sage: act(3^689, 9) 

42 

sage: 3^689 * mod(9, 101) 

42 

  

TESTS: 

  

Use round off error to verify this is doing actual repeated addition 

instead of just multiplying:: 

  

sage: act = IntegerMulAction(ZZ, RR) 

sage: act(49, 1/49) == 49*RR(1/49) 

False 

  

This used to hang before :trac:`17844`:: 

  

sage: E = EllipticCurve(GF(5), [4,0]) 

sage: P = E.random_element() 

sage: (-2^63)*P 

(0 : 1 : 0) 

  

Check that large multiplications can be interrupted:: 

  

sage: alarm(0.5); (2^(10^7)) * P # not tested; see trac:#24986 

Traceback (most recent call last): 

... 

AlarmInterrupt 

  

""" 

cdef int err = 0 

cdef long n_long 

  

if not self._is_left: 

a, nn = nn, a 

  

if integer_check_long(nn, &n_long, &err) and not err: 

return fast_mul_long(a, n_long) 

  

return fast_mul(a, nn) 

  

def _repr_name_(self): 

""" 

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the field 

``GF(5)``, for otherwise it could be garbage collected, giving rise 

random errors (see :trac:`18157`). :: 

  

sage: from sage.structure.coerce_actions import IntegerMulAction 

sage: GF5 = GF(5) 

sage: IntegerMulAction(ZZ, GF5) 

Left Integer Multiplication by Integer Ring on Finite Field of size 5 

""" 

return "Integer Multiplication" 

  

  

cdef class IntegerPowAction(IntegerAction): 

r""" 

The right action ``a ^ n = a * a * ... * a`` where `n` is an 

integer. 

  

The action is implemented using the ``_pow_int`` method on elements. 

  

INPUT: 

  

- ``Z`` -- a type or parent representing integers 

  

- ``M`` -- a parent whose elements implement ``_pow_int`` 

  

- ``m`` -- (optional) an element of ``M`` 

  

EXAMPLES:: 

  

sage: from sage.structure.coerce_actions import IntegerPowAction 

sage: R.<x> = LaurentSeriesRing(QQ) 

sage: act = IntegerPowAction(ZZ, R) 

sage: act(x, 5) 

x^5 

sage: act(x, -2) 

x^-2 

sage: act(x, int(5)) 

x^5 

  

TESTS:: 

  

sage: IntegerPowAction(ZZ, R, True) 

Traceback (most recent call last): 

... 

ValueError: powering must be a right action 

sage: IntegerPowAction(ZZ, QQ^3) 

Traceback (most recent call last): 

... 

TypeError: no integer powering action defined on Vector space of dimension 3 over Rational Field 

  

:: 

  

sage: var('x,y') 

(x, y) 

sage: RDF('-2.3')^(x+y^3+sin(x)) 

(-2.3)^(y^3 + x + sin(x)) 

sage: RDF('-2.3')^x 

(-2.3)^x 

""" 

def __init__(self, Z, M, is_left=False, m=None): 

if is_left: 

raise ValueError("powering must be a right action") 

if m is None: 

m = M.an_element() 

try: 

# Check that there is a _pow_int() method 

m._pow_int 

except AttributeError: 

raise TypeError(f"no integer powering action defined on {M}") 

super().__init__(Z, M, False, operator.pow) 

  

cpdef _call_(self, a, n): 

""" 

EXAMPLES: 

  

Note that coerce actions should only be used inside of the coercion 

model. For this test, we need to strongly reference the field 

``GF(101)``:: 

  

sage: from sage.structure.coerce_actions import IntegerPowAction 

sage: GF101 = GF(101) 

sage: act = IntegerPowAction(ZZ, GF101) 

sage: act(3, 100) 

1 

sage: act(3, -1) 

34 

sage: act(3, 1000000000000000000000000000000000000000000001) 

3 

""" 

cdef Element e = <Element>a 

cdef long value = 0 

cdef int err 

integer_check_long(n, &value, &err) 

if not err: 

return e._pow_long(value) 

return e._pow_int(n) 

  

def _repr_name_(self): 

""" 

EXAMPLES:: 

  

sage: from sage.structure.coerce_actions import IntegerPowAction 

sage: IntegerPowAction(ZZ, QQ) 

Right Integer Powering by Integer Ring on Rational Field 

""" 

return "Integer Powering" 

  

  

cdef inline fast_mul(a, n): 

if n < 0: 

n = -n 

a = -a 

pow2a = a 

while n & 1 == 0: 

sig_check() 

pow2a += pow2a 

n = n >> 1 

sum = pow2a 

n = n >> 1 

while n != 0: 

sig_check() 

pow2a += pow2a 

if n & 1: 

sum += pow2a 

n = n >> 1 

return sum 

  

cdef inline fast_mul_long(a, long s): 

# It's important to change the signed s to an unsigned n, 

# since -LONG_MIN = LONG_MIN. See Trac #17844. 

cdef unsigned long n 

if s < 0: 

n = -s 

a = -a 

else: 

n = s 

if n < 4: 

if n == 0: 

p = parent(a) 

try: 

return p.zero() 

except AttributeError: 

return p(0) 

elif n == 1: return a 

elif n == 2: return a+a 

elif n == 3: return a+a+a 

pow2a = a 

while n & 1 == 0: 

pow2a += pow2a 

n = n >> 1 

sum = pow2a 

n = n >> 1 

while n != 0: 

pow2a += pow2a 

if n & 1: 

sum += pow2a 

n = n >> 1 

return sum