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

989

990

991

992

993

994

995

996

997

998

999

1000

1001

1002

1003

1004

1005

1006

1007

1008

1009

1010

1011

1012

1013

1014

1015

1016

1017

1018

1019

1020

1021

1022

1023

1024

1025

1026

1027

1028

1029

1030

1031

1032

1033

1034

1035

1036

1037

1038

1039

1040

1041

1042

1043

1044

1045

1046

1047

1048

1049

1050

1051

1052

1053

1054

1055

1056

1057

1058

1059

1060

1061

1062

1063

1064

1065

1066

1067

1068

1069

1070

1071

1072

1073

1074

1075

1076

1077

1078

1079

1080

1081

1082

1083

1084

1085

1086

1087

1088

1089

1090

1091

1092

1093

1094

1095

1096

1097

1098

1099

1100

1101

1102

1103

1104

1105

1106

1107

1108

1109

1110

1111

1112

1113

1114

1115

1116

1117

1118

1119

1120

1121

1122

1123

1124

1125

1126

1127

1128

1129

1130

1131

1132

1133

1134

1135

1136

1137

1138

1139

1140

1141

1142

1143

1144

1145

1146

1147

1148

1149

1150

1151

1152

1153

1154

1155

1156

1157

1158

1159

1160

1161

1162

1163

1164

1165

1166

1167

1168

1169

1170

1171

1172

1173

1174

1175

1176

1177

1178

1179

1180

1181

1182

1183

1184

1185

1186

1187

1188

1189

1190

1191

1192

1193

1194

1195

1196

1197

1198

1199

1200

1201

1202

1203

1204

1205

1206

1207

1208

1209

1210

1211

1212

1213

1214

1215

1216

1217

1218

1219

1220

1221

1222

1223

1224

1225

1226

1227

1228

1229

1230

1231

1232

1233

1234

1235

1236

1237

1238

1239

1240

1241

1242

1243

1244

1245

1246

1247

1248

1249

1250

1251

1252

1253

1254

1255

1256

1257

1258

1259

1260

1261

1262

1263

1264

1265

1266

1267

1268

1269

1270

1271

1272

1273

1274

1275

1276

1277

1278

1279

1280

1281

1282

1283

1284

1285

1286

1287

1288

1289

1290

1291

1292

1293

1294

1295

1296

1297

1298

1299

1300

1301

1302

1303

1304

1305

1306

1307

1308

1309

1310

1311

1312

1313

1314

1315

1316

1317

1318

1319

1320

1321

1322

1323

1324

1325

1326

1327

1328

1329

1330

1331

1332

1333

1334

1335

1336

1337

1338

1339

1340

1341

1342

1343

1344

1345

1346

1347

1348

1349

1350

1351

1352

1353

1354

1355

1356

1357

1358

1359

1360

1361

1362

1363

1364

1365

1366

1367

1368

1369

1370

1371

1372

1373

1374

1375

1376

1377

1378

1379

1380

1381

1382

1383

1384

1385

1386

1387

1388

1389

1390

1391

1392

1393

1394

1395

1396

1397

1398

1399

1400

1401

1402

1403

1404

1405

1406

1407

1408

1409

1410

1411

1412

1413

1414

1415

1416

1417

1418

1419

1420

1421

1422

1423

1424

1425

1426

1427

1428

1429

1430

1431

1432

1433

1434

1435

1436

1437

1438

1439

1440

1441

1442

1443

1444

1445

1446

1447

1448

1449

1450

1451

1452

1453

1454

1455

1456

from __future__ import print_function, division 

 

from sympy.logic.boolalg import And 

from sympy.core.add import Add 

from sympy.core.basic import Basic 

from sympy.core.compatibility import as_int, with_metaclass, range, PY3 

from sympy.core.expr import Expr 

from sympy.core.function import Lambda, _coeff_isneg 

from sympy.core.singleton import Singleton, S 

from sympy.core.symbol import Dummy, symbols, Wild 

from sympy.core.sympify import _sympify, sympify, converter 

from sympy.sets.sets import (Set, Interval, Intersection, EmptySet, Union, 

FiniteSet, imageset) 

from sympy.sets.conditionset import ConditionSet 

from sympy.utilities.misc import filldedent, func_name 

 

 

class Naturals(with_metaclass(Singleton, Set)): 

""" 

Represents the natural numbers (or counting numbers) which are all 

positive integers starting from 1. This set is also available as 

the Singleton, S.Naturals. 

 

Examples 

======== 

 

>>> from sympy import S, Interval, pprint 

>>> 5 in S.Naturals 

True 

>>> iterable = iter(S.Naturals) 

>>> next(iterable) 

1 

>>> next(iterable) 

2 

>>> next(iterable) 

3 

>>> pprint(S.Naturals.intersect(Interval(0, 10))) 

{1, 2, ..., 10} 

 

See Also 

======== 

Naturals0 : non-negative integers (i.e. includes 0, too) 

Integers : also includes negative integers 

""" 

 

is_iterable = True 

_inf = S.One 

_sup = S.Infinity 

 

def _intersect(self, other): 

if other.is_Interval: 

return Intersection( 

S.Integers, other, Interval(self._inf, S.Infinity)) 

return None 

 

def _contains(self, other): 

if other.is_positive and other.is_integer: 

return S.true 

elif other.is_integer is False or other.is_positive is False: 

return S.false 

 

def __iter__(self): 

i = self._inf 

while True: 

yield i 

i = i + 1 

 

@property 

def _boundary(self): 

return self 

 

 

class Naturals0(Naturals): 

"""Represents the whole numbers which are all the non-negative integers, 

inclusive of zero. 

 

See Also 

======== 

Naturals : positive integers; does not include 0 

Integers : also includes the negative integers 

""" 

_inf = S.Zero 

 

