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

"""Transform a string with Python-like source code into SymPy expression. """ 

 

from __future__ import print_function, division 

 

from .sympy_tokenize import \ 

generate_tokens, untokenize, TokenError, \ 

NUMBER, STRING, NAME, OP, ENDMARKER 

 

from keyword import iskeyword 

 

import ast 

import re 

import unicodedata 

 

import sympy 

from sympy.core.compatibility import exec_, StringIO 

from sympy.core.basic import Basic 

 

_re_repeated = re.compile(r"^(\d*)\.(\d*)\[(\d+)\]$") 

 

def _token_splittable(token): 

""" 

Predicate for whether a token name can be split into multiple tokens. 

 

A token is splittable if it does not contain an underscore character and 

it is not the name of a Greek letter. This is used to implicitly convert 

expressions like 'xyz' into 'x*y*z'. 

""" 

if '_' in token: 

return False 

else: 

try: 

return not unicodedata.lookup('GREEK SMALL LETTER ' + token) 

except KeyError: 

pass 

if len(token) > 1: 

return True 

return False 

 

 

def _token_callable(token, local_dict, global_dict, nextToken=None): 

""" 

Predicate for whether a token name represents a callable function. 

 

Essentially wraps ``callable``, but looks up the token name in the 

locals and globals. 

""" 

func = local_dict.get(token[1]) 

if not func: 

func = global_dict.get(token[1]) 

return callable(func) and not isinstance(func, sympy.Symbol) 

 

 

def _add_factorial_tokens(name, result): 

if result == [] or result[-1][1] == '(': 

raise TokenError() 

 

beginning = [(NAME, name), (OP, '(')] 

end = [(OP, ')')] 

 

diff = 0 

length = len(result) 

 

for index, token in enumerate(result[::-1]): 

toknum, tokval = token 

i = length - index - 1 

 

if tokval == ')': 

diff += 1 

elif tokval == '(': 

diff -= 1 

 

if diff == 0: 

if i - 1 >= 0 and result[i - 1][0] == NAME: 

return result[:i - 1] + beginning + result[i - 1:] + end 

else: 

return result[:i] + beginning + result[i:] + end 

 

return result 

 

 

class AppliedFunction(object): 

""" 

A group of tokens representing a function and its arguments. 

 

`exponent` is for handling the shorthand sin^2, ln^2, etc. 

""" 

def __init__(self, function, args, exponent=None): 

if exponent is None: 

exponent = [] 

self.function = function 

self.args = args 

self.exponent = exponent 

self.items = ['function', 'args', 'exponent'] 

 

def expand(self): 

"""Return a list of tokens representing the function""" 

result = [] 

result.append(self.function) 

result.extend(self.args) 

return result 

 

def __getitem__(self, index): 

return getattr(self, self.items[index]) 

 

def __repr__(self): 

return "AppliedFunction(%s, %s, %s)" % (self.function, self.args, 

self.exponent) 

 

 

class ParenthesisGroup(list): 

"""List of tokens representing an expression in parentheses.""" 

pass 

 

 

def _flatten(result): 

result2 = [] 

for tok in result: 

if isinstance(tok, AppliedFunction): 

result2.extend(tok.expand()) 

else: 

result2.append(tok) 

return result2 

 

 

def _group_parentheses(recursor): 

def _inner(tokens, local_dict, global_dict): 

"""Group tokens between parentheses with ParenthesisGroup. 

 

Also processes those tokens recursively. 

 

""" 

result = [] 

stacks = [] 

stacklevel = 0 

for token in tokens: 

if token[0] == OP: 

if token[1] == '(': 

stacks.append(ParenthesisGroup([])) 

stacklevel += 1 

elif token[1] == ')': 

stacks[-1].append(token) 

stack = stacks.pop() 

 

if len(stacks) > 0: 

# We don't recurse here since the upper-level stack 

# would reprocess these tokens 

stacks[-1].extend(stack) 

else: 

# Recurse here to handle nested parentheses 

# Strip off the outer parentheses to avoid an infinite loop 

inner = stack[1:-1] 

inner = recursor(inner, 

local_dict, 

global_dict) 

parenGroup = [stack[0]] + inner + [stack[-1]] 

result.append(ParenthesisGroup(parenGroup)) 

stacklevel -= 1 

continue 

if stacklevel: 

stacks[-1].append(token) 

else: 

result.append(token) 

