├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── doc ├── dev-log-wrc.md └── dev-log-zyh.md ├── mathS.sln └── mathS ├── .gitattributes ├── include ├── ConstantEvaluate.h ├── Evaluate.h ├── ExtendedCMath.h ├── LBAssembler.h ├── MathFunction.h ├── MathObject.h ├── MathParser.h ├── NAlgorithm.h ├── NFunction.h ├── NFunctionalOperator.h ├── NMathObject.h ├── Ptr.h ├── Rule.h ├── RuleLib.h ├── lexer.h └── string-switch.h ├── mathS.vcxproj ├── mathS.vcxproj.filters └── src ├── Evaluate.cpp ├── ExtendedCMath.cpp ├── LBAssembler.cpp ├── MathObject.cpp ├── MathParser.cpp ├── NFunction.cpp ├── NFunctionalOperator.cpp ├── NMathObject.cpp ├── Rule.cpp ├── RuleLib.cpp ├── lexer.cpp ├── main.cpp └── string-switch.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # JustCode is a .NET coding add-in 131 | .JustCode 132 | 133 | # TeamCity is a build add-in 134 | _TeamCity* 135 | 136 | # DotCover is a Code Coverage Tool 137 | *.dotCover 138 | 139 | # AxoCover is a Code Coverage Tool 140 | .axoCover/* 141 | !.axoCover/settings.json 142 | 143 | # Visual Studio code coverage results 144 | *.coverage 145 | *.coveragexml 146 | 147 | # NCrunch 148 | _NCrunch_* 149 | .*crunch*.local.xml 150 | nCrunchTemp_* 151 | 152 | # MightyMoose 153 | *.mm.* 154 | AutoTest.Net/ 155 | 156 | # Web workbench (sass) 157 | .sass-cache/ 158 | 159 | # Installshield output folder 160 | [Ee]xpress/ 161 | 162 | # DocProject is a documentation generator add-in 163 | DocProject/buildhelp/ 164 | DocProject/Help/*.HxT 165 | DocProject/Help/*.HxC 166 | DocProject/Help/*.hhc 167 | DocProject/Help/*.hhk 168 | DocProject/Help/*.hhp 169 | DocProject/Help/Html2 170 | DocProject/Help/html 171 | 172 | # Click-Once directory 173 | publish/ 174 | 175 | # Publish Web Output 176 | *.[Pp]ublish.xml 177 | *.azurePubxml 178 | # Note: Comment the next line if you want to checkin your web deploy settings, 179 | # but database connection strings (with potential passwords) will be unencrypted 180 | *.pubxml 181 | *.publishproj 182 | 183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 184 | # checkin your Azure Web App publish settings, but sensitive information contained 185 | # in these scripts will be unencrypted 186 | PublishScripts/ 187 | 188 | # NuGet Packages 189 | *.nupkg 190 | # NuGet Symbol Packages 191 | *.snupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/[Pp]ackages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/[Pp]ackages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/[Pp]ackages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | *.appxbundle 217 | *.appxupload 218 | 219 | # Visual Studio cache files 220 | # files ending in .cache can be ignored 221 | *.[Cc]ache 222 | # but keep track of directories ending in .cache 223 | !?*.[Cc]ache/ 224 | 225 | # Others 226 | ClientBin/ 227 | ~$* 228 | *~ 229 | *.dbmdl 230 | *.dbproj.schemaview 231 | *.jfm 232 | *.pfx 233 | *.publishsettings 234 | orleans.codegen.cs 235 | 236 | # Including strong name files can present a security risk 237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 238 | #*.snk 239 | 240 | # Since there are multiple workflows, uncomment next line to ignore bower_components 241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 242 | #bower_components/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- [Bb]ackup.rdl 268 | *- [Bb]ackup ([0-9]).rdl 269 | *- [Bb]ackup ([0-9][0-9]).rdl 270 | 271 | # Microsoft Fakes 272 | FakesAssemblies/ 273 | 274 | # GhostDoc plugin setting file 275 | *.GhostDoc.xml 276 | 277 | # Node.js Tools for Visual Studio 278 | .ntvs_analysis.dat 279 | node_modules/ 280 | 281 | # Visual Studio 6 build log 282 | *.plg 283 | 284 | # Visual Studio 6 workspace options file 285 | *.opt 286 | 287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 288 | *.vbw 289 | 290 | # Visual Studio LightSwitch build output 291 | **/*.HTMLClient/GeneratedArtifacts 292 | **/*.DesktopClient/GeneratedArtifacts 293 | **/*.DesktopClient/ModelManifest.xml 294 | **/*.Server/GeneratedArtifacts 295 | **/*.Server/ModelManifest.xml 296 | _Pvt_Extensions 297 | 298 | # Paket dependency manager 299 | .paket/paket.exe 300 | paket-files/ 301 | 302 | # FAKE - F# Make 303 | .fake/ 304 | 305 | # CodeRush personal settings 306 | .cr/personal 307 | 308 | # Python Tools for Visual Studio (PTVS) 309 | __pycache__/ 310 | *.pyc 311 | 312 | # Cake - Uncomment if you are using it 313 | # tools/** 314 | # !tools/packages.config 315 | 316 | # Tabs Studio 317 | *.tss 318 | 319 | # Telerik's JustMock configuration file 320 | *.jmconfig 321 | 322 | # BizTalk build output 323 | *.btp.cs 324 | *.btm.cs 325 | *.odx.cs 326 | *.xsd.cs 327 | 328 | # OpenCover UI analysis results 329 | OpenCover/ 330 | 331 | # Azure Stream Analytics local run output 332 | ASALocalRun/ 333 | 334 | # MSBuild Binary and Structured Log 335 | *.binlog 336 | 337 | # NVidia Nsight GPU debugger configuration file 338 | *.nvuser 339 | 340 | # MFractors (Xamarin productivity tool) working folder 341 | .mfractor/ 342 | 343 | # Local History for Visual Studio 344 | .localhistory/ 345 | 346 | # BeatPulse healthcheck temp database 347 | healthchecksdb 348 | 349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 350 | MigrationBackup/ 351 | 352 | # Ionide (cross platform F# VS Code tools) working folder 353 | .ionide/ 354 | 355 | # Clang 356 | *.o 357 | *.bin 358 | *.out 359 | 360 | /CMakeLists.txt 361 | /cmake-build-debug/ 362 | /.idea 363 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(mathS) 3 | 4 | set(SHARED OFF) 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_FLAGS_RELEASE "-O3") 7 | 8 | add_compile_options("$<$:/utf-8>") 9 | add_compile_options("$<$:/utf-8>") 10 | 11 | include_directories( 12 | mathS/include 13 | ) 14 | AUX_SOURCE_DIRECTORY(mathS/src DIR_SRCS) 15 | 16 | add_executable(mathS mathS/include/LBAssembler.h mathS/include/MathObject.h mathS/include/MathParser.h 17 | mathS/include/NMathObject.h 18 | mathS/include/Rule.h 19 | mathS/include/RuleLib.h 20 | mathS/include/NFunction.h 21 | mathS/include/NFunctionalOperator.h 22 | mathS/include/ExtendedCMath.h 23 | mathS/include/Compute.h 24 | mathS/src/LBAssembler.cpp mathS/src/MathObject.cpp mathS/src/MathParser.cpp 25 | mathS/src/NMathObject.cpp 26 | mathS/src/NFunction.cpp 27 | mathS/src/ExtendedCMath.cpp 28 | mathS/src/Rule.cpp 29 | mathS/src/RuleLib.cpp 30 | mathS/src/Compute.cpp 31 | mathS/src/NFunctionalOperator.cpp 32 | mathS/src/main.cpp mathS/src/lexer.cpp mathS/include/lexer.h) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mathS 2 | 3 | A library for computer algebra (symbolic computing) and scientific computing. 4 | 5 | We start from an imitation of Mathematica. We try to make it more connected to C++, and allow you to enjoy its feature conveniently in C++ programs. For example, parse a text input `Sin(1/x)+2*y^2"` and instantly get an `std::function `. 6 | 7 | *mathS=math+Science|math+Symbol* 8 | 9 | 10 | 11 | ## Features 12 | 13 | * Symbolic expression processing. **MathS** grammar is designed to state an expression clearly and without those ambiguous meanings usually in writing. Vector, matrix, any shape of tensors or general list are supported. Functional operators and some advanced operators like $\nabla,\int,\sum,\prod$ are supported. Equations and inequations are also supported in expression. We have already implemented `MathParser`. It converts text expressions to varied `MathObject`. 14 | 15 | Sample input and output: 16 | 17 | ``` 18 | (x+y/3)^2-(y/3+x)^2+u*u*v/v 19 | = u^2 20 | ``` 21 | 22 | We are still working on the development. 23 | 24 | * `NMath` module offers better performance on numerical tasks. Numerical linear algebra will be strongly supported. It is under developing. We have already implemented `Assembler`. `MathObejct` can be converted to `NFunction` which takes the variables in the expression as parameters. This would support those cases like plotting, numerical integrating when massive computing is needed. 25 | 26 | * Convert `MathObject` to **LaTeX** format string. 27 | 28 | ```C++ 29 | std::cout << Parse("4*Sin(x^2+Pi/2)+Sum<>({1,12})")->GetLaTeXString() << std::endl; 30 | 31 | /***Output****** 32 | 4\,\sin{\left(x^{2}+\frac{{\pi}}{2}\right)}+\sum_{i}^{\left\{1,12\right\}}\cos{\left(\log{i}\right)^{2}} 33 | ***************/ 34 | ``` 35 | 36 | Rendered in markdown or LaTeX: 37 | 38 | ![](http://latex.codecogs.com/svg.latex?4\\,\\sin{\\left(x^{2}+\\frac{{\\pi}}{2}\\right)}+\\sum_{i}^{\\left\\{1,12\\right\\}}\\cos{\\left(\\log{i}\\right)^{2}}) 39 | 40 | * As an C++ library, you can enjoy its features in C++ freely. We use lambda expression to convert `MathObject` to `std::function` so that you can use it freely in your program. 41 | 42 | ```C++ 43 | Assembler assembler; 44 | auto f = assembler.assemble(Parse("Sin(x^2)-y/2"),{"x","y"}); 45 | std::cout << f({1.2, 1.3}) << std::endl; 46 | 47 | /******Output******* 48 | 0.3414583 49 | *******************/ 50 | ``` 51 | 52 | 53 | 54 | ## A powerful calculator in 9 line 55 | 56 | The simplest application with **mathS** is a calculator. The follow program is a calculator that supports various operations, vector and matrix. 57 | 58 | ```c++ 59 | #include 60 | #include 61 | #include 62 | 63 | using namespace mathS; 64 | 65 | int main() { 66 | std::string str; 67 | Assembler assembler; 68 | 69 | std::cin >> str; 70 | auto mobj = Parse(str); // Get MathObject 71 | 72 | if (mobj->GetType() == MathObject::ERROR) // Check sytanx 73 | std::cout << mobj->GetString() << std::endl; 74 | 75 | std::vector params = {}; // No variables in the expression in a calculator program. 76 | 77 | auto f = assembler.Assemble(mobj, params); // Get NFunction 78 | std::cout << " = " << f({})->GetString() << std::endl; 79 | 80 | return 0; 81 | } 82 | ``` 83 | 84 | Sample input and output 85 | 86 | ``` 87 | E^3+9.1*(3-2.1) 88 | = 28.275537 89 | 90 | Floor(1.34+3) 91 | = 4.000000 92 | 93 | {3,6,9}/3 94 | = {1.000000,2.000000,3.000000} 95 | 96 | {3.1,3.2,{6,2,1}}*{1.1,2.2,{3.1,3.2,4.3}} 97 | = {3.410000,7.040000,{18.600000,6.400000,4.300000}} 98 | 99 | sin({1,PI/6,PI/2}) 100 | = {0.841471,0.500000,1.000000} 101 | ``` 102 | 103 | ## Build 104 | 105 | TODO. 106 | 107 | 108 | 109 | ## What's to be done 110 | 111 | This is our timeline. We are now at medium term of *step 2*. 112 | 113 | * *Step 1*: Basic part 114 | 115 | * **Parser**: Convert text expressions to `MathObject` 116 | * **Assembler**: Convert `MathObject` to `NMathFuncition`(numeric math function), also C++ std function. 117 | 118 | When *Step 1* is done, mathS is already a quite useful library. It will allow programmers get a function instantly by text expressions. 119 | 120 | * *Step 2*: Essential part 121 | 122 | * **Rule**: Use a chain of rules to transform `MathObject`, so that we can perform symbolic integral, differential, simplification to any expression. 123 | * **NAlgorithms**: Adopt numeric computing algorithms. Performing interpolation, numeric integral, matrix decomposition, numeric optimization, linear programming, solving linear and non-linear equations, statistics, etc. . Also many other interesting utilities.(This will take a very long time) 124 | * **Interpreter**: More controlling functions, and allow user to execute a mathS script. Similar to a Mathematica program. 125 | 126 | * *Step 3*: Advanced part 127 | 128 | Many of the following could be just dreams. 129 | 130 | * Even more diverse objects. 131 | 132 | * **SparseList**: For large sparse matrix and algorithms. 133 | * **Graph**: Build a graph, display and perform graph algorithms. 134 | * **Graphics**: Allow users to plot and draw with simple commands. (Very useful, but to make it great is not that easy) 135 | * **Image**: Read, process and show images. 136 | * ... 137 | 138 | * Extensions 139 | 140 | (This is cool but maybe not practical. We are not supposed to repeat useless work, which has been done by others perfectly.) 141 | 142 | * **MLlib**: Simple implementation of machine learning algorithms 143 | 144 | 145 | 146 | ## Documentation 147 | 148 | TODO. 149 | 150 | 151 | 152 | # Development 153 | 154 | * See in `doc/dev-log-***.md`. -------------------------------------------------------------------------------- /doc/dev-log-wrc.md: -------------------------------------------------------------------------------- 1 | ## 2020-7-6 2 | 3 | **\[任务\]** 这个阶段我们有一下几个独立的开发任务 4 | 5 | * Parser. 对输入的表达式文本解析,返回一个MathObject. 6 | 7 | * Match. 对两个MathObject`pattern`与`target`进行匹配: 8 | 9 | * 初始化一个**匹配表**`std::sting`->`MathObject`,用于特殊标识符的匹配 10 | * 递归地对当前MathObject进行下面的算法 11 | * 如果`pattern`中的当前MathObject是Atom并且以特殊标识符'_'修饰,就是要匹配任意MathObject. 首先检查匹配表中,是否已经有这个特殊表示符修饰的串,如果有的话,就把匹配表中对应的MathObject与当前`target`的MathObject进行匹配,并返回匹配结果;如果匹配表中没有,也就是未出现过的特殊标识,就将这个映射添加到匹配表中,并返回匹配成功。 12 | * 如果`pattern`中的当前MathObject是Atom并且以特殊标识符''@'修饰,就是要匹配一个名称,要求`target`对应的MathObject必须是Atom,并且是变量名称而不是数字和字符串。如果是以特殊标识符`$s`修饰,就是要匹配字符串,以特殊标识符`$n`修饰,就是匹配数字。**同样也要先去对照匹配表。** 13 | * 如果`pattern`当前的MathObject是Atom,并且没有特殊标识符修饰,就要求`target`与之对应的必须完全一模一样。 14 | * 如果`pattern`当前MathObject是更高级的结构,要求`target`的MathObject类型与之相同(如果是ListObject/Polynomial/Item这些还要求size相同),并且递归地匹配每个子MathObject。 15 | 16 | 这里的Match,是成对的`pattern`与`target`匹配。有时,一些匹配不方便用pattern来表示,需要用一段代码,一个函数来进行匹配。这些要另外讨论,如何把两种匹配统一起来,以后再想。我们就先把`pattern`对`target`的匹配做好把。 17 | 18 | * LBAssembler:给一个MathObject和参数名称列表,返回一个NMathFunction,即一个输入NMathObject返回NMathObject的函数。其原理是利用LBAssembler,在NMath体系下,组装出一个函数。可以附加一个功能ToStdFunction,把NMathFunction变为std::function,更方便对函数的使用。 19 | 20 | ## 2020-7-7 21 | 22 | **[工作]** LBAssembler进度推进。 23 | 24 | * 介绍LBAssemble的原理:所谓Assemble,即把一个表达式的基本元素变成NFunction,根据表达式的结构,一层一层组装成更复杂运算的NFunction。例如已有两个NFunction,`f1,f2`,则他们的和就是下面的lambda表达式: 25 | 26 | ```C++ 27 | [f1,f2](NMathObject* param) 28 | { 29 | return f1(param)+f2(param); 30 | } 31 | ``` 32 | 33 | 例如`2*x+sin(y)`是一个表达式,要组装出函数`f(x,y)`,需要把每个Atom看做是关于参数`x,y`的NFunction,然后再一层一层组装. 34 | 35 | * 本次工作,先实现了基本Atom的转换,也就是Number和Variable的组装。String不支持转换,因为没有对应的NMathObject。 36 | 37 | ## 2020-9-22 38 | 39 | **[工作]** 40 | 41 | * MathParser已经开发完成。它没有使用栈结构,而是逐层嵌套地构造表达式。 42 | * 所有对象(MathObject, NMathObject)的指针使用改为使用STL的智能指针。为了简化名称和体现程序逻辑,在Ptr.h中有简单封装。这将更方便内存管理。我认为在目前阶段广泛使用`std::shared_ptr`不会对程序的性能有显著影响。 43 | 44 | **[约定]** 45 | 46 | * 对MathObject的表示框架作了修改,增加FunctionalOperator类型,这用来表示积分、求和、累乘、傅里叶变换、卷积、导数算子等这些特殊的函数。我们把这些函数与普通的函数区分开,因为它们是*函数到函数的映射*。我们当然可以把函数和数字都看做等价的对象,但对于表达式来说,想要表达一个对象是函数还是数是比较困难而且容易产生歧义的,尤其是对于函数对象,我们需要明确函数的参数是什么。为此引入的FunctionalOperator的书写格式为: 47 | 48 | * ``` 49 | _FUNCOP<<@VAR1,@VAR2,...|_FUNC>>(_PARA) 50 | ``` 51 | 52 | **[任务]** 53 | 54 | * 完成LBAssemble,从符号对象转为数值计算对象,并具有初步的数值计算功能。 55 | * 建立在MathObject上的运算库,库将具有初步的符号计算功能: 56 | * 首先需要基本的匹配源模式->变换为目标模式的模块 57 | * 手动编写不能使用匹配变换的方法进行变形的规则 58 | 59 | 60 | 61 | ## 2020-9-23 62 | 63 | **[工作]** LBAssembler 大部分开发完成。 64 | 65 | 66 | 67 | ## 2020-9-23 68 | 69 | **[工作]** 实现了FucntionalOperator,并用数值求和Sum测试,LBAssembler开发完成。对于每次运行独立的单条命令,不需要考虑更多的上下文,已经够用。 70 | 71 | **[约定]** MathObject框架变动,废弃了ListObject。本来ListObject的引入,就是为了方便统一处理函数的参数列表、向量的元素列表、索引定位的列表,但这样会导致其他的麻烦: 72 | 73 | 1. 每次对函数的参数都要作类型检查是否为ListObject,ListObject中套了一个MathObject, 和直接一个MathObject,应当是等价的,而他们能表示为不同的结构,会增加处理的麻烦; 74 | 2. 转为NMath时,由于NList不像Vector那样,是List套一层Vector,所以会混淆函数多元函数和向量作为参数的函数,即f(x,y)和f({x,y})。如果要区分,则不得不强制给参数套一层List,即参数的第一层一定是List,而这与MathObject的Function表示逻辑不同,Function是允许不套List的 75 | 3. ListObject会导致语法过于灵活,可能出现(1,2)\*3之类的写法,而这是没有意义的,应当表达成{1,2}\*3的向量形式。 76 | 77 | 因此我们放弃ListObject作为中间对象,这并不影响MathObject的表达能力。凡是允许多元组的地方,直接在相应的MathObject中内置std::vector。他们的处理方法,如Parse, Assemble是类似的。 78 | 79 | 为了废弃ListObject,框架从上至下进行了很多变动,因为原本ListObject的地位很重要。但改动后,能感觉到代码更优美了,少了很多的检查,例如我们不再需要EmptyObject,因为std::vector为空时,直接表达了函数参数为空,或者索引列表为空这些情况,而不必需要EmptyObject。其他地方则用不到EmptyObject。 80 | 81 | 原本ListObject的代码并不能算删掉,因为对于List的处理方法是不变的,这些代码被修改后重新用上了。 82 | 83 | **[任务]** 总结一下各个模块 84 | 85 | * Symbolic 86 | * MathObject 87 | * Rule=Match&Replace 88 | * RuleLibrary:Grad,Derivative,Simplify,Integrate,Evaluate... 89 | * LBAssembler:MathObject->NFunction 90 | * Numeric 91 | * NMathObject 92 | * NFunction 93 | * NFunctionLibrary 94 | * NFuncOperatorLibrary 95 | 96 | ## 2020-9-30 97 | 98 | **[工作]** 99 | 100 | * 完成Match,Rule模块。 101 | 102 | * Match和Rule是做什么的? 103 | 104 | * Match和Rule是用于符号表达式计算的基础模块,它们都是输入一个`Ptr`返回一个`bool`,表示是否匹配成功的函数。Match只会作匹配尝试,而Rule则会做匹配尝试后进行Rule应用的结果,并通过参数中的引用返回。所以Rule其实就是Match & Replace。(Match单独使用的情况应该很少,绝大多数是直接用Rule) 105 | 106 | * 如何定义Match和Rule? 107 | 108 | * 1 给定含有特殊匹配符号修饰的变量的表达式, Source Pattern和Target Pattern,直接通过MakeMatch或MakeRule定义。(通过这种方式定义的Rule或Match必须在程序初始化时就MakeMatch或MakeRule完成。如果在其他地方用MakeRule或MakeMatch来定义,要用static关键字,避免每次调用到这个函数都会重新MakeMatch或MakeRule) 109 | 110 | 通配符的含义:\_xxx,表示匹配任意MathObject;@xxx表示匹配Atom变量名称;#xxx表示匹配Atom数字,$xxx表示匹配Atom字符串。在Item或Polynomial的*最后*一项,\_xxx\_表示匹配剩下所有的项。 111 | 112 | * 2 手写`Ptr(Ptr)`或`Ptr(Ptr, Ptr&)`型函数。因为不是所有的Match和Rule都是可以用一个Source pattern到Target Pattern就能表示的,有些如不定长的向量就不能表示。这时需要手写函数。 113 | 114 | * 程序可能要定义大量的Rule,将这些Rule定义在`RuleLib`命名空间下。 115 | 116 | * Match和Rule的定义和使用,可以参考程序中示例。在现在的`main.cpp`中,有对单个Rule应用的测试。 117 | 118 | ## 2020-10-2 119 | 120 | **[工作]** 121 | 122 | * 完备的Match。现在是基于CSP的前向检验求解的,不会漏匹配情况了。 123 | 124 | * Evaluate初步,后面继续开发Evaluate可以参考。现在main.cpp中可以测试Evaluate。 125 | 126 | **[任务]** 继续完善RuleLib: 127 | 128 | * 常数值计算的Rule,包括乘法 129 | * Function和FunctionalOperator计算的Rule 130 | 131 | 132 | 133 | ## 2020-11-25 134 | 135 | **[算法]** 136 | 137 | 符号不定积分 138 | 139 | * 约定 140 | 141 | * 在符号积分、符号求导中,为了方便符合习惯,特别地,我们允许省略积分/求导后的函数的变量符号。实际上,一般我们要求外部符号和内部符号不冲突,即`D<>(t)​`表示积分后函数为`F(t)`,但对于符号积分求导而言,变量 `t` 只在最后结果代换,因此采用`D<>(x)`这种写法不会由于歧义导致错误的结果。那么我们允许省略掉圆括号中的内容,写成`D<>`,就表示积分/求导后的函数,仍然使用符号`x`。这实际上是一个危险的、容易产生歧义的,原则上内部变量和外部变量是不能混淆的,例如在可能`x`预先有个赋“值”`x=2`或者`x=a+b`,这时便会产生歧义和错误,应该禁止省略写法。而**在符号`x`未被占用、赋值的情况下,可以允许这样写**。这对于用户更方便,也符合一般的书写习惯。但我们自己必须十分清楚两种写法的区别。 142 | * 简而言之:省略写法`D<>`等价`D<>(x)`。在脚本运行的上下文中,会检查符号`x`的占用情况,如果`x`被占用,它会报错,并提示使用不冲突的局部变量名称如`D<>(x)`。 143 | * 为了支持省略写法,1. 需要修改Parse,在FOP<>缺少圆括号时,不是报错,而是自动认为是空的参数列表。 2. 在求导、积分算法中,如果参数列表是空,则自动补上和VAR名称相同的变量。之后的处理完全照旧。 144 | 145 | * 关于符号积分的算法,国内外论文肯定是比较丰富,体系完善的。简单翻了几篇中文的文章,没有很多奇妙之处。现在先提一个平凡的,但已经能解决不少问题的算法: 146 | 147 | * 基本要素: 148 | 149 | * 基本积分形式表,是符号积分算法的知识库;除了基本积分,还可以包含常见的困难积分。 150 | * 积分失败表,即常见的没有初等表达的积分形式,用于算法明智地终止返回失败。 151 | 152 | * 算法流程: 153 | 154 | * 化简 155 | 156 | * 化简被积表达式。如果化简后是多项式,则将积分相应地展开,使得每个部分被积式是因式,将常数因子拿到积分外面。对每个部分分别积分,进行下面的步骤: 157 | 158 | * 直接匹配基本积分表、积分失败表 159 | 160 | * 尝试换元积分 161 | 162 | * 设积分表达式形如`Integrate<>`,对于每个基本形式积分`u(_t)`,将`P`尝试匹配到`u(_v)*_Res_` 163 | * 对匹配到的`_v`求导`D<>`,用求导结果匹配`_Res_` 164 | * 若匹配成功,则积分成功,返回结果 165 | * 若匹配失败,则换元积分失败 166 | 167 | * 尝试分部积分 168 | 169 | 这部分比较困难,因为分部积分的情况非常多,并且对于分部积分的情况也比较难很快确定一种做法是好的,通常还要递归地算下去,那么就容易出现尝试次数爆炸的情形,需要解决。 170 | 171 | * 对于被积因式表达式`P`,列出全部划分为两个部分相乘的情况`_u*_dv`。若`P`有m个因子,则共有$2^m-2$种划分。(`_dv`为1的情况不算,`u`为1的情况不算)。 172 | * 启发方法:还没有计算`_dv`的积分,对于每个划分,使用某个标准,对分部后表达式的是否容易积分给出一个评价,按评价结果排序,优先尝试“更容易积分”的分部方法。 173 | * 对于每个划分方法做尝试:求`_dv`的积分`Integrate<>`,如果积分失败,则这个划分是失败的。如果成功,则求`_u`的导数`D<>`,再求二者乘积的积分,如果失败,则这个划分是失败的。如果成功,则积分成功,返回相应的结果。 174 | 175 | -------------------------------------------------------------------------------- /doc/dev-log-zyh.md: -------------------------------------------------------------------------------- 1 | ## 2020-7-6 2 | **[任务]** 编写语法解析方面的内容 3 | 4 | ## 2020-11-15 5 | 6 | **[工作]** 7 | * 数值求和与求积 8 | 9 | ## 2020-11-18 10 | 11 | **[工作]** 12 | * 完成化简过程中常量加减法的运算 13 | 注: 添加了新的MakeRule函数:`Rule mathS::MakeRule(const Ptr& src_pattern, const std::function(std::map>&, bool&)>& do_replace)` 14 | 它接受一个用户自定义的do replace并且此do replace有一个flag参数可以在do replace发现已经完成后但仍然让它进行do replace时拒绝继续化简并将flag设为true 15 | 16 | **[任务]** 编写高精度乘除法算法: 17 | -------------------------------------------------------------------------------- /mathS.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30011.22 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathS", "mathS\mathS.vcxproj", "{C16EF8D5-207B-473B-A109-61BF32EBFE45}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Debug|x64.ActiveCfg = Debug|x64 17 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Debug|x64.Build.0 = Debug|x64 18 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Debug|x86.ActiveCfg = Debug|Win32 19 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Debug|x86.Build.0 = Debug|Win32 20 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Release|x64.ActiveCfg = Release|x64 21 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Release|x64.Build.0 = Release|x64 22 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Release|x86.ActiveCfg = Release|Win32 23 | {C16EF8D5-207B-473B-A109-61BF32EBFE45}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A2C9E5B8-C2EF-4F2C-A1FB-5D6F0216D32B} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /mathS/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /mathS/include/ConstantEvaluate.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathSlib-dev/mathSlib/a8dabf60bed1f1ae503be987deb86c1493af7476/mathS/include/ConstantEvaluate.h -------------------------------------------------------------------------------- /mathS/include/Evaluate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /* 6 | 使用某些策略运用一系列Rule并返回一个MathObject,我们把这称为Evaluate。Evaluate的参数和返回类型与Rule相同,但作用不一样 7 | 8 | 对于每种MathObject,都有默认的Evaluate操作 9 | 10 | 11 | 如果Evaluate是Ptr(Ptr)的,实现逻辑是:Evaluate返回的表达式一定是不能再Evaluate的表达式。 12 | 这个逻辑很简单,但有可能导致问题: 13 | 例如对于一个Item,应用某些规则可能会导致它不再是Item,所以在Evaluate(Item)内部,发现Rule应用改变了结构,又要重新Evaluate, 14 | 这意味着不同的Evaluate之间的执行关系,不是顺序的,而是在栈中层层调用的。如果一个表达式计算步骤很多,有可能导致stack overflow 15 | 最大计算步骤非常有限,如果某个表达式计算需要非常多的步数,不到1秒程序就会栈溢出。 16 | 17 | 如果程序的实现逻辑像下面这样,就不会有栈溢出的问题 18 | 我们令Evaluate 是 bool(Ptr input, Ptr& result),一个Evaluate只是一步运算或几步运算的尝试,并不能保证表达式已经计算完毕 19 | 如果对象还可能需要继续计算,则返回 true. 如果已经计算完成则返回 false. 20 | Evaluate的引用参数返回涉及到input中的内容,一定是拷贝。即result和input是独立的,不用担心他们的子表达式之间有耦合。 21 | 22 | Evaluate 的常见用法: 23 | 计算obj,并直接把结果返回给obj,丢弃计算前的obj:Evaluate(obj, obj). 24 | 对于一个对象obj完成全部计算(直至不再修改):while(Evaluate(obj, obj)); 25 | 全部完成计算,并判断是否修改while(Evaluate(obj))flag = true; 26 | 27 | 28 | 对于一些结构,Evaluate要做的事 29 | Power:(a*b)^e=a^e*b^e展开,(a^e1)^e2=a^(e1*e2),常数自动计算,多项式常整数幂展开,化简 30 | Item: Vec分配率展开(a+b)*c=a*c+b*c,化简:倒数相消a/a=1,常数自动计算 31 | Polynomial:常数自动计算,合并同类项 32 | 33 | Function FunctionalOperator根据函数名称的不同,做不同的计算。未知的函数不做计算。 34 | 35 | Compare 做简单的化简处理,如果全是常数,直接算出结果(True常量或False常量) 36 | 37 | ... 38 | 39 | */ 40 | 41 | namespace mathS{ 42 | 43 | /// 44 | /// 总 Evaluate 45 | /// 46 | /// 47 | /// 48 | bool Evaluate(Ptr input, Ptr& result); 49 | 50 | 51 | // 各个类型的Evaluate 52 | bool Evaluate(Ptr, Ptr& result); 53 | bool Evaluate(Ptr input, Ptr& result); 54 | bool Evaluate(Ptr input, Ptr& result); 55 | bool Evaluate(Ptr input, Ptr& result); 56 | bool Evaluate(Ptr input, Ptr& result); 57 | bool Evaluate(Ptr input, Ptr& result); 58 | bool Evaluate(Ptr input, Ptr& result); 59 | bool Evaluate(Ptr input, Ptr& result); 60 | bool Evaluate(Ptr input, Ptr& result); 61 | bool Evaluate(Ptr, Ptr& result); 62 | bool Evaluate(Ptr input, Ptr& result); 63 | 64 | 65 | } -------------------------------------------------------------------------------- /mathS/include/ExtendedCMath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mathS { 4 | double double_less(double a, double b); 5 | double double_greater(double a, double b); 6 | double double_lesseq(double a, double b); 7 | double double_greatereq(double a, double b); 8 | } 9 | -------------------------------------------------------------------------------- /mathS/include/LBAssembler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | /* 9 | In this file, we introduce methods that use lambda expression to 10 | assemble a NMathFunction(numeric math function) with given MathObject. 11 | Also, the NMathFunction can be converted into a cpp function if you wish. 12 | */ 13 | 14 | namespace mathS 15 | { 16 | 17 | class Assembler 18 | { 19 | 20 | public: 21 | Assembler() { InitializeSTDLIB(); } 22 | // 根据表达式expr,组装一个以expr中的出现的变量为参数的函数。参数的顺序是param_str所给出的。 23 | // 如 expr = sin(u)*v, params={u, v},那么返回的函数就是f(x1,x2)=sin(x1)*x2. 24 | NMath::NFunction Assemble(Ptr expr, std::vector& params); 25 | 26 | private: 27 | 28 | // 考虑到将来可能要在一个脚本运行时组装函数,也许,不是从function_table, constant_table中来查找, 29 | // 而是从运行时的环境中查找所需要的函数、常量、变量等,会更合适,因为运行脚本时,用户可能自定义了的数值函数。 30 | // 但是由于这样的脚本执行器还没有搭建起来, 就先在Assembler里存储function_table和constant_table。 31 | 32 | // 函数表。组装时需要的标准函数直接根据函数名称从函数表里取 33 | std::map function_table; 34 | // 常量表。组装时遇到常量符号,会从常量表里取。 35 | std::map constant_table; 36 | 37 | std::map fop_table; 38 | 39 | void InitializeSTDLIB(); 40 | }; 41 | } -------------------------------------------------------------------------------- /mathS/include/MathFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | 6 | namespace mathS { 7 | 8 | // MathFunction : MathObject -> MathObject 9 | // MathFunction 是对数学对象,运用一些规则来得到结果的 10 | using MathFunction = std::function(std::vector>)>; 11 | 12 | } -------------------------------------------------------------------------------- /mathS/include/MathObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace mathS 10 | { 11 | class MathObject; 12 | class ListObject; 13 | class Atom; 14 | class Vector; 15 | class Function; 16 | class FunctionalOperator; 17 | class Locate; 18 | class Power; 19 | class Inverse; 20 | class Item; 21 | class Opposite; 22 | class Polynomial; 23 | class Map; 24 | class Compare; 25 | class List; 26 | class ErrorObject; 27 | class EmptyObject; 28 | 29 | class MathObject 30 | { 31 | public: 32 | enum Type 33 | { 34 | // The structure of math objects is something like an expression tree. 35 | // We assign different levels to each type of math objects. 36 | // The levels indicate the priority of operations, 37 | // also the implicit structures of of text form expression input. 38 | // In contrast, brackets indicate the explicit structures. 39 | 40 | // Level 1: Atom element. 41 | // NUMBER,VARIABLE,STRING are deprecated!!! Now we use ATOM. 42 | // NUMBER: Starts with a figure from '0'-'9', maybe containing a point, end with space, any operator or bracket. 43 | // NOTE: complex are not actually supported YET. But we allow number text with suffix 'i', 44 | // which represents unit complex. 45 | // 46 | // VARIABLE: Usually starts with an aphabet, end with any operator or bracket. 47 | // When starts with _, it acts as an OBJECT PLACEHOLDER, which matches any math object. 48 | // When starts with @, it acts as a NAME PLACEHOLDER, which matches any name variable. 49 | // NOTE: Its use is more than a variable. For example, it can also represent a name of a function. 50 | // 51 | // STRING: Enclosed with "". The Char \ has the same meaning in C++ string. 52 | // 53 | // ATOM: Basic element, including number, variable, string. Since all of them can be represented by std::string. 54 | // Specific type of ATOM are distinguished only when it is needed. 55 | // 56 | // VECTOR: Enclosed with {}. Inside a vector, there is a list of all elements. 57 | ATOM, VECTOR, EMPTY, NUMBER, STRING, VARIABLE, 58 | // Level 2: _FUNCTION(_PARAMETER) 59 | // : _FOPERATOR<<@VAR1,@VAR2,...|_FPARAMETER>>(_PARAMETER) 60 | FUNCTION, FUNCOPERATOR, 61 | // Level 3: _OBJECT[_LOC] 62 | LOCATE, 63 | // Level 4: _BASE^_EXPONENT 64 | POWER, 65 | // Level 5: /_COMPONENT 66 | INVERSE, 67 | // Level 6: _A*_B/_C*...*_Z 68 | ITEM, 69 | // Level 7: -_COMPONENT 70 | OPPOSITE, 71 | // Level 8: _A+_B-_C...+_Z 72 | POLYNOMIAL, 73 | // Level 9: _KEY->_VALUE 74 | MAP, 75 | // Level 10: _LEFT==_RIGHT; _LEFT<=_RIGHT; _LEFT>=_RIGHT; _LEFT<_RIGHT; _LEFT>_RIGHT ... 76 | COMPARE, 77 | // Level 11: _A;_B;_C; 78 | // Not implemented yet. 79 | // SENTENCE_LIST 80 | 81 | // Level 12: _A,_B,_C,...,_Z 82 | // LIST, 83 | // ListObject is deprecated now! 84 | 85 | // Level -1: 86 | ERROR 87 | }; 88 | static const int LEVEL_EMPTY = 1; 89 | static const int LEVEL_ATOM = 1; 90 | static const int LEVEL_VECTOR = 1; 91 | static const int LEVEL_FUNCTION = 2; 92 | static const int LEVEL_FUNCOPERATOR = 2; 93 | static const int LEVEL_LOCATE = 3; 94 | static const int LEVEL_POWER = 4; 95 | static const int LEVEL_INVERSE= 5; 96 | static const int LEVEL_ITEM = 6; 97 | static const int LEVEL_OPPOSITE = 7; 98 | static const int LEVEL_POLYNOMIAL = 8; 99 | static const int LEVEL_MAP = 9; 100 | static const int LEVEL_COMPARE = 10; 101 | static const int LEVEL_LIST = 12; 102 | static const int LEVEL_CLOSED = 99; 103 | static const int LEVEL_ERROR = -1; 104 | public: 105 | 106 | //MathObject() {}; 107 | virtual ~MathObject() {}; 108 | 109 | virtual Type GetType() const = 0; 110 | virtual std::string GetString() const = 0; 111 | virtual std::string GetLaTeXString() const = 0; 112 | virtual int Level() const = 0; 113 | virtual bool IsZero() const = 0; 114 | virtual bool IsOne() const = 0; 115 | 116 | virtual Ptr DeepCopy() const = 0; 117 | }; 118 | 119 | /* 120 | // list type math object. 121 | // Elements are separated by comma ",". 122 | class ListObject : public MathObject 123 | { 124 | public: 125 | std::vector> components; 126 | 127 | ListObject() {} 128 | ~ListObject() {} 129 | 130 | Type GetType() const { return Type::LIST; }; 131 | int Level() const { return LEVEL_LIST; }; 132 | std::string GetString() const; 133 | 134 | Ptr DeepCopy() const; 135 | 136 | void push_back(Ptr const obj) { components.push_back(obj); } 137 | }; 138 | */ 139 | std::string ListGetString(const std::vector>& lst); 140 | std::string ListGetLaTeXString(const std::vector>& lst); 141 | std::vector> ListDeepCopy(const std::vector>& lst); 142 | 143 | class Atom : public MathObject 144 | { 145 | // 2020-7-3 架构调整. 原先的Number, Variable, String被全部当做了Atom. 146 | // Atom.str 表示其内容: 147 | // 如果是一个number,那么str就是一个数字对应的字符串;如果是一个variable,就是以字母开头的字符串(或特殊修饰符);如果是string,那一定是""包括的字符串. 148 | // 这个调整的理由是:Number, Variable, String本来就是只用std::string来存储的,其Level(),GetString(),DeepCopy()等方法一模一样 149 | // 并且在一般的表达式变形中,不必对这三者作区分。只需要在化简、求值等涉及到其具体内容时,需要区分。 150 | // 因此采用Atom统一表示,语法分析器会更简单。而涉及到其内容时,再作识别Atom是数字、变量还是字符串. 151 | public: 152 | std::string str; 153 | 154 | Atom() {}; 155 | Atom(const std::string name_str) :str{ name_str } {}; 156 | ~Atom() {} 157 | 158 | Type GetType() const { return Type::ATOM; } 159 | bool IsZero() const { return AtomType()== Type::NUMBER && NumberValue() == 0.; } 160 | bool IsOne() const { return AtomType() == Type::NUMBER && NumberValue() == 1.; } 161 | Type AtomType() const; 162 | // 返回数值. 暂时只支持double. 如果以后支持了复数,则需要修改此处. 163 | double NumberValue() const; 164 | 165 | int Level() const { return LEVEL_ATOM; }; 166 | std::string GetString() const; 167 | std::string GetLaTeXString() const; 168 | Ptr DeepCopy() const; 169 | }; 170 | 171 | class Vector : public MathObject 172 | { 173 | // eg. {7,x,y} 174 | public: 175 | Vector() {} 176 | ~Vector() {} 177 | public: 178 | std::vector> components; 179 | 180 | Type GetType() const { return Type::VECTOR; }; 181 | int Level() const { return LEVEL_VECTOR; }; 182 | bool IsZero() const { return false; } 183 | bool IsOne() const { return false; } 184 | void push_back(Ptr const f); 185 | 186 | std::string GetString() const; 187 | std::string GetLaTeXString() const; 188 | Ptr DeepCopy() const; 189 | }; 190 | 191 | class Function : public MathObject 192 | { 193 | // eg. f(x), Sin(u) 194 | public: 195 | Function() {} 196 | ~Function() {} 197 | public: 198 | Ptr function ; 199 | std::vector> parameter ; 200 | 201 | Type GetType() const { return Type::FUNCTION; }; 202 | int Level() const { return LEVEL_FUNCTION; }; 203 | bool IsZero() const { return false; } 204 | bool IsOne() const { return false; } 205 | std::string GetString() const; 206 | std::string GetLaTeXString() const; 207 | Ptr DeepCopy() const; 208 | }; 209 | 210 | class FunctionalOperator : public MathObject 211 | { 212 | public: 213 | FunctionalOperator() {}; 214 | ~FunctionalOperator() { } 215 | public: 216 | Ptr function ; 217 | std::vector> variables; 218 | std::vector> fparameter; 219 | std::vector> parameter; 220 | 221 | Type GetType() const { return Type::FUNCOPERATOR; }; 222 | int Level() const { return LEVEL_FUNCTION; }; 223 | std::string GetString() const; 224 | std::string GetLaTeXString() const; 225 | Ptr DeepCopy() const; 226 | bool IsZero() const { return false; } 227 | bool IsOne() const { return false; } 228 | }; 229 | 230 | class Locate : public MathObject 231 | { 232 | // eg: arr[3], {a,b,3}[2] 233 | public: 234 | Locate() {} 235 | ~Locate() {}; 236 | public: 237 | Ptr object; 238 | std::vector> location; 239 | 240 | Type GetType() const { return Type::LOCATE; }; 241 | int Level() const { return LEVEL_LOCATE; }; 242 | std::string GetString() const; 243 | std::string GetLaTeXString() const; 244 | Ptr DeepCopy() const; 245 | bool IsZero() const { return false; } 246 | bool IsOne() const { return false; } 247 | }; 248 | class Power : public MathObject 249 | { 250 | // eg. a^5, x^y, y^p^q (this is equivalent to y^(p^q)) 251 | public: 252 | Power() {} 253 | Power(const Ptr& base, const Ptr& exponent) :base{ base }, exponent{ exponent }{}; 254 | ~Power() {} 255 | public: 256 | Ptr base; 257 | Ptr exponent; 258 | 259 | Type GetType() const { return Type::POWER; }; 260 | int Level() const { return LEVEL_POWER; }; 261 | std::string GetString() const; 262 | std::string GetLaTeXString() const; 263 | Ptr DeepCopy() const; 264 | bool IsZero() const { return false; } 265 | bool IsOne() const { return false; } 266 | }; 267 | 268 | class Inverse : public MathObject 269 | { 270 | // eg. /y /(x+y*z) 271 | public: 272 | Inverse() {} 273 | Inverse(const Ptr& c) : component(c) {} 274 | ~Inverse() {} 275 | public: 276 | Ptr component; 277 | 278 | Type GetType() const { return Type::INVERSE; }; 279 | int Level() const { return LEVEL_INVERSE; }; 280 | std::string GetString() const; 281 | std::string GetLaTeXString() const; 282 | Ptr DeepCopy() const; 283 | bool IsZero() const { return false; } 284 | bool IsOne() const { return false; } 285 | }; 286 | 287 | class Item : public MathObject 288 | { 289 | public: 290 | Item() {} 291 | ~Item() {} 292 | void push_back(Ptr const f); 293 | // eg. x1*x2 x/y 294 | public: 295 | std::vector> factors; 296 | 297 | Type GetType() const { return Type::ITEM; }; 298 | int Level() const { return LEVEL_ITEM; }; 299 | std::string GetString() const; 300 | std::string GetLaTeXString() const; 301 | Ptr DeepCopy() const; 302 | bool IsZero() const { return false; } 303 | bool IsOne() const { return false; } 304 | }; 305 | Ptr ReduceItem(Ptr itm); 306 | 307 | class Opposite : public MathObject 308 | { 309 | public: 310 | Opposite() {}; 311 | Opposite(const Ptr& component) :component{ component } {}; 312 | ~Opposite() {} 313 | // -x, -y*z, -{1,2}*u/p 314 | public: 315 | Ptr component; 316 | 317 | Type GetType() const { return Type::OPPOSITE; }; 318 | int Level() const { return LEVEL_OPPOSITE; }; 319 | std::string GetString() const; 320 | std::string GetLaTeXString() const; 321 | Ptr DeepCopy() const; 322 | bool IsZero() const { return false; } 323 | bool IsOne() const { return false; } 324 | }; 325 | class Polynomial : public MathObject 326 | { 327 | // eg. 3.2+4*y+6/(x+1) 328 | public: 329 | Polynomial() {} 330 | ~Polynomial() {} 331 | public: 332 | std::vector> items; 333 | 334 | Type GetType() const { return Type::POLYNOMIAL; }; 335 | int Level() const { return LEVEL_POLYNOMIAL; }; 336 | std::string GetString() const; 337 | std::string GetLaTeXString() const; 338 | bool IsZero() const { return false; } 339 | bool IsOne() const { return false; } 340 | 341 | Ptr DeepCopy() const; 342 | void push_back(Ptr const itm); 343 | 344 | }; 345 | // 将只有一项的多项式移出来;将一项没有的多项式化为 0 346 | Ptr ReducePolynomial(Ptr poly); 347 | 348 | class Map : public MathObject 349 | { 350 | // eg. attr -> 1 351 | public: 352 | Map() {} 353 | Map(const Ptr& a, const Ptr& b) :key{ a }, value{ b }{}; 354 | ~Map() {} 355 | public: 356 | Ptr key; 357 | Ptr value; 358 | 359 | Type GetType() const { return Type::MAP; }; 360 | int Level() const { return LEVEL_MAP; }; 361 | bool IsZero() const { return false; } 362 | bool IsOne() const { return false; } 363 | std::string GetString() const ; 364 | std::string GetLaTeXString() const; 365 | Ptr DeepCopy() const; 366 | }; 367 | 368 | class Compare : public MathObject 369 | { 370 | // eg. a==b, u& a, const std::string op, const Ptr& b) :left{ a }, op{ op }, right{ b }{}; 374 | ~Compare() {} 375 | public: 376 | std::string op; 377 | Ptr left; 378 | Ptr right; 379 | 380 | Type GetType() const { return Type::COMPARE; }; 381 | int Level() const { return LEVEL_COMPARE; }; 382 | bool IsZero() const { return false; } 383 | bool IsOne() const { return false; } 384 | std::string GetString() const ; 385 | std::string GetLaTeXString() const; 386 | Ptr DeepCopy() const; 387 | }; 388 | 389 | class ErrorObject : public MathObject 390 | { 391 | public: 392 | std::string info; 393 | 394 | ErrorObject() {} 395 | ErrorObject(const std::string info) :info{ info } {}; 396 | ~ErrorObject() {}; 397 | 398 | Type GetType() const { return Type::ERROR; }; 399 | int Level() const { return LEVEL_ERROR; }; 400 | bool IsZero() const { return false; } 401 | bool IsOne() const { return false; } 402 | std::string GetString() const { return info; }; 403 | std::string GetLaTeXString() const { return info; }; 404 | Ptr DeepCopy() const; 405 | }; 406 | 407 | class EmptyObject : public MathObject 408 | { 409 | public: 410 | EmptyObject(){} 411 | ~EmptyObject() {} 412 | 413 | public: 414 | 415 | Type GetType() const { return Type::EMPTY; }; 416 | int Level() const { return LEVEL_EMPTY; }; 417 | bool IsZero() const { return false; } 418 | bool IsOne() const { return false; } 419 | std::string GetString() const { return std::string(); }; 420 | std::string GetLaTeXString() const { return std::string(); }; 421 | Ptr DeepCopy() const; 422 | }; 423 | /* 424 | class Matrix : public MathObject 425 | { 426 | public: 427 | std::vector rowVectors; 428 | }; 429 | 430 | */ 431 | 432 | 433 | } -------------------------------------------------------------------------------- /mathS/include/MathParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | In this file, we introduce methods that parse text input of expressions 9 | and transform them into MathObject. 10 | 11 | 12 | */ 13 | namespace mathS 14 | { 15 | 16 | /// 17 | /// 从字符串解析表达式,若解析失败,返回相应的MathErrorObject 18 | /// 19 | /// 20 | /// 21 | Ptr Parse(const std::string& c); 22 | 23 | short level(const std::string& c); 24 | /// 25 | /// 从 start 位置开始解析一个对象,直到到达右括号或末尾. 若没有对象则返回 EmptyObject. 若检测到语法错误则返回ErrorObject 26 | /// 27 | /// 28 | /// 29 | /// 引用变量,解析结束时,i在被解析的对象对应token的后一位索引(即往后继续解析开始的位置) 30 | /// 31 | Ptr parseObject(const std::vector& tokens, const int start, int& i); 32 | 33 | Ptr parseAtom(const std::vector& tokens, const int start, int& i); 34 | Ptr parseFunction(const std::vector& tokens, const int start, int& i); 35 | Ptr parseLocate(const std::vector& tokens, const int start, int& i); 36 | Ptr parsePower(const std::vector& tokens, const int start, int& i); 37 | Ptr parseItem(const std::vector& tokens, const int start, int& i); 38 | Ptr parsePolynomial(const std::vector& tokens, const int start, int& i); 39 | Ptr parseMap(const std::vector& tokens, const int start, int& i); 40 | Ptr parseCompare(const std::vector& tokens, const int start, int& i); 41 | std::vector> parseList(const std::vector& tokens, const int start, int& i); 42 | 43 | } -------------------------------------------------------------------------------- /mathS/include/NAlgorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace mathS { 5 | namespace NMath { 6 | Ptr MatrixMultiply(const NParamsList&) { 7 | 8 | } 9 | 10 | Ptr GaussianDecomposition(const NParamsList&) { 11 | 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /mathS/include/NFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | /* 4 | NFunction.h 中,定义了常用的NFunction. 称作标准NFunction库. 5 | */ 6 | 7 | namespace mathS 8 | { 9 | namespace NMath 10 | { 11 | using NParamsList = std::vector>; 12 | using NFunction = std::function(const NParamsList&)>; 13 | 14 | // NFunction的Error类型. 15 | NFunction NFunctionError(const std::string info); 16 | // NFunction的Atom类型。直接返回值 v 的函数。 17 | NFunction NFunctionAtom(const NValueType v); 18 | 19 | 20 | // Declare a shape wise NMathFunction with name o f FUNCNAME 21 | 22 | #define DECLARE_NMATHUNC(FUNCNAME) Ptr FUNCNAME(const NParamsList& params) 23 | 24 | // + - * / 25 | 26 | DECLARE_NMATHUNC(Plus); 27 | DECLARE_NMATHUNC(Subtract); 28 | DECLARE_NMATHUNC(Multiply); 29 | DECLARE_NMATHUNC(Divide); 30 | DECLARE_NMATHUNC(Less); 31 | DECLARE_NMATHUNC(Greater); 32 | DECLARE_NMATHUNC(Lesseq); 33 | DECLARE_NMATHUNC(Greatereq); 34 | DECLARE_NMATHUNC(Power); 35 | 36 | DECLARE_NMATHUNC(Sin); 37 | DECLARE_NMATHUNC(Cos); 38 | DECLARE_NMATHUNC(Tan); 39 | DECLARE_NMATHUNC(ASin); 40 | DECLARE_NMATHUNC(ACos); 41 | DECLARE_NMATHUNC(ATan); 42 | DECLARE_NMATHUNC(Log); 43 | DECLARE_NMATHUNC(Exp); 44 | DECLARE_NMATHUNC(Floor); 45 | 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mathS/include/NFunctionalOperator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace mathS { 7 | 8 | namespace NMath { 9 | 10 | using NFuncParamsList = std::vector; 11 | using NFuncOperator = std::function(NFuncParamsList, NParamsList)>; 12 | 13 | Ptr Sum(NFuncParamsList f, NParamsList i); 14 | Ptr Product(NFuncParamsList f, NParamsList i); 15 | Ptr NDerivative(NFuncParamsList f, NParamsList i); 16 | } 17 | } -------------------------------------------------------------------------------- /mathS/include/NMathObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace mathS 10 | { 11 | /* 12 | The logic of NMathObject: 13 | 14 | NMathObject 15 | |=>NAtom 16 | |=>NList 17 | (The following are not implemented yet) 18 | |=>//NSparseList 19 | |=>//NMatrix 20 | |=>//NSparseMatrix 21 | 22 | NList 和 NAtom 构成广义表,通过类的继承实现。 23 | 与之相对的做法是使用 NNode,但这样的话会浪费一些空间。 24 | 25 | */ 26 | 27 | 28 | // Numeric math library 29 | namespace NMath 30 | { 31 | typedef double NValueType; 32 | 33 | class NMathObject 34 | { 35 | public: 36 | enum Type 37 | { 38 | ATOM, LIST, SAPRSE_LIST, ERROR 39 | }; 40 | public: 41 | virtual ~NMathObject() {}; 42 | 43 | virtual bool IsAtom()const = 0; 44 | virtual Type GetType() const = 0; 45 | virtual int Size()const = 0; 46 | virtual NValueType GetValue() const = 0; 47 | 48 | virtual bool IsError() const = 0; 49 | virtual std::string GetString() const = 0; 50 | virtual Ptr DeepCopy() const = 0; 51 | }; 52 | 53 | // Atom type of numeric math object. 54 | class NAtom : public NMathObject 55 | { 56 | public: 57 | NValueType value; 58 | 59 | NAtom(NValueType v) :value{ v } {}; 60 | ~NAtom() {}; 61 | 62 | Type GetType() const { return Type::ATOM; } 63 | bool IsAtom() const { return true; } 64 | bool IsError() const { return false; } 65 | int Size() const { return 1; } 66 | NValueType GetValue() const { return value; } 67 | void SetValue(NValueType v) { value = v; } 68 | 69 | std::string GetString() const; 70 | Ptr DeepCopy() const; 71 | }; 72 | 73 | // General list of numeric math object. 74 | class NList : public NMathObject 75 | { 76 | public: 77 | // 匹配 78 | /* 79 | f(_x) 80 | f(1,2) 81 | _x -> 1,2 82 | */ 83 | std::vector> components; 84 | 85 | NList() {}; 86 | NList(std::initializer_list> _init_list) : components{ _init_list }{} 87 | NList(std::initializer_list _init_list) 88 | { 89 | for (auto it : _init_list) 90 | components.push_back(New(it)); 91 | } 92 | ~NList() {} 93 | 94 | Type GetType() const { return Type::LIST; } 95 | bool IsAtom() const { return false; } 96 | bool IsError() const { return false; } 97 | int Size() const { return components.size(); }; 98 | NValueType GetValue() const { return components.empty()?0.:components[0]->GetValue(); } 99 | 100 | Ptr PartLocate(const std::vector& loc)const; 101 | std::string GetString() const; 102 | Ptr DeepCopy() const; 103 | }; 104 | 105 | // Error type object, which represents an error occurred during calculation. 106 | class NMathError : public NMathObject 107 | { 108 | public: 109 | std::string info; 110 | 111 | NMathError(const std::string info) : info{ info } {}; 112 | ~NMathError() {}; 113 | 114 | bool IsAtom()const { return false; }; 115 | bool IsError() const { return true; }; 116 | Type GetType() const { return Type::ERROR; }; 117 | int Size()const { return 0; }; 118 | NValueType GetValue() const { return NAN; } 119 | 120 | std::string GetString() const { return info; }; 121 | Ptr DeepCopy() const; 122 | }; 123 | /* 124 | class NMatrix : public NMathObject 125 | { 126 | public: 127 | std::vector components; 128 | 129 | ~NMatrix(); 130 | }; 131 | */ 132 | 133 | 134 | // Locate a part of obj and return a reference. Note that this is unsafe because it does not check the indices! 135 | Ptr& PartLocate_ref(Ptr obj, const std::vector& loc); 136 | 137 | // Locate a part of obj. Cannot modify the depth of obj, since leaf nodes - NAtom is not changable. 138 | Ptr PartLocate(Ptr obj, const std::vector& loc); 139 | 140 | // Locate a part of obj. 141 | Ptr PartLocate(Ptr obj, const int loc); 142 | 143 | Ptr Concatenate(Ptr a, Ptr b); 144 | } 145 | 146 | /* 147 | // Sparse MathObject 148 | class NSparseList :public NMathObject 149 | { 150 | 151 | }; 152 | class NSparseMatrix : public NMathObject 153 | { 154 | 155 | }; 156 | 157 | class NValuePlusOp 158 | { 159 | public: 160 | inline NValueType operator()(NValueType _Left, NValueType _Right) const 161 | { 162 | return _Left + _Right; 163 | } 164 | }; 165 | */ 166 | 167 | 168 | } 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /mathS/include/Ptr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace mathS { 5 | // 使用智能指针,防止内存泄漏 6 | template 7 | using Ptr = std::shared_ptr; 8 | 9 | #define New std::make_shared 10 | // 强制内存转换,基类与派生类之间相互转换 11 | #define Dynamic_cast std::dynamic_pointer_cast 12 | #define Static_cast std::static_pointer_cast 13 | } 14 | -------------------------------------------------------------------------------- /mathS/include/Rule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace mathS { 8 | // Rule的第一个参数是输入obj,第二个引用是返回值。Rule引用不会改变输入obj指向的内容,引用返回的涉及到obj中对应内容都是拷贝。 9 | // 如果返回false,说明匹配失败,引用参数不会改变 10 | using Rule = std::function, Ptr&)>; 11 | using Match = std::function)>; 12 | 13 | /// 14 | /// 对于给定的Pattern,生成一个匹配 15 | /// 16 | /// 17 | /// 18 | Match MakeMatch(Ptr pattern); 19 | /// 20 | /// 对于给定的source pattern, target pattern,生成一个匹配-替换规则 21 | /// 22 | /// 23 | /// 24 | /// 25 | Rule MakeRule(const Ptr& src_pattern, Ptr tar_pattern); 26 | /// 27 | /// 对于给定的source pattern, target function,生成一个匹配-替换规则 28 | /// 29 | /// 30 | /// 31 | /// 32 | Rule MakeRule(const Ptr& src_pattern, const std::function(std::map>&, bool&)>&);// 这里回调的bool参数是用来应答是否拒绝应用此规则的flag,若为true则为拒绝,将不再调用 33 | 34 | /// 35 | /// 匹配。对给定的pattern和obj的形式,并返回匹配表 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// 41 | bool DoMatch(Ptr pattern, Ptr obj, std::map>& table, std::list& table_list); 42 | 43 | /// 44 | /// 替换。对于给定的table,返回将pattern中对应地替换的结果(是拷贝,不影响pattern) 45 | /// 46 | /// 47 | /// 48 | /// 49 | Ptr DoReplace(Ptr pattern, std::map>& table); 50 | 51 | /// 52 | /// 全匹配,当两个两个表达式完全相同返回true。(为什么不比较GetString()?因为GetString()一定会遍历整个表达式,效率很低。) 53 | /// 将来为了提高Compare效率,可以对MathObject维护高度属性 54 | /// 55 | /// 56 | /// 57 | /// 58 | bool FullCompare(Ptr a, Ptr b); 59 | 60 | 61 | 62 | } -------------------------------------------------------------------------------- /mathS/include/RuleLib.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathSlib-dev/mathSlib/a8dabf60bed1f1ae503be987deb86c1493af7476/mathS/include/RuleLib.h -------------------------------------------------------------------------------- /mathS/include/lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHS_LEXER_H 2 | #define MATHS_LEXER_H 3 | 4 | #include 5 | 6 | namespace mathS { 7 | /* 8 | * TODO 词法分析器的实现 9 | * 词法分析器主要是拿来分割字符串的,将其分割为一个个的token方便之后语法的处理及表达式树构建 10 | * */ 11 | 12 | struct Token { 13 | enum TYPE { 14 | NUMORSYMB, STRING, OPERATOR, END 15 | }; 16 | Token() : type(NUMORSYMB) { } 17 | TYPE type; 18 | std::string text; 19 | }; 20 | class Lexer { 21 | public: 22 | explicit Lexer(const std::string& c) : content(c) { } 23 | void get(Token&); 24 | private: 25 | Token::TYPE checkType(char); 26 | const std::string content; 27 | int index = 0; 28 | }; 29 | } 30 | 31 | 32 | #endif //MATHS_LEXER_H 33 | -------------------------------------------------------------------------------- /mathS/include/string-switch.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHS_STRING_SWITCH_H 2 | #define MATHS_STRING_SWITCH_H 3 | 4 | #include 5 | #include 6 | 7 | namespace mathS { 8 | constexpr uint64_t strlen(const char v[]) { 9 | size_t len = 0; 10 | while (v[len++]) ; 11 | return len - 1; 12 | } 13 | constexpr uint64_t hash(const char v[]) { 14 | uint64_t t = 0; 15 | size_t len = 0; 16 | while (v[len++]) ; 17 | --len; 18 | for (size_t i = 0; i < len; i++) { 19 | t <<= 8; 20 | t |= v[i]; 21 | } 22 | return t; 23 | } 24 | } 25 | #define SWITCH(n) switch (mathS::hash(n)) 26 | #define CASE(s, n) case mathS::hash(n): if (s != n) break; 27 | 28 | #endif //MATHS_STRING_SWITCH_H 29 | -------------------------------------------------------------------------------- /mathS/mathS.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {C16EF8D5-207B-473B-A109-61BF32EBFE45} 24 | Win32Proj 25 | mathS 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)mathS\include;$(IncludePath) 76 | 77 | 78 | true 79 | $(SolutionDir)mathS\include;$(IncludePath) 80 | 81 | 82 | false 83 | 84 | 85 | false 86 | $(ProjectDir)include;$(IncludePath) 87 | 88 | 89 | 90 | 91 | 92 | Level3 93 | true 94 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Console 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | true 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | stdcpp17 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | true 124 | true 125 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | Level3 140 | true 141 | true 142 | true 143 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 144 | true 145 | 146 | 147 | Console 148 | true 149 | true 150 | true 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /mathS/mathS.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {2c013a30-09d1-4c11-9c08-915cf581adaa} 18 | 19 | 20 | {01e54150-d1c0-4ce8-b208-944fc89c4f84} 21 | 22 | 23 | {b07fe967-6cd8-433a-99bc-38f07d91d12e} 24 | 25 | 26 | {75d3c6b5-8900-46a1-8031-44f0bb5f4e23} 27 | 28 | 29 | {256ed6f5-8f2a-4904-8b77-86a0feddac30} 30 | 31 | 32 | {16d9803e-fd7a-4007-82bd-18d0f5a65749} 33 | 34 | 35 | 36 | 37 | 源文件 38 | 39 | 40 | 源文件\Utilities 41 | 42 | 43 | 源文件\Utilities 44 | 45 | 46 | 源文件\Utilities 47 | 48 | 49 | 源文件\Utilities 50 | 51 | 52 | 源文件\Numeric 53 | 54 | 55 | 源文件\Numeric 56 | 57 | 58 | 源文件\Numeric 59 | 60 | 61 | 源文件\Symbolic 62 | 63 | 64 | 源文件\Symbolic 65 | 66 | 67 | 源文件\Symbolic 68 | 69 | 70 | 源文件\Symbolic 71 | 72 | 73 | 74 | 75 | 头文件\Utilities 76 | 77 | 78 | 头文件\Utilities 79 | 80 | 81 | 头文件\Utilities 82 | 83 | 84 | 头文件\Utilities 85 | 86 | 87 | 头文件\Symbolic 88 | 89 | 90 | 头文件\Numeric 91 | 92 | 93 | 头文件\Numeric 94 | 95 | 96 | 头文件\Numeric 97 | 98 | 99 | 头文件\Utilities 100 | 101 | 102 | 头文件\Utilities 103 | 104 | 105 | 头文件\Symbolic 106 | 107 | 108 | 头文件\Symbolic 109 | 110 | 111 | 头文件\Symbolic 112 | 113 | 114 | 头文件\Numeric 115 | 116 | 117 | 头文件\Symbolic 118 | 119 | 120 | 头文件\Symbolic 121 | 122 | 123 | -------------------------------------------------------------------------------- /mathS/src/Evaluate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace mathS; 6 | 7 | bool mathS::Evaluate(Ptr input, Ptr& result) { 8 | switch (input->GetType()) 9 | { 10 | case MathObject::ATOM: 11 | return false; 12 | case MathObject::VECTOR: 13 | return Evaluate(Dynamic_cast(input), result); 14 | case MathObject::POWER: 15 | return Evaluate(Dynamic_cast(input), result); 16 | case MathObject::INVERSE: 17 | return Evaluate(Dynamic_cast(input), result); 18 | case MathObject::ITEM: 19 | return Evaluate(Dynamic_cast(input), result); 20 | case MathObject::OPPOSITE: 21 | return Evaluate(Dynamic_cast(input), result); 22 | case MathObject::POLYNOMIAL: 23 | return Evaluate(Dynamic_cast(input), result); 24 | 25 | default: 26 | return false; 27 | break; 28 | } 29 | } 30 | 31 | bool mathS::Evaluate(Ptr input, Ptr& result) 32 | { 33 | Ptr s = New(); 34 | // 先计算子表达式 35 | for (auto it : input->factors) { 36 | bool flag = false; 37 | auto s1 = it; 38 | while (Evaluate(s1, s1)) flag = true; 39 | s->push_back(flag ? s1 : it->DeepCopy()); 40 | } 41 | result = Dynamic_cast(s); 42 | // 化简优先 43 | // 同底数幂合并(包括约分) 44 | while (RuleLib::Power_reduction_1(result, result)); 45 | while (RuleLib::Power_reduction_2(result, result)); 46 | while (RuleLib::Power_reduction_3(result, result)); 47 | while (RuleLib::Power_reduction_4(result, result)); 48 | while (RuleLib::Power_reduction_5(result, result)); 49 | while (RuleLib::Power_reduction_6(result, result)); 50 | // 去掉多余的1 51 | while (RuleLib::Drop_ones(result, result)); 52 | // 常数项计算 TODO 53 | // 常数分子分母约分 TODO 54 | // 再应用 Item 级的 Rule,一旦规则成功应用就返回 55 | if (RuleLib::ExpandDistributive(result, result)) 56 | return true; 57 | if (RuleLib::VectorMultiply(result, result)) 58 | return true; 59 | return false; 60 | } 61 | 62 | bool mathS::Evaluate(Ptr input, Ptr& result) { 63 | // 先拷贝一份,以便对Item的factors递归地做Evaluate 64 | Ptr s1 = Dynamic_cast(input->DeepCopy()); 65 | // 计算子表达式 66 | for (int i = 0; i < s1->components.size(); i++) { 67 | while (Evaluate(s1->components[i], s1->components[i])); 68 | } 69 | result = s1; 70 | return false; 71 | } 72 | 73 | bool mathS::Evaluate(Ptr input, Ptr& result) { 74 | auto base = input->base->DeepCopy(); 75 | while (Evaluate(base, base)); 76 | auto exponet = input->exponent->DeepCopy(); 77 | while (Evaluate(exponet, exponet)); 78 | 79 | result = New(base, exponet); 80 | // 常数计算 TODO 81 | // 多项式幂展开 TODO 82 | // 展开项因子 83 | if (RuleLib::ExpandItemPower(result, result)) return true; 84 | // 指数简化 85 | if (RuleLib::Power_simplify(result, result)) return true; 86 | // 向量幂次展开 87 | if (RuleLib::VectorPower(result, result)) return true; 88 | return false; 89 | } 90 | 91 | bool mathS::Evaluate(Ptr input, Ptr& result) { 92 | auto c = input->component->DeepCopy(); 93 | // 计算子表达式 94 | while (Evaluate(c, c)); 95 | result = New(c); 96 | if (RuleLib::Double_inverse_1(result, result)) return true; 97 | if (RuleLib::Double_inverse_2(result, result)) return true; 98 | return false; 99 | } 100 | 101 | bool mathS::Evaluate(Ptr input, Ptr& result) { 102 | auto c = input->component->DeepCopy(); 103 | // 计算子表达式 104 | while (Evaluate(c, c)); 105 | result = New(c); 106 | // 消除常量负号 107 | if (RuleLib::ConstantNegative(result, result)) return true; 108 | // 消除成对 109 | if (RuleLib::Double_negative(result, result)) return true; 110 | return false; 111 | } 112 | 113 | bool mathS::Evaluate(Ptr input, Ptr& result) { 114 | Ptr s = New(); 115 | // 先计算子表达式 116 | for (auto it : input->items) { 117 | bool flag = false; 118 | auto s1 = it; 119 | while (Evaluate(s1, s1)) flag = true; 120 | s->push_back(flag ? s1 : it->DeepCopy()); 121 | } 122 | // 基本的消项、合并同类项处理 123 | result = ReducePolynomial(s); 124 | while (RuleLib::ConstantPlus(result, result)); 125 | while (RuleLib::Reduce_opposite_terms(result, result)); 126 | while (RuleLib::Combining_similar_terms(result, result)); 127 | while (RuleLib::Drop_zeros(result, result)); 128 | return false; 129 | } -------------------------------------------------------------------------------- /mathS/src/ExtendedCMath.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | double mathS::double_less(double a, double b) { 5 | return a < b ? 1. : 0.; 6 | } 7 | 8 | double mathS::double_greater(double a, double b) { 9 | return a > b ? 1. : 0.; 10 | } 11 | double mathS::double_lesseq(double a, double b) { 12 | return a <= b ? 1. : 0.; 13 | } 14 | double mathS::double_greatereq(double a, double b) { 15 | return a >= b ? 1. : 0.; 16 | } -------------------------------------------------------------------------------- /mathS/src/LBAssembler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace mathS; 4 | using namespace mathS::NMath; 5 | 6 | void mathS::Assembler::InitializeSTDLIB() 7 | { 8 | function_table["Sin"] = Sin; 9 | function_table["Cos"] = Cos; 10 | function_table["Log"] = Log; 11 | function_table["Tan"] = Tan; 12 | function_table["Exp"] = Exp; 13 | function_table["ASin"] = ASin; 14 | function_table["ACos"] = ACos; 15 | function_table["ATan"] = ATan; 16 | function_table["Floor"] = Floor; 17 | 18 | constant_table["PI"] = NFunctionAtom(3.141592653589793); 19 | constant_table["E"] = NFunctionAtom(2.7182818284590452); 20 | 21 | fop_table["Sum"] = Sum; 22 | fop_table["Product"] = Product; 23 | // fop_table["NDerivative"] = NDerivative; 24 | } 25 | 26 | NMath::NFunction mathS::Assembler::Assemble(Ptr expr, std::vector& paramsstr) 27 | { 28 | // TODO 29 | 30 | switch (expr->GetType()){ 31 | case MathObject::ATOM:{ 32 | Ptr atomexpr = Dynamic_cast(expr); 33 | switch (atomexpr->AtomType()) 34 | { 35 | case MathObject::NUMBER: // Number 直接返回值 36 | return NFunctionAtom(atomexpr->NumberValue()); 37 | break; 38 | case MathObject::VARIABLE:{ // Variable 对应参数列表 39 | int i = 0; 40 | auto it_c = constant_table.find(atomexpr->str); 41 | if (it_c != constant_table.end()) 42 | return it_c->second; 43 | for (; i < paramsstr.size(); i++) 44 | if (paramsstr[i] == atomexpr->str) break; 45 | if (i >= paramsstr.size()) 46 | return NMath::NFunctionError("Assemble: Variable " + atomexpr->str + " is not specified as a parameter in its context"); 47 | return [i](const NParamsList& params) { 48 | if (i >= params.size()) 49 | return Dynamic_cast(New("NFunction: Missing parameter.")); 50 | return params[i]; 51 | }; 52 | } 53 | break; 54 | case MathObject::STRING: // String 不支持 55 | return NMath::NFunctionError("Assemble: Cannot convert String type object to NMathObject."); 56 | break; 57 | default: 58 | return NMath::NFunctionError("MathObject Error. "); 59 | break; 60 | } 61 | break; 62 | } 63 | 64 | case MathObject::FUNCTION: { // 函数组装 65 | Ptr funcexpr = Dynamic_cast(expr); 66 | auto it_ffunc = function_table.find(funcexpr->function->GetString()); 67 | if (it_ffunc == function_table.end()) 68 | return NFunctionError("Assemble: No such function as " + funcexpr->function->GetString()); 69 | 70 | NFunction ffunc = it_ffunc->second; 71 | std::vector fpara; // funcexpr->parameter 对于变量的函数 72 | for (auto& it : funcexpr->parameter) 73 | fpara.push_back(Assemble(it, paramsstr)); 74 | 75 | return [ffunc, fpara](const NParamsList& params) { 76 | NParamsList args; 77 | args.reserve(fpara.size()); 78 | for (auto& it : fpara) args.push_back(it(params)); 79 | return ffunc(args); 80 | }; 81 | 82 | break; 83 | } 84 | case MathObject::FUNCOPERATOR: { 85 | Ptr fopexpr = Dynamic_cast(expr); 86 | auto itfop = fop_table.find(fopexpr->function->GetString()); 87 | if (itfop == fop_table.end()) 88 | return NFunctionError("Assemble: No such functional operator as " + fopexpr->function->GetString()); 89 | // 内部变量与外部变量名称冲突检查 90 | // TODO 91 | // 92 | NFuncOperator nfop = itfop->second; 93 | 94 | std::vector paramsstr2; 95 | paramsstr2.reserve(fopexpr->variables.size() + paramsstr.size()); 96 | for (auto it : fopexpr->variables) 97 | paramsstr2.push_back(it->GetString()); 98 | paramsstr2.insert(paramsstr2.end(), paramsstr.begin(), paramsstr.end()); // params2 是 variable & params 99 | 100 | std::vector ffparas; // fparameter对于变量和内部变量的函数 101 | ffparas.reserve(fopexpr->fparameter.size()); 102 | for (auto& it : fopexpr->fparameter) 103 | ffparas.push_back(Assemble(it, paramsstr2)); 104 | 105 | std::vector fparas; // parameter对于变量的函数 106 | fparas.reserve(fopexpr->parameter.size()); 107 | for (auto& it : fopexpr->parameter) 108 | fparas.push_back(Assemble(it, paramsstr)); 109 | 110 | return [nfop, ffparas, fparas](const NParamsList& params) { 111 | // ffparas 是对 外部变量parameters和内部variables的函数 112 | // fs 是 给定了parameter时, ffparas对variables的函数 113 | NFuncParamsList fs; 114 | fs.reserve(ffparas.size()); 115 | for(auto& it:ffparas) 116 | fs.push_back([it, params](const NParamsList& vars){ 117 | // 将 params 和 vars 合并成ffparas的参数 118 | NParamsList paramsvars; 119 | paramsvars.reserve(params.size() + vars.size()); 120 | paramsvars.insert(paramsvars.end(), vars.begin(), vars.end()); 121 | paramsvars.insert(paramsvars.begin(), params.begin(), params.end()); 122 | return it(paramsvars); 123 | }); 124 | NParamsList args; 125 | args.reserve(fparas.size()); 126 | for (auto& it : fparas) args.push_back(it(params)); 127 | return nfop(fs, args); // 调用 fop 128 | }; 129 | break; 130 | } 131 | case MathObject::VECTOR: { 132 | Ptr vecexpr = Dynamic_cast(expr); 133 | std::vector elemfuncs; 134 | for (auto& it : vecexpr->components) { 135 | elemfuncs.push_back(Assemble(it, paramsstr)); 136 | } 137 | return [elemfuncs](const NParamsList& params) { 138 | Ptr ret = New(); 139 | for (auto& it : elemfuncs) { 140 | ret->components.push_back(it(params)); 141 | } 142 | return Dynamic_cast(ret); 143 | }; 144 | break; 145 | } 146 | case MathObject::POWER: { 147 | Ptr powexpr = Dynamic_cast(expr); 148 | NFunction fbase = Assemble(powexpr->base, paramsstr); 149 | NFunction fexp = Assemble(powexpr->exponent, paramsstr); 150 | return [fbase, fexp](const NParamsList& params) { 151 | return NMath::Power({ fbase(params), fexp(params) }); 152 | }; 153 | break; 154 | } 155 | case MathObject::INVERSE: { 156 | Ptr invexpr = Dynamic_cast(expr); 157 | NFunction t = Assemble(invexpr->component, paramsstr); 158 | return [t](const NParamsList& params) { 159 | return Divide({ New(1.), t(params) }); 160 | }; 161 | break; 162 | } 163 | case MathObject::ITEM: { 164 | Ptr itmexpr = Dynamic_cast(expr); 165 | std::vector fctfuncs; 166 | for (auto& it : itmexpr->factors) { 167 | fctfuncs.push_back(Assemble(it, paramsstr)); 168 | } 169 | return [fctfuncs](const NParamsList& params) { 170 | Ptr ret = fctfuncs[0](params); 171 | for (int i = 1; i < fctfuncs.size(); i++) { 172 | ret = Multiply({ ret, fctfuncs[i](params) }); 173 | } 174 | return ret; 175 | }; 176 | break; 177 | } 178 | case MathObject::OPPOSITE:{ 179 | Ptr oppoexpr = Dynamic_cast(expr); 180 | NFunction t = Assemble(oppoexpr->component, paramsstr); 181 | return [t](const NParamsList& params) { 182 | return Subtract({ New(0.), t(params) }); 183 | }; 184 | break; 185 | } 186 | case MathObject::POLYNOMIAL: { 187 | Ptr polyexpr = Dynamic_cast(expr); 188 | std::vector itmfuncs; 189 | for (auto& it : polyexpr->items) { 190 | itmfuncs.push_back(Assemble(it, paramsstr)); 191 | } 192 | return [itmfuncs](const NParamsList& params) { 193 | Ptr ret = itmfuncs[0](params); 194 | for (int i = 1; i < itmfuncs.size(); i++) { 195 | ret = Plus({ ret, itmfuncs[i](params) }); 196 | } 197 | return ret; 198 | }; 199 | break; 200 | } 201 | case MathObject::COMPARE: { 202 | Ptr cmpexpr = Dynamic_cast(expr); 203 | NFunction fleft = Assemble(cmpexpr->left, paramsstr); 204 | NFunction fright = Assemble(cmpexpr->right, paramsstr); 205 | if (cmpexpr->op == "<") { 206 | return [fleft, fright](const NParamsList& params) { 207 | return NMath::Less({ fleft(params), fright(params) }); 208 | }; 209 | } 210 | else if(cmpexpr->op == ">") { 211 | return [fleft, fright](const NParamsList& params) { 212 | return NMath::Greater({ fleft(params), fright(params) }); 213 | }; 214 | } 215 | else if (cmpexpr->op == "<=") { 216 | return [fleft, fright](const NParamsList& params) { 217 | return NMath::Lesseq({ fleft(params), fright(params) }); 218 | }; 219 | } 220 | else if (cmpexpr->op == ">=") { 221 | return [fleft, fright](const NParamsList& params) { 222 | return NMath::Greatereq({ fleft(params), fright(params) }); 223 | }; 224 | } 225 | else { 226 | return NFunctionError("Assemble: Unknown compare operator"); 227 | } 228 | break; 229 | } 230 | default: 231 | return NFunctionError("Assemble: Not supported yet"); 232 | break; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /mathS/src/MathObject.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace mathS; 4 | 5 | void mathS::Vector::push_back(Ptr const f) 6 | { 7 | components.push_back(f); 8 | } 9 | 10 | std::string mathS::Vector::GetString() const 11 | { 12 | return "{" + ListGetString(components) + "}"; 13 | } 14 | 15 | std::string mathS::Vector::GetLaTeXString() const 16 | { 17 | return "\\left\\{" + ListGetLaTeXString(components) + "\\right\\}"; 18 | } 19 | 20 | Ptr mathS::Vector::DeepCopy() const 21 | { 22 | Ptr ret = New(); 23 | ret->components = ListDeepCopy(components); 24 | return ret; 25 | } 26 | 27 | 28 | std::string mathS::Function::GetString() const 29 | { 30 | if (function->Level() <= LEVEL_FUNCTION) 31 | return function->GetString() + "(" + ListGetString(parameter) + ")"; 32 | else 33 | return "(" + function->GetString() + ")" + "(" + ListGetString(parameter) + ")"; 34 | } 35 | 36 | std::string mathS::Function::GetLaTeXString() const 37 | { 38 | static std::unordered_map str2LaTeXstr = { 39 | {"Exp", "\\exp"}, {"Sin", "\\sin"}, {"Cos", "\\cos"}, {"Tan", "\\tan"}, 40 | {"Log", "\\log"}, {"Ln", "\\ln"}, {"Lg", "\\lg"}, {"Cot", "\\cot"}, {"Csc", "\\csc"}, 41 | {"Sec", "\\sec"}, {"ASin", "\\arcsin"}, {"ACos", "\\arccos"}, {"ATan", "\\arctan"}, 42 | {"Sgn", "\\sgn"}, {"Det", "\\det"}, {"Sqrt", "\\sqrt"} 43 | }; 44 | std::string funName = function->GetLaTeXString(); 45 | if (function->Level() <= LEVEL_FUNCTION) { 46 | if (str2LaTeXstr.find(funName) != str2LaTeXstr.end()) { 47 | funName = str2LaTeXstr[funName]; 48 | if(funName=="\\sqrt" || (parameter.size()==1 && parameter[0]->Level() <= MathObject::LEVEL_POWER)) 49 | return funName + "{" + ListGetLaTeXString(parameter) + "}"; 50 | else 51 | return funName + "{\\left(" + ListGetLaTeXString(parameter) + "\\right)}"; 52 | } 53 | else 54 | return funName + "\\left(" + ListGetLaTeXString(parameter) + "\\right)"; 55 | } 56 | else 57 | return "\\left(" + funName + "\\right)" + "\\left(" + ListGetLaTeXString(parameter) + "\\right)"; 58 | } 59 | 60 | mathS::Ptr mathS::Function::DeepCopy() const 61 | { 62 | Ptr ret = New(); 63 | ret->function = function->DeepCopy(); 64 | ret->parameter = ListDeepCopy(parameter); 65 | return ret; 66 | } 67 | 68 | std::string mathS::Locate::GetString() const 69 | { 70 | if (object->Level() <= LEVEL_LOCATE) 71 | return object->GetString() + "[" + ListGetString(location) + "]"; 72 | else 73 | return "(" + object->GetString() + ")" + "[" + ListGetString(location) + "]"; 74 | } 75 | 76 | std::string mathS::Locate::GetLaTeXString() const 77 | { 78 | if (object->Level() <= LEVEL_LOCATE) 79 | return object->GetLaTeXString() + "\\left[" + ListGetLaTeXString(location) + "\\right]"; 80 | else 81 | return "\\left(" + object->GetLaTeXString() + "\\right)" + "\\left[" + ListGetLaTeXString(location) + "\\right]"; 82 | } 83 | 84 | mathS::Ptr mathS::Locate::DeepCopy() const 85 | { 86 | Ptr ret = New(); 87 | ret->object = object->DeepCopy(); 88 | ret->location = ListDeepCopy(location); 89 | return ret; 90 | } 91 | 92 | std::string mathS::Power::GetString() const 93 | { 94 | return 95 | (base->Level() < LEVEL_POWER ? base->GetString() : "(" + base->GetString() + ")") + "^" + 96 | (exponent->Level() <= LEVEL_POWER ? exponent->GetString() : "(" + exponent->GetString() + ")"); 97 | } 98 | 99 | std::string mathS::Power::GetLaTeXString() const 100 | { 101 | return 102 | (base->Level() < LEVEL_FUNCTION ? base->GetLaTeXString() : "\\left(" + base->GetLaTeXString() + "\\right)") + "^" + 103 | ("{" + exponent->GetLaTeXString() + "}"); 104 | } 105 | 106 | mathS::Ptr mathS::Power::DeepCopy() const 107 | { 108 | Ptr ret = New(); 109 | ret->base = base->DeepCopy(); 110 | ret->exponent = exponent->DeepCopy(); 111 | return ret; 112 | } 113 | 114 | std::string mathS::Inverse::GetString() const 115 | { 116 | if (component->Level() <= LEVEL_INVERSE) 117 | return "/" + component->GetString(); 118 | else 119 | return "/(" + component->GetString() + ")"; 120 | } 121 | 122 | std::string mathS::Inverse::GetLaTeXString() const 123 | { 124 | return component->GetLaTeXString(); 125 | } 126 | 127 | mathS::Ptr mathS::Inverse::DeepCopy() const 128 | { 129 | Ptr ret = New(); 130 | ret->component = component->DeepCopy(); 131 | return ret; 132 | } 133 | 134 | void mathS::Item::push_back(Ptr const f) 135 | { 136 | if (f->GetType() == Type::ITEM) { 137 | auto itm = Dynamic_cast(f); 138 | for (auto& it : itm->factors) { 139 | factors.push_back(it); 140 | } 141 | } 142 | else { 143 | factors.push_back(f); 144 | } 145 | } 146 | 147 | std::string mathS::Item::GetString() const 148 | { 149 | std::string ret; 150 | if (factors[0]->Level() < LEVEL_ITEM){ 151 | if (factors[0]->GetType() == Type::INVERSE) 152 | ret += "1"; 153 | ret += factors[0]->GetString(); 154 | } 155 | else{ 156 | ret += "(" + factors[0]->GetString() + ")"; 157 | } 158 | 159 | for (int i = 1; i < factors.size(); i++){ 160 | if (factors[i]->Level() < LEVEL_ITEM){ 161 | if (factors[i]->GetType() != Type::INVERSE) 162 | ret += "*"; 163 | ret += factors[i]->GetString(); 164 | } 165 | else{ 166 | ret += "*(" + factors[i]->GetString() + ")"; 167 | } 168 | } 169 | return ret; 170 | } 171 | 172 | std::string mathS::Item::GetLaTeXString() const 173 | { 174 | std::string ret; 175 | std::string temp = ""; 176 | int invflag = 0, braceflag = 0; 177 | if (factors[0]->Level() < LEVEL_ITEM) { 178 | if (factors[0]->GetType() == Type::INVERSE) { 179 | temp = "\\frac{1}{" + factors[0]->GetLaTeXString() + "}"; 180 | invflag = 1; 181 | } 182 | else 183 | temp = factors[0]->GetLaTeXString(); 184 | } 185 | else { 186 | temp = "\\left(" + factors[0]->GetLaTeXString() + "\\right)"; 187 | braceflag = 1; 188 | } 189 | for (int i = 1; i < factors.size(); i++) { 190 | if (factors[i]->GetType() == Type::INVERSE) { 191 | temp = "\\frac{" + temp + "}{" + factors[i]->GetLaTeXString() + "}"; 192 | invflag = 1; 193 | } 194 | else { 195 | if (!invflag) { 196 | if (factors[i]->Level() >= LEVEL_ITEM) { 197 | temp += "\\left(" + factors[i]->GetLaTeXString() + "\\right)"; 198 | braceflag = 1; 199 | } 200 | else { 201 | if (braceflag) 202 | temp += factors[i]->GetLaTeXString(); 203 | else { 204 | if (factors[i]->GetType()==Type::ATOM && Dynamic_cast(factors[i])->AtomType()==Type::NUMBER) 205 | temp += "\\times " + factors[i]->GetLaTeXString(); 206 | else 207 | temp += "\\, " + factors[i]->GetLaTeXString(); 208 | } 209 | braceflag = 0; 210 | } 211 | } 212 | else { 213 | ret += temp + "\\times "; 214 | temp = ""; 215 | invflag = 0; 216 | if (factors[i]->Level() < LEVEL_ITEM) { 217 | temp += factors[i]->GetLaTeXString(); 218 | braceflag = 0; 219 | } 220 | else { 221 | temp += "\\left(" + factors[i]->GetLaTeXString() + "\\right)"; 222 | braceflag = 1; 223 | } 224 | } 225 | } 226 | } 227 | ret += temp; 228 | return ret; 229 | } 230 | 231 | mathS::Ptr mathS::Item::DeepCopy() const 232 | { 233 | Ptr ret = New(); 234 | ret->factors.reserve(factors.size()); 235 | for (auto it : factors) 236 | ret->factors.push_back(it->DeepCopy()); 237 | return ret; 238 | } 239 | 240 | std::string mathS::Opposite::GetString() const 241 | { 242 | if (component->Level() < LEVEL_OPPOSITE) 243 | return "-" + component->GetString(); 244 | else 245 | return "-(" + component->GetString() + ")"; 246 | } 247 | 248 | std::string mathS::Opposite::GetLaTeXString() const 249 | { 250 | if (component->Level() < LEVEL_OPPOSITE) 251 | return "-" + component->GetLaTeXString(); 252 | else 253 | return "-\\left(" + component->GetLaTeXString() + "\\right)"; 254 | } 255 | 256 | mathS::Ptr mathS::Opposite::DeepCopy() const 257 | { 258 | Ptr ret = New(); 259 | ret->component = component->DeepCopy(); 260 | return ret; 261 | } 262 | 263 | std::string mathS::Polynomial::GetString() const 264 | { 265 | std::string ret; 266 | 267 | for (int i = 0; i < items.size(); i++) { 268 | if (items[i]->Level() < LEVEL_POLYNOMIAL) { 269 | auto t_type = items[i]->GetType(); 270 | if (t_type != Type::OPPOSITE && i != 0 && 271 | !(t_type == Type::ATOM 272 | && Dynamic_cast(items[i])->AtomType() == Type::NUMBER 273 | && Dynamic_cast(items[i])->NumberValue() < 0.) 274 | ) 275 | ret += "+"; 276 | ret += items[i]->GetString(); 277 | } 278 | else { 279 | ret += "+(" + items[i]->GetString() + ")"; 280 | } 281 | } 282 | return ret; 283 | } 284 | 285 | std::string mathS::Polynomial::GetLaTeXString() const 286 | { 287 | std::string ret; 288 | 289 | for (int i = 0; i < items.size(); i++) 290 | { 291 | if (items[i]->Level() < LEVEL_POLYNOMIAL) 292 | { 293 | if (items[i]->GetType() != Type::OPPOSITE && i != 0) 294 | ret += "+"; 295 | ret += items[i]->GetLaTeXString(); 296 | } 297 | else 298 | { 299 | ret += "+\\left(" + items[i]->GetLaTeXString() + "\\right)"; 300 | } 301 | } 302 | return ret; 303 | } 304 | 305 | mathS::Ptr mathS::Polynomial::DeepCopy() const 306 | { 307 | Ptr ret = New(); 308 | ret->items.reserve(items.size()); 309 | for (auto it : items) 310 | ret->items.push_back(it->DeepCopy()); 311 | return ret; 312 | } 313 | 314 | Ptr mathS::ReduceItem(Ptr itm) 315 | { 316 | if (itm->factors.size() > 1) 317 | return itm; 318 | if (itm->factors.size() == 0) 319 | return New("1"); 320 | if (itm->factors.size() == 1) 321 | return itm->factors[0]; 322 | } 323 | 324 | Ptr mathS::ReducePolynomial(Ptr poly) 325 | { 326 | if (poly->items.size() > 1) 327 | return poly; 328 | if (poly->items.size() == 0) 329 | return New("0"); 330 | if (poly->items.size() == 1) 331 | return poly->items[0]; 332 | } 333 | 334 | void mathS::Polynomial::push_back(Ptr const f) 335 | { 336 | if (f->GetType() == Type::POLYNOMIAL) { 337 | auto poly = Dynamic_cast(f); 338 | for (auto& it : poly->items) { 339 | items.push_back(it); 340 | } 341 | } 342 | else { 343 | items.push_back(f); 344 | } 345 | } 346 | 347 | std::string mathS::Map::GetString() const 348 | { 349 | return 350 | (key->Level() < LEVEL_MAP ? key->GetString() : "(" + key->GetString() + ")") + "->" + 351 | (value->Level() < LEVEL_MAP ? value->GetString() : "(" + value->GetString() + ")"); 352 | } 353 | 354 | std::string mathS::Map::GetLaTeXString() const 355 | { 356 | return 357 | (key->Level() < LEVEL_MAP ? key->GetLaTeXString() : "\\left(" + key->GetLaTeXString() + "\\right)") + "\\rightarrow " + 358 | (value->Level() < LEVEL_MAP ? value->GetLaTeXString() : "\\left(" + value->GetLaTeXString() + "\\right)"); 359 | } 360 | 361 | mathS::Ptr mathS::Map::DeepCopy() const 362 | { 363 | Ptr ret = New(); 364 | ret->key = key->DeepCopy(); 365 | ret->value = value->DeepCopy(); 366 | return ret; 367 | } 368 | 369 | std::string mathS::Compare::GetString() const 370 | { 371 | return 372 | (left->Level() < LEVEL_COMPARE ? left->GetString() : "(" + left->GetString() + ")") + op + 373 | (right->Level() < LEVEL_COMPARE ? right->GetString() : "(" + right->GetString() + ")"); 374 | } 375 | 376 | std::string mathS::Compare::GetLaTeXString() const 377 | { 378 | std::string opLaTeX = op; 379 | if (op == ">=") 380 | opLaTeX = "\\ge "; 381 | if (op == "<=") 382 | opLaTeX = "\\le "; 383 | return 384 | (left->Level() < LEVEL_COMPARE ? left->GetLaTeXString() : "\\left(" + left->GetLaTeXString() + "\\right)") + opLaTeX + 385 | (right->Level() < LEVEL_COMPARE ? right->GetLaTeXString() : "\\left(" + right->GetLaTeXString() + "\\right)"); 386 | } 387 | 388 | mathS::Ptr mathS::Compare::DeepCopy() const 389 | { 390 | Ptr ret = New(); 391 | ret->op = op; 392 | ret->left = left->DeepCopy(); 393 | ret->right = right->DeepCopy(); 394 | return ret; 395 | } 396 | 397 | 398 | mathS::MathObject::Type mathS::Atom::AtomType() const 399 | { 400 | if (str[0] == '-' ||('0' <= str[0] && str[0] <= '9')) 401 | return Type::NUMBER; 402 | else if (('a' <= str[0] && str[0] <= 'z') || ('A' <= str[0] && str[0] <= 'Z') || str[0] == '_' || str[0] == '$') 403 | return Type::VARIABLE; 404 | else if ('\"' == str[0] && '\"' == str[str.length() - 1]) 405 | return Type::STRING; 406 | else 407 | return Type::ERROR; 408 | } 409 | 410 | double mathS::Atom::NumberValue() const 411 | { 412 | return std::stod(str); 413 | } 414 | 415 | std::string mathS::Atom::GetString() const 416 | { 417 | return str; 418 | } 419 | 420 | std::string mathS::Atom::GetLaTeXString() const 421 | { 422 | std::string LaTeXstr; 423 | if (str == "Pi") 424 | return "{\\pi}"; 425 | if (str == "E") 426 | return "\\mathrm{e}"; 427 | for (auto c : str) { 428 | if (c == '_' || c == '$' || c == '#' || c == '&') 429 | LaTeXstr += "\\"; 430 | if (c == '~') 431 | LaTeXstr += "\\~{}"; 432 | LaTeXstr += c; 433 | } 434 | return LaTeXstr; 435 | } 436 | 437 | mathS::Ptr mathS::Atom::DeepCopy() const 438 | { 439 | return New(str); 440 | } 441 | 442 | mathS::Ptr mathS::ErrorObject::DeepCopy() const 443 | { 444 | return New(info); 445 | } 446 | 447 | mathS::Ptr mathS::EmptyObject::DeepCopy() const 448 | { 449 | return New(); 450 | } 451 | 452 | std::string mathS::FunctionalOperator::GetString() const 453 | { 454 | std::string ret; 455 | if (function->Level() <= LEVEL_FUNCOPERATOR) 456 | ret = function->GetString() + "<<"; 457 | else 458 | ret = "(" + function->GetString() + ")<<"; 459 | if(!variables.empty()) 460 | ret += variables[0]->GetString(); 461 | for (int i = 1; i < variables.size(); i++) 462 | ret += ","+variables[i]->GetString(); 463 | ret += "|" + ListGetString(fparameter) + ">>(" + ListGetString(parameter) + ")"; 464 | return ret; 465 | } 466 | 467 | std::string mathS::FunctionalOperator::GetLaTeXString() const 468 | { 469 | std::string ret; 470 | if (function->GetString() == "Sum"){ 471 | for (int i = 0; i < variables.size(); i++) { 472 | ret += "\\sum_{" + variables[i]->GetLaTeXString() + "}" + 473 | "^{" + parameter[i]->GetLaTeXString() + "}"; 474 | } 475 | if (fparameter.size() == 1) 476 | if (fparameter[0]->Level() <= MathObject::LEVEL_POWER) 477 | ret += fparameter[0]->GetLaTeXString(); 478 | else 479 | ret += "\\left(" + fparameter[0]->GetLaTeXString() + "\\right)"; 480 | else 481 | ret += "\\left\\{" + ListGetLaTeXString(fparameter) + "\\right\\}"; 482 | return ret; 483 | } else if (function->GetString() == "Product"){ 484 | for (int i = 0; i < variables.size(); i++) { 485 | ret += "\\prod_{" + variables[i]->GetLaTeXString() + "}" + 486 | "^{" + parameter[i]->GetLaTeXString() + "}"; 487 | } 488 | if (fparameter.size() == 1) 489 | if (fparameter[0]->Level() <= MathObject::LEVEL_POWER) 490 | ret += fparameter[0]->GetLaTeXString(); 491 | else 492 | ret += "\\left(" + fparameter[0]->GetLaTeXString() + "\\right)"; 493 | else 494 | ret += "\\left\\{" + ListGetLaTeXString(fparameter) + "\\right\\}"; 495 | return ret; 496 | } else if (function->GetString() == "NDerivative"){ 497 | ret += R"(\frac{\mathrm{d}}{\mathrm{d})" + variables[0]->GetLaTeXString() + "}"; 498 | if (fparameter.size() == 1) 499 | ret += "\\left(" + fparameter[0]->GetLaTeXString() + "\\right)"; 500 | else 501 | ret += "\\left\\{" + ListGetLaTeXString(fparameter) + "\\right\\}"; 502 | return ret; 503 | } 504 | return ret; 505 | } 506 | 507 | mathS::Ptr mathS::FunctionalOperator::DeepCopy() const 508 | { 509 | Ptr ret = New(); 510 | ret->function = function->DeepCopy(); 511 | for (auto itv : variables) 512 | ret->variables.push_back(Dynamic_cast(itv->DeepCopy())); 513 | 514 | ret->fparameter = ListDeepCopy(fparameter); 515 | ret->parameter = ListDeepCopy(parameter); 516 | return ret; 517 | } 518 | 519 | std::string mathS::ListGetString(const std::vector>& lst) 520 | { 521 | std::string ret; 522 | if (lst.size() == 0) 523 | return ""; 524 | if (lst[0]->Level() < MathObject::LEVEL_LIST) 525 | ret += lst[0]->GetString(); 526 | else 527 | ret += "(" + lst[0]->GetString() + ")"; 528 | for (int i = 1; i < lst.size(); i++) 529 | if (lst[i]->Level() < MathObject::LEVEL_LIST) 530 | ret += "," + lst[i]->GetString(); 531 | else 532 | ret += ",(" + lst[i]->GetString() + ")"; 533 | return ret; 534 | } 535 | 536 | std::string mathS::ListGetLaTeXString(const std::vector>& lst) 537 | { 538 | std::string ret; 539 | if (lst.size() == 0) 540 | return ""; 541 | if (lst[0]->Level() < MathObject::LEVEL_LIST) 542 | ret += lst[0]->GetLaTeXString(); 543 | else 544 | ret += "\\left(" + lst[0]->GetLaTeXString() + "\\right)"; 545 | for (int i = 1; i < lst.size(); i++) 546 | if (lst[i]->Level() < MathObject::LEVEL_LIST) 547 | ret += "," + lst[i]->GetLaTeXString(); 548 | else 549 | ret += ",\\left(" + lst[i]->GetLaTeXString() + "\\right)"; 550 | return ret; 551 | } 552 | 553 | std::vector> mathS::ListDeepCopy(const std::vector>& lst) 554 | { 555 | std::vector> ret; 556 | ret.reserve(lst.size()); 557 | for (auto it : lst) 558 | ret.push_back(it->DeepCopy()); 559 | return ret; 560 | } 561 | -------------------------------------------------------------------------------- /mathS/src/MathParser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace mathS; 6 | 7 | #define ERROR_CHECK(x) if (x->GetType() == MathObject::ERROR) return x 8 | #define ERROR_CHECK_LIST(x) if (x->GetType() == MathObject::ERROR) return {x} 9 | #define LIST_ERROR_CHECK(x) if (x.size()>0 && x[0]->GetType() == MathObject::ERROR) return x[0] 10 | 11 | // 解析表达式 12 | Ptr mathS::Parse(const std::string & c) { 13 | Lexer lexer(c); 14 | std::vector tokens; 15 | Token tok; 16 | while (true) { 17 | lexer.get(tok); 18 | if (tok.type == Token::END) break; 19 | tokens.push_back(tok); 20 | } 21 | 22 | int i; 23 | auto obj = parseObject(tokens, 0, i); 24 | ERROR_CHECK(obj); 25 | if (i < tokens.size()) { 26 | return New("Parse: Syntax Error. Unexpected Symbol " + tokens[i].text); 27 | } 28 | 29 | return obj; 30 | } 31 | 32 | short mathS::level(const std::string &c) { 33 | SWITCH(c.c_str()) { 34 | CASE(c, "(") return MathObject::LEVEL_FUNCTION; 35 | CASE(c, "<<") return MathObject::LEVEL_FUNCOPERATOR; 36 | CASE(c, "[") return MathObject::LEVEL_LOCATE; 37 | CASE(c, "^") return MathObject::LEVEL_POWER; 38 | CASE(c, "/") return MathObject::LEVEL_ITEM; 39 | CASE(c, "*") return MathObject::LEVEL_ITEM; 40 | CASE(c, "-") return MathObject::LEVEL_POLYNOMIAL; 41 | CASE(c, "+") return MathObject::LEVEL_POLYNOMIAL; 42 | CASE(c, "==") return MathObject::LEVEL_COMPARE; 43 | CASE(c, "<") return MathObject::LEVEL_COMPARE; 44 | CASE(c, ">") return MathObject::LEVEL_COMPARE; 45 | CASE(c, "<=") return MathObject::LEVEL_COMPARE; 46 | CASE(c, ">=") return MathObject::LEVEL_COMPARE; 47 | CASE(c, ",") return MathObject::LEVEL_LIST; 48 | CASE(c, "->")return MathObject::LEVEL_MAP; 49 | 50 | CASE(c, ")") return MathObject::LEVEL_CLOSED; 51 | CASE(c, "|") return MathObject::LEVEL_CLOSED; 52 | CASE(c, ">>") return MathObject::LEVEL_CLOSED; 53 | CASE(c, "]") return MathObject::LEVEL_CLOSED; 54 | CASE(c, "}") return MathObject::LEVEL_CLOSED; 55 | 56 | default: return MathObject::LEVEL_ERROR; 57 | } 58 | return 0; 59 | } 60 | 61 | 62 | Ptr mathS::parseObject(const std::vector& tokens, const int start, int& i) 63 | { 64 | i = start; 65 | return parseCompare(tokens, i, i); 66 | } 67 | Ptr mathS::parseAtom(const std::vector& tokens, const int start, int& i) 68 | { 69 | Ptr obj; 70 | i = start; 71 | if (i >= tokens.size()) 72 | return New("Parse: Expression is incompleted."); 73 | if (tokens[i].type == Token::NUMORSYMB || tokens[i].type == Token::STRING) { 74 | obj = New(tokens[i].text); 75 | i++; 76 | return obj; 77 | } 78 | else if (tokens[i].type == Token::OPERATOR) { 79 | // 如果是操作符,那么必须是(_OBJECT)或{_OBJECT} 80 | if (tokens[i].text == "(") { 81 | obj = parseObject(tokens, i + 1, i); 82 | ERROR_CHECK(obj); 83 | if (i < tokens.size() && tokens[i].text == ")") { 84 | i++; 85 | return obj; 86 | } 87 | else { 88 | return New("Parser: Unmatched brace ("); 89 | } 90 | } 91 | else if(tokens[i].text == "{") 92 | { 93 | Ptr vobj = New(); 94 | vobj->components = parseList(tokens, start + 1, i); 95 | LIST_ERROR_CHECK(vobj->components); 96 | 97 | if (i < tokens.size() && tokens[i].text == "}") { 98 | i++; 99 | return vobj; 100 | } 101 | else { 102 | return New("Parser: Unmatched brace {"); 103 | } 104 | } 105 | } 106 | return New("Parse: Syntax Error. Unexpected Symbol. " + tokens[i].text); 107 | } 108 | 109 | 110 | Ptr mathS::parseFunction(const std::vector& tokens, const int start, int& i) 111 | { 112 | i = start; 113 | 114 | auto f = parseAtom(tokens, start, i); 115 | ERROR_CHECK(f); 116 | if (i >= tokens.size()) 117 | return f; 118 | 119 | if (tokens[i].text == "(") { 120 | // ( ) 表示函数 121 | auto p = parseList(tokens, i + 1, i); 122 | LIST_ERROR_CHECK(p); 123 | if (i < tokens.size() && tokens[i].text == ")") { 124 | i++; 125 | Ptr fobj = New(); 126 | fobj->function = f; 127 | fobj->parameter = p; 128 | return fobj; 129 | } 130 | else { 131 | return New("Parse: Syntax Error. Unmatched brace ("); 132 | } 133 | } 134 | else if (tokens[i].text == "<<") { 135 | // << | >>( ) 表示泛函算子 136 | std::vector> vars; 137 | // variables 138 | while (true) { 139 | auto v = parseAtom(tokens, i + 1, i); 140 | ERROR_CHECK(v); 141 | vars.push_back(Dynamic_cast(v)); 142 | if (i >= tokens.size()) 143 | return New("Parse: Syntax Error. Unmatched <<. "); 144 | 145 | if (tokens[i].text == "|") 146 | break; 147 | else if (tokens[i].text != ",") 148 | return New("Parse: Syntax Error. Unmatched <<. "); 149 | } 150 | auto fpara = parseList(tokens, i + 1, i); 151 | LIST_ERROR_CHECK(fpara); 152 | if (!(i < tokens.size() && tokens[i].text == ">>")) 153 | return New("Parser: Unmatched <<"); 154 | 155 | i++; 156 | if (!(i < tokens.size() && tokens[i].text == "(")) 157 | return New("Parser: Incompleted Functional Operator"); 158 | 159 | auto para = parseList(tokens, i + 1, i); 160 | LIST_ERROR_CHECK(para); 161 | if (!(i < tokens.size() && tokens[i].text == ")")) 162 | return New("Parser: Unmatched brace ("); 163 | 164 | Ptr fop = New(); 165 | 166 | fop->function = f; 167 | fop->variables = vars; 168 | fop->fparameter = fpara; 169 | fop->parameter = para; 170 | i++; 171 | return fop; 172 | } 173 | else if (level(tokens[i].text) > MathObject::LEVEL_FUNCTION) { 174 | // 后面已经截断,说明并不是函数形式,把 f 返回即可 175 | return f; 176 | } 177 | else { 178 | return New("Parse: Syntax Error. Unexpected symbol " + tokens[i].text); 179 | } 180 | 181 | } 182 | 183 | Ptr mathS::parseLocate(const std::vector& tokens, const int start, int& i) 184 | { 185 | i = start; 186 | auto obj = parseFunction(tokens, start, i); 187 | ERROR_CHECK(obj); 188 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_LOCATE) { 189 | return obj; 190 | } 191 | if (tokens[i].text == "[") { 192 | auto loc = parseList(tokens, i + 1, i); 193 | LIST_ERROR_CHECK(loc); 194 | 195 | if (!(i < tokens.size() && tokens[i].text == "]")) 196 | return New("Parse: Syntax Error. Unmatched brace ["); 197 | i++; 198 | Ptr lc = New(); 199 | lc->object = obj; 200 | lc->location = loc; 201 | return lc; 202 | } 203 | else { 204 | return New("Parse: Syntax Error. Unexpected symbol " + tokens[i].text); 205 | } 206 | 207 | } 208 | 209 | Ptr mathS::parsePower(const std::vector& tokens, const int start, int& i) 210 | { 211 | i = start; 212 | auto b = parseLocate(tokens, start, i); 213 | ERROR_CHECK(b); 214 | // 是否是指数形式 215 | if (!(i < tokens.size() && tokens[i].text == "^")) { 216 | return b; 217 | } 218 | auto e = parsePower(tokens, i + 1, i); 219 | ERROR_CHECK(e); 220 | // parsePower 和 parseAtom 一定不会返回 Empty 221 | Ptr pw = New(); 222 | pw->base = b; 223 | pw->exponent = e; 224 | return pw; 225 | } 226 | 227 | Ptr mathS::parseItem(const std::vector& tokens, const int start, int& i) 228 | { 229 | i = start; 230 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_ITEM) { 231 | return New("Parse: Syntax Error. Incomplete expression."); 232 | } 233 | Ptr itm = New(); 234 | if (tokens[i].text != "/") { 235 | auto fct = parsePower(tokens, start, i); 236 | ERROR_CHECK(fct); 237 | itm->push_back(fct); 238 | } 239 | while (true) { 240 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_ITEM) { 241 | // 若只有一项,简化表达式 242 | if (itm->factors.size() > 1) 243 | return itm; 244 | else 245 | return itm->factors[0]; 246 | } 247 | if (tokens[i].text == "*") { 248 | // 增加乘因子 249 | auto t = parsePower(tokens, i + 1, i); 250 | ERROR_CHECK(t); 251 | itm->push_back(t); 252 | } 253 | else if (tokens[i].text == "/") { 254 | // 增加除因子 255 | auto t = parsePower(tokens, i + 1, i); 256 | ERROR_CHECK(t); 257 | itm->push_back(New(t)); 258 | } 259 | else { 260 | return New("Parse: Syntax Error. Unexpected Symbol " + tokens[i].text); 261 | } 262 | 263 | } 264 | 265 | } 266 | 267 | Ptr mathS::parsePolynomial(const std::vector& tokens, const int start, int& i) 268 | { 269 | i = start; 270 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_POLYNOMIAL) { 271 | return New("Parse: Syntax Error. Incomplete expression."); 272 | } 273 | Ptr itm; 274 | Ptr poly = New(); 275 | if (tokens[i].text != "+" && tokens[i].text != "-") { 276 | itm = parseItem(tokens, i, i); 277 | ERROR_CHECK(itm); 278 | poly->push_back(itm); 279 | } 280 | while (true) { 281 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_POLYNOMIAL) { 282 | // 若只有一项,简化表达式 283 | if (poly->items.size() > 1) 284 | return poly; 285 | else 286 | return poly->items[0]; 287 | } 288 | if (tokens[i].text == "+") { 289 | // 增加正项 290 | auto t = parseItem(tokens, i + 1, i); 291 | ERROR_CHECK(t); 292 | poly->push_back(t); 293 | } 294 | else if (tokens[i].text == "-") { 295 | // 增加负项 296 | auto t = parseItem(tokens, i + 1, i); 297 | ERROR_CHECK(t); 298 | poly->push_back(New(t)); 299 | } 300 | else { 301 | // 多项式没有终止,而下一个字符无法识别有效,报错 302 | return New("Parse: Syntax Error. Unexpected Symbol " + tokens[i].text); 303 | } 304 | } 305 | } 306 | 307 | Ptr mathS::parseMap(const std::vector& tokens, const int start, int& i) 308 | { 309 | i = start; 310 | auto a = parsePolynomial(tokens, i, i); 311 | ERROR_CHECK(a); 312 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_MAP) 313 | return a; 314 | if (tokens[i].text != "->") 315 | return New("Parse: Syntax Error. Unexpected Symbol " + tokens[i].text); 316 | 317 | auto b = parsePolynomial(tokens, i + 1, i); 318 | ERROR_CHECK(b); 319 | Ptr mp = New(a, b); 320 | return mp; 321 | } 322 | 323 | Ptr mathS::parseCompare(const std::vector& tokens, const int start, int& i) 324 | { 325 | i = start; 326 | auto a = parseMap(tokens, i, i); 327 | ERROR_CHECK(a); 328 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_COMPARE) 329 | return a; 330 | if (level(tokens[i].text) != MathObject::LEVEL_COMPARE) { 331 | return New("Parse: Syntax Error. Unexpected Symbol " + tokens[i].text); 332 | } 333 | std::string op = tokens[i].text; 334 | auto b = parseMap(tokens, i + 1, i); 335 | ERROR_CHECK(b); 336 | Ptr cmp = New(a, op, b); 337 | return cmp; 338 | } 339 | 340 | 341 | std::vector> mathS::parseList(const std::vector& tokens, const int start, int& i) 342 | { 343 | i = start; 344 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_LIST) 345 | return std::vector>(); 346 | auto obj = parseCompare(tokens, start, i); 347 | ERROR_CHECK_LIST(obj); 348 | 349 | std::vector> lst; 350 | lst.push_back(obj); 351 | while (true) { 352 | if (i >= tokens.size() || level(tokens[i].text) > MathObject::LEVEL_LIST) 353 | return lst; 354 | if (tokens[i].text == ",") { 355 | auto t = parseCompare(tokens, i + 1, i); 356 | ERROR_CHECK_LIST(t); 357 | lst.push_back(t); 358 | } 359 | else { 360 | return { New("Parse: Syntax Error. Unexpected Symbol " + tokens[i].text) }; 361 | } 362 | } 363 | } 364 | 365 | -------------------------------------------------------------------------------- /mathS/src/NFunction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace mathS; 5 | using namespace mathS::NMath; 6 | 7 | NFunction mathS::NMath::NFunctionError(const std::string info) 8 | { 9 | return [info](const NParamsList&) { 10 | return Dynamic_cast(New(info)); 11 | }; 12 | } 13 | 14 | NFunction mathS::NMath::NFunctionAtom(const NValueType v) 15 | { 16 | return [v](const NParamsList&) { 17 | return Dynamic_cast(New(v)); 18 | }; 19 | } 20 | 21 | 22 | 23 | // Define a shape wise NMathFunction with name of FUNCNAME, based on operator OP 24 | #define DEFINE_SHAPE_WISE_NMATHFUNC_OP(FUNCNAME, OP, FNAMESTRING) \ 25 | Ptr mathS::NMath::FUNCNAME(const NParamsList& params){\ 26 | if (params.size() != 2)\ 27 | return New(std::string("NMath::") + FNAMESTRING + ": Must take 2 arguments but " + std::to_string(params.size()) + " got instead. ");\ 28 | auto& a = params[0];\ 29 | auto& b = params[1]; \ 30 | using NType = NMathObject::Type;\ 31 | NType atype = a->GetType(), btype = b->GetType();\ 32 | /*Case 1 (Basic case)*/\ 33 | if (atype == NType::ATOM && btype == NType::ATOM)\ 34 | return New(Dynamic_cast(a)->value OP Dynamic_cast(b)->value);\ 35 | /*Case 2*/\ 36 | if (atype == NType::ATOM && btype == NType::LIST){\ 37 | Ptr ret = New();\ 38 | Ptr blist = Dynamic_cast(b);\ 39 | for (auto it : blist->components)\ 40 | ret->components.push_back(FUNCNAME({a, it}));\ 41 | return ret;\ 42 | }\ 43 | /*Case 3*/\ 44 | if (atype == NType::LIST && btype == NType::ATOM){\ 45 | Ptr ret = New();\ 46 | Ptr alist = Dynamic_cast(a);\ 47 | for (auto it : alist->components)\ 48 | ret->components.push_back(FUNCNAME({it, b}));\ 49 | return ret;\ 50 | }\ 51 | /*Case 4*/\ 52 | if (atype == NType::LIST && btype == NType::LIST)\ 53 | {\ 54 | Ptr alist = Dynamic_cast(a), blist = Dynamic_cast(b);\ 55 | int absize;\ 56 | if ((absize = alist->Size()) != blist->Size())\ 57 | return New("Shape-wise operation: Shapes of " + alist->GetString() + " and " + blist->GetString() + "do not match. ");\ 58 | \ 59 | Ptr ret = New();\ 60 | Ptr newnode;\ 61 | for (int i = 0; i < absize; i++)\ 62 | {\ 63 | newnode = FUNCNAME({alist->components[i], blist->components[i]});\ 64 | if (newnode->IsError())\ 65 | return newnode; \ 66 | ret->components.push_back(newnode); \ 67 | }\ 68 | return ret; \ 69 | }\ 70 | /*Obvious Error Case*/\ 71 | if (atype == NType::ERROR || btype == NType::ERROR) {\ 72 | return New\ 73 | (\ 74 | (atype == NType::ERROR ? Dynamic_cast(a)->info : "")\ 75 | + (btype == NType::ERROR ? Dynamic_cast(b)->info : "")\ 76 | ); \ 77 | }\ 78 | } \ 79 | 80 | // Pre-defined NMathFunction +, -, *, / 81 | DEFINE_SHAPE_WISE_NMATHFUNC_OP(Plus, +, "Plus"); 82 | 83 | DEFINE_SHAPE_WISE_NMATHFUNC_OP(Subtract, -, "Subtract"); 84 | 85 | DEFINE_SHAPE_WISE_NMATHFUNC_OP(Multiply, *, "Multiply"); 86 | 87 | DEFINE_SHAPE_WISE_NMATHFUNC_OP(Divide, / ,"Divide"); 88 | 89 | 90 | #define DEFINE_SHAPE_WISE_NMATHFUNC_MONO(FUNCNAME, MONO, FNAMESTRING) \ 91 | Ptr mathS::NMath::FUNCNAME(const NParamsList& params)\ 92 | {\ 93 | if(params.size()!=1)\ 94 | return New(std::string("NMath::")+FNAMESTRING+": Must take 1 argument but got "+ std::to_string(params.size()));\ 95 | auto& a = params[0];\ 96 | using NType = NMathObject::Type;\ 97 | NType atype = a->GetType();\ 98 | /*Case 1 (Basic case)*/\ 99 | if (atype == NType::ATOM)\ 100 | return New(MONO(Dynamic_cast(a)->value));\ 101 | /*Case 2*/\ 102 | if (atype == NType::LIST)\ 103 | {\ 104 | Ptr ret = New();\ 105 | Ptr newnode;\ 106 | for (auto it : Dynamic_cast(a)->components)\ 107 | {\ 108 | newnode = FUNCNAME({it});\ 109 | if (newnode->IsError())\ 110 | return newnode;\ 111 | ret->components.push_back(FUNCNAME({it}));\ 112 | }\ 113 | return ret;\ 114 | }\ 115 | /*Case 3*/\ 116 | if (atype == NType::ERROR)\ 117 | return a;\ 118 | else\ 119 | {\ 120 | return New("Mono: Unkown type.");\ 121 | }\ 122 | }\ 123 | 124 | 125 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(Sin, sin, "Sin"); 126 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(Cos, cos, "Cos"); 127 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(Tan, tan, "Tan"); 128 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(ASin, asin, "ASin"); 129 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(ACos, acos, "ACos"); 130 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(ATan, atan, "ATan"); 131 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(Log, log, "Log"); 132 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(Exp, exp, "Exp"); 133 | DEFINE_SHAPE_WISE_NMATHFUNC_MONO(Floor, floor, "Floor"); 134 | 135 | 136 | // Define a shape wise NMathFunction with name o f FUNCNAME, based on operator OP 137 | #define DEFINE_SHAPE_WISE_NMATHFUNC2(FUNCNAME, CFUNC, FNAMESTRING) \ 138 | Ptr mathS::NMath::FUNCNAME(const NParamsList& params){\ 139 | if (params.size() != 2)\ 140 | return New(std::string("NMath::") + FNAMESTRING + ": Must take 2 arguments but " + std::to_string(params.size()) + " got instead. ");\ 141 | auto& a = params[0];\ 142 | auto& b = params[1]; \ 143 | using NType = NMathObject::Type;\ 144 | NType atype = a->GetType(), btype = b->GetType();\ 145 | /*Case 1 (Basic case)*/\ 146 | if (atype == NType::ATOM && btype == NType::ATOM)\ 147 | return New(CFUNC(Dynamic_cast(a)->value, Dynamic_cast(b)->value));\ 148 | /*Case 2*/\ 149 | if (atype == NType::ATOM && btype == NType::LIST){\ 150 | Ptr ret = New();\ 151 | Ptr blist = Dynamic_cast(b);\ 152 | for (auto it : blist->components)\ 153 | ret->components.push_back(FUNCNAME({a, it}));\ 154 | return ret;\ 155 | }\ 156 | /*Case 3*/\ 157 | if (atype == NType::LIST && btype == NType::ATOM){\ 158 | Ptr ret = New();\ 159 | Ptr alist = Dynamic_cast(a);\ 160 | for (auto it : alist->components)\ 161 | ret->components.push_back(FUNCNAME({it, b}));\ 162 | return ret;\ 163 | }\ 164 | /*Case 4*/\ 165 | if (atype == NType::LIST && btype == NType::LIST)\ 166 | {\ 167 | Ptr alist = Dynamic_cast(a), blist = Dynamic_cast(b);\ 168 | int absize;\ 169 | if ((absize = alist->Size()) != blist->Size())\ 170 | return New("Shape-wise operation: Shapes of " + alist->GetString() + " and " + blist->GetString() + "do not match. ");\ 171 | \ 172 | Ptr ret = New();\ 173 | Ptr newnode;\ 174 | for (int i = 0; i < absize; i++)\ 175 | {\ 176 | newnode = FUNCNAME({alist->components[i], blist->components[i]});\ 177 | if (newnode->IsError())\ 178 | return newnode; \ 179 | ret->components.push_back(newnode); \ 180 | }\ 181 | return ret; \ 182 | }\ 183 | /*Obvious Error Case*/\ 184 | if (atype == NType::ERROR || btype == NType::ERROR) {\ 185 | return New\ 186 | (\ 187 | (atype == NType::ERROR ? Dynamic_cast(a)->info : "")\ 188 | + (btype == NType::ERROR ? Dynamic_cast(b)->info : "")\ 189 | ); \ 190 | }\ 191 | } \ 192 | 193 | 194 | 195 | DEFINE_SHAPE_WISE_NMATHFUNC2(Less, double_less, "Less"); 196 | DEFINE_SHAPE_WISE_NMATHFUNC2(Greater, double_greater, "Greater"); 197 | DEFINE_SHAPE_WISE_NMATHFUNC2(Lesseq, double_lesseq, "LessOrEqual"); 198 | DEFINE_SHAPE_WISE_NMATHFUNC2(Greatereq, double_greatereq, "GreaterOrEqual"); 199 | DEFINE_SHAPE_WISE_NMATHFUNC2(Power, pow, "Power"); -------------------------------------------------------------------------------- /mathS/src/NFunctionalOperator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace mathS; 4 | using namespace mathS::NMath; 5 | 6 | Ptr mathS::NMath::Product(NFuncParamsList f, NParamsList i) 7 | { 8 | if (f.size() != 1) { 9 | return New("NMath::Product: Expected 1 function parameter."); 10 | } 11 | if (i.size() == 0) { 12 | return New("NMath::Product: At least given 1 argument."); 13 | } 14 | if (i.size() == 1) { 15 | auto sumbound = i[0]; // {START, END, [STEP]} 16 | if(sumbound->GetType()!=NMathObject::LIST) 17 | return New("NMath::Sum: More than 1 argument is not supported yet."); 18 | auto v = Dynamic_cast(sumbound); 19 | if (v->components.size() == 2) { 20 | if (v->components[0]->IsAtom() && v->components[1]->IsAtom()) { 21 | double start = v->components[0]->GetValue(); 22 | double end = v->components[1]->GetValue(); 23 | auto ret = f[0]({ New(start) }); 24 | for (double k = start + 1.0; k <= end; k += 1.0) { 25 | ret = Multiply({ ret, f[0]({ New(k) }) }); 26 | if (ret->IsError()) return ret; 27 | } 28 | return ret; 29 | } 30 | else { 31 | return New("NMath::Sum: Parameters in {START, END, [STEP]} must be atom value."); 32 | } 33 | } 34 | else if (v->components.size() == 3) { 35 | if (v->components[0]->IsAtom() && v->components[1]->IsAtom()) { 36 | double start = v->components[0]->GetValue(); 37 | double end = v->components[1]->GetValue(); 38 | double step = v->components[2]->GetValue(); 39 | auto ret = f[0]({ New(start) }); 40 | for (double k = start + step; k <= end; k += step) { 41 | ret = Multiply({ ret, f[0]({ New(k) }) }); 42 | if (ret->IsError()) return ret; 43 | } 44 | return ret; 45 | } 46 | else { 47 | return New("NMath::Sum: Parameters in {START, END, [STEP]} must be atom value."); 48 | } 49 | } 50 | else { 51 | return New("NMath::Sum: Please follow {START, END, [STEP]}"); 52 | } 53 | } 54 | std::vector st(i.size()), ed(i.size()), sp(i.size()); 55 | NParamsList paramsList; 56 | for (int t = 0; t < i.size(); t++) { 57 | auto sumbound = i[t]; // {START, END, [STEP]} 58 | if (sumbound->GetType() != NMathObject::LIST) return New("NMath::Product: More than 1 argument is not supported yet."); 59 | auto v = Dynamic_cast(sumbound); 60 | double step = 1.0f; 61 | if (v->components.size() == 3) { 62 | if (v->components[2]->GetType() != NMathObject::ATOM) return New("NMath::Product: Parameters in {START, END, [STEP]} must be atom value."); 63 | step = v->components[2]->GetValue(); 64 | } else if (v->components.size() != 2) return New("NMath::Product: Please follow {START, END, [STEP]}"); 65 | if (v->components[0]->GetType() != NMathObject::ATOM || v->components[1]->GetType() != NMathObject::ATOM) return New("NMath::Sum: Parameters in {START, END, [STEP]} must be atom value."); 66 | paramsList.push_back(New(st[t] = v->components[0]->GetValue())); 67 | ed[t] = v->components[1]->GetValue(); 68 | sp[t] = step; 69 | } 70 | auto lst = i.size() - 1; 71 | auto prelst = i.size() - 2; 72 | auto ret = Static_cast(New(1)); 73 | auto step = sp[lst]; 74 | auto prestep = sp[prelst]; 75 | auto lstpAtomPtr = Dynamic_cast(paramsList[lst]); 76 | auto prelstpAtomPtr = Dynamic_cast(paramsList[prelst]); 77 | while (paramsList[0]->GetValue() <= ed[0]) { 78 | for (double t = st[lst]; t <= ed[lst]; t += step) { 79 | lstpAtomPtr->SetValue(t); 80 | ret = Multiply({ ret, f[0](paramsList) }); 81 | } 82 | lstpAtomPtr->SetValue(st[lst]); 83 | prelstpAtomPtr->SetValue(prelstpAtomPtr->GetValue() + prestep); 84 | for (unsigned t = prelst; ~t; ) { 85 | if (paramsList[t]->GetValue() > ed[t]) { 86 | if (t == 0) {// 说明这是最后一轮回 87 | if (paramsList[t]->GetValue() + sp[t] > ed[t]) return ret; 88 | Dynamic_cast(paramsList[t])->SetValue(st[t]); 89 | break; 90 | } 91 | Dynamic_cast(paramsList[t])->SetValue(st[t]); 92 | Dynamic_cast(paramsList[--t])->SetValue(paramsList[t]->GetValue() + sp[t]); 93 | } else break; 94 | } 95 | } 96 | return ret; 97 | } 98 | Ptr mathS::NMath::Sum(NFuncParamsList f, NParamsList i) 99 | { 100 | if (f.size() != 1) { 101 | return New("NMath::Sum: Expected 1 function parameter."); 102 | } 103 | if (i.size() == 0) { 104 | return New("NMath::Sum: At least given 1 argument."); 105 | } 106 | if (i.size() == 1) { 107 | auto sumbound = i[0]; // {START, END, [STEP]} 108 | if(sumbound->GetType()!=NMathObject::LIST) 109 | return New("NMath::Sum: More than 1 argument is not supported yet."); 110 | auto v = Dynamic_cast(sumbound); 111 | if (v->components.size() == 2) { 112 | if (v->components[0]->IsAtom() && v->components[1]->IsAtom()) { 113 | double start = v->components[0]->GetValue(); 114 | double end = v->components[1]->GetValue(); 115 | auto ret = f[0]({ New(start) }); 116 | for (double k = start + 1.0; k <= end; k += 1.0) { 117 | ret = Plus({ ret, f[0]({ New(k) }) }); 118 | if (ret->IsError()) return ret; 119 | } 120 | return ret; 121 | } 122 | else { 123 | return New("NMath::Sum: Parameters in {START, END, [STEP]} must be atom value."); 124 | } 125 | } 126 | else if (v->components.size() == 3) { 127 | if (v->components[0]->IsAtom() && v->components[1]->IsAtom()) { 128 | double start = v->components[0]->GetValue(); 129 | double end = v->components[1]->GetValue(); 130 | double step = v->components[2]->GetValue(); 131 | auto ret = f[0]({ New(start) }); 132 | for (double k = start + step; k <= end; k += step) { 133 | ret = Plus({ ret, f[0]({ New(k) }) }); 134 | if (ret->IsError()) return ret; 135 | } 136 | return ret; 137 | } 138 | else { 139 | return New("NMath::Sum: Parameters in {START, END, [STEP]} must be atom value."); 140 | } 141 | } 142 | else { 143 | return New("NMath::Sum: Please follow {START, END, [STEP]}"); 144 | } 145 | } 146 | std::vector st(i.size()), ed(i.size()), sp(i.size()); 147 | NParamsList paramsList; 148 | for (int t = 0; t < i.size(); t++) { 149 | auto sumbound = i[t]; // {START, END, [STEP]} 150 | if (sumbound->GetType() != NMathObject::LIST) return New("NMath::Sum: More than 1 argument is not supported yet."); 151 | auto v = Dynamic_cast(sumbound); 152 | double step = 1.0f; 153 | if (v->components.size() == 3) { 154 | if (v->components[2]->GetType() != NMathObject::ATOM) return New("NMath::Sum: Parameters in {START, END, [STEP]} must be atom value."); 155 | step = v->components[2]->GetValue(); 156 | } else if (v->components.size() != 2) return New("NMath::Sum: Please follow {START, END, [STEP]}"); 157 | if (v->components[0]->GetType() != NMathObject::ATOM || v->components[1]->GetType() != NMathObject::ATOM) return New("NMath::Sum: Parameters in {START, END, [STEP]} must be atom value."); 158 | paramsList.push_back(New(st[t] = v->components[0]->GetValue())); 159 | ed[t] = v->components[1]->GetValue(); 160 | sp[t] = step; 161 | } 162 | auto lst = i.size() - 1; 163 | auto prelst = i.size() - 2; 164 | auto ret = Static_cast(New(0)); 165 | auto step = sp[lst]; 166 | auto prestep = sp[prelst]; 167 | auto lstpAtomPtr = Dynamic_cast(paramsList[lst]); 168 | auto prelstpAtomPtr = Dynamic_cast(paramsList[prelst]); 169 | while (paramsList[0]->GetValue() <= ed[0]) { 170 | for (double t = st[lst]; t <= ed[lst]; t += step) { 171 | lstpAtomPtr->SetValue(t); 172 | ret = Plus({ ret, f[0](paramsList) }); 173 | } 174 | lstpAtomPtr->SetValue(st[lst]); 175 | prelstpAtomPtr->SetValue(prelstpAtomPtr->GetValue() + prestep); 176 | for (unsigned t = prelst; ~t; ) { 177 | if (paramsList[t]->GetValue() > ed[t]) { 178 | if (t == 0) {// 说明这是最后一轮回 179 | if (paramsList[t]->GetValue() + sp[t] > ed[t]) return ret; 180 | Dynamic_cast(paramsList[t])->SetValue(st[t]); 181 | break; 182 | } 183 | Dynamic_cast(paramsList[t])->SetValue(st[t]); 184 | Dynamic_cast(paramsList[--t])->SetValue(paramsList[t]->GetValue() + sp[t]); 185 | } else break; 186 | } 187 | } 188 | return ret; 189 | } 190 | 191 | Ptr mathS::NMath::NDerivative(NFuncParamsList f, NParamsList i) { 192 | if (f.size() != 1) return New("NMath::NDerivative: Expected 1 function"); 193 | if (i.size() != 1) return New("NMath::NDerivative: Expected 1 variable"); 194 | if (i[0]->GetType() != NMathObject::LIST) return New("NMath::NDerivative: More than 1 argument is not supported yet."); 195 | auto param = Dynamic_cast(i[0]);// {x, [∆x]} 196 | double x, delta_x = 0.0001f; 197 | if (param->components.size() == 1) x = param->components[0]->GetValue(); 198 | else if (param->components.size() == 2) { 199 | x = param->components[0]->GetValue(); 200 | delta_x = param->components[1]->GetValue(); 201 | } else return New("NMath::NDerivative: Please follow {x, [∆x]}"); 202 | NParamsList delta_f_param, f_param; 203 | delta_f_param.push_back(New(x + delta_x)); 204 | f_param.push_back(New(x)); 205 | return Divide({ Subtract({ f[0](delta_f_param), f[0](f_param) }), New(delta_x) }); 206 | } 207 | -------------------------------------------------------------------------------- /mathS/src/NMathObject.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace mathS; 5 | using namespace mathS::NMath; 6 | 7 | std::string mathS::NMath::NAtom::GetString() const 8 | { 9 | return std::to_string(value); 10 | } 11 | 12 | Ptr mathS::NMath::NAtom::DeepCopy() const 13 | { 14 | return New(value); 15 | } 16 | 17 | Ptr mathS::NMath::NList::PartLocate(const std::vector& loc) const 18 | { 19 | if (loc.size() == 0) 20 | return New("NList::PartLocate: Empty part specification. "); 21 | Ptr pl; 22 | if(loc[0]>=components.size()) 23 | return New("NList::PartLocate: Part " + std::to_string(loc[0]) + " of " + GetString() + " is out of range."); 24 | Ptr p = components[loc[0]]; 25 | for (int i = 1; i < loc.size(); i++) 26 | { 27 | if (p->GetType() == NMathObject::Type::LIST) 28 | { 29 | pl = Dynamic_cast(p); 30 | if (loc[i] >= pl->components.size()) 31 | return New("NList::PartLocate: Part " + std::to_string(loc[i]) + " of " + p->GetString() + " is out of range."); 32 | p = pl->components[loc[i]]; 33 | } 34 | else 35 | { 36 | if (p->IsAtom()) 37 | return New("NList::PartLocate: Part specification is longer than depth of object. "); 38 | else if (p->IsError()) 39 | return New("An error has existed: "+p->GetString()); 40 | } 41 | } 42 | return p; 43 | } 44 | 45 | std::string mathS::NMath::NList::GetString() const 46 | { 47 | std::string ret("{"); 48 | ret += components[0]->GetString(); 49 | for (int i = 1; i < components.size(); i++) 50 | ret += ","+components[i]->GetString(); 51 | ret += "}"; 52 | return ret; 53 | } 54 | 55 | Ptr mathS::NMath::NList::DeepCopy() const 56 | { 57 | Ptr ret = New(); 58 | ret->components.reserve(components.size()); 59 | for (auto& it : components) { 60 | ret->components.push_back(it->DeepCopy()); 61 | } 62 | return Dynamic_cast(ret); 63 | } 64 | 65 | 66 | 67 | Ptr mathS::NMath::PartLocate(Ptr obj, const int loc) 68 | { 69 | if (obj->GetType() == NMathObject::LIST) 70 | { 71 | Ptr pl = Dynamic_cast(obj); 72 | if(0<=loc && loc < pl->components.size()) 73 | return pl->components[loc]; 74 | else 75 | return New("PartLocate: Part " + std::to_string(loc) + " of " + obj->GetString() + " is out of range."); 76 | } 77 | } 78 | 79 | Ptr mathS::NMath::Concatenate(Ptr a, Ptr b) 80 | { 81 | if (a->GetType() == NMathObject::LIST && b->GetType() == NMathObject::LIST) { 82 | Ptr ret = New(); 83 | auto alst = Dynamic_cast(a); 84 | auto blst = Dynamic_cast(b); 85 | ret->components.reserve(alst->components.size() + blst->components.size()); 86 | for (auto& it : alst->components) { 87 | ret->components.push_back(it->DeepCopy()); 88 | } 89 | for (auto& it : blst->components) { 90 | ret->components.push_back(it->DeepCopy()); 91 | } 92 | return Dynamic_cast(ret); 93 | } 94 | else { 95 | return New("NMath: Cannot concatenate " + a->GetString() + " and " + b->GetString()); 96 | } 97 | } 98 | 99 | Ptr& mathS::NMath::PartLocate_ref(Ptr obj, const std::vector& loc) 100 | { 101 | Ptr pl; 102 | Ptr p = obj; 103 | // Locate the first size-1 indices 104 | for (int i = 1; i < loc.size() - 1; i++) 105 | { 106 | pl = Dynamic_cast(p); 107 | p = pl->components[loc[i]]; 108 | } 109 | // return the reference of last index 110 | pl = Dynamic_cast(p); 111 | return pl->components[loc[loc.size() - 1]]; 112 | } 113 | 114 | Ptr mathS::NMath::PartLocate(Ptr obj, const std::vector& loc) 115 | { 116 | Ptr pl; 117 | Ptr p = obj; 118 | for (int i = 0; i < loc.size(); i++) 119 | { 120 | if (p->GetType() == NMathObject::Type::LIST) 121 | { 122 | pl = Dynamic_cast(p); 123 | if (loc[i] >= pl->components.size()) 124 | return New("PartLocate: Part " + std::to_string(loc[i]) + " of " + p->GetString() + " is out of range."); 125 | p = pl->components[loc[i]]; 126 | } 127 | else 128 | { 129 | if (p->IsAtom()) 130 | return New("PartLocate: Part specification is longer than depth of object. "); 131 | else if (p->IsError()) 132 | return New("An error has existed: " + p->GetString()); 133 | } 134 | } 135 | return p; 136 | } 137 | 138 | Ptr mathS::NMath::NMathError::DeepCopy() const 139 | { 140 | return New(info); 141 | } 142 | -------------------------------------------------------------------------------- /mathS/src/Rule.cpp: -------------------------------------------------------------------------------- 1 | #include "Rule.h" 2 | 3 | using namespace mathS; 4 | 5 | Match mathS::MakeMatch(Ptr pattern) 6 | { 7 | return [pattern](Ptr obj) { 8 | std::map> table; 9 | std::list table_list; 10 | return DoMatch(pattern, obj, table, table_list); 11 | }; 12 | } 13 | 14 | Rule mathS::MakeRule(const Ptr& src_pattern, Ptr tar_pattern) 15 | { 16 | return [src_pattern, tar_pattern](Ptr obj, Ptr& rst) { 17 | std::map> table; 18 | std::list table_list; 19 | if (!DoMatch(src_pattern, obj, table, table_list)) 20 | return false; 21 | rst = DoReplace(tar_pattern, table); 22 | return true; 23 | }; 24 | } 25 | Rule mathS::MakeRule(const Ptr& src_pattern, const std::function(std::map>&, bool&)>& do_replace) 26 | { 27 | return [src_pattern, do_replace](Ptr obj, Ptr& rst) { 28 | std::map> table; 29 | std::list table_list; 30 | if (!DoMatch(src_pattern, obj, table, table_list)) 31 | return false; 32 | bool flag = false; 33 | rst = do_replace(table, flag); 34 | if (flag) return false; 35 | return true; 36 | }; 37 | } 38 | 39 | bool mathS::DoMatch(Ptr pattern, Ptr obj, std::map>& table, std::list& table_list) 40 | { 41 | // 通配符匹配表 42 | MathObject::Type mtype = pattern->GetType(); 43 | 44 | switch (mtype) { 45 | case MathObject::ATOM: { 46 | // 如果是Atom, 考虑是匹配变量名还是 47 | Ptr atom_pattern = Dynamic_cast(pattern); 48 | switch (atom_pattern->str[0]) { 49 | case '_': { 50 | auto it = table.find(atom_pattern->str); 51 | if (it == table.end()) { 52 | table.insert(std::make_pair(atom_pattern->str, obj)); 53 | table_list.push_back(atom_pattern->str); 54 | } 55 | else { 56 | if (!FullCompare(it->second, obj)) 57 | return false; 58 | } 59 | break; 60 | } 61 | case '@': { 62 | if (obj->GetType() != MathObject::ATOM) 63 | return false; 64 | auto it = table.find(atom_pattern->str); 65 | auto atom_obj = Dynamic_cast(obj); 66 | if (it == table.end()) { 67 | if (atom_obj->AtomType() != MathObject::VARIABLE) 68 | return false; 69 | table.insert(std::make_pair(atom_pattern->str, obj)); 70 | table_list.push_back(atom_pattern->str); 71 | } 72 | else { 73 | if (it->second->GetString() != atom_obj->str) 74 | return false; 75 | } 76 | break; 77 | } 78 | case '#': { 79 | if (obj->GetType() != MathObject::ATOM) 80 | return false; 81 | auto it = table.find(atom_pattern->str); 82 | auto atom_obj = Dynamic_cast(obj); 83 | if (it == table.end()) { 84 | if (atom_obj->AtomType() != MathObject::NUMBER) 85 | return false; 86 | table.insert(std::make_pair(atom_pattern->str, obj)); 87 | table_list.push_back(atom_pattern->str); 88 | } 89 | else { 90 | if (it->second->GetString() != atom_obj->str) 91 | return false; 92 | } 93 | break; 94 | } 95 | case '$': { 96 | if (obj->GetType() != MathObject::ATOM) 97 | return false; 98 | auto it = table.find(atom_pattern->str); 99 | auto atom_obj = Dynamic_cast(obj); 100 | if (it == table.end()) { 101 | if (atom_obj->AtomType() != MathObject::STRING) 102 | return false; 103 | table.insert(std::make_pair(atom_pattern->str, obj)); 104 | table_list.push_back(atom_pattern->str); 105 | } 106 | else { 107 | if (it->second->GetString() != atom_obj->str) 108 | return false; 109 | } 110 | break; 111 | } 112 | default: { 113 | // 是变量名,要求obj对应也是完全相同的变量名 114 | if (obj->GetType() != MathObject::ATOM) 115 | return false; 116 | if (atom_pattern->str != obj->GetString()) 117 | return false; 118 | break; 119 | } 120 | } 121 | break; 122 | } 123 | case MathObject::VECTOR: { 124 | if (obj->GetType() != MathObject::VECTOR) // 确认类型 125 | return false; 126 | Ptr vec_pattern = Dynamic_cast(pattern); 127 | Ptr vec_obj = Dynamic_cast(obj); 128 | // 分别比较子表达式 129 | if (vec_pattern->components.size() != vec_obj->components.size()) 130 | return false; 131 | for(ptrdiff_t i = 0; icomponents.size();i++) 132 | if (!DoMatch(vec_pattern->components[i], vec_obj->components[i], table, table_list)) return false; 133 | break; 134 | } 135 | case MathObject::FUNCTION: { 136 | // 匹配函数 137 | if (obj->GetType() != MathObject::FUNCTION) // 确认类型 138 | return false; 139 | Ptr func_pattern = Dynamic_cast(pattern); 140 | Ptr func_obj = Dynamic_cast(obj); 141 | // 分别比较子表达式 142 | if (func_pattern->parameter.size() != func_obj->parameter.size()) 143 | return false; 144 | if (!DoMatch(func_pattern->function, func_obj->function, table, table_list)) 145 | return false; 146 | for (ptrdiff_t i = 0; i < func_pattern->parameter.size(); i++) { 147 | if (!DoMatch(func_pattern->parameter[i], func_obj->parameter[i], table, table_list)) 148 | return false; 149 | } 150 | break; 151 | } 152 | case MathObject::FUNCOPERATOR: { 153 | if (obj->GetType() != MathObject::FUNCOPERATOR) 154 | return false; 155 | Ptr fop_pattern = Dynamic_cast(pattern); 156 | Ptr fop_obj = Dynamic_cast(obj); 157 | if (fop_pattern->parameter.size() != fop_obj->parameter.size() || fop_pattern->variables.size() != fop_obj->variables.size() || fop_pattern->fparameter.size() != fop_obj->fparameter.size()) 158 | return false; 159 | if (!DoMatch(fop_pattern->function, fop_obj->function, table, table_list)) 160 | return false; 161 | for (ptrdiff_t i = 0; i < fop_pattern->variables.size(); i++) 162 | if (!DoMatch(fop_pattern->variables[i], fop_obj->variables[i], table, table_list)) return false; 163 | for (ptrdiff_t i = 0; i < fop_pattern->fparameter.size(); i++) 164 | if (!DoMatch(fop_pattern->fparameter[i], fop_obj->fparameter[i], table, table_list)) return false; 165 | for (ptrdiff_t i = 0; i < fop_pattern->parameter.size(); i++) 166 | if (!DoMatch(fop_pattern->parameter[i], fop_obj->parameter[i], table, table_list)) return false; 167 | break; 168 | } 169 | case MathObject::POWER: { 170 | if (obj->GetType() != MathObject::POWER) 171 | return false; 172 | Ptr pow_pattern = Dynamic_cast(pattern); 173 | Ptr pow_obj = Dynamic_cast(obj); 174 | if (!DoMatch(pow_pattern->base, pow_obj->base, table, table_list)) 175 | return false; 176 | if (!DoMatch(pow_pattern->exponent, pow_obj->exponent, table, table_list)) 177 | return false; 178 | break; 179 | } 180 | case MathObject::INVERSE: { 181 | if (obj->GetType() != MathObject::INVERSE) 182 | return false; 183 | Ptr inv_pattern = Dynamic_cast(pattern); 184 | Ptr inv_obj = Dynamic_cast(obj); 185 | if (!DoMatch(inv_pattern->component, inv_obj->component, table, table_list)) 186 | return false; 187 | break; 188 | } 189 | case MathObject::ITEM: { 190 | if (obj->GetType() != MathObject::ITEM) // 确认类型 191 | return false; 192 | auto& pattern_factors = Dynamic_cast(pattern)->factors; 193 | auto& obj_factors = Dynamic_cast(obj)->factors; 194 | 195 | // 判断是否有残项 196 | std::string residual; 197 | bool with_residual = false; 198 | if (pattern_factors.back()->GetType() == MathObject::ATOM) { 199 | residual = pattern_factors.back()->GetString(); 200 | if (residual.size() > 2 && residual[0] == '_' && residual[residual.size() - 1] == '_') { 201 | with_residual = true; 202 | } 203 | } 204 | // 要匹配 pattern 中项的个数。没有残项就全部,有残项,不匹配残项。 205 | ptrdiff_t matchsize = with_residual ? pattern_factors.size() - 1 : pattern_factors.size(); 206 | if (matchsize > obj_factors.size()) // 判断长短 207 | return false; 208 | 209 | std::vector md(obj_factors.size(), false); // 互斥约束 210 | std::vector> feasible; // 直接约束的可行集合 211 | feasible.resize(matchsize); 212 | ptrdiff_t table_size = table_list.size(); 213 | // 先得到直接约束的可行集合 214 | for (ptrdiff_t i = 0; i < matchsize; i++) { 215 | for (ptrdiff_t j = 0; j < obj_factors.size(); j++) { 216 | if (DoMatch(pattern_factors[i], obj_factors[j], table, table_list)) 217 | feasible[i].push_back(j); 218 | // 恢复匹配表 219 | while (table.size() > table_size) { 220 | table.erase(table_list.back()); 221 | table_list.pop_back(); 222 | } 223 | } 224 | if (feasible[i].empty()) 225 | return false; 226 | } 227 | // 对互斥约束前向检验,枚举剩下的情况 228 | std::vector::iterator> it; 229 | for (auto& jt : feasible) 230 | it.push_back(jt.begin()); 231 | std::vector table_sizes; 232 | table_sizes.resize(matchsize); 233 | table_sizes[0] = table_list.size(); 234 | for (ptrdiff_t i = 0; i < matchsize;) { 235 | // 恢复匹配表至 i 未匹配的状态 236 | while (table_list.size() > table_sizes[i]) { 237 | table.erase(table_list.back()); 238 | table_list.pop_back(); 239 | } 240 | // 本层要赋值的变量 pattern_factor[i], 值域为其可行的匹配 *it[i] : feasible[i] 241 | while (it[i] != feasible[i].end()) { 242 | // 必须满足互斥约束,且匹配成功,则选中,跳出选下一层。否则枚举本层的下一个 243 | if ((!md[*it[i]]) && DoMatch(pattern_factors[i], obj_factors[*it[i]], table, table_list)) 244 | break; 245 | it[i]++; 246 | // 本次匹配尝试失败也要恢复匹配表 247 | while (table_list.size() > table_sizes[i]) { 248 | table.erase(table_list.back()); 249 | table_list.pop_back(); 250 | } 251 | } 252 | if (it[i] != feasible[i].end()) { 253 | // 当前变量已经赋值,对下一个变量进行赋值 254 | md[*it[i]] = true; 255 | if (i == matchsize - 1) break; // 已经全部赋值 256 | table_sizes[i + 1] = table_list.size(); 257 | i++; 258 | } 259 | else { 260 | // 没有可选的,返回上一个变量 261 | if (i == 0) return false; 262 | it[i] = feasible[i].begin(); 263 | i--; 264 | md[*it[i]] = false; 265 | it[i]++; 266 | } 267 | } 268 | // 处理残项 269 | if (with_residual) { 270 | // 收集残项 271 | Ptr item_res = New(); 272 | for (ptrdiff_t j = 0; j < obj_factors.size(); j++) { 273 | if (!md[j]) 274 | item_res->push_back(obj_factors[j]); 275 | } 276 | Ptr factors_residual = ReduceItem(item_res); 277 | // 比较table中的项 278 | auto itres = table.find(residual); 279 | if (itres == table.end()) { 280 | table[residual] = factors_residual; 281 | table_list.push_back(residual); 282 | } 283 | else { 284 | if (!FullCompare(itres->second, factors_residual)) 285 | return false; 286 | } 287 | } 288 | break; 289 | } 290 | case MathObject::OPPOSITE: { 291 | if (obj->GetType() != MathObject::OPPOSITE) 292 | return false; 293 | Ptr oppo_pattern = Dynamic_cast(pattern); 294 | Ptr oppo_obj = Dynamic_cast(obj); 295 | if (!DoMatch(oppo_pattern->component, oppo_obj->component, table, table_list)) 296 | return false; 297 | break; 298 | } 299 | case MathObject::POLYNOMIAL: { 300 | if (obj->GetType() != MathObject::POLYNOMIAL) // 确认类型 301 | return false; 302 | auto& pattern_items = Dynamic_cast(pattern)->items; 303 | auto& obj_items = Dynamic_cast(obj)->items; 304 | // 判断是否有残项 305 | std::string residual; 306 | bool with_residual = false; 307 | if (pattern_items.back()->GetType() == MathObject::ATOM) { 308 | residual = pattern_items.back()->GetString(); 309 | if (residual.size() > 2 && residual[0] == '_' && residual[residual.size() - 1] == '_') { 310 | with_residual = true; 311 | } 312 | } 313 | // 要匹配 pattern 中项的个数。没有残项就全部,有残项,不匹配残项。 314 | ptrdiff_t matchsize = with_residual ? pattern_items.size() - 1 : pattern_items.size(); 315 | if (matchsize > obj_items.size()) // 判断长短 316 | return false; 317 | 318 | std::vector md(obj_items.size(), false); // 是否已经配过 319 | std::vector> feasible; // 直接约束的可行集合 320 | feasible.resize(matchsize); 321 | ptrdiff_t table_size = table_list.size(); 322 | // 先得到直接约束的可行集合 323 | for (ptrdiff_t i = 0; i < matchsize; i++) { 324 | for (ptrdiff_t j = 0; j < obj_items.size(); j++) { 325 | if (DoMatch(pattern_items[i], obj_items[j], table, table_list)) 326 | feasible[i].push_back(j); 327 | // 恢复匹配表 328 | while (table.size() > table_size) { 329 | table.erase(table_list.back()); 330 | table_list.pop_back(); 331 | } 332 | } 333 | if (feasible[i].empty()) 334 | return false; 335 | } 336 | // 对互斥约束前向检验,枚举剩下的情况 337 | std::vector::iterator> it; 338 | for (auto& jt : feasible) 339 | it.push_back(jt.begin()); 340 | std::vector table_sizes; 341 | table_sizes.resize(matchsize); 342 | table_sizes[0] = table_list.size(); 343 | for (ptrdiff_t i = 0; i < matchsize;) { 344 | // 恢复匹配表至 i 未匹配的状态 345 | while (table_list.size() > table_sizes[i]) { 346 | table.erase(table_list.back()); 347 | table_list.pop_back(); 348 | } 349 | while (it[i] != feasible[i].end()) { 350 | // 必须满足互斥约束,并且能Match,则认为选中,跳出选下一层。否则尝试本层的下一个 351 | if ((!md[*it[i]]) && DoMatch(pattern_items[i], obj_items[*it[i]], table, table_list)) 352 | break; 353 | it[i]++; 354 | // 本次匹配尝试失败也要恢复匹配表 355 | while (table_list.size() > table_sizes[i]) { 356 | table.erase(table_list.back()); 357 | table_list.pop_back(); 358 | } 359 | } 360 | if (it[i] != feasible[i].end()) { 361 | // 赋值可行 362 | md[*it[i]] = true; 363 | // 全部赋值完毕,得到可行解 364 | if (i == matchsize - 1) break; 365 | table_sizes[i + 1] = table_list.size(); 366 | i++; 367 | } 368 | else { 369 | // 没有可选的,返回上一个变量 370 | if (i == 0) return false; 371 | it[i] = feasible[i].begin(); 372 | i--; 373 | md[*it[i]] = false; 374 | it[i]++; 375 | } 376 | } 377 | // 处理残项 378 | if (with_residual) { 379 | // 收集残项 380 | Ptr poly_res = New(); 381 | for (ptrdiff_t j = 0; j < obj_items.size(); j++) { 382 | if (!md[j]) 383 | poly_res->push_back(obj_items[j]); 384 | } 385 | Ptr items_residual = ReducePolynomial(poly_res); 386 | // 比较table中的项 387 | auto itres = table.find(residual); 388 | if (itres == table.end()) { 389 | table[residual] = items_residual; 390 | table_list.push_back(residual); 391 | } 392 | else { 393 | if(!FullCompare(itres->second, items_residual)) 394 | return false; 395 | } 396 | } 397 | break; 398 | } 399 | case MathObject::MAP: { 400 | if (obj->GetType() != MathObject::MAP) 401 | return false; 402 | Ptr map_pattern = Dynamic_cast(pattern); 403 | Ptr map_obj = Dynamic_cast(obj); 404 | if (!DoMatch(map_pattern->key, map_obj->key, table, table_list)) 405 | return false; 406 | if (!DoMatch(map_pattern->value, map_obj->value, table, table_list)) 407 | return false; 408 | break; 409 | } 410 | case MathObject::COMPARE: { 411 | if (obj->GetType() != MathObject::COMPARE) 412 | return false; 413 | Ptr cmp_pattern = Dynamic_cast(pattern); 414 | Ptr cmp_obj = Dynamic_cast(obj); 415 | if (cmp_pattern->op != cmp_obj->op) 416 | return false; 417 | if (!DoMatch(cmp_pattern->left, cmp_obj->left, table, table_list)) 418 | return false; 419 | if (!DoMatch(cmp_pattern->right, cmp_obj->right, table, table_list)) 420 | return false; 421 | break; 422 | } 423 | default: 424 | // 不支持的类型,放弃匹配,直接返回false 425 | return false; 426 | break; 427 | } 428 | return true; 429 | } 430 | 431 | Ptr mathS::DoReplace(Ptr pattern, std::map>& table) 432 | { 433 | switch (pattern->GetType()) { 434 | case MathObject::ATOM: { 435 | // 如果是Atom, 考虑替换(不检查是通配符等,直接在table里查找,只要找到就替换) 436 | Ptr atom_pattern = Dynamic_cast(pattern); 437 | auto it = table.find(atom_pattern->str); 438 | if (it == table.end()) 439 | return pattern->DeepCopy(); 440 | else 441 | return it->second->DeepCopy(); 442 | } 443 | case MathObject::VECTOR: { 444 | Ptr vec_pattern = Dynamic_cast(pattern); 445 | Ptr vec_ret = New(); 446 | vec_ret->components.reserve(vec_pattern->components.size()); 447 | // 对子表达式应用替换,返回拷贝 448 | for (ptrdiff_t i = 0; i < vec_pattern->components.size(); i++) 449 | vec_ret->components.push_back(DoReplace(vec_pattern->components[i], table)); 450 | return vec_ret; 451 | } 452 | case MathObject::FUNCTION: { 453 | Ptr func_pattern = Dynamic_cast(pattern); 454 | Ptr func_ret = New(); 455 | func_ret->function = DoReplace(func_pattern->function, table); 456 | func_ret->parameter.reserve(func_pattern->parameter.size()); 457 | // 对子表达式应用替换,返回拷贝 458 | for (ptrdiff_t i = 0; i < func_pattern->parameter.size(); i++) 459 | func_ret->parameter.push_back(DoReplace(func_pattern->parameter[i], table)); 460 | return func_ret; 461 | } 462 | case MathObject::FUNCOPERATOR: { 463 | Ptr fop_pattern = Dynamic_cast(pattern); 464 | Ptr fop_ret = New(); 465 | fop_ret->function = DoReplace(fop_pattern->function, table); 466 | fop_ret->variables.reserve(fop_pattern->variables.size()); 467 | fop_ret->fparameter.reserve(fop_pattern->fparameter.size()); 468 | fop_ret->parameter.reserve(fop_pattern->parameter.size()); 469 | // 对子表达式应用替换,返回拷贝 470 | for (ptrdiff_t i = 0; i < fop_pattern->variables.size(); i++) { 471 | auto var = DoReplace(fop_pattern->variables[i], table); 472 | if (var->GetType() != MathObject::ATOM) 473 | return New("Rule: (Unexpected) Cannot replace Functional Operator variable with non-atom object. You may have defined illegal rules. "); 474 | fop_ret->variables.push_back(Dynamic_cast(var)); 475 | } 476 | for (ptrdiff_t i = 0; i < fop_pattern->fparameter.size(); i++) 477 | fop_ret->fparameter.push_back(DoReplace(fop_pattern->fparameter[i], table)); 478 | for (ptrdiff_t i = 0; i < fop_pattern->parameter.size(); i++) 479 | fop_ret->parameter.push_back(DoReplace(fop_pattern->parameter[i], table)); 480 | return fop_ret; 481 | } 482 | case MathObject::POWER: { 483 | Ptr pow_pattern = Dynamic_cast(pattern); 484 | return New(DoReplace(pow_pattern->base, table), DoReplace(pow_pattern->exponent, table)); 485 | } 486 | case MathObject::INVERSE: { 487 | Ptr inv_pattern = Dynamic_cast(pattern); 488 | return New(DoReplace(inv_pattern->component, table)); 489 | } 490 | case MathObject::ITEM: { 491 | Ptr itm_pattern = Dynamic_cast(pattern); 492 | Ptr itm_ret = New(); 493 | itm_ret->factors.reserve(itm_pattern->factors.size()); 494 | // 对子表达式应用替换,返回拷贝 495 | for (ptrdiff_t i = 0; i < itm_pattern->factors.size(); i++) 496 | itm_ret->push_back(DoReplace(itm_pattern->factors[i], table)); 497 | return itm_ret; 498 | } 499 | case MathObject::OPPOSITE: { 500 | Ptr oppo_pattern = Dynamic_cast(pattern); 501 | return New(DoReplace(oppo_pattern->component, table)); 502 | } 503 | case MathObject::POLYNOMIAL: { 504 | Ptr poly_pattern = Dynamic_cast(pattern); 505 | Ptr poly_ret = New(); 506 | poly_ret->items.reserve(poly_pattern->items.size()); 507 | // 对子表达式应用替换,返回拷贝 508 | for (ptrdiff_t i = 0; i < poly_pattern->items.size(); i++) 509 | poly_ret->push_back(DoReplace(poly_pattern->items[i], table)); 510 | return poly_ret; 511 | } 512 | case MathObject::MAP: { 513 | Ptr map_pattern = Dynamic_cast(pattern); 514 | return New(DoReplace(map_pattern->key, table), DoReplace(map_pattern->value, table)); 515 | } 516 | case MathObject::COMPARE: { 517 | Ptr cmp_pattern = Dynamic_cast(pattern); 518 | return New(DoReplace(cmp_pattern->left, table), cmp_pattern->op, DoReplace(cmp_pattern->right, table)); 519 | } 520 | default: 521 | return New("Rule: (Unexpected) Unkown MathObject type. This should not happen."); 522 | } 523 | } 524 | 525 | bool mathS::FullCompare(Ptr a, Ptr b) 526 | { 527 | // 通配符匹配表 528 | MathObject::Type mtype = a->GetType(); 529 | if (b->GetType() != mtype) 530 | return false; 531 | 532 | switch (mtype) { 533 | case MathObject::ATOM: { 534 | // 如果是Atom, 考虑是匹配变量名还是 535 | if (b->GetType() != MathObject::ATOM) 536 | return false; 537 | Ptr atom_a = Dynamic_cast(a); 538 | if (atom_a->str != b->GetString()) 539 | return false; 540 | break; 541 | } 542 | case MathObject::VECTOR: { 543 | if (b->GetType() != MathObject::VECTOR) // 确认类型 544 | return false; 545 | Ptr vec_a = Dynamic_cast(a); 546 | Ptr vec_obj = Dynamic_cast(b); 547 | // 分别比较子表达式 548 | if (vec_a->components.size() != vec_obj->components.size()) 549 | return false; 550 | for (ptrdiff_t i = 0; i < vec_a->components.size(); i++) 551 | if (!FullCompare(vec_a->components[i], vec_obj->components[i])) return false; 552 | break; 553 | } 554 | case MathObject::FUNCTION: { 555 | // 匹配函数 556 | if (b->GetType() != MathObject::FUNCTION) // 确认类型 557 | return false; 558 | Ptr func_a = Dynamic_cast(a); 559 | Ptr func_obj = Dynamic_cast(b); 560 | // 分别比较子表达式 561 | if (func_a->parameter.size() != func_obj->parameter.size()) 562 | return false; 563 | if (!FullCompare(func_a->function, func_obj->function)) 564 | return false; 565 | for (ptrdiff_t i = 0; i < func_a->parameter.size(); i++) { 566 | if (!FullCompare(func_a->parameter[i], func_obj->parameter[i])) 567 | return false; 568 | } 569 | break; 570 | } 571 | case MathObject::FUNCOPERATOR: { 572 | if (b->GetType() != MathObject::FUNCOPERATOR) 573 | return false; 574 | Ptr fop_a = Dynamic_cast(a); 575 | Ptr fop_obj = Dynamic_cast(b); 576 | if (fop_a->parameter.size() != fop_obj->parameter.size() || fop_a->variables.size() != fop_obj->variables.size() || fop_a->fparameter.size() != fop_obj->fparameter.size()) 577 | return false; 578 | if (!FullCompare(fop_a->function, fop_obj->function)) 579 | return false; 580 | for (ptrdiff_t i = 0; i < fop_a->variables.size(); i++) 581 | if (!FullCompare(fop_a->variables[i], fop_obj->variables[i])) return false; 582 | for (ptrdiff_t i = 0; i < fop_a->fparameter.size(); i++) 583 | if (!FullCompare(fop_a->fparameter[i], fop_obj->fparameter[i])) return false; 584 | for (ptrdiff_t i = 0; i < fop_a->parameter.size(); i++) 585 | if (!FullCompare(fop_a->parameter[i], fop_obj->parameter[i])) return false; 586 | break; 587 | } 588 | case MathObject::POWER: { 589 | if (b->GetType() != MathObject::POWER) 590 | return false; 591 | Ptr pow_a = Dynamic_cast(a); 592 | Ptr pow_obj = Dynamic_cast(b); 593 | if (!FullCompare(pow_a->base, pow_obj->base)) 594 | return false; 595 | if (!FullCompare(pow_a->exponent, pow_obj->exponent)) 596 | return false; 597 | break; 598 | } 599 | case MathObject::INVERSE: { 600 | if (b->GetType() != MathObject::INVERSE) 601 | return false; 602 | Ptr inv_a = Dynamic_cast(a); 603 | Ptr inv_obj = Dynamic_cast(b); 604 | if (!FullCompare(inv_a->component, inv_obj->component)) 605 | return false; 606 | break; 607 | } 608 | case MathObject::ITEM: { 609 | if (b->GetType() != MathObject::ITEM) // 确认类型 610 | return false; 611 | Ptr itm_a = Dynamic_cast(a); 612 | Ptr itm_b = Dynamic_cast(b); 613 | if (itm_a->factors.size() != itm_b->factors.size()) // 判断长短 614 | return false; 615 | auto& a_factors = itm_a->factors; 616 | auto& b_factors = itm_b->factors; 617 | 618 | std::vector md(b_factors.size(), false); // 是否已经配过 619 | for (ptrdiff_t i = 0; i < a_factors.size(); i++) { 620 | bool flag = false; 621 | for (ptrdiff_t j = 0; j < b_factors.size(); j++) { 622 | if (md[j]) continue; // 不匹配已经匹配过的项 623 | if (FullCompare(a_factors[i], b_factors[j])) { 624 | flag = true; 625 | md[j] = true; 626 | break; 627 | } 628 | } 629 | if (!flag) 630 | return false; 631 | } 632 | break; 633 | } 634 | case MathObject::OPPOSITE: { 635 | if (b->GetType() != MathObject::OPPOSITE) 636 | return false; 637 | Ptr oppo_a = Dynamic_cast(a); 638 | Ptr oppo_obj = Dynamic_cast(b); 639 | if (!FullCompare(oppo_a->component, oppo_obj->component)) 640 | return false; 641 | break; 642 | } 643 | case MathObject::POLYNOMIAL: { 644 | if (b->GetType() != MathObject::POLYNOMIAL) // 确认类型 645 | return false; 646 | Ptr poly_a = Dynamic_cast(a); 647 | Ptr poly_b = Dynamic_cast(b); 648 | if (poly_a->items.size() != poly_b->items.size()) // 判断长短 649 | return false; 650 | auto& a_items = poly_a->items; 651 | auto& b_items = poly_b->items; 652 | std::vector md(b_items.size(), false); // 是否已经配过 653 | for (ptrdiff_t i = 0; i < a_items.size(); i++) { 654 | bool flag = false; 655 | for (ptrdiff_t j = 0; j < b_items.size(); j++) { 656 | if (md[j]) continue; // 不匹配已经匹配过的项 657 | if (FullCompare(a_items[i], b_items[j])) { 658 | flag = true; 659 | md[j] = true; 660 | break; 661 | } 662 | } 663 | if (!flag) 664 | return false; 665 | } 666 | break; 667 | } 668 | case MathObject::MAP: { 669 | if (b->GetType() != MathObject::MAP) 670 | return false; 671 | Ptr map_a = Dynamic_cast(a); 672 | Ptr map_obj = Dynamic_cast(b); 673 | if (!FullCompare(map_a->key, map_obj->key)) 674 | return false; 675 | if (!FullCompare(map_a->value, map_obj->value)) 676 | return false; 677 | break; 678 | } 679 | case MathObject::COMPARE: { 680 | if (b->GetType() != MathObject::COMPARE) 681 | return false; 682 | Ptr cmp_a = Dynamic_cast(a); 683 | Ptr cmp_b = Dynamic_cast(b); 684 | if (cmp_a->op != cmp_b->op) 685 | return false; 686 | if (!FullCompare(cmp_a->left, cmp_b->left)) 687 | return false; 688 | if (!FullCompare(cmp_a->right, cmp_b->right)) 689 | return false; 690 | break; 691 | } 692 | default: 693 | return false; 694 | break; 695 | } 696 | return true; 697 | } 698 | 699 | 700 | -------------------------------------------------------------------------------- /mathS/src/RuleLib.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathSlib-dev/mathSlib/a8dabf60bed1f1ae503be987deb86c1493af7476/mathS/src/RuleLib.cpp -------------------------------------------------------------------------------- /mathS/src/lexer.cpp: -------------------------------------------------------------------------------- 1 | #include "lexer.h" 2 | #include 3 | 4 | void mathS::Lexer::get(mathS::Token& token) { 5 | token.text = ""; 6 | if (index >= content.length()) { 7 | token.type = Token::END; 8 | return; 9 | } 10 | char c = content[index++]; 11 | // skip space 12 | while ((c == ' ' || c == '\n' || c == '\t') && (index < content.length())) 13 | c = content[index++]; 14 | token.type = checkType(c); 15 | token.text += c; 16 | switch (token.type){ 17 | case Token::OPERATOR: 18 | if ((c == '=' || c == '<' || c == '>') && index < content.length()) { 19 | if (/*content[index] == '=' || */content[index] == c) 20 | token.text += content[index++]; 21 | } 22 | if (c == '-' && index < content.length()) { 23 | if (content[index] == '>') 24 | token.text += content[index++]; 25 | } 26 | break; 27 | case Token::NUMORSYMB: 28 | while (index < content.length()) { 29 | if (checkType(content[index]) != Token::NUMORSYMB) break; 30 | token.text += content[index++]; 31 | } 32 | break; 33 | case Token::STRING: 34 | while (index < content.length()) { 35 | c = content[index++]; 36 | token.text += c; 37 | if (c == '"') break; 38 | if (c == '\\' && index < content.length()) { 39 | token.text += content[index++]; 40 | } 41 | }; 42 | if (token.text.length() == 1 || token.text.back() != '"' || token.text[token.text.length() - 2] == '\\') 43 | token.text += '"'; 44 | break; 45 | default: 46 | break; 47 | } 48 | } 49 | 50 | mathS::Token::TYPE mathS::Lexer::checkType(char c) { 51 | // 判断字符类型 52 | if ((c >= '0' && c <= '9'||c=='.') 53 | ||(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 54 | || c == '_'|| c == '@' || c == '#' || c == '$') 55 | return Token::NUMORSYMB; 56 | if (c == '"') 57 | return Token::STRING; 58 | return Token::OPERATOR; 59 | } 60 | -------------------------------------------------------------------------------- /mathS/src/main.cpp: -------------------------------------------------------------------------------- 1 | // mathS.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 | // 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace mathS; 11 | 12 | int main() { 13 | 14 | 15 | std::string str; 16 | Assembler assembler; 17 | 18 | // Evaluate测试 19 | while (true) { 20 | std::cout << ">>> "; 21 | getline(std::cin, str); 22 | auto obj = Parse(str); 23 | while (Evaluate(obj, obj)); 24 | std::cout << obj->GetString() << std::endl; 25 | } 26 | /*// Rule模块测试 27 | while (true) { 28 | std::cout << "Source pattern: "; 29 | getline(std::cin, str); 30 | auto srcpattern = Parse(str); 31 | 32 | std::cout << "Target pattern: "; 33 | getline(std::cin, str); 34 | auto tarpattern = Parse(str); 35 | 36 | std::cout << "Object: "; 37 | getline(std::cin, str); 38 | auto obj = Parse(str); 39 | 40 | auto rule = MakeRule(srcpattern, tarpattern); 41 | Ptr rst; 42 | if (rule(obj, rst)) 43 | std::cout << rst->GetString() << std::endl; 44 | else 45 | std::cout << "No" << std::endl; 46 | }*/ 47 | 48 | // 计算器程序;测试LBAssembler 49 | while (true) { 50 | std::cout << ">>> "; 51 | getline(std::cin, str); 52 | auto mobj = Parse(str); 53 | 54 | // 检查表达式是否合法,并输出错误信息 55 | if (mobj->GetType() == MathObject::ERROR) { 56 | std::cout << mobj->GetString() << std::endl; 57 | continue; 58 | } 59 | // 计算器程序不需要变量参数,空的参数表 60 | std::vector params = {"x"}; 61 | // 组装 62 | auto f = assembler.Assemble(mobj, params); 63 | // 输出结果 64 | std::cout << f({})->GetString() << std::endl; 65 | // std::cout << "Latex = " << mobj->GetLaTeXString() << std::endl; 66 | } 67 | return 0; 68 | } -------------------------------------------------------------------------------- /mathS/src/string-switch.cpp: -------------------------------------------------------------------------------- 1 | #include "string-switch.h" 2 | --------------------------------------------------------------------------------