def _contains(self, other): 

if other.is_integer and other.is_nonnegative: 

return S.true 

elif other.is_integer is False or other.is_nonnegative is False: 

return S.false 

 

 

class Integers(with_metaclass(Singleton, Set)): 

""" 

Represents all integers: positive, negative and zero. This set is also 

available as the Singleton, S.Integers. 

 

Examples 

======== 

 

>>> from sympy import S, Interval, pprint 

>>> 5 in S.Naturals 

True 

>>> iterable = iter(S.Integers) 

>>> next(iterable) 

0 

>>> next(iterable) 

1 

>>> next(iterable) 

-1 

>>> next(iterable) 

2 

 

>>> pprint(S.Integers.intersect(Interval(-4, 4))) 

{-4, -3, ..., 4} 

 

See Also 

======== 

Naturals0 : non-negative integers 

Integers : positive and negative integers and zero 

""" 

 

is_iterable = True 

 

def _intersect(self, other): 

from sympy.functions.elementary.integers import floor, ceiling 

if other is Interval(S.NegativeInfinity, S.Infinity) or other is S.Reals: 

return self 

elif other.is_Interval: 

s = Range(ceiling(other.left), floor(other.right) + 1) 

return s.intersect(other) # take out endpoints if open interval 

return None 

 

def _contains(self, other): 

if other.is_integer: 

return S.true 

elif other.is_integer is False: 

return S.false 

 

def _union(self, other): 

intersect = Intersection(self, other) 

if intersect == self: 

return other 

elif intersect == other: 

return self 

 

def __iter__(self): 

yield S.Zero 

i = S.One 

while True: 

yield i 

yield -i 

i = i + 1 

 

@property 

def _inf(self): 

return -S.Infinity 

 

@property 

def _sup(self): 

return S.Infinity 

 

@property 

def _boundary(self): 

return self 

 

def _eval_imageset(self, f): 

expr = f.expr 

if not isinstance(expr, Expr): 

return 

 

if len(f.variables) > 1: 

return 

 

n = f.variables[0] 

 

# f(x) + c and f(-x) + c cover the same integers 

# so choose the form that has the fewest negatives 

c = f(0) 

fx = f(n) - c 

f_x = f(-n) - c 

neg_count = lambda e: sum(_coeff_isneg(_) for _ in Add.make_args(e)) 

if neg_count(f_x) < neg_count(fx): 

expr = f_x + c 

 

a = Wild('a', exclude=[n]) 

b = Wild('b', exclude=[n]) 

match = expr.match(a*n + b) 

if match and match[a]: 

# canonical shift 

expr = match[a]*n + match[b] % match[a] 

 

if expr != f.expr: 

return ImageSet(Lambda(n, expr), S.Integers) 

 

 

class Reals(with_metaclass(Singleton, Interval)): 

 

def __new__(cls): 

return Interval.__new__(cls, -S.Infinity, S.Infinity) 

 

def __eq__(self, other): 

return other == Interval(-S.Infinity, S.Infinity) 

 

def __hash__(self): 

return hash(Interval(-S.Infinity, S.Infinity)) 

 

 

class ImageSet(Set): 

""" 

Image of a set under a mathematical function. The transformation 

must be given as a Lambda function which has as many arguments 

as the elements of the set upon which it operates, e.g. 1 argument 

when acting on the set of integers or 2 arguments when acting on 

a complex region. 

 

This function is not normally called directly, but is called 

from `imageset`. 

 

 

Examples 

======== 

 

>>> from sympy import Symbol, S, pi, Dummy, Lambda 

>>> from sympy.sets.sets import FiniteSet, Interval 

>>> from sympy.sets.fancysets import ImageSet 

 

>>> x = Symbol('x') 

>>> N = S.Naturals 

>>> squares = ImageSet(Lambda(x, x**2), N) # {x**2 for x in N} 

>>> 4 in squares 

True 

>>> 5 in squares 

False 

 

>>> FiniteSet(0, 1, 2, 3, 4, 5, 6, 7, 9, 10).intersect(squares) 

{1, 4, 9} 

 

>>> square_iterable = iter(squares) 

>>> for i in range(4): 

... next(square_iterable) 

1 

4 

9 

16 

 

If you want to get value for `x` = 2, 1/2 etc. (Please check whether the 

`x` value is in `base_set` or not before passing it as args) 

 

>>> squares.lamda(2) 

4 

>>> squares.lamda(S(1)/2) 

1/4 

 

>>> n = Dummy('n') 

>>> solutions = ImageSet(Lambda(n, n*pi), S.Integers) # solutions of sin(x) = 0 

>>> dom = Interval(-1, 1) 

>>> dom.intersect(solutions) 

{0} 

 

See Also 

======== 

sympy.sets.sets.imageset 

""" 

def __new__(cls, lamda, base_set): 

if not isinstance(lamda, Lambda): 

raise ValueError('first argument must be a Lambda') 

if lamda is S.IdentityFunction: 

return base_set 

if not lamda.expr.free_symbols or not lamda.expr.args: 

return FiniteSet(lamda.expr) 

 

return Basic.__new__(cls, lamda, base_set) 

 

lamda = property(lambda self: self.args[0]) 

base_set = property(lambda self: self.args[1]) 

 

def __iter__(self): 

already_seen = set() 

for i in self.base_set: 

val = self.lamda(i) 

if val in already_seen: 

continue 

else: 

already_seen.add(val) 

yield val 

 

def _is_multivariate(self): 

return len(self.lamda.variables) > 1 

 

def _contains(self, other): 

from sympy.matrices import Matrix 

from sympy.solvers.solveset import solveset, linsolve 

from sympy.utilities.iterables import is_sequence, iterable, cartes 

L = self.lamda 

if is_sequence(other): 