if stacklevel: 

raise TokenError("Mismatched parentheses") 

return result 

return _inner 

 

 

def _apply_functions(tokens, local_dict, global_dict): 

"""Convert a NAME token + ParenthesisGroup into an AppliedFunction. 

 

Note that ParenthesisGroups, if not applied to any function, are 

converted back into lists of tokens. 

 

""" 

result = [] 

symbol = None 

for tok in tokens: 

if tok[0] == NAME: 

symbol = tok 

result.append(tok) 

elif isinstance(tok, ParenthesisGroup): 

if symbol and _token_callable(symbol, local_dict, global_dict): 

result[-1] = AppliedFunction(symbol, tok) 

symbol = None 

else: 

result.extend(tok) 

else: 

symbol = None 

result.append(tok) 

return result 

 

 

def _implicit_multiplication(tokens, local_dict, global_dict): 

"""Implicitly adds '*' tokens. 

 

Cases: 

 

- Two AppliedFunctions next to each other ("sin(x)cos(x)") 

 

- AppliedFunction next to an open parenthesis ("sin x (cos x + 1)") 

 

- A close parenthesis next to an AppliedFunction ("(x+2)sin x")\ 

 

- A close parenthesis next to an open parenthesis ("(x+2)(x+3)") 

 

- AppliedFunction next to an implicitly applied function ("sin(x)cos x") 

 

""" 

result = [] 

for tok, nextTok in zip(tokens, tokens[1:]): 

result.append(tok) 

if (isinstance(tok, AppliedFunction) and 

isinstance(nextTok, AppliedFunction)): 

result.append((OP, '*')) 

elif (isinstance(tok, AppliedFunction) and 

nextTok[0] == OP and nextTok[1] == '('): 

# Applied function followed by an open parenthesis 

result.append((OP, '*')) 

elif (tok[0] == OP and tok[1] == ')' and 

isinstance(nextTok, AppliedFunction)): 

# Close parenthesis followed by an applied function 

result.append((OP, '*')) 

elif (tok[0] == OP and tok[1] == ')' and 

nextTok[0] == NAME): 

# Close parenthesis followed by an implicitly applied function 

result.append((OP, '*')) 

elif (tok[0] == nextTok[0] == OP 

and tok[1] == ')' and nextTok[1] == '('): 

# Close parenthesis followed by an open parenthesis 

result.append((OP, '*')) 

elif (isinstance(tok, AppliedFunction) and nextTok[0] == NAME): 

# Applied function followed by implicitly applied function 

result.append((OP, '*')) 

elif (tok[0] == NAME and 

not _token_callable(tok, local_dict, global_dict) and 

nextTok[0] == OP and nextTok[1] == '('): 

# Constant followed by parenthesis 

result.append((OP, '*')) 

elif (tok[0] == NAME and 

not _token_callable(tok, local_dict, global_dict) and 

nextTok[0] == NAME and 

not _token_callable(nextTok, local_dict, global_dict)): 

# Constant followed by constant 

result.append((OP, '*')) 

elif (tok[0] == NAME and 

not _token_callable(tok, local_dict, global_dict) and 

(isinstance(nextTok, AppliedFunction) or nextTok[0] == NAME)): 

# Constant followed by (implicitly applied) function 

result.append((OP, '*')) 

if tokens: 

result.append(tokens[-1]) 

return result 

 

 

def _implicit_application(tokens, local_dict, global_dict): 

"""Adds parentheses as needed after functions.""" 

result = [] 

appendParen = 0 # number of closing parentheses to add 

skip = 0 # number of tokens to delay before adding a ')' (to 

# capture **, ^, etc.) 

exponentSkip = False # skipping tokens before inserting parentheses to 

# work with function exponentiation 

for tok, nextTok in zip(tokens, tokens[1:]): 

result.append(tok) 

if (tok[0] == NAME and 

nextTok[0] != OP and 

nextTok[0] != ENDMARKER): 

if _token_callable(tok, local_dict, global_dict, nextTok): 

result.append((OP, '(')) 

appendParen += 1 

# name followed by exponent - function exponentiation 

