Mupad User Manual
Mupad User Manual
Mupad User Manual
R2014a
Product enhancement suggestions Bug reports Documentation error reports Order status, license renewals, passcodes Sales, pricing, and general information
508-647-7000 (Phone) 508-647-7001 (Fax) The MathWorks, Inc. 3 Apple Hill Drive Natick, MA 01760-2098
For contact information about worldwide offices, see the MathWorks Web site. MuPAD Users Guide COPYRIGHT 19932014 by SciFace Software GmbH & Co. KG.
The software described in this document is furnished under a license agreement. The software may be used or copied only under the terms of the license agreement. No part of this manual may be photocopied or reproduced in any form without prior written consent from The MathWorks, Inc. FEDERAL ACQUISITION: This provision applies to all acquisitions of the Program and Documentation by, for, or through the federal government of the United States. By accepting delivery of the Program or Documentation, the government hereby agrees that this software or documentation qualifies as commercial computer software or commercial computer software documentation as such terms are used or defined in FAR 12.212, DFARS Part 227.72, and DFARS 252.227-7014. Accordingly, the terms and conditions of this Agreement and only those rights specified in this Agreement, shall pertain to and govern the use, modification, reproduction, release, performance, display, and disclosure of the Program and Documentation by the federal government (or other entity acquiring for or through the federal government) and shall supersede any conflicting contractual terms or conditions. If this License fails to meet the governments needs or is inconsistent in any respect with federal procurement law, the government agrees to return the Program and Documentation, unused, to The MathWorks, Inc.
Trademarks
MuPAD is a registered trademark of SciFace Software GmbH & Co. KG. MATLAB and Simulink are registered trademarks of The MathWorks, Inc. See www.mathworks.com/trademarks for a list of additional trademarks. Other product or brand names may be trademarks or registered trademarks of their respective holders.
Patents
MathWorks products are protected by one or more U.S. patents. Please see www.mathworks.com/patents for more information.
Revision History
New for Version 5.9 (Release 2012b) Revised for Version 5.10 (Release 2013a) Revised for Version 5.11 (Release 2013b) Revised for Version 6.0 (Release 2014a)
Contents
Getting Started
1
Desktop Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Evaluate Mathematical Expressions and Commands . . Working in a Single Input Region . . . . . . . . . . . . . . . . . . . . Working with Multiple Input Regions . . . . . . . . . . . . . . . . . Quickly Access Standard MuPAD Functions . . . . . . . . . Access Help for Particular Command . . . . . . . . . . . . . . . . Autocomplete Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Tooltips and the Context Menu . . . . . . . . . . . . . . . . . . . Use Help Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Perform Computations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Compute with Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . Differentiation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Linear Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Solve Equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Manipulate Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Assumptions in Your Computations . . . . . . . . . . . . . . . Use Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Graphic Options Available in MuPAD . . . . . . . . . . . . . . . . . Basic Plotting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Format Plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Present Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Create Animated Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . Format and Export Documents and Graphics . . . . . . . . Format Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Format Mathematical Expressions . . . . . . . . . . . . . . . . . . . Format Expressions in Input Regions . . . . . . . . . . . . . . . . . 1-2 1-4 1-4 1-5 1-7 1-15 1-15 1-16 1-18 1-20 1-20 1-25 1-28 1-29 1-33 1-36 1-39 1-42 1-42 1-43 1-53 1-60 1-63 1-66 1-66 1-72 1-74
iii
Change Default Format Settings . . . . . . . . . . . . . . . . . . . . . 1-77 Use Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-80 Use Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-85 Embed Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-92 Work with Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-95 Export Notebooks to HTML, PDF, and Plain Text Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-105 Save and Export Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . 1-106 Use Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mathematical Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vectors and Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use the MuPAD Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . Overview of Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Standard Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Find Information About a Library . . . . . . . . . . . . . . . . . . . . Avoid Name Conflicts Between MuPAD Objects and Library Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Programming Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conditional Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Shortcut for Closing Statements . . . . . . . . . . . . . . . . . . . . . Debug MuPAD Code Using the Debugger . . . . . . . . . . . . Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Open the Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Debug Step-by-Step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Set and Remove Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . Evaluate Variables and Expressions After a Particular Function Call . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Watch Intermediate Values of Variables and Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . View Names of Currently Running Procedures . . . . . . . . . 1-116 1-116 1-117 1-120 1-128 1-134 1-138 1-144 1-148 1-148 1-150 1-150 1-152 1-155 1-155 1-161 1-171 1-179 1-181 1-184 1-184 1-184 1-186 1-190 1-197 1-199 1-200
iv
Contents
Notebook Interface
2
Notebook Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Debugger Window Overview . . . . . . . . . . . . . . . . . . . . . . . . Arrange Toolbars and Panes . . . . . . . . . . . . . . . . . . . . . . . . Enabling and Disabling Toolbars and Panes . . . . . . . . . . . . Move Toolbars and Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . Enter Data and View Results . . . . . . . . . . . . . . . . . . . . . . . View Status Information . . . . . . . . . . . . . . . . . . . . . . . . . . . Save Custom Arrangements . . . . . . . . . . . . . . . . . . . . . . . . Set Preferences for Notebooks . . . . . . . . . . . . . . . . . . . . . . Preferences Available for Notebooks . . . . . . . . . . . . . . . . . . Change Default Formatting . . . . . . . . . . . . . . . . . . . . . . . . . Scalable Format for Copying Graphics . . . . . . . . . . . . . . . . Set Preferences for Dialogs, Toolbars, and Graphics . . Preferences Available for Dialogs, Toolbars, and Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Preferences for Toolbars . . . . . . . . . . . . . . . . . . . . . . . . . . . . Preferences for Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . Preferences for Dialog Boxes . . . . . . . . . . . . . . . . . . . . . . . . Set Font Preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Select Generic Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Default Generic Fonts for Microsoft Windows, Macintosh, and Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-3 2-5 2-8 2-8 2-9 2-11 2-13 2-14 2-15 2-15 2-17 2-18 2-20 2-20 2-22 2-22 2-22 2-24 2-24 2-26
Set Engine Preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . Change Global Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . Restore Default Global Settings . . . . . . . . . . . . . . . . . . . . . . Add Hidden Startup Commands to All Notebooks . . . . . . . Options Available for MuPAD Engine Startup . . . . . . . . . . Get Version Information . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Different Output Modes . . . . . . . . . . . . . . . . . . . . . . . . Abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Typeset Math Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pretty Print Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mathematical Notations Used in Typeset Mode . . . . . . . . . Set Line Length in Plain Text Outputs . . . . . . . . . . . . . . . Delete Outputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Greek Letters in Text Regions . . . . . . . . . . . . . . . . . . . . . . Special Characters in Outputs . . . . . . . . . . . . . . . . . . . . . . Non-Greek Characters in Text Regions . . . . . . . . . . . . . . Use Keyboard Shortcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Mnemonics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wrap Long Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wrap Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wrap Expressions in Input Regions . . . . . . . . . . . . . . . . . . . Wrap Output Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . Hide Code Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Change Font Size Quickly . . . . . . . . . . . . . . . . . . . . . . . . . .
2-27 2-27 2-29 2-29 2-29 2-32 2-33 2-33 2-34 2-36 2-38 2-40 2-41 2-42 2-43 2-44 2-45 2-46 2-47 2-48 2-48 2-51 2-53 2-57 2-60
vi
Contents
Scale Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Print Preview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . View Documents Before Printing . . . . . . . . . . . . . . . . . . . . . Print Documents from Print Preview . . . . . . . . . . . . . . . . . Save Documents to PDF Format . . . . . . . . . . . . . . . . . . . . . Get More Out of Print Preview . . . . . . . . . . . . . . . . . . . . . . . Change Page Settings for Printing . . . . . . . . . . . . . . . . . . Print Wide Notebooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Mathematics
3
Evaluations in Symbolic Computations . . . . . . . . . . . . . . Level of Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . What Is an Evaluation Level? . . . . . . . . . . . . . . . . . . . . . . . Incomplete Evaluations . . . . . . . . . . . . . . . . . . . . . . . . . . . . Control Evaluation Levels . . . . . . . . . . . . . . . . . . . . . . . . . . Enforce Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Prevent Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Actual and Displayed Results of Evaluations . . . . . . . . . Evaluate at a Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Choose a Solver 3-5 3-8 3-8 3-9 3-12 3-17 3-20 3-22 3-24 3-26 3-29 3-29 3-29 3-31
...................................
Solve Algebraic Equations and Inequalities . . . . . . . . . . Specify Right Side of Equation . . . . . . . . . . . . . . . . . . . . . . . Specify Equation Variables . . . . . . . . . . . . . . . . . . . . . . . . . Solve Higher-Order Polynomial Equations . . . . . . . . . . . . .
vii
Find Multiple Roots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Isolate Real Roots of Polynomial Equations . . . . . . . . . . . . Solve Algebraic Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . Linear Systems of Equations . . . . . . . . . . . . . . . . . . . . . . . . Linear Systems in a Matrix Form . . . . . . . . . . . . . . . . . . . . Nonlinear Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Solve Ordinary Differential Equations and Systems . . General Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Initial and Boundary Value Problems . . . . . . . . . . . . . . . . . Special Types of Ordinary Differential Equations . . . . . . . Systems of Ordinary Differential Equations . . . . . . . . . . . . Plot Solutions of Differential Equations . . . . . . . . . . . . . . . Test Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Solutions Given in the Form of Equations . . . . . . . . . . . . . . Solutions Given as Memberships . . . . . . . . . . . . . . . . . . . . . Solutions Obtained with IgnoreAnalyticConstraints . . If Results Look Too Complicated . . . . . . . . . . . . . . . . . . . . Use Options to Narrow Results . . . . . . . . . . . . . . . . . . . . . . Use Assumptions to Narrow Results . . . . . . . . . . . . . . . . . . Simplify Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . If Results Differ from Expected . . . . . . . . . . . . . . . . . . . . . Verify Equivalence of Expected and Obtained Solutions . . Verify Equivalence of Solutions Containing Arbitrary Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Completeness of Expected and Obtained Solutions . . . . . . Solve Equations Numerically . . . . . . . . . . . . . . . . . . . . . . . Get Numeric Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Solve Polynomial Equations and Systems . . . . . . . . . . . . . . Solve Arbitrary Algebraic Equations and Systems . . . . . . . Isolate Numeric Roots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Solve Differential Equations and Systems . . . . . . . . . . . . . Use General Simplification Functions . . . . . . . . . . . . . . . When to Use General Simplifiers . . . . . . . . . . . . . . . . . . . . . Choose simplify or Simplify . . . . . . . . . . . . . . . . . . . . . . . . .
3-33 3-33 3-35 3-35 3-36 3-42 3-46 3-46 3-48 3-49 3-51 3-53 3-58 3-58 3-60 3-62 3-64 3-64 3-66 3-67 3-69 3-69 3-70 3-73 3-76 3-76 3-78 3-79 3-85 3-85 3-92 3-92 3-93
viii
Contents
Use Options to Control Simplification Algorithms . . . . . . . Choose Simplification Functions . . . . . . . . . . . . . . . . . . . . Collect Terms with Same Powers . . . . . . . . . . . . . . . . . . . . . Combine Terms of Same Algebraic Structures . . . . . . . . . . Expand Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Factor Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Compute Normal Forms of Expressions . . . . . . . . . . . . . . . Compute Partial Fraction Decompositions of Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Simplify Radicals in Arithmetic Expressions . . . . . . . . . . . Extract Real and Imaginary Parts of Complex Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rewrite Expressions in Terms of Other Functions . . . . . . . If You Want to Simplify Results Further . . . . . . . . . . . . . Increase the Number of Simplification Steps . . . . . . . . . . . Apply Several Simplification Functions . . . . . . . . . . . . . . . Use Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Convert Expressions Involving Special Functions . . . . Simplify Special Functions Automatically . . . . . . . . . . . . . . Use General Simplifiers to Reduce Special Functions . . . . Expand Expressions Involving Special Functions . . . . . . . Verify Solutions Involving Special Functions . . . . . . . . . . .
3-93 3-96 3-97 3-98 3-99 3-100 3-101 3-102 3-103 3-103 3-104 3-106 3-106 3-107 3-108 3-109 3-111 3-111 3-111 3-113 3-113
When to Use Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . 3-117 Use Permanent Assumptions . . . . . . . . . . . . . . . . . . . . . . . Set Permanent Assumptions . . . . . . . . . . . . . . . . . . . . . . . . Add Permanent Assumptions . . . . . . . . . . . . . . . . . . . . . . . . Clear Permanent Assumptions . . . . . . . . . . . . . . . . . . . . . . Use Temporary Assumptions . . . . . . . . . . . . . . . . . . . . . . . Create Temporary Assumptions . . . . . . . . . . . . . . . . . . . . . . Assign Temporary Values to Parameters . . . . . . . . . . . . . . Interactions Between Temporary and Permanent Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Temporary Assumptions on Top of Permanent Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-119 3-119 3-122 3-123 3-126 3-126 3-128 3-129 3-130
ix
Choose Differentiation Function . . . . . . . . . . . . . . . . . . . . 3-132 Differentiate Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . 3-133 Differentiate Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-135 Compute Indefinite Integrals . . . . . . . . . . . . . . . . . . . . . . . 3-140 Compute Definite Integrals . . . . . . . . . . . . . . . . . . . . . . . . . 3-143 Compute Multiple Integrals . . . . . . . . . . . . . . . . . . . . . . . . 3-146 Apply Standard Integration Methods Directly . . . . . . . . 3-148 Integration by Parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-148 Change of Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-149 Get Simpler Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-151 If an Integral Is Undefined . . . . . . . . . . . . . . . . . . . . . . . . . 3-152 If MuPAD Cannot Compute an Integral . . . . . . . . . . . . . . 3-153 Approximate Indefinite Integrals . . . . . . . . . . . . . . . . . . . . . 3-153 Approximate Definite Integrals . . . . . . . . . . . . . . . . . . . . . . 3-154 Compute Symbolic Sums . . . . . . . . . . . . . . . . . . . . . . . . . . . Indefinite Sums . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Definite Sums . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sums Over Roots of a Polynomial . . . . . . . . . . . . . . . . . . . . Approximate Sums Numerically 3-156 3-156 3-157 3-158
. . . . . . . . . . . . . . . . . . . . 3-159
Compute Taylor Series for Univariate Expressions . . . 3-161 Compute Taylor Series for Multivariate Expressions . . 3-165 Control Number of Terms in Series Expansions . . . . . . 3-166
Contents
O-term (The Landau Symbol) . . . . . . . . . . . . . . . . . . . . . . . 3-169 Compute Generalized Series . . . . . . . . . . . . . . . . . . . . . . . . 3-170 Compute Bidirectional Limits . . . . . . . . . . . . . . . . . . . . . . 3-172 Compute Right and Left Limits . . . . . . . . . . . . . . . . . . . . . 3-173 If Limits Do Not Exist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-176 Create Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-178 Create Vectors
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-181
Create Special Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-182 Access and Modify Matrix Elements . . . . . . . . . . . . . . . . . 3-184 Use Loops to Modify Matrix Elements . . . . . . . . . . . . . . . . . 3-184 Use Functions to Modify Matrix Elements . . . . . . . . . . . . . 3-185 Create Matrices over Particular Rings . . . . . . . . . . . . . . . 3-186 Use Sparse and Dense Matrices . . . . . . . . . . . . . . . . . . . . . 3-188 Compute with Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-190 Basic Arithmetic Operations . . . . . . . . . . . . . . . . . . . . . . . . 3-190 More Operations Available for Matrices . . . . . . . . . . . . . . . 3-191 Compute Determinants and Traces of Square Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-195 Invert Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-196 Transpose Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-197 Swap and Delete Rows and Columns . . . . . . . . . . . . . . . . 3-198
xi
Compute Dimensions of a Matrix . . . . . . . . . . . . . . . . . . . . 3-200 Compute Reduced Row Echelon Form . . . . . . . . . . . . . . . 3-201 Compute Rank of a Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . 3-202 Compute Bases for Null Spaces of Matrices . . . . . . . . . . 3-203 Find Eigenvalues and Eigenvectors . . . . . . . . . . . . . . . . . 3-204 Find Jordan Canonical Form of a Matrix . . . . . . . . . . . . 3-207 Compute Matrix Exponentials . . . . . . . . . . . . . . . . . . . . . . 3-210 Compute Cholesky Factorization
. . . . . . . . . . . . . . . . . . . 3-211
Compute LU Factorization . . . . . . . . . . . . . . . . . . . . . . . . . 3-214 Compute QR Factorization . . . . . . . . . . . . . . . . . . . . . . . . . 3-216 Compute Determinant Numerically . . . . . . . . . . . . . . . . . 3-218 Compute Eigenvalues and Eigenvectors Numerically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-222 Compute Factorizations Numerically . . . . . . . . . . . . . . . . Cholesky Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . LU Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . QR Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Singular Value Decomposition . . . . . . . . . . . . . . . . . . . . . . . Mathematical Constants Available in MuPAD . . . . . . . . Special Real Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Infinities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Boolean Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Special Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Special Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-227 3-227 3-228 3-231 3-233 3-236 3-236 3-237 3-237 3-237 3-238
xii
Contents
Special Functions Available in MuPAD . . . . . . . . . . . . . . Dirac and Heaviside Functions . . . . . . . . . . . . . . . . . . . . . . Gamma Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zeta Function and Polylogarithms . . . . . . . . . . . . . . . . . . . . Airy and Bessel Functions . . . . . . . . . . . . . . . . . . . . . . . . . . Exponential and Trigonometric Integrals . . . . . . . . . . . . . . Error Functions and Fresnel Functions . . . . . . . . . . . . . . . . Hypergeometric, Meijer G, and Whittaker Functions . . . . Elliptic Integrals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lambert W Function (omega Function) . . . . . . . . . . . . . . . . Floating-Point Arguments and Function Sensitivity . . Use Symbolic Computations When Possible . . . . . . . . . . . . Increase Precision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Approximate Parameters and Approximate Results . . . . . Plot Special Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3-239 3-239 3-239 3-240 3-240 3-241 3-241 3-241 3-242 3-242 3-243 3-244 3-244 3-246 3-247
Integral Transforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-251 Fourier and Inverse Fourier Transforms . . . . . . . . . . . . . . . 3-251 Laplace and Inverse Laplace Transforms . . . . . . . . . . . . . . 3-254 Z-Transforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-259 Discrete Fourier Transforms
. . . . . . . . . . . . . . . . . . . . . . . 3-262
Use Custom Patterns for Transforms . . . . . . . . . . . . . . . . 3-267 Add New Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-267 Overwrite Existing Patterns . . . . . . . . . . . . . . . . . . . . . . . . 3-269 Supported Distributions
. . . . . . . . . . . . . . . . . . . . . . . . . . . 3-270
Import Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-272 Store Statistical Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-276 Compute Measures of Central Tendency . . . . . . . . . . . . . 3-277 Compute Measures of Dispersion
. . . . . . . . . . . . . . . . . . . 3-281
xiii
Compute Measures of Shape . . . . . . . . . . . . . . . . . . . . . . . . 3-283 Compute Covariance and Correlation . . . . . . . . . . . . . . . 3-286 Handle Outliers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-288 Bin Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-289 Create Scatter and List Plots . . . . . . . . . . . . . . . . . . . . . . . 3-291 Create Bar Charts, Histograms, and Pie Charts . . . . . . Bar Charts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Histograms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pie Charts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-295 3-295 3-297 3-298
Create Box Plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-303 Create Quantile-Quantile Plots . . . . . . . . . . . . . . . . . . . . . 3-305 Univariate Linear Regression . . . . . . . . . . . . . . . . . . . . . . . 3-308 Univariate Nonlinear Regression
. . . . . . . . . . . . . . . . . . . 3-312
Multivariate Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-315 Principles of Hypothesis Testing . . . . . . . . . . . . . . . . . . . . 3-318 Perform chi-square Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-319 Perform Kolmogorov-Smirnov Test . . . . . . . . . . . . . . . . . . 3-321 Perform Shapiro-Wilk Test . . . . . . . . . . . . . . . . . . . . . . . . . 3-322 Perform t-Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-323 Divisors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-324
xiv
Contents
Compute Divisors and Number of Divisors . . . . . . . . . . . . . 3-324 Compute Greatest Common Divisors . . . . . . . . . . . . . . . . . . 3-325 Compute Least Common Multiples . . . . . . . . . . . . . . . . . . . 3-326 Primes and Factorizations . . . . . . . . . . . . . . . . . . . . . . . . . Operate on Primes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Factorizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Prove Primality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modular Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Quotients and Remainders . . . . . . . . . . . . . . . . . . . . . . . . . . Common Modular Arithmetic Operations . . . . . . . . . . . . . . Residue Class Rings and Fields . . . . . . . . . . . . . . . . . . . . . . Congruences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Linear Congruences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Systems of Linear Congruences . . . . . . . . . . . . . . . . . . . . . . Modular Square Roots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . General Solver for Congruences . . . . . . . . . . . . . . . . . . . . . . Sequences of Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fibonacci Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mersenne Primes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Continued Fractions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-327 3-327 3-329 3-330 3-331 3-331 3-333 3-334 3-336 3-336 3-337 3-338 3-342 3-344 3-344 3-344 3-345
Programming Fundamentals
4
Data Type Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Domain Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Expression Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Choose Appropriate Data Structures . . . . . . . . . . . . . . . . Convert Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use the coerce Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use the expr Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-3 4-3 4-3 4-6 4-8 4-9 4-10 4-13
xv
Define Your Own Data Types . . . . . . . . . . . . . . . . . . . . . . . Access Arguments of a Procedure . . . . . . . . . . . . . . . . . . . Test Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Check Types of Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . Check Arguments of Individual Procedures . . . . . . . . . . . . Verify Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Debug MuPAD Code in the Tracing Mode . . . . . . . . . . . . Display Progress
4-15 4-19 4-22 4-22 4-24 4-28 4-32 4-36 4-39 4-41 4-43 4-47 4-48 4-48 4-51 4-52 4-63 4-65 4-65 4-66 4-67 4-70 4-70
..................................
.................
Handle Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . When to Analyze Performance . . . . . . . . . . . . . . . . . . . . . . Measure Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Calls to MuPAD Processes . . . . . . . . . . . . . . . . . . . . . . . . . . Calls to External Processes . . . . . . . . . . . . . . . . . . . . . . . . . Profile Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Techniques for Improving Performance . . . . . . . . . . . . . Display Memory Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Use the Status Bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Generate Memory Usage Reports Periodically . . . . . . . . . . Generate Memory Usage Reports for Procedure Calls . . . . Remember Mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Why Use the Remember Mechanism . . . . . . . . . . . . . . . . . .
xvi
Contents
Remember Results Without Context . . . . . . . . . . . . . . . . . . Remember Results and Context . . . . . . . . . . . . . . . . . . . . . . Clear Remember Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . Potential Problems Related to the Remember Mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . History Mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Access the History Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . Specify Maximum Number of Entries . . . . . . . . . . . . . . . . . Clear the History Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . Why Test Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Write Single Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Write Test Scripts
4-72 4-73 4-74 4-77 4-79 4-79 4-82 4-83 4-85 4-87 4-91 4-95 4-97
.................................
................
Data Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-99 Parallel Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-99 Fixed-Length Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-102 Known-Maximum-Length Collection . . . . . . . . . . . . . . . . . . 4-103 Unknown-Maximum-Length Collection . . . . . . . . . . . . . . . . 4-104 Visualize Expression Trees . . . . . . . . . . . . . . . . . . . . . . . . . 4-107 Modify Subexpressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-110 Find and Replace Subexpressions . . . . . . . . . . . . . . . . . . . . 4-110 Recursive Substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-113 Variables Inside Procedures . . . . . . . . . . . . . . . . . . . . . . . . 4-116 Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-116 Static Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-118 Utility Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-121 Utility Functions Inside Procedures . . . . . . . . . . . . . . . . . . 4-121
xvii
Utility Functions Outside Procedures . . . . . . . . . . . . . . . . . 4-122 Utility Functions in Closures . . . . . . . . . . . . . . . . . . . . . . . . 4-123 Private Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-125 Calls by Reference and Calls by Value . . . . . . . . . . . . . . . 4-127 Calls by Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-127 Calls by Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-128 Integrate Custom Functions into MuPAD . . . . . . . . . . . . 4-134
5
Gallery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2D Function and Curve Plots . . . . . . . . . . . . . . . . . . . . . . . . Other 2D examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3D Functions, Surfaces, and Curves . . . . . . . . . . . . . . . . . . Easy Plotting: Graphs of Functions . . . . . . . . . . . . . . . . . 2D Function Graphs: plotfunc2d . . . . . . . . . . . . . . . . . . . . 3D Function Graphs: plotfunc3d . . . . . . . . . . . . . . . . . . . . Attributes for plotfunc2d and plotfunc3d . . . . . . . . . . . . Advanced Plotting: Principles and First Examples . . . General Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Some Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-2 5-2 5-7 5-17 5-25 5-25 5-41 5-57 5-84 5-84 5-91
The Full Picture: Graphical Trees . . . . . . . . . . . . . . . . . . . 5-100 Viewer, Browser, and Inspector: Interactive Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-105 Primitives
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-110
Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-115
xviii
Contents
Default Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inheritance of Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . Primitives Requesting Special Scene Attributes: Hints . . The Help Pages of Attributes . . . . . . . . . . . . . . . . . . . . . . . .
Layout of Canvas and Scenes . . . . . . . . . . . . . . . . . . . . . . . 5-129 Layout of the Canvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-129 Layout of Scenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-135 Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Generate Simple Animations . . . . . . . . . . . . . . . . . . . . . . . . Play Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The Number of Frames and the Time Range . . . . . . . . . . . What Can Be Animated? . . . . . . . . . . . . . . . . . . . . . . . . . . . Advanced Animations: The Synchronization Model . . . . . . Frame by Frame Animations . . . . . . . . . . . . . . . . . . . . . . . . Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-139 5-139 5-145 5-146 5-149 5-151 5-154 5-161
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-177
Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-182 Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-185 RGB Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-185 HSV Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-189 Save and Export Pictures . . . . . . . . . . . . . . . . . . . . . . . . . . 5-191 Save and Export Interactively . . . . . . . . . . . . . . . . . . . . . . . 5-191 Save in Batch Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-191 Import Pictures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-195 Cameras in 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-197 Possible Strange Effects in 3D . . . . . . . . . . . . . . . . . . . . . . 5-208
xix
Quick Reference
6
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-2
7
Abstract Data Types Library . . . . . . . . . . . . . . . . . . . . . . . . Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Axioms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Category Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Combinatorics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Functional Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . Grbner bases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The import Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Integration Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . First steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Integration by parts and by change of variables . . . . . . . . . Linear Algebra Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Data Types for Matrices and Vectors . . . . . . . . . . . . . . . . . . 7-2 7-2 7-4 7-4 7-5 7-5 7-6 7-6 7-7 7-8 7-10 7-11 7-12 7-12 7-14 7-16 7-16 7-17
xx
Contents
Linear Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The misc Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Numeric Algorithms Library . . . . . . . . . . . . . . . . . . . . . . . . Orthogonal Polynomials . . . . . . . . . . . . . . . . . . . . . . . . . . . . Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Typeset Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Greek Letters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Open Face Letters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arrows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Other Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Whitespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Punctuation Marks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Umlauts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Currency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Math Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Type Checking and Mathematical Properties . . . . . . . . Example 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7-24 7-26 7-27 7-28 7-29 7-32 7-32 7-34 7-34 7-35 7-36 7-37 7-38 7-38 7-38 7-39 7-40 7-40 7-41 7-43 7-43 7-44 7-44
xxi
xxii
Contents
1
Getting Started
Desktop Overview on page 1-2 Evaluate Mathematical Expressions and Commands on page 1-4 Quickly Access Standard MuPAD Functions on page 1-7 Access Help for Particular Command on page 1-15 Perform Computations on page 1-20 Use Graphics on page 1-42 Format and Export Documents and Graphics on page 1-66 Use Data Structures on page 1-116 Use the MuPAD Libraries on page 1-148 Programming Basics on page 1-155 Debug MuPAD Code Using the Debugger on page 1-184
Getting Started
Desktop Overview
A MuPAD notebook has three types of regions: input regions, output regions, and text regions.
In the input regions, marked by grey brackets, you can type mathematical expressions and commands in the MuPAD language. For example, type the following expression and press Enter to evaluate the result: 3*2^10 + 1/3 - 3
1-2
Desktop Overview
The results (including graphics) appear in a new output region. The default font color for input regions is red, and the default font color for output regions is blue. To customize default settings, see Changing Default Format Settings. When you evaluate an expression in the bottom input region, MuPAD inserts a new input region below. To insert new input regions in other parts of a notebook:
1 Select the place in a notebook where you want to insert a new input region 2 Insert a new input region:
To insert an input region below the cursor position, select Insert>Calculation from the main menu. To insert an input region above the cursor position, select Insert>Calculation Above from the main menu. You can type and format text in a notebook similar to working in any word processing application. To start a new text region, click outside the gray brackets and start typing. Also, to insert a new text region, you can select Insert>Text Paragraph or Insert>Text Paragraph Above. You cannot insert a text region between adjacent input and output regions. You can exchange data between different regions in a notebook. For example, you can: Copy expressions and commands from the text regions to the input regions and evaluate them. Copy expressions and commands from the input regions to the text regions. Copy results including mathematical expressions and graphics from the output regions to the text regions. Copy results from the output regions to the input regions. Mathematical expressions copied from the output regions appear as valid MuPAD input commands. You cannot paste data into the output regions. To change the results, edit the associated input region and evaluate it by pressing Enter.
1-3
Getting Started
The results appear in the same grey bracket below the input data. By default, the commands and calculations you type appear in red color, the results appear in blue. To suppress the output of a command, terminate a command with a colon. This allows you to hide irrelevant intermediate results. For example, assign the factorial of 123 to the variable a, and the factorial of 132 to the variable b. In MuPAD, the assignment operator is := (the equivalent function is _assign). The factorial operator is ! (the equivalent function is fact). Terminate these assignments with colons to suppress the outputs. Here MuPAD displays only the result of the division a/b: a := 123!: b := 132!: a/b
delete a, b: You can enter several commands in an input region separating them by semicolons or colons: a+b; a*b; a^b
1-4
z := x + y
If you change the value of the variable y, the change does not automatically apply to the variable z. To propagate the change throughout different input regions, select Notebook from the main menu. From here you can: Select Evaluate to evaluate calculations in one input region. Select Evaluate From Beginning to evaluate calculations in the input regions from the beginning of a notebook to the cursor position. Select Evaluate To End to evaluate calculations in the input regions from the cursor position to the end of a notebook. Select Evaluate All to evaluate calculations in all input regions in a notebook.
1-5
Getting Started
Also, you can propagate the change throughout multiple input regions by pressing Enter in each input region.
1-6
1-7
Getting Started
The buttons on the Command Bar display the function labels. To see the name of the function that the button presents, hover your cursor over the button.
To insert a function:
1 Point the cursor at the place in an input region where you want to insert a
function.
2 Click the button corresponding to the function. 3 Insert the parameters instead of the # symbols. You can switch between
1-8
Most of the buttons on the Command Bar include a drop-down menu with a list of similar functions. The buttons display a small triangle in the bottom right corner. Click the button to open the list of functions.
1-9
Getting Started
Using the Command Bar, you also can create the following: Vectors and matrices
1-10
1-11
Getting Started
3-D plots
1-12
General Math and Plot Commands menus at the bottom of the Command Bar display the categorized lists of functions.
1-13
Getting Started
1-14
Autocomplete Commands
MuPAD helps you complete the names of known commands as you type them so that you can avoid spelling mistakes. Type the first few characters of the command name, and then press Ctrl+space. If there is exactly one name of a command that starts with these letters, MuPAD completes the command. If more than one name starts with the characters you typed, MuPAD displays a list of all names starting with those characters.
1-15
Getting Started
1-16
For more detailed information, right-click the name of a command and select Help about from the context menu.
1-17
Getting Started
1-18
For more detailed information about the command and its input parameters, use the ? command: ?solve
1-19
Getting Started
Perform Computations
In this section... Compute with Numbers on page 1-20 Differentiation on page 1-25 Integration on page 1-28 Linear Algebra on page 1-29 Solve Equations on page 1-33 Manipulate Expressions on page 1-36 Use Assumptions in Your Computations on page 1-39
or rational results:
1-20
Perform Computations
(1 + (5/2*3))/(1/7 + 7/9)^2
If MuPAD cannot find a representation of an expression in an integer or rational form, it returns a symbolic expression: 56^(1/2)
For more information on the mathematical constants implemented in MuPAD, see Constants.
Approximate Numerically
By default, MuPAD performs all computations in an exact form. To obtain a floating-point approximation to an expression, use the float command. For example: float(sqrt(56))
The accuracy of the approximation depends on the value of the global variable DIGITS. The variable DIGITS can assume any integer value between 1 and 229 + 1. For example:
1-21
Getting Started
DIGITS:=20: float(sqrt(56))
The default value of the variable DIGITS is 10. To restore the default value, enter: delete DIGITS When MuPAD performs arithmetic operations on numbers involving at least one floating-point number, it automatically switches to approximate numeric computations: (1.0 + (5/2*3))/(1/7 + 7/9)^2
If an expression includes exact values such as or sin(2) and floating-point numbers, MuPAD approximates only numbers: 1.0/3*exp(1)*sin(2)
To approximate an expression with exact values, use the float command: float(1.0/3*exp(1)*sin(2))
1-22
Perform Computations
You also can approximate the constants and : DIGITS:=30: float(PI); float(E); delete DIGITS
Both real and imaginary parts of a complex number can contain integers, rationals, and floating-point numbers: (1 + 0.2*I)*(1/2 + I)*(0.1 + I/2)^3
If you use exact expressions, for example, the result in Cartesian coordinates: 1/(sqrt(2) + I)
To split the result into its real and imaginary parts, use the rectform command:
1-23
Getting Started
rectform(1/(sqrt(2) + I))
The functions Re and Im return real and imaginary parts of a complex number: Re(1/(2^(1/2) + I))
Im(1/(2^(1/2) + I))
The function abs and arg return an absolute value and a polar angle of a complex number: abs(1/(2^(1/2) + I)); arg(1/(2^(1/2) + I))
1-24
Perform Computations
Differentiation
Derivatives of Single-Variable Expressions
To compute the derivative of a mathematical expression, use the diff command. For example: f := 4*x + 6*x^2 + 4*x^3 + x^4: diff(f, x)
Partial Derivatives
You also can compute a partial derivative of a multivariable expression: f := y^2 + 4*x + 6*x^2 + 4*x^3 + x^4: diff(f, y)
You can use the sequence operator $ to compute second or higher order derivatives: diff(sin(x), x $ 3)
1-25
Getting Started
Mixed Derivatives
diff(f, x1, x2, ...) is equivalent to diff(...diff(diff(f, x1), x2)...). The system first differentiates f with respect to x1, and then differentiates the result with respect to x2, and so on. For example
Note To improve performance, MuPAD assumes that all mixed derivatives commute. For example, .
This assumption suffices for most of engineering and scientific problems. For further computations, delete f: delete f:
Derivatives of a Function
MuPAD provides two differentiation functions, diff and D. The diff function serves for differentiating mathematical expressions, such as sin(x), cos(2y), exp(x^2), x^2 + 1, f(y), and so on. To differentiate a standard function, such as sin, exp, heaviside, or a custom function, such as f:= x -> x^2 + 1, use the differential operator D:
1-26
Perform Computations
The command D(f)(x) assumes that f is a univariate function, and represents the derivative of f at the point x. For example, the derivative of the sine function at the point x2 is: D(sin)(x^2)
Note that in this example you differentiate the sin function, not the function f := x -> sin(x^2). Differentiating f returns this result: f := x -> sin(x^2): D(f)
For details about using the operator D for computing second- and higher-order derivatives of functions, see Differentiating Functions.
1-27
Getting Started
Integration
Indefinite Integrals
To compute integrals use the int command. For example, you can compute indefinite integrals: int((cos(x))^3, x)
Definite Integrals
To find a definite integral, pass the upper and lower limits of the integration interval to the int function: int((cos(x))^3, x = 0..PI/4)
You can use infinity as a limit when computing a definite integral: int(sin(x)/x, x = -infinity..infinity)
Numeric Approximation
If MuPAD cannot evaluate an expression in a closed form, it returns the expression. For example: int(sin(x^2)^2, x = -1..1)
1-28
Perform Computations
You can approximate the value of an integral numerically using the float command. For example: float(int(sin(x^2)^2,(x = -1..1)))
You also can use the numeric::int command to evaluate an integral numerically. For example: numeric::int(sin(x^2)^2, x = -1..1)
Linear Algebra
Create a Matrix
To create a matrix in MuPAD, use the matrix command: A := matrix([[1, 2], [3, 4], [5, 6]]); B := matrix([[1, 2, 3], [4, 5, 6]])
You also can create vectors using the matrix command: V := matrix([1, 2, 3])
1-29
Getting Started
You can explicitly declare the matrix dimensions: C := matrix(3, 3, [[-1, -2, -3], [-4, -5, -6], [-7, -8, -9]]); W := matrix(1, 3, [1, 2, 3])
If you declare matrix dimensions and enter rows or columns shorter than the declared dimensions, MuPAD pads the matrix with zero elements: F := matrix(3, 3, [[1, -1, 0], [2, -2]])
If you declare matrix dimensions and enter rows or columns longer than the declared dimensions, MuPAD returns the following error message: matrix(3, 2, [[-1, -2, -3], [-4, -5, -6], [-7, -8, -9]])
Error: The number of columns does not match. [(Dom::Matrix(Dom::Expre You also can create a diagonal matrix: G := matrix(4, 4, [1, 2, 3, 4], Diagonal)
1-30
Perform Computations
Operate on Matrices
To add, substract, multiply and divide matrices, use standard arithmetic operators. For example, to multiply two matrices, enter: A := matrix([[1, 2], [3, 4], [5, 6]]); B := matrix([[1, 2, 3], [4, 5, 6]]); A*B
If you add number x to a matrix A, MuPAD adds x times an identity matrix to A. For example: C := matrix(3, 3, [[-1, -2, -3], [-4, -5, -6], [-7, -8, -9]]); C + 10
1-31
Getting Started
You can compute the determinant and the inverse of a square matrix: G := matrix([[1, 2, 0], [2, 1, 2], [0, 2, 1]]); det(G); 1/G
1-32
Perform Computations
To see all the functions available in this library, enter info(linalg) in an input region. You can obtain detailed information about a specific function by entering ?functionname. For example, to open the help page on the eigenvalue function, enter ?linalg::eigenvalues.
Solve Equations
Solve Equations with One Variable
To solve a simple algebraic equation with one variable, use the solve command: solve(x^5 + 3*x^4 - 23*x^3 - 51*x^2 + 94*x + 120 = 0, x)
1-33
Getting Started
If you want to get the solution for particular values of the parameters, use the assuming command. For example, you can solve the following equation assuming that a is positive: solve(a*x^2 + b*x + c = 0, x) assuming a > 0
or you can solve a system of equations containing symbolic parameters: solve([x^2 + y^2 = a, x^2 - y^2 = b], [x, y])
1-34
Perform Computations
Solve Inequalities
Also, you can solve inequalities: solve(x^4 >= 5, x)
If you want to get the result over the field of real numbers only, assume that x is a real number: assume(x in R_); solve(x^4 >= 5, x)
You can pick the solutions that are positive: solve(x^4 >= 5, x) assuming x > 0
1-35
Getting Started
Manipulate Expressions
Transform and Simplify Polynomial Expressions
There are several ways to present a polynomial expression. The standard polynomial form is a sum of monomials. To get this form of a polynomial expression, use the expand command: expand((x - 1)*(x + 1)*(x^2 + x + 1)* (x^2 + 1)*(x^2 - x + 1)*(x^4 - x^2 + 1))
You can factor this expression using the factor command: factor(x^12 - 1)
For multivariable expressions, you can specify a variable and collect the terms with the same powers in this variable: collect((x - a)^4 + a*x^3 + b^2*x + b*x + 10*a^4 + (b + a*x)^2, x)
For rational expressions, you can use the partfrac command to present the expression as a sum of fractions (partial fraction decomposition). For example: partfrac((7*x^2 + 7*x + 6)/(x^3 + 2*x^2 + 2*x + 1))
1-36
Perform Computations
MuPAD also provides two general simplification functions: simplify and Simplify. The simplify function is faster and it can handle most of the elementary expressions: simplify((x - 1)*(x + 1)*(x^2 + x + 1)*(x^2 + 1)* (x^2 - x + 1)*(x^4 - x^2 + 1))
The Simplify function searches for simpler results deeper than the simplify function. The more extensive search makes this function slower than simplify. The Simplify function allows you to extend the simplification rule set with your own rules and serves better for transforming more complex expressions. For the elementary expressions it gives the same result as simplify: Simplify((x - 1)*(x + 1)*(x^2 + x + 1)*(x^2 + 1)* (x^2 - x + 1)*(x^4 - x^2 + 1))
For the following expression the two simplification functions give different forms of the same mathematical expression: f := exp(wrightOmega(-ln(3/5)))*exp(ln(5) - ln(3)): simplify(f); Simplify(f)
Note that there is no universal simplification strategy, because the meaning of the simplest representation of a symbolic expression cannot be defined clearly. Different problems require different forms of the same mathematical
1-37
Getting Started
expression. You can use the general simplification functions simplify and Simplify to check if they give a simpler form of the expression you use.
To factor the trigonometric expression, use the factor command: factor(cos(x)^4 + 4*cos(x)^3*sin(x) + 6*cos(x)^2*sin(x)^2 + 4*cos(x)*sin(x)^3 + sin(x)^4)
You can use the general simplification functions on trigonometric expressions: simplify(cos(x)^2 + sin(x)^2)
1-38
Perform Computations
To obtain real solutions only, pass the assumption to MuPAD using the assuming command: solve(x^(5/2) = 1, x) assuming x in R_
You can make various assumptions on the values that a variable represents. For example, you can solve an equation assuming that the variable x represents only positive values: solve(x^4 - 1 = 0, x) assuming x > 0
1-39
Getting Started
If you know that x > 1, you can pass the assumption to the integral: int(1/abs(x^2 - 1), x) assuming x > 1
versus simplify(sqrt(x^2 + 2*x + 1) + sqrt(x^2 - 2*x + 1) + sqrt(x^2 + 4*x + 4) + sqrt(x^2 - 4*x + 4)) assuming x > 2
1-40
Perform Computations
You can pass assumptions to the following functions: expand, simplify, limit, solve, and int. The Simplify function does not allow assumptions on variables.
1-41
Getting Started
Use Graphics
In this section... Graphic Options Available in MuPAD on page 1-42 Basic Plotting on page 1-43 Format Plots on page 1-53 Present Graphics on page 1-60 Create Animated Graphics on page 1-63
1-42
Use Graphics
Create function plots in polar or spherical coordinates. Create turtle graphics and Lindenmayer systems. Choose colors, fonts, legends, axes appearance, grid lines, tick marks, line, and marker styles. Apply affine transformations to a plot. You can scale, rotate, reflect, or move a plot. Set cameras for a 3-D plot. See the MuPAD gallery of plots. To see all functions available in the MuPAD graphics library, enter: info(plot)
Basic Plotting
Create 2-D Plots
The simple way to create a 2-D plot of a function is to use the plot command: plot(sin(x)*cos(3*x))
1-43
Getting Started
1-44
Use Graphics
Note By default, for a function of two variables, the plot command creates a 2-D animation. Using the option #3D lets you create a 3-D plot instead of a 2-D animation.
1-45
Getting Started
You can use the sequence generator $ to create a sequence of functions: plot(sin(k*x) $ k = 1..3)
1-46
Use Graphics
You also can plot multiple functions in one 3-D graph: plot(-sqrt(r^2 - x^2 - y^2) $ r = 1..5, #3D)
1-47
Getting Started
1-48
Use Graphics
1-49
Getting Started
For multiple functions plotted in one graph, you can specify one range for all the functions: plot(sin(k*x) $ k = 1..5, x = 0..2*PI)
1-50
Use Graphics
To specify different ranges for multiple functions plotted in one graph, use different variables: plot({sin(k*x), k*t^2} $ k = 1..5, x = 0..2*PI, t = -1..1)
1-51
Getting Started
1-52
Use Graphics
Format Plots
Enable Plot Formatting Mode
In MuPAD, you can format your graphic results interactively when working in plot formatting mode. To switch to graphics formatting mode, click any place on a plot. In this mode, the Object Browser pane appears.
1-53
Getting Started
If you do not see the Object Browser and Property panes, select View > Object Browser or click on the toolbar.
The top of the Object Browser pane displays the components of your graphics such as scene (background), coordinate system, and a function plot. For further information on the structure of graphics, see The Full Picture: Graphical Trees.
1-54
Use Graphics
After you select a component in the Object Browser pane, the bottom of the pane displays the properties of this component.
1-55
Getting Started
You can use predefined colors or select a color from a more extensive palette.
1-56
Use Graphics
Modify Axes
To format the axes of your graphics, switch to plot formatting mode and select Coordinate System at the top of the Object Browser pane. The bottom of the pane shows axes properties that you can change. For example, you can add grid lines.
1-57
Getting Started
1-58
Use Graphics
You can use predefined colors or select a color from a more extensive palette.
1-59
Getting Started
Present Graphics
When you present graphic results in MuPAD, you can move, zoom, and rotate your graphics. You also can select different components of a plot. When presenting graphic results, switch to the plot formatting mode. You can use the following toolbar to manually rotate, move, zoom your plot, and show coordinates of any point on your plot:
1-60
Use Graphics
To see the coordinates for a point on your plot, click the point and hold the mouse button. You can move the cursor while holding the mouse button and see the coordinates of all the points on the path of the cursor.
1-61
Getting Started
You can use the toolbar to rotate and zoom your plot automatically. You also can change the speed for rotation and zooming.
1-62
Use Graphics
1-63
Getting Started
Play Animations
MuPAD displays the first frame of an animation as static picture. To play the animation, click the picture. When MuPAD plays an animation, the Animation toolbar with the player controls appears:
1-64
Use Graphics
Count Backwards
To play an animation forward and then backward, click the Repetition button and select the option Back and Forth. You also can specify the range for a parameter so that the initial value is greater than the final value. The following example creates an animated plot of the function using the parameter a that gradually changes value from 2 to 0.1: plot(sin(a*x^2 + a*y^2), x = -2..2, y = -2..2, a = 2..0.1, #3D)
1-65
Getting Started
Format Text
Choose Font Style, Size, and Colors
To change the font for a particular piece of text:
1 Select text that you want to format. 2 Select Format>Characters from the main menu or use context menu.
1-66
3 In the Character Format dialog box choose the font style, font size, font and
background colors, and effects. The window at the bottom of the dialog box shows a preview of your changes.
1-67
Getting Started
If you want to experiment with different fonts, and see how the formatted text looks in your notebook, click the Apply button. This button applies formatting to the selected text and leaves the Character Format dialog box open. You can change font and color of your text several times without having to open this dialog box for each change. When you finish formatting, click OK to close the Character Format dialog box.
To format selected text, you also can use the Format toolbar. If you do not see the Format toolbar, select View>Toolbars>Format from the main menu.
1-68
To change the font size quickly, you can use Format>Increase Size and Format>Decrease Size or the corresponding buttons on the Format toolbar.
1-69
Getting Started
background color, and writing direction of the text. The writing direction is a language-specific option that allows you to type from right to left.
1-70
If you want to experiment with different paragraph settings, and see how the formatted text looks in your notebook, click the Apply button. This button applies formatting to the selected text and leaves the Paragraph Format dialog box open. You can change paragraph settings several times without having to open this dialog box for each change. When you finish formatting, click OK to close the Paragraph Format dialog box:
1-71
Getting Started
1-72
2 Set your formatting preferences. You can define the script size, choose
between inline (embedded in text) or displayed styles, and use the Slant identifiers check box to italicize variables. Also, you can specify whether you want to wrap long mathematical expressions to a notebook window size.
1-73
Getting Started
If you want to experiment with different settings for mathematical expressions and see how the formatted expression looks in your notebook, click Apply. This button applies formatting to the selected text and leaves the Math Format dialog box open. You can change settings several times without having to open this dialog box for each change. When you finish formatting, click OK to close the Math Format dialog box.
1-74
the top and bottom of the calculation, and width of the left bracket that encloses the input region.
1-75
Getting Started
If you want to experiment with different settings for input regions, and see how the formatted expressions and commands look in your notebook, click the Apply button. This button applies formatting to the selected region and leaves the Calculation Format dialog box open. You can change settings several times without having to open this dialog box for each change. When you finish formatting, click OK to close the Calculation Format dialog box.
1-76
1-77
Getting Started
2 In the resulting dialog box, use tabs to select the required element. For
1-78
1-79
Getting Started
4 In the appropriate fields, enter values for the size of indentation, the
spacing at the top and bottom of the calculation, and the width of the left bracket that encloses each input and output region.
5 Click OK to apply the new default settings and close the Default Formats
dialog box.
Use Frames
If you want to format different parts of a notebook separately, use frames. Frames can include text, mathematical expressions, and commands. To insert a frame:
1 Select the place where you want to insert a frame. 2 Select Insert>Frame.
1-80
1-81
Getting Started
menu.
1-82
3 In the appropriate fields of the Frame Format dialog box, type the size of
left margin, frame border size, width of the left bracket that encloses the input region, and background color.
1-83
Getting Started
4 Click OK to apply the new frame settings and close the Frame Format
dialog box.
1-84
Use Tables
Create Tables
To insert a table in a notebook:
1 Select the place where you want the table to appear. 2 Select Insert>Table.
1-85
Getting Started
3 In the resulting dialog box, select the number of columns and rows and
click OK.
1-86
1-87
Getting Started
If you inserted a row, it appears above the row with the selected cell. If you inserted a column, it appears to the left from the selected cell.
1-88
Format Tables
You can change the appearance of a table in a MuPAD notebook. To format a table:
1 Click the table you want to format. 2 Select Format>Table from the main menu.
1-89
Getting Started
1-90
Text wrapping Cell margins (all margins have the same size.) Distance between the text and the border of a cell Width of the line used to draw cell borders Space between the cells Background color of the cells
If you want to experiment with different settings, and see how the formatted table looks in your notebook, click the Apply button. This button applies formatting to the selected table and leaves the Table Format dialog box open. You can change settings several times without having to open this dialog box for each change. When you finish formatting, click OK to close the Table Format dialog box.
1-91
Getting Started
Embed Graphics
To insert a picture into a text region:
1 Select the place in a text region where you want to insert a picture. 2 Select Insert>Image from the main menu and browse the image you want
to insert in a notebook.
1-92
3 The selected image appears in the original size. You cannot format images
1-93
Getting Started
1-94
1-95
Getting Started
4 In the Create Link Target dialog box, type the name of the link target.
1-96
be the same one where you defined the link target, or it can be any other notebook.
2 Select the part of a notebook where you want to create a link. 3 Select Insert>Link from the main menu or use the context menu. 4 In the Create Hyperlink dialog box, select MuPAD Document and the
name of the notebook that you want to link to. The Targets list displays all link targets available in the selected notebook.
5 In the Targets list, select the link target that you want to use. If you want
1-97
Getting Started
1-98
4 The following dialog box appears. To continue creating a link, click OK.
5 Open the notebook where you want to insert the link target. If you create a
1-99
Getting Started
7 Right-click the selected part. From the context menu, select Interactive
1-100
1 Select the part of a notebook where you want to insert a link. 2 Select Insert>Link from the main menu or use the context menu. 3 In the Create Hyperlink dialog box select Existing File. 4 Select the file you want to refer to. To select the file, enter the file name in
the Link to field or choose the file from the history list. Alternatively, click the Open File button , and then browse for the file.
1-101
Getting Started
2 Select Insert>Link from the main menu or use the context menu. 3 In the Create Hyperlink dialog box, select Internet. 4 Type an Internet address and click OK. For example, insert a link to the
Web page.
1-102
1-103
Getting Started
Delete Links
To delete a link:
1 Select the link that you want to delete. 2 Right-click to open the context menu. 3 Select Remove Link
Alternatively, you can use the Edit Hyperlink dialog box to delete a link. To delete a link by using the Edit Hyperlink dialog box:
1 Select the link that you want to edit.
1-104
2 Select Edit>Link from the main menu or use the context menu. 3 In the Edit Hyperlink dialog box, click the Remove Link button. 4 Click OK.
export a notebook.
1-105
Getting Started
3 In the Export Notebook dialog box, enter a name for the file and click Save.
If you export a MuPAD document with links to PDF format, these links are replaced by regular text in the resulting PDF file.
1-106
1-107
Getting Started
3 Select the file format to which you want to export the image.
1-108
4 The next steps depend on the file format you selected. Follow the
1-109
Getting Started
XVC/XVZ the MuPAD native format. You can import the images saved in this format into a notebook and activate and manipulate them with the MuPAD notebook graphic tools. JVX/JVD JavaView. Java based format for 2-D and 3-D images that you can embed into HTML Web pages. Exporting an animation to JavaView, you can choose to export the current view or a sequence of images. EPS Encapsulated PostScript. Standard format for publishing images in scientific articles and books. This format serves best for 2-D images. 3-D images are exported as raster images embedded in EPS, and, therefore, can loose quality. You cannot export animations to this format. SVG Scalable Vector Graphics. The format serves for including vector graphics and animations on Web pages. MuPAD does not support svg animations. You can only export the current view of an animation in this format. You cannot export 3-D images to this format. WMF Windows Metafile. You can use this file format on Windows operating platforms only. PDF Portable Document Format. You can use this format to export non-animated 2-D images. Bitmap Formats. Bitmap formats save an image pixel by pixel allowing the image to look identical on different computers. To save images in bitmap format, you need to select the image resolution. The quality of images saved in bitmap formats depend on the resolution and can be decreased if you scale an image after saving. MuPAD supports the following bitmap graphics formats: PNG GIF BMP JPEG
Save Animations
You can export an animation created in MuPAD into an animated GIF file. If you use a Windows systems, you can export an animation created in MuPAD into the special format AVI . To save an animation in this format, select a
1-110
compressor from the list of compressors available for your animation and operating system.
A compressor defines the size of the exported animation and the quality of images in the animation. Viewing the exported animation requires the installation of an appropriate compressor.
1-111
Getting Started
1-112
4 Select the format for saving images of the sequence and the file name. A
sequence of numbers automatically appends to the file name you enter. For example, when you enter image.jvx, you get the following sequence of files: image.1.jvx, image.2.jvx, and so on. This sequence of file names displays below the entry field for the file name.
1-113
Getting Started
5 Select the number of frames per second. This number defines the total
1-114
1-115
Getting Started
Mathematical Expressions
You can create mathematical expressions using MuPAD objects and operators. For example, the following equation presents a MuPAD expression: x + y + 1 + 1/5 + sin(5) = z
Precedence levels determine the order in which MuPAD evaluates an expression. Operators in MuPAD expressions have precedences similar to the precedences of regular mathematical operators. For example, when you compute the expression a + b*c, you calculate b*c, and then add a. To change the evaluation order, use parentheses: 1 + 2*3, (1 + 2)*3
1-116
Sequences
Create Sequences
Sequences represent one of the basic data structures. Sequences can contain arbitrary MuPAD objects. For example, numbers, symbols, strings, or functions can be entries of a sequence. There are two methods for creating sequences in MuPAD: Separating MuPAD objects with commas Using the sequence generator Separating MuPAD objects with commas creates a sequence of these objects: sequence := a, b, c, d
As a shortcut for creating a sequence, use the sequence generator $ x^2 $ x = -5..5
1-117
Getting Started
To create a new sequence using the entries of an existing sequence, use the sequence generator with the keyword in or the equivalent command _seqin. For example: x^y $ y in (a, b, c, d); f(x) $ x in [a, b, c, d]; _seqin(f(x), x, [a, b, c, d])
You cannot create nested sequences because MuPAD automatically flattens them: sequence := (a, b, c, d); ((a, b, 10), (1, 10, f))
1-118
Note _index uses the order in which the entries appear on the screen, and op uses the internal order of the entries. Although for sequences these orders are the same, for many other data structures they are different. For details, see the _index help page. To access an entry counting numbers from the end of a sequence, use negative numbers: sequence := a, b, c, d: sequence[-2]
If you use an indexed assignment without creating a sequence, MuPAD generates a table instead of a sequence: S[1] := x: S
1-119
Getting Started
To concatenate sequences, list the sequences separating them with commas: sequence1 := a, b, c: sequence2 := t^3 $ t = 0..3: sequence3 := sequence1, sequence2
To replace an entry of a sequence by a MuPAD object, access the entry by its index, and assign the new value to the entry: sequence := a, b, c, d: sequence[1] := NewEntry: sequence[2] := 1, 2, 3: sequence[-1] := matrix([[1, 2, 3], [5, 6, 7]]): sequence
To remove an entry from a sequence, use the delete command: sequence := a, b, c, d: delete sequence[2]; sequence
Lists
Create Lists
Lists represent ordered data structures. Lists can contain arbitrary MuPAD objects. For example, numbers, symbols, strings, or functions can be entries of a list. To create a list, separate MuPAD objects with commas and enclose the structure in brackets:
1-120
list := [a, b, c, d]
Also, you can create a sequence, and convert it to a list. To convert a sequence to a list, enclose the sequence in brackets. As a shortcut for creating a sequence, use the sequence generator $ or its functional form _seqgen. Enclose the sequence in brakets: [i*(i-1) $ i = 1..10]; [i $ 10]
MuPAD does not flatten lists like it flattens sequences. You can create nested lists: list1 := [1, 2]: list2 := [5, 6]: list3 := [list1, 3, 4, list2]
1-121
Getting Started
To access an entry counting numbers from the end of a list, use negative numbers: list := [a, b, c, d, e, f]: list[-2]
If you use an indexed assignment without creating a list, MuPAD generates a table instead of a list: L[1] := x: L
1-122
Operate on Lists
MuPAD lists support the following operations: Verifying that a list contains a particular object Using a list as a function in a function call Applying a function to all entries of a list Extracting entries of a list Dividing a list according to particular properties of its entries Arithmetical operations on lists To check if an object belongs to a list, use the contains command. The command returns the position of the first occurrence of the object in the list. If the object does not belong to the list, contains returns 0: list := [(i-5)/7 $ i = 10..20]; contains(list, 1); contains(list, -1)
If you use a list as the function in a function call, MuPAD returns the list of appropriate function calls: [sin, cos, tan, f](x); [sin, cos, tan, f](0.1)
1-123
Getting Started
To apply a function to all entries of a list, use the function map: map([x, 0.1, 1/5, PI], sin); map([x, 0.1, 1/5, PI], `+`, a, 1)
To extract entries with particular properties from a list, use the select command: select([i $ i = 1..20], isprime)
To divide a list into three lists according to particular properties, use the split command: split([i $ i = 1..10], isprime)
The resulting three lists contain: Entries with the required properties Entries without the required properties Entries for which the required properties are unknown. MuPAD supports the following arithmetical operations on lists: addition, substraction, multiplication, division, and power. The lists you operate on
1-124
must contain an equal number of entries. MuPAD forms a new list containing the entries of the existing lists combined pairwise: list1 := [a, b, c]: list2 := [d, e, f]: list1 + list2; list1*list2; list1^list2
When you combine a list and a scalar, MuPAD combines a scalar with each entry of a list. For example: list1 := [a, b, c]: list1 + a; list1^5; list1*(a + 5)
Note Combining a scalar and a list differs from combining a scalar and a matrix. When you add a scalar to a matrix, MuPAD adds the scalar multiplied by an identity matrix to the original matrix. For example, define a matrix M as follows. Add the variable a the matrix M:
1-125
Getting Started
Now define the rows of the matrix M by the following three lists. Add the variable a to each list. MuPAD adds the variable a to each entry of the three lists: list1 := [1, 2, list2 := [4, 5, list3 := [7, 8, matrix([list1 + 3]: 6]: 9]: a, list2 + a, list3 + a]);
When you combine a scalar and an empty list, the result is an empty list: [] + 2
MuPAD lets you combine nested lists: [[a, b], c, d] + 1; [[a, b], c, d] + [1, 2, 3]
1-126
To combine lists with unequal numbers of entries, use the zip command. By default, the resulting list has the same number of entries as the shortest list: list1 := [a, b]: list2 := [d, e, f]: zip(list1, list2, _plus); zip(list1, list2, _mult); zip(list1, list2, _power)
To produce the list with the number of entries equal to the longer list, use a default value as additional parameter: zip(list1, list2, _plus, 100)
To concatenate lists, use the operator . (dot) or its functional form _concat:
1-127
Getting Started
:= := := :=
You can replace an entry of a list: list := [a, b, c, d, e]: list[1] := newEntry: list[2] := [1, 2, 3]: list[-1] := matrix([[1, 2, 3], [5, 6, 7]]): list
To remove an entry from a list, use the delete command: list := [a, b, c, d, e, f]: delete list[-1]; list
Sets
Create Sets
Sets represent unordered mathematical structures. Sets can contain arbitrary MuPAD objects. For example, numbers, symbols, strings, or functions can be elements of a set. To create a set, separate MuPAD objects with commas and enclose the structure in braces: set1 := {a, 3, b, c, d, 180, -15}
1-128
Also, you can create a sequence, and convert it to a set. To convert a sequence to a set, enclose the sequence in braces. As a shortcut for creating a sequence, use the sequence generator $ or its functional form _seqgen. Enclose the sequence in braces: {i*(i-1) $ i = 1..10}
The order of the elements in a set does not depend on the order in which you insert them. If an order of elements is important, use a list instead of a set: [a, 3, b, c, d, 180, -15]
MuPAD does not necessarily sort the elements of a set alphabetically: set2 := {cos, tan, sin}
A set cannot contain duplicate elements. When creating a set, MuPAD automatically removes duplicates: set3 := {2, 6, 7, a, 6, 2, 2, a, b}
1-129
Getting Started
When using a notebook interactively, you can access an element of a set by its position in an output region. To access an element by the position as you see it on screen, use brackets or _index: set2 := {[c,a,b], [b,c,a], [a,b,c]}: set2[1]; _index(set2, 3)
You can access particular solutions from a set returned by the solve command. To use the order of elements of a set as they appear on screen, use brackets or _index: solutions := solve(x^4 = 1, x); solutions[3]; _index(solutions, 2..4)
1-130
If you use an indexed assignment without creating a set, MuPAD generates a table instead of a set: set[1] := x: set
Operate on Sets
MuPAD sets support the following operations: Defining an object as a member of a set Verifying that a set contains a particular object Using a set as a function in a function call Applying a function to all elements of a set Extracting entries of a set Computing the intersection of sets Dividing a set according to particular properties of its elements To define an object as a member of a set, use the in command: x in {1, 2, 3, a, d, 5}
To check if an object belongs to a set, use the contains command: set := {a, 3, b, c, d, 180, -15}: contains(set, d); contains(set, e);
1-131
Getting Started
If you use a set as the function in a function call, MuPAD returns the set of appropriate function calls: {sin, cos, tan, f}(x); {sin, cos, tan, f}(0.1)
To apply a function to all elements of a set, use the function map: map({x, 0.1, 1/5, PI}, sin)
To extract elements with particular properties from a set, use the select command: select({{a, x, b}, {a}, {x, 1}}, contains, x)
To find the intersection of sets, use the intersect command: S := {1,2,3}: S intersect {2,3,4};
To divide a set into three sets according to particular properties, use the split command:
1-132
The resulting three sets contain: Elements with the required properties Elements without the required properties Elements for which the required properties are unknown.
To replace an element of a set, use the subs command. The new element does not necessarily appear in place of the old one: set4 := {a, b, 2, 6, 7}; subs(set4, a = 1)
Note When you replace and delete elements of a set, the order of its elements can change even if you delete or replace the last element.
1-133
Getting Started
When replacing or deleting an element, always check that you access the element at the correct position: set4; op(set4, 4)
The subs command does not modify the original set: set4 := {a, b, 2, 6, 7}: subs(set4, a = 1); set4
To delete elements from a set, use the minus command. You can simultaneously delete several elements of a set: set5 := {1, 2, 6, 7, b}: set5 minus {1, b}
Tables
Create Tables
Tables associate arbitrary indices with arbitrary values. For example, you can use tables to represent collections of equations in the form index = value. To generate a table, use the table command: T := table(a = b, c = d)
1-134
You can create tables from equations, existing tables, lists, or sets of equations: table(s = t, T, [x = 6], {y = 13})
MuPAD inserts index-value pairs in a table in the same order as you enter them. Each new entry can override previous entries. The order of output does not reflect the order of input: T1 := table([5 = a, 12 = c]): T2 := table([a = 5, c = 12]): T3 := table(5 = b, T1, T2, [a = 6], {c = 13})
1-135
Getting Started
To access a value entry of a table by its index, also use brackets or _index: T := table(a = 11, c = 12): T[c]
If an index does not exist, you get: T[b]; table(a = 11, c = 12)[b]
Before accessing a value entry of a table by its index, check that the index is available for the table: contains(T, b); contains(T, a); T[a]
Operate on Tables
MuPAD tables support the following operations: Extracting contents of a table as a collection of equations Listing indices and values separately
1-136
Verifying that a table contains a particular object Searching for an object among the indices and the values a table To extract the contents of a table as a collection of equations, use the op command: op(T)
You can list indices and values of a table separately: leftSide := lhs(T); rightSide := rhs(T)
To check if an object belongs to the indices of a table, use the contains command: T := table(a = 11, c = 12): contains(T, a); contains(T, 11)
If you want to search for an object among the indices and the values of a table, use the has command: T := table(a = 11, c = 12): has(T, 11); has(T, c);
1-137
Getting Started
has(T, x)
Arrays
Create Arrays
Arrays represent multidimensional data structures. You can use only integers for array indices. To generate an array, use the array command: A := array(0..2, 0..3); B := array(0..2, 0..3, 0..4)
1-138
array(0..2, 0..3, 0..4) For two-dimensional arrays, the first range defines the number of rows, the second range defines the number of columns. Ranges for array indices do not necessarily start with 0 or 1: A := array(3..5, 1..2)
1-139
Getting Started
To access a range of array entries, first convert the array to a matrix: B := matrix(A); domtype(B)
Use the ranges of indices to access the entries of the matrix. The result is also a matrix. b := B[1..2,1..3]; domtype(b)
To convert matrix b to an array, use the coerce function: a := coerce(b, DOM_ARRAY); domtype(a)
1-140
Alternatively, you can index into an array by using this command: array(1..2, 1..3,[A[i, j] $ j = 1..3 $ i = 1..2])
Operate on Arrays
MuPAD arrays support the following operations: Assigning values to the entries of arrays Comparing arrays MuPAD does not support arithmetical operations on arrays. You can assign values to the entries of an array: A := array(0..1, 0..2): A[0, 0] := 1: A[0, 1] := 2: A[0, 2] := 3: A[1, 0] := a: A[1, 1] := b: A[1, 2] := c: A
You also can provide the values of the entries while creating an array: A := array(0..1, 0..2, [[1, 2, 3], [a, b, c]]); B := array(1..2, 1..3, 1..5, [[[[i, j, k] $ k=1..5 ] $ j=1..3] $ i=1..2]): B[2,3,4]
1-141
Getting Started
MuPAD accepts nested and flat lists as array entries: array([[1, 2, 3], [a, b, c]]); array(1..2, 1..3, [1, 2, 3, a, b, c]);
When comparing arrays, MuPAD compares both indices and values of the entries. By default, indices start with 1: A1 := array([[1, 2, 3], [a, b, c]]): A2 := array(0..1, 0..2, [1, 2, 3, a, b, c]): A3 := array(1..2, 1..3, [1, 2, 3, a, b, c]): bool(A1 = A2); bool(A1 = A3)
1-142
To use arithmetical operations, convert arrays to matrices. For numeric data, you also can use Arrays with Hardware Floating-Point Numbers.
To remove entries from an array, use the delete command. When you remove an entry of an array, the dimensions of an array do not change. MuPAD changes the entry value you remove to NIL: A := array(0..1, 0..2, [[1, 2, 3], [a, b, c]]): delete(A[0, 2]): A
Arrays of hardware floating-point numbers use less memory than regular arrays and matrices. You can use basic arithmetical operations on these arrays:
1-143
Getting Started
A + 2*A
If you declare matrix dimensions and enter rows or columns shorter than the declared dimensions, MuPAD pads the matrix with zero elements: A := matrix(2, 4, [[a, b, c], [1, 2, 3]])
If you declare matrix dimensions and enter rows or columns longer than the declared dimensions, MuPAD returns the following error message: A := matrix(2, 1, [[a, b, c], [1, 2, 3]])
Error: The number of columns does not match. [(Dom::Matrix(Dom::Expre As a shortcut for providing elements of a matrix, you can use the -> command: A := matrix(5, 5, (i, j) -> i*j)
1-144
Create Vectors
To create a vector, also use the matrix command. The command matrix([[x], [y], [z]]) creates a column vector. As a shortcut for creating a column vector, use: a := matrix([x, y, z])
To create a row vector, declare the vector dimensions or use double brackets: b1 := matrix(1, 3, [x, y, z]); b2 := matrix([[x, y, z]])
1-145
Getting Started
To convert a matrix into an array, use the expr command: C := expr(B): type(C)
1-146
1-147
Getting Started
Overview of Libraries
Libraries contain most of the MuPAD functionality. Each library includes a collection of functions for solving particular types of mathematical problems:
combinat solvelib export output fp generate
supports combinatorics operations contains various methods used by the function solve supports exporting MuPAD data to external formats supports formatted output of the MuPAD data supports functional programming methods supports conversion of the MuPAD expressions to C, FORTRAN, MATLAB, and TeX codes supports operating on ideals of multivariate polynomial rings over a field supports importing external data to MuPAD supports integral transformations and the discrete Z-transform
groebner
import transform
1-148
intlib linalg linopt listlib polylib stringlib numlib numeric ode orthpoly Pref prog
supports manipulating and solving integrals supports linear algebra operations provides algorithms for linear and integer programming supports manipulating lists supports manipulating polynomials supports manipulating strings supports number theory operations provides algorithms for numeric mathematics supports manipulating and solving ordinary differential equations provides a set of standard orthogonal polynomials supports setting and restoring user preferences provides programming utilities for analyzing functions and tracing errors provides methods for statistical analysis supports checking types of MuPAD objects supports typesetting symbols
Functions included in libraries are written in the MuPAD language. The calling syntax for functions from all the libraries (except for the standard library) includes both the library name and the function name: library::function.
1-149
Getting Started
Standard Library
The standard library presents the set of most frequently used functions including diff, int, simplify, solve, and other functions. For example: diff(x^2,x)
-- Interface:
numlib::Omega,
numlib::checkPrima
1-150
numlib::lincongruence, numlib::mroots,
numlib::mersenne, numlib::msqrts,
numlib::moebius,
numlib::numdivisor numlib::order,
numlib::numprimedivisors, numlib::omega, numlib::phi, numlib::primroot, numlib::sigma, numlib::sumOfDigits, numlib::toAscii, numlib::pi, numlib::proveprime, numlib::sqrt2cfrac, numlib::sumdivisors,
numlib::primedivis
To see brief information about a particular library function, use the mouse pointer to hover the cursor over the function name. For more information about the library and for information about the library functions, enter: ?numlib To see the implementation of a library function, use the expose command: expose(numlib::tau)
proc(a) name numlib::tau; begin if args(0) <> 1 then error(message("symbolic:numlib:IncorrectNumberOfArguments")) else if not testtype(a, Type::Numeric) then return(procname(args())) else if domtype(a) <> DOM_INT then error(message("symbolic:numlib:ArgumentInteger"))
1-151
Getting Started
After exporting the decimal function, you can use it without using the library name numlib: decimal(1/200)
To call the info, help, or ? commands, use the full name of an exported function including the name of a library: ?numlib::decimal You cannot export a library function with the same name you use for another object: hilbert := x: use(linalg, hilbert)
1-152
Warning: Identifier 'hilbert' already has a value. It is not exported After clearing the variable decimal, you can export a function: delete hilbert: use(linalg, hilbert): hilbert(3)
You also can export several functions from the same library simultaneously. For example, you can export the functions for finding the sum of digits and the set of positive divisors of an integer: use(numlib, sumOfDigits, divisors): divisors(21); sumOfDigits(21)
To export all functions of a library, pass the library name to the use command. If some of the library functions have name conflicts with other objects, the use command issues a warning for each name conflict: use(numeric)
1-153
Getting Started
Warning: Identifier 'sort' already has a value. It is not exported. [ These library functions have the same names as the standard library functions. You cannot delete standard library functions and resolve the name conflicts. Use the full function names such as numeric::product to call these functions.
1-154
Programming Basics
Programming Basics
In this section... Conditional Control on page 1-155 Loops on page 1-161 Procedures on page 1-171 Functions on page 1-179 Shortcut for Closing Statements on page 1-181
Conditional Control
Use if Statements
You can execute different groups of statements depending on particular conditions. Use if to define a condition, and use then to define the group of statements you want to execute when the condition is true: x := -3: if x < 0 then y := x + 2; x := -x; print(x, y) end_if:
You also can define the group of statements that you want to execute when the condition is false: x := 3: if x < 0 then y := x + 2; x := -x; print(x, y) else y := x + 2;
1-155
Getting Started
x := x; print(x, y) end_if
MuPAD does not require parentheses around conditions: x := 10: if testtype(x, Type::Positive) = TRUE and type(x) = DOM_INT then print(Unquoted, "x = ".x." is a positive integer"); end_if
x = 10 is a positive integer
1-156
Programming Basics
x := 0: if (testtype(x, DOM_COMPLEX) = TRUE) then print("The Heaviside function is undefined for complex numbers") elif x = 0 then heavisideX := 1/2 elif x < 0 then heavisideX := 0 else
1-157
Getting Started
heavisideX := 1; end_if
To exit the case statement after executing the statements written under the first valid condition, use the break command. See Exiting a Conditional Statement for more details.
1-158
Programming Basics
Note MuPAD executes the case statements differently from MATLAB. MATLAB executes only the first matching case statement and skips the following case statements. In MuPAD, you must use the break command to stop execution of the following statements.
Use the return value of a conditional statement like any other value. For example, assign the return value to a variable. By default, MuPAD does not allow conditional statements in assignments. To create a valid assignment,
1-159
Getting Started
enclose conditional statements in parentheses. Suppress the output of the return value of a conditional statement with a colon: mapColor := blue: terrain := (if mapColor = blue then "water" else "land" end_if): Write a sentence by concatenating the following string and the variable terrain: print(Unquoted, "Blue color on maps usually shows ".terrain)
Blue color on maps usually shows water The following case statement also returns the result of the last assignment: palette := color: case palette of monochrome do [color1, color2] := [black, white]; break; of color do [color1, color2, color3] := [red, green, blue]; break; end_case
1-160
Programming Basics
Loops
Use Loops with a Fixed Number of Iterations (for Loops)
The for loop repeats a group of statements for a fixed number of iterations. The loop starts with the command for and ends with end_for or just end. MuPAD executes all statements between these two words as many times as you specify. For example, compute the factorial of an integer using the loop: x := 1: for i from 1 to 5 do x := x * i; end_for
More Efficient Alternative to for Loops. You often can speed up the execution of MuPAD code by replacing for loops with the sequence generator $. For example, instead of the loop x := 1: for i from 1 to 10 do x := x * i; end_for
1-161
Getting Started
Control Step Size and Count Up and Down. By default, the loop increments the value of a counter by 1 in each step. You can change the step size: for i from 1 to 3 step 1/2 do print(i) end_for
To count backwards decreasing the value of a counter with each step, instead of to, use the keyword downto: for i from 3 downto 1 do print(i) end_for
Use Mathematical Structures in for Loops. MuPAD supports the use of structures such as lists and matrices in for loops:
1-162
Programming Basics
1-163
Getting Started
Termination Condition at the End (repeat Loops). The repeat loop continues until the termination condition becomes valid. The loop starts with repeat and ends with end_repeat. MuPAD executes all the statements between these commands repeatedly while the conditions are false. The repeat loop tests a termination condition at the end of each iteration. When the condition becomes true, the loop terminates after executing the statements of the current iteration: i := 2; repeat i := i^2; print(i) until i >= 16 end_repeat:
Avoid Infinite Loops: Set a Counter. The while and repeat loops do not operate for a fixed number of steps. If the execution or termination conditions of such loops never become true, MuPAD can execute the statements within these loops infinitely. For example, if the termination condition is not valid during the first iteration, and it does not change inside the loop, the loop is infinite: i := 1; repeat print(i)
1-164
Programming Basics
until i > 3 end_repeat: To avoid this infinite loop, use the additional statement to change it in each iteration: i := 1; repeat i := i + 1; print(i) until i > 3 end_repeat:
Use Multiple Conditions. You can use multiple conditions combining the expressions by and, or, xor, or other logical operators: i := 2: j := 3: repeat i := i*j; j := j^2; print(i, j) until i > 100 and j > 10 end_repeat:
1-165
Getting Started
to 3 do 2 do i + j; 1;
1-166
Programming Basics
Exit a Loop
To add a possibility to exit a loop, use the break command. Suppose you want to exit a loop if some condition is true: for i from 1 to 3 do for j from 1 to 2 do if i = j then print(Unquoted, "i = j = ".expr2text(i)); break end_if end_for end_for:
i = j = 1
i = j = 2 The break command lets you exit the loop in which you place this command. If you create nested loops and use break inside an inner loop, MuPAD continues to execute the statements in the outer loops: for i from 1 to 3 do for j from 1 to 2 do if i = j then print(Unquoted, "break with i = j = ".i); break end_if; print(Unquoted, "i = ".i.", j = ".j); end_for end_for:
break with i = j = 1
1-167
Getting Started
i = 2, j = 1
break with i = j = 2
i = 3, j = 1
i = 3, j = 2 Suppose you want to stop executing the statements and exit the nested loops as soon as the condition i = j is true. Use the additional variable for the break state of the inner loop. Use this variable to exit the outer loop: breakAll := FALSE: for i from 1 to 3 do for j from 1 to 2 do if i = j then print(Unquoted, "break with i = j = ".i); breakAll := TRUE; break end_if; print(Unquoted, "i = ".i.", j = ".j); end_for; if breakAll then break end_if; end_for:
break with i = j = 1
1-168
Programming Basics
i = j = 1
i = 1, j = 2
i = 2, j = 1
i = j = 2
i = 3, j = 1
i = 3, j = 2
1-169
Getting Started
Suppress the output of the return value with a colon: for i from 1 to 3 do x := 2*i; y := 3*i end_for:
To display results of each iteration in a for loop, also use the print command:
1-170
Programming Basics
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
Procedures
Create a Procedure
If you want to execute a piece of code repeatedly, create and use a procedure. Define a procedure with the proc command. Enclose your code in the begin and end_proc commands: myProc:= proc(n) begin if n = 1 or n = 0 then 1 else n * myProc(n - 1) end_if;
1-171
Getting Started
Call a Procedure
Now call the procedure: myProc(5)
To display the results on your screen without returning them, use the print command: myProcPrint:= proc(n) begin print(n); if n = 0 or n = 1 then
1-172
Programming Basics
1-173
Getting Started
To enable your custom procedure to return symbolic calls, use the special syntax procname(args()). For example, create the procedure that computes a factorial of its argument: f := proc(x) begin if testtype(x, Type::PosInt) then return(x!) else return(procname(args())) end_if: end_proc: If its argument is a positive integer, this procedure returns an exact number: f(5), f(10)
Otherwise, it does not error, but returns a symbolic call to itself: f(1/3), f(1.1), f(x), f(x + 1)
1-174
Programming Basics
Multiple calls change the value of the global variable further: gProc(5): gVar
1-175
Getting Started
Global variables reduce code readability, occupy the global namespace, and often lead to errors. When you use global variables inside a procedure, always verify that each call to the procedure changes global variables as intended. Local Variables. You can access and modify local variables only inside a procedure. Suppose, you use a variable lVar in your notebook: lVar := 10
To declare a local variable, use the local command inside a procedure: lProc := proc(x) local lVar; begin lVar := 10; lVar := lVar^2 + x^2 + 1 end_proc: When you call this procedure, the value of the variable lVar changes only inside a procedure. Outside the procedure, the variable does not change its value: lProc(5): lVar
If you declare a local variable, it does not inherit the value of a global variable with the same name. Local variables are not identifiers of type DOM_IDENT. They belong to a special domain type DOM_VAR. Therefore, you cannot use a local variable as a symbolic variable. Before performing computations with a local variable, you must assign a value to that variable. For example, without the assignment lVar:= 10, the procedure call lProc returns an error message: lProc := proc(x) local lVar;
1-176
Programming Basics
Error: The operand is invalid. [_power] Evaluating: lProc Local variables cannot have assumptions.
To save this default value, use the save command at the beginning of the procedure: myProcSave := proc(newDigits, x) save DIGITS; begin DIGITS := newDigits; print(float(x)); end_proc:
1-177
Getting Started
After you call the procedure myProcSave, MuPAD restores the value of the global variable DIGITS: myProcSave(20, PI); DIGITS
The combination of save and delete lets you temporarily free the variable for the use inside a procedure. For example, the procedure cannot use the variable x because the variable has a value assigned to it: x := 10: proc() begin solve(x^2 + x = 1, x) end_proc();
Error: Invalid variable to solve for. [solve] Use the save command to save the original value 10. Then, free the variable x using the delete command: x := 10: proc() save x; begin delete x; solve(x^2 + x = 1, x) end_proc()
1-178
Programming Basics
The save and delete combination is helpful when you want to use a symbolic variable (without any value assigned to it) inside a procedure. You cannot use local variables for that purpose because a local variable in MuPAD is not an identifier. A local variable must have a value assigned to it. Also, you cannot specify assumptions on local variables, and you cannot integrate with respect to local variables.
Functions
Call Existing Functions
If you want to execute the same code repeatedly, create a procedure and use it. As a shortcut for simple procedures, create and use functions. Compared to procedures, functions require less complicated syntax. Like procedures, functions let you use the same code for different arguments as many times as you need. For example, you can always calculate sine and cosine of a particular value: sin(30.0), sin(-1.0), sin(0.5); cos(10.0), cos(-0.8), cos(3.0)
Create Functions
To define your own functions in MuPAD, use the arrow operator: f := x -> x^2
1-179
Getting Started
After defining a function, call it in the same way you call system functions: f(1), f(x), f(sin(x))
The arrow operator also can create a multivariate function: g := (x, y) -> x^2 + y^3
Call the multivariate function with numeric or symbolic parameters: g(5, 2); g(x, 2*x); g(a, b)
1-180
Programming Basics
To evaluate the right-side expression when defining a function, use the double arrow operator: f2 := x --> int(x^2, x)
Functions with symbolic parameters serve best for interactive use in a notebook. In your regular code, avoid unnecessary creation of such functions. When using a symbolic parameter, you use a global variable even though you do not explicitly declare it. See Global Variables for information on global variables and recommendations on their use.
1-181
Getting Started
For example, the following two loops are equivalent: for i in [0, 1, 0, 0] do if i = 1 then print(Unquoted, "True") else print(Unquoted, "False") end_if end_for
False
True
False
False
for i in [0, 1, 0, 0] do if i = 1 then print(Unquoted, "True") else print(Unquoted, "False") end end
False
True
1-182
Programming Basics
False
False
1-183
Getting Started
Overview
Besides syntax errors such as misspelling a function name or omitting parenthesis, run-time errors can appear when executing your code. For example, you might modify the wrong variable or code a calculation incorrectly. Runtime errors are usually apparent when your code produces unexpected results. Debugging is the process of isolating and fixing these run-time problems. MuPAD provides a tool to help you with the debugging process. With the Debugger, you can: Run your procedure step-by-step. Set rigid and conditional breakpoints. Evaluate variables and expressions after a particular function call. Watch the changing intermediate values of the variables. View the name of the currently running procedure.
1-184
2 In the Debug Procedure Call dialog box enter the procedure call you want
to debug.
1-185
Getting Started
You also can open the Debugger directly from the command line using the
debug command, for example:
debug(factor(x^2-1)) If you debug several lines of code, place the debug command in a separate input region. This allows you to avoid reevaluating the code every time you open the Debugger: g := proc(x) begin x/(x+1) end_proc: f := proc(n) begin g(10)^n end_proc: debug(f(5))
Debug Step-by-Step
Using the MuPAD Debugger, you can run a procedure step by step. Running a procedure step by step helps you isolate the errors in your code. To start the step-by-step debugging process, select Step from the main menu.
1-186
1-187
Getting Started
Executing your code step by step you can: Use Step Over to execute the current line. If the code line contains a call to another function, the Debugger passes to the next code line without stepping into that function. Use Step Into to execute the current code line and, if the code line contains a call to another function, the Debugger steps into that function. After stepping in, use Step Out to run the rest of the current function, leave the called function, and pause. For example, use Step Into to open and step through the inner procedure g.
1-188
1-189
Getting Started
right-click to use the context menu. Also you can click the Toggle Breakpoint button on the toolbar.
1-190
1-191
Getting Started
1 Select a line where you want to set a breakpoint 2 Select Breakpoints>Set Breakpoint from the main menu.
1-192
3 In the Set Breakpoint dialog box, type the condition under which you want
the Debugger to stop on this line. In the dialog box, you also can change the placement of a breakpoint defining the file and line where you want to set the breakpoint.
Use Breakpoints
After you set the breakpoint, you can continue the debugging process. The Debugger pauses at the breakpoints and executes the line with the breakpoint after you click the Continue button.
1-193
Getting Started
After setting breakpoints, you also can leave the current debugging session and start a new one. In the new session, the Debugger stops at all the breakpoints you previously set.
1-194
You can see the list of all breakpoints in the debugging process using the Breakpoints window. To open this window, select View>Breakpoints.
Remove Breakpoints
To remove a breakpoint:
1 Select the breakpoint you want to remove. 2 Select Breakpoints>Toggle Breakpoint from the main menu or
right-click to use the context menu. Also, you can click the Toggle Breakpoint button on the toolbar. The second click releases the button and removes the breakpoint. If you want to remove all breakpoints, select Breakpoints>Remove All Breakpoints from the main menu.
1-195
Getting Started
1-196
menu.
2 In the Output pane, type the expression you want to evaluate or select one
1-197
Getting Started
Alternatively, you can select an expression and hover the cursor over it. If the expression is syntactically correct and can be computed fast, MuPAD displays the value of the expression in a tooltip.
1-198
You also can enter the expressions directly into the Watch table.
1-199
Getting Started
1-200
To switch between procedures, click the name of a procedure you want to switch to. Also, you can select Step>Stack Up or Step>Stack Down from the main menu or use the toolbar. As an alternative, you can press u and d. The Call Stack pane helps you navigate within nested calls of various procedures.
Correct Errors
The Debugger displays procedures and helps you find errors in the code, but you cannot correct the errors in the Debugger window. To edit your code use the MATLAB Editor, a MuPAD notebook, or any text editor. To open a new MATLAB Editor window, select File>New Editor with Source from the main menu or select Open in Editor from the context menu. The MATLAB Editor window contains the source that you see in the Debugger and lets you modify and save it. Changes made in the Editor window do not automatically appear in the Debugger window. The Debugger presents the code that is already in the kernel. To run the Debugger on the corrected file:
1 Close the Debugger window if it is open. 2 In the Editor window select File>Save from the main menu to save
changes.
3 Open a notebook.
1-201
Getting Started
5 Select the file you want to run. 6 Start the Debugger from the notebook.
1-202
2
Notebook Interface
Notebook Overview on page 2-3 Debugger Window Overview on page 2-5 Arrange Toolbars and Panes on page 2-8 Enter Data and View Results on page 2-11 View Status Information on page 2-13 Save Custom Arrangements on page 2-14 Set Preferences for Notebooks on page 2-15 Set Preferences for Dialogs, Toolbars, and Graphics on page 2-20 Set Font Preferences on page 2-24 Set Engine Preferences on page 2-27 Get Version Information on page 2-32 Use Different Output Modes on page 2-33 Set Line Length in Plain Text Outputs on page 2-40 Delete Outputs on page 2-41 Greek Letters in Text Regions on page 2-42 Special Characters in Outputs on page 2-43 Non-Greek Characters in Text Regions on page 2-44 Use Keyboard Shortcuts on page 2-45 Use Mnemonics on page 2-46 Overview on page 2-47 Wrap Long Lines on page 2-48
Notebook Interface
Hide Code Lines on page 2-57 Change Font Size Quickly on page 2-60 Scale Graphics on page 2-63 Use Print Preview on page 2-65 Change Page Settings for Printing on page 2-69 Print Wide Notebooks on page 2-70
2-2
Notebook Overview
Notebook Overview
The first time you start MuPAD notebook, it appears with the default layout, as shown in the following illustration.
A Perform most common tasks from the Standard toolbar. B Type your comments in the text regions.
2-3
Notebook Interface
C Enter commands in the input regions. D View results (including graphics) in the output regions. E A new input region appears after evaluation of the bottom input region. F View current status information in the Status bar. G Find and Replace text in the input and text regions. H Quickly access standard functions from the Command Bar. I Format nongraphical objects in the input and output regions from the Format toolbar. J Use more items from the toolbars. K Menus change in the Graphics Format mode.
2-4
2-5
Notebook Interface
2-6
A Perform common tasks from the toolbar. B View the code that you debug. C Type an expression and evaluate it in the Output pane anytime during the debugging process. D Use the Status bar to view memory and time usage for the current or most recent debugging step. E Use the Watch pane to view values of variables during the debugging process. F Use the Call Stack pane to view the names of the procedures participating in the debugging process. For information about the Debugger mode, see Tracing Errors with the Debugger.
2-7
Notebook Interface
To use context menu, right-click any bar. The following illustration shows the context menu for the Notebook and Debugger windows.
2-8
To move the Command Bar or Find and Replace Bar, grab the pane title and drag the pane to a different location. For example, move the Command Bar to the left.
2-9
Notebook Interface
2-10
MuPAD notebook has a special type of region for viewing results: Output regions serve for viewing results. These regions automatically appear when you evaluate input regions. The results can include graphics and error messages. The default font color for output regions is blue. You cannot edit data in the output regions. To change the results, edit the associated input region and evaluate it by pressing Enter. Also, you can copy results from the output regions to the text and input regions. When you copy outputs to the input regions, MuPAD inserts ASCII equivalents of the results in the input regions. If you want to change the default text color, font, or the appearance of brackets for the current notebook, see Changing Default Format Settings. If you want to change preferences for all notebooks, see Setting Preferences for Notebooks.
2-11
Notebook Interface
Note Most preferences affect only new notebooks. They do not affect existing notebooks.
2-12
A Displays memory and time usage for the current or most recent computation. B Indicated the type of the currently active region. C Indicates insert or overwrite mode. View the current engine state at the far left end of the status bar. If the engine is not connected to your notebook, the status bar displays Not Connected.
The status bar indicates the type of the region where you position the cursor. The indicator displays: Cmd, if the cursor is in an input region Text, if the cursor is in a text region Outp, if the cursor is in an output region The status bar also indicates if the cursor is in a read-only part of a notebook, for example, in an output region.
For text and input regions, MuPAD notebook supports overwrite mode. Press the Insert key to enter text in overwrite mode. Press the Insert key again to return to entering text in insert mode. View the current state at the far right of the status bar.
2-13
Notebook Interface
2-14
2-15
Notebook Interface
The right pane of the dialog box lets you change two types of settings: the settings that affect the new notebooks only and the global settings that affect all notebooks, including existing ones. For new notebooks, you can do the following: Change the default formatting settings of all new notebooks. For details, see Changing Default Formatting for Notebook Elements.
2-16
Change the default mode for displaying results. For details on output modes, see Using Different Output Modes. Change the default line length for displaying results in plain text format. Change key sequence for evaluation of input regions to Shift+Enter. The default key is Enter. Specify how often MuPAD automatically saves a backup document. For all notebooks including existing ones, you can do the following: On Windows platforms, copy graphics using scalable Windows Metafile (WMF) format. For details, see Scalable Format for Copying Graphics on page 2-18. Highlight matched and mismatched delimiters (parentheses, brackets, and braces) in input regions. When you type a parenthesis, a bracket, or a brace, MuPAD highlights the matched delimiter in the pair. If a delimiter is missing or if a pair includes delimiters of different types (for example, a bracket and a brace), MuPAD uses a different color to highlight the delimiters. In addition to highlighting mismatched delimiters, MuPAD underlines them. To make the display of highlighting and underlining disappear, move the cursor away from a delimiter.
element. You can specify default formatting for text regions, calculations, tables, frames, and links.
2-17
Notebook Interface
5 Specify default formatting for the element you selected. For example, set
the default font size, style, and color for the text regions.
2-18
2 In the left pane of the Configure MuPAD dialog box, click Notebook. 3 In the right pane of the dialog box, select Embed scalable graphics for
2-19
Notebook Interface
2-20
3 Use the right pane of the dialog box to specify the setting you want for the
toolbars, graphics, units of measurements used in dialog boxes, and other options.
2-21
Notebook Interface
Now all dialog boxes in MuPAD except those displaying the font sizes, use millimeters as the units of measurement. For example, the Paragraph Format dialog box shows the indentation and spacing sizes in millimeters.
2-22
Hide Help buttons. Select this option if you do not want to see help buttons in the dialog boxes. Hide Welcome dialog. Select this option if you do not want to see the welcome dialog box on startup.
2-23
Notebook Interface
2-24
3 Use the right pane of the dialog box to select the fonts you want to use
as generic fonts. Use these specified generic fonts to format text, mathematical expressions, or calculations in your notebooks.
2-25
Notebook Interface
On Linux platforms, the default generic fonts depend on the system default fonts.
2-26
2-27
Notebook Interface
Engine. Path to the MuPAD engine that you want to use. Leaving this field empty indicates that you want to use the default engine.
2-28
Library Path. Path to the standard set of the MuPAD libraries that you want to use. Leaving this field empty indicates that you want to use the default library. Package Path. Path to additional libraries (packages) you that want to use. Leaving this field empty indicates that you want to use the default packages. User Init Path. Path to the folder containing initialization file (userinit.mu). This file contains startup commands for MuPAD notebooks. You can add your own commands to the initialization file. Arguments. Options you want to use when starting MuPAD engine. See the list of Options Available When Starting Engine.
2-29
Notebook Interface
-g
Start the engine in debug mode. The engine creates debug nodes during the initial read of the MuPAD library. Without this option MuPAD creates the nodes during a debug session (after the first debug call). Then, it writes the information about passes through the nodes to a temporary file. Start the engine in the debug mode. MuPAD displays more detailed debug information in the output pane of the Debugger window. Suppress reading the initialization files. Use this option to test your code without deleting the files or the path specified in the User Init Path field. Suppress reading all the package files from the path specified in the Package Path field. Use this option to test your code without deleting the files or the path. Set the limit of precalculated prime numbers. The engine calculates and stores all prime numbers that are less than the number at startup. The default startup number is 1000000. You can increase this number. The maximum value for this option is 436273009. Specify options as strings. See Pref::userOptions for details.
-v
-f
-F
-L number
-U string
2-30
-t -T filename
Start the engine in the test coverage mode. See prog::tcov for details. Start the engine in the test coverage mode and export the test coverage information to filename. See prog::tcov for details.
2-31
Notebook Interface
Build Number
For the build number of the kernel, call Pref::kernel(BuildNr). For the build number of the MuPAD library, call buildnumber.
2-32
Abbreviations
MuPAD can display results of your calculations using different modes. By default, expressions in outputs use typeset mode and abbreviations: solve(x^3 + x^2 + 1 = 0, x, MaxDegree = 3)
2-33
Notebook Interface
To enable abbreviations, select Notebook>Abbreviate Output. Alternatively, you can enable and disable abbreviations by using
Pref::abbreviateOutput. For example, disable abbreviations:
2-34
To disable the typeset mode, clear Notebook>Typeset Math: solve(x^3 + x^2 + 1 = 0, x, MaxDegree = 3)
{ { { { { 1 / 29 sqrt(31) sqrt(108) \1/3 { - -------------------------------- - | -- - ------------------ | { / 29 sqrt(31) sqrt(108) \1/3 \ 54 108 / { 9 | -- - ------------------ | { \ 54 108 / / 29 sqrt(31) sqrt(108) \1/3 | -- - ------------------ | \ 54 108 / 1 + ------------------------------ - 2 3
/ 1 / 29 sqrt(31) sqr sqrt(3) | -------------------------------- - | -- - -----------| / 29 sqrt(31) sqrt(108) \1/3 \ 54 108 | 9 | -- - ------------------ | \ \ 54 108 / - ---------------------------------------------------------------2
2-35
Notebook Interface
/ 29 sqrt(31) sqrt(108) \1/3 | -- - ------------------ | 1 \ 54 108 / --------------------------------- + -----------------------------/ 29 sqrt(31) sqrt(108) \1/3 2 18 | -- - ------------------ | \ 54 108 /
/ 1 / 29 sqrt(31) sqr sqrt(3) | -------------------------------- - | -- - -----------| / 29 sqrt(31) sqrt(108) \1/3 \ 54 108 | 9 | -- - ------------------ | \ \ 54 108 / + ---------------------------------------------------------------2
To enable the typeset mode, select Notebook>Typeset Math. You cannot disable the typeset mode programmatically.
{ { { { { 1 / 29 sqrt(31) sqrt(108) \1/3 { - -------------------------------- - | -- - ------------------ | { / 29 sqrt(31) sqrt(108) \1/3 \ 54 108 / { 9 | -- - ------------------ |
2-36
\ 54
108
/ 1 / 29 sqrt(31) sqr sqrt(3) | -------------------------------- - | -- - -----------| / 29 sqrt(31) sqrt(108) \1/3 \ 54 108 | 9 | -- - ------------------ | \ \ 54 108 / - ---------------------------------------------------------------2 / 29 sqrt(31) sqrt(108) \1/3 | -- - ------------------ | 1 \ 54 108 / --------------------------------- + -----------------------------/ 29 sqrt(31) sqrt(108) \1/3 2 18 | -- - ------------------ | \ 54 108 /
/ 1 / 29 sqrt(31) sqr sqrt(3) | -------------------------------- - | -- - -----------| / 29 sqrt(31) sqrt(108) \1/3 \ 54 108 | 9 | -- - ------------------ | \ \ 54 108 / + ---------------------------------------------------------------2
To disable the pretty print mode, clear Notebook>Pretty Print: solve(x^3 + x^2 + 1 = 0, x, MaxDegree = 3)
2-37
Notebook Interface
{- (1/9)/(29/54 - (1/108)*31^(1/2)*108^(1/2))^(1/3) - (29/54 - (1/108 (1/108)*31^(1/2)*108^(1/2))^(1/3) + (1/2)*(29/54 - (1/108)*31^(1/2)* 1/108)*31^(1/2)*108^(1/2))^(1/3) - (29/54 - (1/108)*31^(1/2)*108^(1/2 108^(1/2))^(1/3) + (1/2)*(29/54 - (1/108)*31^(1/2)*108^(1/2))^(1/3) 8^(1/2))^(1/3) - (29/54 - (1/108)*31^(1/2)*108^(1/2))^(1/3))*1/2*I} When you copy some part of an output region to an input region, plain text outputs serve best. To obtain plain text outputs, disable both typeset and pretty print modes. When you copy an entire output region to an input region, typeset mode serves best. To enable the pretty print mode, select Notebook>Pretty Print. Alternatively, you can switch between the pretty print and plain text modes by using PRETTYPRINT. Note that first you must disable the typeset mode. For example, switch to the plain text mode: PRETTYPRINT := FALSE: Switch to the pretty print mode: PRETTYPRINT := TRUE:
If you are not familiar with a notation, you can see the corresponding MuPAD command using one of following methods:
2-38
Disable typesetting mode by selecting Notebook>Typeset Math. Reevaluate the expression containing the unknown notation. Copy the output expression and paste it to an input region. Set PRETTYPRINT to FALSE, and then use the print command with the option Plain to display the results in plain text mode. For example: PRETTYPRINT := FALSE: print(Plain, Result)
(1/2)*2^(1/2)*PI^(1/2)*fresnelS(2^(1/2)/PI^(1/2)*x) For further computations, set PRETTYPRINT to TRUE. PRETTYPRINT := TRUE: Knowing the MuPAD command, you can access the corresponding help page and get more information about the special function.
2-39
Notebook Interface
Alternatively, assign the new value to the environment variable TEXTWIDTH: TEXTWIDTH := 15: To restore the setting to its default value, delete TEXTWIDTH: delete TEXTWIDTH MuPAD applies the new setting to all new outputs in a notebook. To apply the setting to existing output regions, re-evaluate the appropriate input regions. See Evaluate Mathematical Expressions and Commands on page 1-4. To change the default line length limit for the current and all new notebooks, see Setting Preferences for Notebooks.
2-40
Delete Outputs
Delete Outputs
To clear a particular output region in your notebook:
1 Click the output region you want to delete or click the adjacent input region. 2 Select Edit>Delete Output
To clear all the outputs in your current notebook, select Edit>Delete All Outputs.
2-41
Notebook Interface
of the character.
2 Select Edit>Toggle Greek.
2-42
2-43
Notebook Interface
region.
2-44
2-45
Notebook Interface
Use Mnemonics
Using mnemonics, you can access menu items and buttons. Mnemonics are underlined on the menu item or button. For example, on the File menu, the F in File is underlined, which indicates that Alt+F opens the menu. The Macintosh platform does not support mnemonics. Some versions of Windows operating system do not automatically show the mnemonics on the menu. For example, you might need to hold down the Alt key while the tool is selected to see the mnemonics on the menus and buttons. Use the Windows Control Panel to set preferences for underlining keyboard shortcuts. See the Windows documentation for details.
2-46
Overview
Overview
MuPAD provides functionality for creating electronic or printed documents, class notes, textbooks, and interactive presentations. Notebooks support the following options to help you design appealing and flexible documents: Separate formatting styles for commands in the input regions, text and mathematical formulas in the text regions Default formatting styles Different modes for displaying the results of your calculations Embedded graphics Links, tables, and frames Invisible startup commands Quick modifications of the font and graphics sizes during the presentation Export of your notebooks to PDF and HTML formats Export of your graphic results separately from notebooks
2-47
Notebook Interface
Wrap Text
To wrap text to a notebook window size, select View > Wrap To Window. If you use text wrapping and resize your notebook, MuPAD automatically adjusts text lines to a new window size. This option affects text regions only.
2-48
When you wrap text in a notebook, and then unwrap it, the vertical line appears. This line shows you the position of the right margin of the current page format.
2-49
Notebook Interface
When you print the page, MuPAD lets you choose between scaling down the whole page or cropping the content to the right of the line. The line does not appear on printed pages. To remove this line, select View > Wrap To Window.
2-50
2-51
Notebook Interface
Now MuPAD wraps all new expressions and commands in the input regions to a notebook window size. If you use wrapping for input regions and then resize your notebook, MuPAD automatically adjusts expressions and commands to a new window size.
2-52
2-53
Notebook Interface
cannot be wrapped to the default notebook window size without inserting a line break inside the number:
The line break symbol does not affect the result of computation. If you copy the result to an input region, the line break symbol does not appear in the copy. When you resize a notebook, MuPAD automatically adjusts output lines to a new window size. If a new window is large enough to accommodate the output in one line, the line break symbols disappear. They also disappear when you disable wrapping and reevaluate the corresponding input region. To disable wrapping:
1 Select Format > Defaults. 2 In the resulting dialog box, click the Calculations tab. 3 From the drop-down menu Format, select Output Math. 4 Select the Wrap lines check box.
2-54
If you disable wrapping, MuPAD does not insert lines breaks in the new output expressions. If you want to remove line breaks in the existing output expressions, reevaluate these expressions.
2-55
Notebook Interface
2-56
specify the commands you want to run without displaying in the notebook. Alternatively, attach an existing file containing the commands.
2-57
Notebook Interface
B Attach an existing file with the MuPAD script that you want to execute invisibly at the notebook startup. C Type the commands that you want to execute invisibly at the notebook startup.
3 Save the notebook. MuPAD saves the hidden code with the notebook. This
code does not affect other notebooks. If you want to use hidden code for all notebooks, see Adding Hidden Startup Commands to All Notebooks. To execute the commands you entered, restart the notebook engine. To restart an engine you can use one of the following methods: Select Notebook>Disconnect, and then Notebook>Start Engine. Close the notebook and reopen it. After you restart an engine, you can access all the objects defined in the Notebook Properties dialog box from your notebook.
2-58
2-59
Notebook Interface
2-60
Note Graphics size does not change. To change graphics size, see Scaling Graphics.
To undo font size changes, select Edit>Undo or use the toolbar button
2-61
Notebook Interface
Note Using the opposite option (such as increasing the fonts you have decreased before) does not guarantee to restore the original font size.
2-62
Scale Graphics
Scale Graphics
To resize your graphics, right-click the graphics and select Graphics Size.
In the Graphics Size dialog box, set the height and width of the graphics. The option Keep Aspect Ratio lets you conserve the height to width ratio.
2-63
Notebook Interface
2-64
2-65
Notebook Interface
When you print directly from Print Preview, you can select and print specific pages. To print a particular page:
1 Open Print Preview. 2 Click the Print button in the Print Preview toolbar. 3 In the resulting dialog box, click the Pages option under Page Range. 4 Type the number of the page you want to print. To specify a range of
pages, use a hyphen. For example, to print the second, third, and fourth pages, type 2-4. If your document is wide and does not fit the page, use the Print Preview toolbar to adjust the document before printing. When you print a wide document from the Print Preview window, MuPAD does not prompt you to scale your document down. MuPAD prints documents exactly as you see them in the Print Preview window.
2-66
PDF files created with the Save as PDF button are not editable. To create editable PDF files, click the Print button and try using a PDF printer available for your system. Note If a MuPAD document has links, these links are replaced by regular text in the resulting PDF file.
A Indicates the current page number. Use this field to jump to a particular page. Click the appropriate arrow to display the previous or the next page. B Lets you zoom in and out on a page. C Displays the current zoom factor. Use this field to zoom in or out by a fixed percentage. The drop-down menu lets you quickly select one of the commonly used zoom factors. D Fits the page to the Print Preview window. The button adjusts the document so the width of the page matches the width of the Print Preview adjusts the document so that an entire page fits in window. The button the Print Preview window. If you display two pages side-by-side, the Fit buttons adjust the document so that both pages fit in the window. E Scales the document so that all objects including graphics and calculation regions fit in the page width. F Selects page orientation. Lets you choose portrait or landscape layout.
2-67
Notebook Interface
G Opens the Page Format dialog box for adjusting page settings. When you modify settings in the Format dialog box, MuPAD applies the new settings not only to a preview, but also to the notebook itself. If later you close the Print Preview window and save the notebook, MuPAD saves the new page settings with the notebook. See Changing Page Settings for Printing for details. H Lets you view multiple pages in the Print Preview window.
The option Show facing pages displays even pages on the left and odd pages on the right. If you select this option to display a document with multiple pages, the first page appears in the top-right corner.
2-68
MuPAD saves your page settings with a notebook. These settings do not affect other existing or new notebooks.
2-69
Notebook Interface
Also, you can change the page format. When you print a wide document from the Print Preview window, the above dialog box does not appear. Use the Print Preview toolbar to adjust the document before printing. MuPAD prints documents exactly as you see them in the Print Preview window.
2-70
3
Mathematics
Evaluations in Symbolic Computations on page 3-5 Level of Evaluation on page 3-8 Enforce Evaluation on page 3-17 Prevent Evaluation on page 3-20 Actual and Displayed Results of Evaluations on page 3-22 Evaluate at a Point on page 3-24 Choose a Solver on page 3-26 Solve Algebraic Equations and Inequalities on page 3-29 Solve Algebraic Systems on page 3-35 Solve Ordinary Differential Equations and Systems on page 3-46 Test Results on page 3-58 If Results Look Too Complicated on page 3-64 If Results Differ from Expected on page 3-69 Solve Equations Numerically on page 3-76 Use General Simplification Functions on page 3-92 Choose Simplification Functions on page 3-96 If You Want to Simplify Results Further on page 3-106 Convert Expressions Involving Special Functions on page 3-111 When to Use Assumptions on page 3-117 Use Permanent Assumptions on page 3-119 Use Temporary Assumptions on page 3-126
Mathematics
Choose Differentiation Function on page 3-132 Differentiate Expressions on page 3-133 Differentiate Functions on page 3-135 Compute Indefinite Integrals on page 3-140 Compute Definite Integrals on page 3-143 Compute Multiple Integrals on page 3-146 Apply Standard Integration Methods Directly on page 3-148 Get Simpler Results on page 3-151 If an Integral Is Undefined on page 3-152 If MuPAD Cannot Compute an Integral on page 3-153 Compute Symbolic Sums on page 3-156 Approximate Sums Numerically on page 3-159 Compute Taylor Series for Univariate Expressions on page 3-161 Compute Taylor Series for Multivariate Expressions on page 3-165 Control Number of Terms in Series Expansions on page 3-166 O-term (The Landau Symbol) on page 3-169 Compute Generalized Series on page 3-170 Compute Bidirectional Limits on page 3-172 Compute Right and Left Limits on page 3-173 If Limits Do Not Exist on page 3-176 Create Matrices on page 3-178 Create Vectors on page 3-181 Create Special Matrices on page 3-182 Access and Modify Matrix Elements on page 3-184 Create Matrices over Particular Rings on page 3-186 Use Sparse and Dense Matrices on page 3-188 Compute with Matrices on page 3-190
3-2
Compute Determinants and Traces of Square Matrices on page 3-195 Invert Matrices on page 3-196 Transpose Matrices on page 3-197 Swap and Delete Rows and Columns on page 3-198 Compute Dimensions of a Matrix on page 3-200 Compute Reduced Row Echelon Form on page 3-201 Compute Rank of a Matrix on page 3-202 Compute Bases for Null Spaces of Matrices on page 3-203 Find Eigenvalues and Eigenvectors on page 3-204 Find Jordan Canonical Form of a Matrix on page 3-207 Compute Matrix Exponentials on page 3-210 Compute Cholesky Factorization on page 3-211 Compute LU Factorization on page 3-214 Compute QR Factorization on page 3-216 Compute Determinant Numerically on page 3-218 Compute Eigenvalues and Eigenvectors Numerically on page 3-222 Compute Factorizations Numerically on page 3-227 Mathematical Constants Available in MuPAD on page 3-236 Special Functions Available in MuPAD on page 3-239 Floating-Point Arguments and Function Sensitivity on page 3-243 Integral Transforms on page 3-251 Z-Transforms on page 3-259 Discrete Fourier Transforms on page 3-262 Use Custom Patterns for Transforms on page 3-267 Supported Distributions on page 3-270 Import Data on page 3-272 Store Statistical Data on page 3-276
3-3
Mathematics
Compute Measures of Central Tendency on page 3-277 Compute Measures of Dispersion on page 3-281 Compute Measures of Shape on page 3-283 Compute Covariance and Correlation on page 3-286 Handle Outliers on page 3-288 Bin Data on page 3-289 Create Scatter and List Plots on page 3-291 Create Bar Charts, Histograms, and Pie Charts on page 3-295 Create Box Plots on page 3-303 Create Quantile-Quantile Plots on page 3-305 Univariate Linear Regression on page 3-308 Univariate Nonlinear Regression on page 3-312 Multivariate Regression on page 3-315 Principles of Hypothesis Testing on page 3-318 Perform chi-square Test on page 3-319 Perform Kolmogorov-Smirnov Test on page 3-321 Perform Shapiro-Wilk Test on page 3-322 Perform t-Test on page 3-323 Divisors on page 3-324 Primes and Factorizations on page 3-327 Modular Arithmetic on page 3-331 Congruences on page 3-336 Sequences of Numbers on page 3-344
3-4
The variable y is an identifier, and the number 4 is the value of that identifier. Values of identifiers are not always numbers. For example, a value of an identifier can also contain identifiers. In the following assignment, y is an identifier, and the expression a + x is the value of that identifier: y := a + x
The value of y is a sum of two identifiers, a and x. You can assign a value to any of these identifiers. For example, assign the value 10 to the identifier a. Now, MuPAD recognizes that a is equal to 10. Therefore, the system evaluates the value a + x of the identifier y to the expression x + 10: a := 10: y
Note The value of an identifier is the value computed at the time of assignment. The value of the identifier y is still x + a. If you assign any other value to a, MuPAD evaluates y using this new value:
3-5
Mathematics
a := 15: y
Now, assign the value 10 to the identifier a, and then assign the expression x + a to y. As in the previous example, MuPAD evaluates the identifier y and returns the expression x + 10: a := 10: y := a + x: y
Although the evaluation returns the same result as in the previous example, the value of y is different. Here the value of y is the expression x + 10. This value does not depend of the identifier a: a := 15: y
For further computations, clear the identifiers a, x, and y: delete a, x, y The value of an identifier can be any MuPAD object. For example, the value of an identifier can be a list: list := [x^k $ k = 1..10]
If later you assign the value to x, the evaluation of the identifier list changes accordingly: x := 1/2: list
3-6
MuPAD applies the same evaluation mechanism to function names. For example, assign the function call f( ) to the identifier y: y := f(PI)
Now, assign the function sin to f. If you evaluate the identifier y, the system replaces the identifier f by its value sin. Then, the system evaluates the ) and returns 0: call sin( f := sin: y
) changes
delete f: y
3-7
Mathematics
Level of Evaluation
In this section... What Is an Evaluation Level? on page 3-8 Incomplete Evaluations on page 3-9 Control Evaluation Levels on page 3-12
The resulting expression x + 1 is the complete evaluation of y. The level function demonstrates each step of this recursive evaluation. The zero level of evaluation returns the identifier y itself: level(y, 0)
The first level accesses the value of the identifier, and returns that value: level(y, 1)
3-8
Level of Evaluation
When you evaluate y up to the second level, the system recognizes that the expression x + a contains identifiers, which can also have assigned values. When searching for these values, the system finds that the identifier a has the value 1, and the identifier x does not have an assigned value: level(y, 2)
In this example, MuPAD completely evaluates the identifier y by using just two evaluation steps. Evaluating y up to the third and higher levels returns the same expression: level(y, 3)
delete a, x, y
Incomplete Evaluations
MuPAD does not always evaluate identifiers completely. For some expressions, a complete evaluation requires a huge number of steps. To avoid very long or infinite evaluations, the system implements two environment variables, LEVEL and MAXLEVEL. These variables limit evaluation levels. If the current evaluation level exceeds the limitation set by one these variables, MuPAD stops the evaluation process before the system can replace all identifiers by their assigned values. The environment variable LEVEL limits evaluation levels to a specified value. It does not try to detect and prevent an infinite evaluation loop. For interactive computations, the default value of the environment variable LEVEL is: LEVEL
When the evaluation level reaches the value of LEVEL, MuPAD stops the evaluation and returns the result of the last computed evaluation step:
3-9
Mathematics
LEVEL := 10: x := x + 1: x
delete LEVEL, x MuPAD does not specify one uniform value of LEVEL for all computations. For most computations, the value is 100, but there are exceptions to this rule: If the evaluation occurs in a procedure, MuPAD limits the evaluation level to 1. If the evaluation occurs in a matrix, MuPAD limits the evaluation level to 1. MuPAD does not evaluate arrays, tables, and polynomials. (The evaluation level for these objects is 0.) MuPAD does not evaluate a returned value of the last() function call or its equivalent %. (The evaluation level is 0.) MuPAD does not evaluate returned values of some other system functions. For example, the system does not evaluate the results returned by the subs and text2expr functions. The help pages for such functions provide the information about the evaluation levels of the returned values. If the evaluation occurs in a function call level(expression, n), MuPAD disregards the environment value LEVEL. Instead, the system uses the evaluation level n. For example, although LEVEL = 100 by default, the function call level(a + x, 1) evaluates the expression a + x to the first evaluations level: a := b: b := 2: level(a + x, 1)
delete a, b, x
3-10
Level of Evaluation
For more examples of incomplete evaluations and information about enforcing such evaluations, see Enforcing Evaluation. To detect and prevent infinite loops, MuPAD implements another environment variable, MAXLEVEL. The default value of MAXLEVEL for all computations is MAXLEVEL
When evaluation level reaches the value of MAXLEVEL, MuPAD assumes that the evaluation is infinite and issues an error: MAXLEVEL := 2: a := b: b := c: c := d: a
delete MAXLEVEL, a, b, c, d If the value of MAXLEVEL is greater than the value of LEVEL, the global variable MAXLEVEL does not affect that evaluation. Otherwise, the value of MAXLEVEL limits the number of evaluation steps. For example, the default values of LEVEL and MAXLEVEL are equal (both values are 100). If an evaluation reaches the level 100, MuPAD uses the global variable MAXLEVEL and, therefore, issues an error: x := x + 1: x
delete x
3-11
Mathematics
3-12
Level of Evaluation
Since the default value of the environment value LEVEL = 100 is greater than 10, in interactive computations MuPAD returns the completely evaluated identifier x1: x[1]
Delete the identifiers xk: delete x Set the value of the environment variable LEVEL to 2: LEVEL := 2: Now, MuPAD evaluates the identifier x1 only up to the second level: (x[k] := (k + 1)*x[k + 1]) $ k = 1..9: x[10] := 10: x[1]
The new value of LEVEL affects all interactive evaluations, except for evaluations in arrays, matrices, tables, and polynomials. For example, use the following recursive definition for the identifiers a, b, and c. Evaluation of the identifier a proceeds only to the second level: a := b: b := c: c := 1: a
3-13
Mathematics
For further computations, delete the identifiers: delete x, a, b, c: The new value of LEVEL does not affect evaluations that happen in procedures. The evaluation level in procedures remains equal to 1. For example, create the procedure myProc that defines the values of the identifiers a, b, and c recursively: myProc:= proc(d) begin a := b: b := c: c := d: a end_proc: The procedure evaluates the identifier a up to the first evaluation level: myProc(10)
delete a, b, c, d: You can change the evaluation level inside a particular procedure. This change does not affect evaluations occuring in other procedures or inside interactive computations: myProc:= proc(d) begin LEVEL := 3: a := b: b := c: c := d: a end_proc: myProc(10)
For further computations, delete the identifiers and restore the value of LEVEL to its default: delete a, b, c, d:
3-14
Level of Evaluation
delete LEVEL: Another environment variable, MAXLEVEL enables the system to detect and interrupt infinite evaluation loops. The default value of this variable is 100. This value is recommended for most computations. If your code has recursive evaluations that require more than 99 steps, change the value of MAXLEVEL. For example, the following definition of the identifier x1 requires 111 evaluation steps. MuPAD issues an error because the system cannot evaluate x1 in 99 steps and assumes that the evaluation loop is infinite: (x[k] := (k + 1)*x[k + 1]) $ k = 1..110: x[111] := 1: x[1]
delete x To avoid the error, the value of MAXLEVEL must exceed the number of required evaluation steps at least by 1. Changing the value to 112 resolves the error. Now, MuPAD evaluates the identifier x1 to the 100th evaluation level, which is the default value of the environment variable LEVEL: MAXLEVEL:= 112: (x[k] := (k + 1)*x[k + 1]) $ k = 1..110: x[111] := 1: x[1]
delete x
3-15
Mathematics
To evaluate x1 to the 111th evaluation level, you must change both LEVEL and MAXLEVEL variables. Also, you can use the level function instead of changing the value of LEVEL: MAXLEVEL:= 112: (x[k] := (k + 1)*x[k + 1]) $ k = 1..110: x[111] := 1: level(x[1], 111)
Increase the value of MAXLEVEL only when you know that your code requires it. Do not increase this value for computations where you can avoid it. If your code has infinite loops, the increased level of MAXLEVEL can significantly decrease performance. Always restore the default value for further computations: delete x, MAXLEVEL
3-16
Enforce Evaluation
Enforce Evaluation
MuPAD automatically evaluates results returned by most of the system functions. However, a few functions can return unevaluated results. For example, the text2expr function does not evaluate the returned results: text2expr("2 + 2")
The last function and its shortcut %, which return the previously computed object, also do not evaluate the results: %
For such cases, MuPAD provides the eval function. This function enables you to enforce evaluation of an expression. For example, enforce evaluation of the previously returned expression: eval(%);
Another example of the function that does not automatically evaluate returned results is the subs function. This function can simplify expressions that contain only purely arithmetical operations: subs(x^2 + 1, x = 0)
However, the subs function does not evaluate expressions. For example, substitute the variable x with the value 0 in the following expression that contains the sine function:
3-17
Mathematics
subs(sin(x^2) + 1, x = 0)
You can use the eval function to enforce evaluation of the results returned by subs. In this case, MuPAD evaluates the whole expression: eval(%)
Alternatively, the subs function provides a more efficient method to evaluate its results. The EvalChanges option enforces evaluation of the modified parts of the expression, leaving the unchanged parts out of the evaluation process: subs(sin(x^2) + 1, x = 0, EvalChanges)
Most efficiently, evaluate an expression at a particular value of a variable by using the evalAt function. See Evaluation at a Point. Also, MuPAD does not evaluate arrays, tables, and polynomials. For example, the system does not evaluate the identifiers a and b of the following array A: A := array(1..2, [a, b]): b := 2*a: a := 1: A
When you access the entries of the array A by using the op function, the system does not evaluate the entries of A. When you use the indexed access, the system evaluates the entries of arrays, matrices and tables: op(A, 1), op(A, 2); A[1], A[2]
3-18
Enforce Evaluation
To evaluate all entries of an array, a table, or a polynomial apply the eval function to that array, table, or polynomial. Use the map function to apply eval to an array or a table: map(A, eval)
For polynomials, use the mapcoeffs function: p := poly(c*x, [x]): c := 10: mapcoeffs(p, eval)
delete a, b, c:
3-19
Mathematics
Prevent Evaluation
When you perform interactive computations in MuPAD, the system tries to evaluate all expressions before returning them. For example, if the system can compute an integral, it returns the evaluated result. In most cases, the result is also simplified: int(x^2*sin(x), x)
The hold command enables you to prevent the evaluation of a MuPAD object. For example, hold lets you display the integral in its symbolic form: hold(int)(x^2*sin(x), x) = int(x^2*sin(x), x)
Also, you can prevent evaluation of an object by using the level function with the second argument 0. When you use level to prevent evaluation of identifiers, the results are equivalent to the results obtained with the hold function: level(int(x^2*sin(x), x), 0)
The level function only prevents evaluation of identifiers. If you create a function without a name, for example , level does not prevent evaluation of that function: level((x -> sin(x))(PI), 0)
3-20
Prevent Evaluation
In this case, use the hold function to prevent evaluation. For example, hold successfully prevents evaluation of the function at the point x = : hold((x -> sin(x))(PI))
Both hold and level functions prevent the evaluation of an object only in the particular computation in which you explicitly use them. These functions do not prevent further evaluations. For example, if you assign an expression containing hold to a variable, and then call that variable, MuPAD evaluates the expression: y := hold(int)(x^2*sin(x), x); y
3-21
Mathematics
MuPAD also suppresses intermediate results obtained within loops and procedures. For example, the evaluation of the following for loop returns five numbers. However, the output contains only the final result: for x from 1 to 5 do hold(_power)(x, 2) = x^2 end_for
To display intermediate results obtained in loops and procedures, use the print function inside a loop or a procedure. For example, to display all five numbers obtained in the for loop, enter: for x from 1 to 5 do print(hold(_power)(x, 2) = x^2) end_for
3-22
Alternatively, use the fprint function. This function typically writes results to a file indicated by one of the arguments of fprint. When this argument is 0, the function displays the results on screen: for x from 1 to 5 do fprint(Unquoted, 0, hold(_power)(x, 2) = x^2); end_for 1^2 = 1 2^2 = 4 3^2 = 9 4^2 = 16 5^2 = 25 The print and fprint functions display outputs differently. The print function uses the typeset mode, which is how mathematical expressions are typically written on paper. The fprint function uses the ASCII format. For information about different output modes available in MuPAD, see Using Different Output Modes.
3-23
Mathematics
Evaluate at a Point
To evaluate an expression for particular values of identifiers, use the evalAt function or its shortcut |. For example, evaluate the following expression at the point x = 0: diff(x^2*exp(sin(x)), x $ 3) | x = 0
In MuPAD, all computations are symbolic by default. For example, evaluating the previous expression at x = 1 returns the exact symbolic result: diff(x^2*exp(sin(x)), x $ 3) | x = 1
To get a numeric approximation of the result, use the floating-point number to specify the point at which you want to evaluate an expression: diff(x^2*exp(sin(x)), x $ 3) | x = 1.0
Alternatively, you can evaluate an expression at a point by using the subs function with the EvalChanges option. For expressions that contain only free variables, evalAt and subs return identical results: diff(sin(x)*cos(x^2), x $ 2) | x = PI, subs(diff(sin(x)*cos(x^2), x $ 2), x = PI, EvalChanges)
evalAt and subs return different results for the expressions that contain dependent variables. The subs function does not distinguish between free and
dependent variables. The function replaces both free and dependent variables with the new value, for example:
3-24
Evaluate at a Point
3-25
Mathematics
Choose a Solver
The general solvers (solve for symbolic solutions and numeric::solve for numeric approximations) handle a wide variety of equations, inequalities, and systems. When you use the general solver, MuPAD identifies the equation or the system as one of the types listed in the table that follows. Then the system calls the appropriate solver for that type. If you know the type of the equation or system you want to solve, directly calling the special solver is more efficient. When you call special solvers, MuPAD skips trying other solvers. Direct calls to the special solvers can help you to: Improve performance of your code Sometimes get a result where the general solver fails The following table lists the types of equations and systems for which MuPAD offers special solvers. The solve and numeric::solve commands also handle these types of equations and systems (except systems presented in a matrix form). Define ordinary differential equations with the ode command before calling the general solver. Symbolic Solvers
linsolve
Equation Type General system of linear equations General system of linear equations given in a matrix form System of linear equations given in , where A is a a matrix form Vandermonde matrix. For example:
Numeric Solvers
numeric::linsolve
linalg::matlinsolve numeric::matlinsolve
linalg::vandermondeSolve
3-26
Choose a Solver
Equation Type
Symbolic Solvers
Numeric Solvers
. See linalg::vandermonde for the definition and details. System of linear equations given in , where A is a a matrix form Toeplitz matrix. For example:
linalg::toeplitzSolve
. See linalg::toeplitz for the definition and details. System of linear equations given . The in a matrix form lower triangular matrix L and the upper triangular matrix U form an LU-decomposition.
linalg::matlinsolveLU
3-27
Mathematics
Equation Type Univariate polynomial equation. Call these functions to isolate the intervals containing real roots. Bivariate polynomial equation for which the general solver returns RootOf. Try calling solve with the option MaxDegree. If the option does not help to get an explicit solution, compute the series expansion of the solution. Expand the solution around the point where one of the variables is 0. System of polynomial equations Arbitrary univariate equation System of arbitrary equations Ordinary differential equation or a system of ODEs Ordinary differential equation or a system of ODEs. Call this function to get a procedure representing the numeric results instead of getting the numeric approximation itself. Ordinary differential equations on homogeneous manifolds embedded in the space of nm matrices. Linear congruence equation Quadratic congruence equation Polynomial equation. Call this function to find modular roots.
Symbolic Solvers
Numeric Solvers
numeric::odesolveGeometric
3-28
3-29
Mathematics
If your equation contains symbolic parameters, specify the variable for which you want to solve the equation: solve(a*x^2 + b*x + c, x)
If you solve an equation with symbolic parameters and do not specify the variable, solve uses all parameters as variables and returns a set of all possible solutions. For example, solving the following equation the solver assumes that both x and y are free variables. when returning all possible solutions for this equation, the solver uses an arbitrary parameter z: solve(x^3 + y^3)
To specify more than one variable, provide a list of variables as a second argument: solve(a*x^2 + b*x + c, [a, b, c])
3-30
solve also can return an expression as x in S, where x is a list of variables for which you solve an equation, and S is a set of the solution vectors:
solve(a*x + 1/x)
To get an explicit solution for such equations, try calling the solver with the option MaxDegree. The option specifies the maximal degree of polynomials for which the solver tries to return explicit solutions. By default, MaxDegree=2. Increasing this value, you can get explicit solutions for higher-order polynomials. For example, specify MaxDegree=3 and get explicit solutions instead of RootOf for the third-order polynomial: solve(x^3 + 2*x + 1 = 0, x, MaxDegree = 3)
3-31
Mathematics
When you solve a fifth- or higher-order polynomial equation, the solver might be unable to return the solution explicitly, even with the option MaxDegree: solve(x^5 + 2*x + 1 = 0, x); solve(x^5 + 2*x + 1 = 0, x, MaxDegree = 5)
In general, there are no explicit expressions for the roots of polynomials of degrees higher than 4. Setting the option MaxDegree to 4 or a higher value makes no difference.
RootOf symbolically represents the set of the roots of a polynomial. You can use the expressions containing RootOf in your further computations. For example, find the sum over all roots of the polynomial:
To get the numeric approximation of the roots, use the float command:
3-32
float(RootOf(X^4 + X + 1, X))
For more details on numeric approximations, see Solving Equations Numerically. For univariate polynomial equations, MuPAD also can compute intervals containing the real roots. See Isolating Real Roots of Polynomial Equations.
The solver does not display multiple roots because it returns results as a set. A set in MuPAD cannot contain duplicate elements. To obtain polynomial roots with their multiplicities, use the option Multiple: solve(x^2 - 6*x + 9 = 0, x, Multiple); solve((x - 1)^3*(x - 2)^7, x, Multiple)
3-33
Mathematics
solve(p, x)
If you prefer a solution in a form other than RootOf and want to avoid numeric methods, use polylib::realroots to find all intervals containing real solutions: p:= x^5 - 31*x^4/32 + 32*x^3/33 - 33*x^2/34 - 34*x/35 + 35/36: polylib::realroots(p)
3-34
The function linsolve returns a list of solutions: linsolve([x + y = 1, 3*x - 2*y = 5], [x, y])
If there are more unknowns than independent equations in a system, linsolve solves the system for the first unknowns: linsolve([x + y = a, 3*x - 2*y = b], [x, y, a, b])
Providing the unknowns in different order affects the solution: linsolve([x + y = a, 3*x - 2*y = b], [a, b, x, y])
3-35
Mathematics
containing the right sides of the equations. . When solving a system in . The solver returns .
a matrix form, you provide a matrix A and a vector the solutions of the system as a vector
The dimensions m n of the coefficient matrix define the following types of linear systems.
m = n
Square system
If the determinant of A is not a zero, a unique solution of the system exists. Otherwise, the system has either infinitely many solutions or no solutions. The system includes more equations than variables. The system can have one solution, infinitely many solutions, or no solutions.
m > n m < n
Overdetermined system
Underdetermined The system includes more variables than system equations. The system has either infinitely many solutions or no solutions.
To solve a linear system in a matrix form, use the linalg::matlinsolve command. For example, solve the following system of linear equations: eqn1 := 2*x + 3*y = 4: eqn2 := 3*x - 2*y = 1:
3-36
To convert the system to a matrix form, use the matrix command to create a matrix of coefficients and a vector containing right sides of equations: A := matrix([[2, 3],[3, -2]]); b := matrix([4, 1])
As a shortcut for converting a system of linear equations to a matrix form, use linalg::expr2Matrix: Ab := linalg::expr2Matrix([eqn1, eqn2], [x,y])
Alternatively, split the matrix Ab into a matrix of coefficients A and a vector b containing the right sides of equations. Use linalg::matlinsolve to solve the system: A := Ab[1..2, 1..2]: b := Ab[1..2, 3..3]: linalg::matlinsolve(A, b)
3-37
Mathematics
If your linear system is originally defined by a matrix equation, using the matrix form to solve the system is more intuitive. Also, the matrix form is convenient for solving equations with many variables because it avoids creating symbols for these variables. For example, the following matrices define a linear system: A := linalg::hilbert(10); b := matrix([i^(-2) $ i = 1..10])
3-38
3-39
Mathematics
Specialized Matrices
If your system of linear equations can be presented as a specialized matrix, you can solve the system by calling a special solver. Direct calls to the special solvers often improve the performance of your code. MuPAD offers special solvers for linear systems that can be represented by matrices of the following types: A matrix given by , where L is a lower triangular matrix, and U is an upper triangular matrix (LU-decomposition of a matrix) Toeplitz matrix. For example, the following matrix is a Toeplitz matrix:
3-40
. See linalg::toeplitz for the definition and details. Vandermonde matrix. For example, the following matrix is a Vandermonde matrix::
. See linalg::vandermonde for the definition and details. Suppose you want to solve the following system given by a Toeplitz matrix. Use linalg::toeplitz to define the system: T := linalg::toeplitz(3, [0, 2, 5, 3, 0])
3-41
Mathematics
To solve a system given by a Toeplitz matrix, use the linalg::toeplitzSolve special solver. This special solver is more efficient than linalg::matlinsolve. This solver accepts a vector or a list of diagonal elements t of a Toeplitz matrix instead of a Toeplitz matrix itself: t := [0, 2, 5, 3, 0]: x := linalg::toeplitzSolve(t, y)
For the list of special solvers available in MuPAD, see Choosing Solver. For information on linear algebra functions, see Linear Algebra.
Nonlinear Systems
To solve a system of nonlinear equations symbolically, use the general solver. For example, solve the following system of trigonometric equations: solve({4*cos(x) + 2*cos(y) = 3, 2*sin(x) + sin(y) = 1}, [x, y])
3-42
When you use the VectorFormat option, the solver returns the solutions as a set of vectors. If you want the solver to return one solution from the set, use the PrincipalValue option. When you use PrincipalValue, the solver still returns a set, although that set contains only one solution: solve({4*cos(x) + 2*cos(y) = 3, 2*sin(x) + sin(y) = 1}, [x, y], VectorFormat, PrincipalValue)
You can also approximate the exact symbolic solution numerically: float(%)
3-43
Mathematics
If solve cannot compute explicit solutions for a system, use numeric methods to approximate the solutions. For nonlinear systems, MuPAD offers the following special solvers: For a system of polynomial equations, use numeric::polysysroots. For an arbitrary system of equations, use numeric::fsolve.
To approximate the solutions of the system of polynomial equations numerically, use the special solver numeric::polysysroots: numeric::polysysroots({eqn1, eqn2}, [x, y])
3-44
The general solver cannot find a symbolic solution: solve({eqn1, eqn2}, [a, b])
For numeric approximations of the solutions of the nonlinear system of equations, use the numeric::fsolve. The numeric solver returns only one solution: numeric::fsolve({eqn1, eqn2}, [a, b])
Note When numeric::fsolve finds one solution, it stops looking for other solutions. When you solve an arbitrary nonlinear system numerically, there is no general way to find all solutions. For more information, see Solving Equations Numerically.
3-45
Mathematics
General Solutions
An ordinary differential equation (ODE) contains derivatives of dependent variables with respect to the only independent variable. If y is a dependent variable and x is an independent variable, the solution of an ODE is an expression y(x). The order of the derivative of a dependent variable defines the order of an ODE. The solution of a single explicit first-order ODE can always be computed by integration, provided the solution exists. To define an ordinary differential equation, use the ode command: o := ode(y'(x) = y(x)^2, y(x))
Note ode does not accept multivariate expressions such as y(x, t). It also does not accept piecewise expressions. Now use the general solve to solve this equation: solve(o)
3-46
Alternatively, you can call the ODE solver directly: ode::solve(y'(x) = y(x)^2, y(x))
The general solutions of ODEs contain arbitrary constants of integration. The solver generates the constants of integration using the format of an uppercase letter C followed by an automatically generated number. For example, it generates C1, C2, and so on. For higher-order ODEs, you can find explicit solutions only for special types of equations. For example, the following second-order equation has a solution in terms of elementary functions: ode::solve(y''(x) = y(x), y(x))
The solver introduces the solution of the following equation in terms of the Bessel functions. MuPAD uses standard mathematical notations for Bessel and other special functions: ode::solve(y''(x) = y'(x) + y(x)*exp(x), y(x))
If you have a second- or higher-order ODE, nonlinear ODE, or a system of ODEs, a symbolic solution does not always exist: ode::solve(y''(x) = y'(x)^2 + y(x)*exp(x), y(x))
3-47
Mathematics
For ODEs that cannot be solved symbolically, try using numeric solvers.
When you solve an ODE with initial or boundary conditions, the solver adjusts the integration constants to fit these conditions: solve(IVP)
The following equation has both initial and boundary conditions: ode::solve({y'''(x) = y(x), y(0) = 0, y(5) = 1, y'(0) = 0}, y(x))
3-48
Each independent condition removes one integration constant: ode::solve({y'''(x) = y'(x)}, y(x))
The solver recognizes the type of the equation and applies the algorithm for solving Clairaut equations. To improve performance, call the solver with the option Type = Clairaut:
3-49
Mathematics
The solver tries to recognize and tries to solve the following classes of ODEs. Type Abel differential equation Bernoulli differential equation Chini differential equation Clairaut differential equation Exact first-order ordinary differential equation that can be represented as M(x, y)dx + N(x, y)dy = 0 where where n 0 and n 1 Chini Clairaut ExactFirstOrder Equation ODE Solver Option Abel Bernoulli
Exact second-order ordinary differential equation Linear homogeneous ordinary differential equation Lagrange differential equation Riccati differential equation
Homogeneous
3-50
If the solver cannot identify the equation with the type you indicated, it issues a warning and returns the special value FAIL: ode::solve(y'(x) + y(x) = x, y(x), Type = Homogeneous)
Now, suppose the system of differential equations appears in a matrix form. , where A, B, and Y represent For example, define the system the following matrices: Y:= matrix([x(t), y(t)]):
3-51
Mathematics
A:= matrix([[1, 2], [-1, 1]]): B:= matrix([1, t]): The ode::solve function does not accept matrices. To be able to use this solver, extract the components of the matrix and include them in a set. Use the op function to extract the equations from the matrix. Then, use the braces to create a set of the equations. You can omit the right sides of equations, in which case MuPAD assumes them to be 0: s := {op(diff(Y, t) - A*Y - B)}
Now, specify the set of functions {x(t), y(t)} for which you want to solve the system. Solve the system: ode::solve(s, {x(t), y(t)})
If you are solving several similar systems of ordinary differential equations in a matrix form, create your own solver for these systems, and then use it as a shortcut. The solver for such systems must be a function that accepts matrices as input arguments, and then performs all required steps. For example, create a solver for a system of the first-order linear differential , where the components of functions equations in a matrix form depend on the variable t:
3-52
solveLinearSystem := (A, B, Y) -> solve(ode({op(diff(Y, t) - A*Y - B)}, {op(Y)})): The solveLinearSystem function accepts matrices as input parameters, creates a matrix of equations, extracts these equations to a set, and solves the system: Y:= matrix([x(t), y(t)]): A:= matrix([[1, 2], [-3, 1]]): B:= matrix([2, t]): solveLinearSystem(A, B, Y)
The plotting functions in MuPAD do not accept sets. To plot the solution, access the elements of a solution set using square brackets or the op command: plotfunc2d(f[1], x = -3..3)
3-53
Mathematics
If you have more than one element of a solution set, you can access a particular element. For example, pick the second element of the solution set for the system of ODEs: f := ode::solve( {y'(x) = z(x), z'(x) = y(x) + 2*z(x), y(0) = 0, z(0) = 1}, {y(x), z(x)})
3-54
The solver returns results for a system as a set that contains a list. To open the set and access the list, use square brackets or the op command. To access a particular entry of this list, use square brackets: f[1][2]; op(f)[2]
To access the right side of the equation, use square brackets or the rhs command: f[1][2][2]; rhs(f[1][2])
3-55
Mathematics
To plot a solution of the system of ODEs in 3-D, use the plot::Curve3d command: solution := plot::Curve3d([x, f[1][2][2], f[1][1][2]], x = -2..2, GridVisible): plot(solution)
3-56
MuPAD provides the functions plot::Ode2d and plot::Ode3d for visualizing solutions of ODEs. Also, you can plot a vector field associated with an ODE. For all graphic capabilities available in MuPAD, see Graphics and Animations.
3-57
Mathematics
Test Results
In this section... Solutions Given in the Form of Equations on page 3-58 Solutions Given as Memberships on page 3-60 Solutions Obtained with IgnoreAnalyticConstraints on page 3-62
To verify the correctness of the returned solutions, substitute the solutions into the original equation. To substitute the results given in the form of equations, evaluate the original equations at the solution points. Use evalAt or the vertical bar | as a shortcut. For the first solution, the command returns the identity: equation | solution[1]
To check that the left side of the equation is equal to the right side, use the testeq command: testeq(equation | solution[1])
3-58
Test Results
For the second solution, evalAt returns an equation with an unsimplified left side. In many cases, MuPAD does not automatically simplify expressions, for example: equation | solution[2];
testeq(equation | solution[2])
As an alternative to evaluating at a point, use the subs command to substitute the solution into the original equation: equation := x^3 + 4 = 0: solution := solve(equation); testeq(subs(equation, solution[1])); testeq(subs(equation, solution[2])); testeq(subs(equation, solution[3]))
To verify the solutions of a system of equations, test each equation separately: equations := {x^2 + 2*y = 3, 4*x^2 + 5*y = 6}:
3-59
Mathematics
To verify the results, evaluate the original equation at the solution points. Evaluating at a point requires a solution to be in the form of an equation. If you have a solution in the form of membership, evalAt returns an error: equation | op(solution)
3-60
Test Results
You cannot use the expression x = solution directly because solution is represented by a set. This set contains the solution for the variable x, the independent variable k, and the condition on the variable k: op(solution)
Extract the solution for x, the variable k, and the conditions on the variable k from the set. MuPAD returns the variable k and its conditions as lists. Use the additional square brackets to extract k and the conditions from the lists: op(solution)[1]; op(solution)[2][1]; op(solution)[3][1]
Now evaluate the original equation at the solution points x = k under the conditions for k: testeq(equation | x = op(solution)[1]) assuming op(solution)[2][1] in op(solution)[3][1]
Alternatively, use the subs command to substitute the solution into the original equation: testeq(subs(equation, x = op(solution)[1])) assuming op(solution)[2][1] in op(solution)[3][1]
3-61
Mathematics
When you solve an equation, inequality or a system using the IgnoreAnalyticConstraints option, the solver uses an additional set of simplified mathematical rules. These rules intentionally trade off mathematical strictness and correctness for simplicity of the results. Although this option often leads to the most practical and expected results, it also can lead to incorrect results. For the set of rules IgnoreAnalyticConstraints applies, see the help page of the solve command. To verify such solutions, try using the same IgnoreAnalyticConstraints option for testeq. When you use this option, the testeq command does not guarantee that the solutions are correct everywhere on the complex plane. The command checks that the solutions are correct for the values of the parameters for which the rules applied by IgnoreAnalyticConstraints are valid: testeq(subs(equation, x = solutions[1]), IgnoreAnalyticConstraints); testeq(subs(equation, x = solutions[2]),
3-62
Test Results
IgnoreAnalyticConstraints)
The testeq command did not verify both solutions. When trying to prove the equivalence of two expressions, testeq runs random tests before applying IgnoreAnalyticConstraints. If tests for random values of identifiers show that expressions are not equivalent, testeq disregards the IgnoreAnalyticConstraints option and returns FALSE. To suppress running random tests, set the number of these tests to zero: testeq(subs(equation, x = solutions[2]), NumberOfRandomTests = 0, IgnoreAnalyticConstraints)
Verifying numeric results returned by the solver using IgnoreAnalyticConstraints does not require using the same option. Substitute numeric results into the original equations and call testeq to prove equivalence of the expressions on both sides of the equations: equation := x^(11/2) = 1: solution := solve(equation, IgnoreAnalyticConstraints); testeq(equation | solution[1])
3-63
Mathematics
If you need a solution in real numbers, use the Real option. The only real solution of this equation is 1: solve(x^5 - 1, x, Real)
3-64
For the following standard quadratic equation, the solver returns the solutions for all possible values of symbolic parameters a, b, and c: solve(a*x^2 + b*x + c, x)
To disregard special cases, use the IgnoreSpecialCases option: solve(a*x^2 + b*x + c, x, IgnoreSpecialCases)
For the following equation, the solver returns a complete, but rather long and complicated solution: solve(x^(5/2) + 1/x^(5/2) = 1, x)
3-65
Mathematics
If you want a simpler and more practical solution, try the IgnoreAnalyticConstraints option. With this option, the solver uses a set of simplified mathematical rules that are not generally correct. The returned solutions tend to be most useful for many problems in engineering and physics. Note that with this option the solver does not guarantee the correctness and completeness of the result: solve(x^(5/2) + 1/x^(5/2) = 1, x, IgnoreAnalyticConstraints)
See the list of the options accepted by the general solver solve.
3-66
the assuming command to temporarily assume that x is a positive number. Under this assumption, the solver returns four positive solutions: solve(x^7 + 2*x^6 - 59*x^5 - 106*x^4 + 478*x^3 + 284*x^2 - 1400*x + 800, x) assuming x > 0
Without the assumption, the solver returns all seven solutions: solve(x^7 + 2*x^6 - 59*x^5 - 106*x^4 + 478*x^3 + 284*x^2 - 1400*x + 800, x)
To make several assumptions, combine them with and: solve([a*x + b*y = c, h*x - g*y = f], [x, y]) assuming f = c and a = h and a <> 0
{ { -f + g z { { | x = -------, y = z { { -h { { { -f -{ { | x = -, y = 0 | { { -h --
-- } | } -- } } } }
if
b + g = 0
if
b + g <> 0
Simplify Solutions
While solving equations, MuPAD automatically simplifies many objects such as some function calls and arithmetical expressions with numbers. Automatic
3-67
Mathematics
simplifications reduce the complexity of expressions used in intermediate steps, which improves performance of the solvers. MuPAD solvers do not call the simplification functions for final results. When you call the solve command, you can get a long and complicated solution: S:= solve(ln(1/x) + ln(5) = 1/x + ln(3), x)
To simplify such results, use simplify or Simplify. The simplify function is faster: simplify(S)
Simplify(S)
3-68
For the same equation, MuPAD 5.2 (R2009a) returns: solution := solve(eq): eval(solution) assuming a <> 0
3-69
Mathematics
Note testeq cannot compare sets. To test mathematical equality of the solutions returned as sets, compare each pair of the solutions individually. If a returned solution differs from what you expect, test mathematical equality of the solutions: testeq(cos(a*t), (1/exp(a*t*I))/2 + exp(a*t*I)/2)
If you explicitly specify the type as Bernoulli, the solver returns another form of the result: o2 := solve(o, Type = Bernoulli)
3-70
Check the equality of these two solutions by calling the testeq command for each pair of the solutions. Remember that testeq cannot compare sets. testeq(o1[1], o2[1]), testeq(o1[2], o2[2])
The second solution returns FALSE because testeq does not know that C2 and C3 are arbitrary constants. When you explicitly assume the equality of the constants, testeq confirms that the solutions are mathematically equal: testeq(o1[1], o2[1]) assuming C2 = C3, testeq(o1[2], o2[2]) assuming C2 = C3
3-71
Mathematics
Specifying the type of the same ordinary differential equation as Riccati gives you two separate solutions: M := solve(o, Type = Riccati)
When you specify the equation type as Riccati, the solver returns a more general result. This result combines the second and third elements of the set returned for the Chini type. The additional solution for the Chini equation appears at a particular value of the integration constant for the Riccati equation. Find the value of the constant at which the more general solution for the Riccati equation turns to the second solution for the Chini equation: solve(L[2] = M[2], C5)
Use evalAt to verify that if the integration constant is 0, the solution for Riccati equation gives the additional solution that you see for Chini type: evalAt(M[2], C5 = 0)
You can find the dependency between the constants in the solutions returned for Riccati and Chini types. As a first step, rewrite the results using similar
3-72
terms. For example, rewrite the expression with exponents in terms of tangents: m2 := rewrite(M[2], tan)
Now if you want to verify that the two forms of the solution are equivalent, substitute the constant in Riccati solution with this expression. For more information on testing mathematical equivalence of the solutions, see Testing Results.
3-73
Mathematics
>> solve(a*x + b = y) ans = -(b - y)/a MuPAD returns the complete set of solutions accounting for all possible values of the symbolic parameters a, b, and y: solve(a*x + b = y, x)
Solving the equation in MuPAD with the IgnoreSpecialCases option, you get the same short result as in the MATLAB Command Window: solve(a*x + b = y, x, IgnoreSpecialCases)
3-74
To get one element of the solution set, use the solvelib::getElement command: solvelib::getElement(S)
If you want the solver to return just one solution, use the PrincipalValue option: S := solve(sin(x), x, PrincipalValue)
PrincipalValue can help you shorten the results omitting all solutions,
except one. The option does not allow you to select a particular solution.
3-75
Mathematics
3-76
If you have a symbolic solution that you want to approximate numerically, use the float command: float(%)
Use float to approximate the solutions of the symbolic system: float(solve([x^3 + x^2 + 2*x = y, y^2 = x^2], [x, y]))
Approximating symbolic solutions numerically, you get the complete set of solutions. For example, solve the following equation symbolically: S := solve(sin(x^2) = 1/2, x)
Suppose, you want to get numeric results instead of expressions containing PI. The float command returns the infinite solution set: float(S)
3-77
Mathematics
When called with the option AllRealRoots, the solver omits all complex roots. For example, when you symbolically solve the polynomial equation and approximate the solutions, you get all solutions: numeric::solve(4*x^4 + 3*x^3 + 2*x^2 + x -1 = 0, x)
To limit the solution set to the real solutions only, use the option AllRealRoots: numeric::solve(4*x^4 + 3*x^3 + 2*x^2 + x - 1 = 0, x, AllRealRoots)
3-78
Using numeric::solve, you also can solve a system of polynomial equations: numeric::solve([x^3 + 2*x = y, y^2 = x], [x, y])
To solve linear systems numerically, use the numeric::linsolve command. For example, solve the following system symbolically and numerically: linsolve([x = y - 1, x + y = 5/2], [x, y]); numeric::linsolve([x = y - 1, x + y = 5/2], [x, y])
This equation obviously has more than one solution: plot(sin(1/x), x, x = -1..1)
3-79
Mathematics
To get more real solutions of a single equation containing one variable, call the numeric solver with the option AllRealRoots. The AllRealRoots option does not guarantee that the solver finds all existing real roots. For example, the option helps to find additional solutions for the equation: numeric::solve(sin(1/x) = x, x, AllRealRoots)
3-80
For a system of nonpolynomial equation, the solver also returns only one solution. Plotting the equations, you see that the system has more than one solution: numeric::solve([sin(x) = y^2 - 1, cos(x) = y], [x, y]); plot(sin(x) = y^2 - 1, cos(x) = y)
The AllRealRoots option does not work for systems: numeric::solve([sin(x) = y^2 - 1, cos(x) = y], [x, y], AllRealRoots)
3-81
Mathematics
To find numerical approximations of other solutions, specify intervals that contain the solutions. You can use the command numeric::solve that internally calls numeric::fsolve. However, to speed up your calculations, call numeric::fsolve directly. Note that numeric::solve returns a set of solutions, and numeric::fsolve returns a list: numeric::solve([sin(x) = y^2 - 1, cos(x) = y], [x = 2.5..3.5, y = -1.5..-0.5]); numeric::fsolve([sin(x) = y^2 - 1, cos(x) = y], [x = 4..5, y = -0.2..0.2])
The MultiSolutions option also serves to find more than one numeric approximation. Without this option, the numeric solver looks for a solution inside the specified interval and disregards any solutions it finds outside of the interval. When the solver finds the first solution inside the interval, it stops and does not look for other solutions. If you use MultiSolutions, the solver returns the solutions found outside of a specified interval. Note If you use the option MultiSolutions and do not specify any interval, the numeric solver returns only the first solution it finds. With the MultiSolutions option, the solver also stops after it finds the first solution inside the specified interval. For example, find several numeric approximations for the following system: eqs := [x*sin(10*x) = y^3, y^2 = exp(-2*x/3)]: plot(x*sin(10*x) = y^3, y^2 = exp(-2*x/3))
3-82
Specify the interval where you want to search for the solutions. For example, consider the interval x = 0..1 that contains two solutions: plot(x*sin(10*x) = y^3, y^2 = exp(-2*x/3), x = 0..1, y = 0..1)
3-83
Mathematics
Call the numeric::solve or numeric::fsolve command with the MultiSolutions option. Both solvers return one solution that belongs to the specified interval and one solution outside of the interval: numeric::fsolve(eqs, [x = 0..1, y = 0..1], MultiSolutions); numeric::solve(eqs, [x = 0..1, y = 0..1], MultiSolutions)
Specifying the interval that does not contain any solutions can help you find more approximations. In this case, the solver cannot find the solution inside the interval and continues searching. Before the solver quits, it can find many solutions outside the specified interval: numeric::fsolve(eqs, [x = -10..0, y = 0..1], MultiSolutions)
3-84
You also can specify an interval and search for all subintervals that can contain real roots. The numeric::realroots command returns a complete list of such subintervals: numeric::realroots(1/4*x^4 + x^3 + x + 1 = 0, x = -5..0)
If the equation you solve is polynomial, each subinterval contains exactly one root. For nonpolynomial equations, numeric::realroots can return subintervals that do not contain any roots. numeric::realroots guarantees that the search interval does not contain any real roots outside the returned subintervals.
3-85
Mathematics
Suppose, you do not need an exact symbolic solution, but you want to approximate the solution for several values of the parameter t. For numeric approximations of the solutions of ODEs, MuPAD provides two functions: numeric::odesolve returns a numeric approximation of the solution at a particular point. numeric::odesolve2 returns a function representing a numeric approximation of the solution. Both functions accept either a first-order ODE or a system of first-order ODEs. To solve a higher-order equation, convert it to a system of the first-order equations. For example, represent the second-order ODE you solved symbolically as a system of two first-order equations: . The solution vector for this system is Y =
[y, z].
The second parameter of numeric::odesolve is the range over which you want to solve an ODE. The third parameter is a list of initial conditions ( ). Approximate the solutions y(t) for t = 1, t = 3, and :
3-86
MuPAD also offers an alternate way to generate parameters for the ODE numeric solvers:
1 Define your initial value problem as a list or a set:
by numeric::odesolve. The function numeric::ode2vectorfield generates the required procedure: [ODE, t0, Y0] := [numeric::ode2vectorfield(IVP, fields)]
Now call numeric::odesolve to approximate the solution at particular values of t: numeric::odesolve(ODE, t0..1, Y0)
3-87
Mathematics
by numeric::odesolve2. The function numeric::ode2vectorfield generates the required procedure: ODE := numeric::ode2vectorfield(IVP, fields)
Using the function generated by numeric::odesolve2, find the numeric approximation at any point. For example, find the numeric solutions for the values t = 1, t = 3, and . You get the same results as with
numeric::odesolve, but the syntax is shorter:
3-88
Plot the numeric solution using the function generated by numeric::odesolve2. The function numApprox returns a list [y(t), y'(t)]. When plotting the solution y(t), use brackets to extract the first entry of the solution list: plotfunc2d(numApprox(t)[1], t = 0..3)
Use numeric::odesolve2 to find numeric approximations for the following system of ODEs: IVP := {x'(t) = -y(t) + x(t)^2, y'(t) = 10*x(t) - y(t)^2, x(0) = 1, y(0) = 1}: fields := [x(t), y(t)]: ODE := numeric::ode2vectorfield(IVP, fields):
3-89
Mathematics
numApprox := numeric::odesolve2(ODE)
Plot the numeric solutions for x(t) and y(t) in one graph: plotfunc2d(numApprox(t)[1], numApprox(t)[2], t = 0..20)
Use the plot::Curve2d plotting function to generate a parametric plot of the numeric solution: curve := plot::Curve2d([numApprox(t)[1], numApprox(t)[2]], t = 0..20): plot(curve)
3-90
3-91
Mathematics
3-92
extend the set of simplification rules and also accepts a number of options allowing you more control over the simplification algorithm. If you do not need a particular form of expressions (expanded, factored, or expressed in particular terms), use simplify and Simplify to shorten mathematical expressions. For example, use these functions to find a shorter form for a final result. The general simplifiers also can help you in verifying the result.
For elementary expressions, simplify is an effective and fast simplifier. For more complicated expressions, simplify might be less effective. The returned form of the following expression can be shortened further. Simplify returns a simpler form: f := (cos(x)^2 - sin(x)^2)/(sin(x)*cos(x)): simplify(f), Simplify(f)
3-93
Mathematics
You can change the number of internal simplification steps through the option Steps. This option is not available for simplify: Simplify(F, Steps = 250)
By default, the general simplifiers return only one form of an expressionthe form that MuPAD considers to be simplest. To return all forms found by Simplify, use the option All: Simplify((x - 1)*(x + 1)*(x^2 + x + 1)*(x^2 + 1) *(x^2 - x + 1)*(x^4 - x^2 + 1), All)
3-94
While transforming an expression, MuPAD simplifiers keep all forms of an expression mathematically equivalent to the initial expression. For example, the simplifiers do not combine logarithms. The rule for combining logarithms does not hold for arbitrary complex arguments and, therefore, combining logarithms can be incorrect for some parameters: Simplify(ln(x + 2) - ln(x^2 + 4*x + 4))
Potential division by zero is the only exception of this rule: Simplify(x*(x + 1)/x)
To apply more simplification rules that are not generally correct, but which can return simpler results, use the option IgnoreAnalyticConstraints. This option is available for both simplify and Simplify. For example, simplifying an expression with IgnoreAnalyticConstraints, you get the result with combined logarithms: Simplify(ln(x + 2) - ln(x^2 + 4*x + 4), IgnoreAnalyticConstraints)
For the list of all options available for the general simplifiers, see simplify and Simplify.
3-95
Mathematics
3-96
Type of Transformation Normalize an expression Compute a partial fraction decomposition Simplify radicals in an expression Separate the real and imaginary parts of a complex expression Rewrite an expression in terms of a specified target function
Function
normal partfrac radsimp rectform rewrite
collect can consider an expression as the specified unknown. For example, group the terms of the following trigonometric expression with the equal powers of sin(x) and cos(x):
collect(f, cos(x))
3-97
Mathematics
The collect function also can accept several unknowns for collecting terms. If you have several unknowns, pass them to collect as a list: collect(a^2*sin(x) - cos(x)^2*sin(x)^3 + cos(x)^2 + a - a^2*sin(x)^4, [a, cos(x)])
If you do not specify a target function, combine uses the identities for powers wherever these identities are valid: a ba c = a b + c acbc = (ab)c, if c is an integer (ab)c = abc, if c is an integer For example, by default the function combines the following square roots: combine(sqrt(2)*sqrt(x))
The function does not combine these square roots because the identity is not valid for negative values of variables:
3-98
combine(sqrt(x)*sqrt(y))
As target functions, combine accepts arctan, exp, gamma, ln, sincos, and other functions. For the complete list of target functions, see the combine help page.
Expand Expressions
For elementary expressions, the expand function transforms the original expression by multiplying sums of products: expand((x + 1)*(x + 2)*(x + 3))
expand(sin(5*x))
To prevent the expansion of particular subexpressions, pass these subexpressions to expand as arguments: expand((sin(3*x) + 1)*(cos(2*x) - 1), sin(3*x))
3-99
Mathematics
To prevent the expansion of all trigonometric subexpressions in this example, use the option ArithmeticOnly: expand((sin(3*x) + 1)*(cos(2*x) - 1), ArithmeticOnly)
Factor Expressions
To present an expression as a product of sums, try the factor function. The factored form of the following polynomial is visibly shorter than the original one. The factored form also shows that this polynomial has only one root x = -5: factor(x^10 + 50*x^9 + 1125*x^8 + 15000*x^7 + 131250*x^6 + 787500*x^5 + 3281250*x^4 + 9375000*x^3 + 17578125*x^2 + 19531250*x + 9765625)
For sums of rational expressions, factor first computes a common denominator, and then factors both the numerator and denominator: f := (x^3 + 3*y^2)/(x^2 - y^2) + 3: f = factor(f)
The function also can factor expressions other than polynomials and rational functions. Internally, MuPAD converts such expressions into polynomials or rational function by substituting subexpressions with identifiers. After factoring the expression with temporary identifiers, MuPAD restores the original subexpressions: factor((ln(x)^2 - 1)/(cos(x)^2 - sin(x)^2))
3-100
By default, factor searches for polynomial factors with rational numbers. : The function does not factor the expression into a product containing factor(x^2 - 2)
3-101
Mathematics
The normal function also handles expressions other than polynomials and rational functions. Internally, MuPAD converts such expressions into polynomials or rational functions by substituting subexpressions with identifiers. After normalizing the expression with temporary identifiers, MuPAD restores the original subexpressions: f := (exp(2*x) - exp(2*y))/(exp(3*x) - exp(3*y)): f = normal(f)
The denominators in rational terms represent the factored common denominator of the original expression: factor(x^6 + 14*x^5 + 80*x^4 + 238*x^3 + 387*x^2 + 324*x + 108)
3-102
Use the rectform function to split a symbolic expression into its real and imaginary parts: y := rectform(tan(x))
To extract the real and imaginary parts of y, use the Re and Im functions: Re(y); Im(y)
3-103
Mathematics
Use rewrite to express the trigonometric and hyperbolic functions in terms of the exponential function: sin(x) = rewrite(sin(x), exp); cos(x) = rewrite(cos(x), exp); sinh(x) = rewrite(sinh(x), exp);
3-104
The command also expresses inverse hyperbolic functions in terms of logarithms: arcsinh(x) = rewrite(arcsinh(x), ln); arccosh(x) = rewrite(arccosh(x), ln)
As target functions, rewrite accepts: direct and inverse trigonometric functions, direct and inverse hyperbolic functions, diff, D, erf, exp, fact, gamma, harmonic, piecewise, and more. See the rewrite help page for the complete list of target functions.
3-105
Mathematics
The returned expression has an even shorter representation. To simplify this result further, call the Simplify command: Simplify(f)
3-106
You can simplify the result even more by increasing the number of steps: Simplify(f, Steps = 150)
The more powerful Simplify function converts this expression back to its trigonometric form: Simplify(f)
3-107
Mathematics
Use Options
When transforming expressions, the MuPAD simplifiers apply the rules valid for the entire complex plane. For example, try to simplify this expression containing logarithms: h := ln(x + 1)/2 - ln(1 - 1/x)/2 - ln(1 - x)/2 + ln(1/x + 1)/2
By default, the simplifier does not combine logarithms because this operation is only valid for particular real numbers. For complex numbers, combining logarithms is not generally valid: Simplify(h)
If you solve a problem that does not require application of strict mathematical rules, try using the IgnoreAnalyticConstraints option. With this option, the simplifier uses a set of mathematical rules that are not generally correct. For example, if you use the IgnoreAnalyticConstraints option, the simplifier returns: Simplify(h, IgnoreAnalyticConstraints)
The results obtained with the option IgnoreAnalyticConstraints are most useful for many in engineering and physics problems. Note that when you use this option, the simplifiers do not guarantee the equivalence of the original and simplified expressions for the entire complex plane.
3-108
Use Assumptions
When transforming an expression, the simplification functions apply the rules valid for the entire plane of complex numbers. By default, MuPAD does not assume any additional mathematical properties on the identifiers. For is not generally valid for all complex numbers: example, the identity simplify(ln(exp(x)))
When you work with real numbers, the simplification functions can also use the rules valid for real numbers. Use the assume or assuming command to specify that a variable x represents a real number. The assume command creates a permanent assumption. The assuming command creates a temporary assumption, which is valid during a single command. The simplifier applies the appropriate rule and returns the expected result: simplify(ln(exp(x))) assuming x in R_
When you simplify the following expression, the returned expression is shorter than the original one. However, you can further simplify the returned expression: f := ln(- 2*sin(-(sin(x)*I)/2)^2 + sin(-sin(x)*I)*I + 1); Simplify(f)
3-109
Mathematics
If you want to get a simplified result for real x, assume that x is real: assume(x, Type::Real); Simplify(f, Steps = 300)
When assuming any additional mathematical property for a variable (such as assuming that x is real), make sure that your problem does not require solutions to be valid for all complex numbers. Be especially careful if your initial expression contains complex numbers. For more information about assumptions, see Properties and Assumptions.
3-110
3-111
Mathematics
The general simplification functions, simplify and Simplify, represent this expression in terms of elementary functions: simplify(meijerG([[], []], [[1], []], z))
MuPAD also does not use automatic simplifications for many expressions involving special functions. Suppose you get an expression containing the Fresnel sine integral function: 2*fresnelS(z) + fresnelS(-z)
To apply the reflection rule fresnelS(-z) = -fresnelS(z) and simplify this expression, explicitly call one of the general simplifiers: simplify(2*fresnelS(z) + fresnelS(-z))
Particular values of parameters can reduce more general special functions to expressions containing simpler special functions. For example, reduce meijerG to the hypergeometric functions: Simplify(meijerG([[1/3, 1/3, 3/2], []], [[0], [-2/3, 4/3]], z))
3-112
The following choice of parameters expresses meijerG in terms of the Bessel functions: simplify(meijerG([[], []], [[1], [1]], z))
When you expand the gamma function, MuPAD expresses it in terms of gamma functions: gamma(5*x + 1) = expand(gamma(5*x + 1))
3-113
Mathematics
For this ODE, the solver returns the result in terms of the Bessel functions: S := solve(ode(eq, y(x)))
To verify correctness of the returned solution, try substituting it into the original equation by using evalAt or its shortcut |. You get the following long and complicated result that still contains the Bessel special functions. MuPAD does not automatically simplify this result: eq | y(x) = S[1]
3-114
3-115
Mathematics
The testeq command serves best for verifying correctness of the solutions. The command automatically simplifies expressions on both sides of the equation: testeq(eq | y(x) = S[1])
3-116
3-117
Mathematics
solving a single equation, the solver applies this assumption only to solve this particular equation. Using temporary assumptions to solve problems works best when an object holds its property only during particular calculations. Temporary assumptions also help you to keep the object name free and reuse it during the solution process. For more information see Using Temporary Assumptions.
3-118
If you do not consider the special case where no gravitational forces exist, you can safely assume that the gravitational acceleration is positive. This assumption removes the special zero-gravity cases from the solution: assume(g > 0); t = solve(h = g*t^2/2, t)
3-119
Mathematics
The variable h in the equation represents the height from which the object falls. If you do not consider that someone initially throws the object upward and that the object reflects from the ground, the height h is always positive. Therefore, you can assume that both gravitational acceleration g and height h are positive: assume(g > 0 and h > 0); t = solve(h = g*t^2/2, t)
Assuming that the time of the drop is a positive value, you get the expected result. When you set assumptions on variables, the solver compares the obtained solutions with the specified assumptions. This additional task can slow down the solver: assume(g > 0 and h > 0 and t > 0); t := solve(h = g*t^2/2, t)
The solver returns the solutions as a set, even if the set contains only one element. To access the elements of a solution set, use square brackets or the op command: time = t[1]
3-120
If you set several assumptions for the same object, each new assumption overwrites the previous one: assume(h in R_); assume(h <> 0); is(h in R_), is(h <> 0)
If you want to keep the previous assumption while adding a new one, see Adding Assumptions. The assume command cannot solve assumptions in the form of equations and does not assign values to the variables: assume(g + 5 = 14.8 and 2*t = 14); h = g*t^2/2
When you set an assumption in the form of an inequality, both sides of the inequality must represent real values. Inequalities with complex numbers are invalid because the field of complex numbers is not an ordered field. For example, if you try to use the following assumption, MuPAD returns an error: assume(t > 2*I)
Error: Assumptions are inconsistent. [property::_assume] You can use complex values in an assumption written in the form of an equation: assume(t = 2*PI*I)
3-121
Mathematics
To add a new assumption without removing the previous assumptions, use the assumeAlso command: assume(x in Z_); assumeAlso(x in R_); is(x in Z_), is(x in R_)
Also, you can set multiple assumptions in one function call by using the logical operators. For example, set two assumptions on x: assume(x in Z_ and x in R_); is(x in Z_), is(x in R_)
When adding assumptions, always check that a new assumption does not contradict the existing assumption. MuPAD does not guarantee to detect conflicting assumptions. For example, assume that y is simultaneously nonzero, real and an imaginary value. Type::Imaginary refers to all complex numbers lying on the imaginary axis. When you set these assumptions, MuPAD does not issue any warning and does not error: assume(y <> 0); assumeAlso(y in R_); assumeAlso(y, Type::Imaginary)
3-122
Note Do not set conflicting assumptions because they can lead to unpredictable and inconsistent results. To check if the assumption still holds true, use the is command. For example, MuPAD drops the assumption that the variable y represents imaginary numbers because this assumption conflicts with the combination of the previous two assumptions: is(y <> 0), is(y in R_), is(y, Type::Imaginary)
If you set conflicting assumptions, the order in which you set them does not always determine which assumption MuPAD accepts: assume(y <> 0); assumeAlso(y, Type::Imaginary); assumeAlso(y in Z_); is(y <> 0), is(y, Type::Imaginary), is(y in Z_)
3-123
Mathematics
The unassume command clears a particular object from all assumptions: unassume(g); unassume(h); unassume(t); property::showprops(g), property::showprops(h), property::showprops(t)
To delete the value of a parameter and clear all assumptions set for this parameter, use the delete command: delete g, h, t For example, assign the value h := g*t^2/2: assume(g > 0 and h > 0); property::showprops(h); h to the variable h and assume that h > 0:
The unassume command clears the assumption, but does not remove the value of the variable: unassume(h > 0); property::showprops(h); h
3-124
The delete command clears the assumption and the value: delete h; property::showprops(h); h
3-125
Mathematics
3-126
Suppose, you want to keep the general solution for all possible cases of the linear motion with constant acceleration. You also want to derive several special cases of this motion and get particular solutions for these cases. For example, one of the objects you consider moves with constant velocity. Derive the solution for this object from the general solution for the time of the motion by assuming the acceleration a = 0: t = solve(r = r_0 + v_0*t + a*t^2/2, t) assuming a = 0 and r > r_0 and v_0 > 0
The assumption a = 0 holds true only for this particular call to solve. The assumption does not affect other calculations: is(a = 0)
If you set an assumption in the form of an inequality, both sides of an inequality should represent real values. Inequalities with complex numbers
3-127
Mathematics
are invalid because the field of complex numbers is not an ordered field. For example, if you try to use the following assumption, MuPAD returns an error: y + 1 assuming y > 2*I
Error: Assumptions are inconsistent. [property::_assume] You can use complex values in assumptions presented in forms of equations: y + 1 assuming y = 2*I
If you use assignments, MuPAD evaluates variables to their values in all further computations: r, r_0, v_0, a
To be able to reuse the variables in further computations, use the delete command:
3-128
delete r, r_0, v_0, a Using assumptions, you can temporarily assign values to the parameters. For example, solve the equation for the following values: t = solve(r = r_0 + v_0*t + a*t^2/2, t) assuming r = 4 and r_0 = 0 and v_0 = 3 and a = 2 and t > 0
The variables remain free for further calculations because temporary assumptions do not hold true: r, r_0, v_0, a, t
If assumptions contain linear equations with one variable, MuPAD solves these equations, inserts the solutions into the expression, and then evaluates the expression: r = r_0 + v_0*t + a*t^2/2 assuming a + 5 = 5 and 2*v_0 + 4 = 14 and t = 3 and r_0 = 0
3-129
Mathematics
After evaluating the statement with a temporary assumption, MuPAD reinstates the permanent assumption: is(z in R_)
See how to use temporary assumptions in combination with permanent assumptions in Using Temporary Assumptions on Top of Permanent Assumptions.
To use permanent assumptions and a temporary assumption together, add the temporary assumption using the assumingAlso command: assume(x in R_); solve(x^3 + x = 0, x) assumingAlso (x <> 0)
When you use temporary assumptions on top of the permanent ones, always check that the assumptions do not contradict each other. Contradicting assumptions can lead to inconsistent and unpredictable results. In some cases, MuPAD detects conflicting assumptions and issues the following error: assume(x < 0); x assumingAlso (x > 0);
3-130
Error: Assumptions are inconsistent. [property::_assume] MuPAD does not guarantee to detect contradicting assumptions: assume(x, Type::Even); x assumingAlso (x + 1, Type::Even)
3-131
Mathematics
To differentiate a function or functional expression, use D or its shortcut '. Using this command, you can differentiate any standard mathematical function or your custom created function. For example: D(cos); f := x -> x*sin(x): f'
3-132
Differentiate Expressions
Differentiate Expressions
For differentiating an expression, use the diff command. Specify the expression you want to differentiate, and the differentiation variable. Specifying the differentiation variable is important even if your expression contains only one variable. For example, find the derivative of an expression with one variable: diff(x^2 + sqrt(sin(x)), x)
Note If you do not specify differentiation variable, diff(expr) returns the expression expr. Find first-order partial derivatives of a multivariable expression by specifying differentiation variables: diff(sin(x*cos(x*y)), x); diff(sin(x*cos(x*y)), y)
To take second and higher order derivatives, you can use nested calls to the diff function. More efficiently, use only one diff command and specify variables for each differentiation step. Calling diff only once is shorter and also can improve performance because MuPAD internally converts nested calls to diff into a single call with multiple arguments: diff(diff(sqrt(sin(x)), x), x); diff(sqrt(sin(x)), x, x)
3-133
Mathematics
When computing higher order derivatives with respect to one variable, use the sequence operator as a shortcut: diff(sqrt(sin(x)), x $ 3) = diff(sqrt(sin(x)), x, x, x)
To compute mixed derivatives, specify differentiation variables for each step: diff(x*cos(x*y), y, x)
Note To improve performance, MuPAD assumes that all mixed derivatives commute. For example, .
3-134
Differentiate Functions
Differentiate Functions
To compute derivatives of functions, use the differential operator D. This operator differentiates both standard mathematical functions and your own functions created in MuPAD. For example, find the first derivatives of the following standard mathematical functions implemented in MuPAD: D(sin), D(exp), D(cosh), D(sqrt), D(heaviside)
Create your own function with one variable and compute a derivative of this function: f := x -> x^3: D(f)
Alternatively, use ' as a shortcut for the differential operator D: f := x -> sin(x)/x^2: f'; f'(x)
Computing the first derivatives of a function lets you find its local extrema (minima and maxima). For example, create this function and plot it on the interval -10 < x < 10: F := x -> x^3*sin(x);
3-135
Mathematics
plot(F, x = -10..10)
Find the local extrema of F on the interval -10 < x < 10. If the point is a local extremum (either minimum or maximum), the first derivative of the function at that point equals 0. Therefore, to find the local extrema of F, solve the equation F'(x) = 0. Use the AllRealRoots option to return more than one solution. extrema := numeric::solve(F'(x) = 0, x = -10..10, AllRealRoots)
Now, compute the corresponding values of F. For example, compute F for the third element, -2.455643863, in the solution set: F(extrema[3])
3-136
Differentiate Functions
To compute the values of F for all local minima and maxima, use the following command. Here, $ is used to evaluate F for every element of the extrema set. points := {[x, F(x)] $ x in extrema}
To compute a derivative of a multivariable function, specify the differentiation variable. The operator D does not accept the variable names. Instead of providing a variable name, provide its index. For example, integrate the
3-137
Mathematics
following function with respect to its first variable x. Then integrate the function with respect to its second variable y: f := (x, y) -> x^2 + y^3: D([1], f); D([2], f)
The list of indices accepted by the operator D refers to the order in which you provided the variables when creating a function: f := (x, y) -> x^2 + y^3: D([1], f); f := (y, x) -> x^2 + y^3: D([1], f)
To find second- and higher-order partial derivatives of a function, use the same index two or more times. For example, compute the second-order partial derivatives with respect to x and with respect to y: f := (x, y) -> x^3*sin(y): D([1, 1], f); D([2, 2], f)
3-138
Differentiate Functions
To compute second- and higher-order derivatives with respect to several variables (mixed derivatives), provide a list of indices of differentiation variables: f := (x, y) -> x^3*sin(y): D([1, 2], f);
Note To improve performance, MuPAD assumes that all mixed derivatives commute. For example, most engineering and scientific problems. . This assumption suffices for
3-139
Mathematics
The following integrand also consists of standard trigonometric functions, but here the integrator cannot return the result in terms of elementary functions. The antiderivative involves a special function: int(sin(x)/x, x)
When you compute an indefinite integral, MuPAD implicitly assumes that the integration variable is real. The result of integration is valid for all real numbers, but can be invalid for complex numbers. You also can define properties of the integration variables by using the assume function. The properties you specify can interfere with the assumption that the integration variable is real. If MuPAD cannot integrate an expression using your assumption, the int function issues a warning. Use the intlib::printWarnings function to switch the warnings on and off. For example, switch on the warnings: intlib::printWarnings(TRUE):
3-140
Suppose you want to integrate the following expression under the assumption that the integration variable is positive. This assumption does not conflict with the assumption that the variable is real. The int command uses your assumption: f := abs(x): int(f, x) assuming x > 0
Integrate this expression under the assumption that x is an integer. MuPAD cannot integrate the expression over a discrete subset of the real numbers. The int command issues a warning, and then integrates over the field of real numbers: int(f, x) assuming x in Z_
Warning: Cannot integrate when 'x' has property 'Z_'. The assumption
For a discrete set of values of the integration variable, compute a sum instead of computing an integral. See Summation for details. Now integrate under the assumption that x is imaginary. The int command cannot compute the integral of the expression over imaginary numbers. It issues a warning and integrates the expression over the domain of complex numbers: assume(x, Type::Imaginary); int(f, x)
3-141
Mathematics
For more information about the assumptions, see Properties and Assumptions. Before you proceed with other computations, clear the assumption on the variable x: unassume(x): Also, disable the warnings: intlib::printWarnings(FALSE):
3-142
If the int command determines that an integral does not converge, it returns the special value undefined: int(exp(x*I), x = 1..infinity)
When the int command cannot compute an integral and also cannot prove that the integral does not converge, it returns an unresolved integral: int(sin(cos(x)), x = 0..10)
For definite integrals, the int command restricts the integration to the specified interval. If you use the assume function to set properties on the integration variable, int temporarily overwrites these properties and integrates over the specified interval. To display warnings, set the value of intlib::printWarnings to TRUE: intlib::printWarnings(TRUE): assume(x > 0): int(x, x = 1 .. 2); int(x, x = -3 .. 1)
3-143
Mathematics
Warning: The assumption that 'x' has property '[1, 2]' instead of giv
Warning: The assumption that 'x' has property '[-3, 1]' instead of gi
After computing an integral, MuPAD restores the assumptions set for integration variable. If you do not want the assumptions to affect further computations, use the unassume function: unassume(x) MuPAD also makes implicit assumptions on the specified interval. Suppose, you use the integration range as [a, b]. The system assumes that both a and b represent real numbers, and that a <= b unless you clearly specify otherwise. If you set the value of intlib::printWarnings to TRUE, MuPAD displays the warning about using implicit assumptions: int(heaviside(x - a), x = a..b)
Warning: Cannot decide if 'a <= b' is true, will temporarily assume i
To avoid this implicit assumption, specify that a > b or a < b int(heaviside(x - a), x = a..b) assuming a > b
3-144
3-145
Mathematics
Compute the expression for the surface area of a sphere. The distance from the center of a sphere to the surface remains constant, r = R. The angle changes its value from 0 to . The angle changes its value from 0 to 2: int(int(R^2*sin(phi), phi = 0..PI), chi = 0..2*PI)
Compute the expression for the volume of a sphere. The angles accept the same values, but the distance from the center of any point inside the sphere ranges from 0 to R. To find the volume, compute the following triple integral: int(int(int(r^2*sin(phi), r = 0..R), phi = 0..PI), chi = 0..2*PI)
3-146
3-147
Mathematics
Integration by Parts
Integration by parts is one of the common methods for computing integrals. Using this method, you rewrite the original integral in terms of an expression containing a simpler integral. Integration by parts for indefinite integrals uses the definition:
. Internally, MuPAD uses integration by parts along with other integration methods. To use this method explicitly, call the intlib::byparts function. If you want to integrate an expression by parts, keep the original integral unevaluated. By default, int returns evaluated integrals. Use the hold or freeze commands to prevent evaluation of the integral: f := freeze(int)(exp(a*x)*cos(I*x*b), x)
Call intlib::byparts and specify the part of an expression you want to integrate. For example, specify :
3-148
If the resulting expression is too long, try using the simplify or Simplify function: Simplify(%)
Change of Variable
Change of variable is also one of the common methods for computing integrals. For explicit use of this method, MuPAD provides the intlib::changevar function. When changing an integration variable, you need to keep the integral unevaluated. By default, int returns evaluated integrals. Use the hold or freeze commands to prevent evaluation of the integral: f := intlib::changevar(hold(int)(sin(exp(x)), x), t = exp(x), t)
3-149
Mathematics
eval(f)
The change of variable method also works for computing definite integrals: f := intlib::changevar(hold(int)(x/sqrt(1 - x^2), x = a..b), t = x^2, t)
3-150
If you want a simple practical solution, try the IgnoreAnalyticConstraints option. With this option, MuPAD uses a set of simplified mathematical rules that are not generally correct. The returned results might be shorter and more useful, for example: int(arcsin(sin(x)), x, IgnoreAnalyticConstraints)
3-151
Mathematics
If an Integral Is Undefined
If one of the following conditions is true, a definite integral not exist in a strict mathematical sense: might
If the interior of the integration interval (a, b) contains poles of the integrand f(x). If a = - or b = or both. If f(x) changes sign at all poles in (a, b), the so-called infinite parts of the integral to the left and to the right of a pole can cancel each other. In this case, use the PrincipalValue option to find a weaker form of a definite integral called the Cauchy principal value. For example, this integral is not defined because it has a pole at x = 0: int(1/x, x = -1..1)
To compute the Cauchy principal value, call int with the option PrincipalValue: int(1/x, x = -1..1, PrincipalValue)
If an expression can be integrated in a strict mathematical sense, and such an integral exists, the Cauchy principal value coincides with the integral: int(x^2, x = -1..1) = int(x^2, x = -1..1, PrincipalValue)
3-152
If MuPAD cannot compute an integral of an expression, one of the following reasons may apply: The antiderivative does not exist in a closed form. The antiderivative exists, but MuPAD cannot find it. Try to approximate these integrals by using one of the following methods: For indefinite integrals, use series expansions. Use this method to approximate an integral around a particular value of the variable. For definite integrals, use numeric approximations.
3-153
Mathematics
To approximate the result around some point, use the series function. For example, approximate the integral around x = 0: series(F, x = 0)
If you know in advance that the integral cannot be found in a closed form, skip calculating the symbolic form of the integral. To use the system more efficiently, call the series command to expand the integrand, and then integrate the result: int(series(cos(x)/sqrt(1 + x^2), x = 0), x)
If you know in advance that the integral cannot be found in a closed form, skip calculating the symbolic form of the integral. Use the system more
3-154
efficiently by calling the numeric::int function. This command applies numeric integration methods from the beginning: numeric::int(cos(x)/sqrt(1 + x^2), x = 0..10)
3-155
Mathematics
Indefinite Sums
The function is called the indefinite sum of xi over i, if the following identity holds for all values of i: . When you compute an indefinite sum, the result often involves much more complicated functions than those you use in the original expression. If the original expression consists of elementary functions, you can get the result in terms of elementary functions: sum(x^2/(x^2 - 1), x)
Although the following expression consists of elementary functions, the result involves a special function:
3-156
sum(x/(x^2 + 1), x)
Definite Sums
When computing an indefinite sum, the sum command implicitly assumes that the integration index runs through all integer numbers. Definite summation lets you specify the range of the summation index. For example, specify the summation index range using a symbolic parameter: sum(x/(x^2 + 1), x = a..10*a)
To find a sum over two variables, use nested calls to sum: sum(sum(x^n/n!, n = 0..infinity), x = a..100*a)
If your sum has a small finite number of terms, use the _plus command instead of sum. The sum command is slower than _plus: _plus(x/(x^2 + 1) $ x = 0..10)
3-157
Mathematics
To compute a sum for a large finite number of terms, use the sum command: sum(x/(x^2 + 1), x = 1..10^10)
If the result of a finite summation contains more than 1000 terms, the sum command returns an unexpanded symbolic sum. If you want to display all the terms explicitly, use the expand function. To get the expanded result in the following example, delete the colon at the end of the example: S := sum(exp(x)/(x^2 + 1), x = a..a + 1000); expand(S):
3-158
The reasons MuPAD cannot compute the closed form of a particular sum are the same as the reasons for not computing an integral: The antidifference does not exist in a closed form. The antidifference exists, but MuPAD cannot find it. MuPAD can find the antidifference on a larger computer, but runs out of time or memory on the available machine. If MuPAD cannot compute a definite sum, try to approximate it numerically: S := sum(exp(x)^(-x), x = 0..infinity); float(S)
If you know in advance that the antidifference cannot be computed in a closed form, skip trying to calculate this sum symbolically. For such expressions, call the numeric::sum function to perform numeric summation directly. Trying to calculate a symbolic sum, and then approximating it numerically can be much slower than applying numeric summation from the beginning: numeric::sum(exp(x)^(-x), x = 0..infinity)
3-159
Mathematics
3-160
. To compute Taylor series expansion, use the taylor command. For example, approximate the expression sin(x)/x around x = 0: exact := sin(x)/x: approx := taylor(sin(x)/x, x)
Plot the exact expression and its taylor series expansion in the same coordinate system. The taylor series expansion approximates the expression near x = 0, but visibly deviates from sin(x)/x for larger |x|: plot( plot::Function2d(exact, x = -PI..PI, Legend = "sin(x)/x", Color = RGB::Red), plot::Function2d(approx, x = -PI..PI, Legend = "approximation of sin(x)/x") )
3-161
Mathematics
Accuracy of an approximation depends on the proximity to the expansion point and on the number of terms used in the series expansion. See how to specify the number of terms in Controlling the Number of Terms in Series Expansions. Taylor series expansions around x = 0 are also called Maclaurin series expansions. Approximate the expressions by Maclaurin series: taylor(exp(x), x); taylor(sin(x), x); taylor(cos(x)/(1 - x), x)
3-162
The Maclaurin series expansion does not exist for the following expression. MuPAD returns an error: taylor(arccot(x), x)
Error: Cannot compute a Taylor expansion of 'arccot(x)'. Try 'series' You can represent the following expression by a Taylor series around x = 1. To compute the series expansion around a nonzero value of a variable, specify the value. For example, compute the Taylor series expansions around x = 1 for the following expressions: taylor(ln(x), x = 1); taylor(arccot(x), x = 1)
The taylor command returns results in the form of Taylor series including the order term O. To convert the results to a regular polynomial expression without the O-term, use the expr command: s := taylor(sin(x)/exp(x), x); expr(s)
3-163
Mathematics
3-164
Specify all nonzero values of the variables at the point where you want to compute the series expansion. Besides numbers and symbolic parameters, mtaylor also accepts real positive infinity infinity and real negative infinity - : mtaylor((1 - x)^(1/2)/exp(1/y), [x, y = infinity])
3-165
Mathematics
The number of terms includes the terms with coefficients equal to zero. For example, the taylor series expansion of cos(x) includes the terms 0x, 0x3, and 0x5. MuPAD computes these terms, but does not display them: taylor(cos(x), x)
Suppose, you want to approximate an exponential function with the polynomial expression around x = 0. Use the third parameter in taylor to specify the order of series expansion. For example, compute the series expansions approx1 specifying the truncation order 3. Compare the result with the series expansion computed for the default order: exact := exp(x): approx1 := taylor(exp(x), x, 3); approx2 := taylor(exp(x), x)
3-166
Plot the exact expression, exact, and its taylor series expansions, approx1 and approx2, in the same coordinate system. The series expansion with more terms approximates the expression exp(x) better: plot( plot::Function2d(exact, x = -PI..PI, Legend = "exp(x)", Color = RGB::Red), plot::Function2d(approx2, x = -PI..PI, Legend = "approximation of exp(x), up to O(x^6)", Color = RGB::Blue), plot::Function2d(approx1, x = -PI..PI, Legend = "approximation of exp(x), up to O(x^3)", Color = RGB::Green) )
There are two ways to change the truncation order for series expansions: Locally by passing the truncation order as the third parameter to taylor. By using this parameter, you specify the truncation order for a particular
3-167
Mathematics
series expansion. All other series expansions use the default order. The parameter is available for the following commands: taylor, mtaylor, and series. For more information, see the help pages for these commands. Globally by using the environment variable ORDER. When you change this variable, all series expansions use the new truncation order. To change the truncation order for a particular series expansion, pass the new order as a third parameter to taylor: taylor(exp(x), x, 10)
To change the default truncation order for all series expansions, modify the environment variable ORDER: ORDER := 7: taylor(exp(x), x)
The following computations use the new value of ORDER: taylor(sqrt(1 - x), x)
To restore the default value of ORDER, use the delete command: delete ORDER: taylor(sqrt(1 - x), x)
3-168
When evaluating expressions with order terms, the system uses standard arithmetical operations for these terms: O(x^3)/O(x^2), O(x^3) + O(x^2), O(x^3)*O(x^2)
3-169
Mathematics
Error: Cannot compute a Taylor expansion of '1/(x^3 - 8)'. Try 'serie If a Taylor series expansion does not exist for your expression, try to compute other power series. MuPAD provides the function series for computing power series. When you call series, MuPAD tries to compute the following power series: Taylor series Laurent series Puiseux series. For more information, see Series::Puiseux. Generalized series expansion of f around x = x0. For more information, see Series::gseries. As soon as series computes any type of power series, it does not continue computing other types of series, but stops and returns the result. For example, for this expression it returns a Laurent series: S := series(1/(x^3 - 8), x = 2); testtype(S, Type::Series(Laurent))
3-170
When computing series expansions, MuPAD returns only those results that are valid for all complex values of the expansion variable in some neighborhood of the expansion point. If you need the expansion to be valid only for real numbers, use the option Real. For example, when you compute the series expansion of the following expression for complex numbers, series returns: series(sign(x^2*sin(x)), x = 0)
When you compute the series expansion for real numbers, series returns a simplified result: series(sign(x^2*sin(x)), x = 0, Real)
Along the real axis, compute series expansions for this expression when x approaches the value 0 from the left and from the right sides: series(sign(x^2*sin(x)), x = 0, Left); series(sign(x^2*sin(x)), x = 0, Right)
3-171
Mathematics
. MuPAD provides the limit command for computing limits. When computing a limit for a variable approaching 0, you can omit specifying x0. By default, the limit command assumes x0 = 0: limit(sin(x)/x, x = 0); limit((1 - cos(x))/x, x)
Note Avoid computing limits for floating-point arguments. If you use floating-point numbers as the parameters of limit, the round-off error can completely change the result. For example, a small error in the following example with the floating-point parameter changes the result from a rational number to the floating-point infinity: limit((sin(x) - x)/x^3, x = 0); limit((1.000001*sin(x) - x)/x^3, x = 0)
3-172
limit(tan(x), x = PI/2)
The plot of this function shows that the function can have two different limits as the variable x approaches the value plot(tan(x), x = -PI..PI) from the left and from the right:
To compute one-sided limits of a function, use the options Left and Right: limit(tan(x), x = PI/2, Left);
3-173
Mathematics
If the function has a bidirectional limit at some point, one-sided limits are equal at this point. They also are equal to the bidirectional limit at this point: Left = limit(abs(tan(x)), x = PI/2, Left); Right = limit(abs(tan(x)), x = PI/2, Right); Bidirectional = limit(abs(tan(x)), x = PI/2)
plot(abs(tan(x)), x = 0..PI)
3-174
3-175
Mathematics
If limit can prove that the limit is undefined at a particular point, then it returns undefined: limit(exp(x)*cos(1/x), x = 0)
The function exp(x)*cos(1/x) also does not have one-sided limits at x = 0: limit(exp(x)*cos(1/x), x = 0, Left); limit(exp(x)*cos(1/x), x = 0, Right)
The plot shows that as exp(x)*cos(1/x) approaches x = 0, the function oscillates between and : p1 := plot::Function2d(exp(x)*cos(1/x), x = -PI/4..PI/4): p2 := plot::Function2d(exp(x), x = -PI/4..PI/4, Color = RGB::Red): p3 := plot::Function2d(-exp(x), x = -PI/4..PI/4,Color = RGB::Red): plot(p1, p2, p3)
3-176
To get the interval of all possible accumulation points of the function exp(x)*cos(1/x) near the singularity x = 0, use the option Intervals: limit(exp(x)*cos(1/x), x = 0, Intervals)
3-177
Mathematics
Create Matrices
MuPAD supports creating and operating on vectors and multidimensional matrices. Vectors and matrices in MuPAD can contain arbitrary MuPAD objects: numbers, variables, arithmetical expressions, and so on. The simplest way to create a matrix is to use the matrix command: matrix([[1, 2, 3], [4, 5, 6]])
When creating a matrix, you can explicitly specify its dimensions. If you specify matrix dimensions, you can use a flat list to specify all elements of a matrix. The matrix command takes the entries from the flat list and generates a matrix, row by row. For example, create the following 23 matrix: matrix(2, 3, [1, 2, 3, 4, 5, 6])
Using the same list of elements, create the following 3 2 matrix: matrix(3, 2, [1, 2, 3, 4, 5, 6])
If you specify matrix dimensions, and then enter rows or columns shorter than the declared dimensions, MuPAD pads the matrix with zero elements: matrix(3, 3, [[1, 2, 3], [4, 5, 6]])
3-178
Create Matrices
To create a matrix of zeros, specify matrix dimensions and omit specifying elements: matrix(3, 2)
If you use a flat list, MuPAD cannot determine where to put zeros and, therefore, issues an error: matrix(3, 3, [1, 2, 3, 4])
Error: The number of list entries does not match matrix row dimension If you specify matrix dimensions, and then enter rows or columns longer than the declared dimensions, MuPAD also issues an error: A := matrix(2, 3, [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
Error: The number of list entries does not match matrix row dimension The matrix command creates an object of the type Dom::Matrix(): A := matrix([[1, 2, 3], [4, 5, 6]]): type(A)
3-179
Mathematics
3-180
Create Vectors
Create Vectors
Vectors in MuPAD do not form a separate data type. As matrices, vectors belong to the type Dom::Matrix(). To create a row or a column vector, use the matrix command and specify one of the dimensions to be 1. For example, create a row vector that contains five elements: matrix(1, 5, [1, 2, 3, 4, 5])
If you do not specify the dimensions, the matrix command creates a column vector: matrix([x, y, z])
3-181
Mathematics
Now, create the 33 diagonal matrix with the number 5 on the diagonal: matrix(3, 3, 5, Diagonal)
To create a matrix containing variables or arithmetical expressions, always use a list to specify matrix elements. For example, when creating the 33 diagonal matrix with the variable x on its main diagonal, specify the diagonal elements in a list [x, x, x]. As a shortcut for creating this list, you can use the sequence generator $: matrix(3, 3, [x $ 3], Diagonal)
To create special matrices such as Hilbert, Toeplitz, Pascal, or Vandermonde matrices, use the appropriate function of the linalg library. For example, to create the 44 Hilbert matrix, use the linalg::hilbert function: linalg::hilbert(3)
3-182
To create a matrix of random numbers, use the linalg::randomMatrix function. For example, create a matrix of random integer numbers: linalg::randomMatrix(3, 4, Dom::Integer)
Now, create a matrix that has random rational numbers on the main diagonal and zeros everywhere else: linalg::randomMatrix(3, 3, Diagonal, Dom::Rational)
3-183
Mathematics
To access any element of the matrix, use square brackets to specify indices. For example, assign the value 22 to the second element of the second row of A: A[2, 2] := 22: Now, assign the value 23 to the third element of the second row of A: A[2, 3] := 23: Display the modified matrix A: A
3-184
A := matrix(3, 4): for i from 1 to 3 do for j from 1 to 4 do A[i, j] := i*j end_for end_for: A
3-185
Mathematics
Use that constructor to produce matrices with integer elements: A := constructor(3, 3, [[1, 2, 3], [2, 3, 1], [3, 1, 2]])
When you use the constructor to create a matrix, you must ensure that all matrix elements belong to the ring or can be converted to the elements in that ring. Otherwise, the constructor issues an error and does not create a matrix: constructor(3, 3, [[1/3, 2, 3], [2, 3, 1], [3, 1, 2]])
Error: Cannot define a matrix over 'Dom::Integer'. [(Dom::Matrix(Dom: If you use a constructor to create a matrix over a particular ring, you cannot use that matrix in operations that create matrices with elements outside
3-186
of the ring. For example, you cannot compute the inverse of the matrix A because the inverse matrix contains noninteger numbers: 1/A
Now, create the matrix containing the same elements as A, but use the constructor for matrices with rational numbers: constructorRational := Dom::Matrix(Dom::Rational): B := constructorRational(3, 3, [[1, 2, 3], [2, 3, 1], [3, 1, 2]])
3-187
Mathematics
3-188
Dom::DenseMatrix(). You also can use the constructor itself. For matrices of the Dom::DenseMatrix() domain, indexed reading and writing is faster than for matrices of the Dom::Matrix() domain.
3-189
Mathematics
To perform basic operations on a matrix and a number, use the same operators. When you multiply a matrix by a number, MuPAD multiplies all elements of a matrix by that number: 5*A
When you add a number to a matrix, MuPAD multiplies the number by an identity matrix, and then adds the result to the original matrix: A + 5
3-190
Note MATLAB adds a number to each element of a matrix. MuPAD adds a number only to the diagonal elements of a matrix. You can combine matrices with the same number of rows by using the concatenation operator (.): A.B
The int and diff functions compute the derivative and the integral of each element of a matrix: A := matrix(2, 2, [x, x^2, x^3, x^4]): int(A, x), diff(A, x)
3-191
Mathematics
The expand function expands each element of a matrix: A := matrix(2, 2, [x, (x + 1)^2, x*(x - 1), x*(x + 4)]): expand(A)
The map function applies the specified function to all operands of each element of a matrix: A := matrix(3, 3, [1, 2, 3], Diagonal): B := map(A, sin)
The float function converts each element of a matrix or numerical subexpressions of each element of a matrix to floating-point numbers: float(B)
The evalAt function (and its shortcut |) substitutes the specified object by another specified object, and then evaluates each element of a matrix: A := matrix(2, 2, [x, x^2, x^3, x^4]):
3-192
A|x = 2
The subs function returns a copy of a matrix in which the specified object replaces all instances of another specified object. The function does not evaluate the elements of a matrix after substitution: A := matrix(2, 2, [x, x^2, x^3, x^4]): subs(A, x = exp(y))
The has function determines whether a matrix contains the specified object: A := matrix(2, 2, [x, x^2, x^3, x^4]): has(A, x^3), has(A, x^5)
The iszero function checks whether all elements of a matrix are zeros: A := matrix(2, 2): iszero(A)
A[1, 1] := 1: iszero(A)
The norm function computes the infinity norm (row sum norm) of a matrix:
3-193
Mathematics
The zip(A, B, f) function combines matrices A and B into a matrix C so that Cij = f(Aij, Bij): A := matrix(2, 2, [a, b, c, d]): B := matrix(2, 2, [10, 20, 30, 40]): zip(A, B, _power)
3-194
To compute a sum of the diagonal elements of a square matrix (the trace of a matrix), use the linalg::tr function. For example, the trace of the matrix A is: A := matrix(2, 2, [a, b, c, d]): linalg::tr(A)
Now, compute the trace of the 1212 Hilbert matrix: H := linalg::hilbert(12): linalg::tr(H)
3-195
Mathematics
Invert Matrices
To find the inverse of a matrix, enter 1/A or A^(-1): A := matrix([[a, b], [c, d]]): B := matrix([[1, 2], [3, 4]]): 1/A; B^(-1)
When MuPAD cannot compute the inverse of a matrix, it returns FAIL: C := matrix([[1, 1], [1, 1]]): 1/C
3-196
Transpose Matrices
Transpose Matrices
To transpose a matrix, use the transpose command: A := matrix([[1, 2, 3], [4, 5, 6]]): transpose(A)
3-197
Mathematics
To delete a row or a column, use linalg::delRow or linalg::delCol, respectively: OriginalMatrix := linalg::pascal(3); DeleteRows := linalg::delRow(OriginalMatrix, 3); DeleteColumns := linalg::delCol(OriginalMatrix, 3)
3-198
To delete a block of rows or columns simultaneously, use the same functions as for one row or column. Specify the range of rows or columns that you want to delete: OriginalMatrix := linalg::pascal(3); DeleteRows := linalg::delRow(OriginalMatrix, 2..3); DeleteColumns := linalg::delCol(OriginalMatrix, 2..3)
3-199
Mathematics
3-200
3-201
Mathematics
Now, compute the reduced row echelon form and the rank of the following 34 matrix: OriginalMatrix := matrix([[1, 2, 3], [5, 6, 7], [9, 10, 11], [13, 14, 15]]); RREF = linalg::gaussJordan(OriginalMatrix); Rank = linalg::rank(OriginalMatrix)
3-202
Now, compute the basis for the null space of the following 3 4 matrix: B := matrix([[1, 2, 3], [5, 6, 7], [9, 10, 11], [13, 14, 15]]): linalg::nullspace(B)
3-203
Mathematics
To compute the eigenvalues of the matrix A, use the linalg::eigenvalues function: linalg::eigenvalues(A)
The linalg::eigenvalues function returns a set of eigenvalues. A set in MuPAD cannot contain duplicate elements. Therefore, if a matrix has eigenvalues with multiplicities greater than 1, MuPAD automatically removes duplicate eigenvalues. If you want the linalg::eigenvalues function to return eigenvalues along with their multiplicities, use the Multiple option. For example, zero is a double eigenvalue of the matrix A: linalg::eigenvalues(A, Multiple)
3-204
To compute the eigenvectors of a matrix, use the linalg::eigenvectors function. The function returns eigenvectors along with corresponding eigenvalues and their multiplicities: linalg::eigenvectors(A)
The linalg::eigenvalues function computes eigenvalues of a matrix by finding the roots of the characteristic polynomial of that matrix. There is no general method for solving polynomial equations of orders higher than 4. When trying to compute eigenvalues of a large matrix, the solver can return complicated solutions or solutions in the form of RootOf. Also, the solver can fail to find any solutions for some matrices. For example, create the 6 6 Pascal matrix: P := linalg::pascal(6)
For that matrix, MuPAD finds eigenvalues in the form of RootOf: eigenvalues := linalg::eigenvalues(P)
You can find floating-point approximation of the result by using the float command:
3-205
Mathematics
float(eigenvalues)
For more information about approximating eigenvalues and eigenvectors numerically, see Numeric Eigenvalues and Eigenvectors.
3-206
The Jordan canonical form of the matrix P is a diagonal matrix with the eigenvalues on its main diagonal: linalg::eigenvalues(P); linalg::jordanForm(P)
To find the Jordan canonical form of a matrix along with the nonsingular similarity transformation matrix T that transforms the original matrix to its Jordan form, use the All option: [J, T] := linalg::jordanForm(P, All)
3-207
Mathematics
You can restore the original matrix from its Jordan form and the similarity transformation: simplify(T*J*T^(-1))
You cannot transform to a diagonal form matrices for which the number of linearly independent eigenvectors is less than the matrix dimensions. For example, the following matrix has the triple eigenvalue 2. The Jordan block corresponding to that eigenvalue has 1s on its first superdiagonal: A := matrix([[-6, 11, -15, -11], [11, -14, 22, 16], [-6, 7, -7, -7], [24, -32, 43, 34]]): linalg::jordanForm(A)
The 44 matrix A has a triple eigenvalue 2 and only two eigenvectors: linalg::eigenvectors(A)
3-208
3-209
Mathematics
Now, compute the matrix exponential for the following matrix. Simplify the result: B := matrix(2, 2, [0, 2, 2, 0]): simplify(exp(B*x))
3-210
To compute the Cholesky decomposition of a matrix, use the linalg::factorCholesky function. The result is the following lower triangular matrix: L := linalg::factorCholesky(P)
The product of the triangular matrix L and its transpose gives the original matrix P: testeq(P = L*linalg::transpose(L))
3-211
Mathematics
Note MuPAD returns a lower triangular matrix as a result of Cholesky factorization. MATLAB returns an upper triangular matrix, which is the transpose of the result returned by MuPAD. When MuPAD cannot determine whether a matrix is Hermitian, linalg::factorCholesky throws an error: A := matrix([[a, b, c], [b, c, a], [c, a, b]]): linalg::factorCholesky(A)
Error: A Hermitian matrix is expected. [linalg::factorCholesky] If you know that the matrix is Hermitian, you can suppress this error. The
NoCheck option suppresses the error and lets the linalg::factorCholesky
3-212
If you know that the matrix is real and symmetric, use the Real option to avoid complex conjugates (implied by |a| = a*) in the result: linalg::factorCholesky(A, NoCheck, Real)
3-213
Mathematics
Compute LU Factorization
The LU factorization expresses an mn matrix A as follows: P*A = L*U. Here L is an mm lower triangular matrix that contains 1s on the main diagonal, U is an mn matrix upper triangular matrix, and P is a permutation matrix. To compute the LU decomposition of a matrix, use the linalg::factorLU function. For example, compute the LU decomposition of the following square matrix: A := matrix([[0, 0, 1], [1, 2, 3], [0, 1, 2]]): [L, U, p] := linalg::factorLU(A)
Instead of returning the permutation matrix P, MuPAD returns the list p with numbers corresponding to row exchanges in the matrix A. For an nn matrix, the list p represents the following permutation matrix with indices i and j ranging from 1 to n:
. Using this expression, restore the permutation matrix P from the list p: P := matrix(3, 3): for i from 1 to 3 do P[i, p[i]] := 1 end_for: P
3-214
Compute LU Factorization
More efficiently, compute the result of applying the permutation matrix to A without restoring the permutation matrix itself: PA := matrix(3, 3): for i from 1 to 3 do PA[i, 1..3] := A[p[i], 1..3] end_for: PA
The product of the lower triangular matrix L and the upper triangular matrix U is the original matrix A with the rows interchanged according to the permutation matrix P: testeq(PA = L*U)
Now, compute the LU decomposition for the 3 2 matrix B: B := matrix([[1, 2], [3, 4], [5, 6]]): [L, U, p] := linalg::factorLU(B)
The permutation matrix for this LU factorization shows that the order of the rows does not change. Therefore, the product of the lower triangular matrix L and the upper triangular matrix U gives the original matrix A: testeq(B = L*U)
3-215
Mathematics
Compute QR Factorization
The QR factorization expresses an mn matrix A as follows: A = Q*R. Here Q is an mm unitary matrix, and R is an mn upper triangular matrix. If the components of A are real numbers, Q is an orthogonal matrix. To compute the QR decomposition of a matrix, use the linalg::factorQR function. For example, compute the QR decomposition of the 33 Pascal matrix: P := linalg::pascal(3): [Q, R] := linalg::factorQR(P)
The product of Q and R gives the original 33 Pascal matrix: testeq(P = Q*R)
Also, you can perform the QR factorization for matrices that contain complex values. In this case, the matrix Q is unitary: B := matrix([[I, -1], [1, I]]): [Q, R] := linalg::factorQR(B)
Again, the product of Q and R gives the original matrix B: testeq(B = Q*R)
3-216
Compute QR Factorization
3-217
Mathematics
When you use numeric functions, the result can be extremely sensitive to roundoff errors. For example, the determinant of a Pascal matrix of any size is 1. However, if you use the numeric::det function to compute the determinant of a 2525 Pascal matrix, you get the following incorrect result: numeric::det(linalg::pascal(15))
When computing determinants numerically, you can use the HardwareFloats and SoftwareFloats options to employ the hardware or software float arithmetic, respectively. (You can use the short names for these options: Hard and Soft.) When you use the HardwareFloats option, MuPAD converts all input data to hardware floating-point numbers, and passes the data for processing by compiled C code outside of the MuPAD session. Then, the results get back into the MuPAD session. Hardware arithmetic often allows you to perform computations much faster than software arithmetic, which uses the MuPAD kernel for performing computations. The precision of hardware arithmetic is limited to about 15 digits. By default, the numeric::det function uses the HardwareFloats option. The function switches to software arithmetic under one or more of the following conditions: You use the SoftwareFloats option or the MinorExpansion option explicitly. The current value of DIGITS is larger than 15.
3-218
The input data or computed data involves numbers that are larger than 10308 or smaller than 10- 308. Hardware floats cannot represent such numbers. The precision of hardware and software arithmetic can differ. Therefore, the results obtained with the HardwareFloats and SoftwareFloats options also can differ. For example, compute the determinant of the 25 25 Pascal matrix using each of the options. Both numeric results are several orders larger than the correct answer because of the roundoff errors. However, the result obtained using software arithmetic is several orders closer to the correct answer: P := linalg::pascal(25): detP := det(P): float(detP); numeric::det(P, SoftwareFloats); numeric::det(P, HardwareFloats)
Another example of numerically ill-conditioned matrices is the Hilbert matrices. For example, create the 2020 Hilbert matrix, compute its determinant symbolically, and then approximate the result numerically: H := linalg::hilbert(15): detH := det(H): float(detH)
Now, use the numeric::det function to compute the determinant numerically: numeric::det(H)
3-219
Mathematics
The numeric result obtained with the SoftwareFloats option is closer to the correct result: numeric::det(linalg::hilbert(15), SoftwareFloats)
To prevent the conversion of input data to floating-point numbers while using the numeric::det function, use the Symbolic option. This option allows you to compute the determinant exactly (without roundoff errors). For matrices over particular rings and fields, the determinant computed by numeric::det with the Symbolic option can differ from the determinant computed by det. The reason is that det performs computations over the component domain of the input matrix. The numeric::det function with the Symbolic option always performs computations over the field of arbitrary MuPAD expressions. For example, create the following matrix over the domain Dom::IntegerMod(5): A := Dom::Matrix(Dom::IntegerMod(5))([[1, 2], [3, 4]])
The det function computes the determinant over the component domain Dom::IntegerMod(5): det(A)
The numeric::det function with the Symbolic option computes the determinant of the following matrix instead of the original matrix A: expr(A)
3-220
The numeric::det function switches to the Symbolic option under one or more of the following conditions: You use the Symbolic option explicitly. The input data contains symbolic objects.
3-221
Mathematics
3-222
3-223
Mathematics
Numeric approximation of the result returned by the symbolic linalg::eigenvectors function gives a shorter answer that contains complex numbers: float(eigen)
If you need simple (though approximate) eigenvalues and eigenvectors of the Hilbert matrix in further computations, use numeric methods from the beginning. To approximate eigenvalues and eigenvectors of a matrix numerically, use the numeric::eigenvectors function. The function returns
3-224
eigenvalues, eigenvectors, and residues (estimated errors for the numerical eigenvalues): [eigenvalues, eigenvectors, residues] := numeric::eigenvectors(H)
Small residue values indicate that roundoff errors do not significantly affect the results. To suppress the computation of the residues, use the NoResidues option: numeric::eigenvectors(H, NoResidues)
If you want to compute only eigenvalues of a matrix, use the numeric::eigenvalues function: numeric::eigenvalues(H)
3-225
Mathematics
When computing eigenvalues and eigenvectors numerically, you can use the HardwareFloats and SoftwareFloats options to employ hardware or software float arithmetic, respectively. For information about these options, see the Numeric Determinant section. For more details, see the numeric::eigenvectors and numeric::eigenvalues help pages.
3-226
Cholesky Decomposition
The Cholesky decomposition of a Hermitian (self-adjoint) positive definite matrix is a product of a lower triangular matrix L and its Hermitian transpose LH: A = LLH. The Hermitian transpose of a matrix is the complex conjugate of its transpose. For real symmetric positive definite matrices, A = LLT, where LT is the transpose of L. You can perform the Cholesky factorization of complex matrices symbolically by using linalg::factorCholesky or numerically by using numeric::factorCholesky. For example, create the following 22 matrix: A := matrix([[sin(1), I], [-I, exp(2)]])
First, compute the Cholesky decomposition of that matrix by using the symbolic linalg::factorCholesky function: L := linalg::factorCholesky(A)
3-227
Mathematics
Now, compute the Cholesky decomposition by using the symbolic numeric::factorCholesky function: L := numeric::factorCholesky(A)
When using numeric::factorCholesky, you can prevent the conversion of data to floating-point numbers and, therefore, get the symbolic result by using the Symbolic option: L := numeric::factorCholesky(A, Symbolic)
The product of the triangular matrix L and its Hermitian transpose gives the original matrix A: testeq(A = L*htranspose(L))
LU Decomposition
LU factorization expresses an mn matrix A as a product of a lower triangular matrix L and an upper triangular matrix U: A = LU. Also, LU decomposition can involve a row permutation matrix: PA = LU. To compute the LU
3-228
decomposition of a matrix numerically, use the numeric::factorLU function. For example, create the following 44 Toeplitz matrix: T := linalg::toeplitz(4, [1, 2, 3, 4, 5])
Use the numeric::factorLU function to compute the LU decomposition of the matrix T numerically: [L, U, p] := numeric::factorLU(T)
Instead of returning the permutation matrix P, MuPAD returns the list p with numbers corresponding to row exchanges in a matrix T. For an nn matrix, the list p represents the following permutation matrix with indices i and j ranging from 1 to n:
. Using this expression, restore the permutation matrix P from the list p: P := matrix(4, 4): for i from 1 to 4 do P[i, p[i]] := 1 end_for: P
3-229
Mathematics
More efficiently, compute the result of applying the permutation matrix to A without restoring the permutation matrix itself: PT := matrix(4, 4): for i from 1 to 4 do PT[i, 1..4] := T[p[i], 1..4] end_for: PT
Within floating-point precision, the product of the lower triangular matrix L and the upper triangular matrix U is the original matrix A with the rows interchanged according to the permutation matrix P: float(PT) = L*U
The symbolic LU factorization function uses a different pivoting strategy than the numeric LU factorization function. Therefore, the symbolic function can return different results for the same matrix: linalg::factorLU(T)
3-230
QR Decomposition
The QR factorization expresses an mn matrix A as follows: A = Q*R. Here Q is an mm unitary matrix, and R is an mn upper triangular matrix. If the components of A are real numbers, Q is an orthogonal matrix. To compute the QR decomposition of a matrix numerically, use the numeric::factorQR function. For example, create the following 33 Vandermonde matrix: V := linalg::vandermonde([2, PI, 1/3])
When computing the QR decomposition of that matrix symbolically, you get the following long result: [Q, R] := linalg::factorQR(V)
3-231
Mathematics
To get a shorter answer, approximate this result by floating-point numbers: [Q, R] := float([Q, R])
3-232
You can get the same result faster by calling the numeric factorization function from the beginning: [Q, R] := numeric::factorQR(V)
Within floating-point precision, the product of Q and R gives the original 33 Vandermonde matrix V: float(V) = Q*R
are equivalent. For example, compute the singular value decomposition of the following matrix: A := matrix([[9, 4], [6, 8], [2, 7]]): svd := numeric::svd(A)
3-233
Mathematics
Instead of returning the diagonal matrix S, MuPAD returns the list d of the diagonal elements of that matrix: d := svd[2]
You can restore the matrix S from that list: S := matrix(3, 2, d, Diagonal)
The numeric::svd function also computes the residues resU and resV for the numeric singular vectors. The residues are the estimated errors for the numerical matrices U and V: res_U = svd[4]; res_V = svd[5]
3-234
Small residue values indicate that roundoff errors do not significantly affect the results. To suppress the computation of the residues, use the NoResidues option: svd := numeric::svd(A, NoResidues)
Within the floating-point precision, the product of U, S, and the Hermitian transpose of V returns the original matrix A: [U, d, V, res_U, res_V] := svd: A = U*S*conjugate(transpose(V))
3-235
Mathematics
Euler number (exponential constant, base of natural logarithm) 3.141592653 Euler-Mascheroni constant
PI EULER
CATALAN
Catalan constant
3-236
Infinities
MuPAD provides the symbolic representations for real and complex infinities. Many functions accept infinities as their arguments. For example, you can use infinities when computing sums, limits, integrals, and so on. Also, you can perform arithmetical operations with infinities. MuPAD can return infinities as results of computations:
infinity complexInfinity RD_INF RD_NINF
Real positive infinity Infinite point of the complex plane Real positive infinity used in floating-point intervals Real negative infinity used in floating-point intervals
Boolean Constants
MuPAD uses a three-state logic with the Boolean constants TRUE, FALSE, and UNKNOWN. You can use these constants in computations. MuPAD can return these constants as a result of computations.
Special Values
The following objects in MuPAD represent special values. You can use these special values in computations. MuPAD can return these values as a result of computations:
I
Imaginary unit
NIL
Null object of the domain DOM_NIL. MuPAD uses this object to indicate missing objects explicitly.
3-237
Mathematics
null()
Null (void) object of the domain DOM_NULL. This object does not produce any visible output. MuPAD removes this object from data structures (such as sequences, lists, sets, and so on). Undefined value. Undefined value used in floating-point intervals. If you use typeset mode, MuPAD displays this value as in output regions. Failure object of the domain DOM_FAIL.
undefined RD_NAN
FAIL
Special Sets
MuPAD provides the following predefined sets and lets you use them in computations. For example, you can use these predefined sets to compute intersections, differences, and unions, or to make assumptions. MuPAD can use these sets to return results of computations:
C_ N_
The set
of complex numbers
The set of positive integers: The set The set The set of rational numbers of real numbers of integers
Q_ R_ Z_
3-238
Gamma Functions
MuPAD provides the following functions to represent the -function, -function, and other related special functions. You can use these functions as input for your computations. MuPAD can return results in terms of these functions:
beta binomial gamma
3-239
Mathematics
Airy function Ai Airy function Bi Modified Bessel function of the first kind Bessel function of the first kind Modified Bessel function of the second kind Bessel function of the second kind
3-240
Cosine integral Hyperbolic cosine integral Exponential integral Sine integral Shifted sine integral Hyperbolic sine integral
Error function Complementary error function Imaginary error function Inverse of error function Inverse of complementary error function Fresnel cosine integral function Fresnel sine integral function
3-241
Mathematics
Hypergeometric function Confluent hypergeometric KummerU function Meijer G function Whittakers M function Whittakers W function
Elliptic Integrals
The following MuPAD functions represent the elliptic integrals of different kinds. You can use these functions as input for your computations. MuPAD can return results in terms of these functions:
ellipticK ellipticCK ellipticF ellipticE ellipticCE ellipticPi ellipticCPi ellipticNome
Complete elliptic integral of the first kind Complementary complete elliptic integral of the first kind Incomplete elliptic integral of the first kind Elliptic integral of the second kind Complementary complete elliptic integral of the second kind Elliptic integral of the third kind Complementary complete elliptic integral of the third kind Elliptic nome
3-242
3-243
Mathematics
Avoid unnecessary conversions to floating-point numbers. A floating-point number approximates a constant; it is not the constant itself. Using this approximation, you can get incorrect results. For example, the heaviside special function returns different results for the sine of and the sine of 10-digit floating-point approximation of : heaviside(sin(PI)), heaviside(sin(pi))
Increase Precision
The Riemann hypothesis states that all nontrivial zeros of the Riemann Zeta function have the same real part . To locate possible zeros of the . The following plot shows :
the first three nontrivial roots of the Zeta function plot(abs(zeta(1/2 + I*y)), y = 0..30, AxesTitles = ["y", "|zeta|"])
3-244
Use the numeric solver to approximate the first three zeros of this Zeta function: numeric::solve(zeta(1/2 + I*y), y = 13..15), numeric::solve(zeta(1/2 + I*y), y = 20..22), numeric::solve(zeta(1/2 + I*y), y = 24..26)
Now, consider the same function, but slightly increase the real part: . According to the Riemann hypothesis, this function does not have a zero for any real value y. By default, MuPAD uses 10 significant decimal digits for computations that involve floating-point numbers. When you use the numeric::solve solver with the default number of digits, the solver finds the following (nonexisting) zero of the Zeta function: numeric::solve(zeta(1000000001/2000000000 + I*y), y = 14..15)
3-245
Mathematics
Increasing the numbers of digits shows that the result is incorrect. The Zeta function does not have a zero at 14 < y < 15:
delete DIGITS;
3-246
Now, call the Bessel function with the floating-point parameter. Significant difference in these two approximations indicates that one or both results are incorrect: besselJ(53/2, float(PI))
Increase the numeric working precision to obtain more accurate approximations: DIGITS:= 45: float(B); besselJ(53/2, float(PI))
delete DIGITS; Now you can see that using the floating-point parameter to compute the Bessel function produces the correct result (within working precision). Approximation of the exact symbolic expression for that Bessel function returns the wrong result because of numerical instability.
3-247
Mathematics
Plot the function for the values of x around 53/2. The function plot shows that the floating-point approximation is incorrect: plot(besselJ(x, PI), x = 26..27)
Sometimes, to see that the floating-point approximation is incorrect, you must zoom the particular parts of the function plot. For example, the numeric solver finds the unexpected zero of the Zeta function: numeric::solve(zeta(1000000001/2000000000 + I*y), y = 14..15)
To investigate whether the Zeta function actually has a zero at that point or whether the result appears because of the roundoff error, plot the absolute value of Zeta function .
3-248
To see more details of the function plot near the possible zero, zoom the plot. To see that the numeric result is incorrect, enlarge that part of the function plot beyond the numeric working precision, and then reevaluate the plot. When you zoom and reevaluate, MuPAD recalculates the part of the function plot with the increased numeric precision. Note When zooming, MuPAD does not automatically reevaluate the function plot. To get accurate results after zooming the plot, use the Recalculate button . After zooming and reevaluating the plot, you can see that the function does not have a zero at that interval.
3-249
Mathematics
3-250
Integral Transforms
Integral Transforms
In this section... Fourier and Inverse Fourier Transforms on page 3-251 Laplace and Inverse Laplace Transforms on page 3-254
Here c and s are the parameters of the Fourier transform. By default, c = 1 and s = -1. Pref::fourierParameters lets you specify other values for these parameters. For the inverse Fourier transform (IFT), MuPAD uses the following definition:
To compute the Fourier transform of an arithmetical expression, use the fourier function. For example, compute the Fourier transforms of the following exponential expression and the Dirac delta distribution: fourier(exp(-t^2), t, w), fourier(dirac(t), t, w)
If you know the Fourier transform of an expression, you can find the original expression or its mathematically equivalent form by computing the inverse
3-251
Mathematics
Fourier transform. To compute the inverse Fourier transform, use the ifourier function. For example, find the original exponential expression and the Dirac delta distribution: ifourier(PI^(1/2)*exp(-w^2/4), w, t), ifourier(1, w, t)
Suppose, you compute the Fourier transform of an expression, and then compute the inverse Fourier transform of the result. In this case, MuPAD can return an expression that is mathematically equivalent to the original one, but presented in a different form. For example, compute the Fourier transforms of the following trigonometric expressions: Cosine := fourier(cos(t), t, w); Sine := fourier(sin(t^2), t, w)
Now, compute the inverse Fourier transforms of the resulting expressions Cosine and Sine. The results differ from the original expressions: invCosine := ifourier(Cosine, w, t); invSine := ifourier(Sine, w, t)
3-252
Integral Transforms
Simplifying the resulting expressions invCosine and invSine gives the original expressions: simplify(invCosine), simplify(invSine)
Besides arithmetical expressions, the fourier and ifourier functions also accept matrices of arithmetical expressions. For example, compute the Fourier transform of the following matrix: A := matrix(2, 2, [exp(-t^2), t*exp(-t^2), t^2*exp(-t^2), t^3*exp(-t^2)]): fourier(A, t, w)
The fourier and ifourier functions let you evaluate the transforms of an expression or a matrix at a particular point. For example, evaluate the Fourier transform of the matrix A for the values w = 0 and w = 2*x: fourier(A, t, 0); fourier(A, t, 2*x)
3-253
Mathematics
If MuPAD cannot compute the Fourier transform of an expression, it returns an unresolved transform: fourier(f(t), t, w)
If MuPAD cannot compute the inverse Fourier transform of an expression, it returns the result in terms of an unresolved direct Fourier transform: ifourier(F(w), w, t)
. The inverse Laplace transform is defined by a contour integral in the complex plane:
3-254
Integral Transforms
where c is a real value. To compute the Laplace transform of an arithmetical expression, use the laplace function. For example, compute the Laplace transform of the following expression: tsine := laplace(t*sin(a*t), t, s)
To compute the original expression from its Laplace transform, perform the inverse Laplace transform. To compute the inverse Laplace transform, use the ilaplace function. For example, compute the inverse Laplace transform of the resulting expression tsine: ilaplace(tsine, s, t)
Suppose, you compute the Laplace transform of an expression, and then compute the inverse Laplace transform of the result. In this case, MuPAD can return an expression that is mathematically equivalent to the original one, but presented in a different form. For example, compute the Laplace transforms of the following expression: L := laplace(t*ln(t), t, s)
Now, compute the inverse Laplace transform of the resulting expression L. The result differs from the original expression: invL := ilaplace(L, s, t)
3-255
Mathematics
simplify(invL)
Besides arithmetical expressions, the laplace and ilaplace functions also accept matrices of arithmetical expressions. For example, compute the Laplace transform of the following matrix: A := matrix(2, 2, [1, t, t^2, t^3]): laplace(A, t, s)
When computing a transform of an expression, you can use assumptions on mathematical properties of the arguments. For example, compute the Laplace transform of the Dirac delta distribution: d := laplace(dirac(t - t_0), t, s) assuming t_0 >=0
Restore the Dirac delta distribution from the resulting expression d: ilaplace(d, s, t) assuming t_0 >=0
The laplace function provides the transforms for some special functions. For example, compute the Laplace transforms of the following Bessel functions: laplace(besselJ(0, t), t, s); laplace(besselJ(1, t), t, s); laplace(besselJ(1/2, t), t, s)
3-256
Integral Transforms
The laplace and ilaplace functions let you evaluate the transforms of an expression or a matrix at a particular point. For example, evaluate the Laplace transform of the following expression for the value s = 10: laplace(t*exp(-t), t, 10)
Now, evaluate the inverse Laplace transform of the following expression for the value t = x + y: ilaplace(1/(1 + s)^2, s, x + y)
If MuPAD cannot compute the Laplace transform or the inverse Laplace transform of an expression, it returns an unresolved transform: laplace(f(t), t, s)
ilaplace(F(s), s, t)
3-257
Mathematics
3-258
Z-Transforms
Z-Transforms
The Z-transform of the function F(z) is defined as follows:
. If R is a positive number, such that the function F(Z) is analytic on and outside the circle |z| = R, then the inverse Z-transform is defined as follows:
You can consider the Z-transform as a discrete equivalent of the Laplace transform. To compute the Z-transform of an arithmetical expression, use the ztrans function. For example, compute the Z-transform of the following expression: S := ztrans(sinh(n), n, z)
If you know the Z-transform of an expression, you can find the original expression or a mathematically equivalent form by computing the inverse Z-transform. To compute the inverse Z-transform, use the iztrans function. For example, compute the inverse Z-transform of the expression S: iztrans(S, z, n)
Suppose, you compute the Z-transform of an expression, and then compute the inverse Z-transform of the result. In this case, MuPAD can return
3-259
Mathematics
an expression that is mathematically equivalent to the original one, but presented in a different form. For example, compute the Z-transform of the following expression: C := ztrans(exp(n), n, z)
Now, compute the inverse Z-transform of the resulting expression C. The result differs from the original expression: invC := iztrans(C, z, n)
Simplifying the resulting expression invC gives the original expression: simplify(invC)
Besides arithmetical expressions, the ztrans and iztrans functions also accept matrices of arithmetical expressions. For example, compute the Z-transform of the following matrix: A := matrix(2, 2, [1, n, n + 1, 2*n + 1]): ZA := ztrans(A, n, z)
3-260
Z-Transforms
iztrans(ZA, z, n)
The ztrans and iztrans functions let you evaluate the transforms of an expression or a matrix at a particular point. For example, evaluate the Z-transform of the following expression for the value z = 2: ztrans(1/n!, n, 2)
Evaluate the inverse Z-transform of the following expression for the value n = 10: iztrans(z/(z - exp(x)), z, 10)
If MuPAD cannot compute the Z-transform or the inverse Z-transform of an expression, it returns an unresolved transform: ztrans(f(n), n, z)
iztrans(F(z), z, n)
3-261
Mathematics
. The inverse discrete Fourier transform is defined as the list L of the following elements:
. MuPAD uses a fast Fourier transform (FFT) algorithm to compute the discrete and the inverse discrete Fourier transforms. For any N, the computing costs are O(Nlog2(N)). To compute the discrete Fourier transforms, use the following functions: numeric::fft to compute the Fourier transform numeric::invfft to compute the inverse Fourier transform These functions accept lists (domain type DOM_LIST), arrays (domain type DOM_ARRAY), hardware floating-point arrays (domain type DOM_HFARRAY), and matrices (category Cat::Matrix). The accepted data structures (except for lists) can be one- or multidimensional. You can use arbitrary arithmetical expressions as entries. The discrete Fourier transform is often used in signal processing. It allows you to decompose a signal into a set of periodic signals with different frequencies and to analyze those frequencies. Suppose, you have a discrete set of values of a signal sampled at a fixed rate. The signal might be periodic, but the noise effectively hides the period. For example, the following data list represents such a signal:
3-262
f1 := 150: f2 := 300: data := [sin(f1*2*PI*t/1000) + sin(f2*2*PI*t/1000) + 10*(frandom() - 1/2) $t = 0..1000]: When you plot the data, the signal seems random. The noise effectively hides the two main frequencies of the signal: plot(plot::Listplot(data, t = 0..1000), AxesTitles = ["Time", "Amplitude"], YAxisTitleOrientation = Vertical, XAxisTitleAlignment = Center, YAxisTitleAlignment = Center)
To prove that the signal has a strong periodic component and to find the main frequencies, compute the discrete Fourier transform of the signal: fft := abs(numeric::fft(data)): The plot of fft shows four peaks. The peaks correspond to the two main frequencies of the original signal (f1 = 150 and f2 = 300):
3-263
Mathematics
plot(plot::Listplot(fft, f = 0..1000), AxesTitles = ["Frequency", "Power"], YAxisTitleOrientation = Vertical, XAxisTitleAlignment = Center, YAxisTitleAlignment = Center)
The numeric::fft and numeric::invfft functions accept options. Use the Symbolic option to prevent the conversion of your data to floating-point numbers. For example, create a list of the following exact values: exactData := [sin(1/3*2*PI*n/10) $n = 0..3]
Compute the discrete Fourier transform keeping the data in its exact symbolic form: fft := numeric::fft(exactData, Symbolic)
3-264
Compute the inverse discrete Fourier transform of the resulting list. Use the numeric::invfft function with the Symbolic to prevent the data from the conversion to floating-point values: numeric::invfft(fft, Symbolic)
Also, you can clean results by removing very small terms. To discard all times the entries of the result with absolute values smaller than maximal absolute value of all operands of the result, use the Clean option. This option also removes tiny imaginary terms that often appear as a result of roundoff effects. For example, without the Symbolic option, the inverse Fourier transform from the previous example returns the following list of floating-point values: numeric::invfft(fft)
3-265
Mathematics
When you use the Clean option, the numeric::invfft function discards small terms that appear in the second and fourth entries of the resulting list: numeric::invfft(fft, Clean)
3-266
Suppose, you want to add the pattern F(s) for the Fourier transform of the function f(t). To add a new pattern for the Fourier transform, use the fourier::addpattern function: fourier::addpattern(f(t), t, s, F(s)): Now, when you compute the Fourier transform of f(t), MuPAD returns F(s): fourier(f(t), t, s)
3-267
Mathematics
MuPAD can use the new pattern indirectly: fourier(sin(t^2) + f(10*t + 33), t, s)
When you add a pattern for the Fourier transform, MuPAD does not automatically add the pattern for the inverse Fourier transform: ifourier(F(s), s, t)
To add the corresponding pattern for the inverse Fourier transform, use the ifourier::addpattern function. For example, add the pattern f(t) for the inverse Fourier transform of F(s): ifourier::addpattern(F(s), s, t, f(t)): ifourier(F(s), s, t)
Using the same method, you can add your own patterns for the Laplace transform, inverse Laplace transform, Z-transform, and inverse Z-transform. Use the following functions to add patterns for computing these transforms: laplace::addpattern to add a pattern for computing the Laplace transform ilaplace::addpattern to add a pattern for computing the inverse Laplace transform ztrans::addpattern to add a pattern for computing the Z-transform iztrans::addpattern to add a pattern for computing the inverse Z-transform
3-268
Suppose, you want to change this pattern. Use the laplace::addpattern function to replace the existing standard pattern with your custom pattern: laplace::addpattern(sinh(t), t, s, 1/2*(1/(s - 1) - 1/(s + 1))): laplace(sinh(t), t, s)
3-269
Mathematics
Supported Distributions
MuPAD supports standard continuous and discrete distributions. The system associates the following routines with each implemented distribution: A probability density function (PDF) for continuous distributions or probability function (PF) for discrete distributions A cumulative distribution function (CDF) An inverse cumulative distribution function (quantile function) A random number generator The following continuous distributions are available in MuPAD. Random Generator
CDF
Quantile
F-distribution stats::fPDF Logistic distribution Lognormal distribution Normal distribution Students t-distribution
stats::lognormalPDF stats::lognormalCDF stats::lognormalQuantile stats::lognormalRandom stats::normalPDF stats::normalCDF stats::normalQuantile stats::normalRandom stats::tPDF stats::tCDF stats::tQuantile stats::tRandom
3-270
Supported Distributions
CDF
Quantile
Random Generator
Name Binomial distribution Empirical distribution Distribution of a Finite Sample Space Geometric Distribution
PF
CDF
Quantile
Poisson Distribution
3-271
Mathematics
Import Data
If you have an external data set and want to analyze it in MuPAD, import the data to the MuPAD session. To import an ASCII data file to the MuPAD session, use the import::readdata function. Suppose, you want to analyze the world population growth and compare it to the US population growth between 1970 and 2000. The text file "WorldPopulation" contains the required data. To be able to work with the data in MuPAD, import the contents of the file line-by-line by using the import::readdata function. The function returns the following nested list: data := import::readdata("WorldPopulation")
You can convert the resulting nested list to other data structures, For example, represent the imported data as a sample. A sample is a collection of statistical data in the form of a matrix. To convert the nested list of imported data to a sample, use the stats::sample function: s := stats::sample(data)
3-272
Import Data
year 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
world(thousands) 3711962 3789539 3865804 3941551 4016056 4088612 4159763 4231510 4303134 4377497 4452548 4528882 4608682 4690278 4770468 4852052 4935874 5022023 5108860 5195713 5283687 5367185 5451672 5534138 5615311 5696677 5776857 5855087 5932091 6008255 6083550
US(thousands) 205052 207661 209896 211909 213854 215973 218035 220239 222585 225055 227726 229966 232188 234307 236348 238466 240651 242804 245021 247342 250132 253493 256894 260255 263436 266557 269667 272912 276115 279295 282172
AnnualRateWorld 2.07 1.99 1.94 1.87 1.79 1.73 1.71 1.68 1.71 1.7 1.7 1.75 1.75 1.7 1.7 1.71 1.73 1.71 1.69 1.68 1.57 1.56 1.5 1.46 1.44 1.4 1.35 1.31 1.28 1.25 1.24
AnnualRateUS 1.26 1.07 0.95 0.91 0.99 0.95 1.01 1.1 1.18 0.98 0.96 0.91 0.87 0.89 0.91 0.89 0.91 0.94 1.12 1.33 1.33 1.3 1.21 1.18 1.16 1.2 1.17 1.15 1.02 1.01 0.94
The first row in that sample contains text. The statistical functions cannot work with the text. Before you start analyzing the data, delete the first row: s := stats::sample::delRow(s, 1)
3-273
Mathematics
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
3711962 3789539 3865804 3941551 4016056 4088612 4159763 4231510 4303134 4377497 4452548 4528882 4608682 4690278 4770468 4852052 4935874 5022023 5108860 5195713 5283687 5367185 5451672 5534138 5615311 5696677 5776857 5855087 5932091 6008255 6083550
205052 207661 209896 211909 213854 215973 218035 220239 222585 225055 227726 229966 232188 234307 236348 238466 240651 242804 245021 247342 250132 253493 256894 260255 263436 266557 269667 272912 276115 279295 282172
2.07 1.99 1.94 1.87 1.79 1.73 1.71 1.68 1.71 1.7 1.7 1.75 1.75 1.7 1.7 1.71 1.73 1.71 1.69 1.68 1.57 1.56 1.5 1.46 1.44 1.4 1.35 1.31 1.28 1.25 1.24
1.26 1.07 0.95 0.91 0.99 0.95 1.01 1.1 1.18 0.98 0.96 0.91 0.87 0.89 0.91 0.89 0.91 0.94 1.12 1.33 1.33 1.3 1.21 1.18 1.16 1.2 1.17 1.15 1.02 1.01 0.94
The MuPAD statistical functions accept the resulting sample because it contains only numeric data. Now, you can analyze the sample. For example, compute the correlation between the US population and total world population stored in the second and third columns of the sample. Use the float function to approximate the result: float(stats::correlation(s, 2, 3))
3-274
Import Data
The correlation coefficient is close to 1. Therefore, the world population data and the US population data are linearly related. Now, compute the correlation coefficient for the population growth rates stored in the fourth and fifth columns of the sample. In this case, you can omit the float function. MuPAD returns a floating-point result because the input data contains floating-point numbers: stats::correlation(s, 4, 5)
The correlation coefficient indicates that the data for the world population growth rates and the data for the US population growth rates are not linearly related.
3-275
Mathematics
3-276
3-277
Mathematics
L := [1, 1, 1, 1, 1, 100.0]: S := [100, 100, 100, 100, 100, 1.0]: The stats::modal function shows that the most frequent entry of the first list is 1. The most frequent entry of the second list is 100. A most frequent entry appears in each list five times: modalL = stats::modal(L); modalS = stats::modal(S)
If the value of the outlier is large, the outlier can significantly move the mean and the quadratic mean away from the center: meanL = stats::mean(L); quadraticMeanL = stats::quadraticMean(L)
Large outliers affect the geometric mean and the harmonic mean less than they affect the simple arithmetic average. Nevertheless, both geometric and harmonic means are also not completely resistant to outliers: geometricMeanL = stats::geometricMean(L); harmonicMeanL = stats::harmonicMean(L)
3-278
If the value of the outlier is small, the impact on the mean of a data set is less noticeable. Quadratic mean can effectively mitigate the impact of a few small outliers: meanS = stats::mean(S); quadraticMeanS = stats::quadraticMean(S)
The small outlier significantly affects the geometric and harmonic means computed for the list S: geometricMeanS = stats::geometricMean(S); harmonicMeanS = stats::harmonicMean(S)
The median is usually resistant to both large and small outliers: medianL = stats::median(L); medianS = stats::median(S)
For data samples that contain an even number of elements, MuPAD can use two definitions of the median. By default, stats::median returns the n/2-th element of a sorted data sample: z := [1, 1, 1, 100, 100, 100]: medianZ = stats::median(z)
3-279
Mathematics
When you use the Averaged option, stats::median returns the arithmetic average of the two central elements of a sorted data sample: z := [1, 1, 1, 100, 100, 100]: medianZ = stats::median(z, Averaged)
Nevertheless, the median is not always the best choice for measuring central tendency of a data sample. For example, the following data sample distribution has a step in the middle: z := [1, 1, 1, 2, 100, 100, 100]: medianZ = stats::median(z)
3-280
3-281
Mathematics
The mean deviation is also sensitive to outliers. Nevertheless, the large outlier in the list x affects the mean deviation less than it affects the variance and the standard deviation: meandev = stats::meandev(L)
Now, compute the variance, the standard deviation, and the mean deviation of the list y that contains one small outlier. Again, the mean deviation is less sensitive to the outlier than the other two measures: S := [100, 100, 100, 100, 100, 100, 100, 100, 1.0]: variance = stats::variance(S); stdev = stats::stdev(S); meandev = stats::meandev(S)
3-282
, where is the arithmetic average (mean) of the data sample x1, x2, ..., xn.
, where is the arithmetic average (mean) of the data sample x1, x2, ..., xn.
The stats::moment function enables you to compute the kth moment of a data sample centered around an arbitrary value X. One of the popular measures in descriptive statistics is a central moment. The kth central moment of a data sample is the kth moment centered around the arithmetic average (mean) of that data sample. The following statements are valid for any data sample: The zero central moment is always 1. The first central moment is always 0. The second central moment is equal to the variance computed by using a divisor n, rather than n - 1 (available via the Population option of stats::variance). For example, create the lists L and S as follows:
3-283
Mathematics
L := [1, 1, 1, 1, 1, 1, 1, 1, 100.0]: S := [100, 100, 100, 100, 100, 100, 100, 100, 1.0]: Calculate the arithmetic average of each list by using the stats::mean function: meanL := stats::mean(L); meanS := stats::mean(S)
Calculate the first four central moments of the list L: stats::moment(0, stats::moment(1, stats::moment(2, stats::moment(3, meanL, meanL, meanL, meanL, L), L), L), L)
The zero and first central moments are the same for any data sample. The second central moment is the variance computed with the divisor n: stats::variance(L, Population)
Now, calculate the first four central moments of the list S: stats::moment(0, stats::moment(1, stats::moment(2, stats::moment(3, meanS, meanS, meanS, meanS, S), S), S), S)
3-284
Again, the zero central moment is 1, the first central moment is 0, and the second central moment is the variance computed with the divisor n: stats::variance(S, Population)
The obliquity (skewness) is a measure of the symmetry of a distribution. If the distribution is close to symmetrical around its mean, the value of obliquity is close to zero. Positive values of obliquity indicate that the distribution function has a longer tail to the right of the mean. Negative values indicate that the distribution function has a longer tail to the left of the mean. For example, calculate the obliquity of the lists L and S: stats::obliquity(L); stats::obliquity(S)
The kurtosis measures the flatness of a distribution. For normally distributed data, the kurtosis is zero. Negative kurtosis indicates that the distribution function has a flatter top than the normal distribution. Positive kurtosis indicates that the peak of the distribution function is sharper than it is for the normal distribution: stats::kurtosis(-2, -1, -0.5, 0, 0.5, 1, 2), stats::kurtosis(-1, 0.5, 0, 0, 0, 0, 0.5, 1)
3-285
Mathematics
sample x1, x2, ..., xn, and y1, y2, ..., yn.
sample x1, x2, ..., xn, and y1, y2, ..., yn. Create the lists x and y: x := [1, 1, 0.1]: y := [1, 2, 0.1]:
. Here is the arithmetic average of the data is the arithmetic average of the data sample
To estimate the similarity of these lists, compute their covariance. For completely uncorrelated (nonsimilar) data, the covariance is a small value. A positive covariance indicates that the data change in the same direction (increases or decreases together). A negative covariance indicates the data change in opposite directions. There are two common definitions of the covariance. By default, the stats::covariance function uses the definition with the divisor n - 1. To switch to the alternative definition, use the Population option: stats::covariance(x, y), stats::covariance(x, y, Population)
3-286
The covariance of a data sample with itself is the variance of that data sample: stats::covariance(x, x) = stats::variance(x)
The correlation of data samples indicates the degree of similarity of these data samples. For completely uncorrelated data, the value of the correlation (as well as the covariance) tends to 0. For correlated data that change in the same direction, the correlation tends to 1. For correlated data that change in the opposite directions, the correlation tends to -1. Compute the correlation of x and y: stats::correlation(x, y), stats::correlation(x, x), stats::correlation(x, -x)
3-287
Mathematics
Handle Outliers
The outliers are data points located far outside the range of the majority of the data. Glitches, data-entry errors, and inaccurate measurements can produce outliers in real data samples. The outliers can significantly affect the analysis of data samples. If you suspect that the data that you want to analyze contains outliers, you can discard the outliers or replace them with the values typical for that data sample. Before you discard or replace the outliers, try to verify that they are actual errors. The outliers can be a part of the correct data sample, and discarding them can lead you to incorrect conclusions. If you cannot determine whether the outliers are correct data or errors, the recommended strategy is to analyze the data with the outliers and without them. To discard outliers, use the stats::cutoff function. For example, discard the outliers with the values smaller than the 1/10 quantile (10th percentile) and larger than 9/10 quantile of the list x: x := [1/100, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100]: stats::cutoff(x, 1/10)
To replace the outliers with the value of a k-th quantile, use the stats::winsorize function. In the list x, replace the values of the outliers with the 10th and 90th percentiles: stats::winsorize(x, 1/10)
3-288
Bin Data
Bin Data
The stats::frequency function categorizes the numerical data into a number of bins given by semiopen intervals (ai, bi]. This function returns a table with the entries (rows) corresponding to the bins. Each entry shows the following information: The number of the bin The interval defining the bin The number of data in the bin The data contained in the bin The stats::frequency function enables you to specify the number of bins. By default, stats::frequency categorizes the data into 10 bins. For example, categorize the following data into 10 bins: x := [-10.1, -1, 1.1, 3.5, 13, 0, -5.5, 0.5, 7.9, 15, 0.15, 6.7, 2, 9]: stats::frequency(x)
3-289
Mathematics
When creating the bins, you can specify the intervals. For example, divide the data into two bins: one bin contains the numbers that are less or equal to zero, and the other bin contains the numbers that are greater than zero: stats::frequency(x, [[-infinity, 0], [0, infinity]])
For graphical interpretation of the data binning, see Create Bar Charts, Histograms, and Pie Charts on page 3-295.
3-290
By default, the plot::Scatterplot function also displays a regression line. This line shows the linear dependency that best fits the two data samples. To hide the regression line, use the LinesVisible option: plot(plot::Scatterplot(x, y, LinesVisible = FALSE))
3-291
Mathematics
Another plot that can help you identify the relationship between two discrete data samples is a list plot. List plots are convenient for plotting one data sample with equidistant x-values. They are also convenient for plotting combined data samples, such as [[x1, y1], [x2, y2], ..., [xn, yn]]. If you have two separate data samples, you can combine the data of these samples pairwise: xy := [[x[i], y[i]] $ i = 1..10]: To create a list plot, use the plot::Listplot function: plot(plot::Listplot(xy), AxesTitles = ["x", "y"])
3-292
By default, the plot::Listplot function connects adjacent points on the plot by straight lines. To hide these connections, use the LinesVisible option: plot(plot::Listplot(xy), AxesTitles = ["x", "y"], LinesVisible = FALSE)
3-293
Mathematics
3-294
Bar Charts
To compare different data samples or to show how individual elements contribute to an aggregate amount, use bar charts. A bar chart represents each element of a data sample as one bar. Bars are distributed along the horizontal or vertical axis, with each data element at a different location. To compare data samples, create a bar chart for two or more data samples. In this case, MuPAD accesses elements with the same index and plots the bars for these elements next to each other. For example, create three lists of random numbers: x := [frandom() $ i = 1..10]; y := [frandom() $ i = 1..10]; z := [frandom() $ i = 1..10]
3-295
Mathematics
To create a 2-D bar chart, use the plot::Bars2d function. The chart displays data from the data samples x, y, and z. The resulting plot shows the elements with the same index clustered together. Small gaps separate each group of elements from the previous and the next group: plot(plot::Bars2d(x, y, z))
To create a 3-D bar chart, use the plot::Bars3d function. This function accepts matrices and arrays. The function also accepts nested lists with flat inner lists. The plot::Bars3d function draws each element as a separate 3-D block. The elements of each row of an array or a matrix (or the elements of each flat list) appear along one horizontal axis. Bars that represent elements in the first column of an array or a matrix appear along the other horizontal axis. If you use a nested list, the elements of the inner lists with the same indices appear along the other horizontal axis. By default, the plot::Bars3d function does not display gaps between the groups of elements. Use the Gap option to create gaps and specify their size: plot(plot::Bars3d([x, y, z], Gap = [0.5, 0.8]))
3-296
Histograms
Histograms show the distribution of data values across a data range. They divide the data range into a certain number of intervals (bins), tabulate the number of values that fall into each bin, and plot these numbers using bars of varying height. To create a histogram, use the plot::Histogram2d function. By default, this function divides the data range into seven bins. To specify the number of bins, use the Cells option. For example, create the histogram of the following data sample categorizing the data into 10 bins: data := [-10.1, -1, 1.1, 3.5, 13, 0, -5.5, 0.5, 7.9, 15, 0.15, 6.7, 2, 9]: plot(plot::Histogram2d(data, Cells = 10))
3-297
Mathematics
Pie Charts
Pie charts can help you effectively communicate a portion (or percentage) that each element of a data sample contributes to the total number of all elements. To create a 2-D pie chart, use the plot::Piechart2d function. To create a 3-D pie chart, use the plot::Piechart3d function. A 3-D pie chart does not show any additional information. The 3-D view simply adds depth to the presentation by plotting the chart on top of a cylindrical base and lets you rotate the plot. Suppose, you need to analyze the following list of numbers: data := [-10.1, -1, 1.1, 3.5, 13, 0, -5.5, 0.5, 7.9, 15, 0.15, 6.7, 2, 9]: First, use the stats::frequency function to categorize the data into bins. (See Data Binning for more details.) T := stats::frequency(data)
3-298
The result is a table that shows the intervals (bins), number of elements in those bins, and the data elements in each bin. The plot::Piechart2d and plot::Piechart3d functions do not accept tables as arguments. They accept lists, vectors, and arrays with one row or one column. Before creating a pie chart, extract the bins and the number of elements in them into two separate tables: Counts := map(T, op, 2); Bins := map(T, op, 1)
3-299
Mathematics
Now, extract the entries from the Bins and Counts tables and create the lists containing these entries: slices := [Counts[i] $ i = 1..10]: titles := [expr2text(Bins[i]) $ i = 1..10]: Create a 2-D pie chart by using the plot::Piechart2d function. The slices list specifies the portions that each bin contributes to the total number of all elements of the data sample. The titles list specifies the titles for each piece on the pie chart: plot(plot::Piechart2d(slices, Titles = titles))
3-300
Create a 3-D pie chart from the same data by using the plot::Piechart3d function. To rotate the resulting 3-D chart, click any place on the chart, hold the mouse button and move the cursor: plot(plot::Piechart3d(slices, Titles = titles, Radius = 0.3))
3-301
Mathematics
3-302
3-303
Mathematics
The tops and bottoms of each box are the 25th and 75th percentiles of the data samples, respectively. The distances between the tops and bottoms are the interquartile ranges. The line in the middle of each box is the sample median. A median is not always in the center of the box. The median shows the sample obliquity (skewness) of the sample distribution. The lines extending above and below each box are the whiskers. Whiskers extend from the ends of the interquartile ranges to the furthest observations within the maximum whisker length. The maximum whisker length is 3/2 of the height of the central box measured from the top or bottom of the box. The data points that lay beyond the whisker lengths are the outliers. Outliers are values that are more than 3/2 times the interquartile range away from the top or bottom of the box. The Notched option enables you to create a box plot with notches. Notches display the variability of the median between samples: p := plot::Boxplot(data1, data2, Notched = TRUE): plot(p)
3-304
3-305
Mathematics
The following quantile-quantile plot clearly shows that these two data samples come from different distribution families: data1 := [stats::uniformRandom(0, 1)() $ k = 1..100]: data2 := [stats::exponentialRandom(0, 1)() $ k = 1..100]: p := plot::QQplot(data1, data2): plot(p)
3-306
3-307
Mathematics
. The function also can perform weighted least-squares linear regression that minimizes
with the positive weight wi. By default, the weights are equal to 1. Besides the slope a and the offset b of a fitted linear model, stats::linReg also returns the value of the quadratic deviation 2. For example, fit the linear model to the following data: x := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: y := [11, 13, 15, 17, 19, 21, 23, 25, 27, 29]: stats::linReg(x, y)
The linear model yi = 9 + 2xi fits this data perfectly. The quadratic error for this model is zero. To visualize the data and the resulting model, plot the data by using the plot::Scatterplot function. The plot shows the regression line yi = 9 + 2xi computed by stats::linReg:
3-308
plot(plot::Scatterplot(x, y))
When you work with experimental data samples, the data almost never completely fits any linear model. The value of the quadratic error indicates how far the actual data deviate from the fitted model. For example, modify the data from the previous example by adding small random floating-point values to the entries of the list y. Then, perform linear regression for the entries of the lists x and y1 and plot the data: y1 := y + [10*frandom() $ i = 1..10]: stats::linReg(x, y1); plot(plot::Scatterplot(x, y1))
3-309
Mathematics
The fact that stats::linReg finds a linear model to fit your data does not guarantee that the linear model is a good fit. For example, you can find a linear model to fit the following uniformly distributed random data points: x := [frandom() $ i = 1..100]: y := [frandom() $ i = 1..100]: stats::linReg(x, y); plot(plot::Scatterplot(x, y))
3-310
The large value of the quadratic error indicates that the linear model is a poor fit for these data. delete x, y, y1
3-311
Mathematics
. Here xij is the ith measurement of the independent variable xj. The stats::reg function also can perform weighted least-squares nonlinear regression. By default, weights are equal to 1.
stats::reg returns a list of optimized parameters [p1, ..., pn] and the minimized value of the quadratic error for the specified model. Suppose, you want to find a model for the following data:
sampleX := [1, 2, 3, 4, 5, 6, 7, 8, 9]: sampleY := [36.97666099, 54.14911101, 131.3852077, 30.43939553, 202.2004454, 129.5801972, 321.0663718, 411.3959961, 929.597986]: Plotting the data can help you choose the model: plot( plot::Scatterplot(sampleX, sampleY, LinesVisible = FALSE) ):
3-312
The scatter plot clearly shows that linear models do not fit the data. The dependency looks similar to exponential. Therefore you can try to fit the data to different models involving exponential functions. Suppose, you want to try fitting the data to the expression :
The stats::reg function returns the parameters of the model and the quadratic error as a nested list. To access the parameters separately, use the following commands: a := fit[1][1]; b := fit[1][2]; chi2 := fit[2]
3-313
Mathematics
Now, plot the data and expression that you used to fit the data on the same plot. This plot shows how the model expression fits the data: plot2 := plot::Function2d(a + b^2*exp(x)/x, x = 1..9): plot(plot1, plot2)
3-314
Multivariate Regression
Multivariate Regression
The stats::reg function also performs linear and nonlinear regressions with two or more independent variables. The following example demonstrates how to perform regression and fit the data to a function of two variables. Suppose, you have three data lists that contain coordinates x, y, and z of discrete points: sampleX := [ -0.9612553839, -0.329576986, 0.7544749248, 0.7339191669, -0.294101483, -0.9809519422, -0.6251624775, -0.1885706545, 0.4729466504, 0.4402179092, -0.1883574567, -0.6260246367, -0.0274947885, -0.01843922645, -0.02687538212, -0.03682895886, -0.009212115975, -0.04956242636]: sampleY := [ -0.02185415496, -0.9146217269, -0.5792023459, 0.5440822742, 0.8848317212, -0.03925037966, -0.02360776024, -0.5657632266, -0.3461422332, 0.3429495709, 0.5113552882, -0.02089004809, -0.03700165982, -0.0226531849, -0.004897297126, -0.03063832565, -0.03469956571, -0.01391540741]: sampleZ := [ 0.2755344332, 0.272077192, 0.2682296712, 0.2915713541, 0.2737466882, 0.3060314064, 0.7624231851, 0.8013891042, 0.7755723041, 0.7631156115, 0.7816602999, 0.7807856826, 0.9679031724, 0.9661527172, 0.9632260164, 0.986479402, 0.9554368723, 0.9768285979]: Suppose, you want to find the surface that fits these points. Start with plotting the data. The plot::PointList3d function, which plots a finite number of discrete points, requires the coordinates of each point to be grouped together. The following commands create separate lists for the coordinates of each point: [xi, yi, zi] and put these lists into one nested list: points := [[sampleX[i], sampleY[i], sampleZ[i]] $ i = 1..nops(sampleX)]: Now, use the plot::PointList3d function to visualize the data: plot1 := plot::PointList3d(points, PointSize = 2.5): plot(plot1)
3-315
Mathematics
Rotating the plot can help you guess which surface can possibly fit the data. This plot shows that the data can belong to the upper half of a sphere. Thus, try to fit the data to a sphere with an unknown radius r. The stats::reg function searches for the best fitting value for the parameter r: fit := stats::reg(sampleX, sampleY, sampleZ, sqrt(r^2 - x1^2 - y1^2), [x1, y1], [r])
The stats::reg function also accepts the nested list points: fit := stats::reg(points, sqrt(r^2 - x1^2 - y1^2), [x1, y1], [r])
3-316
Multivariate Regression
The stats::reg function returns the parameters of the model and the quadratic error in a form of a nested list. To access the parameters separately, use the following commands: R := op(fit)[1][1]; chi2 := op(fit)[2]
Now, plot the data and sphere that you used to fit the data on the same plot. Rotate the plot to see how the sphere fits the data: plot2 := plot::Function3d(sqrt(R^2 - x^2 - y^2), x = -1..1, y = -1..1): plot(plot1, plot2)
3-317
Mathematics
3-318
distribution. When you use the stats::csGOFT function, specify the cell boundaries as an argument. You must specify at least three cells. The recommended minimum . The recommended number of cells for a sample of n data elements is method for defining the cells is to use the stats::equiprobableCells function. This function creates equiprobable cells when the underlying distribution is continuous: q := stats::normalQuantile(0, 1/2): cells := stats::equiprobableCells(40, q): Now, call the stats::csGOFT function to test the data sequence x. For example, compare x with the cumulative normal distribution function with the same mean and variance. The stats::csGOFT returns a large p-value for this test. Therefore, the null hypothesis (x is normally distributed with
3-319
Mathematics
the mean equal to 0 and the variance equal to 1/2) passes this test. Besides the p-value, stats::csGOFT returns the observed value of the chi-square statistics and the minimum of the expected cell frequencies: stats::csGOFT(x, cells, CDF = stats::normalCDF(0, 1/2))
The stats::csGOFT enables you to test the data against any distribution function. For example, testing the sequence x against the probability density function gives the same result: stats::csGOFT(x, cells, PDF = stats::normalPDF(0, 1/2))
If you test the same data sequence x against the normal distribution function with different values of the mean and the variance, stats::csGOFT returns the p-value that is below the typical significance level 0.05. The null hypothesis does not pass the test: stats::csGOFT(x, cells, CDF = stats::normalCDF(0, 1))
3-320
Test the same sequence, but this time compare it to the normal distribution with the variance 1. Both p-values are much smaller than the significance level. The null hypothesis states that the sequence x has a normal distribution with the mean 1 and the variance 1. This hypothesis must be rejected: stats::ksGOFT(x, CDF = stats::normalCDF(1, 1))
3-321
Mathematics
3-322
Perform t-Test
Perform t-Test
The t-Test compares the actual mean value of a data sample with the specified value m. The null hypothesis for this test states that the actual mean value is larger than m. For the t-Test, MuPAD provides the stats::tTest function. For example, create the normally distributed data sequence of 1000 entries by using the stats::normalRandom function: f := stats::normalRandom(1, 2): x := f() $ k = 1..1000: Now, use the stats::tTest function to test whether the actual mean value of x is larger than 1. Use the significance level 0.05. The returned p-value indicates that the hypothesis passes the t-Test: stats::tTest(x, 1)
With the same significance level 0.05, the hypothesis that the actual mean value is larger than 2 does not pass the t-Test: stats::tTest(x, 2)
3-323
Mathematics
Divisors
In this section... Compute Divisors and Number of Divisors on page 3-324 Compute Greatest Common Divisors on page 3-325 Compute Least Common Multiples on page 3-326
To find only prime divisors of an integer, use the numlib::primedivisors function: numlib::primedivisors(12345)
To compute the number of all divisors of an integer, use the numlib::numdivisors function. To compute the number of prime divisors, use the numlib::numprimedivisors function. For example, the number 123456789987654321 has 192 divisors. Only seven of these divisors are prime numbers: numlib::numdivisors(123456789987654321), numlib::numprimedivisors(123456789987654321)
3-324
Divisors
The numlib::numprimedivisors function does not take into account multiplicities of prime divisors. This function counts a prime divisor with multiplicity as one prime divisor. To compute the sum of multiplicities of prime divisors, use the numlib::Omega function. For example, the number 27648 has 44 divisors, and 2 of them are prime numbers. The prime divisors of 27648 have multiplicities; the total sum of these multiplicities is 13: numlib::numdivisors(27648), numlib::numprimedivisors(27648), numlib::Omega(27648)
You can factor the number 27648 into prime numbers to reveal the multiplicities. To factor an integer into primes, use the ifactor function: ifactor(27648)
To compute the sum of all positive integer divisors of an integer number, use the numlib::sumdivisors function. For example, compute the sum of positive divisors of the number 12345: numlib::sumdivisors(12345)
3-325
Mathematics
The icontent function computes the greatest common divisor of the coefficients of a polynomial. All coefficients must be integers: icontent(12*x^2 + 16*x + 24)
3-326
Operate on Primes
Prime numbers are positive integers larger than 1 that have only two positive integer divisors: 1 and the number itself. In MuPAD, you can check whether the number is prime by using the isprime function. For example, 809 is a prime number while 888 and 1 are not primes: isprime(809), isprime(888), isprime(1)
In rare cases, the isprime function can return a false positive result. The function performs the Miller-Rabin primality test and uses 10 independent random bases. For a more accurate (and also slower) method, see Proving Primality. The sequence of prime numbers is infinite. It starts with 2, 3, 5, 7, 11, 13, 17, and goes on. The ithprime function lets you quickly find and display any entry of this sequence. For example, to find the 100th prime number, enter ithprime(100): ithprime(100)
To find the prime number that appears in the sequence before a particular value, use the prevprime function. To find the prime number that appears after a particular value, use the nextprime function. For example, find the prime numbers that precede and follow the number 1000:
3-327
Mathematics
prevprime(1000), nextprime(1000)
Note prevprime and nextprime use the probabilistic primality test (the Miller-Rabin test). In rare cases, these functions can return nonprime numbers. MuPAD stores a precalculated table of the prime numbers up to a certain value. The ifactor function with the PrimeLimit option returns that value: ifactor(PrimeLimit)
The ithprime function with the PrimeLimit option returns the number of primes in that table: ithprime(PrimeLimit)
The ithprime function extracts the prime number from this table. To compute larger prime numbers (which MuPAD does not store in the table), ithprime chooses some number as a starting point, and then recursively calls the nextprime function. Although the internal algorithm tries to reduce the number of computation steps, computing huge prime numbers can be very slow: ithprime(100000000)
3-328
Suppose, you want to display a sequence of prime numbers. For the numbers that MuPAD stores in the table, call the ithprime function to find each number in the sequence: ithprime(i) $ i = 1000..1010
If the numbers exceed the value returned by ifactor(PrimeLimit), MuPAD does not store them. In this case, calling ithprime for each number can be very slow. More efficiently, use ithprime to find the first number in the sequence, and then use nextprime to find all following numbers: (n := ithprime(3*10^7)), (n := nextprime(n + 1)) $i = 1..10
To find how many prime numbers do not exceed a particular value, use the numlib::pi function: numlib::pi(2), numlib::pi(3), numlib::pi(20), numlib::pi(1000), numlib::pi(15.789)
Factorizations
You can represent any integer number as a product of primes. This process is called factoring an integer. To factor an integer, use the ifactor function. For example, factor the number 362880: ifactor(362880)
3-329
Mathematics
Prove Primality
The function numlib::proveprime implements the Atkin-Goldwasser-Kilian-Morain algorithm for proving primality. For information about primality proving and this particular algorithm, see the following papers: Atkin, A. O., and F. Morain. Elliptic curves and primality proving. Mathematics of Computation. Vol. 61, Number 203, 1993. Goldwasser, S., and J. Kilian. Almost all primes can be quickly certified. Proceedings of the 18th annual ACM symposium on theory of computing. Berkeley, CA, US, 1986, pp. 316-329. For relatively small prime numbers, numlib::proveprime returns the value TRUE. For composite numbers, the function returns FALSE: numlib::proveprime(541), numlib::proveprime(243)
For larger prime numbers, numlib::proveprime returns a certificate of primality: certificate := numlib::proveprime(1299709)
Generated primality certificates provide all data that you need for proving primality of a number by the Atkin-Goldwasser-Kilian-Morain algorithm. You can substitute the numbers into the algorithm and verify the primality of a number. The numlib::checkPrimalityCertificate function can verify the certificate for you: numlib::checkPrimalityCertificate(certificate)
3-330
Modular Arithmetic
Modular Arithmetic
In this section... Quotients and Remainders on page 3-331 Common Modular Arithmetic Operations on page 3-333 Residue Class Rings and Fields on page 3-334
MuPAD supports two definitions of the remainder of a division. The first definition states that the remainder is always a nonnegative number. To compute the remainder by this definition, use the positive modulo function modp or the default modulo operator mod: 123 mod 5, modp(123, 5)
The symmetric modulo function mods implements the alternative definition of the remainder of a division. This definition allows the remainder to be negative. The symmetric modulo function compares the absolute values of the negative and the positive remainders, and returns the remainder that has the least absolute value: mods(122, 5), mods(123, 5)
3-331
Mathematics
You can redefine the modulo operator mod by assigning mods or modp to mod: 123 mod 5; _mod := mods: 123 mod 5
Redefining the modulo operator mod does not affect the div function that computes the quotient. The div function always computes the quotient by assuming that the remainder must be nonnegative: 123 div 5, 123 mod 5
For further computations, restore the default behavior of the modulo operator: _mod := modp: Now, suppose that the number is represented as ab, where a and b are integers. Suppose, you want to compute the modular power of ab over c, which is the remainder of the division of ab by an integer c. You can compute the modular power by using the modulo operator mod: 987^124 mod 12
When you use the mod operator to compute the modular power, MuPAD performs computations in two steps. First, the system computes the power of an integer, and then it divides the result and finds the remainder. This approach works if both the number and its power are small. However, if the
3-332
Modular Arithmetic
numbers are large, the first step (computing the power of an integer) can be extremely slow. To avoid this step, use the powermod function. This function computes the modular power more efficiently, especially for large numbers: powermod(987, 124, 12), powermod(987, 123456789, 12)
The numlib::order function computes the order of a residue class. For an integer a and a positive integer n, this function returns the least number k, such that ak 1(mod n). For example, compute the order of the residue class of 3 in the unit group modulo 7: numlib::order(3, 7)
3-333
Mathematics
The Eulers totient function of an integer n counts all positive integers that satisfy the following two conditions: The integer is coprime to n. The integer is smaller or equal to n. The Eulers totient function returns the number of such integers. To compute the Eulers totient function in MuPAD, use the numlib::phi function: numlib::phi(i) $ i = 1..20
For other modular arithmetic functions available in MuPAD, see the numlib library.
Z11:= Dom::IntegerMod(11)
Now, create the elements a and b of this ring. Then, compute the sum of a and b: a:= Z11(1); b:= Z11(6); a + b
3-334
Modular Arithmetic
You can use Dom::IntegerMod to specify polynomials over a coefficient ring. When computing the coefficients of a polynomial, Dom::IntegerMod(7) uses the positive modulo function modp: poly([[9, 3], [13, 1]], [x], Dom::IntegerMod(11))
For specifying polynomials over a residue class ring n, the poly function also provides the IntMod option. This option enables you to create a polynomial with the coefficients that belong to the IntMod(n) ring. Here n is an integer greater than 1. Mathematically, this ring coincides with Dom::IntegerMod(n). However, MuPAD operates differently on the polynomials created over IntMod(n) and the polynomials created over Dom::IntegerMod(n). In particular, MuPAD performs arithmetic operations for polynomials over the IntMod ring faster. Also, if you use IntMod(n), MuPAD uses the symmetric modulo function mods: poly([[9, 3], [13, 1]], [x], IntMod(11))
The domain Dom::GaloisField enables you to create the residue class field , which is a finite field with pn elements. If you do not specify f, MuPAD randomly chooses f from all irreducible polynomials of the degree n. For more information, see the Dom::GaloisField help page.
3-335
Mathematics
Congruences
In this section... Linear Congruences on page 3-336 Systems of Linear Congruences on page 3-337 Modular Square Roots on page 3-338 General Solver for Congruences on page 3-342
Linear Congruences
If a, b, and m are integers, and (a - b)/m is also an integer, then the numbers a and b are congruent modulo m. The remainder of the division a/m is equal to the remainder of the division of b/m. For example, 11 5(mod 3): 5 mod 3 = 11 mod 3
For known integers a and m, all integers b, such that a b(mod m), form a residue class. Thus, the numbers 5 and 11 belong to the same residue class modulo 3. The numbers 5 + 3n, where n is an integer, also belong to this residue class. Suppose, you want to solve an equation ax b(mod m), where a, b, and m are integers and x is an unknown integer. Such equations are called linear congruence equations. To solve a linear congruence equation, use the
numlib::lincongruence function. This function returns only the solutions x < m. For example, solve the linear congruence equation 56x 77(mod 49):
A linear congruence equation ax b(mod m) has at least one solution if and only if the parameters a, b, and m satisfy the following condition: b 0(mod gcd(a, m)). If the parameters of a linear congruence equation do not
3-336
Congruences
satisfy this condition, the equation does not have a solution. In this case, numlib::lincongruence returns FAIL: numlib::lincongruence(56, 77, 48)
You can divide a rational number u/v modulo an integer m, and compute the remainder of such a division. Here u and v are nonzero coprime integers. The modulo operator computes an integral solution r of the linear congruence vr u(mod m). For example, compute the remainder of the division of the rational number 3/7 modulo 1231: r := 3/7 mod 1231
To reconstruct a linear congruence from the modulus m and the remainder r, use the numlib::reconstructRational(r, m) function call. For m = 1231 and r = 528, the numlib::reconstructRational function returns the coefficients of the linear congruence 7r 3(mod 1231): numlib::reconstructRational(528, 1231)
3-337
Mathematics
The Chinese remainder theorem does not state that the system of linear congruences is solvable only if numbers m1,... mn are pairwise coprime. If these numbers are not pairwise coprime, the system still can have a solution. Even if the numbers are not pairwise coprime, the solution is still unique up to multiples of the least common multiple (ilcm) of m1, m2, ..., mn: numlib::ichrem([5, 7, 9, 6], [10, 11, 12, 13])
If the numbers are not pairwise coprime, a system of linear congruences does not always have a solution. For unsolvable systems, numlib::ichrem returns FAIL: numlib::ichrem([5, 1, 9, 6], [10, 15, 12, 13])
If the congruence does not have any solutions, numlib::msqrts returns an empty set: numlib::msqrts(10, 17)
3-338
Congruences
Error: Arguments must be relative prime. [numlib::msqrts] If numlib::msqrts cannot solve a congruence, try using the numlib::mroots function. For more information, see General Solver for Congruences.
-1
MuPAD implements the Legendre symbol as the numlib::legendre function. If, and only if, the congruence x2 a(mod m) is solvable, the Legendre symbol is equal to 1: numlib::legendre(12, 13)
numlib::msqrts(12, 13)
3-339
Mathematics
If, and only if, the congruence x2 a(mod m) does not have any solutions, the Legendre symbol is equal to -1: numlib::legendre(11, 13)
numlib::msqrts(11, 13)
If a and m are not coprime, the Legendre symbol is equal to 0. In this case, numlib::legendre function returns 0, and numlib::msqrts errors: numlib::legendre(13, 13)
numlib::msqrts(13, 13)
Error: Arguments must be relative prime. [numlib::msqrts] You can compute the Legendre symbol only if the modulus is a prime number. If a congruence has a nonprime odd modulus, you can compute the Jacobi symbol. The Jacobi symbol determines the unsolvable congruences x2 a(mod m). You cannot compute the Jacobi symbol if the modulus is an even number. The following table demonstrates the dependency between the value of the Jacobi symbol and the solvability of the congruence:
3-340
Congruences
The congruence... Might have solutions Cannot be solved by numlib::msqrts. Try numlib::mroots. Has no solutions
-1
MuPAD implements the Jacobi symbol as the numlib::jacobi function. If the Jacobi symbol is equal to -1, the congruence does not have a solution: numlib::jacobi(19, 21)
numlib::msqrts(19, 21)
If Jacobi symbol is equal to 1, the congruence might have solutions: numlib::jacobi(16, 21)
numlib::msqrts(16, 21)
However, the value 1 of the Jacobi symbol does not guarantee that the congruence has solutions. For example, the following congruence does not have any solutions: numlib::jacobi(20, 21)
3-341
Mathematics
numlib::msqrts(20, 21)
If a and m are not coprime, the Jacobi symbol is equal to 0. In this case, numlib::jacobi function returns 0, and numlib::msqrts errors: numlib::jacobi(18, 21)
numlib::msqrts(18, 21)
Now, use the numlib::mroots function to solve the congruence: numlib::mroots(p, 299)
3-342
Congruences
Using the numlib::mroots function, you also can solve the congruence for a multivariate polynomial. For a multivariate polynomial P( x1, ..., xn), numlib::mroots returns a nested list as a result. Each inner list contains one solution x1, ..., xn. For example, find modular roots of the following multivariate polynomial: p := poly(x^3*y^2 + x^2*y + x + y + 1): numlib::mroots(p, 11)
3-343
Mathematics
Sequences of Numbers
In this section... Fibonacci Numbers on page 3-344 Mersenne Primes on page 3-344 Continued Fractions on page 3-345
Fibonacci Numbers
The Fibonacci numbers are a sequence of integers. The following recursion formula defines the nth Fibonacci number:
To compute the Fibonacci numbers, use the numlib::fibonacci function. For example, the first 10 Fibonacci numbers are: numlib::fibonacci(n) $ n = 0..9
Mersenne Primes
The Mersenne numbers are the prime numbers 2p - 1. Here p is also a prime. The numlib::mersenne function returns the list that contains the following currently known Mersenne numbers: numlib::mersenne()
3-344
Sequences of Numbers
Continued Fractions
The continued fraction approximation of a real number r is an expansion of the following form:
Here a1 is the integer floor(r), and a2, a3, ... are positive integers. To create a continued fraction approximation of a real number, use the
numlib::contfrac function. For example, approximate the number
Alternatively, you can use the more general contfrac function. This function belongs to the standard library. While numlib::contfrac accept only real numbers as parameters, contfrac also accepts symbolic expressions. When working with real numbers, contfrac internally calls numlib::contfrac, and returns the result of the domain type numlib::contfrac: a := contfrac(123456/123456789); domtype(a)
3-345
Mathematics
Since contfrac internally calls numlib::contfrac, calling the numlib::contfrac directly can speed up your computations.
3-346
4
Programming Fundamentals
Data Type Definition on page 4-3 Choose Appropriate Data Structures on page 4-6 Convert Data Types on page 4-8 Define Your Own Data Types on page 4-15 Access Arguments of a Procedure on page 4-19 Test Arguments on page 4-22 Verify Options on page 4-28 Debug MuPAD Code in the Tracing Mode on page 4-32 Display Progress on page 4-36 Use Assertions on page 4-39 Write Error and Warning Messages on page 4-41 Handle Errors on page 4-43 When to Analyze Performance on page 4-47 Measure Time on page 4-48 Profile Your Code on page 4-52 Techniques for Improving Performance on page 4-63 Display Memory Usage on page 4-65 Remember Mechanism on page 4-70 History Mechanism on page 4-79
Programming Fundamentals
Why Test Your Code on page 4-85 Write Single Tests on page 4-87 Write Test Scripts on page 4-91 Code Verification on page 4-95 Protect Function and Option Names on page 4-97 Data Collection on page 4-99 Visualize Expression Trees on page 4-107 Modify Subexpressions on page 4-110 Variables Inside Procedures on page 4-116 Utility Functions on page 4-121 Private Methods on page 4-125 Calls by Reference and Calls by Value on page 4-127 Integrate Custom Functions into MuPAD on page 4-134
4-2
Domain Types
MuPAD stores all objects as elements of particular domains. There are two types of domains in MuPAD: basic domains and library domains. The system includes the basic domains written in C++. The names of the basic domains start with DOM_. For example, the domain of integers DOM_INT, the domain of rational numbers DOM_RAT, and the domain of identifiers DOM_IDENT are basic domains. Most of the basic domains available in MuPAD are listed in Basic Domains. The system also includes library domains, such as the domain Dom::Matrix() of matrices, the domain Dom::ArithmeticalExpression of arithmetical expressions, the domain Dom::Interval of floating-point intervals, and the domain stats::sample of statistical samples. Many library domains are listed in Library Domains. Other library domains are listed in the corresponding libraries. For example, you can find the library domain solvelib::BasicSet of the basic infinite sets under the Utilities for the Solver category. The library domains are written in the MuPAD programming language. You also can create your own library domains. Overloading works differently for the basic domains and the library domains. The system can overload any method of a library domain. For basic domains, the system overloads only some methods.
Expression Types
The basic domain DOM_EXPR includes MuPAD expressions, such as expressions created by arithmetical or indexed operators, statements, and function calls. MuPAD classifies the elements of the domain DOM_EXPR further by defining expression types. Expression types provide more detailed information about a particular expression. For example, you might want to know whether the expression is an arithmetical expression, such as a sum or a product, a
4-3
Programming Fundamentals
Boolean expression, a function call, or some other type of expression. For these expressions, the domtype function returns their domain type DOM_EXPR: domtype(a + b), domtype(a*b), domtype(a and b), domtype(sin(a)), domtype(a = b)
To find the expression types of these expressions, use the type function: type(a + b), type(a*b), type(a and b), type(sin(a)), type(a = b)
If an operator or a function has a type slot, the type function returns the string value stored in that slot. For example, the type slot of the addition operator contains the string value _plus, the type slot of the multiplication operator contains _mult, the type slot of the sine function contains sin, and so on. An expression can include more than one operator. Typically, MuPAD associates the expression type of such expressions with the lowest precedence operator. If you visualize an expression as an expression tree, the lowest precedence operator appears at the root of that tree. See Visualizing Expression Trees for more information. For example, consider the expression a + b*c. When evaluating this expression, the system performs multiplication, and then performs addition. Therefore, the addition operator is the lowest precedence operator in the expression. This operator determines the expression type: type(a + b*c)
4-4
If the lowest precedence operator in the expression does not have a type slot, the type function returns the string function: type(f(a^2 + a + 2))
The domtype and type functions return the same results for elements of most MuPAD domains: domtype(5/7), type(5/7); domtype(1.2345), type(1.2345); domtype(a), type(a);
If your code relies on the assumption that an object belongs to a particular domain type or expression type, verify that assumption before executing the code. To test whether a MuPAD object belongs to a particular type, use the testtype function. Use this function to test both domain types and expression types: testtype(a + b, DOM_EXPR), testtype(a + b, "_plus")
4-5
Programming Fundamentals
When choosing a data structure for a new object, try to answer these questions: Which features are essential to the new object? For example, some structures keep the initial order of elements, while other structures can change the order. Another example is that you can create multidimensional arrays, but you cannot create MuPAD matrices with more than two dimensions. Which functions do you want to use on that object? Each MuPAD function accepts only objects of particular domain types. If an object that you pass to a function is not one of the acceptable domain types for that function, the function issues an error. To determine the domain types
4-6
acceptable for a particular function, see the help page for that function. For example, you cannot use standard mathematical operations for MuPAD arrays. If you already created an object, and then realized that it must belong to another domain type, try to convert the domain type of the object. See Converting Data Types.
4-7
Programming Fundamentals
4-8
Note If you implement a new domain, consider implementing the conversion methods for that domain.
domtype(L), domtype(S)
Results of the conversion can depend on the original domain type. For example, create an array and a matrix with the same number of elements and equal dimensions: M := matrix(2, 3, [1, 2, 3, 4, 5, 6]); A := array(1..2, 1..3, [1, 2, 3, 4, 5, 6])
Verify that matrix M belongs to the domain Dom::Matrix(), and array A belongs to the domain DOM_ARRAY:
4-9
Programming Fundamentals
domtype(M), domtype(A)
Use the coerce function to convert both objects to elements of the domain DOM_LIST. The coerce function converts matrix M to a nested list, where the inner lists represent the rows of the original matrix. At the same time, coerce converts the array A to a flat list: LM := coerce(M, DOM_LIST); LA := coerce(A, DOM_LIST)
Both new objects belong to the basic domain of lists DOM_LIST: domtype(LM), domtype(LA)
For further computations, delete the identifiers L, S, M, A, LM, and LA: delete L, S, M, A, LM, LA
4-10
y := poly(x); expr(y)
The original object y belongs to the domain of polynomials. The result of conversion belongs to the domain of identifiers DOM_IDENT: domtype(y), domtype(expr(y))
If you call the expr function for a more complicated polynomial, the function converts that polynomial to the expression: p := poly(x^2 + x + 2); expr(p)
Again, the original polynomial belongs to the domain of polynomials. This time, the result of the conversion belongs to the domain of expressions: domtype(p), domtype(expr(p))
MuPAD can apply the expr function to an object recursively. If an object contains terms that belong to library domains or complicated basic domains, expr also tries to convert those terms elements of simpler basic domains. For example, if the polynomial p is an element of a list, applying the expr function to the list converts the polynomial p to the expression:
4-11
Programming Fundamentals
The expr function converts a matrix of the library domain Dom::Matrix() to an array of the basic kernel domain DOM_ARRAY: M := matrix(2, 3, [1, 2, 3, 4, 5, 6])
domtype(M), domtype(expr(M))
The expr function converts an element of the series domain to the expression of a basic domain DOM_EXPR. Typically, the order of terms in the resulting expression changes: s := series(exp(x), x); expr(s)
domtype(s), domtype(expr(s))
4-12
Use Constructors
Instead of calling the conversion functions, you can use the constructor of a domain to which you want to convert an object. This approach works for most conversions, but it can fail in some cases. Calling the constructor of the required domain is often the simplest way to convert an object to the element of that domain. Suppose you want to convert the following list L to a matrix: L := [1, 2, 3, 4, 5, 6]
To convert a list to a matrix, call the matrix constructor matrix. Use the arguments of the matrix constructor to specify the dimensions of the required matrix and the list L of the elements of a matrix. The resulting object is the 23 matrix of the domain Dom::Matrix(): matrix(2, 3, L); domtype(%)
Alternatively, you can convert a list to a matrix by using Dom::Matrix(): Dom::Matrix()(2, 3, L); domtype(%)
4-13
Programming Fundamentals
4-14
To verify that the object x belongs to the domain TempF, use the testtype function. You can also use the domtype or type function: testtype(x, TempF), domtype(x), type(x)
Suppose you want the new method of the domain TempF to check whether an input argument is a valid temperature measurement. In this case, redefine the new method for your domain TempF: TempF::new := t -> if testtype(t, Type::Real) then
4-15
Programming Fundamentals
if t >= -459.67 then new(dom, t); else error("Temperature is below absolute zero."); end_if; else error("Expecting a real number above absolute zero."); end_if: The redefined method checks that an input argument is a number. It also checks that the provided temperature is not below absolute zero. Absolute zero is zero degrees on the Kelvin temperature scale, which is equivalent to -459.67 degrees on the Fahrenheit scale. The redefined method creates new elements in degrees Fahrenheit. Call the method TempF::new directly or use the shorter syntax TempF(newElement): TempF::new(0), TempF(32)
The TempF::new method also ensures that all new elements represent valid temperatures: TempF(-500)
Error: Temperature is below absolute zero. [TempF::new] The TempF::new method requires new elements to be real numbers: TempF(x + 2)
TempF(1 + 2*I)
4-16
Error: Expecting a real number above absolute zero. [TempF::new] As a next step, improve the output format for the elements of your new domain. To change the format that MuPAD uses for displaying the elements of a domain, redefine the print method for that domain. For example, when displaying elements of the domain TempF::new, show temperature measurements followed by the units of measurements (degrees Fahrenheit): TempF::print := proc(TempF) begin expr2text(extop(TempF, 1)).Symbol::deg."F" end_proc: Now, MuPAD displays the elements of the domain TempF::new as follows: TempF(32), TempF(72), TempF(90), TempF(104.8)
Suppose you want to perform additions for the elements of the new domain. By default, arithmetical operations treat the elements of a new domain as identifiers: TempF(75) + TempF(10)
You can implement arithmetical operations for your domain. For example, define addition for the domain TempF. The result of addition must also belong to the domain TempF: TempF::_plus := proc() local elements; begin elements:= map([args()], op, 1); new(TempF, _plus(op(elements))) end_proc:
4-17
Programming Fundamentals
The system add the elements of your new domain the same way as it adds numbers. The system also displays the degrees Fahrenheit unit for the resulting sum: TempF(75) + TempF(10)
4-18
Also, you can access the whole sequence of arguments or any subsequence of that sequence. For example, the following procedure prints all arguments used in the current call. If the current call uses three or more arguments, the procedure also prints its first three arguments:
4-19
Programming Fundamentals
g := proc() begin print(Unquoted, "all arguments" = args()): if args(0) > 2 then print(Unquoted, "first three arguments" = args(1..3)): else print(Unquoted, "not enough arguments"): end_if end_proc: Call the procedure g with five arguments: g(10, 20, 30, 40, 50)
first three arguments = (10, 20, 30) When you pass arguments to a procedure, MuPAD evaluates these arguments. Then the system creates a local variable for each formal parameter specified in the procedure definition. The system assigns evaluated arguments to these local variables. Parameters outside the procedure do not change. For example, assign a new value to a formal parameter inside the procedure: h := proc(a) begin a := b; print(args()): end_proc: Assigning a new value to a formal parameter inside a procedure does not affect the parameter itself. This assignment affects the result returned by args. For example, if you pass any argument to the procedure h, that argument changes to a variable b inside the procedure: h(100)
4-20
The formal parameter a does not change its value outside the procedure: a
4-21
Programming Fundamentals
Test Arguments
In this section... Check Types of Arguments on page 4-22 Check Arguments of Individual Procedures on page 4-24
The system compares the type of the formal parameter k and the type of an argument passed to the procedure. If the first argument that you pass to the procedure f is not an integer, MuPAD issues an error: f(2/3)
Error: The type of argument number 1 must be 'DOM_INT'. The object '2 Evaluating: f
4-22
Test Arguments
During a typical procedure call, for example a call to the solve or int function, MuPAD internally calls many other procedures. Testing argument types for each internal procedure call is computationally expensive. To provide better performance, MuPAD reduces the amount of type checks in the running code. By default, the system checks the types of arguments only in those procedures that you call interactively. If one procedure internally calls another procedure, MuPAD does not check types of the arguments of the internally called procedure. For example, create the following procedure g as a wrapper for the procedure f: g := proc(n:Type::Numeric) begin f(n) end_proc: MuPAD performs type checks only for the arguments of the procedure g, which you call interactively. It does not perform type checks for the arguments of the procedure f: g(2/3)
The Pref::typeCheck function enables you to control type checking of procedure arguments. This function affects all procedures. It does not allow you to control type checking for individual procedures. The default setting of Pref::typeCheck is Interactive: Pref::typeCheck()
To perform type checks in all procedure calls, including internal calls, set the value of Pref::typeCheck to Always: Pref::typeCheck(Always): Now, the system realizes that 2/3 is not a valid argument of the internally called procedure f: g(2/3)
4-23
Programming Fundamentals
Error: The type of argument number 1 must be 'DOM_INT'. The object '2 Evaluating: f To disable type checks in all procedure calls, including interactive calls, set the value of Pref::typeCheck to None: Pref::typeCheck(None): Now, the system does not check argument types in any procedure calls: g(2/3), f(2/3)
To restore the default setting of Pref::typeCheck, use the NIL option: Pref::typeCheck(NIL):
p := proc(x:Dom::Real) begin if abs(x) > 1 then error("invalid number. Choose a value from the interval [-1,1].") end_if; arcsin(x) end_proc:
4-24
Test Arguments
Typically, when you call one MuPAD procedure, that procedure internally calls other MuPAD procedures. Some of these internal calls are multiple calls to the same procedure with different sets of arguments. Testing arguments for each internal procedure call can become computationally expensive. By default, the system uses the following general principle for testing arguments of a typical MuPAD procedure: If you call a procedure interactively, the procedure performs all argument checks. If one procedure internally calls another procedure, the second procedure skips argument checks. Currently, the procedure p always checks whether the value of its argument belongs to the interval [-1,1]. To follow the general principle for testing arguments, the procedure must be able to recognize internal and interactive calls, and skip argument checking when a call is internal. For this task, MuPAD provides the testargs function. When you call testargs inside an interactive procedure call, testargs returns the value TRUE. For internal procedure calls, testargs returns the value FALSE by default. For example, rewrite your procedure p as follows:
p := proc(x) begin if testargs() then if abs(x) > 1 then error("invalid number. Choose a value from the interval [-1,1]. end_if; end_if; arcsin(x) end_proc: When you call the procedure p, it checks whether the input argument belongs to the specified interval: p(1/2), p(1), p(0)
4-25
Programming Fundamentals
p(10)
Error: invalid number. Choose a value from the interval [-1,1]. [p] Now, write the simple wrapper procedure f that calls the procedure p: f := proc(x) begin p(x) end_proc: When the wrapper procedure f calls p, the procedure p does not check its arguments because testargs returns the value FALSE: f(10)
The testargs function also allows you to switch to the argument checking mode. In this mode, MuPAD checks arguments of all procedures, regardless of how a procedure is called. This mode can slow down your computations. Use this mode only for debugging your code. To switch to the argument checking mode, set the value of testargs to TRUE: testargs(TRUE): In the argument checking mode, the procedure p checks its argument during interactive and internal calls: p(10)
Error: invalid number. Choose a value from the interval [-1,1]. [p]
f(10)
Error: invalid number. Choose a value from the interval [-1,1]. [p]
4-26
Test Arguments
Always restore testargs to its default value FALSE after you finish debugging: testargs(FALSE):
4-27
Programming Fundamentals
Verify Options
For many standard MuPAD procedures, you can use different options. If a MuPAD procedure accepts options, it has an embedded mechanism for collecting and verifying these options. For example, the solve function accepts the Real option. The option indicates that the solver must return only real solutions and accepts the values TRUE and FALSE. If an option accepts only TRUE and FALSE values, you can provide the option name without specifying its value: solve(x^4 - 1 = 0, x, Real)
If you do not specify the Real option, the solver uses the default option value FALSE, and returns all complex solutions of the equation: solve(x^4 - 1 = 0, x)
You can explicitly specify the option-value pair, for example, Real = TRUE or Real = FALSE: solve(x^4 - 1 = 0, x, Real = TRUE); solve(x^4 - 1 = 0, x, Real = FALSE)
If you provide an unexpected option (for example, if you spell the option name incorrectly), MuPAD issues an error indicating the wrong option. If there are several wrong options, MuPAD indicates the first wrong option: solve(x^4 - 1 = 0, x, Rea, Rel)
4-28
Verify Options
Error: The argument number 3 is invalid. Evaluating: solvelib::getOptions You can embed the same option checking mechanism in your own procedures. For this task, MuPAD provides the prog::getOptions function, which collects and verifies options used during a procedure call. When a user calls your procedure, prog::getOptions scans all arguments and returns a table that contains all expected options and their values. It also returns a list of all unexpected options. When you pass arguments to prog::getOptions, always use the following order. The first argument of prog::getOptions is the number n + 1, where n is the number of required (non-optional) arguments of the procedure. Then you must provide the list of all actual arguments followed by the table of all acceptable options and their default values. To access a sequence of all arguments of a procedure call, including required arguments and options, use the args function. The following example demonstrates the procedure that accepts the numeric coefficients a, b, and c and solves the quadratic equation ax2 + bx + c = 0 using these coefficients. The procedure solveQuadraticEqn requires the user to provide three numeric values. Therefore, if you embed prog::getOptions into this procedure, the first parameter of prog::getOptions must be the number 4. The procedure also accepts the optional argument PositiveOnly. If the value of PositiveOnly is TRUE, the procedure returns only positive solutions of the quadratic equation. If the value is FALSE, the procedure returns all solutions. The following function call to prog::getOptions sets the default option value PositiveOnly = FALSE: solveQuadraticEqn := proc(a:Type::Numeric, b:Type::Numeric, c:Type::Numeric) local options, S; begin options := prog::getOptions(4, [args()], table(PositiveOnly = FALSE)); S := solve(a*x^2 + b*x + c = 0, x); if options[1][PositiveOnly] = TRUE then S := select(S, testtype, Type::Positive)
4-29
Programming Fundamentals
end_if: return(S) end_proc: If you call solveQuadraticEqn without the PositiveOnly option, the procedure returns all solutions of the quadratic equation: solveQuadraticEqn(2, 3, -9)
If you use the PositiveOnly option, the procedure returns only positive solutions: solveQuadraticEqn(2, 3, -9, PositiveOnly)
By default, prog::getOptions does not error when it finds an unexpected option (an option that is not listed in the table of accepted options). Instead, it collects all unexpected options and returns them in a separate list. Thus, the procedure solveQuadraticEqn does not issue an error when you spell the option name incorrectly: solveQuadraticEqn(2, 3, -9, Positive)
The prog::getOptions function can issue an error when it finds an unexpected option. In a function call to prog::getOptions, the fourth argument indicates whether prog::getOptions must silently collect unexpected options or issue an error. This argument is optional. By default, it is set to FALSE. To issue an error instead of listing unexpected arguments, use TRUE as the fourth argument of prog::getOptions: solveQuadraticEqn := proc(a:Type::Numeric, b:Type::Numeric,
4-30
Verify Options
c:Type::Numeric) local options, S; begin options := prog::getOptions(4, [args()], table(PositiveOnly = FALSE), TRUE); S := solve(a*x^2 + b*x + c = 0, x); if options[1][PositiveOnly] = TRUE then S := select(S, testtype, Type::Positive) end_if: return(S) end_proc: Now, the procedure solveQuadraticEqn issues an error. The error message indicates the wrong option: solveQuadraticEqn(2, 3, -9, Positive)
4-31
Programming Fundamentals
Although MuPAD does not provide a function that computes the Lucas numbers, writing your own procedure for this task is easy: lucas:= proc(n:Type::PosInt) begin if n = 1 then 1 elif n = 2 then 3 else lucas(n - 1) + lucas(n - 2) end_if end_proc: The procedure call lucas(n) returns the nth Lucas number. For example, display the first 10 Lucas numbers:
4-32
lucas(n) $ n = 1..10
Suppose you want to trace this procedure. To switch execution of a particular procedure, domain, method, or function environment to the tracing mode, use the prog::trace function. For example, to trace the lucas procedure, enter: prog::trace(lucas): Now, if you call the lucas procedure, the trace mechanism observes every step of the procedure call and generates the report for that call: lucas(5) enter lucas(5) enter lucas(4) enter lucas(3) enter lucas(2) computed 3 enter lucas(1) computed 1 computed 4 enter lucas(2) computed 3 computed 7 enter lucas(3) enter lucas(2) computed 3 enter lucas(1) computed 1 computed 4 computed 11
The prog::traced() function call returns the names of all currently traced procedures, domains, methods, and function environments:
4-33
Programming Fundamentals
prog::traced()
By using different options of the prog::trace function, you can customize generated reports. Most of these options are independent of a particular procedure call. They affect all reports generated after you use an option. See the prog::trace help page for more details. If a procedure uses many nested procedure calls, the generated report for that procedure can be very long. To limit the number of nested procedure calls in a report, use the Depth option of prog::trace: prog::trace(Depth = 2): lucas(5) enter lucas(5) enter lucas(4) computed 7 enter lucas(3) computed 4 computed 11
The Depth option affects all reports generated for further calls to procedures, domains, methods, and function environments. If you do not want to use this option for further calls, set its value to 0. The value 0 indicates that prog::trace must display all nested calls: prog::trace(Depth = 0): To display memory usage in each step of the procedure call, use the Mem option: prog::trace(Mem): lucas(5)
4-34
enter lucas(5) [mem: 5636064] enter lucas(4) [mem: 5636544] enter lucas(3) [mem: 5636944] enter lucas(2) [mem: 5637344] computed 3 [mem: 5637060] enter lucas(1) [mem: 5637424] computed 1 [mem: 5637140] computed 4 [mem: 5636756] enter lucas(2) [mem: 5637120] computed 3 [mem: 5636836] computed 7 [mem: 5636356] enter lucas(3) [mem: 5636720] enter lucas(2) [mem: 5637120] computed 3 [mem: 5636836] enter lucas(1) [mem: 5637200] computed 1 [mem: 5636916] computed 4 [mem: 5636532] computed 11 [mem: 5636052]
To stop using the Mem option for further calls, set its value to FALSE: prog::trace(Mem = FALSE): To stop tracing calls to the lucas procedure, use the prog::untrace function: prog::untrace():
4-35
Programming Fundamentals
Display Progress
By default, MuPAD procedures do not show progress information or comments on run time. For example, create the following procedure that returns the sign of an input number. (MuPAD provides the standard function sign for this task.) S := proc(z:Type::Numeric) begin if not(testtype(z, Dom::Real)) then z/abs(z) elif z > 0 then 1 elif z < 0 then -1 else 0 end_if end_proc: When you execute this procedure, it returns only the final result: S(10)
Typically, the final result is all that your users want to see. However, if executing a procedure takes a long time or if users can benefit from the comments on some procedure steps, you can extend the procedure to include additional information. To embed the progress information into your procedure, use the print function. For example, modify the procedure S so it reports its progress:
S := proc(z:Type::Numeric) begin print(Unquoted, "Is ".expr2text(z)." a real number?"); if not(testtype(z, Dom::Real)) then print(Unquoted, expr2text(z)." is a complex number. Computing the z/abs(z);
4-36
Display Progress
else print(Unquoted, expr2text(z)." is a real number"); print(Unquoted, "Is ".expr2text(z)." a positive number?"); if z > 0 then print(Unquoted, expr2text(z)." is a positive number"); 1 else print(Unquoted, expr2text(z)." is not a positive number"); print(Unquoted, "Is ".expr2text(z)." a negative number?"); if z < 0 then print(Unquoted, expr2text(z)." is a negative number"); -1 else print(Unquoted, expr2text(z)." is not a negative number"); print(Unquoted, expr2text(z)." is zero."); 0 end_if end_if end_if end_proc: Now the procedure S displays the status messages: S(0)
Is 0 a real number?
0 is a real number
Is 0 a positive number?
4-37
Programming Fundamentals
Is 0 a negative number?
0 is zero.
4-38
Use Assertions
Use Assertions
If you rely on correctness of particular statements for your code, then consider including these statements in the code. Such statements are called assertions. Assertions help you remember specific conditions under which you expected to execute your code. They can also help other developers who might need to review or update your code. MuPAD lets you use checked assertions. If you switch to a special mode of executing your code, the system evaluates assertions during run time. If an assertion does not evaluate to TRUE, the system stops code execution and throws an error. For example, this procedure solves the equation sin(x) + cos(x) = a2. Suppose you get the parameter a as a result of some computations, and you expect the to be always valid. Relying on this condition, you expect the condition solutions to be real. Specify this condition as an assertion by using assert: f := proc(a) begin assert(a^2 <= sqrt(2)); s := solve(sin(x) + cos(x) = a^2) end: Assertions are checked only when you run your code in a special mode called the argument checking mode. Otherwise, the system ignores all assertions. For example, in this procedure call, MuPAD skips the assertion and returns the following complex result: f(4/3)
4-39
Programming Fundamentals
To switch to the argument checking mode, set the value of testargs to TRUE: testargs(TRUE): Now when you call the procedure f, MuPAD checks the assertion. For a = 4/3, the assertion evaluates to FALSE, and the procedure execution stops with the error: f(4/3)
Error: Assertion 'a^2 <= sqrt(2)' has failed. [f] For a = 1, the assertion evaluates to TRUE. The procedure call runs to completion, and returns the following set of real solutions: f(1)
The argument checking mode can slow down your computations. Use this mode only for debugging your code. Always restore testargs to its default value FALSE after you finish debugging: testargs(FALSE):
4-40
4-41
Programming Fundamentals
monthNumberToName(12)
If you call monthNumberToName with an integer greater than 12, the procedure terminates with the specified error: monthNumberToName(13)
Error: Invalid number. The number must not exceed 12. [monthNumberToN Warning messages help you inform your users about potential problems in the algorithm. These problems are typically minor and do not interfere with the execution of a procedure. For example, you can warn your users about limited functionality of a procedure or about implicit assumptions made by a procedure. The following procedure uses the simplify function to simplify the fraction. The function implicitly assumes that the variable x is not equal to a. If your procedure uses the simplify function, you can add the following warning for your users: simplifyW := proc(a) begin warning("Assuming x <> ".expr2text(a)); simplify((x^2 - a^2)/(x - a)) end: Now, your procedure informs its users about the assumption: simplifyW(10)
4-42
Handle Errors
Handle Errors
Typically, when a MuPAD procedure encounters an error caused by evaluation of an object, the procedure terminates, the system returns to an interactive level and displays an error message. If you want to avoid terminating a procedure, use the traperror function to catch an error. The traperror function returns the error number instead of the error itself. Later, you can reproduce the error by using the lasterror function. This function produces the last error that occurred in the current MuPAD session. If you call lasterror inside a statement or a procedure, it terminates that statement or procedure. If you want to display the error message without throwing the error itself, save the error number returned by traperror, and then retrieve the message by using the getlasterror function. For example, the function f throws an error when sin(k) is equal to zero: f := (k) -> 1/sin(PI*k)
f(1)
Error: Division by zero. [_invert] Evaluating: f Suppose you want to compute f for the values - k increasing the value of k by in each step. To call the function f for all required values, create the for loop. When you try to execute this statement, it terminates as soon as the function f encounters division by zero for the first time. To avoid terminating the for statement, use the traperror function to catch the error. To display the text of that error message without interrupting execution of the for statement, use getlasterror(): for k from -1 to 1 step 1/4 do err := traperror(f(k)):
4-43
Programming Fundamentals
if err = 0 then print(Unquoted, "k = ".expr2text(k), "f = ".expr2text(f(k))) else print(Unquoted, "k = ".expr2text(k), getlasterror()) end_if end_for
k = -3/4, f = -2^(1/2)
k = -1/2, f = -1
k = -1/4, f = -2^(1/2)
k = 1/4, f = 2^(1/2)
k = 1/2, f = 1
k = 3/4, f = 2^(1/2)
4-44
Handle Errors
k = 1, [1025, Error: Division by zero. [_invert]] Evaluating: f For errors created with the error function, including your custom error messages, traperror always returns the error code 1028. If an error message with the code 1028 is the last error message that occurred in a MuPAD session, you can retrieve that error message by using lasterror or getlasterror. For example, create the procedure g that computes the factorial of any number less than 10. If you pass a number greater than 10 to this procedure, the procedure reduces the number to 10, and then computes the factorial: g := proc(n:Type::PosInt) local test; begin test := proc() begin if n > 10 then error("The number must not exceed 10.") end_if end_proc: if traperror(test(n)) <> 0 then g(n - 1) else n! end_if; end_proc: Call the procedure with the number 100. During run time, the procedure encounters the error, but does not terminate. It also does not display the error message. Instead, it returns the result: g(100)
To retrieve and display the error message caught during execution of the procedure g, use the lasterror function:
4-45
Programming Fundamentals
lasterror()
Error: The number must not exceed 10. [test] To display the error code and the text of that message, use the getlasterror function: g(100): getlasterror()
4-46
4-47
Programming Fundamentals
Measure Time
In this section... Calls to MuPAD Processes on page 4-48 Calls to External Processes on page 4-51
4-48
Measure Time
Call the procedure f 1000 times to check if each number from 1 to 1000 appears in that matrix: g := proc() begin f(M, matrixSize, i) $ i = 1..1000 end_proc: This algorithm is very inefficient for the specified task. The function f performs 104 computation steps to find out that an integer does not occur in the matrix M. Since you call the function f 1000 times, executing this algorithm takes a long time: time(g()) 62435.902 In this example, the bottleneck of the chosen approach is obviously the algorithm that accesses each matrix element. To accelerate the computation, rewrite the procedure f using the bisection method. Before using this method, convert the matrix M to a list and sort the list. Then select the first and last elements of the sorted list as initial points. Each step in this algorithm divides the list of elements at the midpoint: f := proc(M, n, x) begin if (M[1] - x)*(M[n] - x) > 0 then return(FALSE) elif (M[1] - x)*(M[n] - x) = 0 then return(TRUE); else a := 1: b := n: while (b - a > 1) do if is(b - a, Type::Odd) then c := a + (b - a + 1)/2 else c := a + (b - a)/2 end_if; if M[c] - x = 0 then return(TRUE)
4-49
Programming Fundamentals
elif (M[a] - x)*(M[c] - x) < 0 then b := c: else a := c: end_if; end_while; end_if; return(FALSE) end_proc: Use the op function to access all elements of the matrix M. This function returns a sequence of elements. Use brackets to convert this sequence to a list. Then use the sort function to sort the list in ascending order. Finally, call the procedure f for each integer from 1 to 1000: g := proc() local M1; begin M1 := sort([op(M)]): f(M1, matrixSize^2, i) $ i = 1..1000 end_proc: Using the bisection method instead of accessing each matrix element significantly improves the performance of the example: time(g()) 3724.233 Typically, the best approach is to use the appropriate MuPAD functions whenever possible. For example, to improve performance further, rewrite the code using the MuPAD function has. Also, converting a matrix to a set can reduce the number of elements. (MuPAD removes duplicate elements of a set.) In addition to speed up, this approach makes your code significantly shorter and easier to read: g := proc() local M1; begin M1 := {op(M)}:
4-50
Measure Time
has(M1, i) $ i = 1..1000 end_proc: In this case, execution time is even shorter than for the code that implements the bisectional method: time(g()) 1508.094
4-51
Programming Fundamentals
4-52
for k from 1 to n do if M[j, k] = x then return(TRUE) end_if end_for end_for; return(FALSE) end_proc: Use the linalg::randomMatrix to create a 10001000 matrix of random integers: matrixSize := 1000: M := linalg::randomMatrix(matrixSize, matrixSize, Dom::Integer): Then call the procedure f 1000 times to check if each number from 1 to 1000 appears in that matrix: g := proc() begin f(M, matrixSize, i) $ i = 1..1000 end_proc: Measuring the time needed to run the procedure g shows that the procedure requires optimization. Although the performance bottleneck in this procedure is obvious, it is not always easy to identify performance bottlenecks in more complicated procedures. The time function does not indicate where the procedure spends most of its execution time: time(g()) 62023.876 To obtain the complete profiling report that shows timings for all inner function calls, use prog::profile: prog::profile(g()): percent usage of all
4-53
Programming Fundamentals
| | | call | |
time self per single call | | time self | time children per single
| time children
| | |
| | |
calls/normal exit
| | calls/remember exit
| | |
| | | | |
calls/e
19.7 .
. 5460.3
21689.3 3019825
[2]
Dom::Integer::coerce
16.7 .
18373.1
77616.9
3019825
[3]
(Dom::Matr
4-54
12.7 96.0
[4]
5.0 .
5460.3
3019825
[5]
Dom::Int
. 8.0
8.0
109974.9
109974.9
[6]
---------------------------------------------------------------------
index %time
self
children
called
[index] name
8.0
109974.8
[6]
[3] [1]
(Dom::Matrix(Dom::Int
[2]
---------------------------------------------------------------------
4-55
Programming Fundamentals
[1]
5460.346
3019825
[5]
Dom::Integer::convert
--------------------------------------------------------------------18373.13 [4] [3] 77616.89 f 16.7 18373.13 3019825 (Dom::Matrix(Dom::Integer))::_index 50467.24 27149.65 3019825 (Dom::Matrix(Dom::Integer))::_index_intern 77616.89 3019825
[1]
18373.13
77616.89
3019825
[3]
(Dom::Matrix(Dom::Int
[2]
[5]
5.0
5460.346
3019825
Dom::Integer::convert
---------------------------------------------------------------------
4-56
[6] 1 g
0.0
8.0
109974.8
95990.02
--------------------------------------------------------------------Time sum: 109982.873 ms Top rows of the profiling report indicate that the procedure spends most of its time accessing each matrix element. To improve performance, rewrite the procedure so that it can access fewer elements of a matrix in each call to the procedure f. For example, use the algorithm based on the bisection method: f := proc(M, n, x) begin if (M[1] - x)*(M[n] - x) > 0 then return(FALSE) elif (M[1] - x)*(M[n] - x) = 0 then return(TRUE); else a := 1: b := n: while (b - a > 1) do if is(b - a, Type::Odd) then c := a + (b - a + 1)/2 else c := a + (b - a)/2 end_if; if M[c] - x = 0 then return(TRUE) elif (M[a] - x)*(M[c] - x) < 0 then b := c: else a := c: end_if; end_while; end_if; return(FALSE) end_proc:
4-57
Programming Fundamentals
Before calling the procedure f, you must convert the matrix M to a list and sort that list. Sorting the list that contains 104 entries is an expensive operation. Depending on the number of calls to the procedure f, this operation can potentially eliminate the increase in performance that you gain by improving the procedure f itself: g := proc() local M1; begin M1 := sort([op(M)]): f(M1, matrixSize^2, i) $ i = 1..1000 end_proc: For these particular matrix size and number of calls to f, implementing the bisectional algorithm is still efficient despite the time required to sort the list: time(g()) 3840.24 The profiling report shows that the procedure spends most of the time executing the op and g function calls. This is because implementation of the bisection algorithm added new expensive operations in g (conversion of a matrix to a list and then sorting the list). The profiling report generated for the procedure call g() is very long. This example shows only the top of the report: prog::profile(g()): percent usage of all | | | call | | | | time children time self per single call | | time self | time children per single
4-58
| | calls/remember exit
--------------------------------------------------------------------56.1 1 33.0 1 6.1 1000 3.2 1000 1.5 1000 0.1 2 . 2 2180.1 2180.1 . . [1] g 1704.1 1704.1
0.1 124.0 . . . [4] `p -> [coeff(p, All)][2..-1]` 0.1 60.0 . . . [5] `l -> l.[Rzero $ r - nops(l)]` 2.0 . [6] . . 4.0 . . Dom::Integer::hasProp . . . DomainConstructor::hasProp
[7]
4-59
Programming Fundamentals
. .
9981
. .
[8]
. is
---------------------------------------------------------------------
The recommended approach for improving performance of your code is to use the MuPAD functions when possible. For example, MuPAD provides the has function for checking whether one MuPAD object contains another MuPAD object. Rewrite your code using the has function and combining the procedures f and g: g := proc() local M1; begin M1 := {op(M)}: has(M1, i) $ i = 1..1000 end_proc: This procedure also converts the matrix M to a set. Converting a matrix to a set can reduce the number of elements. (MuPAD removes duplicate elements of a set.) The execution time for the procedure call g() is the shortest among the three implementations: time(g()) 1520.095 The profiling report shows that the procedure spends most of its execution time accessing the 10001000 matrix of random integers and converting it to a set. This example shows only the top of the profiling report: prog::profile(g()): percent usage of all | time self per single call
4-60
| | call | | | | | | | | | | | | |
| |
| | time children
| |
calls/normal exit |
| | calls/remember exit
| |
calls/errors
--------------------------------------------------------------------78.9 1228.1 1 . . [1] 9.0 [2] 8.2 [3] 3.9 [4] . 140.0 g 0.1 128.0 . `p -> [coeff(p, All)][2..-1]` 0.1 60.0 . `l -> l.[Rzero $ r - nops(l)]` . . . . 1000 . 1228.1 188.0 188.0 (Dom::Matrix(Dom::Integer))::op 140.0 1416.1 1416.1 1 .
1000
4-61
Programming Fundamentals
[5] . [6]
Dom::Integer::hasProp . . . DomainConstructor::hasProp . 2 .
---------------------------------------------------------------------
4-62
4-63
Programming Fundamentals
Avoid creating large symbolic matrices and dense matrices when possible. For details about improving performance when working with matrices, see Using Sparse and Dense Matrices. Avoid using for loops to create a sequence, a flat list, a string and similar data structures by appending new entries. Instead, use the sequence generator $. Use for loops as outer loops when creating deep nested structures. Use the sequence generator $ for inner loops. Use the remember mechanism if you call a procedure with the same arguments more than once. The remember mechanism lets you avoid unnecessary reevaluations. See Remember Mechanism. At the same time, avoid using the remember mechanism for nonrecurring procedure calls, especially if the arguments are numerical. Avoid storing lots of data in the history table. If you suspect that the history table uses a significant amount of memory, clear the history table or reset the engine. For information about the history table, see History Mechanism. Avoid running large background processes, including additional MuPAD sessions, at the same time as you execute code in MuPAD.
4-64
If the engine is not connected to your notebook, the status bar displays Not Connected. For more information about the status bar, see Viewing Status Information. Note When you perform computations in several MuPAD notebooks, each notebook starts its own engine. In this case, watch for the total amount of memory used by all MuPAD engines (the mupkern.exe processes).
4-65
Programming Fundamentals
[used=167852k, reserved=168579k, seconds=30] [used=294614k, reserved=295370k, seconds=60] [used=421376k, reserved= seconds=90] If you increase the value of Pref::report to 6, MuPAD prints the status messages more frequently: Pref::report(6): sort([random() $ i = 1..10^7]): [used=84035k, reserved=84661k, seconds=10] [used=126987k, reserved=127664k, seconds=21] seconds=32] [used=212892k, reserved=213537k, reserved=256540k, seconds=54] [used=298797k, [used=341749k, reserved=342413k, seconds=76] seconds=87] [used=427654k, reserved=428352k, reserved=471355k, seconds=109]
[used=169940k, reserved= seconds=43] [used=255844 reserved=299476k, second [used=384701k, reserved= seconds=98] [used=470606
4-66
Every time you execute this example, MuPAD adds a new list of 107 random numbers and stores that list in the history table. By default, the history table contains up to 20 elements. While this list remains in the history table, MuPAD cannot release the memory needed to store 107 integers. To release this memory, use one of these alternatives: Continue computations waiting until MuPAD writes 20 new elements to the history table. Performing computations with a reduced amount of available memory can be very slow. Terminate the MuPAD engine connected to the notebook by selecting Notebook > Disconnect. The new engine starts when you evaluate any command in the notebook. Clear the history table by setting the value of variable HISTORY to 0. This variable specifies the maximum number of elements in the history table. To restore the default value of HISTORY, enter delete HISTORY: HISTORY := 0: delete HISTORY: HISTORY
For more information about the history mechanism in MuPAD, see History Mechanism. For further computations, also restore the default value of Pref::report: Pref::report(NIL):
4-67
Programming Fundamentals
begin J := append(J, n); if n = 1 then return(J) end_if: if testtype(n, Type::Even) then juggler(floor(n^(1/2))) else juggler(floor(n^(3/2))) end_if end_proc: Suppose you want to see the memory usage report for every call to this procedure. First call the prog::trace function with the Mem option. Then switch execution of the juggler procedure to the tracing mode: prog::trace(Mem): prog::trace(juggler) Now when you call the juggler procedure, the tracing report shows the memory usage for each call to juggler: J := []: juggler(7)
enter juggler(7) [mem: 5338408] enter juggler(18) [mem: 5373600] ente juggler(4) [mem: 5374080] enter juggler(2) [mem: 5374584] enter juggler(1) [mem: 5375064] computed [7, 18, 4, 2, 1] [mem: 5375032] computed [7, 18, 4, 2, 1] [mem: 5374648] computed [7, 18, 4, 2, 1] [mem: 5374264] computed [7, 18, 4, 2, 1] [mem: 5373880] computed [7, 18, 4, 2, 1] [mem: 5373524] The Mem option is independent of the traced procedure. Now if you use prog::trace to trace any other procedure, prog::trace displays memory usage in every step of that procedure. Remove this global option for further computations: prog::trace(Mem = FALSE)
4-68
To stop tracing the juggler procedure, use the prog::untrace function: prog::untrace(juggler):
4-69
Programming Fundamentals
Remember Mechanism
In this section... Why Use the Remember Mechanism on page 4-70 Remember Results Without Context on page 4-72 Remember Results and Context on page 4-73 Clear Remember Tables on page 4-74 Potential Problems Related to the Remember Mechanism on page 4-77
The following recursive procedure returns any Lucas number: lucas:= proc(n:Type::PosInt) begin
4-70
Remember Mechanism
if n = 1 then 1 elif n = 2 then 3 else lucas(n - 1) + lucas(n - 2) end_if end_proc: However, if the value n is large, computing the nth Lucas number can be very slow. The number of required procedure calls is exponential. Often, the procedure calls itself with the same arguments, and it reevaluates the result in every call: time(lucas(35))
Using the remember mechanism eliminates these reevaluations. To enable the remember mechanism for a particular procedure, use the prog::remember function. This function returns a modified copy of a procedure that stores results of previous calls in the remember table: lucas := prog::remember(lucas): When you call this procedure, MuPAD accesses the remember table. If the system finds the required entry in the remember table, it returns remembered results immediately. Now, MuPAD computes the 35th and even the 100th Lucas number almost instantly: time(lucas(35)), time(lucas(100))
Alternatively, you can enable the remember mechanism for a particular procedure by using the option remember for that procedure. For example, use the option remember to enable the remember mechanism for the procedure lucas:
4-71
Programming Fundamentals
lucas:= proc(n:Type::PosInt) option remember; begin if n = 1 then 1 elif n = 2 then 3 else lucas(n - 1) + lucas(n - 2) end_if end_proc: For further computations, delete the procedure lucas: delete lucas:
Now increase the number of digits to 50. Then call the function f with the argument 3 again. By default, MuPAD does not realize that you increased
4-72
Remember Mechanism
the required accuracy. The system accesses the remember table, finds the entry that corresponds to the argument 3, and returns the result previously computed for that argument. Since MuPAD must display the output with 50 digits, the last digits in the displayed result are incorrect: DIGITS := 50: f(3)
For further computations, restore the default value of DIGITS and delete f: delete DIGITS, f
4-73
Programming Fundamentals
f := prog::remember(f, () -> [property::depends(args()), DIGITS]): The default number of significant digits for floating-point numbers is 10. Use the function f to compute the reciprocal of 3. The system displays the result with the 10-digits accuracy: f(3)
If you set the number of digits to 50, and then call the function f with the same argument 3, prog::remember realizes that the number of digits has changed. Instead of returning the previous result stored in the remember table, the system reevaluates the result and updates the remember table: DIGITS := 50: f(3)
For further computations, restore the default value of DIGITS and delete f: delete DIGITS, f
4-74
Remember Mechanism
f := prog::remember(f): Now compute the Heaviside function for the values -10, 0, and 10. MuPAD uses the value heaviside(0)=1/2: f(-10), f(0), f(10)
You can define a different value for heaviside(0). First, use the unprotect function to be able to overwrite the value of heaviside. Then, assign the new value to heaviside(0): unprotect(heaviside): heaviside(0):= 0: Despite the new value heaviside(0) = 0, the wrapper procedure f returns the old value 1/2: f(0)
The result of the procedure call f(0) does not change because the system does not reevaluate this result. It finds the result in the remember table of the procedure f and returns that result. To display the content of the remember table, call the wrapper procedure f with the Remember option as a first argument and the Print option as a second argument. The value 106 in the second column is the value of MAXEFFORT used during computations. f(Remember, Print)
4-75
Programming Fundamentals
To force reevaluation of the procedure calls of f, clear the remember table of that procedure. To clear the remember table, call f with the Remember option as a first argument and the Clear option as a second argument: f(Remember, Clear): Now f returns the correct result: f(0)
If you use the option remember, you also can clear the remember table and force reevaluation. For example, rewrite the procedure f as follows: f := proc(x) option remember; begin heaviside(x) end: f(0)
Now restore the heaviside function to its default definition: heaviside(0):= 1/2: To clear a remember table created by the option remember, use the forget function:
4-76
Remember Mechanism
forget(f): f(0)
Use the protect function with the ProtectLevelError option to prevent further changes to heaviside. Also, delete the procedure f: protect(heaviside, ProtectLevelError): delete f
4-77
Programming Fundamentals
the remember table can be necessary when a procedure changes global variables or if global variables affect the results of a procedure. See Clearing Remember Tables. Many predefined MuPAD functions have special values stored in their remember tables. Therefore, clearing the remember tables of predefined MuPAD functions is not recommended. Note that the forget function does not error when you call it for a predefined MuPAD function.
4-78
History Mechanism
History Mechanism
In this section... Access the History Table on page 4-79 Specify Maximum Number of Entries on page 4-82 Clear the History Table on page 4-83
4-79
Programming Fundamentals
To access the computed factorial of 30, use the function call last(3) or the shorter call %3: last(3)
Note When you call the last or history function, MuPAD adds the result of that call to the history table. Calling the last function or its shortcut % inserts a new entry in the history table. Thus, the history table now contains the results of the following evaluations: 10!, 20!, 30!, and %3 (which in this example is equal to 10!). If you call the last function with the argument 3 again, the system displays the result of evaluation of 20!: last(3)
To access the most recent entry of the history table, you can use the shortcut % without parameters. For example, solve the following equation, and then simplify the result. Note that using % lets you avoid assigning the result of a solution to an identifier: solve(log(2, x) + log(2, 5) = x + 5, x);
simplify(%)
4-80
History Mechanism
The last function does not evaluate results. The last function also returns the results for which you used colons to suppress the outputs: hold(2 + 2): %
The history function displays both the result and the command that produced that result. This function counts the entries of the history table from the first result obtained in the current MuPAD session. Thus, when you use the history function, the most recent result is the last entry of the history table. In this section, the first entry of the history table is the computation of the factorial of 10: history(1)
To find the current number of entries in the history table, call the history function without an argument: history()
You can use the history function to access the most recent computation and its result: a := 2: history(history())
4-81
Programming Fundamentals
For the following statements, the history mechanism depends on whether you call the statement interactively or within a procedure: for, repeat, and while loops if and case conditional statements procedure definitions These statements are called compound statements. At the interactive level, MuPAD stores compound statements as one unit. In procedures, MuPAD stores the statements found within a compound statement in a separate history table of the procedure. In this case, the system does not store the compound statement itself.
To change the maximum number of entries in the history table for the current MuPAD session, assign the new value to HISTORY: HISTORY := 2: Now MuPAD stores only the two most recent commands and their results in the history table: a := 1: b := 2: c := 3: %1, %2; %3
4-82
History Mechanism
Note Within a procedure, the maximum number of entries in the local history table of the procedure is always 3, independent of the value of HISTORY. For further computations, restore the default maximum number entries in the history table: delete HISTORY: HISTORY
4-83
Programming Fundamentals
For further computations, restore the default maximum number entries in the history table: delete HISTORY: HISTORY
If the history table already contains a memory-consuming result, to release the memory you also can clear the history table by setting the value of HISTORY to 0. Alternatively, you can wait until the MuPAD fills the history table with new entries. Also, you can select Notebook > Disconnect to restart the MuPAD engine.
4-84
Suppose you decide to keep the procedure f as it is. It works for equal complex arguments. The error only occurs when the complex arguments are not equal. Later, you or somebody else forgets about the issue with complex numbers, but sees that the procedure can be improved as follows:
4-85
Programming Fundamentals
f := proc(a:Type::Numeric, b:Type::Numeric) begin if a >= b then return(a) else return(b) end_if end_proc: This code looks shorter, and takes advantage of the >= operator. However, if some users relied on the procedure f to recognize equal complex numbers, their code breaks when they use the updated version: f(I, I)
Error: Cannot evaluate to Boolean. [_leequal] Evaluating: f If you do not create and use a test script for the procedure f, you might never realize that the procedure stopped working for the particular choices of arguments. Even if you tested this choice of arguments before, you might forget to test it for the updated version. Writing a test script and running it every time when you (or somebody else) update your code helps to avoid unexpected loss in functionality.
4-86
Near line: 1 If the error is expected, you can rewrite the test using the TrapError option:
4-87
Programming Fundamentals
prog::test(f(2*I, I), TrapError = 1003) When you call prog::test, MuPAD evaluates actual and expected results before comparing them: prog::test(f(x^2 | x = 2, 5), 2*2) Error in test 4 Input: f(x^2 | x = 2, 5) Expected: Got: 4 5
Near line: 1 Evaluation of actual and expected results can take a long time. To avoid long evaluations, the prog::test function lets you specify the time limit for evaluation of the test. To limit the evaluation time for a particular test, use the Timeout option of the prog::test function. For example, set the time limit to 2 seconds: prog::test(f([i! $ i = 1..1000000], [i! $ i = 1..1000000]), [i! $ i = 1..1000000], Timeout = 2) Error in test interactive 5 Input: f([i! $ i = 1..100000], [i! $ i = 1..100001]) Expected: FAIL Got: TrapError = [1320, "Error: Execution time exceeded"] Timeout: 2.0 (5.106*prog::ntime())
4-88
In this example, the time limit measurement depends on your hardware configuration. The test report also shows the hardware-independent time in terms of the prog::ntime function. By default, prog::test tests the strict equality between actual and expected results. Testing equality of floating-point values can be confusing when the display precision differs from the internal precision. In this case, different floating-point numbers can look identical. Thus, with the default values of DIGITS and Pref::outputDigits, the floating-point approximation of 1/3 and the number 0.3333333333 look identical: prog::test(float(1/3), 0.3333333333) Error in test 5 Input: float(1/3) Expected: Got: 0.3333333333 0.3333333333
Near line: 1 Internally, MuPAD uses more than 10 digits to approximate 1/3 with the floating-point number. The system adds guard digits for increased precision. To see how many guard digits the system uses, increase the number of output digits using the Pref::outputDigits function. Then, test the equality of the numbers again: Pref::outputDigits(20): prog::test(float(1/3), 0.3333333333) Error in test 6 Input: float(1/3) Expected: Got: 0.3333333333 0.33333333333333333304
4-89
Programming Fundamentals
Near line: 2 When you test equality of floating-point numbers, it can be helpful to test the approximate equality. The approximate equality operator in MuPAD is ~=. The corresponding function is _approx. The prog::test function lets you choose the method for comparing actual and expected results. For example, 1/3 is approximately equal to 0.3333333333 within the default 10-digits precision: prog::test(float(1/3), 0.3333333333, Method= `~=`) Also, using the Method option lets you specify more than one acceptable solution. For example, if you randomly pick one solution of the following equation, you can get any of its four valid solutions: i := random(1..4): prog::test(solve(x^4 - 16 = 0, x)[i()], {-2, 2, -2*I, 2*I}, Method= _in) For further computations, restore the default output precision: Pref::outputDigits(UseDigits):
4-90
4-91
Programming Fundamentals
//test-f.tst prog::testinit("f"); print(Unquoted, "function f that compares two numbers") prog::test(f(1, 1), 1): prog::test(f(1, 2), 2): prog::test(f(2, 1), 2): prog::test(f(100, 0.01), 100): prog::test(f(0.01, 100), 100): prog::test(f(-10, 10), 10): prog::test(f(2*I, 2*I), 2*I): prog::test(f(2 + I, 2 + I), 2 + I): prog::test(error(f(2 + I, 3 + I)), TrapError=1003): prog::test(error(f(x, y)), TrapError=1202): prog::test(error(f(x, x)), TrapError=1202): prog::testexit(f) Info: 11 tests, 0 errors, runtime factor Info: CPU time: 12.7 s
0.0
(nothing expected)
Info: Memory allocation 20452460 bytes [prog::testexit] If you change the original procedure f, run the test script to catch any unexpected results: f := proc(a:Type::Numeric, b:Type::Numeric) begin if a >= b then return(a) else return(b) end_if end_proc: You do not need to copy the test script to the notebook. Instead, you can execute the test script that you saved to a file without opening the file. To execute a test script:
4-92
1 Select Notebook > Read Commands to open the Read Commands dialog
box.
2 Change the file filter to show MuPAD test files or all files.
3 Navigate to the test file that contains the script and click OK.
Alternatively, use the READPATH variable to specify the path to the folder that contains the file. Then use the read function to find and execute the test file. For example, if you saved the test file test-f.tst in the folder C:/MuPADfiles/TestScripts, use the following commands: READPATH := "C:/MuPADfiles/TestScripts": read("test-f.tst") Error in test function f that compares two numbers 7 Input: f(2*I, 2*I) Expected: 2*I Got: TrapError = [1003, "Error: Can't evaluate to boolean [_leequal];\r\n Near line: 9 Error in test function f that compares two numbers 8 Input: f(2 + I, 2 + I) Expected: 2 + I
Evaluating: f"]
4-93
Programming Fundamentals
Got:
TrapError = [1003, "Error: Can't evaluate to boolean [_leequal] Evaluating: f"] Near line: 10 Info: 11 tests, 2 errors, runtime factor Info: CPU time: 12.7 s
0.0
(nothing expected)
Info: Memory allocation 20452460 bytes [prog::testexit] Although the change seems reasonable and safe, the test report shows that the procedure does not work for equal complex numbers anymore. Instead, the procedure throws an error. If you do not test the code, you can miss this change in procedure behavior. If this behavior is expected, correct the test script. Otherwise, correct the procedure.
4-94
Code Verification
Code Verification
Even if your code executes without errors, and all your tests run without failures, the code can still have some flaws. For example, it can: Modify global variables, protected identifiers, environment variables, and formal parameters. Declare local variables or formal parameters and not use them afterwards. Contain undefined entries of domains or domain interfaces. To ensure that your code does not introduce such flaws, use the prog::check function to verify it. Use this function to check your procedures, domains, and function environments. Suppose you wrote the following procedure: f := proc(x, n) local a, b, c; begin a := m; b := a; if x > 0 then x := level(b, 2) else x := -level(b, 2) end_if; end: When you call this procedure, it does not error: f(42, 24)
To check f for common programming flaws, use prog::check. When calling prog::check, you can specify how detailed the report must be. This setting is called the information level of the report. The second argument controls the information level of the report generated by prog::check. Use options to see specific flaws or call prog::check without options to see all common flaws that MuPAD finds in the procedure. For the procedure f, prog::check with the information level 3 reports these flaws:
4-95
Programming Fundamentals
Warnings: 3 [f] For the list of all available options, see the prog::check help page.
4-96
Create the following procedure that computes the nth Lucas number: lucas:= proc(n:Type::PosInt) option remember; begin if n = 1 then 1 elif n = 2 then 3 else lucas(n - 1) + lucas(n - 2) end_if end_proc: lucas(i) $ i = 1..5
Now protect the procedure name, lucas, using protect with the ProtectLevelError option:
4-97
Programming Fundamentals
protect(lucas, ProtectLevelError):
ProtectLevelError lets you set full protection for the identifier. Now, trying to assign any value to lucas results in error:
lucas := 0
Error: The identifier 'lucas' is protected. [_assign] Alternatively, you can use the ProtectLevelWarning option. In this case, you can still assign a value to the protected identifier, but a warning appears, for example: protect(lucas, ProtectLevelWarning): You can assign any value to lucas now, but such assignment triggers a warning: lucas := 0
For further computations, remove protection from the identifier lucas: unprotect(lucas):
4-98
Data Collection
Data Collection
In this section... Parallel Collection on page 4-99 Fixed-Length Collection on page 4-102 Known-Maximum-Length Collection on page 4-103 Unknown-Maximum-Length Collection on page 4-104
Parallel Collection
Suppose the data that you want to collect is generated element-by-element and you know in advance how many elements will be generated. The intuitive approach for collecting such data is to create an empty list and append each new element to the end of the list. For example, this procedure uses this approach to collect random integers generated by random: col := proc(n) local L, i; begin L := []; for i from 1 to n do L := L.[random()]; end_for; end: The procedure generates random integers and collects them in a list: col(5)
To estimate the performance of this approach, use the procedure col to generate a list of 50,000 random numbers: time(col(50000))
4-99
Programming Fundamentals
The time function returns results measured in milliseconds. Now, check how much time the procedure actually spends generating random numbers: time(random() $ i = 1..50000)
Thus, the procedure spends most of the time appending the newly generated numbers to a list. In MuPAD, appending a new entry to a list of n entries takes time proportional to n. Therefore, run time of col(n) is proportional to n2. You can visualize this dependency by plotting the times that col(n) spends when creating lists of 1 to 50,000 entries: plotfunc2d(n -> time(col(n)), n = 1..50000, Mesh = 20, AdaptiveMesh = 0)
4-100
Data Collection
When appending a new entry to a list, MuPAD allocates space for the new, longer list. Then it copies all entries of the old list plus a new entry to this new list. The faster approach is to create the entire list at once, without adding each new entry separately. This approach is called parallel collection because you create and collect data simultaneously. Use the sequence operator $ to implement this approach: col := proc(n) local i; begin [random() $ i = 1..n]; end: This procedure spends most of its time generating random numbers: time(col(50000))
4-101
Programming Fundamentals
Fixed-Length Collection
Suppose you know how many elements you will generate, but you cannot generate them all at once. In this case, the best strategy is to create a list of the required length filling it with some constant, such as 0 or NIL. Then you can replace any entry of this list with the generated value. In this case, you do not need to generate elements in the order in which you want them to appear in the list. For example, use this procedure to generate the list of the first n Lucas numbers. The procedure creates a list of n entries, where each entry is 0. Then it assigns the values to the first two entries. To replace all other entries of the list with the Lucas numbers, the procedure uses the for loop: lucas := proc(n) local L, i; begin L := [0 $ n]; L[1] := 1; L[2] := 3; for i from 3 to n do L[i] := L[i-1] + L[i-2]; end_for; L end: Measure the time needed to create a list of 10,000 Lucas numbers: time(lucas(10000))
If you use the procedure that creates an empty list and appends each generated Lucas number to this list, then creating a list of 10,000 Lucas numbers takes much longer: lucas := proc(n) local L, i;
4-102
Data Collection
begin L := []; L :=L.[1]; L := L.[3]; for i from 3 to n do L := L.[L[i-1] + L[i-2]]; end_for; L end: time(lucas(10000))
Known-Maximum-Length Collection
If you cannot predict the number of elements that you will generate, but have a reasonable upper limit on this number, use this strategy:
1 Create a list with the number of entries equal to or greater than the upper
limit.
2 Generate the data and populate the list. 3 Discard the unused part of the list.
For example, use the following procedure to create a list. The entries of this list are modular squares of a number a (a2 mod n). You cannot predict the number of entries in the resulting list because it depends on the parameters a and n. Nevertheless, you can see that in this case the number of entries in the list cannot exceed n: modPowers := proc(a, n) local L, i; begin L := [0 $ n]; L[1] := a; L[2] := a^2 mod n; i := 2;
4-103
Programming Fundamentals
while L[i] <> a do L[i + 1] := a*L[i] mod n; i := i + 1; end_while; L := L[1..i - 1]; end: When you call modPowers for a = 3 and a = 2, it creates two lists of different lengths: modPowers(3, 14); modPowers(2, 14)
Unknown-Maximum-Length Collection
Often, you cannot predict the number of elements and cannot estimate the upper limit on this number before you start generating actual data. One way of dealing with this problem is to choose some upper limit, and use the strategy described in Known Maximum Length Collection. If that limit is reached, then:
1 Choose a larger limit. 2 Create a new list with the number of elements corresponding to the new
limit.
3 Copy existing collected data to the new list.
Typically, increasing the list length by a constant factor results in better performance than increasing it by a constant number of entries: rndUntil42 := proc() local L, i; begin i := 1;
4-104
Data Collection
L := [random()]; while L[i] mod 42 <> 0 do if i = nops(L) then L := L.L; end_if; i := i+1; L[i] := random(); end_while; L[1..i]; end: SEED := 123456789: rndUntil42()
Alternatively, if you cannot predict the number of elements that you will need to collect, then use a table that grows automatically (a hash table): rndUntil42 := proc() local L, i, j; begin i := 1; L := table(1 = random()); while L[i] mod 42 <> 0 do
4-105
Programming Fundamentals
i := i+1; L[i] := random(); end_while; [L[j] $ j=1..i]; end: SEED := 123456789: time(rndUntil42() $ i = 1..500)
For this example, using the table is slightly faster. If you change the value 42 to another value, using the list might be faster. In general, tables are preferable when you collect large amounts of data. Choose the approach that works best for solving your problem.
4-106
4-107
Programming Fundamentals
MuPAD internally represents the difference a - b as a + b*(-1). Therefore, MuPAD represents the difference using this expression tree.
To display expression trees in a MuPAD notebook, use the prog::exprtree function. It replaces operators with the names of the corresponding system functions: prog::exprtree(a + b * c + d * e *sin(f)^g):
4-108
4-109
Programming Fundamentals
Modify Subexpressions
In this section... Find and Replace Subexpressions on page 4-110 Recursive Substitution on page 4-113
4-110
Modify Subexpressions
subs replaces specified objects in the expression tree with the specified values
or subexpressions. This function cannot replace a part of the branch in the expression tree: subs(a*(b + c), b + c = d), subs(a*(b + c + 1), b + c = d)
After substitution, subs does not evaluate the resulting expression (although it can simplify the expression). You can enforce evaluation of the modified subexpressions by using the EvalChanges option: subs(ln(x), x = E), subs(ln(x), x = E, EvalChanges)
subs replaces both free and dependent identifiers. In some cases, replacing dependent identifiers can cause invalid results:
subsex analyzes associative system operators and can replace part of the branch in the expression tree:
4-111
Programming Fundamentals
subsex(ln(x + a + 1),
x + a = E - 1)
subsop replaces only entire branches in the expression tree of an expression, the same way as subs. When using subsop, you must know the position (index) of the branch inside the expression in internal order that might differ from the output order used to represent the expression on screen. To find the internal index of a particular subexpression, use the op function:
ex := sin(a*x + b) op(ex);
+ cos(a*x + b):
op(ex, 2);
4-112
Modify Subexpressions
Now you can use subsop to replace the parameter a with some value. For example, replace it with the value 3: subsop(ex, [2, 1, 2, 1] = 3)
prog::find helps you find all occurrences of a specific value in the expression. For example, find all sums in this expression:
ex := (x + 1)/(x^2 + 2*x - 2) - 1/x + 1/(x + 1): pos := [prog::find(ex, hold(_plus))]; map(pos, p -> op(ex, p)); map(pos, p -> op(ex, p[1..-2]))
Recursive Substitution
You also can find all subexpressions of a particular type (for example, all Bessel functions or all branches not containing x), execute some code for these subexressions and replace them with the return value of that code. For this task, use the misc::maprec function.
4-113
Programming Fundamentals
Suppose you want to rewrite all terms that contain the sine and tangent functions in terms of cosine functions. (In this example, do not use sin(x)2 = 1 - cos(x)2 and similar identities.) First, create the functions sin2cos and tan2cos that rewrite expressions in terms of the cosine function. These functions access the operands of the sine and tangent functions using op(ex): sin2cos := ex -> cos(op(ex) - PI/2): tan2cos := ex -> cos(op(ex) - PI/2)/cos(op(ex)): Now you can use these functions when replacing all occurrences of sine and tangent functions in an expression. To replace subexpressions of the original expression, use misc::maprec. The misc::maprec function uses the syntax misc::maprec(expression, selector = replacement), where: expression is the original expression (subexpressions of which you want to replace). selector is the selection criterion (for example, a set of types of subexpressions that you want to replace). replacement is the procedure that you want to use to replace subexpressions of the original expression. MuPAD applies misc::maprec recursively to all subexpressions of the original expression. For example, in this call misc::maprec replaces all occurrences of sin and tan, including the sine function in tan(sin(x)): misc::maprec(sin(x) + tan(x^2) - tan(sin(x)), {"sin"} = sin2cos, {"tan"} = tan2cos)
Besides data types or types of expressions, such as "sin" or "tan", you can use procedures to represent selection criteria in misc::maprec. In this example, the selection criterion of misc::maprec is the procedure ex -> bool(freeIndets(ex) = {}) that excludes free identifiers and selects all constants of an expression. Using the procedure f as a replacement,
4-114
Modify Subexpressions
identifiers: f := proc(x) option remember; begin if testtype(x, Type::Rational) then x else genident(); end_if; end: misc::maprec(a = 5*b + PI*sqrt(2)*c + PI, (ex -> bool(freeIndets(ex) = {})) = f)
option remember in f ensures that constants appearing multiple times always get the same identifier. Moreover, you can access the remember table of the procedure f and select which substitutions you want to make:
select([op(op(f,5))], _not@bool)
4-115
Programming Fundamentals
Closures
When you call a procedure, MuPAD allocates memory for the local variables, marks them as uninitialized, and evaluates the body of the procedure. At the end of a procedure call, MuPAD destroys local variables freeing the allocated memory. Now suppose that the result of a procedure call refers to local variables of that procedure. For example, the returned value of this procedure refers to its local variable z: f := proc(x, y) local z; begin z := x + y; return(z); end: In this case, the variable z is replaced by its value at the end of the procedure call. Therefore, the returned value of the procedure is the value of the variable z, not the variable z itself: f(1, 2)
Use hold to suppress evaluation of the variable z. Now the procedure returns an object of type DOM_VAR: f := proc(x, y) local z; begin
4-116
Objects of type DOM_VAR represent local variables and can only be used inside procedures. An object of type DOM_VAR returned as a result of a procedure call is useless because it does not have any connection to the procedure. You can access local variables of a procedure if you either declare them in that procedure or declare them in a lexically enclosing procedure. For example, in the following code the procedure g can access and modify the variable x of the enclosing procedure f: f := proc(x) local g; begin g := proc() begin x := x+1; end: g(); end: f(2)
Instead of returning the result of the procedure call g(), you can return g itself. In this case, the returned value retains a link to the variable x of the procedure call. For reasons of memory management, f must declare that it will return something holding a reference to a local variable. To declare it, use option escape: f := proc(x) local g;
4-117
Programming Fundamentals
option escape; begin g := proc() begin x := x+1; end: g; end: h := f(2): i := f(17): h(); h(); i(); h()
Static Variables
Alternative to Static Variables in MuPAD
Many programming languages support the concept of static variables. Static variables are local variables the values of which are not reset in each call to a procedure. The value of a static variable is initialized during the first call to a procedure. In each subsequent call, a procedure remembers the value of a static variable from the previous call. Although MuPAD does not let you declare a variable inside a procedure as a static variable, you can still use the concept of static variables while programming in MuPAD.
4-118
When defining a procedure with proc, you often assign the procedure to an identifier. However, MuPAD lets you use anonymous procedures. Also, you can define one procedure inside another procedure. Thus, you can implement the alternative to a static variable in MuPAD as a nested procedure where:
1 The outer procedure has a local variable. The outer procedure can be
anonymous.
2 The inner procedure uses the local variable of the outer procedure. For the
inner procedure that variable is not local, and therefore it does not reset its value in each call. For example, this code implements cnt as a static variable in MuPAD: proc() local cnt; option escape; begin cnt := 0; f := proc() begin cnt := cnt + 1; end: end(): f(); f(); f()
4-119
Programming Fundamentals
proc() local x, y; option escape; begin x := 0; y := 0; f := () -> (x := x + y; [x, y]); g := n -> (y := y + n; [x, y]); end_proc(): f(); g(2); f(); f()
4-120
Utility Functions
Utility Functions
In this section... Utility Functions Inside Procedures on page 4-121 Utility Functions Outside Procedures on page 4-122 Utility Functions in Closures on page 4-123
4-121
Programming Fundamentals
4-122
Utility Functions
The utility function cannot access local variables of the procedure that uses that utility function. The workaround is to pass these local variables as arguments to the utility function. The utility function does not have privileged access to the arguments of the procedure that uses that utility function. Defining the utility function far from the code line where you call it reduces readability of the code. Be careful when defining utility functions in slots of a function environment because MuPAD uses these slots for overloading. Do not define utility functions with such names as f::print, f::diff, f::evaluate, or f::simplify unless you want to use these utility functions for overloading.
4-123
Programming Fundamentals
proc(arguments) local ...; begin ... code using helper(...) ... end: end(): For details about such structures, see Closures and Static Variables. If you define a utility function in a closure, that function is inaccessible to any external code. Your users cannot see and, therefore, rely on a particular implementation of that utility function. Changing it will not break their code. At the same time, this approach lets you create more than one procedure that can access the utility function. In the example, both f and g can access helper. The disadvantage of this approach is that the helper function cannot access the local variables of the procedures that use it. To overcome this limitation, you can use the context function or shared static variables. Note Using context or shared static variables to make local variables of the calling procedure accessible for the utility function is not recommended. Using context to overcome this limitation typically leads to unreadable and difficult to maintain code. The problems with shared static variables resemble the problems with global variables, especially for recursive calls. The helper procedure can access and modify such variables, but all other procedures inside the same outer procedure can access and modify them too.
4-124
Private Methods
Private Methods
Although MuPAD does not let you declare a method as private, you can create private methods by using closures. MuPAD uses a fundamentally simple object and name lookup model. Objects are data that belong to a particular domain type, and domains have named entries (called slots). If the value of a slot is a function, this entry is called a method. Therefore, MuPAD lets you use the same techniques for hiding method calls as you use for hiding utility functions. For details, see Utility Functions in Closures. This example creates the private method f of the domain d. This method is not accessible from methods in inherited domains and from category methods: domain d local f; inherits Dom::BaseDomain; g := proc() begin print("g"); f(); end; begin f := proc() begin print("f"); end; end: d::f
d::g()
4-125
Programming Fundamentals
4-126
Calls by Value
When calling a procedure with some arguments, you expect the procedure to assign these values for its local variables and perform some computations with those variables. For example, this procedure divides any number that you pass to it by 10: f := x -> (x := x/10): In this example, x is a local variable of f. When you call f with any value, the procedure assigns that value to the local variable x, uses it to compute the result, and then destroys the local variable x freeing allocated memory: x := 10: f(x), x
Although the value of the local variable x changes to 1 inside the procedure and then gets destroyed, the value of the global variable x remains the same. Therefore, you can conclude that the procedure does not access the actual memory block that contains the value of x. When you call this procedure, MuPAD allocates a new memory block and copies the value of x to that block. While the procedure executes, the system associates the local variable x with this new memory block. At the end of the procedure call, it frees this memory block. The memory block that contains the value of the global variable x does not change. The strategy of copying values of procedure arguments to new memory blocks and referring to these blocks during the procedure calls is known as calling by value. Most MuPAD functions use this strategy.
4-127
Programming Fundamentals
Since calling by value creates extra copies of data, it can be inefficient in terms of memory management. Creating extra copies of large data sets, especially when your procedure calls are recursive or nested can significantly reduce free memory on your computer. In many programming languages, calling by value always means copying data, even when a procedure does not change that data. MuPAD uses lazy copying to avoid creating unnecessary copies of data. When you call a procedure, MuPAD does not allocate new memory blocks right away. Instead, it links local variables to memory blocks where the arguments of the procedure are stored. The system always counts how many objects are linked to the same memory block. When a procedure modifies the value of a local variable, MuPAD checks if there are other objects linked to the same memory block, and creates a copy only if necessary. For example, when you call f(x), MuPAD points both global variable x (DOM_IDENT) and local (DOM_VAR) variable x to the same memory block. Only when the local variable x changes its value, MuPAD allocates a new memory block for it.
Calls by Reference
Typically, when you call a MuPAD procedure with some arguments, the system uses the calling-by-value approach and creates copies of the values of these arguments. This approach prevents procedures from modifying objects passed to a procedure as arguments. For some functions, such as assignment, MuPAD uses the calling-by-reference approach. In a call by reference, the system does not copy the values of arguments to new memory blocks. Instead, it copies references (pointers) to these arguments. Some programming languages let you specify which approach to use for each particular function. MuPAD does not offer specific language constructs for calling by reference. Nevertheless, you can still call by reference in MuPAD. Note For experienced MuPAD users, objects with reference semantics can behave unexpectedly. Be careful when exposing reference semantics to your users because it can be confusing.
4-128
Suppose your task requires a function call to be able to change the values of its arguments. The simple strategy is to return a modified copy of the arguments and overwrite the original object by using assignment. For example, replace matrix A with its upper row echelon form: A := linalg::hilbert(3)
A := linalg::gaussElim(A)
When working with large data sets and deep nested calls, this strategy can cause memory problems. Check the profiling report to see if your implementation has such problems. For details, see Profiling Your Code. You also can achieve the calling-by-reference effect in MuPAD using: Lexical Scoping Closures in Objects Domains in Objects Context Switching
Lexical Scoping
Instead of passing data as arguments of a procedure, you can use a local variable of the outer procedure to store the data. For the inner procedure, this variable is not local. Therefore, the inner procedure can change the value of
4-129
Programming Fundamentals
that variable, and the variable is not destroyed after the inner procedure is executed: f := proc(x) local n, incr; begin n := 0; incr := () -> (n := n + 1); while x > n do incr(); end_while; end_proc: This approach does not fit many programming tasks, but it is recommended wherever you can apply it. It is the simplest and most readable approach to get the calling-by-reference effect in MuPAD.
Closures in Objects
When working with domains, you also can use the approach of having the actual data in a closure. For example, instead of storing the actual data in the objects, you can store functions that access the data: domain d local get, set; inherits Dom::BaseDomain; new := proc(x) option escape; begin new(dom, () -> x, y -> (x := y)); end; incr := x -> set(x, get(x) + 1); print := x -> get(x); begin get := x -> extop(x, 1)(); set := (x, y) -> extop(x, 2)(y);
4-130
end_domain: e := d(4)
d::incr(e)
Domains in Objects
You can implement the calling-by-reference approach in your code by using domains as tables with reference effects. (Using domains as tables is unrelated to object-oriented programming.) The following example demonstrates this strategy: domain dd local get, set; inherits Dom::BaseDomain; new := proc(x) local d; begin d := newDomain(genident()); d::number := x; new(dom, d); end; get := (x, entry) -> slot(extop(x, 1), entry); set := (x, entry, value) -> slot(extop(x, 1), entry, value);
4-131
Programming Fundamentals
incr := x -> (dom::set(x, "number", dom::get(x, "number") + 1); x); print := x -> dom::get(x, "number"); end_domain: e := dd(4)
dd::incr(e)
The primitives of the plot library use this strategy. For example, when you execute the following code, the domain plot::Function2d overloads the slot function: f := plot::Function2d(sin(x), x=-PI..PI): f::Color := RGB::Green:
Context Switching
The context function and option hold also let you implement the calling be reference effect in your procedures. option hold prevents the procedure from evaluating its arguments before executing the code in the procedure body. The context function lets you perform operations as if they occur in the calling procedure. For example, in this code option hold prevents the incr procedure from evaluating its argument. Therefore, the system does not copy the value of x to a new memory block: incr :=
4-132
proc(x) option hold; begin context(hold(_assign)(x, x + 1)); end_proc: operator("++", incr, Prefix, 500): While executing this procedure, the system performs the assignment operation in the context of the procedure f (the calling procedure for incr). Thus, incr changes the value of the argument, n, with which it was called: f := proc(x) local n; begin n := 0; while x > n do ++n; end_while; end_proc: If you use the ++ operator on an unchangeable object, MuPAD throws an error. For example, you cannot assign the value 2 to the value 1: ++1
Error: The left side is invalid. [_assign] This error message does not mention incr because the error occurs in the assignment which is performed in a different evaluation context. The incr procedure behaves essentially like a dynamic macro.
4-133
Programming Fundamentals
You can say that the mathematical knowledge about the built-in functions is distributed over several system functions: float knows how to compute numerical approximations of the sine function, diff knows the derivative of the sine function, and expand knows the addition theorems of the trigonometric functions. When you implement your own function, you can integrate it into the MuPAD system, making other functions aware how to work with this new function correctly. If the new function consists only of built-in MuPAD functions, then you do not need to take extra steps. All MuPAD functions interact correctly with the new function: f := x -> (x*sin(x)): diff(f(x), x)
However, if you implement a function that is not composed of the standard MuPAD objects (for example, a new special function), you must distribute the
4-134
knowledge about the mathematical meaning of the new function to standard MuPAD functions, such as diff, expand, float, and so on. This extra task is necessary for integrating the new function with the rest of the system. For example, you might want to differentiate an expression that contains both the new function and some built-in functions, and such differentiation is only possible via the MuPAD differentiation routine. Therefore, this routine must know how to handle the new symbol. MuPAD uses function environments (domain type DOM_FUNC_ENV) to integrate functions into the system. A function environment stores special function attributes (slots) in an internal table. Whenever an overloadable system function, such as diff, expand, or float, encounters an object of type DOM_FUNC_ENV, it searches the function environment for a corresponding slot. If a system function finds the appropriate slot, it calls that slot and returns the value produced by the slot. All built-in MuPAD functions are implemented as function environments: domtype(sin), domtype(exp)
You can call a function environment as you would call any MuPAD function or procedure: sin(1.7), exp(1.0)
Suppose you implement the complete elliptic integral functions of the first and second kind, K(z) and E(z). These functions appear in different contexts, such as calculating the perimeter of an ellipsis, the gravitational or electrostatic potential of a uniform ring, and the probability that a random walk in three dimensions ever goes through the origin. The elliptic integrals have the following special values:
, E(1) = 1,
4-135
Programming Fundamentals
MuPAD provides the built-in functions ellipticE and ellipticK for computing these elliptic integrals. However, you can implement your own functions for the same task. For example, write the procedures ellipE and ellipK. These procedures define the values of the elliptic integrals for special values of x. For all other argument values, the values of elliptic integrals are unknown, and the procedures return the symbolic expressions ellipE(x) and ellipK(x). Use procname to return symbolic expressions: ellipE := proc(x) begin if x = 0 then PI/2 elif x = 1 then 1 else procname(x) end_if end_proc: ellipK := proc(x) begin if x = 0 then PI/2 elif x = 1/2 then 8*PI^(3/2)/gamma(-1/4)^2 elif x = -1 then gamma(1/4)^2/4/sqrt(2*PI) else procname(x) end_if end_proc:
ellipE and ellipK return special values for particular arguments. For all
other arguments, they return symbolic expressions: ellipE(0), ellipE(1/2), ellipK(12/17), ellipK(x^2 + 1)
The standard MuPAD differentiation function diff does not know about these rules. Therefore, trying to differentiate ellipE and ellipK simply returns the symbolic notations of the derivatives:
4-136
To make diff work with the new functions, create function environments from the procedures ellipE and ellipK. In addition, function environments let you control the appearance of the symbolic function calls in outputs. A function environment consists of three operands. The first operand is a procedure that computes the return value of a function call. The second operand is a procedure for printing a symbolic function call on the screen. The third operand is a table that specifies how the system functions handle symbolic function calls. To create function environments, use funcenv. For example, create function environments ellipE and ellipK. Use the second argument to specify that symbolic calls to ellipE and ellipK must appear as E and K outputs: output_E := f -> hold(E)(op(f)): ellipE := funcenv(ellipE, output_E): output_K := f -> hold(K)(op(f)): ellipK := funcenv(ellipK, output_K): Although ellipE and ellipK are now function environments, you can call them as you would call any other MuPAD function: ellipE(0), ellipE(1/2), ellipK(12/17), ellipK(x^2+1)
4-137
Programming Fundamentals
The third argument funcenv is a table of function attributes. It tells the system functions (such as float, diff, expand, and so on) how to handle symbolic calls of the form ellipE(x) and ellipK(x). You can update this table specifying the rules for the new function. For example, specify the new differentiation rules by assigning the appropriate procedures to the diff slot of the function environments: ellipE::diff := proc(f,x) local z; begin z := op(f); (ellipE(z) - ellipK(z))/(2*z) * diff(z, x) end_proc: ellipK::diff := proc(f,x) local z; begin z := op(f); (ellipE(z) - (1-z)*ellipK(z))/ (2*(1-z)*z) * diff(z, x) end_proc: Now, whenever f = ellipE(z), and z depends on x, the call diff(f, x) uses the procedure assigned to ellipE::diff: diff(ellipE(z), z); diff(ellipE(y(x)), x); diff(ellipE(x*sin(x)), x)
4-138
Since the taylor function internally calls diff, the new differentiation routine also lets you compute Taylor expansions of the elliptic integrals: taylor(ellipK(x), x = 0, 6)
If a derivative of a function contains the function itself, the integration routine has a good chance of finding symbolic integrals after you implement the diff attributes. For example, int now computes the following integrals: int(ellipE(x), x)
int(ellipK(x), x)
4-139
Programming Fundamentals
4-140
5
Graphics and Animations
Gallery on page 5-2 Easy Plotting: Graphs of Functions on page 5-25 Advanced Plotting: Principles and First Examples on page 5-84 The Full Picture: Graphical Trees on page 5-100 Viewer, Browser, and Inspector: Interactive Manipulation on page 5-105 Primitives on page 5-110 Attributes on page 5-115 Layout of Canvas and Scenes on page 5-129 Animations on page 5-139 Groups of Primitives on page 5-170 Transformations on page 5-172 Legends on page 5-177 Fonts on page 5-182 Colors on page 5-185 Save and Export Pictures on page 5-191 Import Pictures on page 5-195 Cameras in 3D on page 5-197 Possible Strange Effects in 3D on page 5-208
Gallery
In this section... 2D Function and Curve Plots on page 5-2 Other 2D examples on page 5-7 3D Functions, Surfaces, and Curves on page 5-17 We present a collection of pictures illustrating the capabilities of the present MuPAD graphics system. These pictures are created at various places in this document where they are used to demonstrate certain features of the graphics system. A reference to the location of detailed documentation is provided along with each picture in this gallery. There, further details including the MuPAD commands for generating the picture can be found.
5-2
Gallery
The following picture shows a function plot together with a spline interpolation through a set of sample points. See section Some Examples for details:
5-3
The following picture shows a hatched area between functions. See the examples on the help page of plot::Hatch for details:
5-4
Gallery
The following picture demonstrates some layout possibilities. See the examples on the help page of Layout for details:
5-5
The following picture demonstrates the construction of cycloids via points fixed to a rolling wheel. See section Some Examples for an animated version and details:
5-6
Gallery
The following picture demonstrates hatched areas inside curves. See the examples on the help page of plot::Hatch for details:
Other 2D examples
The following picture shows an imported bitmap inside function plots. See section Importing Pictures for details:
5-7
The following picture shows some frames of an animation of the perturbed orbit of a small planet kicked out of a solar system by a giant planet after a near-collision. See section Example 3 for details of the animation:
5-8
Gallery
The following picture shows three solution curves of an ODE inside the directional vector field associated with the ODE. See the examples on the help page of plot::VectorField2d for details:
5-9
The following picture shows the Mandelbrot set together with two blow ups of regions of special interest. See the examples on the help page of plot::Density for details:
5-10
Gallery
The following picture shows several rotated copies of a function graph. See the examples on the help page of plot::Rotate2d for details:
5-11
The following picture shows a data plot of type plot::Bars2d. See the examples on the help page of plot::Bars2d for details:
5-12
Gallery
The following picture shows the image of a rectangle in the complex plane under the map . See the examples on the help page of plot::Conformal for details:
5-13
The following picture shows some elliptic curves generated as a contour plot. See the examples on the help page of plot::Implicit2d for details:
5-14
Gallery
The following picture shows the Feigenbaum diagram of the logistic map. See the examples on the help page of plot::PointList2d for details:
5-15
The following picture shows a fractal object generated by a turtle plot of a Lindenmayer system. See the examples on the help page of plot::Lsys for details:
5-16
Gallery
5-17
The following picture demonstrates a 3D function plot enhanced by a coordinate grid. See the examples on the help page of GridVisible for details:
5-18
Gallery
The following picture demonstrates a 3D function plot of , which is not real for some parts of the parameter space. See the documentation of plot::Function3d for details:
5-19
The following picture shows Kleins bottle (a famous topological object). This surface does not have an orientation; there is no inside and no outside of this object. See the examples on the help page of plot::Surface for details:
5-20
Gallery
The following picture demonstrates the reconstruction of an object with rotational symmetry from measurements of its radius at various points. See section Some Examples for details:
5-21
The following picture shows the Lorenz attractor. See section Cameras in 3D for an animated version and details:
5-22
Gallery
The following picture shows a 3D level surface of a function (the solution set of z2 = sin(z - x2y2)). See the examples on the help page of plot::Implicit3d for details:
5-23
5-24
5-25
If several functions are to be plotted in the same graphical scene, just pass a sequence of function expressions. All functions are plotted over the specified common range: plotfunc2d(sin(x)/x, x*cos(x), tan(x), x = -4..4):
5-26
Functions that do not allow a simple symbolic representation by an expression can also be defined by a procedure that produces a numerical value f(x) when called with a numerical value x from the plot range. In the following example we consider the largest eigenvalue of a symmetric 33 matrix that contains a parameter x. We plot this eigenvalue as a function of x: f := x -> max(numeric::eigenvalues(matrix([[-x, x, -x ], [ x, x, x ], [-x, x, x^2]]))): plotfunc2d(f, x = -1..1):
5-27
The name x used in the specification of the plotting range provides the name that labels the horizontal axis. Functions can also be defined by piecewise objects: plotfunc2d(piecewise([x < 1, 1 - x], [1 < x and x < 2, 1/2], [x > 2, 2 - x]), x = -2..3)
5-28
Note that there are gaps in the definition of the function above: no function value is specified for x = 1 and x = 2. This does not cause any problem, because plotfunc2d simply ignores all points that do not produce real numerical values. Thus, in the following example, the plot is automatically restricted to the regions where the functions produce real values: plotfunc2d(sqrt(8 - x^4), ln(x^3 + 2)/(x - 1), x = -2 ..2):
5-29
When several functions are plotted in the same scene, they are drawn in different colors that are chosen automatically. With the Colors attribute one may specify a list of RGB colors that plotfunc2d shall use: plotfunc2d(x, x^2, x^3, x^4, x^5, x = 0..1, Colors = [RGB::Red, RGB::Orange, RGB::Yellow, RGB::BlueLight, RGB::Blue]):
5-30
Animated 2D plots of functions are created by passing function expressions depending on a variable (x, say) and an animation parameter (a, say) and specifying a range both for x and a: plotfunc2d(cos(a*x), x = 0..2*PI, a = 1..2):
5-31
Once the plot is created, the first frame of the picture appears as a static plot. After clicking on the picture, the graphics tool starts playing the animation. There are the usual controls to stop, start, and fast-forward/rewind the animation. The default number of frames of the animation is 50. If a different value is desired, just pass the attribute Frames = n, where n is the number of frames that shall be created: plotfunc2d(sin(a*x), sin(x - a), x = 0..PI, a = 0..4*PI, Colors = [RGB::Blue, RGB::Red], Frames = 200):
5-32
Apart from the color specification or the Frames number, there is a large number of further attributes that may be passed to plotfunc2d. Each attribute is passed as an equation AttributeName = AttributeValue to plotfunc2d. Here, we only present some selected attributes. See the section on attributes for plotfunc for further tables with more attributes. possible values/example meaning
8*unit::cm 12*unit::cm
attribute name
Height Width Footer Header Title
default
80*unit::mm 120*unit::mm "" (no footer) "" (no header) "" (no title)
physical height of the picture physical width of the picture footer text header text title text
5-33
attribute name
TitlePosition
default
coordinates of the lower left corner of the title visibility of major grid lines in all directions visibility of minor grid lines in all directions number of sample points of the numerical mesh axes type
FALSE
GridVisible
SubgridVisible
TRUE, FALSE
FALSE
AdaptiveMesh
integer 2
121
Axes
None, Automatic, Boxed, Frame, Origin TRUE, FALSE [string, string] LinLin, LinLog, LogLin, LogLog
Automatic
TRUE ["x","y"]
first 10 entries of
RGB::ColorList 50 TRUE
5-34
attribute name
LineColorType
default
Flat
color scheme
Mesh
integer 2
121
Scaling
Unconstrained
TicksNumber
number of labeled ticks at all axes vertical asymptotes on/off restricted viewing range in y direction restricted viewing range in y direction (equivalent to
Normal
TRUE
ViewingBoxYRange ymin..ymax
Automatic
YRange
ymin..ymax
Automatic
ViewingBoxYRange)
The following plot example features the notorious function oscillates wildly near the origin: plotfunc2d(sin(1/x), x = -0.5..0.5):
that
5-35
Clearly, the default of 121 sample points used by plotfunc2d does not suffice to create a sufficiently resolved plot. We increase the number of numerical mesh points via the Mesh attribute. Additionally, we increase the resolution depth of the adaptive plotting mechanism from its default value AdaptiveMesh = 2 to AdaptiveMesh = 4: plotfunc2d(sin(1/x), x = -0.5..0.5, Mesh = 500, AdaptiveMesh = 4):
5-36
The following call specifies a header via Header = "The function sin(x^2)". The distance between labeled ticks is set to 0.5 along the x axis and to 0.2 along the y axis via XTicksDistance = 0.5 and YTicksDistance = 0.2, respectively. Four additional unlabeled ticks between each pair of labeled ticks are set in the x direction via XTicksBetween = 4. One additional unlabeled tick between each pair of labeled ticks in the y direction is requested via YTicksBetween = 1. Grid lines attached to the ticks are switched on by GridVisible = TRUE and SubgridVisible = TRUE: plotfunc2d(sin(x^2), x = 0..7, Header = "The function sin(x^2)", XTicksDistance = 0.5, YTicksDistance = 0.2, XTicksBetween = 4, YTicksBetween = 1, GridVisible = TRUE, SubgridVisible = TRUE):
5-37
When singularities are found in the function, an automatic clipping is called trying to restrict the vertical viewing range in some way to obtain a reasonably scaled picture. This is a heuristic approach that sometimes needs a helping adaptation by hand. In the following example, the automatically chosen range between y - 1 and y 440 in vertical direction is suitable to represent the 6th order pole at x = 1, but it does not provide a good resolution of the first order pole at x = - 1: plotfunc2d(1/(x + 1)/(x - 1)^6, x = -2..2):
5-38
There is no good viewing range that is adequate for both poles because they are of different order. However, some compromise can be found. We override the automatic viewing range suggested by plotfunc2d and request a specific viewing range in vertical direction via ViewingBoxYRange: plotfunc2d(1/(x + 1)/(x - 1)^6, x = -2..2, ViewingBoxYRange = -10..10):
5-39
The values of the following function have a lower bound but no upper bound. We use the attribute ViewingBoxYRange = Automatic..10 to let plotfunc2d find a lower bound for the viewing box by itself whilst requesting a specific value of 10 for the upper bound: plotfunc2d(exp(x)*sin(PI*x) + 1/(x + 1)^2/(x - 1)^4, x = -2..2, ViewingBoxYRange = Automatic..10):
5-40
5-41
If several functions are to be plotted in the same graphical scene, just pass a sequence of function expressions; all functions are plotted over the specified common range: plotfunc3d((x^2 + y^2)/4, sin(x - y)/(x - y), x = -2..2, y = -2..2):
5-42
Functions that do not allow a simple symbolic representation by an expression can also be defined by a procedure that produces a numerical value f(x, y) when called with numerical values x, y from the plot range. In the following example we consider the largest eigenvalue of a symmetric 33 matrix that contains two parameters x, y. We plot this eigenvalue as a function of x and y: f := (x, y) -> max(numeric::eigenvalues( matrix([[-y, x, -x], [x, y, x], [-x, x, y^2]]))): plotfunc3d(f, x = -1..1, y = -1..1):
5-43
The names x, y used in the specification of the plotting range provide the labels of the corresponding axes. Functions can also be defined by piecewise objects: plotfunc3d(piecewise([x < y, y - x], [x > y, (y - x)^2]), x = 0..1, y = 0..1)
5-44
Note that there are gaps in the definition of the function above: no function value is specified for x = y. This does not cause any problem, because plotfunc3d simply ignores points that do not produce real numerical values if it finds suitable values in the neighborhood. Thus, missing points do not show up in a plot if these points are isolated or are restricted to some 1-dimensional curve in the x-y plane. If the function is not real valued in regions of nonzero measure, the resulting plot contains holes. The following function is real valued only in the disk x2 + y2 1: plotfunc3d(sqrt(1 - x^2 - y^2), x = 0..1, y = 0..1):
5-45
When several functions are plotted in the same scene, they are drawn in different colors that are chosen automatically. With the Colors attribute one may specify a list of RGB colors that plotfunc3d shall use: plotfunc3d(2 + x^2 + y^2, 1 + x^4 + y^4, x^6 + y^6, x = -1..1, y = -1..1, Colors = [RGB::Red, RGB::Green, RGB::Blue]):
5-46
Animated 3D plots of functions are created by passing function expressions depending on two variables (x, y, say) and an animation parameter (a, say) and specifying a range for x, y, and a: plotfunc3d(x^a + y^a, x = 0..2, y = 0..2, a = 1..2):
5-47
Once the plot is created, the first frame of the picture appears as a static plot. After double-clicking on the picture, the animation starts. The usual controls for stopping, going to some other point in time etc. are available. The default number of frames of the animation is 50. If a different value is desired, just pass the attribute Frames = n, where n is the number of frames that shall be created: plotfunc3d(sin(a)*sin(x) + cos(a)*cos(y), x = 0..2*PI, y = 0..2*PI, a = 0..2*PI, Frames = 32):
5-48
Apart from the color specification or the Frames number, there is a large number of further attributes that may be passed to plotfunc3d. Each attribute is passed as an equation AttributeName = AttributeValue to plotfunc3d. Here, we only present some selected attributes. Section Attributes for plotfunc2d and plotfunc3d provides further tables with more attributes. plotfunc3d possible values/example meaning
8*unit::cm 12*unit::cm
attribute name
Height Width Footer Header
default
80*unit::mm 120*unit::mm "" (no footer) "" (no header)
physical height of the picture physical width of the picture footer text header text
string string
5-49
attribute name
Title TitlePosition
default
"" (no title)
title text coordinates of the lower left corner of the title visibility of major grid lines in all directions visibility of minor grid lines in all directions depth of the adaptive mesh axes type
GridVisible
FALSE
SubgridVisible
TRUE, FALSE
FALSE
AdaptiveMesh Axes
integer 0
Automatic, Boxed, Frame, Origin TRUE, FALSE [string, string, string] LinLinLin, ..., LogLogLog
0 Boxed
AxesVisible AxesTitles
TRUE ["x","y","z"]
CoordinateType
linear-linear-linear,LinLinLin linear-logarithmic, logarithmic-linear, log-log plot fill colors number of frames of the animation legend on/off
50 TRUE
5-50
attribute name
FillColorType
default
Dichromatic
color scheme
Mesh
number of major mesh points number of minor mesh points scaling mode
[25, 25]
Submesh
[0, 0]
Scaling
Unconstrained
TicksNumber
number of labeled ticks at all axes restricted viewing range in z direction restricted viewing range in z direction (equivalent to
Normal
ViewingBoxZRange zmin..zmax
Automatic
ZRange
zmin..zmax
Automatic
ViewingBoxZRange)
In the following example, the default mesh of 25 25 sample points used by plotfunc3d does not suffice to create a sufficiently resolved plot: plotfunc3d(sin(x^2 + y^2), x = -3..3, y = -3..3):
5-51
We increase the number of numerical mesh points via the Submesh attribute: plotfunc3d(sin(x^2 + y^2), x = -3..3, y = -3..3, Submesh = [3, 3])
5-52
The following call specifies a header via Header = "The function sin(x y^2)". Grid lines attached to the ticks are switched on by GridVisible = TRUE and SubgridVisible = TRUE: plotfunc3d(sin(x - y^2), x = -2*PI..2*PI, y = -2..2, Header = "The function sin(x - y^2)", GridVisible = TRUE, SubgridVisible = TRUE):
5-53
When singularities are found in the function, an automatic clipping is called trying to restrict the vertical viewing range in some way to obtain a reasonably scaled picture. This is a heuristic approach that sometimes needs a helping adaptation by hand. In the following example, the automatically chosen range between z 0 and z 0.8 in vertical direction is suitable to represent the pole at x = 1, y = 1, but it does not provide a good resolution of the pole at x = - 1, y = 1: plotfunc3d(1/((x + 1)^2 + (y - 1)^2)/((x - 1)^2 + (y - 1)^2)^5, x = -2..3, y = -2..3, Submesh = [3, 3]):
5-54
There is no good viewing range that is adequate for both poles because they are of different order. We override the automatic viewing range suggested by plotfunc3d and request a specific viewing range in the vertical direction via ViewingBoxZRange: plotfunc3d(1/((x + 1)^2 + (y - 1)^2)/((x - 1)^2 + (y - 1)^2)^5, x = -2..3, y = -2..3, Submesh = [3, 3], ViewingBoxZRange = 0..0.1):
5-55
The values of the following function have a lower bound but no upper bound. We use the attribute ViewingBoxZRange = Automatic..20 to let plotfunc2d find a lower bound for the viewing box by itself whilst requesting a specific value of 20 for the upper bound: plotfunc3d(1/x^2/y^2 + exp(-x)*sin(PI*y), x = -2..2, y = -2..2, ViewingBoxZRange = Automatic..20):
5-56
5-57
within the canvas, whilst axes, grid lines, viewing boxes etc. are associated with the coordinate system. Some attributes such as colors, line width, the numerical mesh size etc. belong to the function graphs and can be set separately for each function plotted by plotfunc2d/plotfunc3d. The last entry in the following tables provides the location of the attribute in the graphical hierarchy of the object browser. For example, for changing the background color of the picture, select the scene by double clicking the Scene2d/Scene3d entry in the object browser. Now, the property inspector provides a tree of attributes with the nodes Annotation, Layout, and Style. Opening the Style sub-tree, one finds an entry for BackgroundColor which allows to change the background color interactively. Here is a table of the most important attributes for setting the layout and the background of the picture: attribute name
Width
default
browser entry
120*unit::mm Canvas
Height
8*unit::cm
80*unit::mm
Canvas
color of the RGB::White background color of the border width of the border common width for all margins: etc.
RGB::Grey50 0 1*unit::mm
RGB color
1*unit::mm 1*unit::mm
BottomMargin, LeftMargin,
5-58
(Continued) attribute name possible values/example meaning width of bottom margin width of left margin width of right margin width of top margin browser entry
Scene2d/3d
default
1*unit::mm
BottomMargin 1*unit::mm
LeftMargin RightMargin
1*unit::mm 1*unit::mm
1*unit::mm 1*unit::mm
Scene2d/3d Scene2d/3d
TopMargin
1*unit::mm
1*unit::mm
Scene2d/3d Scene3d
Scene3d
Scene2d
An overall title can be set as a footer and/or a header. Here is a table of the attributes determining the footer and/or header of the picture: attribute name
Footer Header
default
"" (no footer) "" (no
browser entry
Scene2d/3d Scene2d/3d
header)
5-59
(Continued) attribute name possible values/example meaning horizontal alignment horizontal alignment font for the footer font for the header browser entry
Scene2d/3d Scene2d/3d Scene2d/3d Scene2d/3d
default
Center Center
FooterAlignment Left, Center, Right HeaderAlignment Left, Center, Right FooterFont HeaderFont
sans-serif 12 sans-serif 12
Apart from footers and/or headers of scenes and canvas, there are titles associated with the functions. In contrast to footer and header, function titles can be placed anywhere in the coordinate system via the attribute TitlePosition. Typically, titles are associated with individual objects rather than with entire scenes. Thus, when using plotfunc2d or plotfunc3d, a title attribute will usually only be used when a single function is displayed. However, several titles with separate positions can be set interactively in the property inspector for each of the functions: attribute name possible values/example
Title string
Function2d/3d
(no title)
Function2d Function3d
TitlePosition [real value, real value] TitlePosition [real value,real value,real value] TitlePositionX real value TitlePositionY real value
coordinates of the lower left corner of the title coordinates of the lower left corner of the title x coordinate of the lower left corner of the title y coordinate of the lower left corner of the title
Function2d/3d
Function2d/3d
5-60
meaning z coordinate of the lower left corner of the title font for the titles
Function2d/3d sans-serif 11
If several functions are drawn simultaneously in one picture, it is useful to display a legend indicating which color is used for which function. See section Legends for further details on legends. Here is a table of the most important attributes determining the form of the legend. The attributes LegendEntry, LegendText, and LegendVisible = TRUE are set automatically by plotfunc2d/plotfunc3d if more than one function is plotted. The property inspector (Viewer, Browser, and Inspector: Interactive Manipulation) allows to reset the legend entry for each function: attribute name
LegendEntry
default
TRUE
browser entry
Function2d/3d
add this function to the legend? legend text legend on/off vertical placement horizontal alignment font for the legend text
LegendText
string
LegendVisibleTRUE, FALSE LegendPlacement Top, Bottom LegendAlignment Left, Center, Right LegendFont
sans-serif 8
When singular functions are plotted, it is often useful to request a specific viewing range. Here is a table of the most important attributes for setting
5-61
viewing ranges. In the interactive object browser, you will find them under CoordinateSystem2d (CS2d) and CoordinateSystem3d (CS3d), respectively: attribute possible name values/examplemeaning
ViewingBox [xmin..xmax, ymin..ymax], [Automatic, Automatic] ViewingBox [xmin..xmax, ymin..ymax, zmin..zmax], [Automatic, Automatic, Automatic] ViewingBoxXRange xmin..xmax ViewingBoxYRange ymin..ymax ViewingBoxZRange zmin..zmax ViewingBoxXMin xmin: real value or Automatic ViewingBoxXMax xmax: real value or Automatic ViewingBoxYMin ymin: real value or Automatic ViewingBoxYMax ymax: real value or Automatic
default
browser entry
viewing range in x direction viewing range in y direction viewing range in z direction lowest viewing value in x direction highest viewing value in x direction lowest viewing value in y direction highest viewing value in y direction
Automatic.. CS2d/3d Automatic Automatic.. CS2d/3d Automatic Automatic.. CS3d Automatic Automatic Automatic Automatic Automatic CS2d/3d CS2d/3d CS2d/3d CS2d/3d
5-62
default
Automatic Automatic
browser entry
CS3d CS3d
In contrast to the routines of the plot library, plotfunc2d and plotfunc3d also accept the attributes YMin, YMax, YRange and ZMin, ZMax, ZRange, respectively, as shortcuts for the somewhat clumsy attribute names ViewingBoxYMin etc. E.g., plotfunc2d(f(x), x = xmin..xmax, YRange = ymin..ymax) is equivalent to plotfunc2d(f(x), x = xmin..xmax, ViewingBoxYRange = ymin..ymax) and plotfunc3d(f(x, y), x = xmin..xmax, y = ymin..ymax, ZRange = zmin..zmax) is equivalent to plotfunc3d(f(x, y), x = xmin..xmax, y = ymin..ymax, ViewingBoxZRange = zmin..zmax)
5-63
Here is a table of the most important attributes for arranging coordinate axes. In the interactive object browser, you will find them under CoordinateSystem2d (CS2d) and CoordinateSystem3d (CS3d), respectively: attribute name
Axes
browser entry
CS2d/3d
axes type
Automatic
AxesVisible
visibility TRUE of all axes visibility TRUE of the x axis visibility TRUE of the y axis visibility TRUE of the z axis titles of the axes (2D) titles of the axes (3D) title of the x axis title of the y axis
["x","y"]
CS2d/3d
XAxisVisible
TRUE, FALSE
CS2d/3d
YAxisVisible
TRUE, FALSE
CS2d/3d
ZAxisVisible
TRUE, FALSE
CS3d
AxesTitles
CS2d
AxesTitles
["x","y","z"] CS3d
XAxisTitle
string
"x"
CS2d/3d
YAxisTitle
string
"y"
CS2d/3d
5-64
browser entry
CS3d
alignment End for all axes titles alignment Center for all axes titles alignment End for the x axis title alignment Center for the x axis title alignment End for the y axis title alignment Center for the y axis title alignment Center for the z axis title
CS2d
CS3d
CS2d
CS3d
CS2d
CS3d
CS3d
5-65
(Continued) attribute name possible values/example meaning default orientationHorizontal of the y axis title axes with tips?
TRUE
browser entry
CS2d
AxesTips
TRUE, FALSE
CS2d/3d
AxesOrigin
crosspoint [0, 0] of the axes (2D) crosspoint [0, 0, 0] of the axes (3D) x value of y value of z value of color of the axes width of the axes lines
0
CS2d
AxesOrigin
CS3d
AxesOriginX
real value
CS2d/3d
AxesOrigin AxesOriginY
real value
CS2d/3d
AxesOrigin AxesOriginZ
real value
CS3d
0.18*unit::mm CS2d/3d
5-66
browser entry
CS2d
FALSE
Fonts
sans-serif 10
CS2d/3d
Here is a table of the most important attributes for setting tick marks and tick labels along the axes. In the interactive object browser, you will find them under CoordinateSystem2d (CS2d) and CoordinateSystem3d (CS3d), respectively: attribute name possible values/example browser entry
CS2d/3d
meaning visibility of ticks along all axes visibility of ticks along the x axis visibility of ticks along the y axis visibility of ticks along the z axis
default
TRUE
TRUE
CS2d/3d
TRUE
CS2d/3d
TRUE
CS3d
5-67
meaning distance between labeled ticks along all axes distance between labeled ticks along the x axis distance between labeled ticks along the y axis distance between labeled ticks along the z axis the position of a labeled tick to start with the position of a labeled tick to start with
default
CS2d/3d
CS2d/3d
CS3d
TicksAnchorreal value
CS2d/3d
CS2d/3d
5-68
meaning the position of a labeled tick to start with the position of a labeled tick to start with number of labeled ticks along all axes number of labeled ticks along the x axis number of labeled ticks along the y axis number of labeled ticks along the z axis
default
0
CS3d
Normal
CS2d/3d
Normal
CS2d/3d
Normal
CS2d/3d
Normal
CS3d
5-69
meaning number of smaller unlabeled ticks between labeled ticks along all axes number of smaller unlabeled ticks between labeled ticks along the x axis number of smaller unlabeled ticks between labeled ticks along the y axis number of smaller unlabeled ticks between labeled ticks along the z axis
default
1
TicksBetween integer 0
XTicksBetween integer 0
CS2d/3d
YTicksBetween integer 0
CS2d/3d
ZTicksBetween integer 0
CS3d
5-70
meaning
default
orientation Horizontal CS2d/3d and style of tick labels along all axes orientation Horizontal CS2d/3d and style of tick labels along the x axes orientation Horizontal CS2d/3d and style of tick labels along the y axis orientation Horizontal CS3d and style of tick labels along the z axis ticks set by the user, valid for all axes
CS2d/3d
TicksAt
5-71
meaning ticks along the x axis set by the user ticks along the y axis set by the user ticks along the z axis set by the user length of the tick marks font for all axes titles
default
browser entry
CS2d/3d
YTicksAt
see TicksAt
CS2d/3d
ZTicksAt
see TicksAt
CS3d
TicksLength2*unit::mm
2*unit::mm CS2d
sans-serif 8
CS2d/3d
Coordinate grid lines can be drawn in the background of a graphical scene (corresponding to the rulings of lined paper). They are attached to the tick marks along the axes. There are grid lines attached to the major labeled tick marks which are referred to as the Grid. There are also grid lines associated with the minor unlabeled tick marks set be the attribute TicksBetween. These minor grid lines are referred to as the Subgrid. The two kinds of grid lines can be set independently. In the interactive object browser, you will find the following attributes under CoordinateSystem2d (CS2d) and CoordinateSystem3d (CS3d), respectively:
5-72
(Continued) attribute name possible values/example meaning visibility of major grid lines in all directions visibility of minor grid lines in all directions visibility of major grid lines in x direction visibility of minor grid lines in x direction visibility of major grid lines in y direction visibility of minor grid lines in y direction visibility of major grid lines in z direction visibility of minor grid lines in z direction browser entry
CS2d/3d
default
FALSE
FALSE
CS2d/3d
XGridVisibleTRUE, FALSE
FALSE
CS2d/3d
FALSE
CS2d/3d
YGridVisibleTRUE, FALSE
FALSE
CS2d/3d
FALSE
CS2d/3d
ZGridVisibleTRUE, FALSE
FALSE
CS3d
FALSE
CS3d
5-73
(Continued) attribute name possible values/example meaning color of all major grid lines color of all minor grid lines width of all major grid lines width of all minor grid lines drawing style of all major grid lines drawing style of all minor grid lines grid lines in front of all objects? browser entry
default
RGB::Grey75 CS2d/3d
RGB::Grey
CS2d/3d
GridLineWidth 0.1*unit::mm
0.1*unit::mmCS2d/3d
SubgridLineWidth 0.1*unit::mm
0.1*unit::mmCS2d/3d
GridLineStyle Dashed, Dotted, Solid SubgridLineStyle Dashed, Dotted, Solid GridInFront TRUE, FALSE
Solid
CS2d/3d
Solid
CS2d/3d
FALSE
CS2d
Animations require that plotting ranges x = xmin..xmax (and y = ymin..ymax) are fully specified in plotfunc2d (or plotfunc3d, respectively). Animations are triggered by passing an additional range such as a = amin..amax to plotfunc2d/plotfunc3d. The animation parameter a may turn up in the expression of the functions that are to be plotted as well as in various other places such as the coordinates of titles etc. See section Graphics and Animations for details.
5-74
possible values/example meaning integer 0 number of frames of the animation name of the animation parameter range of the animation parameter lowest value of the animation parameter highest value of the animation parameter physical time range for the animation physical time when the animation begins physical time when the animation ends physical time when the object becomes invisible
default
50
browser entry
Function2d/3d
Function2d/3d
ParameterRange amin..amax
Function2d/3d
Function2d/3d
value
ParameterEndamax: real
Function2d/3d
value
TimeRange start..end
0..10
Function2d/3d
TimeBegin
start: real
Function2d/3d
value
TimeEnd
10
Function2d/3d
Function2d/3d
5-75
(Continued) attribute name possible values/example meaning physical time when the object becomes visible physical time range when the object is visible visible before animation begins? visible after animation ends?
TRUE
default
browser entry
Function2d/3d
VisibleAfterreal value
Function2d/3d
values
VisibleBeforeBegin TRUE, FALSE
Function2d/3d
TRUE
Function2d/3d
Functions are plotted as polygons consisting of straight line segments between points of the numerical mesh. The number of points in this numerical mesh are set by various mesh attributes: attribute name
Mesh
possible values/example meaning integer 2 number of major mesh points in x direction. The same as XMesh. number of major mesh points in x and y direction. Corresponds to XMesh, YMesh.
default
121
browser entry
Function2d
Mesh
[integer 2, integer 2]
[25,25]
Function3d
5-76
possible values/example meaning integer 0 number of minor mesh points between the major mesh points set by Mesh. The same as XSubmesh. number of minor mesh points between the major mesh points set by Mesh. Corresponds to XSubmesh, YSubmesh. number of major mesh points in the x direction number of major mesh points in the x direction number of minor mesh points between the major mesh points set by
XMesh
default
0
browser entry
Function2d
Submesh
[integer 0, integer 0]
[0, 0]
Function3d
XMesh
integer 2
121
Function2d
XMesh
integer 2
25
Function3d
XSubmesh
integer 0
Function2d/3d
5-77
possible values/example meaning integer 2 number of major mesh points in the y direction number of major mesh points in the y direction number of minor mesh points between the major mesh points set by
YMesh
default
121
browser entry
Function2d
YMesh
integer 2
25
Function3d
YSubmesh
integer 0
Function3d
2 0
Function2d Function3d
In 2D pictures generated by plotfunc2d, singularities of a function are indicated by vertical lines (vertical asymptotes), unless DiscontinuitySearch = FALSE is set. Here is a table with the attributes for setting the style of the vertical asymptotes: attribute name possible values/example meaning visibility color browser entry
Function2d Function2d
default
TRUE RGB::Grey50
5-78
(Continued) attribute name possible values/example meaning drawing style physical width browser entry
Function2d
default
Dashed
0.2*unit::mm Function2d
The colors of the functions plotted by plotfunc2d are chosen automatically. The property inspector (see section Viewer, Browser, and Inspector: Interactive Manipulation) allows to change these attributes: attribute possible name values/example meaning
LinesVisible TRUE, FALSE LineWidth 0.2*unit::mm LineColor RGB color LineColor2 RGB color LineStyle Dashed, Dotted, Solid LineColorType Dichromatic, Flat, Functional, Monochrome, Rainbow
visibility of lines (switch this function on/off) physical line width color drawing style of line objects color scheme for lines
Function2d
Setting LinesVisible = FALSE and PointsVisible = TRUE, the functions plotted by plotfunc2d will not be displayed as polygons but as sequences of points. Here is a table of the attributes to set the presentation style of points:
5-79
(Continued) attribute name possible values/example meaning visibility of points physical size of points browser entry
Function2d
default
FALSE
Circles, presentation Crosses, style of Diamonds, points FilledCircles, FilledDiamonds, FilledSquares, Squares, Stars, XCrosses
The colors and surface styles of the functions plotted by plotfunc3d are chosen automatically. The property inspector (see section Viewer, Browser, and Inspector: Interactive Manipulation) allows to the change these attributes: attribute name
Filled
default
TRUE
browser entry
Function3d
display as a surface or as a wireframe model? main color (for flat coloring) secondary color (for
Dichromatic
FillColor FillColor2
Function3d Function3d
and
Monochrome
coloring)
5-80
(Continued) attribute name possible values/example meaning color scheme browser entry
default
FillColorType Dichromatic, Flat, Functional, Monochrome, Rainbow FillColorFunction procedure Shading Smooth, Flat
Dichromatic Function3d
user defined coloring smooth or flat shading? visibility of x parameter lines visibility of y parameter lines visibility of the internal triangulation width
Smooth TRUE
TRUE
Function3d
FALSE
Function3d
LineWidth LineColor
Besides the usual linear plots, logarithmic plots are also possible by choosing an appropriate CoordinateType. With Scaling = Constrained, the unit box in model coordinates (a square in 2D, a cube in 3D) is displayed as a unit box. With Scaling = Unconstrained, the renderer applies different scaling transformation in the coordinate directions to obtain an optimal fit of the picture in the display window. This,
5-81
however, may distort a circle to an ellipse. With Scaling = Constrained a 2D circle appears on the screen like a circle, a 3D sphere appears like a sphere. 2D functions are preprocessed by a semi-symbolic search for discontinuities to improve the graphical representation near singularities and to avoid graphical artifacts. If continuous functions are plotted, one may gain some speed up by switching off this search with DiscontinuitySearch = FALSE. When very time consuming plots are to be created, it may be useful to create the plots in batch mode. With the attribute OutputFile = filename, the graphical output is not rendered to the screen. An external file with the specified name containing the graphical data is created instead. It may contain xml data that may be viewed later by opening the file with the MuPAD graphics tool VCam. Alternatively, bitmap files in various standard bitmap formats such as bmp, jpg etc. can be created that may be viewed by other standard tools. See section Batch Mode for further details. attribute name possible values/example meaning browser entry
Coord.Sys.2d
default
CoordinateType LinLin, LinLog, LogLin, LogLog CoordinateType LinLinLin, ..., LogLogLog Scaling
Coord.Sys.3d
UnconstrainedCoord.Sys.2d/3d
YXRatio
aspect ratio
y : x
Scene2d/3d
(only for
Scaling = Unconstrained)
5-82
default
2/3
browser entry
Scene3d
(only for
Scaling = Unconstrained) DiscontinuitySearch TRUE, FALSE
enable/disable TRUE semi-symbolic search for discontinuities save the plot data in a file
Function2d
OutputFile
string
5-83
General Principles
In general, graphical scenes are collections of graphical primitives. There are simple primitives such as points, line segments, polygons, rectangles
5-84
and boxes, circles and spheres, histogram plots, pie charts etc. An example of a more advanced primitive is plot::VectorField2d that represents a collection of arrows attached to a regular mesh visualizing a vector field over a rectangular region in 2. Yet more advanced primitives are function graphs and parametrized curves that come equipped with some internal intelligence, e.g., knowing how to evaluate themselves numerically on adaptive meshes and how to clip themselves in case of singularities. The most advanced primitives in the present plot library are plot::Ode2d, plot::Ode3d and plot::Implicit2d, plot::Implicit3d. The first automatically solve systems of ordinary differential equations numerically and display the solutions graphically. The latter display the solution curves or surfaces of algebraic equations f(x, y) = 0 or f(x, y, z) = 0, respectively, by solving these equation numerically. All these primitives are just objects representing some graphical entities. They are not rendered directly when they are created, but just serve as data structures encoding the graphical meaning, collecting attributes defining the presentation style and providing numerical routines to convert the input parameters to some numerical data that are to be sent to the renderer. An arbitrary number of such primitives can be collected to form a graphical scene. Finally, a call to plot passing a sequence of all primitives in the scene invokes the renderer to draw the plot. The following example shows the graph of the function f(x) = xsin(x). At the point (x0, f(x0)), a graphical point is inserted and the tangent to the graph through this point is added: f := x -> x*sin(x): x0 := 1.2: dx := 1: g := plot::Function2d(f(x), x = 0..2*PI): p := plot::Point2d(x0, f(x0)): t := plot::Line2d([x0 - dx, f(x0) - f'(x0)*dx], [x0 + dx, f(x0) + f'(x0)*dx]): The picture is drawn by calling plot: plot(g, p, t):
5-85
Each primitive accepts a variety of plot attributes that may be passed as a sequence of equations AttributeName = AttributeValue to the generating call. Most prominently, each primitive allows to set the color explicitly: g := plot::Function2d(f(x), x = 0..2*PI, Color = RGB::Blue): Alternatively, the generated objects allow to set attributes via slot assignments of the form primitive::AttributeName := AttributeValue as in p::Color := RGB::Black: p::PointSize := 3.0*unit::mm: t::Color := RGB::Red: t::LineWidth := 1.0*unit::mm: The help page of each primitive provides a list of all attributes the primitive is reacting to.
5-86
Certain attributes such as axes style, the visibility of grid lines in the background etc. are associated with the whole scene rather than with the individual primitives. These attributes may be included in the plot call: plot(g, p, t, GridVisible = TRUE):
As explained in detail in section The Full Picture: Graphical Trees, the plot command automatically embeds the graphical primitives in a coordinate system, which in turn is embedded in a graphical scene, which is drawn inside a canvas. The various attributes associated with the general appearance of the whole picture are associated with these grouping structures: a concise list of all such attributes is provided on the help pages of plot::Canvas, plot::Scene2d, plot::Scene3d, plot::CoordinateSystem2d, and plot::CoordinateSystem3d, respectively. The object browser provided by the MuPAD graphics tool allows to select each primitive in the plot. After selection, the attributes of the primitive can be changed interactively in the property inspector (see section Viewer, Browser, and Inspector: Interactive Manipulation).
5-87
Next, we wish to demonstrate a animation. It is remarkably simple to generate an animated picture. We want to let the point x0 at which the tangent is added move along the graph of the function. In MuPAD, you do not need to create an animation frame by frame. Instead, each primitive can be told to animate itself by simply defining it with a symbolic animation parameter and adding an animation range for this parameter. Static and animated objects can be mixed and rendered together. The static function graph of f(x) used in the previous plot is recycled for the animation. The graphical point at (x0, f(x0)) and the tangent through this point shall be animated using the coordinate x0 as the animation parameter. Deleting its value set above, we can use the same definitions as before, now with a symbolic x0. We just have to add the range specification x0 = 0..2*PI for this parameter: delete x0: dx := 2/sqrt(1 + f'(x0)^2): p := plot::Point2d(x0, f(x0), x0 = 0..2*PI, Color = RGB::Black, PointSize = 2.0*unit::mm): t := plot::Line2d([x0 - dx, f(x0) - f'(x0)*dx], [x0 + dx, f(x0) + f'(x0)*dx], x0 = 0..2*PI, Color = RGB::Red, LineWidth = 1.0*unit::mm): plot(g, p, t, GridVisible = TRUE):
5-88
Details on animations and further examples are provided in section Graphics and Animations. We summarize the construction principles for graphics with the MuPAD plot library: Note Graphical scenes are built from graphical primitives. Section Graphics and Animations provides a survey of the primitives that are available in the plot library.
Note Primitives generated by the plot library are symbolic objects that are not rendered directly. The call plot(Primitive1, Primitive2, ...) generates the pictures.
5-89
Note Graphical attributes are specified as equations AttributeName = AttributeValue. Attributes for a graphical primitive may be passed in the call that generates the primitive. The help page of each primitive provides a complete list of all attributes the primitive reacts to.
Note Attributes determining the general appearance of the picture may be passed in the plot call. The help pages of plot::Canvas, plot::Scene2d, plot::Scene3d, plot::CoordinateSystem2d, and plot::CoordinateSystem3d, respectively, provide a complete list of all attributes determining the general appearance.
Note Presently, 2D and 3D plots are strictly separated. Objects of different dimension cannot be rendered in the same plot.
Note Animations are not created frame by frame but objectwise (also see section Frame by Frame Animations). An object is animated by generating it with a symbolic animation parameter and providing a range for this parameter in the generating call. Section Graphics and Animations provides for further details on animations.
5-90
Presently, it is not possible to add objects to an existing plot. However, using animations, it is possible to let primitives appear one after another in the animated picture. See Graphics and Animations.
Some Examples
Example 1
We wish to visualize the interpolation of a discrete data sample by cubic splines. First, we define the data sample, consisting of a list of points [[x1, y1], [x2, y2], ]. Suppose they are equidistant sample points from the graph of the function :
f := x -> x*exp(-x)*sin(5*x): data := [[i/3, f(i/3)] $ i = 0..9]: We use numeric::cubicSpline to define the cubic spline interpolant through these data: S := numeric::cubicSpline(op(data)): The plot shall consist of the function f(x) that provides the data of the sample points and of the spline interpolant S(x). The graphs of f(x) and S(x) are generated via plot::Function2d. The data points are plotted as a plot::PointList2d: plot( plot::Function2d(f(x), x = 0..3, Color = RGB::Red, LegendText = expr2text(f(x))), plot::PointList2d(data, Color = RGB::Black), plot::Function2d(S(x), x = 0..3, Color = RGB::Blue, LegendText = "spline interpolant"), GridVisible = TRUE, SubgridVisible = TRUE, LegendVisible = TRUE ):
5-91
Example 2
A cycloid is the curve that you get when following a point fixed to a wheel rolling along a straight line. We visualize this construction by an animation in which we use the x coordinate of the hub as the animation parameter. The wheel is realized as a circle. There are 3 points fixed to the wheel: a green point on the rim, a red point inside the wheel and a blue point outside the wheel: WheelRadius := 1: WheelCenter := [x, WheelRadius]: WheelRim := plot::Circle2d(WheelRadius, WheelCenter, x = 0..4*PI, LineColor = RGB::Black): WheelHub := plot::Point2d(WheelCenter, x = 0..4*PI, PointColor = RGB::Black): WheelSpoke := plot::Line2d(WheelCenter, [WheelCenter[1] + 1.5*WheelRadius*sin(x), WheelCenter[2] + 1.5*WheelRadius*cos(x)], x = 0..4*PI, LineColor = RGB::Black):
5-92
color:= [RGB::Red, RGB::Green, RGB::Blue]: r := [1.5*WheelRadius, 1.0*WheelRadius, 0.5*WheelRadius]: for i from 1 to 3 do Point[i] := plot::Point2d([WheelCenter[1] + r[i]*sin(x), WheelCenter[2] + r[i]*cos(x)], x = 0..4*PI, PointColor = color[i], PointSize = 2.0*unit::mm): Cycloid[i] := plot::Curve2d([y + r[i]*sin(y), WheelRadius + r[i]*cos(y)], y = 0..x, x = 0..4*PI, LineColor = color[i]): end_for: plot(WheelRim, WheelHub, WheelSpoke, Point[i] $ i = 1..3, Cycloid[i] $ i = 1..3, Scaling = Constrained, Width = 120*unit::mm, Height = 60*unit::mm):
Example 3
We wish to visualize the solution of the ordinary differential equation (ODE) with the initial condition y(0) = 0. The solution shall be drawn together with the vector field associated
5-93
with this ODE (along the solution curve, the vectors of this field are tangents of the curve). We use numeric::odesolve2 to generate the solution as a function plot. Since the numerical integrator returns the result as a list of one floating-point value, one has to pass the single list entry as Y(x)[1] to plot::Function2d. The vector field is generated via plot::VectorField2d: f := (x, y) -> -y^3 + cos(x): Y := numeric::odesolve2( numeric::ode2vectorfield({y'(x) = f(x, y), y(0) = 0}, [y(x)])): plot( plot::Function2d(Y(x)[1], x = 0..6, Color = RGB::Red, LineWidth = 0.7*unit::mm), plot::VectorField2d([1, f(x, y)], x = 0..6, y = -1..1, Color = RGB::Blue, Mesh = [25, 25]), GridVisible = TRUE, SubgridVisible = TRUE, Axes = Frame ):
5-94
Example 4
The radius r of an object with rotational symmetry around the x-axis is measured at various x positions: x r (x ) 0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 0.95 1.00 0.60 0.58 0.55 0.51 0.46 0.40 0.30 0.15 0.23 0.24 0.20 0.00
A spline interpolation is used to define a smooth function r(x) from the measurements: samplepoints := [0.00, 0.60], [0.10, 0.58], [0.20, 0.55], [0.30, 0.51], [0.40, 0.46], [0.50, 0.40], [0.60, 0.30], [0.70, 0.15], [0.80, 0.23], [0.90, 0.24], [0.95, 0.20], [1.00, 0.00]: r := numeric::cubicSpline(samplepoints): We reconstruct the object as a surface of revolution via plot::XRotate. The rotation angle is restricted to a range that leaves a gap in the surface. The spline curve and the sample points are added as a plot::Curve3d and a plot::PointList3d, respectively, and displayed in this gap: plot( plot::XRotate(r(x), x = 0..1, AngleRange = 0.6*PI..2.4*PI, Color = RGB::MuPADGold), plot::Curve3d([x, 0, r(x)], x = 0..1, LineWidth = 0.5*unit::mm, Color = RGB::Black), plot::PointList3d([[p[1], 0, p[2]] $ p in samplepoints], PointSize = 2.0*unit::mm, Color = RGB::Red), CameraDirection = [70, -70, 40] ):
5-95
Example 5
The following sum is a Fourier representation of a periodic step function:
for some small values of n. To this end, we assign the value of fn(x) to the MuPAD identifier f_n. For our second and third example, we will need to accept fractional values of n, so the code uses floor to get a proper integer value for the sum: f_n := sum(sin((2*k-1)*x)/(2*k-1), k = 1..floor(n))
5-96
First, we use plotfunc2d and the sequence operator $ to plot the first 5 partial sums into the same coordinate system (and switch off the legend, which is not useful for this application). plotfunc2d(f_n $ n = 1..5, LegendVisible = FALSE)
This plot clearly shows what is known as Gibbs phenomenon: At the discontinuities of the step function, the approximation overshoots. Plotting more approximations simultaneously is going to create a too crowded plot to be of use, so to show that using more terms in the sum does not help against Gibbs phenomenon, we revert to animations to show the first 30 partial sums this is one of the reasons we used floor(n) above: plotfunc2d(f_n, x = -5..5, n = 1..30, Frames = 15)
5-97
Another possibility of showing the convergence behavior is to create a 3D plot with the second ordinate being the number of terms used in the approximation: plotfunc3d(f_n, x = -5..5, n = 1..30, Submesh = [5,1], FillColorType = Rainbow)
5-98
5-99
5-100
See section Layout of Canvas and Scenes for details on how the layout of a canvas containing several scenes is set. Coordinate systems of type plot::CoordinateSystem2d or plot::CoordinateSystem3d exist inside a 2D scene or a 3D scene, respectively. There may be one or more coordinate systems in a scene. Each coordinate system has its own axes. In the following example, we place two coordinate systems in one scene. The first is used to display the sales of apples in the years 1998 through 2003 in units of 1000 tons, the second is used to display the sale of cars in units of 10.000 cars. The y-axis for the apples is flushed left by setting the x component of its origin to the first year 1998, whilst the y-axis for the cars is flushed right by setting the x component of its origin to the last year 2003: apples := plot::Polygon2d( [[1998, 7.4], [1999, 7.8], [2000, [2001, 8.3], [2002, 8.0], [2003, Color = RGB::Red, PointsVisible = cars := plot::Polygon2d( [[1998, 3.2], [1999, 3.5], [2000,
5-101
[2001, 3.7], [2002, 4.0], [2003, 4.1]], Color = RGB::Blue, PointsVisible = TRUE): plot(plot::Scene2d( plot::CoordinateSystem2d(apples, ViewingBoxYRange = 0..10, YAxisTitle = "apples/10^3 tons", Axes = Origin, AxesOriginX = 1998, XTicksNumber = None, XTicksAt = [$ 1998..2003]), plot::CoordinateSystem2d(cars, ViewingBoxYRange = 0..5, YAxisTitle = "cars/10^4", Axes = Origin, AxesOriginX = 2003, XTicksNumber = None, XTicksAt = [$ 1998..2003]) )):
Inside the coordinate systems, an arbitrary number of primitives (of the appropriate dimension) can be displayed. Thus, we always have a canvas, containing one or more scenes, with each scene containing one or more coordinate systems. The graphical primitives (or groups of such primitives)
5-102
are contained in the coordinate systems. Hence, any MuPAD plot has the following general structure:
Canvas | +-- Scene 1 | | | +-- CoordinateSystem 1 | | +-- Primitive 1 | | +-- Primitive 2 | | ... | | | +-- CoordinateSystem 2 | | +-- Primitive | | ... | ... | +-- Scene 2 | | | +-- CoordinateSystem | | +-- Primitive | | ... | ... ...
This is the graphical tree that is displayed by the object browser of the MuPAD graphics tool (see section Viewer, Browser, and Inspector: Interactive Manipulation). Shortcuts: For simple plots containing primitives inside one coordinate system only that resides in a single scene of the canvas, it would be rather cumbersome to generate the picture by a command such as plot( plot::Canvas( plot::Scene2d( plot::CoordinateSystem2d(Primitive1, Primitive2, ...) ) )
5-103
): In fact, the command plot(Primitive1, Primitive2, ...): suffices: It is a shortcut of the above command. It generates automatically a coordinate system that contains the primitives, embedded it in a scene which is automatically placed inside a canvas object. Thus, this command implicitly creates the graphical tree
Canvas | +-- Scene 1 | +-- CoordinateSystem 1 +-- Primitive 1 +-- Primitive 2 ...
5-104
In the object browser, the graphical tree of the plot as introduced in the preceding section is visible. It allows to select any node of the graphical tree by a mouse click. After selecting an object in the object browser, the corresponding part of the plot is highlighted in some way allowing to identify the selected object visually. The property inspector now displays all attributes the selected object reacts to. For example, for an object of type Function2d, the attributes visible in the property inspector are categorized as Definition, Animation, Annotation, Calculation, and Style with the latter split into the sub-categories (Style of) Lines, (Style of) Points, (Style of) Asymptotes. Opening one of these categories, one finds the attributes and their current values that apply to the currently selected object. After selection of an attribute with the mouse, its value can be changed:
5-105
There is a sophisticated way of setting defaults for the attributes via the object browser and the property inspector. The View menu provides an item Hide Defaults. Disabling Hide Defaults, the object browser changes from
5-106
to:
5-107
At each node of the graphical tree, default values for the attributes can be set via the property inspector. These defaults are valid for all primitives that exist below this node, unless these defaults are redefined at some other node further down in tree hierarchy. This mechanism is particularly useful when there are many primitives of the same kind in the plot. Imagine a picture consisting of 1000 points. If you wish to change the color of all points to green, it would be quite cumbersome to set PointColor = RGB::Green in all 1000 points. Instead, you can set PointColor = RGB::Green in the PointColor defaults entry at some tree node that contains all the points (e.g., the canvas). Similarly, if there are 1000 points in one scene and another 1000 points in a second scene, you can change the color of all points in the first scene by an appropriate default entry in
5-108
the first scene, whilst the default entry for the second scene can be set to a different value. A 3D plot can be rotated and shifted by the mouse. Also zooming in and out is possible. In fact, these operations are realized by moving the camera around, closer to, or farther away from the scene, respectively. There is a camera control that may be switched on and off via the Camera Control item of the View menu. It provides the current viewing parameters such as camera position, focal point and the angle of the camera lens:
Section Attributes for plotfunc2d and plotfunc3d provides more information on cameras.
5-109
Primitives
In this section, we give a brief survey of the graphical primitives, grouping constructs, transformation routines etc. provided by the plot library. The following table lists the low-level primitives.
plot::Arc2d plot::Arrow2d plot::Arrow3d plot::Box plot::Circle2d plot::Circle3d plot::Cone plot::Cylinder plot::Ellipse2d plot::Ellipsoid plot::Line2d plot::Line3d plot::Parallelogram2d plot::Parallelogram3d plot::Point2d plot::Point3d plot::PointList2d plot::PointList3d plot::Polygon2d plot::Polygon3d
circular arc in 2D arrow in 2D arrow in 3D rectangular box in 3D circle in 2D circle in 3D cone/conical frustum in 3D cylinder in 3D ellipse in 2D ellipsoid in 3D graphical line segment in 2D graphical line segment in 3D parallelogram in 2D parallelogram in 3D graphical point in 2D graphical point in 3D collection of graphical points in 2D collection of graphical points in 3D line segments forming a polygon in 2D line segments forming a polygon in 3D
5-110
Primitives
rectangle in 2D sphere in 3D surfaces in 3D (as a collection of 3D triangles) import of 3D stl surfaces text object in 2D text object in 3D
The following table lists the high-level primitives and special purpose primitives.
plot::Bars2d plot::Bars3d plot::Boxplot plot::Conformal plot::Curve2d plot::Curve3d plot::Density plot::Function2d plot::Function3d plot::Hatch plot::Histogram2d
(statistical) data plot in 2D (statistical) data plot in 3D (statistical) box plot conformal plot of complex functions parametrized curve in 2D parametrized curve in 3D density plot in 2D function graph in 2D function graph in 3D hatched region in 2D (statistical) histogram plot in 2D
5-111
plot::Implicit2d plot::Implicit3d plot::Inequality plot::Integral plot::Iteration plot::Listplot plot::Lsys plot::Matrixplot plot::MuPADCube plot::Ode2d plot::Ode3d plot::Piechart2d plot::Piechart3d plot::Plane plot::Raster plot::Scatterplot plot::Sequence plot::SparseMatrixplot plot::Sum plot::Surface plot::Sweep plot::Turtle plot::VectorField2d plot::VectorField3d
plot of implicitly defined curves in 2D plot of implicitly defined surfaces in 3D visualization of inequalities in 2D visualization of integration visualization of iterations in 2D lists of points in 2D Lindenmayer system in 2D visualization of matrix data as a surface in 3D the MuPAD logo graphical solution of an ODE in 2D graphical solution of an ODE in 3D (statistical) pie chart in 2D (statistical) pie chart in 3D infinite plane in 3D raster and bitmap plots in 2D (statistical) scatter plot in 2D visualization of a sequence of numbers sparsity pattern of a matrix visualization of a sum of numbers parametrized surface in 3D sweep surface in 3D turtle plot in 2D vector field plot in 2D vector field plot in 3D
5-112
Primitives
plot::XRotate plot::ZRotate
The following table lists the various light sources available to illuminate 3D plots.
plot::AmbientLight plot::DistantLight plot::PointLight plot::SpotLight
ambient (undirected) light directed light (undirected) point light (directed) spot light
drawing area, container for 2D or 3D scenes container for 2D coordinate systems container for 3D coordinate systems container for 2D primitives and
plot::Group2d
5-113
5-114
Attributes
Attributes
In this section... Default Values on page 5-116 Inheritance of Attributes on page 5-117 Primitives Requesting Special Scene Attributes: Hints on page 5-125 The Help Pages of Attributes on page 5-127 The plot library provides for more than 400 attributes for fine-tuning of the graphical output. Because of this large number, the attributes are grouped into various categories in the object browser (see section Viewer, Browser, and Inspector: Interactive Manipulation) and the documentation: category Animation Annotation Axes Cameras Lights Calculation Definition Grid Lines Layout Style meaning parameters relevant for animations footer, header, titles, and legends axes style and axes titles cameras in 3D lights in 3D numerical evaluation (mesh parameters) parameters that change the object itself grid lines in the background (rulings) layout parameters for canvas and scenes parameters that do not change the objects but their presentation (visibility, color, line width, point size etc.) style parameters for arrows style parameters for line objects
5-115
style parameters for point objects style parameters for surface objects in 3D and filled areas in 2D axes tick marks: style and labels
On the help page for each primitive, there is a complete list of all attributes the primitive reacts to. Clicking on an attribute, you are lead to the help page for this attribute which provides for all the necessary information concerning its semantics and admissible values. The examples on the help page demonstrate the typical use of the attribute.
Default Values
Most attributes have a default value that is used if no value is specified explicitly. As an example, we consider the attribute LinesVisible that is used by several primitives such as plot::Box, plot::Circle2d, plot::Cone, plot::Curve2d, plot::Raster etc. Although they all use the same attribute named LinesVisible, its default value differs among the different primitive types. The specific defaults are accessible by the slots plot::Box::LinesVisible, plot::Circle2d::LinesVisible etc.: plot::getDefault(plot::Box::LinesVisible), plot::getDefault(plot::Circle2d::LinesVisible), plot::getDefault(plot::Cone::LinesVisible), plot::getDefault(plot::Raster::LinesVisible)
If any of the default values provided by the MuPAD system do not seem appropriate for your applications, change these defaults via plot::setDefault: plot::setDefault(plot::Box::LinesVisible = FALSE)
5-116
Attributes
(The return value is the previously valid default value.) Several defaults can be changed simultaneously: plot::setDefault(plot::Box::LinesVisible = FALSE, plot::Circle2d::LinesVisible = FALSE, plot::Circle2d::Filled = TRUE)
plot::getDefault(plot::Box::LinesVisible)
Inheritance of Attributes
The setting of default values for attributes is quite sophisticated. Assume that you have two scenes that are to be displayed in one single canvas. Both scenes consist of 51 graphical points, each: points1 := plot::Point2d(i/50*PI, sin(i/50*PI)) $ i = 0..50: points2 := plot::Point2d(i/50*PI, cos(i/50*PI)) $ i = 0..50: S1 := plot::Scene2d(points1): S2 := plot::Scene2d(points2): plot(S1, S2):
5-117
If we wish to color all points in both scenes red, we can set a default for the point color in the plot command: plot(S1, S2, PointColor = RGB::Red):
5-118
Attributes
If we wish to color all points in the first scene red and all points in the second scene blue, we can give each of the points the desired color in the generating call to plot::Point2d. Alternatively, we can set separate defaults for the point color inside the scenes: S1 := plot::Scene2d(points1, PointColor = RGB::Red): S2 := plot::Scene2d(points2, PointColor = RGB::Blue): plot(S1, S2):
5-119
Here is the general rule for setting defaults inside a graphical tree (see The Full Picture: Graphical Trees): Note When an attribute is specified in a node of the graphical tree, the specified value serves as the default value for the attribute for all primitives that exist in the sub-tree starting from that node. The default value can be overwritten by another value at each node further down in the sub-tree (for example, finally, by a specific value in the primitives). In the following call, the default color red is set in the canvas. This value is accepted and used in the first scene. The second scene sets the default color blue overriding the default value red set in the canvas. Additionally, there is an extra point with a color set explicitly to black. This point ignores the defaults set further up in the tree hierarchy: extrapoint := plot::Point2d(1.4, 0.5, PointSize = 3*unit::mm, PointColor = RGB::Black): S1 := plot::Scene2d(points1, extrapoint):
5-120
Attributes
The following call generates the same result. Note that the plot command automatically creates a canvas object and passes the attribute PointColor = RGB::Red to the canvas: plot(S1, S2, PointColor = RGB::Red):
5-121
We note that there are different primitives that react to the same attribute. We used LinesVisible in the previous section to demonstrate this fact. One of the rules for inheriting attributes in a graphical tree is: Note If an attribute such as LinesVisible = TRUE is specified in some node of the graphical tree, all primitives below this node that react to this attribute use the specified value as the default value. If a type specific attribute such as plot::Circle2d::LinesVisible = TRUE is specified, the new default value is valid only for primitives of that specific type. In the following example, we consider 100 randomly placed circles with a rectangle indicating the area into which all circle centers are placed: rectangle := plot::Rectangle(0..1, 0 ..1): circles := plot::Circle2d(0.05, [frandom(), frandom()]) $ i = 1..100:
5-122
Attributes
We wish to turn the circles into filled circles by Filled = TRUE, LinesVisible = FALSE: plot(rectangle, circles, Filled = TRUE, FillPattern = Solid, LinesVisible = FALSE, Axes = Frame):
5-123
This is not quite what we wanted: Not only the circles, but also the rectangle reacts to the attributes Filled, FillPattern, and LinesVisible. The following command restricts these attributes to the circles: plot(rectangle, circles, plot::Circle2d::Filled = TRUE, plot::Circle2d::FillPattern = Solid, plot::Circle2d::LinesVisible = FALSE, Axes = Frame):
5-124
Attributes
However, there are exceptions. E.g., a plot containing a 3D pie chart should probably have no axes at all. Since it is not desirable to use Axes = None as the default setting for all plots, exceptional primitives such as plot::Piechart3d are given a chance to override the default axes automatically. In a pie chart plot, no axes are used by default: plot(plot::Piechart3d([20, 30, 10, 7, 20, 13],
5-125
Note that Axes is a scene attribute that cannot be processed by pie chart objects directly. Hence, a separate mechanism for requesting special scene attributes by primitives is implemented: so-called hints. A hint is an attribute of one of the superordinate nodes in the graphical tree, for example, an attribute of a coordinate system, a scene or the canvas. The help pages of the primitives give information on what hints are sent by the primitive. If several primitives send conflicting hints, the first hint is used. Hints are implemented internally and cannot be switched off by the user. Note, however, that the hints concept only concerns default values for attributes. You can always specify the attribute explicitly if you think that a default value or a hint is not appropriate. E.g., we explicitly request Axes = Boxed in the following call: plot(plot::Piechart3d([20, 30, 10, 7, 20, 13], Titles = [1 = "20%", 2 = "30%", 3 = "10%",
5-126
Attributes
4 = Axes = Boxed):
5-127
The Details section gives further information on the semantics of the attribute(s). Finally, there are Examples of plot commands using the described attribute(s).
5-128
attribute name
Width Height
default
120*unit::mm 80*unit::mm RGB::White RGB::Grey50 0 1*unit::mm
physical width of the canvas physical height of the canvas color of the background color of the border width of the border common width for all margins: BottomMargin, LeftMargin, etc. width of the bottom margin width of the left margin width of the right margin
RGB color
1*unit::mm 1*unit::mm
5-129
attribute name
TopMargin Footer Header
default
1*unit::mm "" (no footer) "" (no header) Center Center
width of the top margin footer text header text horizontal footer alignment horizontal header alignment font for the footer font for the header automatic or user-defined layout?
string string
FooterAlignment Left, Center, Right HeaderAlignment Left, Center, Right FooterFont HeaderFont Layout
see section Fonts see section Fonts Tabular, Horizontal, Vertical, Absolute, Relative integer > 0
sans-serif 12 sans-serif 12
Tabular
Rows
number of rows in automatic tabular layout mode number of columns in automatic tabular layout mode space between scenes
1.0*unit::mm
Columns
integer > 0
Spacing
1.0*unit::mm
A canvas may contain one or more scenes. The following picture shows a canvas with four scenes to illustrate the meaning of the layout attributes
5-130
The basic attribute that switches between automatic and user-defined layout is Layout: With the default setting Layout = Tabular, a sequence of scenes in a canvas is displayed as a graphical array. The number of columns or rows of this array may be chosen via the attributes Columns or Rows, respectively. If none of these attributes is specified, the tabular layout scheme chooses some suitable values automatically. The setting Layout = Horizontal places the scenes side by side in a single row. It is a shortcut for the setting Layout = Tabular, Rows = 1:
5-131
The setting Layout = Vertical places the scenes one below the other in a single column. It is a shortcut for the setting Layout = Tabular, Columns = 1:
The settings Layout = Absolute and Layout = Relative switch the automatic layout mode off and allow to position each scene via the scene attributes Left and Bottom. These attributes determine the position of the lower left corner of the scene and can be set separately for each scene. With Layout = Absolute, the values for the lower left corner of the scene as well as its width and height may be specified as absolute physical lengths such as Left = 3.0*unit::mm, Bottom = 4.5*unit::mm, Width = 10*unit::cm, Height = 4*unit::inch.
5-132
With Layout = Relative, these values may be specified as fractions of the canvas height and width. E.g.,
Layout = Relative, Left = 0.3, Bottom = 0.2, Width = 0.5, Height = 0.5
is equivalent to
Layout = Absolute, Left = 0.3*canvaswidth, Bottom = 0.2*canvasheight, Width = 0.5*canvaswidth, Height = 0.5*canvasheight,
where canvaswidth and canvasheight are the physical width and height of the canvas. The following command uses Layout = Relative to position 3 scenes by specifying the lower left corner together with their widths and heights as fractions of the canvas dimensions: Left1 := 0.1: Bottom1 := 0.06: Width1 := 0.60: Height1 := 0.8: Left2 := 0.6: Bottom2 := 0.5: Width2 := 0.35: Height2 := 0.45: Left3 := 0.75: Bottom3 := 0.2: Width3 := 0.22: Height3 := 0.35: plot(plot::Canvas( BorderWidth = 0.5*unit::mm, BackgroundColor = RGB::Grey, plot::Scene2d(plot::Rectangle(-1.2..1.2, -1.2..1.2), Left = Left1, Bottom = Bottom1, Width = Width1, Height = Height1), plot::Scene2d(plot::Rectangle(-1.2..1.2, -1.2..1.2), Left = Left2, Bottom = Bottom2, Width = Width2, Height = Height2), plot::Scene2d(plot::Rectangle(-1.2..1.2, -1.2..1.2), Left = Left3, Bottom = Bottom3, Width = Width3, Height = Height3), Header = "The Canvas Header", Layout = Relative, Width = 110*unit::mm, Height = 90*unit::mm)):
5-133
In detail:
5-134
Layout of Scenes
The following scene attributes are relevant for the layout and the style of a scene: Layout and style parameters for scenes possible values/example meaning
0.8, 12*unit::cm 0.8, 8*unit::cm
attribute name
Width
default automatic
width of the scene (relative or absolute value) height of the scene (relative or absolute value)
Height
automatic
5-135
Layout and style parameters for scenes (Continued) possible values/example meaning color of the background secondary color for color blend (3D only) style of color blend (3D only) background transparent or opaque? color of the border width of the border common width for all margins: BottomMargin, LeftMargin, etc. width of the bottom margin width of the left margin width of the right margin width of the top margin footer text header text
attribute name
default
RGB::White RGB::Grey75
FLAT
FALSE
RGB color
1*unit::mm 1*unit::mm
RGB::SlateGrey 0 1*unit::mm
1*unit::mm 1*unit::mm 1*unit::mm 1*unit::mm "" (no footer) "" (no header)
string string
5-136
Layout and style parameters for scenes (Continued) possible values/example meaning horizontal footer alignment horizontal header alignment font for the footer font for the header legend on/off horizontal legend alignment vertical legend placement distance of the left side of the scene to the left side of the canvas (relative or absolute value) distance of the bottom side of the scene to the bottom side of the canvas (relative or absolute value)
attribute name
default
Center Center
FooterAlignment Left, Center, Right HeaderAlignment Left, Center, Right FooterFont HeaderFont LegendVisible
sans-serif 12 sans-serif 12
FALSE Center Bottom 0
LegendAlignment Center, Left, Right LegendPlacement Bottom, Top Left 0.1, 1.0*unit::mm
Bottom
0.1, 1.0*unit::mm
Similar to the canvas, scenes can have a border (set via BorderWidth and BorderColor). There is a (small) margin into which no graphical content is rendered. Further, a header and a footer can be specified:
5-137
5-138
Animations
Animations
In this section... Generate Simple Animations on page 5-139 Play Animations on page 5-145 The Number of Frames and the Time Range on page 5-146 What Can Be Animated? on page 5-149 Advanced Animations: The Synchronization Model on page 5-151 Frame by Frame Animations on page 5-154 Examples on page 5-161
5-139
Note Whenever a graphical primitive receives a surplus range specification by an equation such as a = amin..amax, the parameter a is interpreted as an animation parameter assuming values from amin to amax. Thus, it is very easy indeed to create animated objects: Just pass a surplus range equation a = amin..amax to the generating call of the primitive. All other entries and attributes of the primitive that are symbolic expressions of the animation parameter will be animated. In the following call, both the function expression as well as the x range of the function graph depend on the animation parameter. Also, the ranges defining the width and the height of the rectangle as well as the end point of the line depend on it: plot( plot::Function2d(a*sin(x), x = 0..a*PI, a = 0.5..1), plot::Rectangle(0..a*PI, 0..a, a = 0.5..1, LineColor = RGB::Black), plot::Line2d([0, 0], [PI*a, a], a = 0.5 ..1, LineColor = RGB::Black) )
5-140
Animations
Additional range specifications may enter via the graphical attributes. Here is an animated arc whose radius and angle range depend on the animation parameter: plot(plot::Arc2d(1 + a, [0, 0], AngleRange = 0..a*PI, a = 0..1)):
5-141
Here, the attribute AngleRange is identified by its attribute name and thus not assumed to be the specification of an animation parameter with animation range. Note Do make sure that attributes are specified by their correct names. If an incorrect attribute name is used, it may be mistaken for an animation parameter! In the following examples, we wish to define a static semicircle, using plot::Arc2d with AngleRange = 0..PI. However, AngleRange is spelled incorrectly. A plot is created. It is an animated full circle with the animation parameter AngelRange! plot(plot::Arc2d(1, [0, 0], AngelRange = 0..PI)):
5-142
Animations
The animation parameter may be any symbolic parameter (identifier or indexed identifier) that is different from the symbols used for the mandatory range specifications (such as the names of the independent variables in function graphs). The parameter must also be different from any of the protected names of the plot attributes. Note Animations are created object by object. The names of the animation parameters in different objects need not coincide. In the following example, different names a, b are used for the animation parameters of the two functions: plot(plot::Function2d(4*a*x, x = 0..1, a = 0..1), plot::Function2d(b*x^2, x = 0..1, b = 1..4)):
5-143
An animation parameter is a global symbolic name. It can be used as a global variable in procedures defining the graphical object. The following example features the 3D graph of a bivariate function that is defined by a procedure using the globally defined animation parameter. Further, a fill color functionmycolor is defined that changes the color in the course of the animation. It could use the animation parameter as a global parameter, just as the function f does. Alternatively, the animation parameter may be declared as an additional input parameter. Refer to the help page of FillColorFunction to find out, how many input parameters the fill color function expects and which of the input parameters is fed with the animation parameter. One finds that for plot::Function3d, the fill color function is called with the coordinates x, y, z of the points on the graph. The next input parameter (the 4th argument of mycolor) is the animation parameter: f := (x, y) -> 4 - (x - a)^2 - (y - a)^2: mycolor := proc(x, y, z, a) local t; begin t := sqrt((x - a)^2 + (y - a)^2): if t < 0.1 then
5-144
Animations
return(RGB::Red) elif t < 0.4 then return(RGB::Orange) elif t < 0.7 then return(RGB::Green) else return(RGB::Blue) end_if; end: plot(plot::Function3d(f, x = -1..1, y = -1..1, a = -1..1, FillColorFunction = mycolor)):
Play Animations
When an animated plot is created in a MuPAD notebook, the first frame of the animation appears as a static picture below the input region. To start the animation, double click on the plot. An icon for starting the animation will appear (make sure the item Animation Bar of the View menu is enabled):
5-145
One can also use the slider to animate the picture by hand. Alternatively, the Animation menu provides an item for starting the animation.
5-146
Animations
. Increasing the number of frames does not mean that the animation runs longer; the renderer does not work with a fixed number of frames per second but processes all frames within a fixed time interval. In the background, there is a real time clock used to synchronize the animation of different animated objects. An animation has a time range measured by this clock. The time range is set by the attributes TimeBegin = t0, TimeEnd = t1 or, equivalently, TimeRange = t0..t1, where t0, t1 are real numerical values representing physical times in seconds. These attribute can be set in the generating call of the animated primitives, or at some higher node of the graphical tree. In the latter case, these attributes are inherited by all primitives that exist below the node. The absolute value of t0 is irrelevant if all animated objects share the same time range. Only the time difference t1 - t0 matters. It is (an approximation of) the physical time in seconds that the animation will last. Note The parameter range amin..amax in the specification of the animation parameter a = amin..amax together with Frames = n defines an equidistant time mesh in the time interval set by TimeBegin = t0 and TimeEnd = t1. The frame with a = amin is visible at the time t0, the frame with a = amax is visible at the time t1.
Note With the default TimeBegin = 0, the value of the attribute TimeEnd gives the physical time of the animation in seconds. The default value is TimeEnd = 10, i.e., an animation using the default values will last about 10 seconds. The number of frames set by Frames = n does not influence the time interval, but changes the number of frames displayed in this time interval. Here is a simple example: plot(plot::Point2d([a, sin(a)], a = 0..2*PI,
5-147
The point will be animated for about 5 physical seconds in which it moves along one period of the sine graph. Each frame is displayed for about 0.05 seconds. After increasing the number of frames by a factor of 2, each frame is displayed for about 0.025 seconds, making the animation somewhat smoother: plot(plot::Point2d([a, sin(a)], a = 0..2*PI, Frames = 200, TimeRange = 0..5)):
5-148
Animations
Note that the human eye cannot distinguish between different frames if they change with a rate of more than 25 frames per second. Thus, the number of frames n set for the animation should satisfy . Hence, with the default time range TimeBegin = t0 = 0, TimeEnd = t1 = 10 (seconds), it does not make sense to specify Frames = n with n > 250. If a higher frame number is required to obtain a sufficient resolution of the animated object, one should increase the time for the animation by a sufficiently high value of TimeEnd.
5-149
Which attributes can be animated? The answer is: Almost any attribute can be animated! Instead of listing the attributes that allow animation, it is much easier to characterize the attributes that cannot be animated: None of the canvas attributes can be animated. This includes layout parameters such as the physical size of the picture. See the help page of plot::Canvas for a complete list of all canvas attributes. None of the attributes of 2D scenes and 3D scenes can be animated. This includes layout parameters, background color and style, camera positioning in 3D etc. See the help pages of plot::Scene2d and plot::Scene3d for a complete list of all scene attributes. Note that there are camera objects of type plot::Camera that can be placed in a 3D scene. These camera objects can be animated and allow to realize a flight through a 3D scene. See section Cameras in 3D for details. None of the attributes of 2D coordinate systems and 3D coordinate systems can be animated. This includes viewing boxes, axes, axes ticks, and grid lines (rulings) in the background. See the help pages of plot::CoordinateSystem2d and plot::CoordinateSystem3d for a complete list of all attributes for coordinate systems. Although the ViewingBox attribute of a coordinate system cannot be animated, the user can still achieve animated visibility effects in 3D by clipping box objects of type plot::ClippingBox. None of the attributes that are declared as Attribute Type: inherited on their help page can be animated. This includes size specifications such as PointSize, LineWidth etc. RGB and RGBa values cannot be animated. However, it is possible to animate the coloring of lines and surfaces via user defined procedures. See the help pages LineColorFunction and FillColorFunction for details. The texts of annotations such as Footer, Header, Title, legend entries, etc. cannot be animated. The position of titles, however, can be animated. There are special text objects plot::Text2d and plot::Text3d that allow to animate the text as well as their position. Fonts cannot be animated.
5-150
Animations
Attributes such as DiscontinuitySearch = TRUE or FillPattern = Solid that can assume only finitely many values from a fixed discrete set cannot be animated. Nearly all attributes not falling into one of these categories can be animated. You will find detailed information on this issue on the corresponding help pages of primitives and attributes.
These values only need to be modified if a shorter or longer real time period for the animation is desired, or if the animation contains several animated objects, where some of the animated objects are to remain static while others change. Here is an example for the second situation. The plot consists of 3 jumping points. For the first 5 seconds, the left point jumps up and down, while the other points remain at their initial position. Then, all points stay static for 1 second. After a total of 6 seconds, the middle point starts its animation by jumping up and down, while the left point remains static in its final position and the right points stays static in its initial position. After 9 seconds, the right point begins to move as well. The overall time span for the animation is the hull of the time ranges of all animated objects, i.e., 15 seconds in this example: p1 := plot::Point2d(-1, sin(a), a = 0..PI, Color = RGB::Red,
5-151
PointSize = 5*unit::mm, TimeBegin = 0, TimeEnd = 5): p2 := plot::Point2d(0, sin(a), a = 0..PI, Color = RGB::Green, PointSize = 5*unit::mm, TimeBegin = 6, TimeEnd = 12): p3 := plot::Point2d(1, sin(a), a = 0..PI, Color = RGB::Blue, PointSize = 5*unit::mm, TimeBegin = 9, TimeEnd = 15): plot(p1, p2, p3, PointSize = 3.0*unit::mm, YAxisVisible = FALSE):
Here, all points use the default settings VisibleBeforeBegin = TRUE and VisibleAfterEnd = TRUE which make them visible as static objects outside the time range of their animation. We set VisibleAfterEnd = FALSE for the middle point, so that it disappears after the end of its animation. With VisibleBeforeBegin = FALSE, the right point is not visible until its animation starts: p2::VisibleAfterEnd := FALSE: p3::VisibleBeforeBegin := FALSE:
5-152
Animations
We summarize the synchronization model of animations: Note The total real time span of an animated plot is the physical real time given by the minimum of the TimeBegin values of all animated objects in the plot to the maximum of the TimeEnd values of all the animated objects. When a plot containing animated objects is created, the real time clock is set to the minimum of the TimeBegin values of all animated objects in the plot. The real time clock is started when pushing the play button for animations in the graphical user interface. Before the real time reaches the TimeBegin value t0 of an animated object, this object is static in the state corresponding to the begin of its animation. Depending on the attribute VisibleBeforeBegin, it may be visible or invisible before t0.
5-153
During the time from t0 to t1, the object changes from its original to its final state. After the real time reaches the TimeEnd value t1, the object stays static in the state corresponding to the end of its animation. Depending on the value of the attribute VisibleAfterEnd, it may stay visible or become invisible after t1. The animation of the entire plot ends with the physical time given by the maximum of the TimeEnd values of all animated objects in the plot.
Note With VisibleBefore = t1, an object is visible from the start of the animation until time t1. Then it will disappear and remain invisible for the rest of the animation. These attributes should not be combined to define a visibility range from t0 to t1. Use the attribute VisibleFromTo instead: Note With VisibleFromTo = t0..t1, an object is invisible from the start of the animation until time t0. Then it will appear and remain visible until time t1, when it will disappear and remain invisible for the rest of the animation. We continue the example of the previous section in which we defined the following animated points:
5-154
Animations
p1 := plot::Point2d(-1, sin(a), a = 0..PI, Color = RGB::Red, PointSize = 5*unit::mm, TimeBegin = 0, TimeEnd = 5): p2 := plot::Point2d(0, sin(a), a = 0..PI, Color = RGB::Green, PointSize = 5*unit::mm, TimeBegin = 6, TimeEnd = 12): p3 := plot::Point2d(1, sin(a), a = 0..PI, Color = RGB::Blue, PointSize = 5*unit::mm, TimeBegin = 9, TimeEnd = 15): p2::VisibleAfterEnd := FALSE: p3::VisibleBeforeBegin := FALSE: We add a further point p4 that is not animated. We make it invisible at the start of the animation via the attribute VisibleFromTo. It is made visible after 7 seconds to disappear again after 13 seconds: p4 := plot::Point2d(0.5, 0.5, Color = RGB::Black, PointSize = 5*unit::mm, VisibleFromTo = 7..13): The start of the animation is determined by p1 which bears the attribute TimeBegin = 0, the end of the animation is determined by p3 which has set TimeEnd = 15: plot(p1, p2, p3, p4, PointSize = 3.0*unit::mm, YAxisVisible = FALSE):
5-155
Although a typical MuPAD animation is generated object by object, each animated object taking care of its own animation, we can also use the attributes VisibleAfter, VisibleBefore, VisibleFromTo to build up an animation frame by frame: Note Frame by frame animations: Choose a collection of (typically static) graphical primitives that are to be visible in the i-th frame of the animation. Set VisibleFromTo = t[i]..t[i+1] for these primitives, where t[i]..t[i+1] is the real time life span of the i-th frame (in seconds). Finally, plot all frames in a single plot command. Here is an example. We let two points wander along the graphs of the sine and the cosine function, respectively. Each frame is to consist of a picture of two points. We use plot::Group2d to define the frame; the group forwards the attribute VisibleFromTo to all its elements: for i from 0 to 101 do t[i] := i/10;
5-156
Animations
end_for: for i from 0 to 100 do x := i/100*PI; myframe[i] := plot::Group2d( plot::Point2d([x, sin(x)], Color = RGB::Red), plot::Point2d([x, cos(x)], Color = RGB::Blue), VisibleFromTo = t[i]..t[i + 1]); end_for: plot(myframe[i] $ i = 0..100, PointSize = 5.0*unit::mm):
This frame by frame animation certainly needs a little bit more coding effort than the equivalent objectwise animation, where each of the points is animated: delete i: plot(plot::Point2d([i/100*PI, sin(i/100*PI)], i = 0..100, Color = RGB::Red), plot::Point2d([i/100*PI, cos(i/100*PI)], i = 0..100, Color = RGB::Blue), Frames = 101, TimeRange = 0..10,
5-157
PointSize = 5.0*unit::mm):
There is, however, a special kind of plot where frame by frame animations are very useful. Note that in the present version of the graphics, new plot objects cannot be added to a scene that is already rendered. With the special visibility animations for static objects, however, one can easily simulate a plot that gradually builds up: Fill the frames of the animation with static objects that are visible for a limited time only. The visibility can be chosen very flexibly by the user. For example, the static objects can be made visible only for one frame (VisibleFromTo) so that the objects seem to move. In the following example, we use VisibleAfter to fill up the plot gradually. We demonstrate the caustics generated by sunlight in a tea cup. The rim of the cup, regarded as a mirror, is given by the function , x [- 1, 1] (a semicircle). Sun rays parallel to the y-axis are reflected by the rim. After reflection at the point (x, f(x)) of the rim, a ray heads into the direction if x is positive. It heads into the direction
5-158
Animations
if x is negative. Sweeping through the mirror from left to right, the incoming rays as well as the reflected rays are visualized as lines. In the animation, they become visible after the time 5x, where x is the coordinate of the rim point at which the ray is reflected: f := x -> -sqrt(1 - x^2): plot(// The static rim: plot::Function2d(f(x), x = -1..1, Color = RGB::Black), // The incoming rays: plot::Line2d([x, 2], [x, f(x)], VisibleAfter = 5*x ) $ x in [-1 + i/20 $ i = 1..39], // The reflected rays leaving to the right: plot::Line2d([x, f(x)], [1, f(x) + (1-x)*(f'(x) - 1/f'(x))/2], Color = RGB::Orange, VisibleAfter = 5*x ) $ x in [-1 + i/20 $ i = 1..19], // The reflected rays leaving to the left: plot::Line2d([x, f(x)], [-1, f(x) - (x+1)*(f'(x) - 1/f'(x))/2], Color = RGB::Orange, VisibleAfter = 5*x ) $ x in [-1 + i/20 $ i = 21..39], ViewingBox = [-1..1, -1..1]):
5-159
Compare the spherical mirror with a parabolic mirror that has a true focal point: f := x -> -1 + x^2: plot(// The static rim: plot::Function2d(f(x), x = -1..1, Color = RGB::Black), // The incoming rays: plot::Line2d([x, 2], [x, f(x)], VisibleAfter = 5*x ) $ x in [-1 + i/20 $ i = 1..39], // The reflected rays leaving to the right: plot::Line2d([x, f(x)], [1, f(x) + (1-x)*(f'(x) - 1/f'(x))/2], Color = RGB::Orange, VisibleAfter = 5*x ) $ x in [-1 + i/20 $ i = 1..19], // The reflected rays leaving to the left: plot::Line2d([x, f(x)], [-1, f(x) - (x+1)*(f'(x) - 1/f'(x))/2], Color = RGB::Orange, VisibleAfter = 5*x ) $ x in [-1 + i/20 $ i = 21..39], ViewingBox = [-1..1, -1..1]):
5-160
Animations
Examples
Example 1
We build a 2D animation that displays a function f(x) together with the . The area between the graph of f and the x-axis is integral displayed as an animated hatch object. The current value of F(x) is displayed by an animated text: DIGITS := 2: // the function: f := x -> cos(x^2): // the anti-derivative: F := x -> numeric::int(f(y), y = 0..x): // the graph of f(x): g := plot::Function2d(f(x), x = 0..6, Color = RGB::Blue): // the graph of F(x): G := plot::Function2d(F(x), x = 0..6, Color = RGB::Black): // a point moving along the graph of F(x):
5-161
p := plot::Point2d([a, F(a)], a = 0..6, Color = RGB::Black): // hatched region between the origin and the moving point p: h := plot::Hatch(g, 0, 0 ..a, a = 0..6, Color = RGB::Red): // the right border line of the hatched region: l := plot::Line2d([a, 0], [a, f(a)], a = 0..6, Color = RGB::Red): // a dashed vertical line from f to F: L1 := plot::Line2d([a, f(a)], [a, F(a)], a = 0..6, Color = RGB::Black, LineStyle = Dashed): // a dashed horizontal line from the y axis to F: L2 := plot::Line2d([-0.1, F(a)], [a, F(a)], a = 0..6, Color = RGB::Black, LineStyle = Dashed): // the current value of F at the moving point p: t := plot::Text2d(a -> F(a), [-0.2, F(a)], a = 0..6, HorizontalAlignment = Right): plot(g, G, p, h, l, L1, L2, t, YTicksNumber = None, YTicksAt = [-1, 1]): delete DIGITS:
5-162
Animations
Example 2
We build two 3D animations. The first starts with a rectangular strip that is deformed to an annulus in the x, y plane: c := a -> 1/2 *(1 - 1/sin(PI/2*a)): mycolor := (u, v, x, y, z) -> [(u - 0.8)/0.4, 0, (1.2 - u)/0.4]: rectangle2annulus := plot::Surface( [c(a) + (u - c(a))*cos(PI*v), (u - c(a))*sin(PI*v), 0], u = 0.8..1.2, v = -a..a, a = 1/10^10..1, FillColorFunction = mycolor, Mesh = [3, 40], Frames = 40): plot(rectangle2annulus, Axes = None, CameraDirection = [-11, -3, 3]):
The second animation twists the annulus to become a Moebius strip: annulus2moebius := plot::Surface( [((u - 1)*cos(a*v*PI/2) + 1)*cos(PI*v), ((u - 1)*cos(a*v*PI/2) + 1)*sin(PI*v), (u - 1)*sin(a*v*PI/2)], u = 0.8..1.2, v = -1..1, a = 0..1,
5-163
FillColorFunction = mycolor, Mesh = [3, 40], Frames = 20): plot(annulus2moebius, Axes = None, CameraDirection = [-11, -3, 3]):
Note that the final frame of the first animation coincides with the first frame of the second animation. To join the two separate animations, we can set appropriate visibility ranges and plot them together. After 5 seconds, the first animation object vanishes and the second takes over: rectangle2annulus::VisibleFromTo := 0..5: annulus2moebius::VisibleFromTo := 5..7: plot(rectangle2annulus, annulus2moebius, Axes = None, CameraDirection = [-11, -3, 3]):
5-164
Animations
Example 3
In this example, we consider the planar celestial 3 body problem. We solve the system of differential equations
5-165
, which is nothing but the equations of motions for two planets with masses m1, m2 at positions (x1, y1), (x2, y2) revolving in the x, y plane around a sun of mass ms positioned at (xs, ys). We specify the mass ratios: The first planet is a giant with a mass m1 that is 4% of the suns mass. The second planet is much smaller: ms := 1: m1 := 0.04: m2 := 0.0001: As we will see, the motion of the giant is nearly undisturbed by the small planet. The small one, however, is heavily disturbed by the giant and, finally, kicked out of the system after a near collision. We solve the ODEs via the MuPAD numerical ODE solve numeric::odesolve2 that provides a solution vector . The initial conditions are chosen such that the total momentum vanishes, i.e., the total center of mass stays put (at the origin): Y := numeric::odesolve2(numeric::ode2vectorfield( {xs''(t) = -m1*(xs(t)-x1(t))/sqrt((xs(t)-x1(t))^2 + (ys(t)-y1(t))^2)^3 -m2*(xs(t)-x2(t))/sqrt((xs(t)-x2(t))^2 + (ys(t)-y2(t))^2)^3, ys''(t) =
5-166
Animations
-m1*(ys(t)-y1(t))/sqrt((xs(t)-x1(t))^2 + (ys(t)-y1(t))^2)^3 -m2*(ys(t)-y2(t))/sqrt((xs(t)-x2(t))^2 + (ys(t)-y2(t))^2)^3, x1''(t) = -ms*(x1(t)-xs(t))/sqrt((x1(t)-xs(t))^2 + (y1(t)-ys(t))^2)^3 -m2*(x1(t)-x2(t))/sqrt((x1(t)-x2(t))^2 + (y1(t)-y2(t))^2)^3, y1''(t) = -ms*(y1(t)-ys(t))/sqrt((x1(t)-xs(t))^2 + (y1(t)-ys(t))^2)^3 -m2*(y1(t)-y2(t))/sqrt((x1(t)-x2(t))^2 + (y1(t)-y2(t))^2)^3, x2''(t) = -ms*(x2(t)-xs(t))/sqrt((x2(t)-xs(t))^2 + (y2(t)-ys(t))^2)^3 -m1*(x2(t)-x1(t))/sqrt((x2(t)-x1(t))^2 + (y2(t)-y1(t))^2)^3, y2''(t) = -ms*(y2(t)-ys(t))/sqrt((x2(t)-xs(t))^2 + (y2(t)-ys(t))^2)^3 -m1*(y2(t)-y1(t))/sqrt((x2(t)-x1(t))^2 + (y2(t)-y1(t))^2)^3, xs(0) = -m1 , x1(0) = ms, x2(0) = 0, ys(0) = 0.7*m2, y1(0) = 0, y2(0) = -0.7*ms, xs'(0) = -1.01*m2, x1'(0) = 0, x2'(0) = 1.01*ms, ys'(0) = -0.9*m1, y1'(0) = 0.9*ms, y2'(0) = 0}, [xs(t), xs'(t), ys(t), ys'(t), x1(t), x1'(t), y1(t), y1'(t), x2(t), x2'(t), y2(t), y2'(t)] )): The positions [xs(t), ys(t)] = [Y(t)[1], Y(t)[3]], [x1(t), y1(t)] = [Y(t)[5], Y(t)[7]], [x2(t), y2(t)] = [Y(t)[9], Y(t)[11]] are computed on an equidistant time mesh with dt = 0.05. The animation is built up frame by frame by defining static points with suitable values of VisibleFromTo and static line segments with suitable values of VisibleAfter. Setting VisibleFromTo = t..t + 0.99*dt, each solution point is visible only for a short time (the factor 0.99 makes sure that not two points can be visible simultaneously on each orbit). The orbits of the points are realized as line segments from the positions at time t - dt to the positions at time t. The line segments become visible at time t and stay visible for the rest of the animation (VisibleAfter = t), thus leaving a trail of the moving points. We obtain the following graphical solution (the computation takes about two minutes on a 1 GHz computer): dt := 0.05: imax := 516: plot(// The sun:
5-167
plot::Point2d(Y(t)[1], Y(t)[3], Color = RGB::Orange, VisibleFromTo = t..t + 0.99*dt, PointSize = 4*unit::mm ) $ t in [i*dt $ i = 0..imax], // The giant planet: plot::Point2d(Y(t)[5], Y(t)[7], Color = RGB::Red, VisibleFromTo = t..t + 0.99*dt, PointSize = 3*unit::mm ) $ t in [i*dt $ i = 0..imax], // The orbit of the giant planet: plot::Line2d([Y(t - dt)[5], Y(t - dt)[7]], [Y(t)[5], Y(t)[7]], Color = RGB::Red, VisibleAfter = t ) $ t in [i*dt $ i = 1..imax], // The small planet: plot::Point2d(Y(t)[9], Y(t)[11], Color = RGB::Blue, VisibleFromTo = t..t + 0.99*dt, PointSize = 2*unit::mm ) $ t in [i*dt $ i = 0..imax], // The orbit of the small planet: plot::Line2d([Y(t - dt)[9], Y(t - dt)[11]], [Y(t)[9], Y(t)[11]], Color = RGB::Blue, VisibleAfter = t ) $ t in [i*dt $ i = 1..imax] ):
5-168
Animations
5-169
Groups of Primitives
An arbitrary number of graphical primitives in 2D or 3D can be collected in groups of type plot::Group2d or plot::Group3d, respectively. This is useful for inheriting attribute values to all elements in a group. In the following example, we visualize random generators with different distributions by using them to position random points: r1 := stats::normalRandom(0, 1): group1 := plot::Group2d(plot::Point2d(r1(), r1()) $ i = 1..200): r2 := stats::uniformRandom(-3, 3): group2 := plot::Group2d(plot::Point2d(r2(), r2()) $ i = 1..500): plot(group1, group2, Axes = Frame):
We cannot distinguish between the two kinds of points. Due to the grouping, it is very easy to change their color and size by setting the appropriate attributes in the groups. Now, the two kinds of points can be distinguished easily: group1::PointColor := RGB::Red:
5-170
Groups of Primitives
group1::PointSize := 1.5*unit::mm: group2::PointColor := RGB::Blue: group2::PointSize := 1.3*unit::mm: plot(group1, group2, Axes = Frame):
5-171
Transformations
Affine linear transformations with a vector b and a matrix A can be applied to graphical objects via transformation objects. There are special transformations such as translations, scaling, and rotations as well as general affine linear transformations: plot::Translate2d([b1, b2], Primitive1, Primitive2, ...) applies the translation by the vector b = [b1, b2] to all points of 2D primitives. plot::Translate3d([b1, b2, b3], Primitive1, ...) applies the translation by the vector b = [b1, b2, b3] to all points of 3D primitives. plot::Reflect2d([x1, y1], [x2, y2], Primitive1, ...) reflects all 2D primitives about the line through the points [x1, y1] and [x2, y2]. plot::Reflect3d([x, y, z], [nx, ny, nz], Primitive1, ...) reflects all 3D primitives about the plane through the point [x, y, z] with the normal [nx, ny, nz]. plot::Rotate2d(angle, [c1, c2], Primitive1, ...) rotates all points of 2D primitives counter clockwise by the given angle about the pivot point [c1, c2]. plot::Rotate3d(angle, [c1, c2, c3], [d1, d2, d3], Primitive1, ...) rotates all points of 3D primitives by the given angle around the rotation axis specified by the pivot point [c1, c2, c3] and the direction [d1, d2, d3]. plot::Scale2d([s1, s2], Primitive1, ...) applies the diagonal scaling matrix diag(s1, s2) to all points of 2D primitives. plot::Scale3d([s1, s2, s3], Primitive1, ...) applies the diagonal scaling matrix diag(s1, s2, s3) to all points of 3D primitives. plot::Transform2d([b1, b2], A, Primitive1, ...) applies the general affine linear transformation with a 22 matrix A and a vector b = [b1, b2] to all points of 2D primitives.
5-172
Transformations
plot::Transform3d([b1, b2, b3], A, Primitive1, ...) applies the general affine linear transformation with a 33 matrix A and a vector b = [b1, b2, b3] to all points of 3D primitives. The ellipses plot::Ellipse2d provided by the plot library have axes parallel to the coordinate axes. We use a rotation to create an ellipse with a different orientation: center := [1, 2]: ellipse := plot::Ellipse2d(2, 1, center): plot(plot::Rotate2d(PI/4, center, ellipse))
Transform objects can be animated. We build a group consisting of the ellipse and its symmetry axes. An animated rotation is applied to the group: g := plot::Group2d( ellipse, plot::Line2d(center, [center[1] + 2, center[2]]), plot::Line2d(center, [center[1] - 2, center[2]]), plot::Line2d(center, [center[1], center[2] + 1]),
5-173
Objects inside an animated transformation can be animated, too. The animations run independently and may be synchronized via suitable values of the TimeRange as described in section Advanced Animations: The Synchronization Model on page 5-151. We generate a sphere s of radius r with center c = (cx, cy, cz). We wish to visualize the tangent plane at various points of the surface. We start with the tangent plane of the north pole and rotate it around the y axes (i.e., along the line with zero longitude) by the polar angle for the first 3 seconds. Then it is rotated around the z-axis (i.e., along the line with constant latitude) by the azimuth angle . We end up with the tangent plane at the point x = cx + cos()sin(), y = cy + sin()sin(), z = cz + cos(). The two rotations are realized as a nested animation: By specifying disjoint time ranges, the second rotation (around the z-axis) starts when the first rotation (around the y-axis) is finished:
5-174
Transformations
r := 1: // the radius of the sphere R := 1.01: // increase the radius a little bit c := [0, 0, 0]: // the center of the sphere thet := PI/3: // spherical coordinates of phi := PI/4: // the final point p // the final point: p := plot::Point3d(c[1] + R*cos(phi)*sin(thet), c[2] + R*sin(phi)*sin(thet), c[3] + R*cos(thet), PointSize = 2*unit::mm, Color = RGB::Black): // the sphere: s := plot::Sphere(r, c, Color = RGB::Green): // the meridian at thet = 0 c1 := plot::Curve3d([c[1] + R*sin(t), c[2], c[3] + R*cos(t)], t = 0..thet, Color = RGB::Black): // the meridian at thet = 0 c2 := plot::Curve3d([c[1] + R*cos(t)*sin(thet), c[2] + R*sin(t)*sin(thet), c[3] + R*cos(thet)], t = 0..phi, Color = RGB::Black): // form a group consisting of the tangent plane and its normal: g := plot::Group3d( plot::Surface([c[1] + u, c[2] + v, c[3] + R], u = -1..1, v = -1..1, Mesh = [2, 2], Color = RGB::Red.[0.3]), plot::Arrow3d([c[1], c[2], c[3] + R], [c[1], c[2], c[3] + R + 0.7]) ): // rotate the group for 3 seconds along the meridian: g := plot::Rotate3d(a, c, [0, 1, 0], a = 0..thet, g, TimeRange = 0..3): // rotate the group for further 3 seconds along the azimuth: g := plot::Rotate3d(a, c, [0, 0, 1], a = 0..phi, g, TimeRange = 3..6): plot(s, g, c1, c2, p, CameraDirection = [2, 3, 4]):
5-175
5-176
Legends
Legends
The annotations of a MuPAD plot may include a legend. A legend is a small table that relates the color of an object with some text explaining the object: f := 3*x*sin(2*x): g := 4*x^2*cos(x): h := sin(4*x)/x: plotfunc2d(f, g, h, x = 0..PI/2):
By default, legends are provided only by plotfunc2d and plotfunc3d. These routines define the legend texts as the expressions with which the functions are passed to plotfunc2d or plotfunc3d, respectively. A corresponding plot command using primitives of the plot library does not generate the legend automatically: plot(plot::Function2d(f, x = 0..PI/2, Color = RGB::Red), plot::Function2d(g, x = 0..PI/2, Color = RGB::Green), plot::Function2d(h, x = 0..PI/2, Color = RGB::Blue)):
5-177
However, legends can be requested explicitly: plot(plot::Function2d(f, x = Legend plot::Function2d(g, x = Legend plot::Function2d(h, x = Legend ): 0..PI/2, Color = "Function 1: 0..PI/2, Color = "Function 2: 0..PI/2, Color = "Function 3: = RGB::Red, ".expr2text(f)), = RGB::Green, ".expr2text(g)), = RGB::Blue, ".expr2text(h))
5-178
Legends
Each graphical primitive accepts the attribute Legend. Passing this attribute to an object triggers several actions: The object attribute LegendText is set to the given string. The object attribute LegendEntry is set to TRUE. A hint is sent to the scene containing the object advising it to use the scene attribute LegendVisible = TRUE. The attributes LegendText and LegendEntry are visible in the object inspector of the interactive viewer (see section Viewer, Browser, and Inspector: Interactive Manipulation) and can be manipulated interactively for each single primitive after selection in the object browser. The attribute LegendVisible is associated with the scene object accessible via the object browser. At most 20 entries can be displayed in a legend. If more entries are specified in a plot command, the surplus entries are ignored. Further, the legend may not cover more than 50% of the height of the drawing area of a scene. Only
5-179
those legend entries fitting into this space are displayed; remaining entries are ignored. If the attribute LegendText = TRUE is set for a primitive, its legend entry is determined as follows: If the attribute LegendText is specified, its value is used for the legend text. If no LegendText is specified, but the Name attribute is set, the name is used for the legend text. If no Name attribute is specified either, the type of the object such as Function2d, Curve2d etc. is used for the legend text. Here are all attributes relevant for legends: attribute name
Legend
default
browser entry
and
LegendVisible to TRUE. LegendEntry TRUE, FALSE
TRUE for
primitive
LegendText
string
Scene2d/3d
5-180
Legends
(Continued) attribute name possible values/example meaning horizontal alignment font for the legend text browser entry
Scene2d/3d
default
Center
sans-serif 8
Scene2d/3d
5-181
Fonts
The plot attributes allow to specify the fonts AxesTitleFont, FooterFont, HeaderFont, LegendFont, TextFont, TicksLabelFont, and TitleFont. Each such font is specified by a MuPAD list of the following form: [<family>, <size>, <Bold>, <Italic>, <color>, <alignment>]. The parameters are:
family
the font family name: a string. The available font families depend on the fonts that are installed on your machine. For example, typical font families available on Microsoft Windows systems are "Times New Roman" (of type serif), "Arial" (of type sans-serif), or "Courier New" (of type monospace). To find out which fonts are available on your machine, open the menu Format, submenu Font in your MuPAD notebook. The first column in the font dialog provides the names of the font families that you may specify. You may also specify one the three generic family names "serif", "sans-serif", or "monospace", and the system will automatically choose one of the available font families of the specified type for you. the size of the font in integral points: a positive integer. if specified, the font is bold if specified, the font is italic. an RGB color value: a list of 3 numerical values between 0 and 1 text alignment in case of new-lines: one of the flags Left, Center, or Right.
size Bold
Italic color
alignment
In the following example, we specify the font for the canvas header: plot(plot::Function2d(sin(x), x = 0..2*PI), Header = "The sine function", HeaderFont = ["monospace", 14, Bold]):
5-182
Fonts
All font parameters are optional; some default values are chosen for entries that are not specified. For example, if you do not care about the footer font family for your plot, but you insist on a specific font size, you may specify an 18 pt font as follows: plot(plot::Function2d(sin(x), x = 0..2*PI), Footer = "The sine function", FooterFont = [18]):
5-183
5-184
Colors
Colors
In this section... RGB Colors on page 5-185 HSV Colors on page 5-189 The most prominent plot attribute, available for all primitives, is Color. The MuPAD plot library knows 3 different types of colors: The attribute PointColor refers to the color of points in 2D and 3D (of type plot::Point2d and plot::Point3d, respectively). The attribute LineColor refers to the color of line objects in 2D and 3D. This includes the color of function graphs in 2D, curves in 2D and in 3D, polygon lines in 2D and in 3D, etc. Also 3D objects such as function graphs in 3D, parametrized surfaces etc. react to the attribute LineColor; it defines the color of the coordinate mesh lines that are displayed on the surface. The attribute FillColor refers to the color of closed and filled polygons in 2D and 3D as well as hatched regions in 2D. Further, it sets the surface color of function graphs in 3D, parametrized surfaces etc. This includes spheres, cones etc. The primitives also accept the attribute Color as a shortcut for any one of these colors. Depending on the primitive, either PointColor, LineColor, or FillColor is set with the Color attribute.
RGB Colors
MuPAD uses the RGB color model, i.e., colors are specified by lists [r, g, b] of red, green, and blue values between 0 and 1. Black and white correspond to[0, 0, 0] and [1, 1, 1], respectively. The library RGB contains numerous color names with corresponding RGB values: RGB::Black, RGB::White, RGB::Red, RGB::SkyBlue
5-185
You may list all color names available in the RGB library via info(RGB). Alternatively, there is the command RGB::ColorNames() returning a complete list of names, optionally filtered. For example, let us list all the colors whose names contain Red: RGB::ColorNames(Red)
After loading the color library via use(RGB), you can use the color names in the short form Black, White, IndianRed etc. In MuPAD, the color of all graphic elements can either be specified by RGB or RGBa values.
5-186
Colors
RGBa color values consist of lists [r, g, b, a] containing a fourth entry: the opacity value a between 0 and 1. For a = 0, a surface patch painted with this RGBa color is fully transparent (i.e., invisible). For a = 1, the surface patch is opaque, i.e., it hides plot objects that are behind it. For 0 < a < 1, the surface patch is semitransparent, i.e., plot objects behind it shine through. RGBa color values can be constructed easily via the RGB library. One only has to append a fourth entry to the [r, g, b] lists provided by the color names. The easiest way to do this is to append the list [a] to the RGB list via the concatenation operator .. We create a semitransparent grey: RGB::Grey.[0.5]
The following command plots a highly transparent red box, containing a somewhat less transparent green box with an opaque blue box inside: plot( plot::Box(-3..3, -3..3, -3..3, plot::Box(-2..2, -2..2, -2..2, plot::Box(-1..1, -1..1, -1..1, LinesVisible = TRUE, LineColor Scaling = Constrained ):
5-187
In the following example, we plot points randomly distributed with random colors and random translucencies: plot(plot::PointList2d([[frandom() $ i = 1..2, [frandom() $ i = 1..4]] $ i = 1..300], PointSize=4), Axes=None, Scaling=Constrained)
5-188
Colors
HSV Colors
Apart from the RGB model, there are various other popular color formats used in computer graphics. One is the HSV model (Hue, Saturation, Value). The RGB library provides the routines RGB::fromHSV and RGB::toHSV to convert HSV colors to RGB colors and vice versa: hsv := RGB::toHSV(RGB::Orange)
RGB::fromHSV(hsv) = RGB::Orange
With the RGB::fromHSV utility, all colors in a MuPAD plot can be specified easily as HSV colors. For example, the color violet is given by the HSV values [290, 0.4, 0.6], whereas dark green is given by the HSV specification
5-189
opaque dark green plane may be specified as follows: plot(plot::Sphere(1, [0, 0, 0], Color = RGB::fromHSV([290, 0.4, 0.6]).[0.5]), plot::Surface([x, y, 0.5], x = -1..1, y = -1..1, Mesh = [2, 2], Color = RGB::fromHSV([120, 1, 0.4])) ):
5-190
5-191
Alternatively, the extension .xvc may be used to write the xml data without final compression of the file (the resulting text file can be read with any text editor). Files in both formats can be opened by the MuPAD graphics tool VCam to generate the plot encoded by the xml data. If the MuPAD environment variable WRITEPATH does not have a value, the previous call creates the file in the directory where MuPAD is installed. An absolute pathname can be specified to place the file anywhere else: plot(primitives, OutputFile = "C:\\Documents\\mypicture.xvz"): Alternatively, the environment variable WRITEPATH can be set: WRITEPATH := "C:\\Documents": plot(primitives, OutputFile = "mypicture.xvz"): Now, the plot data are stored in the file C:\Documents\mypicture.xvz. If a MuPAD notebook of is saved to a file, its location is available inside the notebook as the environment variable NOTEBOOKPATH. If you wish to save your plot in the same folder as the notebook, you may call plot(primitives, OutputFile = NOTEBOOKPATH."mypicture.xvz"): Apart from saving files as xml data, MuPAD pictures can also be saved in a variety of standard graphical formats such as jpg, eps, svg, bmp etc. In batch mode, the export is triggered by the OutputFile attribute in the same way as for saving in xml format. Just use an appropriate extension of the filename indicating the format. The following commands save the plot in four different files in jpg, eps, svg, and bmp format, respectively: plot(primitives, plot(primitives, plot(primitives, plot(primitives, OutputFile OutputFile OutputFile OutputFile = = = = "mypicture.jpg"): "mypicture.eps"): "mypicture.svg"): "mypicture.bmp"):
On Windows systems, an animated MuPAD plot can be exported to avi format: plot(plot::Function2d(sin(x - a), x = 0..2*PI, a = 0..5) OutputFile = "myanimation.avi"):
5-192
If no file extension is specified by the file name, the default extension .xvc is used, i.e., compressed xml data are written. In addition to OutputFile, there is the attribute OutputOptions to specify parameters for some of the export formats. The admissible value for this attribute is a list of equations
OutputOptions = [<ReduceTo256Colors = b >, <DotsPerInch = n1>, <Quality = n2>, <JPEGMode = n3>, <EPSMode = n4>, <AVIMode = n5>, <WMFMode = n6>, <FramesPerSecond = n7>, <PlotAt = l1>]
n1
Positive integer setting the resolution in dpi (dots per inch). Has an effect for export to raster formats only. The default value depends on the hardware. One of the integers 1, 2, , 100. This integer represents a percentage value determining the quality of the export. Has an effect for jpg, 3D eps, 3D wmf, and avi export only. The default value is 75.
0, 1, or 2. Has an effect for jpg export only. The flag 0 represents the jpg mode Baseline Sequential, 1 represents Progressive, 2 represents Sequential Optimized. The default value is 0. 0 or 1. Has an effect for eps export only. The flag 0 represents the eps mode Painters Algorithm, 1 represents BSP Tree Algorithm. The default value is 0. 0, 1 or 2. Has an effect for avi export only. With 0, the Microsoft Video 1 Codec is used. With 1, the Uncompressed Single Frame Codec is used. With 2, the Radius Cinepak Codec is used. The default value is 0. 0, 1 or 2. Has an effect for wmf export only. With 0, the Painters Algorithm is used. With 1, the BSP Tree Algorithm is used. With 2, a embedded bitmap is created. The default value is 0.
n2
n3
n4
n5
n6
5-193
n7
Positive integer setting the frames per second for the avi to be generated. Has an effect for avi export only. The default value is 15. List of real values between TimeBegin and TimeEnd which determines the times at which pictures should be saved from an animation.
l1
5-194
Import Pictures
Import Pictures
MuPAD does not provide for many tools to import standard graphical vector formats, yet. Presently, the only supported vector type is the stl format, popular in Stereo Lithography, which encodes 3D surfaces. It can be imported via the routine plot::SurfaceSTL. In contrast to graphical vector formats, there are many standard bitmap formats such as bmp, gif, jpg, ppm etc. that can be imported. One can read such a file via import::readbitmap, thus creating a MuPAD array of RGB color values that can be manipulated at will. In particular, it can be fed into the routine plot::Raster which creates an object that can be used in any 2D MuPAD plot. Note, however, that the import of bitmap data consumes a lot of memory, i.e., only reasonably small bitmaps (up to a few hundred pixels in each direction) should be processed. In the following example, we plot the probability density function and the cumulative density function of the standard normal (Gaussian) distribution. Paying tribute to Carl Friedrich Gauss, we wish to display his picture in this plot. Assume that we have his picture as a ppm bitmap file Gauss.ppm. We import the file via import::readbitmap that provides us with the width and height in pixels and the color data: [width, height, gauss] := import::readbitmap("Gauss.ppm"): We have to use Scaling = Constrained to preserve the aspect ratio of the image. Unfortunately, this setting is not appropriate for the function plots. So we use two different scenes that are positioned via Layout = Relative in one canvas (see section Layout of Canvas and Scenes). The first scene plots the two functions using the default setting Scaling = Unconstrained for function plots. With the sizes Width = 1, Height = 1, representing fractions of the canvas size, this scene fills the whole canvas. The second scene is given a width and height of approximately the desired magnitude. It uses Scaling = Constrained to get the aspect ratio right, automatically. With the attributes Bottom and Left, the lower left corner of Gauss image is moved to an appropriate point of the canvas: pdf := stats::normalPDF(0, 1):
5-195
cdf := stats::normalCDF(0, 1): plot(plot::Scene2d(plot::Function2d(pdf(x), x = -4..7), plot::Function2d(cdf(x), x = -4..7), Width = 1, Height = 1), plot::Scene2d(plot::Raster(gauss), Scaling = Constrained, Width = 0.3, Height = 0.6, Bottom = 0.25, Left = 0.6, BorderWidth = 0.5*unit::mm, Footer = "C.F. Gauss", FooterFont = [8]), Layout = Relative ):
5-196
Cameras in 3D
Cameras in 3D
The MuPAD 3D graphics model includes an observer at a specific position, pointing a camera with a lens of a specific opening angle to some specific focal point. The specific parameters position, angle, and focal point determine the picture that the camera will take. When a 3D picture is created in MuPAD, a camera with an appropriate default lens is positioned automatically. Its focal point is chosen as the center of the graphical scene. The interactive viewer allows to rotate the scene which, in fact, is implemented internally as a change of the camera position. Also interactive zooming in and zooming out is realized by moving the camera closer to or farther away from the scene. Apart from interactive camera motions, the perspective of a 3D picture can also be set in the calls generating the plot. One way is to specify the direction from which the camera is pointing towards the scene. This is done via the attribute CameraDirection: plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), CameraDirection = [-25, 20, 30]):
5-197
5-198
Cameras in 3D
In these calls, the position of the camera is not fully specified by CameraDirection. This attribute just requests the camera to be placed at some large distance from the scene along the ray in the direction given by the attribute. The actual distance from the scene is determined automatically to let the graphical scene fill the picture optimally. For a full specification of the perspective, there are camera objects of type plot::Camera that allow to specify the position of the camera, its focal point and the opening angle of its lens: position := [-5, -10, 5]: focalpoint := [0, 0, 0]: angle := PI/12: camera := plot::Camera(position, focalpoint, angle): This camera can be passed like any graphical object to the plot command generating the scene. Once a camera object is specified in a graphical scene, it determines the view. No automatic camera is used: plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1),
5-199
camera):
Camera objects can be animated: camera := plot::Camera([3*cos(a), 3*sin(a), 1 + cos(2*a)], [0, 0, 0], PI/3, a = 0..2*PI, Frames = 100): Inserting the animated camera in a graphical scene, we obtain an animated plot simulating a flight around the scene: plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), camera):
5-200
Cameras in 3D
In fact, several cameras can be installed simultaneously in a scene: camera1 := plot::Camera([3*cos(a), 3*sin(a), 1 + cos(2*a)], [0, 0, 0], PI/3, a = 0..2*PI, Name = "Camera 1"): camera2 := plot::Camera([2*cos(a), 2*sin(a), 2 + cos(2*a)], [0, 0, 0], PI/3, a = 0..2*PI, Name = "Camera 2"): plot(plot::Function3d(sin(x + y^3), x = -1..1, y = -1..1), camera1, camera2):
5-201
Per default, the first camera produces the view rendered. After clicking on another camera in the object browser of the viewer (see section Viewer, Browser, and Inspector: Interactive Manipulation), the selected camera takes over and the new view is shown.
5-202
Cameras in 3D
Next, we have a look at a more appealing example: the so-called Lorenz attractor. The Lorenz ODE is the system
with fixed parameters p, r, b. As a dynamic system for Y = [x, y, z], we have to solve the ODE f := proc(t, Y) with the following vector field:
5-203
local x, y, z; begin [x, y, z] := Y: [p*(y - x), -x*z + r*x - y, x*y - b*z] end_proc: Consider the following parameters and the following initial condition Y0: p := 10: r := 28: b := 1: Y0 := [1, 1, 1]: The routine plot::Ode3d serves for generating a graphical 3D solution of a dynamic system. It solves the ODE numerically and generates graphical data from the numerical mesh. The plot data are specified by the user via generators (procedures) that map a solution point (t, Y) to a point (x, y, z) in 3D. The following generator Gxyz produces a 3D phase plot of the solution. The generator Gyz projects the solution curve to the (y, z) plane with x = - 20; the generator Gxz projects the solution curve to the (x, z) plane with y = - 20; the generator Gxy projects the solution curve to the (x, y) plane with z = 0: Gxyz := (t, Y) -> Y: Gyz := (t, Y) -> [-20, Y[2], Y[3]]: Gxz := (t, Y) -> [Y[1], -20, Y[3]]: Gxy := (t, Y) -> [Y[1], Y[2], 0]: With these generators, we create a 3D plot object consisting of the phase curve and its projections. The following command calls the numerical solver numeric::odesolve to produce the graphical data. It takes about half a minute on a 1 GHz computer: object := plot::Ode3d(f, [i/10 $ i=1..500], Y0, [Gxyz, Style = Splines, Color = RGB::Red], [Gyz, Style = Splines, Color = RGB::LightGrey], [Gxz, Style = Splines, Color = RGB::LightGrey], [Gxy, Style = Splines, Color = RGB::LightGrey]): We define an animated camera moving around the scene: camera := plot::Camera([-1 + 100*cos(a), 6 + 100*sin(a), 120],
5-204
Cameras in 3D
[-1, 6, 25], PI/6, a = 0..2*PI, Frames = 120): The following plot call also takes about half a minute on a 1 GHz computer: plot(object, camera, Axes = Boxed, TicksNumber = Low):
Next, we wish to fly along the Lorenz attractor. We cannot use plot::Ode3d, because we need access to the numerical data of the attractor to build a suitable animated camera object. We use the numerical ODE solver numeric::odesolve2 and compute a list of numerical sample points on the Lorenz attractor. This takes about half a minute on a 1 GHz computer: Y := numeric::odesolve2(f, 0, Y0, RememberLast): timemesh := [i/50 $ i = 0..2000]: Y := [Y(t) $ t in timemesh]: Similar to the picture above, we define a box around the attractor with the projections of the solution curve:
5-205
:= := := :=
-20, 26, 1, 50]: -> [box[1], pt[2], pt[3]]): -> [pt[1], pt[2], box[5]]): -> [pt[1], box[3], pt[3]]):
We create an animated camera using an animation parameter a that corresponds to the index of the list of numerical sample points. The following procedure returns the i-th coordinate (i = 1, 2, 3) of the a-th point in the list of sample points: Point := proc(a, i) begin if domtype(float(a)) <> DOM_FLOAT then procname(args()); else Y[round(a)][i]; end_if; end_proc: In the a-th frame of the animation, the camera is positioned at the a-th sample point of the Lorenz attractor, pointing toward the next sample point. Setting TimeRange = 0..n/10, the camera visits about 10 points per second: n := nops(timemesh) - 1: plot(plot::Scene3d( plot::Camera([Point(a, i) $ i = 1..3], [Point(a + 1, i) $ i = 1..3], PI/4, a = 1..n, Frames = n, TimeRange = 0..n/10), plot::Polygon3d(Y, LineColor = RGB::Red, PointsVisible = TRUE), plot::Polygon3d(Yxy, LineColor = RGB::DimGrey), plot::Polygon3d(Yxz, LineColor = RGB::DimGrey), plot::Polygon3d(Yyz, LineColor = RGB::DimGrey), plot::Box(box[1]..box[2], box[3]..box[4], box[5]..box[6], LineColor = RGB::Black, Filled = TRUE, FillColor = RGB::Grey.[0.1]), BackgroundStyle = Flat) ):
5-206
Cameras in 3D
5-207
5-208
6
Quick Reference
Quick Reference
Glossary
This glossary explains some of the terms that are used throughout the MuPAD documentation. arithmetical expression Syntactically, this is an object of Type::Arithmetical. In particular, this type includes numbers, identifiers and expressions of domain type DOM_EXPR. The phrase domain is synonymous with data type. Every MuPAD object has a data type referred to as its domain type. It may be queried via the function domtype. There are basic domains provided by the system kernel. These include various types of numbers, sets, lists, arrays, hfarrays, tables, expressions, polynomials etc. The documentation refers to these data types as kernel domains. The name of the kernel domains are of the form DOM_XXX (e.g., DOM_INT, DOM_SET,DOM_LIST, DOM_ARRAY, DOM_HFARRAY, DOM_TABLE, etc.). In addition, the MuPAD programming language allows to introduce new data types via the keyword domain or the function newDomain. The MuPAD library provides many such domains. For example, series expansions, matrices, piecewise defined objects etc. are domains implemented in the MuPAD language. The documentation refers to such data types as library domains. In particular, the library Dom provides
domain
6-2
Glossary
a variety of predefined data types such as matrices, residue classes, intervals etc. See DOM_DOMAIN for general explanations on data types. Here you also find some simple examples demonstrating how the user can implement her own domains. domain element The phrase x is an element of the domain d is synonymous with x is of domain type d, i.e., domtype(x) = d. In many cases, the help pages refer to domain elements as objects of library domains, i.e., the corresponding domain is implemented in the MuPAD language. The domain type of an object is the data type of the object. It may be queried via domtype. Sequences such as a := (x, y) or b := (u, v) consist of objects separated by commas. Several sequences may be combined to a longer sequence: (a, b) is flattened to the sequence (x, y, u, v) consisting of 4 elements. Most functions flatten their arguments, i.e., the call f(a, b) is interpreted as the call f(x, y, u, v) with 4 arguments. Note, however, that some functions (e.g., the operand function op) do not flatten their arguments: op(a, 1) is a call with 2 arguments. The concept of flattening also applies to some functions such as max, where it refers to simplification rules such
domain type
flattening
6-3
Quick Reference
as max(a, max(b, c)) = max(a, b, c). function Typically, functions are represented by a procedure or a function environment. Also functional expressions such as sin@exp + id^2: represent functions. Also numbers can be used as (constant) functions. For example, the call 3(x) yields the number 3 for any argument x. A number may be an integer (of type DOM_INT), or a rational number (of type DOM_RAT), or a real floating-point number (of type DOM_FLOAT), or a complex number (of type DOM_COMPLEX). The type DOM_COMPLEX encompasses the Gaussian integers such as 3 + 7*I, the Gaussian rationals such as 3/4 + 7/4*I, and complex floating point numbers such as 1.2 + 3.4*I. This is an expression that does not contain any symbolic variable apart from the special constants PI, E, EULER, and CATALAN. A numerical expression such as I^(1/3) + sqrt(PI)*exp(17) is an exact representation of a real or a complex number; it may be composed of numbers, radicals and calls to special functions. It may be converted to a real or complex floating-point number via float.
number
numerical expression
6-4
Glossary
overloading
The help page of a system function only documents the admissible arguments that are of some basic type provided by the MuPAD kernel. If the system function f, say, is declared as overloadable, the user may extend its functionality. He can implement his own domain or function environment with a corresponding slot "f". An element of this domain is then accepted by the system function f which calls the user-defined slot function. Syntactically, a polynomial such as poly(x^2 + 2, [x]) is an object of type DOM_POLY. It must be created by a call to the function poly. Most functions that operate on such polynomials are overloaded by other polynomial domains of the MuPAD library. This is an arithmetical expression in which symbolic variables and combinations of such variables only enter via positive integer powers. Examples are x^2 + 2 or x*y + (z + 1)^2. This is an arithmetical expression in which symbolic variables and combinations of such variables only enter via integer powers. Examples are x^(-2) + x + 2 or x*y + 1/(z + 1)^2. Every polynomial expression is also a rational expression, but the two previous expressions are not polynomial expressions.
polynomial
polynomial expression
rational expression
6-5
Quick Reference
6-6
7
More Information About Some of the MuPAD Libraries
Abstract Data Types Library on page 7-2 Axioms on page 7-4 Categories on page 7-5 Combinatorics on page 7-7 Functional Programming on page 7-8 Grbner bases on page 7-10 The import Library on page 7-11 Integration Utilities on page 7-12 Linear Algebra Library on page 7-16 Linear Optimization on page 7-24 The misc Library on page 7-26 Numeric Algorithms Library on page 7-27 Orthogonal Polynomials on page 7-28 Properties on page 7-29 Typeset Symbols on page 7-32 Type Checking and Mathematical Properties on page 7-41
Example
We create an object of the abstract data type stack and perform the standard operations. The stack will be initialized with the characters "a", "b" and "c": S:= adt::Stack("a", "b", "c")
To handle the stack, it must be assigned to an identifier. The depth (number of elements) and the top of the stack: S::depth(), S::top()
Push an element, control the depth and then revert the stack. You can see that S is changed, e.g., when the method "push" is called:
7-2
The stack is now reverted (although this is not a standard operation for abstract stacks, it comes in handy in many uses). After that, we pop all elements until the stack is empty: S::reverse(): while not S::empty() do print(S::pop()) end_while; S::depth(), S::top()
7-3
Axioms
In MuPAD, an algebraic structure may be represented by a domain. Parameterized domains may be defined by domain constructors. Many domain constructors are defined in the library package Dom. Domains which have a similar mathematical structure may be members of a category. A category adds a level of abstraction because it postulates conditions which must hold for a domain in order to become a valid member of the category. Operations may be defined for all members of a category based on the assumptions and basic operations of that category, as long as they make no assumptions about the representation of the elements of the domain that belong to the category. Categories may also depend on parameters and are created by category constructors. The category constructors of the MuPAD library are contained in the library package Cat. Attributes of domains and categories are defined in terms of so-called axioms. Axioms state properties of domains or categories. They may also depend on parameters and are defined by axiom constructors. Please note that most axioms of the domains and categories defined in the MuPAD library are not stated explicitly. Only axioms which are not implied by the definition of a category are stated explicitly. The category of groups for example has no axiom stating that the multiplication is invertible because that is implied by the definition of a group. Most axioms defined in this package are of technical (i.e. algorithmic nature).
Bibliography
K. Drescher. Axioms, Categories and Domains. Automath Technical Report No. 1, Univ. GH Paderborn 1995.
7-4
Categories
Categories
In this section... Introduction on page 7-5 Category Constructors on page 7-6 Bibliography on page 7-6
Introduction
In MuPAD, an algebraic structure may be represented by a domain. Parametrized domains may be defined by domain constructors. Many domain constructors are defined in the library package Dom. Domains which have a similar mathematical structure may be members of a category. A category adds a level of abstraction because it postulates conditions which must hold for a domain in order to become a valid member of the category. Operations may be defined for all members of a category based on the assumptions and basic operations of that category, as long as they make no assumptions about the representation of the elements of the domains that belong to the category. Categories may also depend on parameters and are created by category constructors. Attributes of domains and categories are defined in terms of so-called axioms. Axioms state properties of domains or categories. This paper describes the category constructors which are part of the Cat library package. The categories defined so far in general follow the conventions of algebra. There are some properties of the categories which differ from the classical nonconstructive theory of algebra because these properties are not constructive or can not be constructed efficiently. The category hierarchy of the Cat package is quite similar to (part of) the category hierarchy of AXIOM JeSu (see DaTr for a description of the basic categories of Scratchpad, the predecessor of AXIOM).
7-5
Category Constructors
For each category constructor only the entries defined directly by the constructor are described. Entries which are inherited from super-categories are not described. Please note that most axioms of the categories are not stated explicitly. Only axioms which are not implied by the definition of a category are stated explicitly. The category of groups for example has no axiom stating that the multiplication is invertible because that is implied by the definition of a group.
Bibliography
J.H. Davenport and B.M. Trager. Scratchpads View of Algebra I: Basic Commutative Algebra. DISCO 90 (Springer LNCS 429, ed. A. Miola):4054, 1990. K. Drescher. Axioms, Categories and Domains. Automath Technical Report No. 1, Univ. GH Paderborn 1995. R.D. Jenks and R.S. Sutor. AXIOM, The Scientific Computation System. Springer, 1992.
7-6
Combinatorics
Combinatorics
The combinat library provides combinatorial functions. Many more combinatorial functions can be found in the algebraic combinatorics contribution package which can be downloaded at http://sourceforge.net/. Note: Computed results may differ after an external package is installed compared to those computed with the original software installation. The library functions are called using the library name combinat and the name of the function. E.g., use combinat::bell(5) to compute the 5-th Bell number. This mechanism avoids naming conflicts with other library functions. If this is found to be inconvenient, then the routines of the combinat library may be exported via use. E.g., after calling use(combinat, bell) the function combinat::bell may be called directly: bell(5) All routines of the combinat library are exported simultaneously by use(combinat) The functions available in the combinat library can be listed using info(combinat)
7-7
Functional Programming
The functions of the fp package are higher order functions and other utilities useful for functional programming. Some other functions useful for functional programming are already contained in the MuPAD standard library, like map, select and zip. For a more detailed description of concepts like higher order function, currying and fixed points see for example the textbook Computability, Complexity and Languages by M. Davis, R. Sigal, and E. J. Weyuker, Academic Press (1994). Most of the functions of the fp package take functions as arguments and return other functions. In this context a function may be a functional environment, a procedure, a kernel function or any other object which may be regarded as a function (i.e. applied to arguments). Note that almost all MuPAD objects are functions in this sense. The rational integer 2/3 for example may be regarded as a constant function returning the value 2/3: 2/3(x)
The list [sin, cos, 2/3] may be regarded as a unary function mapping x to [sin(x), cos(x), 2/3]: [sin, cos, 2/3](x)
The library functions are called in the form fp::fixedpt(f). By this mechanism, naming conflicts with other library functions are avoided. If this is found to be too awkward the methods of the fp package may be exported. After calling use(fp, fixedpt) the function fixedpt is also directly available, i.e. fixedpt(f) may also be called. If a variable with the name
7-8
Functional Programming
fixedpt already exists then use raises an error. The value of the identifier fixedpt must then be deleted in order to be exported. With use(fp) all methods of the fp package are exported.
7-9
Grbner bases
The groebner package contains some functions dealing with ideals of multivariate polynomial rings over a field. In particular, Grbner bases of such ideals can be computed. An ideal is given by a list of generators. They must all be polynomials of the same type, i.e., for all of them, the coefficient ring (third operand) and list of unknowns (second operand) must be the same. The generators may also be expressions (all of them must be, if any of them is). Grbner bases and related notions depend on the monomial ordering (also called term ordering) under consideration. MuPAD knows the following orderings: the lexicographical ordering, denoted by the identifier LexOrder. the ordering by total degree, with the lexicographical ordering used as a tie-break; it is denoted by the identifier DegreeOrder. the ordering by total degree, with the opposite of the lexicographical ordering for the reverse order of unknowns used as a tie-break (i.e., the monomial that is lexicographically smaller if the order of variables is reversed, is considered the bigger one); this one is denoted by DegInvLexOrder. user-defined orderings. They constitute a domain Dom::MonomOrdering of their own. Orderings always refer to the order of the unknowns of the polynomial; e.g., x is lexicographically bigger than y in F[x, y], but smaller than y when regarded as an element of F[y, x].
7-10
7-11
Integration Utilities
In this section... First steps on page 7-12 Integration by parts and by change of variables on page 7-14 This library contains functions for manipulating and solving integrals. Currently there are only described interfaces for the well-known integration methods change of variables and integration by parts. In addition, a function for integrating over arbitrary subsets of the real numbers exists. In future versions more interfaces will be added.
First steps
Integration is the process inverse to differentiation. Any function F in the variable x with is an integral of f:
f := cos(x)*exp(sin(x))
F := int(f,x)
diff(F,x)
No constant is added to the integral or, in other words, a special integration constant is chosen automatically. With MuPAD it is possible to determine integrals of elementary functions, of many special functions and, with some restrictions, of algebraic functions: int(sin(x)^4*cos(x),x)
7-12
Integration Utilities
int(1/(2+cos(x)),x)
int(exp(-a*x^2),x)
int(x^2/sqrt(1-5*x^3),x)
normal(simplify(diff(%,x)))
int(sin(x)*dirac(x+2)-heaviside(x+3)/x, x=1..4)
7-13
are integrals of the form where p(x) is polynomial. Thereby one has to use the rule in the way that the polynomial is differentiated. Thus one has to choose . intlib::byparts(hold(int)((x-1)*cos(x),x),cos(x))
In particular with the guess it is possible to compute a lot of the . well-known standard integrals, like e.g. intlib::byparts(hold(int)(arcsin(x),x),1)
In order to determine the remaining integral one may use the method change of variable
7-14
Integration Utilities
Via backsubstition into the solved integral F one gets the requested result. hold(int)(arcsin(x),x) = x*arcsin(x)-subs(eval(F),t=1-x^2)
Applying change of variable with the integrator is problematic, since it may occur that the integrator will never terminate. For that reason this rule is used within the integrator only on certain secure places. On the other hand, this may also lead to the fact that some integrals cannot be solved directly. f:= sqrt(x)*sqrt(1+sqrt(x)): int(f,x)
eval(intlib::changevar(hold(int)(f,x),t=sqrt(x))) | t=sqrt(x)
7-15
Introduction
An overview of all the available functions can be obtained by using the MuPAD function info. Here we see an extract of the functions available in the linear algebra library (we do not state the whole output generated by the call info(linalg), since the library contains more than 40 different functions): info(linalg) Library 'linalg': the linear algebra package -- Interface: linalg::addCol, linalg::adjoint, linalg::basis, linalg::charpoly, ...
After being exported, library functions can also be used by their short notation. The function call use(linalg) exports all functions of linalg. After that one can use the function name gaussElim instead of linalg::gaussElim, for example. Please note that user-defined procedures that use functions of the library linalg should always use the long notation linalg::functionname, in order to make sure that the unambiguity of the function name is guaranteed. The easiest way to define a matrix A is using the command matrix. The following defines a 22 matrix: A := matrix([[1, 2], [3, 2]])
7-16
Now, you can add or multiply matrices using the standard arithmetical operators of MuPAD: A * A, 2 * A, 1/A
7-17
represents matrices over the field of arithmetical expressions, i.e., the domain Dom::ExpressionField(). Be careful with calculations with matrices over this coefficient domain, because their entries usually do not have a unique representation (e.g., there is more than one representation of zero). You can normalize the components of such a matrix A with the command map(A, normal ). The library Dom offers standard coefficient domains, such as the field of rational numbers (Dom::Rational), the ring of integers (Dom::Integer), the residue classes of integers (Dom::IntegerMod(n)) for an integer n, or even the rings of polynomials (such as Dom::DistributedPolynomial(ind,R) or Dom::Polynomial(R), where ind is the list of variables and R is the coefficient ring). A domain created by the domain constructor Dom::SquareMatrix represents the ring of square matrices over a specified coefficient domain. Dom::SquareMatrix expects the number of rows of the square matrices and optionally a coefficient ring of category Cat::Rng. There are several possibilities to define matrices of a domain created by
Dom::Matrix or Dom::SquareMatrix. A matrix can be created by giving a
two-dimensional array, a list of the matrix components, or a function that generates the matrix components: delete a, b, c, d: A := matrix([[a, b], [c, d]])
The command matrix actually is an abbreviation for the domain Dom::Matrix(). To create diagonal matrices one should use the option Diagonal (the third argument of matrix is either a function or a list): B := matrix(2, 2, [2, -2], Diagonal)
7-18
The following two examples show the meaning of the third argument: delete x: matrix(2, 2, () -> x), matrix(2, 2, x)
1/A
Next we create the 22 generalized Hilbert matrix (see also linalg::hilbert) as a matrix of the ring of two-dimensional square matrices: MatQ2 := Dom::SquareMatrix(2, Dom::Rational)
7-19
A vector with n components is a 1n matrix (a row vector) or a n1 matrix (a column vector). The components of a matrix or a vector are accessed using the index operator, i.e., A[i,j] returns the component of the row with index i and column with index j. The input A[i, j]:= x sets the (i, j)-th component of the matrix A to the value of x. The index operator can also be used to extract sub-matrices by giving ranges of integers as its arguments: A := Dom::Matrix(Dom::Integer)( [[1, 2, 3], [4, 5, 6], [7, 8, 9]] )
7-20
of the domain constructor Dom::Matrix in their name and functionality. These functions are implemented by calling relevant methods of the domain to that they belong, apart from additional argument checking. These functions enable an user-friendly usage on the interactive level after exporting. However, in user-defined procedures the methods of the corresponding domain should be used directly to avoid additionally calls of procedures. For example standard matrix manipulation functions such as deleting, extracting or swapping of rows and columns are defined as methods of the domain constructors Dom::Matrix and Dom::SquareMatrix. The method "gaussElim" offers a Gaussian elimination process for each domain created by these constructors.
2 When creating a new matrix the method "new" is called. It converts each
component of the matrix explicitly into a component the component ring, which may be time consuming. However, matrices and vectors are often the results of computations, whose components already are elements of the component ring. Thus, the conversion of the entries is not necessary. To take this into account, the domain constructors Dom::Matrix and Dom::SquareMatrix offer a method "create" to define matrices in the usual way but without the conversion of the components. Please note that this method does not test its arguments. Thus it should be used with caution.
3 A further possibility of achieving better runtimes using functions of linalg
or methods of the constructor Dom::Matrix is to store functions and methods that are called more than once in local variables. This enables a faster access of these functions and methods. The following example shows how a user-defined procedure using functions of linalg and methods of the domain constructor Dom::Matrix may look like. It computes the adjoint of a square matrix defined over a commutative ring (see Cat::CommutativeRing):
7-21
adjoint := proc(A) local n, R, i, j, a, Ai, Mat, // local variables to store often used methods det, delRow, delCol, Rnegate; begin if args(0) <> 1 then error("wrong number of arguments") end_if; Mat := A::dom; // the domain of A R := Mat::coeffRing; // the component ring of A n := Mat::matdim(A); // the dimension of A; faster than calling // 'linalg::matdim'! if testargs() then if Mat::hasProp(Cat::Matrix) <> TRUE then error("expecting a matrix") elif not R::hasProp( Cat::CommutativeRing ) then error("expecting matrix over a 'Cat::CommutativeRing'") elif n[1] <> n[2] then error("expecting a square matrix") end_if end_if; // store often used methods in local variables: det := linalg::det; delRow := Mat::delRow; // faster than calling 'linalg::delRow'! delCol := Mat::delCol; // faster than calling 'linalg::delCol'! Rnegate := R::_negate; // faster than using the '-' operator! n := Mat::matdim(A)[1]; // faster than calling 'linalg::nrows'! a := array(1..n, 1..n); for i from 1 to n do Ai := delCol(A, i); for j from 1 to n do a[i, j] := det(delRow(Ai, j)); if i + j mod 2 = 1 then a[i, j] := Rnegate(a[i, j]) end_if end_for
7-22
end_for; // create a new matrix: use Mat::create instead of Mat::new // because the entries of the array are already elements of R return(Mat::create(a)) end_proc: We give an example: MatZ6 := Dom::Matrix(Dom::IntegerMod(6)): adjoint(MatZ6([[1, 5], [2, 4]]))
7-23
Linear Optimization
The linopt library provides algorithms for linear and integer programming. The routines in this library can be used in order to minimize and maximize a linear function subject to the set of linear constraints. It is possible to get only integer solutions. The routines for linear optimization are based on the two phase simplex algorithm. The algorithm of Land-Doig is used to find integer solutions. The library functions are called using the library name linopt and the name of the function. E.g., use c := [{3*x + 4*y - 3*z <= 23, 5*x - 4*y - 3*z <= 10, 7*x + 4*y + 11*z <= 30}, - x + y + 2*z, {x, y, z}]: linopt::maximize(c)
to solve the linear optimization problem defined in the variable c. This mechanism avoids naming conflicts with other library functions. If this is found to be inconvenient, then the routines of the linopt package may be exported via use. E.g., after calling use(linopt, maximize): the function linopt::maximize may be called directly: c := [{3*x + 4*y - 3*z <= 23, 5*x - 4*y - 3*z <= 10, 7*x + 4*y + 11*z <= 30}, - x + y + 2*z, {x, y, z}]: maximize(c)
7-24
Linear Optimization
The functions available in the linopt library can be listed with: info(linopt)
-- Interface:
7-25
7-26
7-27
Orthogonal Polynomials
The orthpoly package provides some standard orthogonal polynomials. The package functions are called using the package name orthpoly and the name of the function. E.g., use orthpoly::legendre(5, x) to generate the fifth degree Legendre polynomial in the indeterminate x. This mechanism avoids naming conflicts with other library functions. If this is found to be inconvenient, then the routines of the orthpoly package may be exported via use. E.g., after calling use(orthpoly, legendre) the function orthpoly::legendre may be called directly: legendre(5, x) All routines of the orthpoly package are exported simultaneously by use(orthpoly) If the identifier legendre already has a value, then use returns a warning and does not export orthpoly::legendre. The value of the identifier legendre must be deleted before it can be exported successfully from the orthpoly package.
7-28
Properties
Properties
Three types of mathematical properties are available in MuPAD: Basic number domains, such as the domain of integers, the domain of rational numbers, the domain of real numbers, the domain of positive real numbers, or the domain of complex numbers Intervals in basic number domains Residue classes of integers Often, there are several equivalent ways to specify a property. For example, >= 0, Type::NonNegative, and Type::Interval([0], infinity) are equivalent properties. Similarly, Type::Odd is equivalent to Type::Residue(1, 2). Some members of the Type library do not correspond to mathematical properties, for example, Type::ListOf. This table shows some examples of how to set properties on the identifier or expression expr. Note If expr is a list, vector, or matrix, then only the syntax (expr, set) is valid. Do not use the syntaxes (expr in set) or relations, such as expr > 0 or expr < 0, for nonscalar expr.
Property
Real value, Imaginary value, Complex value, . This is a default value for most MuPAD objects.
7-29
Property
Integer value, Rational value, Positive value, Negative value, Nonnegative value,
Zero, {0} Nonzero value, Even value, Odd value, Positive integer value,
(expr = 0) (expr <> 0) (expr, 2*Z_) or (expr in 2*Z_) (expr, 2*Z_ + 1) (expr in Z_ and expr > 0) (expr in Z_ and expr < 0) (expr in Z_ and expr >= 0) (expr in Q_ and expr > 0) (expr in Q_ and expr < 0)
(expr,Type::NegInt)
(expr,Type::NonNegInt)
(expr,Type::PosRat)
(expr,Type::NegRat)
7-30
Properties
Property
Here, a,b are expressions, and T is a basic number domain. b+a Here, a and b are integers.
7-31
Typeset Symbols
In this section... Greek Letters on page 7-32 Open Face Letters on page 7-34 Arrows on page 7-34 Operators on page 7-35 Comparison Operators on page 7-36 Other Symbols on page 7-37 Whitespaces on page 7-38 Braces on page 7-38 Punctuation Marks on page 7-38 Umlauts on page 7-39 Currency on page 7-40 Math Symbols on page 7-40
Symbol provides access to typesetting symbols. All available symbols are
shown below, sorted in appropriate groups. The symbols can be accessed via slots of Symbol (e.g. Symbol::alpha for the symbol ) or via function calls (e.g. Symbol("alpha")). Some symbols can be accessed only via function calls. For details, see Symbol::new.
Greek Letters
alpha gamma epsi, epsilon zeta theta beta delta varepsilon, epsiv eta thetasym, thetav, vartheta
7-32
Typeset Symbols
iota lambda nu omicron varpi, piv sigma tau straightphi, phi chi omega Beta Delta Zeta Theta Kappa Mu Xi Pi Sigma Upsi, upsih, Upsilon Chi Omega, ohm
kappa mu, micro xi pi rho sigmaf, sigmav, varsigma upsilon, upsi phiv, varphi psi Alpha Gamma Epsi, Epsilon Eta Iota Lambda Nu Omicron Rho Tau Phi Psi
7-33
Arrows
uarr, UpArrow Uparrow, DoubleUpArrow, uArr Downarrow, dArr, DoubleDownArrow
7-34
Typeset Symbols
Operators
+ ^ plus PlusMinus, plusmn, pm Hat, circ prod minus times dot coprod, Coproduct, amalg * lowast cdot, middot, CenterDot, centerdot deg otimes CircleTimes, bigotimes, xotime dagger Del Backslash, setminus, setmn, bsol
7-35
Comparison Operators
ap, approx, asymp, TildeTilde TildeFullEqual, cong < Congruent, equiv ge, geq, GreaterEqual le, leq lt subseteq, sube, SubsetEqual = > tilde, Tilde, sim
bot, bottom, UpTee, perp Equal, equals gt NotEqual, ne Subset, sub, subset Superset, sup, supset
7-36
Typeset Symbols
NotElement, notin
Other Symbols
brvbar UnderBar, UnderLine, lowbar # true unknown Fail NaN num, sharp true UNKNOWN FAIL NotANumber PartialD, part commat trade die, uml hearts, heartsuit
CapitalDifferentialD, D, DD DifferentialD, dd copy reg diam, diams, diamond, diamondsuit spades, spadesuit E half, frac12 frac34 sup2 @
7-37
permil sect
Whitespaces
ApplyFunction InvisibleTimes blank Space InvisibleComma Tab MediumSpace ThickSpace
NonBreakingSpace, nbsp
Braces
lang, langle, { LeftAngleBracket [ | ) lbrack, lsqb LeftFloor, lfloor verbar, vert rpar rceil, RightCeiling } rbrace, rcub ] ( lbrace, lcub lceil, LeftCeiling lpar Verbar, Vert rfloor, RightFloor rsqb, rbrack rang, rangle, RightAngleBracket
Punctuation Marks
:: , Colon comma : ; colon semi
7-38
Typeset Symbols
sdot hellip, tdot, dots horbar, mdash apos, quot, rsquo backprime, bprime
Umlauts
auml ouml uuml szlig Auml Ouml Uuml
7-39
Currency
cent euro yen $ dollar pound
Math Symbols
nabla weierp, wp aleph, alefsym Sqrt, radic int, Integral cauchypv, pvint, PrincipalValueIntegral
vprop, varpropto, vprop not loz, lozenge Sum, sum conint, oint, ContourIntegral there4, Therefore, therefore ForAll, forall emptyv, varnothing Re Im, image ImaginaryI, ii
Re
7-40
yes Type::ConstantIdents
7-41
is a property no no yes yes yes yes yes yes yes no yes no yes yes yes no no no yes yes no yes no no no no
has arguments yes yes no no no no no no no no no yes no no no no yes no no no no yes yes yes no yes
Type::ListProduct yes
Type::NonNegInt yes Type::NonNegRat yes Type::NonNegative yes Type::NonZero Type::Numeric Type::Odd Type::PolyOf Type::PosInt Type::PosRat Type::Positive Type::Prime Type::Product Type::Property Type::Rational Type::Real Type::Relation Type::Residue Type::Series Type::Set Type::SetOf yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes
Type::SequenceOf yes
7-42
Name Type::Singleton
is a property no no no no no yes
Example 1
testtype performs syntactical tests:
Example 2
Some types depends on parameters and cannot be used without parameters: testtype([1, 2, 3], Type::ListOf)
7-43
assume(x, Type::Interval)
Example 3
is derives mathematical properties:
is(-(2*x + 1) < 0)
Example 4
Type::Property and Type::Constant are not properties:
assume(x, Type::Property)
is(x, Type::AnyType)
7-44