if not is_sequence(L.expr): 

return S.false 

if len(L.expr) != len(other): 

raise ValueError(filldedent(''' 

Dimensions of other and output of Lambda are different.''')) 

elif iterable(other): 

raise ValueError(filldedent(''' 

`other` should be an ordered object like a Tuple.''')) 

 

solns = None 

if self._is_multivariate(): 

if not is_sequence(L.expr): 

# exprs -> (numer, denom) and check again 

# XXX this is a bad idea -- make the user 

# remap self to desired form 

return other.as_numer_denom() in self.func( 

Lambda(L.variables, L.expr.as_numer_denom()), self.base_set) 

eqs = [expr - val for val, expr in zip(other, L.expr)] 

variables = L.variables 

free = set(variables) 

if all(i.is_number for i in list(Matrix(eqs).jacobian(variables))): 

solns = list(linsolve([e - val for e, val in 

zip(L.expr, other)], variables)) 

else: 

syms = [e.free_symbols & free for e in eqs] 

solns = {} 

for i, (e, s, v) in enumerate(zip(eqs, syms, other)): 

if not s: 

if e != v: 

return S.false 

solns[vars[i]] = [v] 

continue 

elif len(s) == 1: 

sy = s.pop() 

sol = solveset(e, sy) 

if sol is S.EmptySet: 

return S.false 

elif isinstance(sol, FiniteSet): 

solns[sy] = list(sol) 

else: 

raise NotImplementedError 

else: 

raise NotImplementedError 

solns = cartes(*[solns[s] for s in variables]) 

else: 

x = L.variables[0] 

if isinstance(L.expr, Expr): 

# scalar -> scalar mapping 

solnsSet = solveset(L.expr - other, x) 

if solnsSet.is_FiniteSet: 

solns = list(solnsSet) 

else: 

msgset = solnsSet 

else: 

# scalar -> vector 

for e, o in zip(L.expr, other): 

solns = solveset(e - o, x) 

if solns is S.EmptySet: 

return S.false 

for soln in solns: 

try: 

if soln in self.base_set: 

break # check next pair 

except TypeError: 

if self.base_set.contains(soln.evalf()): 

break 

else: 

return S.false # never broke so there was no True 

return S.true 

 

if solns is None: 

raise NotImplementedError(filldedent(''' 

Determining whether %s contains %s has not 

been implemented.''' % (msgset, other))) 

for soln in solns: 

try: 

if soln in self.base_set: 

return S.true 

except TypeError: 

return self.base_set.contains(soln.evalf()) 

return S.false 

 

@property 

def is_iterable(self): 

return self.base_set.is_iterable 

 

def _intersect(self, other): 

from sympy.solvers.diophantine import diophantine 

if self.base_set is S.Integers: 

g = None 

if isinstance(other, ImageSet) and other.base_set is S.Integers: 

g = other.lamda.expr 

m = other.lamda.variables[0] 

elif other is S.Integers: 

m = g = Dummy('x') 

if g is not None: 

f = self.lamda.expr 

n = self.lamda.variables[0] 

# Diophantine sorts the solutions according to the alphabetic 

# order of the variable names, since the result should not depend 

# on the variable name, they are replaced by the dummy variables 

# below 

a, b = Dummy('a'), Dummy('b') 

f, g = f.subs(n, a), g.subs(m, b) 

solns_set = diophantine(f - g) 

if solns_set == set(): 

return EmptySet() 

solns = list(diophantine(f - g)) 

 

if len(solns) != 1: 

return 

 

# since 'a' < 'b', select soln for n 

nsol = solns[0][0] 

t = nsol.free_symbols.pop() 

return imageset(Lambda(n, f.subs(a, nsol.subs(t, n))), S.Integers) 

 

if other == S.Reals: 

from sympy.solvers.solveset import solveset_real 

from sympy.core.function import expand_complex 

if len(self.lamda.variables) > 1: 

return None 

 

f = self.lamda.expr 

n = self.lamda.variables[0] 

 

n_ = Dummy(n.name, real=True) 

f_ = f.subs(n, n_) 

 

re, im = f_.as_real_imag() 

im = expand_complex(im) 

 

return imageset(Lambda(n_, re), 

self.base_set.intersect( 

solveset_real(im, n_))) 

 

elif isinstance(other, Interval): 

from sympy.solvers.solveset import (invert_real, invert_complex, 

solveset) 

 

f = self.lamda.expr 

n = self.lamda.variables[0] 

base_set = self.base_set 

new_inf, new_sup = None, None 

 

if f.is_real: 

inverter = invert_real 

else: 

inverter = invert_complex 

 

g1, h1 = inverter(f, other.inf, n) 

g2, h2 = inverter(f, other.sup, n) 

 

if all(isinstance(i, FiniteSet) for i in (h1, h2)): 

if g1 == n: 

if len(h1) == 1: 

new_inf = h1.args[0] 

if g2 == n: 

if len(h2) == 1: 

new_sup = h2.args[0] 

# TODO: Design a technique to handle multiple-inverse 

# functions 

 

# Any of the new boundary values cannot be determined 

if any(i is None for i in (new_sup, new_inf)): 

return 

 

range_set = S.EmptySet 

 

if all(i.is_real for i in (new_sup, new_inf)): 

new_interval = Interval(new_inf, new_sup) 

range_set = base_set._intersect(new_interval) 

else: 

if other.is_subset(S.Reals): 

solutions = solveset(f, n, S.Reals) 

if not isinstance(range_set, (ImageSet, ConditionSet)): 

range_set = solutions._intersect(other) 

else: 

return 

 

if range_set is S.EmptySet: 

return S.EmptySet 

elif isinstance(range_set, Range) and range_set.size is not S.Infinity: 

range_set = FiniteSet(*list(range_set)) 

 