elif (tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**'): 

if _token_callable(tok, local_dict, global_dict): 

exponentSkip = True 

elif exponentSkip: 

# if the last token added was an applied function (i.e. the 

# power of the function exponent) OR a multiplication (as 

# implicit multiplication would have added an extraneous 

# multiplication) 

if (isinstance(tok, AppliedFunction) 

or (tok[0] == OP and tok[1] == '*')): 

# don't add anything if the next token is a multiplication 

# or if there's already a parenthesis (if parenthesis, still 

# stop skipping tokens) 

if not (nextTok[0] == OP and nextTok[1] == '*'): 

if not(nextTok[0] == OP and nextTok[1] == '('): 

result.append((OP, '(')) 

appendParen += 1 

exponentSkip = False 

elif appendParen: 

if nextTok[0] == OP and nextTok[1] in ('^', '**', '*'): 

skip = 1 

continue 

if skip: 

skip -= 1 

continue 

result.append((OP, ')')) 

appendParen -= 1 

 

if tokens: 

result.append(tokens[-1]) 

 

if appendParen: 

result.extend([(OP, ')')] * appendParen) 

return result 

 

 

def function_exponentiation(tokens, local_dict, global_dict): 

"""Allows functions to be exponentiated, e.g. ``cos**2(x)``. 

 

Examples 

======== 

 

>>> from sympy.parsing.sympy_parser import (parse_expr, 

... standard_transformations, function_exponentiation) 

>>> transformations = standard_transformations + (function_exponentiation,) 

>>> parse_expr('sin**4(x)', transformations=transformations) 

sin(x)**4 

""" 

result = [] 

exponent = [] 

consuming_exponent = False 

level = 0 

for tok, nextTok in zip(tokens, tokens[1:]): 

if tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**': 

if _token_callable(tok, local_dict, global_dict): 

consuming_exponent = True 

elif consuming_exponent: 

exponent.append(tok) 

 

# only want to stop after hitting ) 

if tok[0] == nextTok[0] == OP and tok[1] == ')' and nextTok[1] == '(': 

consuming_exponent = False 

# if implicit multiplication was used, we may have )*( instead 

if tok[0] == nextTok[0] == OP and tok[1] == '*' and nextTok[1] == '(': 

consuming_exponent = False 

del exponent[-1] 

continue 

elif exponent and not consuming_exponent: 

if tok[0] == OP: 

if tok[1] == '(': 

level += 1 

elif tok[1] == ')': 

level -= 1 

if level == 0: 

result.append(tok) 

result.extend(exponent) 

exponent = [] 

continue 

result.append(tok) 

if tokens: 

result.append(tokens[-1]) 

if exponent: 

result.extend(exponent) 

return result 

 

 

def split_symbols_custom(predicate): 

"""Creates a transformation that splits symbol names. 

 

``predicate`` should return True if the symbol name is to be split. 

 

For instance, to retain the default behavior but avoid splitting certain 

symbol names, a predicate like this would work: 

 

 

>>> from sympy.parsing.sympy_parser import (parse_expr, _token_splittable, 

... standard_transformations, implicit_multiplication, 

... split_symbols_custom) 

>>> def can_split(symbol): 

... if symbol not in ('list', 'of', 'unsplittable', 'names'): 

... return _token_splittable(symbol) 

... return False 

... 

>>> transformation = split_symbols_custom(can_split) 

>>> parse_expr('unsplittable', transformations=standard_transformations + 

... (transformation, implicit_multiplication)) 

unsplittable 

""" 

def _split_symbols(tokens, local_dict, global_dict): 

result = [] 

split = False 

split_previous=False 

for tok in tokens: 

if split_previous: 

# throw out closing parenthesis of Symbol that was split 

split_previous=False 

continue 

split_previous=False 

if tok[0] == NAME and tok[1] == 'Symbol': 

split = True 

elif split and tok[0] == NAME: 

symbol = tok[1][1:-1] 

if predicate(symbol): 

for char in symbol: 

if char in local_dict or char in global_dict: 

# Get rid of the call to Symbol 

del result[-2:] 

result.extend([(NAME, "%s" % char), 

(NAME, 'Symbol'), (OP, '(')]) 

else: 

result.extend([(NAME, "'%s'" % char), (OP, ')'), 

(NAME, 'Symbol'), (OP, '(')]) 

# Delete the last two tokens: get rid of the extraneous 

# Symbol( we just added 

# Also, set split_previous=True so will skip 

# the closing parenthesis of the original Symbol 

del result[-2:] 

split = False 

split_previous = True 

continue 

else: 

split = False 

result.append(tok) 

return result 

return _split_symbols 

 

 

#: Splits symbol names for implicit multiplication. 

#: 

#: Intended to let expressions like ``xyz`` be parsed as ``x*y*z``. Does not 

#: split Greek character names, so ``theta`` will *not* become 

#: ``t*h*e*t*a``. Generally this should be used with 

#: ``implicit_multiplication``. 

split_symbols = split_symbols_custom(_token_splittable) 

 

 

def implicit_multiplication(result, local_dict, global_dict): 

"""Makes the multiplication operator optional in most cases. 

 

Use this before :func:`implicit_application`, otherwise expressions like 

``sin 2x`` will be parsed as ``x * sin(2)`` rather than ``sin(2*x)``. 

 

Examples 

======== 

 

>>> from sympy.parsing.sympy_parser import (parse_expr, 

... standard_transformations, implicit_multiplication) 

>>> transformations = standard_transformations + (implicit_multiplication,) 

>>> parse_expr('3 x y', transformations=transformations) 

3*x*y 

""" 

# These are interdependent steps, so we don't expose them separately 

for step in (_group_parentheses(implicit_multiplication), 

_apply_functions, 

_implicit_multiplication): 

result = step(result, local_dict, global_dict) 

 

result = _flatten(result) 

return result 

 

 

def implicit_application(result, local_dict, global_dict): 

"""Makes parentheses optional in some cases for function calls. 

 

Use this after :func:`implicit_multiplication`, otherwise expressions 

like ``sin 2x`` will be parsed as ``x * sin(2)`` rather than 

``sin(2*x)``. 

 

Examples 

======== 

 

>>> from sympy.parsing.sympy_parser import (parse_expr, 

... standard_transformations, implicit_application) 

>>> transformations = standard_transformations + (implicit_application,) 

>>> parse_expr('cot z + csc z', transformations=transformations) 

cot(z) + csc(z) 

""" 

for step in (_group_parentheses(implicit_application), 

_apply_functions, 

_implicit_application,): 

result = step(result, local_dict, global_dict) 

 

result = _flatten(result) 

return result 

 

 

def implicit_multiplication_application(result, local_dict, global_dict): 

"""Allows a slightly relaxed syntax. 

 

- Parentheses for single-argument method calls are optional. 

 

- Multiplication is implicit. 

 

- Symbol names can be split (i.e. spaces are not needed between 

symbols). 

 

- Functions can be exponentiated. 

 

Examples 

======== 

 

>>> from sympy.parsing.sympy_parser import (parse_expr, 

... standard_transformations, implicit_multiplication_application) 

>>> parse_expr("10sin**2 x**2 + 3xyz + tan theta", 

... transformations=(standard_transformations + 

... (implicit_multiplication_application,))) 

3*x*y*z + 10*sin(x**2)**2 + tan(theta) 

 

""" 

for step in (split_symbols, implicit_multiplication, 

implicit_application, function_exponentiation): 

result = step(result, local_dict, global_dict) 

 

return result 

 

 

def auto_symbol(tokens, local_dict, global_dict): 

"""Inserts calls to ``Symbol`` for undefined variables.""" 

result = [] 

prevTok = (None, None) 

 

tokens.append((None, None)) # so zip traverses all tokens 

for tok, nextTok in zip(tokens, tokens[1:]): 

tokNum, tokVal = tok 

nextTokNum, nextTokVal = nextTok 

if tokNum == NAME: 

name = tokVal 

 

if (name in ['True', 'False', 'None'] 

or iskeyword(name) 

or name in local_dict 

# Don't convert attribute access 

or (prevTok[0] == OP and prevTok[1] == '.') 

# Don't convert keyword arguments 

or (prevTok[0] == OP and prevTok[1] in ('(', ',') 

and nextTokNum == OP and nextTokVal == '=')): 

result.append((NAME, name)) 

continue 

elif name in global_dict: 

obj = global_dict[name] 

if isinstance(obj, (Basic, type)) or callable(obj): 

result.append((NAME, name)) 

continue 

 

result.extend([ 

(NAME, 'Symbol'), 

(OP, '('), 

(NAME, repr(str(name))), 

(OP, ')'), 

]) 

else: 

result.append((tokNum, tokVal)) 

 

prevTok = (tokNum, tokVal) 

 

return result 

 

 

def lambda_notation(tokens, local_dict, global_dict): 

"""Substitutes "lambda" with its Sympy equivalent Lambda(). 

However, the conversion doesn't take place if only "lambda" 

is passed because that is a syntax error. 

 

""" 

result = [] 

flag = False 

toknum, tokval = tokens[0] 

tokLen = len(tokens) 

if toknum == NAME and tokval == 'lambda': 

if tokLen == 2: 

result.extend(tokens) 

elif tokLen > 2: 

result.extend([ 

(NAME, 'Lambda'), 

(OP, '('), 

(OP, '('), 

(OP, ')'), 

(OP, ')'), 

]) 

for tokNum, tokVal in tokens[1:]: 

if tokNum == OP and tokVal == ':': 

tokVal = ',' 

flag = True 

if not flag and tokNum == OP and tokVal in ['*', '**']: 

raise TokenError("Starred arguments in lambda not supported") 

if flag: 

result.insert(-1, (tokNum, tokVal)) 

else: 

result.insert(-2, (tokNum, tokVal)) 

else: 

result.extend(tokens) 

 

return result 

 

 

def factorial_notation(tokens, local_dict, global_dict): 

"""Allows standard notation for factorial.""" 

result = [] 

prevtoken = '' 

for toknum, tokval in tokens: 

if toknum == OP: 

op = tokval 

 

if op == '!!': 

if prevtoken == '!' or prevtoken == '!!': 

raise TokenError 

result = _add_factorial_tokens('factorial2', result) 

elif op == '!': 

if prevtoken == '!' or prevtoken == '!!': 

raise TokenError 

result = _add_factorial_tokens('factorial', result) 

else: 

result.append((OP, op)) 

else: 

result.append((toknum, tokval)) 

 

prevtoken = tokval 

 

return result 

 

 

def convert_xor(tokens, local_dict, global_dict): 

"""Treats XOR, ``^``, as exponentiation, ``**``.""" 

result = [] 

for toknum, tokval in tokens: 

if toknum == OP: 

if tokval == '^': 

result.append((OP, '**')) 

else: 

result.append((toknum, tokval)) 

else: 

result.append((toknum, tokval)) 

 

return result 

 

 

def auto_number(tokens, local_dict, global_dict): 

"""Converts numeric literals to use SymPy equivalents. 

 

Complex numbers use ``I``; integer literals use ``Integer``, float 

literals use ``Float``, and repeating decimals use ``Rational``. 

 

""" 

result = [] 

prevtoken = '' 

 

for toknum, tokval in tokens: 

if toknum == NUMBER: 

number = tokval 

postfix = [] 

 

if number.endswith('j') or number.endswith('J'): 

number = number[:-1] 

postfix = [(OP, '*'), (NAME, 'I')] 

 

if '.' in number or (('e' in number or 'E' in number) and 

not (number.startswith('0x') or number.startswith('0X'))): 

match = _re_repeated.match(number) 

 

if match is not None: 

# Clear repeating decimals, e.g. 3.4[31] -> (3 + 4/10 + 31/990) 

pre, post, repetend = match.groups() 

 

zeros = '0'*len(post) 

post, repetends = [w.lstrip('0') for w in [post, repetend]] 

# or else interpreted as octal 

 

a = pre or '0' 

b, c = post or '0', '1' + zeros 

d, e = repetends, ('9'*len(repetend)) + zeros 

 

seq = [ 

(OP, '('), 

(NAME, 

'Integer'), (OP, '('), (NUMBER, a), (OP, ')'), 

(OP, '+'), 

(NAME, 'Rational'), (OP, '('), ( 

NUMBER, b), (OP, ','), (NUMBER, c), (OP, ')'), 

(OP, '+'), 

(NAME, 'Rational'), (OP, '('), ( 

NUMBER, d), (OP, ','), (NUMBER, e), (OP, ')'), 

(OP, ')'), 

] 

else: 

seq = [(NAME, 'Float'), (OP, '('), 

(NUMBER, repr(str(number))), (OP, ')')] 

else: 

seq = [(NAME, 'Integer'), (OP, '('), ( 

NUMBER, number), (OP, ')')] 

 

result.extend(seq + postfix) 

else: 

result.append((toknum, tokval)) 

 

return result 

 

 

def rationalize(tokens, local_dict, global_dict): 

"""Converts floats into ``Rational``. Run AFTER ``auto_number``.""" 

result = [] 

passed_float = False 

for toknum, tokval in tokens: 

if toknum == NAME: 

if tokval == 'Float': 

passed_float = True 

tokval = 'Rational' 

result.append((toknum, tokval)) 

elif passed_float == True and toknum == NUMBER: 

passed_float = False 

result.append((STRING, tokval)) 

else: 

result.append((toknum, tokval)) 

 

return result 

 

 

def _transform_equals_sign(tokens, local_dict, global_dict): 

"""Transforms the equals sign ``=`` to instances of Eq. 

 

This is a helper function for `convert_equals_signs`. 

Works with expressions containing one equals sign and no 

nesting. Expressions like `(1=2)=False` won't work with this 

and should be used with `convert_equals_signs`. 

 

Examples: 1=2 to Eq(1,2) 

1*2=x to Eq(1*2, x) 

 

This does not deal with function arguments yet. 

 

""" 

result = [] 

if (OP, "=") in tokens: 

result.append((NAME, "Eq")) 

result.append((OP, "(")) 

for index, token in enumerate(tokens): 

if token == (OP, "="): 

result.append((OP, ",")) 

continue 

result.append(token) 

result.append((OP, ")")) 

else: 

result = tokens 

return result 

 

 

def convert_equals_signs(result, local_dict, global_dict): 

""" Transforms all the equals signs ``=`` to instances of Eq. 

 

Parses the equals signs in the expression and replaces them with 

appropriate Eq instances.Also works with nested equals signs. 

 

Does not yet play well with function arguments. 

For example, the expression `(x=y)` is ambiguous and can be interpreted 

as x being an argument to a function and `convert_equals_signs` won't 

work for this. 

 

See also 

======== 

convert_equality_operators 

 

Examples: 

========= 

 

>>> from sympy.parsing.sympy_parser import (parse_expr, 

... standard_transformations, convert_equals_signs) 

>>> parse_expr("1*2=x", transformations=( 

... standard_transformations + (convert_equals_signs,))) 

Eq(2, x) 

>>> parse_expr("(1*2=x)=False", transformations=( 

... standard_transformations + (convert_equals_signs,))) 

Eq(Eq(2, x), False) 

 

""" 

for step in (_group_parentheses(convert_equals_signs), 

_apply_functions, 

_transform_equals_sign): 

result = step(result, local_dict, global_dict) 

 

result = _flatten(result) 

return result 

 

 

#: Standard transformations for :func:`parse_expr`. 

#: Inserts calls to :class:`Symbol`, :class:`Integer`, and other SymPy 

#: datatypes and allows the use of standard factorial notation (e.g. ``x!``). 

standard_transformations = (lambda_notation, auto_symbol, auto_number, factorial_notation) 

 

 

def stringify_expr(s, local_dict, global_dict, transformations): 

""" 

Converts the string ``s`` to Python code, in ``local_dict`` 

 

Generally, ``parse_expr`` should be used. 

""" 

 

tokens = [] 

input_code = StringIO(s.strip()) 

for toknum, tokval, _, _, _ in generate_tokens(input_code.readline): 

tokens.append((toknum, tokval)) 

 

for transform in transformations: 

tokens = transform(tokens, local_dict, global_dict) 

 

return untokenize(tokens) 

 

 

def eval_expr(code, local_dict, global_dict): 

""" 

Evaluate Python code generated by ``stringify_expr``. 

 

Generally, ``parse_expr`` should be used. 

""" 

expr = eval( 

code, global_dict, local_dict) # take local objects in preference 

 

return expr 

 

 

def parse_expr(s, local_dict=None, transformations=standard_transformations, 

global_dict=None, evaluate=True): 

"""Converts the string ``s`` to a SymPy expression, in ``local_dict`` 

 

Parameters 

========== 

 

s : str 

The string to parse. 

 

local_dict : dict, optional 

A dictionary of local variables to use when parsing. 

 

global_dict : dict, optional 

A dictionary of global variables. By default, this is initialized 

with ``from sympy import *``; provide this parameter to override 

this behavior (for instance, to parse ``"Q & S"``). 

 

transformations : tuple, optional 

A tuple of transformation functions used to modify the tokens of the 

parsed expression before evaluation. The default transformations 

convert numeric literals into their SymPy equivalents, convert 

undefined variables into SymPy symbols, and allow the use of standard 

mathematical factorial notation (e.g. ``x!``). 

 

evaluate : bool, optional 

When False, the order of the arguments will remain as they were in the 

string and automatic simplification that would normally occur is 

suppressed. (see examples) 

 

Examples 

======== 

 

>>> from sympy.parsing.sympy_parser import parse_expr 

>>> parse_expr("1/2") 

1/2 

>>> type(_) 

<class 'sympy.core.numbers.Half'> 

>>> from sympy.parsing.sympy_parser import standard_transformations,\\ 

... implicit_multiplication_application 

>>> transformations = (standard_transformations + 

... (implicit_multiplication_application,)) 

>>> parse_expr("2x", transformations=transformations) 

2*x 

 

When evaluate=False, some automatic simplifications will not occur: 

 

>>> parse_expr("2**3"), parse_expr("2**3", evaluate=False) 

(8, 2**3) 

 

In addition the order of the arguments will not be made canonical. 

This feature allows one to tell exactly how the expression was entered: 

 

>>> a = parse_expr('1 + x', evaluate=False) 

>>> b = parse_expr('x + 1', evaluate=0) 

>>> a == b 

False 

>>> a.args 

(1, x) 

>>> b.args 

(x, 1) 

 

See Also 

======== 

 

stringify_expr, eval_expr, standard_transformations, 

implicit_multiplication_application 

 

""" 

 

if local_dict is None: 

local_dict = {} 

 

if global_dict is None: 

global_dict = {} 

exec_('from sympy import *', global_dict) 

 

code = stringify_expr(s, local_dict, global_dict, transformations) 

 

if not evaluate: 

code = compile(evaluateFalse(code), '<string>', 'eval') 

 

return eval_expr(code, local_dict, global_dict) 

 

 

def evaluateFalse(s): 

""" 

Replaces operators with the SymPy equivalent and sets evaluate=False. 

""" 

node = ast.parse(s) 

node = EvaluateFalseTransformer().visit(node) 

# node is a Module, we want an Expression 

node = ast.Expression(node.body[0].value) 

 

return ast.fix_missing_locations(node) 

 

 

class EvaluateFalseTransformer(ast.NodeTransformer): 

operators = { 

ast.Add: 'Add', 

ast.Mult: 'Mul', 

ast.Pow: 'Pow', 

ast.Sub: 'Add', 

ast.Div: 'Mul', 

ast.BitOr: 'Or', 

ast.BitAnd: 'And', 

ast.BitXor: 'Not', 

} 

 

def flatten(self, args, func): 

result = [] 

for arg in args: 

if isinstance(arg, ast.Call) and arg.func.id == func: 

result.extend(self.flatten(arg.args, func)) 

else: 

result.append(arg) 

return result 

 

def visit_BinOp(self, node): 

if node.op.__class__ in self.operators: 

sympy_class = self.operators[node.op.__class__] 

right = self.visit(node.right) 

left = self.visit(node.left) 

if isinstance(node.left, ast.UnaryOp) and (isinstance(node.right, ast.UnaryOp) == 0) and sympy_class in ('Mul',): 

left, right = right, left 

if isinstance(node.op, ast.Sub): 

right = ast.UnaryOp(op=ast.USub(), operand=right) 

if isinstance(node.op, ast.Div): 

if isinstance(node.left, ast.UnaryOp): 

if isinstance(node.right,ast.UnaryOp): 

left, right = right, left 

left = ast.Call( 

func=ast.Name(id='Pow', ctx=ast.Load()), 

args=[left, ast.UnaryOp(op=ast.USub(), operand=ast.Num(1))], 

keywords=[ast.keyword(arg='evaluate', value=ast.Name(id='False', ctx=ast.Load()))], 

starargs=None, 

kwargs=None 

) 

else: 

right = ast.Call( 

func=ast.Name(id='Pow', ctx=ast.Load()), 

args=[right, ast.UnaryOp(op=ast.USub(), operand=ast.Num(1))], 

keywords=[ast.keyword(arg='evaluate', value=ast.Name(id='False', ctx=ast.Load()))], 

starargs=None, 

kwargs=None 

) 

 

new_node = ast.Call( 

func=ast.Name(id=sympy_class, ctx=ast.Load()), 

args=[left, right], 

keywords=[ast.keyword(arg='evaluate', value=ast.Name(id='False', ctx=ast.Load()))], 

starargs=None, 

kwargs=None 

) 

 

if sympy_class in ('Add', 'Mul'): 

# Denest Add or Mul as appropriate 

new_node.args = self.flatten(new_node.args, sympy_class) 

 

return new_node 

return node