if range_set is not None: 

return imageset(Lambda(n, f), range_set) 

return 

else: 

return 

 

 

class Range(Set): 

""" 

Represents a range of integers. Can be called as Range(stop), 

Range(start, stop), or Range(start, stop, step); when stop is 

not given it defaults to 1. 

 

`Range(stop)` is the same as `Range(0, stop, 1)` and the stop value 

(juse as for Python ranges) is not included in the Range values. 

 

>>> from sympy import Range 

>>> list(Range(3)) 

[0, 1, 2] 

 

The step can also be negative: 

 

>>> list(Range(10, 0, -2)) 

[10, 8, 6, 4, 2] 

 

The stop value is made canonical so equivalent ranges always 

have the same args: 

 

>>> Range(0, 10, 3) 

Range(0, 12, 3) 

 

Infinite ranges are allowed. If the starting point is infinite, 

then the final value is ``stop - step``. To iterate such a range, 

it needs to be reversed: 

 

>>> from sympy import oo 

>>> r = Range(-oo, 1) 

>>> r[-1] 

0 

>>> next(iter(r)) 

Traceback (most recent call last): 

... 

ValueError: Cannot iterate over Range with infinite start 

>>> next(iter(r.reversed)) 

0 

 

Although Range is a set (and supports the normal set 

operations) it maintains the order of the elements and can 

be used in contexts where `range` would be used. 

 

>>> from sympy import Interval 

>>> Range(0, 10, 2).intersect(Interval(3, 7)) 

Range(4, 8, 2) 

>>> list(_) 

[4, 6] 

 

Athough slicing of a Range will always return a Range -- possibly 

empty -- an empty set will be returned from any intersection that 

is empty: 

 

>>> Range(3)[:0] 

Range(0, 0, 1) 

>>> Range(3).intersect(Interval(4, oo)) 

EmptySet() 

>>> Range(3).intersect(Range(4, oo)) 

EmptySet() 

 

""" 

 

is_iterable = True 

 

def __new__(cls, *args): 

from sympy.functions.elementary.integers import ceiling 

if len(args) == 1: 

if isinstance(args[0], range if PY3 else xrange): 

args = args[0].__reduce__()[1] # use pickle method 

 

# expand range 

slc = slice(*args) 

 

if slc.step == 0: 

raise ValueError("step cannot be 0") 

 

start, stop, step = slc.start or 0, slc.stop, slc.step or 1 

try: 

start, stop, step = [ 

w if w in [S.NegativeInfinity, S.Infinity] 

else sympify(as_int(w)) 

for w in (start, stop, step)] 

except ValueError: 

raise ValueError(filldedent(''' 

Finite arguments to Range must be integers; `imageset` can define 

other cases, e.g. use `imageset(i, i/10, Range(3))` to give 

[0, 1/10, 1/5].''')) 

 

if not step.is_Integer: 

raise ValueError(filldedent(''' 

Ranges must have a literal integer step.''')) 

 

if all(i.is_infinite for i in (start, stop)): 

if start == stop: 

# canonical null handled below 

start = stop = S.One 

else: 

raise ValueError(filldedent(''' 

Either the start or end value of the Range must be finite.''')) 

 

if start.is_infinite: 

end = stop 

else: 

ref = start if start.is_finite else stop 

n = ceiling((stop - ref)/step) 

if n <= 0: 

# null Range 

start = end = 0 

step = 1 

else: 

end = ref + n*step 

return Basic.__new__(cls, start, end, step) 

 

start = property(lambda self: self.args[0]) 

stop = property(lambda self: self.args[1]) 

step = property(lambda self: self.args[2]) 

 

@property 

def reversed(self): 

"""Return an equivalent Range in the opposite order. 

 

Examples 

======== 

 

>>> from sympy import Range 

>>> Range(10).reversed 

Range(9, -1, -1) 

""" 

if not self: 

return self 

return self.func( 

self.stop - self.step, self.start - self.step, -self.step) 

 

def _intersect(self, other): 

from sympy.functions.elementary.integers import ceiling, floor 

from sympy.functions.elementary.complexes import sign 

 

if other is S.Naturals: 

return self._intersect(Interval(1, S.Infinity)) 

 

if other is S.Integers: 

return self 

 

if other.is_Interval: 

if not all(i.is_number for i in other.args[:2]): 

return 

 

# In case of null Range, return an EmptySet. 

if self.size == 0: 

return S.EmptySet 

 

# trim down to self's size, and represent 

# as a Range with step 1. 

start = ceiling(max(other.inf, self.inf)) 

if start not in other: 

start += 1 

end = floor(min(other.sup, self.sup)) 

if end not in other: 

end -= 1 

return self.intersect(Range(start, end + 1)) 

 

if isinstance(other, Range): 

from sympy.solvers.diophantine import diop_linear 

from sympy.core.numbers import ilcm 

 

# non-overlap quick exits 

if not other: 

return S.EmptySet 

if not self: 

return S.EmptySet 

if other.sup < self.inf: 

return S.EmptySet 

if other.inf > self.sup: 

return S.EmptySet 

 

# work with finite end at the start 

r1 = self 

if r1.start.is_infinite: 

r1 = r1.reversed 

r2 = other 

if r2.start.is_infinite: 

r2 = r2.reversed 

 

# this equation represents the values of the Range; 

# it's a linear equation 

eq = lambda r, i: r.start + i*r.step 

 

# we want to know when the two equations might 

# have integer solutions so we use the diophantine 

# solver 

a, b = diop_linear(eq(r1, Dummy()) - eq(r2, Dummy())) 

 

# check for no solution 

no_solution = a is None and b is None 

if no_solution: 

return S.EmptySet 

 

# there is a solution 

# ------------------- 

 

# find the coincident point, c 

a0 = a.as_coeff_Add()[0] 

c = eq(r1, a0) 

 

# find the first point, if possible, in each range 

# since c may not be that point 

def _first_finite_point(r1, c): 

if c == r1.start: 

return c 

# st is the signed step we need to take to 

# get from c to r1.start 

st = sign(r1.start - c)*step 

# use Range to calculate the first point: 

# we want to get as close as possible to 

# r1.start; the Range will not be null since 

# it will at least contain c 

s1 = Range(c, r1.start + st, st)[-1] 

if s1 == r1.start: 

pass 

else: 

# if we didn't hit r1.start then, if the 

# sign of st didn't match the sign of r1.step 

# we are off by one and s1 is not in r1 

if sign(r1.step) != sign(st): 

s1 -= st 

if s1 not in r1: 

return 

return s1 

 

# calculate the step size of the new Range 

step = abs(ilcm(r1.step, r2.step)) 

s1 = _first_finite_point(r1, c) 

if s1 is None: 

return S.EmptySet 

s2 = _first_finite_point(r2, c) 

if s2 is None: 

return S.EmptySet 

 

# replace the corresponding start or stop in 

# the original Ranges with these points; the 

# result must have at least one point since 

# we know that s1 and s2 are in the Ranges 

def _updated_range(r, first): 

st = sign(r.step)*step 

if r.start.is_finite: 

rv = Range(first, r.stop, st) 

else: 

rv = Range(r.start, first + st, st) 

return rv 

r1 = _updated_range(self, s1) 

r2 = _updated_range(other, s2) 

 

# work with them both in the increasing direction 

if sign(r1.step) < 0: 

r1 = r1.reversed 

if sign(r2.step) < 0: 

r2 = r2.reversed 

 

# return clipped Range with positive step; it 

# can't be empty at this point 

start = max(r1.start, r2.start) 

stop = min(r1.stop, r2.stop) 

return Range(start, stop, step) 

else: 

return 

 

def _contains(self, other): 

if not self: 

return S.false 

if other.is_infinite: 

return S.false 

if not other.is_integer: 

return other.is_integer 

ref = self.start if self.start.is_finite else self.stop 

if (ref - other) % self.step: # off sequence 

return S.false 

return _sympify(other >= self.inf and other <= self.sup) 

 

def __iter__(self): 

if self.start in [S.NegativeInfinity, S.Infinity]: 

raise ValueError("Cannot iterate over Range with infinite start") 

elif self: 

i = self.start 

step = self.step 

 

while True: 

if (step > 0 and not (self.start <= i < self.stop)) or \ 

(step < 0 and not (self.stop < i <= self.start)): 

break 

yield i 

i += step 

 

def __len__(self): 

if not self: 

return 0 

dif = self.stop - self.start 

if dif.is_infinite: 

raise ValueError( 

"Use .size to get the length of an infinite Range") 

return abs(dif//self.step) 

 

@property 

def size(self): 

try: 

return _sympify(len(self)) 

except ValueError: 

return S.Infinity 

 

def __nonzero__(self): 

return self.start != self.stop 

 

__bool__ = __nonzero__ 

 

def __getitem__(self, i): 

from sympy.functions.elementary.integers import ceiling 

ooslice = "cannot slice from the end with an infinite value" 

zerostep = "slice step cannot be zero" 

# if we had to take every other element in the following 

# oo, ..., 6, 4, 2, 0 

# we might get oo, ..., 4, 0 or oo, ..., 6, 2 

ambiguous = "cannot unambiguously re-stride from the end " + \ 

"with an infinite value" 

if isinstance(i, slice): 

if self.size.is_finite: 

start, stop, step = i.indices(self.size) 

n = ceiling((stop - start)/step) 

if n <= 0: 

return Range(0) 

canonical_stop = start + n*step 

end = canonical_stop - step 

ss = step*self.step 

return Range(self[start], self[end] + ss, ss) 

else: # infinite Range 

start = i.start 

stop = i.stop 

if i.step == 0: 

raise ValueError(zerostep) 

step = i.step or 1 

ss = step*self.step 

#--------------------- 

# handle infinite on right 

# e.g. Range(0, oo) or Range(0, -oo, -1) 

# -------------------- 

if self.stop.is_infinite: 

# start and stop are not interdependent -- 

# they only depend on step --so we use the 

# equivalent reversed values 

return self.reversed[ 

stop if stop is None else -stop + 1: 

start if start is None else -start: 

step].reversed 

#--------------------- 

# handle infinite on the left 

# e.g. Range(oo, 0, -1) or Range(-oo, 0) 

# -------------------- 

# consider combinations of 

# start/stop {== None, < 0, == 0, > 0} and 

# step {< 0, > 0} 

if start is None: 

if stop is None: 

if step < 0: 

return Range(self[-1], self.start, ss) 

elif step > 1: 

raise ValueError(ambiguous) 

else: # == 1 

return self 

elif stop < 0: 

if step < 0: 

return Range(self[-1], self[stop], ss) 

else: # > 0 

return Range(self.start, self[stop], ss) 

elif stop == 0: 

if step > 0: 

return Range(0) 

else: # < 0 

raise ValueError(ooslice) 

elif stop == 1: 

if step > 0: 

raise ValueError(ooslice) # infinite singleton 

else: # < 0 

raise ValueError(ooslice) 

else: # > 1 

raise ValueError(ooslice) 

elif start < 0: 

if stop is None: 

if step < 0: 

return Range(self[start], self.start, ss) 

else: # > 0 

return Range(self[start], self.stop, ss) 

elif stop < 0: 

return Range(self[start], self[stop], ss) 

elif stop == 0: 

if step < 0: 

raise ValueError(ooslice) 

else: # > 0 

return Range(0) 

elif stop > 0: 

raise ValueError(ooslice) 

elif start == 0: 

if stop is None: 

if step < 0: 

raise ValueError(ooslice) # infinite singleton 

elif step > 1: 

raise ValueError(ambiguous) 

else: # == 1 

return self 

elif stop < 0: 

if step > 1: 

raise ValueError(ambiguous) 

elif step == 1: 

return Range(self.start, self[stop], ss) 

else: # < 0 

return Range(0) 

else: # >= 0 

raise ValueError(ooslice) 

elif start > 0: 

raise ValueError(ooslice) 

else: 

if not self: 

raise IndexError('Range index out of range') 

if i == 0: 

return self.start 

if i == -1 or i is S.Infinity: 

return self.stop - self.step 

rv = (self.stop if i < 0 else self.start) + i*self.step 

if rv.is_infinite: 

raise ValueError(ooslice) 

if rv < self.inf or rv > self.sup: 

raise IndexError("Range index out of range") 

return rv 

 

def _eval_imageset(self, f): 

from sympy.core.function import expand_mul 

if not self: 

return S.EmptySet 

if not isinstance(f.expr, Expr): 

return 

if self.size == 1: 

return FiniteSet(f(self[0])) 

if f is S.IdentityFunction: 

return self 

 

x = f.variables[0] 

expr = f.expr 

# handle f that is linear in f's variable 

if x not in expr.free_symbols or x in expr.diff(x).free_symbols: 

return 

if self.start.is_finite: 

F = f(self.step*x + self.start) # for i in range(len(self)) 

else: 

F = f(-self.step*x + self[-1]) 

F = expand_mul(F) 

if F != expr: 

return imageset(x, F, Range(self.size)) 

 

@property 

def _inf(self): 

if not self: 

raise NotImplementedError 

if self.step > 0: 

return self.start 

else: 

return self.stop - self.step 

 

@property 

def _sup(self): 

if not self: 

raise NotImplementedError 

if self.step > 0: 

return self.stop - self.step 

else: 

return self.start 

 

@property 

def _boundary(self): 

return self 

 

 

if PY3: 

converter[range] = Range 

else: 

converter[xrange] = Range 

 

def normalize_theta_set(theta): 

""" 

Normalize a Real Set `theta` in the Interval [0, 2*pi). It returns 

a normalized value of theta in the Set. For Interval, a maximum of 

one cycle [0, 2*pi], is returned i.e. for theta equal to [0, 10*pi], 

returned normalized value would be [0, 2*pi). As of now intervals 

with end points as non-multiples of `pi` is not supported. 

 

Raises 

====== 

 

NotImplementedError 

The algorithms for Normalizing theta Set are not yet 

implemented. 

ValueError 

The input is not valid, i.e. the input is not a real set. 

RuntimeError 

It is a bug, please report to the github issue tracker. 

 

Examples 

======== 

 

>>> from sympy.sets.fancysets import normalize_theta_set 

>>> from sympy import Interval, FiniteSet, pi 

>>> normalize_theta_set(Interval(9*pi/2, 5*pi)) 

[pi/2, pi] 

>>> normalize_theta_set(Interval(-3*pi/2, pi/2)) 

[0, 2*pi) 

>>> normalize_theta_set(Interval(-pi/2, pi/2)) 

[0, pi/2] U [3*pi/2, 2*pi) 

>>> normalize_theta_set(Interval(-4*pi, 3*pi)) 

[0, 2*pi) 

>>> normalize_theta_set(Interval(-3*pi/2, -pi/2)) 

[pi/2, 3*pi/2] 

>>> normalize_theta_set(FiniteSet(0, pi, 3*pi)) 

{0, pi} 

 

""" 

from sympy.functions.elementary.trigonometric import _pi_coeff as coeff 

 

if theta.is_Interval: 

interval_len = theta.measure 

# one complete circle 

if interval_len >= 2*S.Pi: 

if interval_len == 2*S.Pi and theta.left_open and theta.right_open: 

k = coeff(theta.start) 

return Union(Interval(0, k*S.Pi, False, True), 

Interval(k*S.Pi, 2*S.Pi, True, True)) 

return Interval(0, 2*S.Pi, False, True) 

 

k_start, k_end = coeff(theta.start), coeff(theta.end) 

 

if k_start is None or k_end is None: 

raise NotImplementedError("Normalizing theta without pi as coefficient is " 

"not yet implemented") 

new_start = k_start*S.Pi 

new_end = k_end*S.Pi 

 

if new_start > new_end: 

return Union(Interval(S.Zero, new_end, False, theta.right_open), 

Interval(new_start, 2*S.Pi, theta.left_open, True)) 

else: 

return Interval(new_start, new_end, theta.left_open, theta.right_open) 

 

elif theta.is_FiniteSet: 

new_theta = [] 

for element in theta: 

k = coeff(element) 

if k is None: 

raise NotImplementedError('Normalizing theta without pi as ' 

'coefficient, is not Implemented.') 

else: 

new_theta.append(k*S.Pi) 

return FiniteSet(*new_theta) 

 

elif theta.is_Union: 

return Union(*[normalize_theta_set(interval) for interval in theta.args]) 

 

elif theta.is_subset(S.Reals): 

raise NotImplementedError("Normalizing theta when, it is of type %s is not " 

"implemented" % type(theta)) 

else: 

raise ValueError(" %s is not a real set" % (theta)) 

 

 

class ComplexRegion(Set): 

""" 

Represents the Set of all Complex Numbers. It can represent a 

region of Complex Plane in both the standard forms Polar and 

Rectangular coordinates. 

 

* Polar Form 

Input is in the form of the ProductSet or Union of ProductSets 

of the intervals of r and theta, & use the flag polar=True. 

 

Z = {z in C | z = r*[cos(theta) + I*sin(theta)], r in [r], theta in [theta]} 

 

* Rectangular Form 

Input is in the form of the ProductSet or Union of ProductSets 

of interval of x and y the of the Complex numbers in a Plane. 

Default input type is in rectangular form. 

 

Z = {z in C | z = x + I*y, x in [Re(z)], y in [Im(z)]} 

 

Examples 

======== 

 

>>> from sympy.sets.fancysets import ComplexRegion 

>>> from sympy.sets import Interval 

>>> from sympy import S, I, Union 

>>> a = Interval(2, 3) 

>>> b = Interval(4, 6) 

>>> c = Interval(1, 8) 

>>> c1 = ComplexRegion(a*b) # Rectangular Form 

>>> c1 

ComplexRegion([2, 3] x [4, 6], False) 

 

* c1 represents the rectangular region in complex plane 

surrounded by the coordinates (2, 4), (3, 4), (3, 6) and 

(2, 6), of the four vertices. 

 

>>> c2 = ComplexRegion(Union(a*b, b*c)) 

>>> c2 

ComplexRegion([2, 3] x [4, 6] U [4, 6] x [1, 8], False) 

 

* c2 represents the Union of two rectangular regions in complex 

plane. One of them surrounded by the coordinates of c1 and 

other surrounded by the coordinates (4, 1), (6, 1), (6, 8) and 

(4, 8). 

 

>>> 2.5 + 4.5*I in c1 

True 

>>> 2.5 + 6.5*I in c1 

False 

 

>>> r = Interval(0, 1) 

>>> theta = Interval(0, 2*S.Pi) 

>>> c2 = ComplexRegion(r*theta, polar=True) # Polar Form 

>>> c2 # unit Disk 

ComplexRegion([0, 1] x [0, 2*pi), True) 

 

* c2 represents the region in complex plane inside the 

Unit Disk centered at the origin. 

 

>>> 0.5 + 0.5*I in c2 

True 

>>> 1 + 2*I in c2 

False 

 

>>> unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, 2*S.Pi), polar=True) 

>>> upper_half_unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, S.Pi), polar=True) 

>>> intersection = unit_disk.intersect(upper_half_unit_disk) 

>>> intersection 

ComplexRegion([0, 1] x [0, pi], True) 

>>> intersection == upper_half_unit_disk 

True 

 

See Also 

======== 

 

Reals 

 

""" 

is_ComplexRegion = True 

 

def __new__(cls, sets, polar=False): 

from sympy import sin, cos 

 

x, y, r, theta = symbols('x, y, r, theta', cls=Dummy) 

I = S.ImaginaryUnit 

polar = sympify(polar) 

 

# Rectangular Form 

if polar == False: 

if all(_a.is_FiniteSet for _a in sets.args) and (len(sets.args) == 2): 

 

# ** ProductSet of FiniteSets in the Complex Plane. ** 

# For Cases like ComplexRegion({2, 4}*{3}), It 

# would return {2 + 3*I, 4 + 3*I} 

complex_num = [] 

for x in sets.args[0]: 

for y in sets.args[1]: 

complex_num.append(x + I*y) 

obj = FiniteSet(*complex_num) 

else: 

obj = ImageSet.__new__(cls, Lambda((x, y), x + I*y), sets) 

obj._variables = (x, y) 

obj._expr = x + I*y 

 

# Polar Form 

elif polar == True: 

new_sets = [] 

# sets is Union of ProductSets 

if not sets.is_ProductSet: 

for k in sets.args: 

new_sets.append(k) 

# sets is ProductSets 

else: 

new_sets.append(sets) 

# Normalize input theta 

for k, v in enumerate(new_sets): 

from sympy.sets import ProductSet 

new_sets[k] = ProductSet(v.args[0], 

normalize_theta_set(v.args[1])) 

sets = Union(*new_sets) 

obj = ImageSet.__new__(cls, Lambda((r, theta), 

r*(cos(theta) + I*sin(theta))), 

sets) 

obj._variables = (r, theta) 

obj._expr = r*(cos(theta) + I*sin(theta)) 

 

else: 

raise ValueError("polar should be either True or False") 

 

obj._sets = sets 

obj._polar = polar 

return obj 

 

@property 

def sets(self): 

""" 

Return raw input sets to the self. 

 

Examples 

======== 

 

>>> from sympy import Interval, ComplexRegion, Union 

>>> a = Interval(2, 3) 

>>> b = Interval(4, 5) 

>>> c = Interval(1, 7) 

>>> C1 = ComplexRegion(a*b) 

>>> C1.sets 

[2, 3] x [4, 5] 

>>> C2 = ComplexRegion(Union(a*b, b*c)) 

>>> C2.sets 

[2, 3] x [4, 5] U [4, 5] x [1, 7] 

 

""" 

return self._sets 

 

@property 

def args(self): 

return (self._sets, self._polar) 

 

@property 

def variables(self): 

return self._variables 

 

@property 

def expr(self): 

return self._expr 

 

@property 

def psets(self): 

""" 

Return a tuple of sets (ProductSets) input of the self. 

 

Examples 

======== 

 

>>> from sympy import Interval, ComplexRegion, Union 

>>> a = Interval(2, 3) 

>>> b = Interval(4, 5) 

>>> c = Interval(1, 7) 

>>> C1 = ComplexRegion(a*b) 

>>> C1.psets 

([2, 3] x [4, 5],) 

>>> C2 = ComplexRegion(Union(a*b, b*c)) 

>>> C2.psets 

([2, 3] x [4, 5], [4, 5] x [1, 7]) 

 

""" 

if self.sets.is_ProductSet: 

psets = () 

psets = psets + (self.sets, ) 

else: 

psets = self.sets.args 

return psets 

 

@property 

def a_interval(self): 

""" 

Return the union of intervals of `x` when, self is in 

rectangular form, or the union of intervals of `r` when 

self is in polar form. 

 

Examples 

======== 

 

>>> from sympy import Interval, ComplexRegion, Union 

>>> a = Interval(2, 3) 

>>> b = Interval(4, 5) 

>>> c = Interval(1, 7) 

>>> C1 = ComplexRegion(a*b) 

>>> C1.a_interval 

[2, 3] 

>>> C2 = ComplexRegion(Union(a*b, b*c)) 

>>> C2.a_interval 

[2, 3] U [4, 5] 

 

""" 

a_interval = [] 

for element in self.psets: 

a_interval.append(element.args[0]) 

 

a_interval = Union(*a_interval) 

return a_interval 

 

@property 

def b_interval(self): 

""" 

Return the union of intervals of `y` when, self is in 

rectangular form, or the union of intervals of `theta` 

when self is in polar form. 

 

Examples 

======== 

 

>>> from sympy import Interval, ComplexRegion, Union 

>>> a = Interval(2, 3) 

>>> b = Interval(4, 5) 

>>> c = Interval(1, 7) 

>>> C1 = ComplexRegion(a*b) 

>>> C1.b_interval 

[4, 5] 

>>> C2 = ComplexRegion(Union(a*b, b*c)) 

>>> C2.b_interval 

[1, 7] 

 

""" 

b_interval = [] 

for element in self.psets: 

b_interval.append(element.args[1]) 

 

b_interval = Union(*b_interval) 

return b_interval 

 

@property 

def polar(self): 

""" 

Returns True if self is in polar form. 

 

Examples 

======== 

 

>>> from sympy import Interval, ComplexRegion, Union, S 

>>> a = Interval(2, 3) 

>>> b = Interval(4, 5) 

>>> theta = Interval(0, 2*S.Pi) 

>>> C1 = ComplexRegion(a*b) 

>>> C1.polar 

False 

>>> C2 = ComplexRegion(a*theta, polar=True) 

>>> C2.polar 

True 

""" 

return self._polar 

 

@property 

def _measure(self): 

""" 

The measure of self.sets. 

 

Examples 

======== 

 

>>> from sympy import Interval, ComplexRegion, S 

>>> a, b = Interval(2, 5), Interval(4, 8) 

>>> c = Interval(0, 2*S.Pi) 

>>> c1 = ComplexRegion(a*b) 

>>> c1.measure 

12 

>>> c2 = ComplexRegion(a*c, polar=True) 

>>> c2.measure 

6*pi 

 

""" 

return self.sets._measure 

 

def _contains(self, other): 

from sympy.functions import arg, Abs 

from sympy.core.containers import Tuple 

other = sympify(other) 

isTuple = isinstance(other, Tuple) 

if isTuple and len(other) != 2: 

raise ValueError('expecting Tuple of length 2') 

# self in rectangular form 

if not self.polar: 

re, im = other if isTuple else other.as_real_imag() 

for element in self.psets: 

if And(element.args[0]._contains(re), 

element.args[1]._contains(im)): 

return True 

return False 

 

# self in polar form 

elif self.polar: 

if isTuple: 

r, theta = other 

elif other.is_zero: 

r, theta = S.Zero, S.Zero 

else: 

r, theta = Abs(other), arg(other) 

for element in self.psets: 

if And(element.args[0]._contains(r), 

element.args[1]._contains(theta)): 

return True 

return False 

 

def _intersect(self, other): 

 

if other.is_ComplexRegion: 

# self in rectangular form 

if (not self.polar) and (not other.polar): 

return ComplexRegion(Intersection(self.sets, other.sets)) 

 

# self in polar form 

elif self.polar and other.polar: 

r1, theta1 = self.a_interval, self.b_interval 

r2, theta2 = other.a_interval, other.b_interval 

new_r_interval = Intersection(r1, r2) 

new_theta_interval = Intersection(theta1, theta2) 

 

# 0 and 2*Pi means the same 

if ((2*S.Pi in theta1 and S.Zero in theta2) or 

(2*S.Pi in theta2 and S.Zero in theta1)): 

new_theta_interval = Union(new_theta_interval, 

FiniteSet(0)) 

return ComplexRegion(new_r_interval*new_theta_interval, 

polar=True) 

 

if other is S.Reals: 

return other 

 

if other.is_subset(S.Reals): 

new_interval = [] 

 

# self in rectangular form 

if not self.polar: 

for element in self.psets: 

if S.Zero in element.args[0]: 

new_interval.append(element.args[0]) 

new_interval = Union(*new_interval) 

return Intersection(new_interval, other) 

 

# self in polar form 

elif self.polar: 

for element in self.psets: 

if (0 in element.args[1]) or (S.Pi in element.args[1]): 

new_interval.append(element.args[0]) 

new_interval = Union(*new_interval) 

return Intersection(new_interval, other) 

 

def _union(self, other): 

 

if other.is_ComplexRegion: 

 

# self in rectangular form 

if (not self.polar) and (not other.polar): 

return ComplexRegion(Union(self.sets, other.sets)) 

 

# self in polar form 

elif self.polar and other.polar: 

return ComplexRegion(Union(self.sets, other.sets), polar=True) 

 

if self == S.Complexes: 

return self 

 

return None 

 

 

class Complexes(with_metaclass(Singleton, ComplexRegion)): 

 

def __new__(cls): 

return ComplexRegion.__new__(cls, S.Reals*S.Reals) 

 

def __eq__(self, other): 

return other == ComplexRegion(S.Reals*S.Reals) 

 

def __hash__(self): 

return hash(ComplexRegion(S.Reals*S.Reals)) 

 

def __str__(self): 

return "S.Complexes" 

 

def __repr__(self): 

return "S.Complexes"