diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..0c0fe3c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: Test Math God Build + +on: + push: + branches: [ "main", "master" ] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ“ฅ Checkout code + uses: actions/checkout@v4 + + - name: ๐Ÿง Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: ๐Ÿ“ฑ Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: 'stable' + cache: true + + - name: ๐Ÿ”‘ Decode Keystore + run: | + echo "${{ secrets.SIGNING_KEYSTORE_BASE64 }}" | base64 -d > android/mathgod-keystore.jks + shell: bash + + - name: ๐Ÿ“ฆ Install dependencies + run: flutter pub get + + - name: ๐Ÿ”ง Test Build APK (Release Validation) + run: flutter build apk --release + env: + KEYSTORE_PASSWORD: ${{ secrets.SIGNING_KEYSTORE_PASSWORD }} + KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }} + KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }} diff --git a/.gitignore b/.gitignore index 3820a95..39aee22 100644 Binary files a/.gitignore and b/.gitignore differ diff --git a/README.md b/README.md index e364270..f309707 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,31 @@ -# mathgod +# MathGod ๐Ÿงฎ -A new Flutter project. +[![Website](https://img.shields.io/badge/Website-mathgod--woad.vercel.app-blue?style=flat-square)](https://mathgod-woad.vercel.app/#home) +[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg?style=flat-square)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) -## Getting Started +MathGod is an offline-first, high-performance symbolic mathematics and calculus solver built for mobile devices. -This project is a starting point for a Flutter application. +The primary mission of this project is educational empowermentโ€”providing university students with a robust Computer Algebra System (CAS) that runs completely offline, mitigating the barriers of high data costs and unstable internet connectivity. -A few resources to get you started if this is your first Flutter project: +๐ŸŒ **Official Landing Page & Documentation:** [mathgod-woad.vercel.app](https://mathgod-woad.vercel.app/#home) -- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter) -- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources) +--- -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## ๐Ÿš€ The Engineering Behind MathGod + +This application represents a novel integration architecture combining modern mobile UI frameworks with low-level symbolic math engines: + +* **Frontend:** Built with Flutter, utilizing Dart FFI (Foreign Function Interface) to seamlessly bridge high-performance native layers. +* **Core Computing Kernel:** Powered by the Giac/Xcas C++ library developed by Bernard Parisse. +* **Native Compilation:** Implemented via custom `CMakeLists.txt` configurations to compile the native Giac source into an optimized Android Shared Object (`.so`) binary using the Android NDK. + +--- + +## โš–๏ธ Open Source & Licensing + +In strict compliance with the **GNU General Public License v2.0 (GPLv2)**, the complete integration layer, build scripts, and interface mechanics for this application are fully open-sourced here for the global developer community. + +### Credits & Attribution + +* **Giac/Xcas Core:** Developed by Bernard Parisse / Universitรฉ Grenoble Alpes. Source and documentation: [Institut Fourier - Giac](https://www-fourier.ujf-grenoble.fr/~parisse/giac.html) +* **Android Build Dependencies:** The Android-specific pre-generated configuration headers and prebuilt GMP/MPFR static libraries used in this project were sourced from the [GeoGebra Giac fork](https://github.com/geogebra/giac). These files are not part of the original Giac project and are attributed to the GeoGebra team accordingly. diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index e109563..a09b2df 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,3 +1,13 @@ +import java.util.Properties +import java.io.FileInputStream + +// Load keystore properties +val keystoreProperties = Properties() +val keystorePropertiesFile = rootProject.file("key.properties") +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) +} + plugins { id("com.android.application") id("kotlin-android") @@ -5,9 +15,9 @@ plugins { } android { - namespace = "com.mathgod.app" // Changed from com.example.mathgod + namespace = "com.mathgod.app" compileSdk = flutter.compileSdkVersion - ndkVersion = "28.2.13676358" // Fixed NDK version for Giac + ndkVersion = "28.2.13676358" compileOptions { sourceCompatibility = JavaVersion.VERSION_17 @@ -18,6 +28,23 @@ android { jvmTarget = JavaVersion.VERSION_17.toString() } + signingConfigs { + create("release") { + // Priority 1: key.properties (Local) | Priority 2: Env Vars (CI) + keyAlias = (keystoreProperties["keyAlias"] as? String) ?: System.getenv("KEY_ALIAS") + keyPassword = (keystoreProperties["keyPassword"] as? String) ?: System.getenv("KEY_PASSWORD") + storePassword = (keystoreProperties["storePassword"] as? String) ?: System.getenv("KEYSTORE_PASSWORD") + + // Resolve keystore file path + storeFile = if (keystoreProperties.containsKey("storeFile")) { + file(keystoreProperties["storeFile"] as String) + } else { + // This matches the path created in your GitHub YAML + file("../mathgod-keystore.jks") + } + } + } + defaultConfig { applicationId = "com.mathgod.app" minSdk = flutter.minSdkVersion @@ -25,14 +52,12 @@ android { versionCode = flutter.versionCode versionName = flutter.versionName - // NDK ABI filters (arm64-v8a covers all modern phones) ndk { abiFilters.add("arm64-v8a") abiFilters.add("armeabi-v7a") abiFilters.add("x86_64") } - // CMake build for Giac externalNativeBuild { cmake { cppFlags("-std=c++17 -fexceptions -frtti") @@ -41,7 +66,6 @@ android { } } - // Point to CMakeLists.txt externalNativeBuild { cmake { path = file("src/main/cpp/CMakeLists.txt") @@ -51,7 +75,7 @@ android { buildTypes { release { - signingConfig = signingConfigs.getByName("debug") + signingConfig = signingConfigs.getByName("release") isMinifyEnabled = true isShrinkResources = true proguardFiles( @@ -64,4 +88,4 @@ android { flutter { source = "../.." -} \ No newline at end of file +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c6c6ed4..66b7d53 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ + + + + + + + + + + + + diff --git a/android/app/src/main/cpp/CMakeLists.txt b/android/app/src/main/cpp/CMakeLists.txt index ed081f0..00159a1 100644 --- a/android/app/src/main/cpp/CMakeLists.txt +++ b/android/app/src/main/cpp/CMakeLists.txt @@ -7,9 +7,27 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(GIAC_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/giac) +# โ”€โ”€โ”€ ABI โ†’ prebuilt path mapping โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +if(ANDROID_ABI STREQUAL "arm64-v8a") + set(GIAC_ABI_DIR "arm-v8") +elseif(ANDROID_ABI STREQUAL "armeabi-v7a") + set(GIAC_ABI_DIR "arm-v7") +elseif(ANDROID_ABI STREQUAL "x86_64") + set(GIAC_ABI_DIR "x86-64") +elseif(ANDROID_ABI STREQUAL "x86") + set(GIAC_ABI_DIR "x86") +else() + message(FATAL_ERROR "Unsupported ABI: ${ANDROID_ABI}") +endif() + +set(GIAC_PREBUILT_DIR ${GIAC_ROOT}/src/jni/prebuilt/android/${GIAC_ABI_DIR}) +set(GIAC_HEADER_DIR ${GIAC_ROOT}/src/giac/headers/android/${GIAC_ABI_DIR}) + include_directories( ${GIAC_ROOT}/src ${GIAC_ROOT}/src/giac + ${GIAC_ROOT}/src/giac/headers + ${GIAC_HEADER_DIR} ) file(GLOB_RECURSE GIAC_SOURCES @@ -17,18 +35,53 @@ file(GLOB_RECURSE GIAC_SOURCES "${GIAC_ROOT}/src/*.cc" ) +# โ”€โ”€โ”€ EXCLUDE EVERYTHING NOT NEEDED FOR CORE CAS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Test files +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/test/.*") + +# Graphics (plot.cc is needed, but opengl/gui/fltk/glut are not) +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/opengl.*") +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/gui.*") +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/fltk.*") +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/glut.*") + +# GeoGebra-specific wrappers (not needed) +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/geogebra.*") +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*GeoGebraCAS.*") + +# Node.js bindings (not needed) +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/nodegiac.*") + +# Simple interface examples (not needed) +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*/simpleInterface.*") + +# Only exclude files that genuinely cause compile errors +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*signalprocessing.*") +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*graphtheory.*") + +# Demo files +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*-demo.*") +list(FILTER GIAC_SOURCES EXCLUDE REGEX ".*minigiac.*") + +# โ”€โ”€โ”€ BUILD THE LIBRARY โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + add_library(giac SHARED ${CMAKE_CURRENT_SOURCE_DIR}/giac_wrapper.cpp ${GIAC_SOURCES} ) +# โ”€โ”€โ”€ FIX FOR global.cc fread error โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +set_source_files_properties(${GIAC_ROOT}/src/giac/cpp/global.cc PROPERTIES COMPILE_FLAGS "-U_FORTIFY_SOURCE") + target_compile_definitions(giac PRIVATE HAVE_CONFIG_H=1 NO_GNUPLOT=1 - NO_PARI=1 NO_FLTK=1 ANDROID=1 GIAC_COUT=0 + _POSIX_C_SOURCE=200809L + _GNU_SOURCE + GIAC_GGB=1 ) target_compile_options(giac PRIVATE @@ -37,12 +90,22 @@ target_compile_options(giac PRIVATE -fexceptions -frtti -Wno-unused-function + -include unistd.h + -Wno-c++11-narrowing ) find_library(log-lib log) find_library(m-lib m) +# โ”€โ”€โ”€ Prebuilt GMP + MPFR โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +add_library(gmp STATIC IMPORTED) +add_library(mpfr STATIC IMPORTED) +set_target_properties(gmp PROPERTIES IMPORTED_LOCATION ${GIAC_PREBUILT_DIR}/libgmp.a) +set_target_properties(mpfr PROPERTIES IMPORTED_LOCATION ${GIAC_PREBUILT_DIR}/libmpfr.a) + target_link_libraries(giac + mpfr + gmp ${log-lib} ${m-lib} ) diff --git a/android/app/src/main/cpp/giac b/android/app/src/main/cpp/giac deleted file mode 160000 index f9cde64..0000000 --- a/android/app/src/main/cpp/giac +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f9cde646f6b17537c5d4ff290c9a45d18743ee2e diff --git a/android/app/src/main/cpp/giac/.gitignore b/android/app/src/main/cpp/giac/.gitignore new file mode 100644 index 0000000..d8e58ec --- /dev/null +++ b/android/app/src/main/cpp/giac/.gitignore @@ -0,0 +1,6 @@ +/local.properties +.gradle +.idea +.gems +build +/cbuild64/ diff --git a/android/app/src/main/cpp/giac/.npmignore b/android/app/src/main/cpp/giac/.npmignore new file mode 100644 index 0000000..87e3ea2 --- /dev/null +++ b/android/app/src/main/cpp/giac/.npmignore @@ -0,0 +1,14 @@ +.gradle +.npmignore +.svn +ANDROID_README +build +build.gradle +giac-android +giac-gwt +gradle-scripts +LINUX_README +settings.gradle +node_modules +local.properties +emsdk diff --git a/android/app/src/main/cpp/giac/.npmrc b/android/app/src/main/cpp/giac/.npmrc new file mode 100644 index 0000000..65e970e --- /dev/null +++ b/android/app/src/main/cpp/giac/.npmrc @@ -0,0 +1 @@ +//registry.npmjs.org/:_authToken=${NPM_PSW} \ No newline at end of file diff --git a/android/app/src/main/cpp/giac/ANDROID_README.md b/android/app/src/main/cpp/giac/ANDROID_README.md new file mode 100644 index 0000000..8f046b4 --- /dev/null +++ b/android/app/src/main/cpp/giac/ANDROID_README.md @@ -0,0 +1,74 @@ +This tutorial explains how to create Linux -> android-eabi, android-x86 +cross compilers and compile the Giac library. The tutorial has been +tested on Kubuntu 14.04, Ubuntu 14.10 and Ubuntu 16.04 systems. + +Prerequisites +------------- + +1. Download Crystax NDK 10.2.1 from https://crystax.net/en/download. You may need about 2 GB free space. + +2. Unpack the contents to ~/android-sdks/. Note that you need about 8 GB extra free space. + +3. Set the enviroment variables: + ``` + NDK_DIR=~/android-sdks/crystax-ndk-10.2.1 + CC_DIR=~/cross-compilers + ``` +4. Set + ``` + ARCH=arm + HOST=arm-linux-androideabi + ``` +5. Run + ``` + $NDK_DIR/build/tools/make-standalone-toolchain.sh --ndk-dir=$NDK_DIR --arch=$ARCH --platform=android-21 --install-dir=$CC_DIR/$ARCH + ``` +6. Type + ``` + export PATH=$CC_DIR/$ARCH/bin/:$PATH + ``` +7. Optionally check out GMP and MPFR and make them with the following command (for versions see src/jni/prebuilt/android/README.txt): + ``` + CFLAGS="-fPIC" ./configure --host=$HOST --prefix=$CC_DIR/$ARCH/sysroot/usr --disable-assembly && make && make install + ``` + This step requires additional 300-500 MB disk space. + +8. The static and shared libraries can be found in `$CC_DIR/$ARCH/sysroot/usr/lib` + +9. Repeat the steps 4-8 above but instead in step 4 use + ``` + ARCH=x86 + HOST=i686-linux-android + ``` + +10. Repeat the steps 4-8 above but instead in step 4 use + ``` + ARCH=x86_64 + HOST=x86_64-linux-android + ``` + +11. Repeat the steps 4-8 above but instead in step 4 use + ``` + ARCH=arm64 + HOST=aarch64-linux-android + ``` + +11. Now you may remove the `$NDK_DIR` folder and save some disk space. + +Compilation +----------- + +1. Make sure that the `PATH` variable is properly set (see step 6 above). + +2. Run + ``` + ../gradlew androidAar + ``` + in this directory. + +Troubleshooting +--------------- + +You may need to create the file `local.properties` on your own +with `sdk.dir=/path/to/android/sdk` if you don't want to set the +`ANDROID_SDK` variable manually. diff --git a/android/app/src/main/cpp/giac/CMakeLists.txt b/android/app/src/main/cpp/giac/CMakeLists.txt new file mode 100644 index 0000000..5110515 --- /dev/null +++ b/android/app/src/main/cpp/giac/CMakeLists.txt @@ -0,0 +1,314 @@ +# This file has been tested on Linux, Mac and Windows. +# +# Note that the source tree comes with prebuilt versions +# of GMP and MPFR for a large variety of platforms +# and they are used by default. This helps in linking +# Giac as much statically as possible and improves +# portability. If you don't want this, change +# ${GMP_STATIC} to gmp and ${MPFR_STATIC} to mpfr. +# +# If you use the default setting (the static option), +# you don't need the prerequisities gmp and mpfr below. +# +# This build machinery does not use config.h. Instead, +# all definitions are given explicitly. +# +# Building on Linux and Mac +# ------------------------- +# +# Install cmake, make, gmp and mpfr: On Linux, use the standard +# packaging tool -- on Mac use Homebrew. Then issue +# "mkdir build; cd build; cmake ..; make". +# +# Building on Windows +# ------------------- +# +# Use MSYS2 with CLANG64 flavor. Necessary packages are: +# +# * base-devel +# * mingw-w64-clang-x86_64-cc +# * mingw-w64-clang-x86_64-gmp +# * mingw-w64-clang-x86_64-mpfr +# * mingw-w64-clang-x86_64-cmake +# * mingw-w64-clang-x86_64-make +# +# Install them via "pacman -S ...". Then issue +# "mkdir build; cd build; CC=clang CXX=clang++ cmake -G "MinGW Makefiles" ..; mingw32-make". +# +# For a 32-bit build the CLANG32 flavor must be used, and instead of "x86_64" "i686" must be set. + +cmake_minimum_required(VERSION 3.10) +project(minigiac) + +if(UNIX AND NOT APPLE) + set(LINUX TRUE) +endif() + +# Detection of gmp/mpfr could be done via find_package, but this +# seems unsupported. + +# We link GMP and MPFR statically to the JNI/DLL. This may break MPFR +# in some cases, see https://www.mpfr.org/faq.html#undef_ref1 if +# you encounter strange bugs. + +function(find_static_library LIB_NAME OUT VENDOR_PATH) + + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + + find_library( + FOUND_${LIB_NAME}_STATIC + ${LIB_NAME} + NO_DEFAULT_PATH + PATHS ${VENDOR_PATH} + ) + + if (FOUND_${LIB_NAME}_STATIC) + get_filename_component(ABS_FILE ${FOUND_${LIB_NAME}_STATIC} ABSOLUTE) + else() + message(SEND_ERROR "Unable to find library ${LIB_NAME} in ${VENDOR_PATH}") + endif() + + set(${OUT} ${ABS_FILE} PARENT_SCOPE) + +endfunction() + +# Use prebuilt versions of GMP and MPFR to support static linking. + +set(PREBUILT_DIR ${CMAKE_SOURCE_DIR}/src/jni/prebuilt) + +if(LINUX) + message(STATUS "Using prebuilt gmp/mpfr (Linux)") + find_static_library(gmp GMP_STATIC ${PREBUILT_DIR}/linux/x86-64/) + find_static_library(mpfr MPFR_STATIC ${PREBUILT_DIR}/linux/x86-64/) +endif() + +if(APPLE) + message(STATUS "Using prebuilt gmp/mpfr (Mac)") + find_static_library(gmp GMP_STATIC ${PREBUILT_DIR}/maccatalyst/x86_64/) + find_static_library(mpfr MPFR_STATIC ${PREBUILT_DIR}/maccatalyst/x86_64/) +endif() + +if(WIN32) + if("$ENV{MSYSTEM}" STREQUAL "CLANG64") + message(STATUS "Using prebuilt gmp/mpfr for clang64") + find_static_library(gmp GMP_STATIC ${PREBUILT_DIR}/windows/clang64/) + find_static_library(mpfr MPFR_STATIC ${PREBUILT_DIR}/windows/clang64/) + endif() + if("$ENV{MSYSTEM}" STREQUAL "CLANG32") + message(STATUS "Using prebuilt gmp/mpfr for clang32") + find_static_library(gmp GMP_STATIC ${PREBUILT_DIR}/windows/clang32/) + find_static_library(mpfr MPFR_STATIC ${PREBUILT_DIR}/windows/clang32/) + endif() +endif() + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "-fpermissive -std=c++0x") + +set(GIAC_SOURCES + src/giac/cpp/alg_ext.cc + src/giac/cpp/cocoa.cc + src/giac/cpp/csturm.cc + src/giac/cpp/derive.cc + src/giac/cpp/desolve.cc + src/giac/cpp/ezgcd.cc + src/giac/cpp/freeglut_stroke_roman.c + src/giac/cpp/gauss.cc + src/giac/cpp/gausspol.cc + src/giac/cpp/gen.cc + src/giac/cpp/global.cc + src/giac/cpp/help.cc + src/giac/cpp/identificateur.cc + src/giac/cpp/ifactor.cc + src/giac/cpp/index.cc + src/giac/cpp/input_lexer.cc + src/giac/cpp/input_parser.cc + src/giac/cpp/intg.cc + src/giac/cpp/intgab.cc + src/giac/cpp/isom.cc + src/giac/cpp/lin.cc + src/giac/cpp/maple.cc + src/giac/cpp/mathml.cc + src/giac/cpp/misc.cc + src/giac/cpp/modfactor.cc + src/giac/cpp/modpoly.cc + src/giac/cpp/moyal.cc + src/giac/cpp/opengl.cc + src/giac/cpp/pari.cc + src/giac/cpp/permu.cc + src/giac/cpp/plot.cc + src/giac/cpp/plot3d.cc + src/giac/cpp/prog.cc + src/giac/cpp/quater.cc + src/giac/cpp/risch.cc + src/giac/cpp/rpn.cc + src/giac/cpp/series.cc + src/giac/cpp/solve.cc + src/giac/cpp/sparse.cc + src/giac/cpp/subst.cc + src/giac/cpp/sym2poly.cc + src/giac/cpp/symbolic.cc + src/giac/cpp/tex.cc + src/giac/cpp/threaded.cc + src/giac/cpp/ti89.cc + src/giac/cpp/tinymt32.cc + src/giac/cpp/TmpFGLM.cpp + src/giac/cpp/TmpLESystemSolver.cpp + src/giac/cpp/unary.cc + src/giac/cpp/usual.cc + src/giac/cpp/vecteur.cc + src/giac/headers/alg_ext.h + src/giac/headers/cocoa.h + # src/giac/headers/config.h + src/giac/headers/csturm.h + src/giac/headers/derive.h + src/giac/headers/desolve.h + src/giac/headers/dispatch.h + src/giac/headers/ezgcd.h + src/giac/headers/fac_table.h + src/giac/headers/fib_table.h + src/giac/headers/first.h + src/giac/headers/fits_s.h + src/giac/headers/fits_u.h + src/giac/headers/fraction.h + src/giac/headers/gauss.h + src/giac/headers/gausspol.h + src/giac/headers/gen.h + src/giac/headers/gen_inverse.h + src/giac/headers/giac.h + src/giac/headers/giacintl.h + src/giac/headers/giacPCH.h + src/giac/headers/global.h + src/giac/headers/gmp-mparam.h + src/giac/headers/gmp.h + src/giac/headers/gmp_replacements.h + src/giac/headers/gmpxx.h + src/giac/headers/help.h + src/giac/headers/identificateur.h + src/giac/headers/ieee_floats.h + src/giac/headers/ifactor.h + src/giac/headers/index.h + src/giac/headers/input_lexer.h + src/giac/headers/input_parser.h + src/giac/headers/intg.h + src/giac/headers/intgab.h + src/giac/headers/isom.h + src/giac/headers/lexer.h + src/giac/headers/lexer_tab_int.h + src/giac/headers/lin.h + src/giac/headers/longlong.h + src/giac/headers/maple.h + src/giac/headers/mathml.h + src/giac/headers/misc.h + src/giac/headers/modfactor.h + src/giac/headers/modpoly.h + src/giac/headers/monomial.h + src/giac/headers/moyal.h + src/giac/headers/mp_bases.h + src/giac/headers/mparam.h + src/giac/headers/mpf2mpfr.h + src/giac/headers/mpfr-gmp.h + src/giac/headers/mpfr-impl.h + src/giac/headers/mpfr-intmax.h + src/giac/headers/mpfr-longlong.h + src/giac/headers/mpfr-thread.h + src/giac/headers/mpfr.h + src/giac/headers/opengl.h + src/giac/headers/pari.h + src/giac/headers/path.h + src/giac/headers/permu.h + src/giac/headers/plot.h + src/giac/headers/plot3d.h + src/giac/headers/poly.h + src/giac/headers/prog.h + src/giac/headers/quater.h + src/giac/headers/risch.h + src/giac/headers/rpn.h + src/giac/headers/series.h + src/giac/headers/solve.h + src/giac/headers/sparse.h + src/giac/headers/static.h + src/giac/headers/static_extern.h + src/giac/headers/static_help.h + src/giac/headers/static_lexer.h + src/giac/headers/static_lexer_.h + src/giac/headers/subst.h + src/giac/headers/sym2poly.h + src/giac/headers/symbolic.h + src/giac/headers/tex.h + src/giac/headers/threaded.h + src/giac/headers/ti89.h + src/giac/headers/tinymt32.h + src/giac/headers/tinymt32_license.h + src/giac/headers/TmpFGLM.H + src/giac/headers/TmpLESystemSolver.H + src/giac/headers/trialdivtab.h + src/giac/headers/unary.h + src/giac/headers/usual.h + src/giac/headers/vecteur.h + src/giac/headers/vector.h +) + +include_directories(src/giac/headers) + +add_definitions(-DHAVE_NO_HOME_DIRECTORY -DGIAC_GGB -DIN_GIAC -DHAVE_LIB_PTHREAD + -DGIAC_GENERIC_CONSTANTS -DTIMEOUT -DSIZEOF_VOID_P=8 + -DHAVE_LIBMPFR -DVERSION="1.2.3") # Version number seems hardwired, FIXME. + +add_executable(minigiac + ${GIAC_SOURCES} + src/minigiac/cpp/minigiac.cc) + +# Note the order: MPFR must precede GMP! +target_link_libraries(minigiac ${MPFR_STATIC} ${GMP_STATIC}) +#target_link_libraries(minigiac mpfr gmp) # minigiac can also be built as a dynamic executable + +# JNI/DLL + +set(GIAC_DEF "") + +if(WIN32) + set(GIAC_DEF ${CMAKE_SOURCE_DIR}/src/jni/giac.def) +endif() + +add_library(javagiac SHARED + ${GIAC_SOURCES} + src/jni/cpp/giac_wrap.cxx + ${GIAC_DEF}) + +# Note the order: MPFR must precede GMP! +target_link_libraries(javagiac ${MPFR_STATIC} ${GMP_STATIC}) + +set_target_properties(javagiac PROPERTIES LINK_FLAGS -s) # strip + +target_include_directories(javagiac PUBLIC + ${CMAKE_SOURCE_DIR}/src/jni/jdkHeaders + ${CMAKE_SOURCE_DIR}/src/giac/headers) + +if(APPLE) + # Fix linking on 10.14+. See https://stackoverflow.com/questions/54068035 + # link_directories(/usr/local/lib) # This is necessary only if you use Homebrew's libs. + add_definitions(-DDONT_USE_LIBLAPLACK) + target_include_directories(javagiac PUBLIC + ${CMAKE_SOURCE_DIR}/src/jni/jdkHeaders/darwin) + # target_link_directories(javagiac PUBLIC /usr/local/lib) # Only for Homebrew's libs. + # target_link_directories(minigiac PUBLIC /usr/local/lib) # Only for Homebrew's libs. +endif() + +if(UNIX) + add_definitions(-DHAVE_SYS_TIMES_H -DHAVE_UNISTD_H -DHAVE_SYS_TIME_H -DHAVE_SYSCONF) +endif() + +if(LINUX) + target_include_directories(javagiac PUBLIC + ${CMAKE_SOURCE_DIR}/src/jni/jdkHeaders/linux) + target_link_options(javagiac PRIVATE -static-libgcc -static-libstdc++) +endif() + +if(WIN32) + add_definitions(-DGIAC_MPQS -D__MINGW_H -DMINGW32 -DHAVE_NO_SYS_TIMES_H + -DHAVE_NO_SYS_RESOURCE_WAIT_H -DHAVE_NO_PWD_H -DHAVE_NO_CWD -DNO_CLOCK + -Dusleep= -DYY_NO_UNISTD_H) + target_include_directories(javagiac PUBLIC + ${CMAKE_SOURCE_DIR}/src/jni/jdkHeaders/win) + target_link_options(javagiac PRIVATE -static-libgcc -static-libstdc++) +endif() \ No newline at end of file diff --git a/android/app/src/main/cpp/giac/Jenkinsfile b/android/app/src/main/cpp/giac/Jenkinsfile new file mode 100644 index 0000000..2c1b0cf --- /dev/null +++ b/android/app/src/main/cpp/giac/Jenkinsfile @@ -0,0 +1,87 @@ +pipeline { + agent none + options { + buildDiscarder(logRotator(numToKeepStr: '30')) + } + + stages { + stage('Mac, Windows binaries') { + parallel { + stage('Win') { + agent {label 'winbuild'} + environment { + MAVEN = credentials('maven-repo') + } + steps { + bat "C:\\msys64\\usr\\bin\\env.exe MSYSTEM=CLANG64 C:\\msys64\\usr\\bin\\bash -l -c \"cd ${env.WORKSPACE.replace('\\','/').replace('C:','/c')}; bash ./recompile-msys.sh cbuild64\"" + stash name: "giac-clang", includes: "cbuild*/**" + } + post { + always { deleteDir() } + } + } + stage('Mac') { + agent {label 'mac-mini'} + environment { + MAVEN = credentials('maven-repo') + } + stages { + stage('Mac JNI') { + steps { + sh "rm src/giac/cpp/kdisplay.cc" + sh "export ANDROID_SDK_ROOT=~/.android-sdk/; ./gradlew javagiacOsx_amd64SharedLibrary javagiacOsx_arm64SharedLibrary --info" + stash name: 'giac-mac', includes: 'build/binaries/javagiacSharedLibrary/osx_x86-64/libjavagiac.jnilib' + stash name: 'giac-mac-arm64', includes: 'build/binaries/javagiacSharedLibrary/osx_arm-v8/libjavagiac.jnilib' + } + } + stage('Objective C') { + steps { + sh ''' + export SVN_REVISION=`git log -1 | grep "\\S" | tail -n 1 | sed "s/.*@\\([0-9]*\\).*/\\1/"` + ./gradlew clean publishMavenZipPublicationToMavenRepository -Prevision=$SVN_REVISION''' + } + } + } + post { + always { deleteDir() } + } + } + } + } + stage('Build') { + parallel { + stage('Java and JS') { + agent {label 'deploy2'} + environment { + MAVEN = credentials('maven-repo') + ANDROID_SDK_ROOT='/var/lib/jenkins/.android-sdk' + EM_BINARYEN_ROOT="${env.WORKSPACE}/emsdk/upstream" + EMSDK_PYTHON='/usr/bin/python3.10' + NDK="$ANDROID_SDK_ROOT/ndk/28.0.12916984" + NDK_TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64" + PATH="$NDK_TOOLCHAIN/bin:$NDK_TOOLCHAIN/sysroot/usr/lib/arm-linux-androideabi:/var/lib/jenkins/glibc/build/elf:$PATH" + } + steps { + unstash name: 'giac-clang' + unstash name: 'giac-mac' + unstash name: 'giac-mac-arm64' + sh "rm src/giac/cpp/kdisplay.cc" + sh ''' + export SVN_REVISION=`git log -1 | grep "\\S" | tail -n 1 | sed "s/.*@\\([0-9]*\\).*/\\1/"` + ./gradlew downloadEmsdk installEmsdk activateEmsdk + ./gradlew :emccClean :giac-gwt:publish --no-daemon -Prevision=$SVN_REVISION --refresh-dependencies + ./gradlew :updateGiac --no-daemon -Prevision=$SVN_REVISION --info''' + } + post { + always { deleteDir() } + } + } + } + } + } + post { + always { + cleanAndNotify("#giac") + } + } +} \ No newline at end of file diff --git a/android/app/src/main/cpp/giac/LINUX_README b/android/app/src/main/cpp/giac/LINUX_README new file mode 100644 index 0000000..4fe7aa0 --- /dev/null +++ b/android/app/src/main/cpp/giac/LINUX_README @@ -0,0 +1,42 @@ +This short tutorial explains how to create a command line driven Linux +version of Giac. The steps below have been tested under Linux Mint 17.2, +Ubuntu Linux 14.04 16.04 and 18.04. + +Prerequisites +------------- + +Install the packages build-essential, libgmp-dev and libmpfr-dev. + +Compilation and running +----------------------- + +1. Enter + + $ ../gradlew run + +2. After a successful compilation you should see something like + + Press CTRL-D to stop + > Building 85% > :run + + Here you can type some examples and exit with CTRL-D. + +Troubleshooting +--------------- + +You may want to remove the line "include giac-android" from the file +settings.gradle in order to avoid installing the whole Android SDK. +Also remove the tasks "androidCopyCrystaxSo" and "androidAar" from +the file build.gradle. + +Alternatively, you can completely remove the file settings.gradle. +Also, the file ../settings.gradle should be removed for Gradle 5.x. + +If you used git to check the source out, you need to put a symlink +on ../gradle-scripts/. + +Debugging in an IDE +------------------- + +Use CLion to import the file CMakeLists.txt. Then put breakpoints to +various points you like (you may start with minigiac.cc). diff --git a/android/app/src/main/cpp/giac/README.md b/android/app/src/main/cpp/giac/README.md new file mode 100644 index 0000000..6f0d593 --- /dev/null +++ b/android/app/src/main/cpp/giac/README.md @@ -0,0 +1,10 @@ +# Giac, a free computer algebra system # + +This repository provides a mirror for +[Giac](https://www-fourier.ujf-grenoble.fr/~parisse/giac.html). +It contains build scripts for compiling the C++ code to binaries (with Java, Android and iOS wrappers), +and to WebAssembly using [Emscripten](https://emscripten.org/) (also including a GWT wrapper). + +The repository also includes a NodeJS port (https://www.npmjs.com/package/giac) that is no longer actively updated. + +In case you want to share any feedback or bug reports please use [the Giac / XCAS forum](https://xcas.univ-grenoble-alpes.fr/forum/). diff --git a/android/app/src/main/cpp/giac/binding.gyp b/android/app/src/main/cpp/giac/binding.gyp new file mode 100644 index 0000000..a7f5cac --- /dev/null +++ b/android/app/src/main/cpp/giac/binding.gyp @@ -0,0 +1,120 @@ +{ + "targets": [ + { + "target_name": "giac", + "sources" : [ "'src/giac/cpp/'+f).join(' ')\")", + "src/nodegiac/cpp/nodegiac.cc" ], + "include_dirs": ['src/giac/headers'], + # Common defines: + "defines" : [ + "GIAC_GGB", + 'VERSION="1.2.3"', + "IN_GIAC", + "HAVE_SYSCONF", + "HAVE_NO_HOME_DIRECTORY", + "TIMEOUT", + 'HAVE_MPFR_1', + 'HAVE_LIBMPFR' + ], + 'conditions': [ + ['OS=="linux"', + { + "cflags_cc" : [ + "-fexceptions", "-fpermissive" + ], + "cflags_cc!" : [ + "-fno-rtti" + ], + 'link_settings': { + 'libraries': [ + '-lgmp', '-lmpfr' + ] + }, + "defines+" : [ "HAVE_LIBPTHREAD" ] + } + ], + ['OS!="win"', + { + "defines+" : [ + "GIAC_GENERIC_CONSTANTS", + "HAVE_UNISTD_H", + 'HAVE_SYS_TIMES_H', + 'HAVE_SYS_TIME_H', + ], + } + ], + ['OS=="mac"', + { + 'defines+': [ + 'NO_STDEXCEPT', + 'APPLE_SMART', + 'NO_GETTEXT', + 'CLANG' ], + 'link_settings': { + 'libraries': [ + '-lgmp', '-lmpfr' + ] + }, + 'xcode_settings': { 'GCC_ENABLE_CPP_RTTI': 'YES', + 'OTHER_CPLUSPLUSFLAGS' : ['-std=c++11', '-stdlib=libc++', "-Wno-narrowing", "-fexceptions"], + 'OTHER_LDFLAGS' : ['-L/opt/local/lib', # Assuming MacPorts is used to provide libgmp. + "-L$(LIBDIR)/." ] # But user defined LIBDIR is also allowed. (FIXME: this will use "/." if LIBDIR is empty.) + } + } + ], + ['OS=="win"', + { + 'conditions': [ + ['target_arch=="x64"', { + 'defines+': [ + 'x86_64' + ] + } + ] + ], + 'defines+': [ + '__VISUALC__', + 'HAVE_NO_SYS_TIMES_H', + 'HAVE_NO_PWD_H', + 'HAVE_NO_SYS_RESOURCE_WAIT_H', + 'HAVE_NO_CWD', + 'MS_SMART' + ], + 'link_settings': { + 'libraries': [ + '-lmpir.lib', '-lmpfr.lib' + ] + }, + "configurations": { + "Release": { + "msvs_settings": { + 'VCCLCompilerTool': { + 'RuntimeTypeInfo': 'true', + 'ExceptionHandling': 1, # /EHsc # seems to have no effect + }, + "VCLinkerTool": { + "AdditionalLibraryDirectories": [ + ".", "..", "$(LIBDIR)" ] + } + } + }, + # This is a bit ugly. We repeat the same settings here as for "Release". + "Debug": { + "msvs_settings": { + 'VCCLCompilerTool': { + 'RuntimeTypeInfo': 'true', + 'ExceptionHandling': 1, # /EHsc # seems to have no effect + }, + "VCLinkerTool": { + "AdditionalLibraryDirectories": [ + ".", "..", "$(LIBDIR)" ] + } + } + } + } + } + ] + ] + } + ] +} diff --git a/android/app/src/main/cpp/giac/build.gradle b/android/app/src/main/cpp/giac/build.gradle new file mode 100644 index 0000000..abf8a86 --- /dev/null +++ b/android/app/src/main/cpp/giac/build.gradle @@ -0,0 +1,1101 @@ +// Authors: +// Balazs Bencze , +// Zbynek Konecny , +// Zoltan Kovacs and +// Agoston Suto . +// Based on Bernard Parisse's original Makefiles and other scripts. + + +plugins { + id 'visual-studio' + id 'cpp' + id 'de.undercouch.download' version '4.0.3' + id 'maven-publish' +} + + +apply from: 'repositories.gradle' + +project.setDescription('Giac CAS for GeoGebra') + + +/* + * For the impatient: Run "./gradlew downloadEmsdk installEmsdk activateEmsdk createGiacWasmJs" + * to compile the WebAssembly version via Emscripten. + * + * Emscripten related settings. + * + * Currently we use version 4.0.7, other versions may not work correctly, + * or may have problems in some Giac commands and results. + * + * 1. You will need to download the correct toolchain version by running the tasks downloadEmsdk, + * then optionally set EMSCRIPTEN_VERSION=tag-X.Y.Z, and run the task installEmsdk. + * (Always take care of using the correct emscripten version and also the appropriate clang compiler, + * otherwise you may encounter extremely strange problems on compilation time or runtime. + * Newer emscripten versions usually do sanity checks during the compilation and inform you + * about any issues.) This step may take a while since clang may be recompiled from source. + * (You may need additional tools to compile it including cmake.) + * + * 2. Hopefully you have the correct versions of GMP and MPFR in src/giac.js/prebuilt/. If not, you + * need to compile the correct version. The prebuilt libraries are compatible with the default Emscripten version. + * For other Emscripten versions you may have to recompile them from source using these tasks: emConfigureGmp, + * emMakeGmp, emConfigureMpfr, emMakeMpfr. These tasks are not executed as part of the build by default + * and may not even be compatible with the default Emscripten version. (The correct GMP and MPFR versions can be tested + * by entering some big integer/real computations.) First you may need to set some environmental + * variables or hardcoded script variables manually. FIXME + * The compilation can be influenced by using the environmental variable EXT_GMPMPFR (local/emgiac). + * + * 3. Run the createGiacWasmJs task. It will recompile all C++ files and then re-link the library. + * It can be fine-tuned by using the EMSCRIPTEN_VERSION environmental variables + * (but usually not required to use them). That, is you usually need the following command line: + * + * $ EMSCRIPTEN_VERSION=tag-X.Y.Z ../gradlew clean activateEmsdk createGiacWasmJs + * + * This command line will work only after you already ran downloadEmsdk and installEmsdk + * (as described above). + */ + +// FIXME: Some of these settings are hardcoded at the moment, they need to be more general. +def externalSourceDir = "/data/jenkins/ws" +// You may need to download and unzip following packages: +def gmpSourceDir = "$externalSourceDir/gmp-6.3.0" +def mpfrSourceDir = "$externalSourceDir/mpfr-4.2.1" + +def jsPrebuiltDir = "src/giac.js/prebuilt" +def LlvmMpfrA = "$jsPrebuiltDir/libmpfr.a" +def LlvmGmpA = "$jsPrebuiltDir/libgmp.a" + +def emsdkDir = file('emsdk') +def emsdkRunDir = file("$emsdkDir") + +def emscriptenVersion = 'tag-4.0.7' +if (System.env['EMSCRIPTEN_VERSION'] != null) { + emscriptenVersion = System.env['EMSCRIPTEN_VERSION'] +} +def emscriptenDir = file("$emsdkRunDir/emscripten/latest") + +def emccCommand = "${emscriptenDir}/emcc" + +// End of emscripten related settings. Huh. +def java_home = org.gradle.internal.jvm.Jvm.current().javaHome +ext.ggrev = project.findProperty("revision") ?: "SNAPSHOT" +def giacVersion = '"1.2.4-' + ggrev + '"' +println giacVersion +import org.apache.tools.ant.taskdefs.condition.Os +def isMac = Os.isFamily(Os.FAMILY_MAC) + +def exec_(String... script) { + if (!Os.isFamily(Os.FAMILY_MAC)) { + return "" + } + def retVal + exec { + commandLine script + standardOutput = new ByteArrayOutputStream() + retVal = { + standardOutput.toString().trim() + } + } + return retVal() +} + +def gccBin = exec_("xcrun", "--sdk", "macosx", "--find", "gcc") +def gccPath = "/usr/bin" +if (gccBin.length() > 0) { + gccPath = gccBin.substring(0, gccBin.lastIndexOf("/")) +} +def clangMacosxBin = exec_("xcrun", "--sdk", "macosx", "--find", "clang") +ext.clangMacosxPath = "/usr/bin" +if (clangMacosxBin.length() > 0) { + ext.clangMacosxPath = clangMacosxBin.substring(0, clangMacosxBin.lastIndexOf("/")) +} +def clangIosBin = exec_("xcrun", "--sdk", "iphoneos", "--find", "clang++") +ext.clangIosPath = "/usr/bin" +if (clangIosBin.length() > 0) { + ext.clangIosPath = clangIosBin.substring(0, clangIosBin.lastIndexOf("/")) +} +def clangIphonesimulatorBin = exec_("xcrun", "--sdk", "iphonesimulator", "--find", "clang++") +ext.clangIphonesimulatorPath = "/usr/bin" +if (clangIphonesimulatorBin.length() > 0) { + ext.clangIphonesimulatorPath = clangIphonesimulatorBin.substring(0, clangIphonesimulatorBin.lastIndexOf("/")) +} + +def macosSdk = exec_("xcrun", "--sdk", "macosx", "--show-sdk-path") +def iphoneosSdk = exec_("xcrun", "--sdk", "iphoneos", "--show-sdk-path") +def iphonesimulatorSdk = exec_("xcrun", "--sdk", "iphonesimulator", "--show-sdk-path") +def minIosVersion = '9.0' + +def simulatorPostfix = "-simulator" +def catalystPostfix = "-macabi" +def iosTarget(arch, minIosVersion, postfix = "") { + return "${arch}-apple-ios${minIosVersion}${postfix}" +} + +def iosClangCompilerArgs(args, sdk, arch, minIosVersion, target) { + appleCompilerArgs(args) + for (int i = args.size() - 1; i >= 0; i--) { + if (args[i].equals("-nostdinc")) { + args.remove(i) + } + } + args << "-isysroot" + args << "${sdk}" + args << "-target" + args << target + args << "-miphoneos-version-min=${minIosVersion}" + args << "-std=gnu++11" + args << "-stdlib=libc++" + args << "-fembed-bitcode" + args << "-O0" +} + +def giacCommonDefines(cppCompiler) { + cppCompiler.define "GIAC_GGB" + cppCompiler.define "IN_GIAC" + cppCompiler.define "GIAC_GENERIC_CONSTANTS" + cppCompiler.define "HAVE_UNISTD_H" + cppCompiler.define "HAVE_LIBPTHREAD" + cppCompiler.define "HAVE_SYSCONF" + cppCompiler.define "HAVE_NO_HOME_DIRECTORY" + cppCompiler.define "VERSION", '"dummy"' // will be overwritten later, see below + cppCompiler.define "TIMEOUT" + cppCompiler.define 'HAVE_SYS_TIMES_H' + cppCompiler.define 'HAVE_SYS_TIME_H' +} + +def giacIosDefines(cppCompiler) { + cppCompiler.define 'APPLE_SMART' + cppCompiler.define 'NO_GETTEXT' + cppCompiler.define 'NO_SCANDIR' + cppCompiler.define 'OSX_10_9_CXX' + cppCompiler.define 'HAVE_CONFIG_H' + cppCompiler.define '_IOS_FIX_' +} + +def giacSpecificSettings(cppCompiler, linker, targetPlatform) { + cppCompiler.define 'IN_GIAC' + cppCompiler.define 'GIAC_GENERIC_CONSTANTS' + cppCompiler.define 'HAVE_CONFIG_H' + cppCompiler.define 'GIAC_GGB' + cppCompiler.define 'TIMEOUT' + cppCompiler.args '-fexceptions' + cppCompiler.args '-O2' // standard optimization (default) + cppCompiler.args '-I.' + + // Architecture based settings: + if (targetPlatform.architecture.name == 'i386') { + cppCompiler.define 'SMARTPTR64' + cppCompiler.define 'SIZEOF_LONG', '8' + } else { + cppCompiler.define 'SIZEOF_LONG', '4' + } + // OS based settings: + if (targetPlatform.operatingSystem.name == 'windows') { + cppCompiler.define 'GIAC_MPQS' + cppCompiler.define '__MINGW_H' + cppCompiler.define 'MINGW32' + cppCompiler.define 'HAVE_NO_SYS_TIMES_H' + cppCompiler.define 'HAVE_NO_SYS_RESOURCE_WAIT_H' + cppCompiler.define 'HAVE_NO_PWD_H' + cppCompiler.define 'HAVE_NO_CWD' + cppCompiler.define 'NO_CLOCK' + cppCompiler.define 'usleep','' + cppCompiler.define 'YY_NO_UNISTD_H' + + cppCompiler.args '-I', file('src/jni/jdkHeaders/win').toString() + // Insert prebuilt libraries + linker.args '-Wl,--add-stdcall-alias' + linker.args '-s' // stripping + + // Add libgcc and libstdc++ statically + linker.args '-static-libgcc' + linker.args '-static-libstdc++' + // Statically link libpthread + // linker.args '-Wl,-Bstatic', '-lstdc++', '-lpthread' + // Or even better, everything + linker.args '-static' + } + + if (targetPlatform.operatingSystem.name == 'linux') { + if (targetPlatform.architecture.name == 'arm-v7') { + cppCompiler.define 'HAVE_GETTEXT' + linker.args '-lstdc++' + } + + + cppCompiler.define 'HAVE_UNISTD_H' + cppCompiler.define 'SIZEOF_VOID_P', '8' + + cppCompiler.args '-I', file('src/jni/jdkHeaders/linux').toString() + cppCompiler.args '-fno-strict-aliasing' // maybe not needed + cppCompiler.args '-DPIC' // maybe not needed + cppCompiler.args '-fpermissive' + + linker.args '-s' // stripping + + // Add libgcc and libstdc++ statically + linker.args '-static-libgcc' + linker.args '-static-libstdc++' + + } + if (targetPlatform.operatingSystem.name == 'android') { + cppCompiler.define 'HAVE_UNISTD_H' + cppCompiler.define 'NO_BSD' + + cppCompiler.args '-I', file('src/jni/jdkHeaders/linux').toString() + // overwrite standard headers with custom android headers + cppCompiler.args '-iquote', file("src/giac/headers/android/${targetPlatform.architecture.name}").toString() + cppCompiler.args '-fno-strict-aliasing' // maybe not needed + cppCompiler.args '-DPIC' // maybe not needed + cppCompiler.args '-fPIC' // android 6.0 doesn't load libraries which have text relocations + + linker.args '-s' // stripping + } + + if (targetPlatform.operatingSystem.name == 'osx') { + cppCompiler.define 'HAVE_UNISTD_H' + cppCompiler.define 'APPLE_SMART' + cppCompiler.define 'NO_SCANDIR' + cppCompiler.define 'HAVE_SYS_TIMES_H' + cppCompiler.define 'HAVE_SYS_TIME_H' + cppCompiler.args '-stdlib=libc++' + + linker.args '-Wl,-search_paths_first' + linker.args '-L', file("src/jni/prebuilt/osx/${targetPlatform.architecture.name}").toString() + + linker.args '-stdlib=libc++', '-lc++' + linker.args '-lgmp', '-lmpfr', '-lpthread', '-dynamiclib' + linker.args '-framework', 'Accelerate' + linker.args '-framework', 'CoreFoundation' + } +} + +def appleCompilerArgs(args) { + // Gradle is including "sensible default" include paths that are based on the host OS that break cross-compilation + // The only fix as I see it is to clear out all includes except the ones that point to protos + // SEE https://github.com/gradle/gradle-native/issues/614 + // isystem args also removed, see https://github.com/gradle/gradle-native/issues/583 + for (int i = args.size() - 1; i >= 0; i--) { + if ((args[i].equals("-I") || args[i].equals("-isystem")) && !args[i+1].startsWith("$rootDir")) { + args.remove(i + 1) + args.remove(i) + } + } +} + +def macosCompilerArgs(args, target) { + appleCompilerArgs(args) + if (target != null) { + args << '-target' + args << target + } + args << '-mmacosx-version-min=10.7' + args << "-isysroot" + args << '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk' + args << '-stdlib=libc++' + args << '-std=c++11' + args << '-I/System/Library/Frameworks/CoreFoundation.framework/Headers' + args << '-I' + args << file('src/jni/jdkHeaders/darwin').toString() +} + +model { + repositories { + libs(PrebuiltLibraries) { + mpfr { + binaries.withType(StaticLibraryBinary) { + def arch = targetPlatform.architecture.name + def os = targetPlatform.operatingSystem.name + staticLibraryFile = file("src/jni/prebuilt/$os/$arch/libmpfr.a") + } + } + gmp { + binaries.withType(StaticLibraryBinary) { + def arch = targetPlatform.architecture.name + def os = targetPlatform.operatingSystem.name + staticLibraryFile = file("src/jni/prebuilt/$os/$arch/libgmp.a") + } + } + } + } + + platforms { + win64 { + architecture 'x64' + operatingSystem 'windows' + } + linux64 { + architecture 'x64' + operatingSystem 'linux' + } + rpi { + architecture 'arm' + operatingSystem 'linux' + } + osx_amd64 { + architecture 'amd64' + operatingSystem 'osx' + } + osx_arm64 { + architecture 'arm64' + operatingSystem 'osx' + } + androideabi { + architecture 'arm' + operatingSystem 'android' + } + androidx86 { + architecture 'x86' + operatingSystem 'android' + } + androidx86_64 { + architecture 'x86_64' + operatingSystem 'android' + } + androidarm64 { + architecture 'arm64' + operatingSystem 'android' + } + ios_arm64 { + architecture 'arm64' + operatingSystem 'ios' + } + iphonesimulator_x86_64 { + architecture 'x86_64' + operatingSystem 'iphonesimulator' + } + iphonesimulator_arm64 { + architecture 'x86_64' + operatingSystem 'iphonesimulator' + } + maccatalyst_x86_64 { + architecture 'x86_64' + operatingSystem 'maccatalyst' + } + maccatalyst_arm64 { + architecture 'arm64' + operatingSystem 'maccatalyst' + } + } + + toolChains { + mingw(Gcc) { + target('win64') { + cppCompiler.executable 'x86_64-w64-mingw32-g++' + linker.executable 'x86_64-w64-mingw32-g++' + } + } + gcc(Gcc) { + target('rpi') { + cppCompiler.executable 'gcc' + linker.executable 'gcc' + } + } + clang(Clang) { + target('osx_amd64') { + cppCompiler.executable 'clang' + linker.executable 'gcc' + path gccPath, clangMacosxPath + + cppCompiler.withArguments { args -> + macosCompilerArgs(args, 'x86_64-apple-macos11') + } + linker.withArguments { args -> + args << '--target=x86_64-apple-macos11' + args << '-std=c++11' + } + } + target('osx_arm64') { + cppCompiler.executable 'clang' + linker.executable 'gcc' + path gccPath, clangMacosxPath + + cppCompiler.withArguments { args -> + macosCompilerArgs(args, 'arm64-apple-macos11') + } + linker.withArguments { args -> + args << '--target=arm64-apple-macos11' + } + } + target('ios_arm64') { + cppCompiler.executable 'clang' + cppCompiler.withArguments { args -> + iosClangCompilerArgs(args, iphoneosSdk, "arm64", minIosVersion, iosTarget("arm64", minIosVersion)) + } + path clangIosPath + } + target('iphonesimulator_x86_64') { + cppCompiler.executable 'clang' + cppCompiler.withArguments { args -> + iosClangCompilerArgs(args, iphonesimulatorSdk, "x86_64", minIosVersion, iosTarget("x86_64", minIosVersion, simulatorPostfix)) + } + path clangIphonesimulatorPath + } + target('iphonesimulator_arm64') { + cppCompiler.executable 'clang' + cppCompiler.withArguments { args -> + iosClangCompilerArgs(args, iphonesimulatorSdk, "arm64", minIosVersion, iosTarget("arm64", minIosVersion, simulatorPostfix)) + } + path clangIphonesimulatorPath + } + target('maccatalyst_x86_64') { + cppCompiler.executable 'clang' + cppCompiler.withArguments { args -> + iosClangCompilerArgs(args, macosSdk, "x86_64", minIosVersion, iosTarget("x86_64", "14.0", catalystPostfix)) + } + path clangMacosxPath + + } + target('maccatalyst_arm64') { + cppCompiler.executable 'clang' + cppCompiler.withArguments { args -> + iosClangCompilerArgs(args, macosSdk, "arm64", minIosVersion, iosTarget("arm64", "14.0", catalystPostfix)) + } + path clangMacosxPath + } + + } + // Note: Make sure manually that these executables are on the PATH. + android(Clang) { + target('androideabi') { + cppCompiler.executable 'armv7a-linux-androideabi35-clang++' + linker.executable 'armv7a-linux-androideabi35-clang++' + } + target('androidx86') { + cppCompiler.executable 'i686-linux-android35-clang++' + linker.executable 'i686-linux-android35-clang++' + } + target('androidx86_64') { + cppCompiler.executable 'x86_64-linux-android35-clang++' + linker.executable 'x86_64-linux-android35-clang++' + } + target('androidarm64') { + cppCompiler.executable 'aarch64-linux-android35-clang++' + linker.executable 'aarch64-linux-android35-clang++' + } + } + } + + components { + // giac static libary + giac(NativeLibrarySpec) { + targetPlatform 'linux64' + targetPlatform 'ios_arm64' + targetPlatform 'iphonesimulator_x86_64' + targetPlatform 'iphonesimulator_arm64' + targetPlatform 'maccatalyst_x86_64' + targetPlatform 'maccatalyst_arm64' + if (isMac) { + targetPlatform 'osx_amd64' + targetPlatform 'osx_arm64' + } + targetPlatform 'rpi' + + binaries.all { + giacCommonDefines(cppCompiler) + giacSpecificSettings(cppCompiler, linker, targetPlatform) + if (targetPlatform.operatingSystem.name == 'ios' + || targetPlatform.operatingSystem.name == 'iphonesimulator' + || targetPlatform.operatingSystem.name == 'maccatalyst') { + giacIosDefines(cppCompiler) + if (targetPlatform.architecture.name == 'arm-v8') { + cppCompiler.define 'x86_64' + } + } else if (targetPlatform.operatingSystem.name == 'osx') { + cppCompiler.define 'NO_GETTEXT' + } + cppCompiler.args '-fpermissive' // needed for recent G++ + } + } + + simpleInterface(NativeLibrarySpec) { + targetPlatform 'ios_arm64' + targetPlatform 'iphonesimulator_x86_64' + targetPlatform 'iphonesimulator_arm64' + targetPlatform 'maccatalyst_x86_64' + targetPlatform 'maccatalyst_arm64' + + binaries.all { + lib library: 'giac', linkage: 'static' + giacCommonDefines(cppCompiler) + if (targetPlatform.operatingSystem.name == 'ios' + || targetPlatform.operatingSystem.name == 'iphonesimulator') { + giacIosDefines(cppCompiler) + if (targetPlatform.architecture.name == 'arm-v8') { + cppCompiler.define 'x86_64' + } + } + } + } + + minigiac(NativeExecutableSpec) { + targetPlatform 'linux64' + + binaries.all { + lib library: 'giac', linkage: 'static' + linker.args '-lgmp', '-lmpfr', '-lpthread' + cppCompiler.define 'GIAC_GGB' + cppCompiler.define 'IN_GIAC' + cppCompiler.define 'GIAC_GENERIC_CONSTANTS' + cppCompiler.define 'HAVE_CONFIG_H' + cppCompiler.define 'HAVE_UNISTD_H' + cppCompiler.define 'HAVE_SYS_TIMES_H' + cppCompiler.define 'HAVE_SYS_TIME_H' + cppCompiler.define 'VERSION', giacVersion + cppCompiler.args '-fpermissive' // needed for recent G++ + } + sources.all { + source { + srcDirs 'src/giac/cpp', 'src/minigiac/cpp' + } + } + } + + javagiac(NativeLibrarySpec) { + targetPlatform 'win64' + targetPlatform 'linux64' + if (isMac) { + targetPlatform 'osx_amd64' + targetPlatform 'osx_arm64' + } + targetPlatform 'androideabi' + targetPlatform 'androidx86' + targetPlatform 'androidx86_64' + targetPlatform 'androidarm64' + targetPlatform 'rpi' + + sources.cpp { + source { + srcDirs 'src/giac/cpp', 'src/jni/cpp' + } + exportedHeaders { + srcDirs 'src/giac/headers', 'src/jni/jdkHeaders' + } + lib library: 'mpfr', linkage: 'static' + lib library: 'gmp', linkage: 'static' + } + + binaries.withType(SharedLibraryBinarySpec) { + giacSpecificSettings(cppCompiler, linker, targetPlatform) + linker.args "-I${java_home}/include", "-Isrc/jni/jdkHeaders" + + if (targetPlatform.operatingSystem.name == 'osx') { + cppCompiler.define 'gettext', '' + def path = "build/binaries/javagiacSharedLibrary/osx_${targetPlatform.architecture.name}/" + mkdir(path) + linker.args '-o', "$path/libjavagiac.jnilib" // TODO: find a more elegant way + } + } + } + + GeoGebraCASDemo(NativeExecutableSpec) { + if (isMac) { + targetPlatform 'osx_amd64' + targetPlatform 'osx_arm64' + } + + binaries.all { + lib library: 'GeoGebraCAS', linkage: 'shared' + if (targetPlatform.operatingSystem.name == 'osx') { + cppCompiler.args '-stdlib=libc++' + linker.args '-stdlib=libc++', '-lc++' + if (targetPlatform.architecture.name == 'i386') { + cppCompiler.args '-m32' + linker.args '-m32' + } else if (targetPlatform.architecture.name == 'arm-v8') { + linker.args '-target', 'arm64-apple-macos11' + } + } else { + cppCompiler.args '/EHsc' + if (project.hasProperty("debugsymbols")) { + linker.args "/DEBUG" + } + } + } + sources.all { + lib library: 'GeoGebraCAS', linkage: 'shared' // maybe necessary only on Windows + source { + srcDirs 'src/GeoGebraCAS-demo/cpp' + } + exportedHeaders { + srcDirs 'src/GeoGebraCAS/headers' + } + } + } + + GeoGebraCAS(NativeLibrarySpec) { + if (isMac) { + targetPlatform 'osx_amd64' + targetPlatform 'osx_arm64' + } + + sources.cpp { + source { + srcDirs 'src/GeoGebraCAS/cpp' + } + exportedHeaders { + srcDirs 'src/GeoGebraCAS/headers', "src/giac/headers" + } + if (System.getProperty("os.name") != "Mac OS X") { + lib library: 'gmp', linkage: 'shared' + lib library: 'mpfr', linkage: 'shared' + } + lib library: 'giac', linkage: 'static' + } + + binaries.withType(SharedLibraryBinarySpec) { + if (targetPlatform.operatingSystem.name == 'osx') { + cppCompiler.args '-stdlib=libc++' + linker.args '-stdlib=libc++', '-lc++' + linker.args '-lgmp', '-lmpfr', '-lpthread' + linker.args '-L', file("src/jni/prebuilt/maccatalyst/${targetPlatform.architecture.name == "arm-v8" ? "arm64" : "x86_64"}").toString(), '-dynamiclib' + } + } + } + } +} + +def lipo(name, output, clangPath, String... libraries) { + def args = ["${clangPath}/lipo"] + libraries.flatten() + ["-create", "-output", "${output}/${name}.a"] + mkdir("${output}") + exec_(args as String[]) +} + +def mergeLibraries(name, output, clangPath, String... libraries) { + def args = ["${clangPath}/libtool", "-static", "-o", "${output}/${name}.a"] + args.addAll(libraries) + mkdir("${output}") + exec_(args as String[]) +} + +tasks.register('simpleInterfaceIosStaticLibrary') { + dependsOn('simpleInterfaceIos_arm64StaticLibrary', + 'simpleInterfaceIphonesimulator_x86_64StaticLibrary', + 'simpleInterfaceIphonesimulator_arm64StaticLibrary', + 'simpleInterfaceMaccatalyst_x86_64StaticLibrary', + 'simpleInterfaceMaccatalyst_arm64StaticLibrary') +} + +tasks.register('giacIosStaticLibrary') { + dependsOn('giacIos_arm64StaticLibrary', + 'giacIphonesimulator_x86_64StaticLibrary', + 'giacIphonesimulator_arm64StaticLibrary', + 'giacMaccatalyst_x86_64StaticLibrary', + 'giacMaccatalyst_arm64StaticLibrary') +} + +tasks.register('createFatIosStaticLibrary') { + dependsOn('simpleInterfaceIosStaticLibrary', 'giacIosStaticLibrary') + doLast { + def output = "${buildDir}/libs/merged" + ["arm64"].each { + mergeLibraries("Giac", "${output}/ios_${it}", clangIosPath, + "${buildDir}/libs/giac/static/ios_${it}/libgiac.a", + "${buildDir}/libs/simpleInterface/static/ios_${it}/libSimpleInterface.a", + "src/jni/prebuilt/ios/${it}/libgmp.a", + "src/jni/prebuilt/ios/${it}/libmpfr.a") + } + ["arm64", "x86_64"].each { + mergeLibraries("Giac", "${output}/iphonesimulator_${it}", clangIphonesimulatorPath, + "${buildDir}/libs/giac/static/iphonesimulator_${it}/libgiac.a", + "${buildDir}/libs/simpleInterface/static/iphonesimulator_${it}/libSimpleInterface.a", + "src/jni/prebuilt/iphonesimulator/${it}/libgmp.a", + "src/jni/prebuilt/iphonesimulator/${it}/libmpfr.a") + } + ["arm64", "x86_64"].each { + mergeLibraries("Giac", "${output}/maccatalyst_${it}", clangIphonesimulatorPath, + "${buildDir}/libs/giac/static/maccatalyst_${it}/libgiac.a", + "${buildDir}/libs/simpleInterface/static/maccatalyst_${it}/libSimpleInterface.a", + "src/jni/prebuilt/maccatalyst/${it}/libgmp.a", + "src/jni/prebuilt/maccatalyst/${it}/libmpfr.a") + } + + lipo("Giac", "${output}/ios", clangIosPath, "${output}/ios_arm64/Giac.a") + lipo("Giac", "${output}/iphonesimulator", clangIphonesimulatorPath, + "${output}/iphonesimulator_arm64/Giac.a", + "${output}/iphonesimulator_x86_64/Giac.a") + lipo("Giac", "${output}/maccatalyst", clangIphonesimulatorPath, + "${output}/maccatalyst_arm64/Giac.a", + "${output}/maccatalyst_x86_64/Giac.a") + } +} + +tasks.register('createIosFramework', Copy) { + dependsOn createFatIosStaticLibrary + description "Creates iOS framework" + from("${buildDir}/libs/merged/ios") { + include "Giac.a" + rename "Giac.a", "Giac" + into "Giac.framework" + } + from("src/simpleInterface/headers") { + include "*.hpp" + into "Giac.framework/Headers" + } + from("src/simpleInterface/framework") { + include "Info.plist" + into "Giac.framework/Resources" + } + + destinationDir = file("${buildDir}/libs/framework/ios") +} + +tasks.register('createIphonesimulatorFramework', Copy) { + dependsOn createFatIosStaticLibrary + description "Creates iPhone Simlator framework" + from("${buildDir}/libs/merged/iphonesimulator") { + include "Giac.a" + rename "Giac.a", "Giac" + into "Giac.framework" + } + from("src/simpleInterface/headers") { + include "*.hpp" + into "Giac.framework/Headers" + } + from("src/simpleInterface/framework") { + include "framework.plist" + rename "framework.plist", "Info.plist" + into "Giac.framework/Resources" + } + + destinationDir = file("${buildDir}/libs/framework/iphonesimulator") +} + +tasks.register('createMaccatalystFramework', Copy) { + dependsOn createFatIosStaticLibrary + description "Creates Mac Catalyst framework" + from("${buildDir}/libs/merged/maccatalyst") { + include "Giac.a" + rename "Giac.a", "Giac" + into "Giac.framework" + } + from("src/simpleInterface/headers") { + include "*.hpp" + into "Giac.framework/Headers" + } + + destinationDir = file("${buildDir}/libs/framework/maccatalyst") +} + + +tasks.register('createIosXcframework', Copy) { + dependsOn = [createIosFramework, createIphonesimulatorFramework, createMaccatalystFramework] + description "Creates XCFramework" + from("${buildDir}/libs/framework/iphonesimulator") { + into "ios-arm64_x86_64-simulator" + } + from("${buildDir}/libs/framework/ios") { + into "ios-arm64" + } + from("${buildDir}/libs/framework/maccatalyst") { + into "ios-arm64_x86_64-maccatalyst" + } + from("src/simpleInterface/framework") { + include "xcframework.plist" + rename "xcframework.plist", "Info.plist" + } + + destinationDir = file("${buildDir}/libs/framework/Giac.xcframework") +} + +tasks.register('cocoapodsZip', Zip) { + dependsOn 'createIosXcframework' + baseName 'Giac' + from("${buildDir}/libs/framework/Giac.xcframework") { + into "Frameworks/Giac.xcframework" + } + destinationDir = file("${buildDir}/cocoapods/") +} + +tasks.register('installMinigiacExecutable') { dependsOn 'installMinigiacLinux64Executable' } + +tasks.register('installNodegiacExecutable', Exec) { + // FIXME: dependencies should be set + description 'Installs the nodegiac executable.' + commandLine 'npm', 'install' +} + +tasks.register('testMinigiacExecutable', Exec) { + dependsOn 'installMinigiacExecutable' + description 'Tests the minigiac executable.' + workingDir 'src/test' + commandLine './regression', '-r' +} + +tasks.register('testNodegiacExecutable', Exec) { + dependsOn 'installNodegiacExecutable' + description 'Tests the nodegiac executable.' + workingDir 'src/test' + commandLine './regression', '-r', '-n' +} + +tasks.register('testExecutables') { + dependsOn = ['testNodegiacExecutable', 'testMinigiacExecutable'] +} + + +tasks.register('androidCopyEabiLibjavagiacSo', Copy) { + dependsOn 'javagiacAndroideabiSharedLibrary' + description 'Copies libjavagiac.so files to the src/android folder.' + from 'build/libs/javagiac/shared/androideabi' + into 'giac-android/src/main/jniLibs/armeabi-v7a' + include('libjavagiac.so') +} + +tasks.register('androidCopyX86LibjavagiacSo', Copy) { + dependsOn 'javagiacAndroidx86SharedLibrary' + description 'Copies libjavagiac.so files to the src/android folder.' + from 'build/libs/javagiac/shared/androidx86' + into 'giac-android/src/main/jniLibs/x86' + include('libjavagiac.so') +} + +tasks.register('androidCopyX86_64LibjavagiacSo', Copy) { + dependsOn 'javagiacAndroidx86_64SharedLibrary' + description 'Copies libjavagiac.so files to the src/android folder.' + from 'build/libs/javagiac/shared/androidx86_64' + into 'giac-android/src/main/jniLibs/x86_64' + include('libjavagiac.so') +} + +tasks.register('androidCopyArm64LibjavagiacSo', Copy) { + dependsOn 'javagiacAndroidarm64SharedLibrary' + description 'Copies libjavagiac.so files to the src/android folder.' + from 'build/libs/javagiac/shared/androidarm64' + into 'giac-android/src/main/jniLibs/arm64-v8a' + include('libjavagiac.so') +} + +tasks.register('run', Exec) { + dependsOn 'installMinigiacExecutable' + description "Runs Giac's minigiac terminal" + commandLine "build/install/minigiac/linux64/minigiac" // FIXME, this is hardcoded + standardInput = System.in +} + +def objDir = "build/objs/giac-wasm.js" +def binaryJsDir = "build/binaries/giacggb.wasm" + +tasks.addRule("Pattern: emccCompileWasm_Cc: Compile .cc into .o.") { String taskName -> + if ((taskName.startsWith('emccCompileWasm')) && (taskName.endsWith('Cc'))) { + def basename = (taskName - 'Cc').substring('emccCompileWasm_'.length()) + task(taskName) { + mustRunAfter 'activateEmsdk' + def input = "src/giac/cpp/${basename}.cc" + inputs.file input + def output = objDir + "/${basename}.o" + outputs.file output + doLast { + file(objDir+"/").mkdirs() + exec { + // Be very careful when changing this: config.h also contains some entries! + def specialOptions = '' + def commandline = emccCommand + commandline += ' -DIN_GIAC -DGIAC_GENERIC_CONSTANTS -DHAVE_CONFIG_H -fwasm-exceptions' // from old Makefile + commandline += ' -DVERSION=' + giacVersion + commandline += " -Dgammaf=tgammaf -s ALLOW_MEMORY_GROWTH=1" + commandline += " -s WASM=1 -s NO_EXIT_RUNTIME=1" + commandline += " -s PRECISE_I64_MATH=1 -Oz" // new setting + commandline += " -DHAVE_UNISTD_H" + commandline += ' -DGIAC_GGB' // from old Makefile + commandline += ' -DTIMEOUT -DEMCC2 ' // from old config.h + commandline += " -Isrc/giac/headers -c $input -o $output" + println "Compiling: ${commandline}" + commandLine commandline.split() + } + } + } + } +} + +tasks.register('emccClean', Delete) { + description 'Deletes .o files and linked giac*.js for cleaning up.' + delete objDir, binaryJsDir +} + + +tasks.register('emccCompileWasm') { + description 'Creates .o files for giac.js.' + def list = [] + FileTree files = fileTree(dir: 'src/giac/cpp') + files.visit { f -> + if (f.name.endsWith('.cc')) { + def emccCompileTask = 'emccCompileWasm' + "_" + f.name - '.cc' + 'Cc' + list << emccCompileTask + } + } + dependsOn list +} + +tasks.register('emccGiacJsWasm') { + dependsOn 'emccCompileWasm' + description 'Links giac.js.' + mustRunAfter 'emccCompileWasm' + def output = binaryJsDir + "/giacggb.js" + outputs.file output + doLast { + def list = [] + def linkerArgs = [] + def inputInclude = [] + FileTree files = fileTree(dir: objDir) + files.visit { f -> + def emccCompileTask = 'emccCompile_' + f.name - '.o' + 'Cc' + inputInclude << f.name + inputInclude << ('src/giac/cpp/' + f.name - '.o' + '.cc') + list << emccCompileTask + linkerArgs << objDir + "/${f.name}" + } + + file(binaryJsDir).mkdirs() + exec { + linkerArgs << LlvmMpfrA // mpfr must precede gmp, see http://www.mpfr.org/faq.html, Q5 + linkerArgs << LlvmGmpA + linkerArgs << '--js-library' << 'src/giac.js/js/time.js' + + linkerArgs << '-DGIAC_GGB' + linkerArgs << '-o' << output + // linkerArgs << "-s" << "DISABLE_EXCEPTION_CATCHING=0" + linkerArgs << '-Oz' << '-v' << '-s' << "EXPORTED_FUNCTIONS=['_caseval']" + linkerArgs << '-s' << 'EXPORTED_RUNTIME_METHODS=["cwrap"]' + + linkerArgs << '-s' << 'TOTAL_MEMORY=67108864' + linkerArgs << '-fwasm-exceptions' + // consider increasing this if running out of memory on GB computations + def linkerArgsString = linkerArgs.join(" ") + println "Linking: ${emccCommand} ${linkerArgsString}" + commandLine emccCommand + args linkerArgs + } + } +} + +tasks.register('createGiacGgbJsWasm', Copy) { + dependsOn 'emccGiacJsWasm' + description 'Creates the giacggb.js folder to store embeddable giac.js.' + from 'src/giac.js' + into binaryJsDir + include('ggb.html') +} + +tasks.register('createGiacWasmJs') { + dependsOn 'createGiacGgbJsWasm' + description 'Creates WebAssembly version of Giac which can be embedded into GeoGebraWeb.' + doLast { + exec { + commandLine "bash", "-c", "base64 -w0 giacggb.wasm > giacggb.wasm.b64" + workingDir binaryJsDir + } + def wasmBase64 = file("${binaryJsDir}/giacggb.wasm.b64").text + file("${binaryJsDir}/giac.wasm.js").text = file("${binaryJsDir}/giacggb.js").text + .replace('Module', '__ggb__giac').replace('"use asm";', '') + .replace('giacggb.wasm', "data:application/wasm;base64,${wasmBase64}") + } +} + +// Using emsdk + +tasks.register('downloadEmsdk') { + description 'Downloads emscripten SDK and downloads it.' + outputs.dir emsdkDir + doLast { + delete { + delete emsdkDir + } + exec { + commandLine 'git clone https://github.com/emscripten-core/emsdk.git'.split() + } + + ant.symlink(resource: emsdkDir, link: "${emsdkDir}/emsdk-portable") + mkdir("${emsdkDir}/emscripten") + ant.symlink(resource: "${emsdkDir}/upstream/emscripten", link: "${emsdkDir}/emscripten/latest") + } +} + +tasks.register('installEmsdk') { + description 'Installs/updates the emscripten SDK.' + mustRunAfter 'downloadEmsdk' + doLast { + exec { + commandLine 'git pull'.split() + workingDir emsdkRunDir + } + // FIXME: If already installed, this results in an error and stops. + // Below this may not work with older emscripten versions. + exec { + commandLine "./emsdk install sdk-${emscriptenVersion}-64bit".split() + workingDir emsdkRunDir + } + } +} + +tasks.register('activateEmsdk') { + description 'Activates the emscripten SDK.' + mustRunAfter 'installEmsdk' + doLast { + exec { + commandLine "./emsdk activate sdk-${emscriptenVersion}-64bit".split() + workingDir emsdkRunDir + } + } +} + +tasks.register('emConfigureGmp') { + description 'Configures GMP for the emscripten SDK.' + doLast { + exec { + commandLine 'bash', '-c', "source $emsdkRunDir/emsdk_env.sh; ${emscriptenDir}/emconfigure $gmpSourceDir/configure --build=none --host=none --disable-assembly" + workingDir gmpSourceDir + } + } +} + +tasks.register('emMakeGmp') { + description 'Makes GMP with the emscripten SDK.' + doLast { + exec { + commandLine 'bash', '-c', "source $emsdkRunDir/emsdk_env.sh; ${emscriptenDir}/emmake make" + workingDir gmpSourceDir + } + copy { + from("$gmpSourceDir/.libs/") + into(jsPrebuiltDir) + include("libgmp.a") + } + } +} + +tasks.register('emConfigureMpfr') { + description 'Configures MPFR for the emscripten SDK.' + doLast { + exec { + commandLine 'bash', '-c', "source $emsdkRunDir/emsdk_env.sh; " + + "${emscriptenDir}/emconfigure $mpfrSourceDir/configure " + + "--build=none --host=none --disable-assembly " + + "--with-gmp-lib=$gmpSourceDir/.libs --with-gmp-include=$gmpSourceDir" + workingDir mpfrSourceDir + } + } +} + +tasks.register('emMakeMpfr') { + description 'Makes MPFR with the emscripten SDK.' + doLast { + exec { + commandLine 'bash', '-c', "source $emsdkRunDir/emsdk_env.sh; ${emscriptenDir}/emmake make" + workingDir mpfrSourceDir + } + copy { + from("$mpfrSourceDir/src/.libs/") + into(jsPrebuiltDir) + include("libmpfr.a") + } + } +} + +tasks.register('androidAar') { + dependsOn = ['giac-android:copyLibcShared', 'androidCopyEabiLibjavagiacSo', + 'androidCopyX86LibjavagiacSo', 'androidCopyX86_64LibjavagiacSo', 'androidCopyArm64LibjavagiacSo', 'giac-android:assemble'] + description 'Creates .aar package' +} + +apply from: "deploy.gradle" diff --git a/android/app/src/main/cpp/giac/config.h b/android/app/src/main/cpp/giac/config.h new file mode 100644 index 0000000..1e22fe8 --- /dev/null +++ b/android/app/src/main/cpp/giac/config.h @@ -0,0 +1,49 @@ +// This file has been taylored after autogenerating it by the autoconf machinery. +// Which is, actually, no longer used. + +/* Additional settings or overrides should be put + * into build.gradle. This file should be considered as + * as a "common base" for all platforms. + */ + +/* Set if debugging is enabled */ +#define DEBUG_SUPPORT + +/* Name of package */ +#define PACKAGE "giac" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "giac" + +/* Define to the full name and version of this package. */ +#ifndef PACKAGE_STRING +#define PACKAGE_STRING "giac 1.2.3" +#endif + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "giac" + +/* Define to the version of this package. */ +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "1.2.3" +#endif + +/* Version number of package */ +#ifndef VERSION +#define VERSION "1.2.3" +#endif + +#define GIAC_NO_OPTIMIZATIONS +#define HAVE_NO_HOME_DIRECTORY + +#define HAVE_SYSCONF + +#define HAVE_LIBMPFR +#define HAVE_MPFR_H 1 + +/* The size of `int' and `long long', as computed by sizeof. */ +#define SIZEOF_INT 4 +#define SIZEOF_LONG_LONG 8 diff --git a/android/app/src/main/cpp/giac/deploy.gradle b/android/app/src/main/cpp/giac/deploy.gradle new file mode 100644 index 0000000..530f163 --- /dev/null +++ b/android/app/src/main/cpp/giac/deploy.gradle @@ -0,0 +1,198 @@ +// GeoGebra Deployment +// Copyright (c) 2015-2017 The GeoGebra Group +// All rights reserved +// @author Zoltan Kovacs + +def ggMavenRepoUser = System.env.MAVEN_USR +def ggMavenRepoPass = System.env.MAVEN_PSW + +def distDir = "$buildDir/distributions" +def javagiacDir = file("$distDir/javagiac/") +def ggbGiacJsDir = file("$distDir/giac.js/") + +// Unsure if this is needed or not. Otherwise there is no .pom file for Java Giac (which is probably a problem). +task javagiacPomJar (type: Jar) { + description 'Creates empty .jar package for the Java Giac library.' + baseName = 'javagiac' + destinationDir = javagiacDir +} + +task javagiacWin64JarClang (type: Jar) { + description 'Create the Windows 64 bit .jar package for the Java Giac library (via clang).' + baseName = 'javagiac-win64' + destinationDir = javagiacDir + from "cbuild64" // Make sure the DLL is compiled and put into this folder first. + include '*.dll' + rename 'libjavagiac.dll', 'javagiac64.dll' + classifier 'natives-windows-amd64' +} + +task testJavagiacWin64 (dependsOn: 'javagiacWin64JarClang') { + description 'Tests the Windows 64 bit version of Java Giac. [incubating]' +} + +task javagiacLinux64Jar (dependsOn: 'javagiacLinux64SharedLibrary', type: Jar) { + description 'Creates the Linux 64 bit .jar package for the Java Giac library.' + baseName = 'javagiac-linux64' + destinationDir = javagiacDir + from "${buildDir}/libs/javagiac/shared/linux64" + include '*.so' + rename 'libjavagiac.so', 'libjavagiac64.so' + classifier 'natives-linux-amd64' +} + +task testJavagiacLinux64 (dependsOn: 'javagiacLinux64Jar') { + description 'Tests the Linux 64 bit version of Java Giac. [incubating]' +} + +task javagiacMacJar (type: Jar) { + description 'Creates the Linux 32 bit .jar package for the Java Giac library.' + baseName = 'javagiac-mac' + destinationDir = javagiacDir + from("${buildDir}/binaries/javagiacSharedLibrary/osx_x86-64") { // FIXME: unify + include '*.jnilib' + } + from("${buildDir}/binaries/javagiacSharedLibrary/osx_arm-v8") { + include '*.jnilib' + rename 'libjavagiac.jnilib', 'libjavagiac-arm64.jnilib' + } + classifier 'natives-macosx-universal' +} + +task testJavagiacMac (dependsOn: 'javagiacMacJar') { + description 'Tests the Mac version of Java Giac. [incubating]' +} + +task testJavagiacAndroidArm (dependsOn: 'javagiacAndroideabiSharedLibrary') { + description 'Tests the Android ARM version of Java Giac. [incubating]' +} + +task testJavagiacAndroidX86 (dependsOn: 'javagiacAndroidx86SharedLibrary') { + description 'Tests the Android x86 version of Java Giac. [incubating]' +} + +task testJavagiac (dependsOn: ['testJavagiacLinux64', + 'testJavagiacWin64', 'testJavagiacMac', 'testJavagiacAndroidArm', 'testJavagiacAndroidX86']) { + description 'Tests the Linux, Windows, Mac and Android versions of the Java Giac library. [incubating]' +} + +task javagiacJars (dependsOn: ['javagiacMacJar', 'javagiacLinux64Jar', + 'javagiacWin64JarClang']) { + description 'Creates the native .jar files for Windows, Linux and Mac for Java Giac.' +} + +task testGiacJs (dependsOn: ['createGiacJs']) { + description 'Tests Javascript version of Giac. [incubating]' +} + +task testGiac (dependsOn: ['testJavagiac', 'testGiacJs']) { + description 'Tests Giac. [incubating]' +} + +/* Publications */ + +publishing { + publications { + mavenJava(MavenPublication) { + artifactId = 'javagiac' + groupId = 'fr.ujf-grenoble' + version = ggrev + artifact javagiacLinux64Jar + artifact javagiacWin64JarClang + artifact javagiacMacJar + artifact javagiacPomJar + pom { + name = 'Java Giac' + description = 'Java Giac for GeoGebra' + } + } + mavenZip(MavenPublication) { + artifactId = 'igiac' + groupId = 'fr.ujf-grenoble' + version = ggrev + artifact cocoapodsZip + pom { + name = 'iOS Cocoapods Zip' + packaging = 'zip' + } + } + } +} + +def processFileInplace(file, Closure processText) { + def text = file.text + file.write(processText(text)) +} + +task uploadDeployerAar (dependsOn: ['androidAar', 'giac-android:uploadDeployerAar']) { + description 'Deploys the .aar package to GeoGebra\'s Maven repository.' +} + + +// giac.js -- taken care of by artifacts + + +// node version + +// Recompilation is slow, and seems to be not really required, so we don't run "npm install". +task updateNodegiacVersion () { + description 'Updates Node Giac version in the package.json file.' + doLast { + def packageJson = file("$projectDir/package.json") + processFileInplace(packageJson) { line -> + def pattern = ~/"version": "(.*)"/ + def matcher = (line =~ pattern) + matcher.replaceAll("\"version\": \"1.23.$ggrev\"") + } + } +} + +task updateNodegiacWebCommit (dependsOn: 'updateNodegiacVersion') { + description 'Commits changes of package.json to the SVN repository.' + doLast { + exec { + // Note that this step may need user interaction on a first run. In such a case, e.g. in Jenkins + // you may need to manually connect to the SVN server first by running this task manually. + // Jenkins' home folder is by default in /var/lib/jenkins and its workspace is + // in jobs/*/workspace which is actually a standard SVN checkout folder. + commandLine 'svn', 'commit', '--username', System.env.MAVEN_USR, + '--password', System.env.MAVEN_PSW, + '-m', "Automatically update package.json to r$ggrev", + projectDir + } + } +} + +task publishNodegiac (dependsOn: 'updateNodegiacWebCommit') { + description 'Publishes Node Giac to npmjs.com' + doLast { + exec { + commandLine 'npm', 'publish' + } + } +} + +// Top level task +task updateGiac (dependsOn: [':publishMavenJavaPublicationToMavenRepository', ':giac-android:publish']) { + description 'Commits all update related changes for Giac.' +} + +allprojects { + afterEvaluate { + publishing { + repositories { + maven { + url 'https://repo.geogebra.net/releases' + credentials { + username = ggMavenRepoUser + password = ggMavenRepoPass + } + authentication { + basic(BasicAuthentication) + } + + } + } + } + } +} diff --git a/android/app/src/main/cpp/giac/giac-android/build.gradle b/android/app/src/main/cpp/giac/giac-android/build.gradle new file mode 100644 index 0000000..fcb1879 --- /dev/null +++ b/android/app/src/main/cpp/giac/giac-android/build.gradle @@ -0,0 +1,75 @@ +buildscript { + repositories { + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.0.0' + } +} +plugins { + id 'maven-publish' +} +apply plugin: 'com.android.library' + +repositories { + mavenCentral() + google() +} + +android { + compileSdkVersion 30 + buildToolsVersion "34.0.0" + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 27 + } +} + +def jniLibsDir = "src/main/jniLibs" +def abiSplits = ["armeabi-v7a": "/../arm-linux-androideabi/", + "x86" : "/../i686-linux-android/", + "x86_64" : "/../x86_64-linux-android/", + "arm64-v8a" : "/../aarch64-linux-android/"] + +task copyLibcShared { + group 'android' + description 'Copies libc++_shared.so files to the appropriate folders.' + doLast { + def so = "libc++_shared.so" + def missing = abiSplits.size() + def PATH = System.env['PATH'].split(":").each { d -> + abiSplits.each { arch, libDirSuffix -> + def libdirArch = d + libDirSuffix + if (file(libdirArch + so).exists()) { + println " Found $arch .so in $d" + missing -- + copy { from libdirArch include so into "$jniLibsDir/$arch" } + } + } + } + if (missing > 0) { + throw new GradleException("Missing $missing $so libraries, check PATH") + } + } +} + +afterEvaluate { +tasks['preBuild'].dependsOn(['copyLibcShared', ':androidCopyEabiLibjavagiacSo', + ':androidCopyX86LibjavagiacSo', ':androidCopyX86_64LibjavagiacSo', ':androidCopyArm64LibjavagiacSo']) +publishing { + publications { + release(MavenPublication) { + artifactId = 'giac-android' + groupId = 'org.geogebra' + version = project.getParent().ggrev + from components.release + pom { + name = 'Giac for Android' + description = 'Android Giac library' + } + } + } +} +} + diff --git a/android/app/src/main/cpp/giac/giac-android/src/main/AndroidManifest.xml b/android/app/src/main/cpp/giac/giac-android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2884b9f --- /dev/null +++ b/android/app/src/main/cpp/giac/giac-android/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/android/app/src/main/cpp/giac/giac-gwt/build.gradle b/android/app/src/main/cpp/giac/giac-gwt/build.gradle new file mode 100644 index 0000000..c3c5281 --- /dev/null +++ b/android/app/src/main/cpp/giac/giac-gwt/build.gradle @@ -0,0 +1,51 @@ +plugins { + id 'java-library' + id 'maven-publish' +} + +apply from: '../repositories.gradle' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } + withSourcesJar() +} + + +dependencies { + api 'org.gwtproject:gwt-user:2.12.1', + 'org.treblereel.gwt.gwtproject.resources:gwt-resources-api:202408061' + annotationProcessor 'org.treblereel.gwt.gwtproject.resources:gwt-resources-processor:202408061' +} + +compileJava.options.sourcepath = files(processResources.destinationDir).builtBy(processResources) + +tasks.register("prepareJs", Copy) { + dependsOn project.getParent().createGiacWasmJs + from "${project.getParent().buildDir}/binaries/giacggb.wasm" + into file("src/main/resources/fr/grenoble/ujf/giac") + include "giac.wasm.js" +} + +tasks.sourcesJar { + dependsOn('classes') + from files(file("build/generated/sources/annotationProcessor/java/main/")) +} + +compileJava.dependsOn prepareJs + +publishing { + publications { + mavenJava(MavenPublication) { + artifactId = 'giac-gwt' + groupId = 'fr.ujf-grenoble' + version = project.getParent().ggrev + from components.java + pom { + name = 'Giac for GWT' + description = 'GWT bining for giac.wasm.js' + } + } + } +} diff --git a/android/app/src/main/cpp/giac/giac-gwt/src/main/java/fr/grenoble/ujf/giac/CASResources.java b/android/app/src/main/cpp/giac/giac-gwt/src/main/java/fr/grenoble/ujf/giac/CASResources.java new file mode 100644 index 0000000..7b6466d --- /dev/null +++ b/android/app/src/main/cpp/giac/giac-gwt/src/main/java/fr/grenoble/ujf/giac/CASResources.java @@ -0,0 +1,18 @@ +package fr.grenoble.ujf.giac; + +import org.gwtproject.resources.client.ClientBundle; +import org.gwtproject.resources.client.Resource; +import org.gwtproject.resources.client.TextResource; + + +/** + * CAS resource bundle + */ +@Resource +public interface CASResources extends ClientBundle { + + /** @return giac.wasm */ + @Source("fr/grenoble/ujf/giac/giac.wasm.js") + TextResource giacWasm(); + +} diff --git a/android/app/src/main/cpp/giac/giac-gwt/src/main/resources/fr/grenoble/ujf/Giac.gwt.xml b/android/app/src/main/cpp/giac/giac-gwt/src/main/resources/fr/grenoble/ujf/Giac.gwt.xml new file mode 100644 index 0000000..07ab9b4 --- /dev/null +++ b/android/app/src/main/cpp/giac/giac-gwt/src/main/resources/fr/grenoble/ujf/Giac.gwt.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/android/app/src/main/cpp/giac/gradle/wrapper/gradle-wrapper.properties b/android/app/src/main/cpp/giac/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e750102 --- /dev/null +++ b/android/app/src/main/cpp/giac/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/app/src/main/cpp/giac/gradlew b/android/app/src/main/cpp/giac/gradlew new file mode 100644 index 0000000..1b6c787 --- /dev/null +++ b/android/app/src/main/cpp/giac/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright ยฉ 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป, +# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป; +# * compound commands having a testable exit status, especially ยซcaseยป; +# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/android/app/src/main/cpp/giac/gradlew.bat b/android/app/src/main/cpp/giac/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/android/app/src/main/cpp/giac/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/app/src/main/cpp/giac/nodegiac b/android/app/src/main/cpp/giac/nodegiac new file mode 100644 index 0000000..0356968 --- /dev/null +++ b/android/app/src/main/cpp/giac/nodegiac @@ -0,0 +1,19 @@ +#!/bin/bash + +# A wrapper to run nodegiac.js from this folder. +# You may need to fine tune this script if some settings/folders +# are different on your system. + +# Support for Bash on Windows +# https://stackoverflow.com/a/38859331/1044586 +if grep -q Microsoft /proc/version; then + NODE="/mnt/c/Program Files (x86)/nodejs/node.exe" + dirname=`dirname $0` + dirname1=`readlink -f $dirname` + dirname2=${dirname1:6} # Removing /mnt/c + "$NODE" "$dirname2/nodegiac.js" $* +else +# Support other systems as well + dirname="$(cd "$(dirname "$0")" && pwd -P)" + node "$dirname/nodegiac.js" $* +fi diff --git a/android/app/src/main/cpp/giac/nodegiac.js b/android/app/src/main/cpp/giac/nodegiac.js new file mode 100644 index 0000000..a66740b --- /dev/null +++ b/android/app/src/main/cpp/giac/nodegiac.js @@ -0,0 +1,59 @@ +var giac = require('bindings')('giac'); + +var readline = require('readline'); +var rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + terminal: false +}); + +const args = process.argv; + +var mini = true; + +if (args.length > 1 && args[2] != "-m") { + mini = false; + console.log("This is a minimalist command line version of NodeGiac"); + console.log("Enter expressions to evaluate"); + console.log("Example: factor(x^4-1); simplify(sin(3x)/sin(x))"); + console.log("int(1/(x^4-1)); int(1/(x^4+1)^4,x,0,inf)"); + console.log("f(x):=sin(x^2); f'(2); f'(y)"); + console.log("Press CTRL-D to stop"); + } + +var n=1; + +rl.on('line', function(line){ + // echo + console.log(n + ">> " + line); + var ans = giac.evaluate(line); + if (mini) ans = ans.replace(/\n/g, "\\n"); + console.log(n + "<< " + ans); + n++; +}) + +/* +console.log(giac.evaluate("expand((x+y)^3)")); +console.log(giac.evaluate("expand((x+y)^4)")); +console.log(giac.evaluate("2^50")); +console.log(giac.evaluate("[1]")); +console.log(giac.evaluate("caseval(\"init geogebra\")")); +console.log(giac.evaluate("[1]")); +console.log(giac.evaluate("evalf(7,15)")); +console.log(giac.evaluate("caseval(\"close geogebra\")")); +console.log(giac.evaluate("normal(sqrt(1+i))")); +*/ + +/* The expected output is: + * + * x^3+y^3+3*x*y^2+3*x^2*y + * x^4+y^4+4*x*y^3+6*x^2*y^2+4*x^3*y + * 1125899906842624 + * [1] + * "geogebra mode on" + * {1} + * 7.00000000000000 + * "geogebra mode off" + * (sqrt(2)*sqrt(sqrt(2)+1)+(1+i)*sqrt(sqrt(2)+1))/(sqrt(2)+2) + * + */ diff --git a/android/app/src/main/cpp/giac/package-lock.json b/android/app/src/main/cpp/giac/package-lock.json new file mode 100644 index 0000000..31a61f4 --- /dev/null +++ b/android/app/src/main/cpp/giac/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "giac", + "version": "1.23.69259", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + } + } +} diff --git a/android/app/src/main/cpp/giac/package.json b/android/app/src/main/cpp/giac/package.json new file mode 100644 index 0000000..e74d92d --- /dev/null +++ b/android/app/src/main/cpp/giac/package.json @@ -0,0 +1,36 @@ +{ + "name": "giac", + "version": "1.23.69823", + "homepage": "https://www-fourier.ujf-grenoble.fr/~parisse/giac.html", + "description": "Giac, a free computer algebra system", + "repository": { + "type": "svn", + "url": "https://dev.geogebra.org/svn/trunk/geogebra/giac" + }, + "contributors": [ + "Bernard Parisse ", + "Zoltรกn Kovรกcs " + ], + "license": "GPL-3.0+", + "main": "nodegiac.js", + "private": false, + "scripts": { + "test": "node nodegiac.js" + }, + "dependencies": { + "bindings": "~1.5.0" + }, + "os": [ + "linux", + "darwin", + "win32" + ], + "keywords": [ + "computer algebra", + "math", + "mathematics", + "cas", + "computer", + "algebra" + ] +} diff --git a/android/app/src/main/cpp/giac/recompile-msys.sh b/android/app/src/main/cpp/giac/recompile-msys.sh new file mode 100644 index 0000000..ee7c223 --- /dev/null +++ b/android/app/src/main/cpp/giac/recompile-msys.sh @@ -0,0 +1,5 @@ +mkdir -p "$1" +cd "$1" || exit 2 +CXX=clang++ CC=clang cmake -G "MinGW Makefiles" .. +mingw32-make clean +mingw32-make || exit 1 \ No newline at end of file diff --git a/android/app/src/main/cpp/giac/repositories.gradle b/android/app/src/main/cpp/giac/repositories.gradle new file mode 100644 index 0000000..4332548 --- /dev/null +++ b/android/app/src/main/cpp/giac/repositories.gradle @@ -0,0 +1,13 @@ + buildscript { + repositories { + maven { url 'https://plugins.gradle.org/m2/' } + mavenCentral() + google() + } + } + + repositories { + maven { url 'https://dev.geogebra.org/maven2' } + mavenCentral() + google() + } diff --git a/android/app/src/main/cpp/giac/settings.gradle b/android/app/src/main/cpp/giac/settings.gradle new file mode 100644 index 0000000..ff977b9 --- /dev/null +++ b/android/app/src/main/cpp/giac/settings.gradle @@ -0,0 +1,2 @@ +include 'giac-android' +include 'giac-gwt' diff --git a/android/app/src/main/cpp/giac/src/.npmignore b/android/app/src/main/cpp/giac/src/.npmignore new file mode 100644 index 0000000..852abca --- /dev/null +++ b/android/app/src/main/cpp/giac/src/.npmignore @@ -0,0 +1,5 @@ +giac.js +jni +minigiac +simpleInterface +test diff --git a/android/app/src/main/cpp/giac/src/GeoGebraCAS-demo/cpp/GeoGebraCAS-demo.cc b/android/app/src/main/cpp/giac/src/GeoGebraCAS-demo/cpp/GeoGebraCAS-demo.cc new file mode 100644 index 0000000..6fea88b --- /dev/null +++ b/android/app/src/main/cpp/giac/src/GeoGebraCAS-demo/cpp/GeoGebraCAS-demo.cc @@ -0,0 +1,26 @@ +#include "GeoGebraCAS.h" +#include + +#ifdef _WIN32 +#include "tchar.h" +int _tmain(int argc, _TCHAR* argv[]) { +#else +int main(int argc, char* argv[]) { +#endif + cout << "Starting GeoGebraCAS-demo" << endl; + // initializeCAS(); + string ret = evaluateCAS("factor(x^2-1)"); + cout << ret << endl; + ret = evaluateCAS("evalf(7,13)"); + cout << ret << endl; + ret = evaluateCAS("evalf(7,15)"); + cout << ret << endl; + ret = evaluateCAS("expand((a+b)^3)"); + cout << ret << endl; + ret = evaluateCAS("evalfa(when ( type(((x)^(2))+(1)) == DOM_SYMBOLIC && type(x) == DOM_SYMBOLIC , (assume(x),solve(((x)^(2))+(1),x))[size(assume(x),solve(((x)^(2))+(1),x))-1] , when ( type(((x)^(2))+(1)) == DOM_IDENT && type(x) == DOM_SYMBOLIC && ((x)^(2))+(1) == 'x', (assume(x),solve(((x)^(2))+(1)=0,x))[size(assume(x),solve(((x)^(2))+(1)=0,x))-1] ,when ( size(x) == 1,flatten1((normal([op(solve(((x)^(2))+(1),x))]))),(normal([op(solve(((x)^(2))+(1),x))])) ) ) ))"); + cout << ret << endl; + ret = evaluateCAS("mean([1,2,3,4,1,2,3])"); + cout << ret << endl; + cout << "Finishing GeoGebraCAS-demo" << endl; + return 0; +} diff --git a/android/app/src/main/cpp/giac/src/GeoGebraCAS/cpp/GeoGebraCAS.cc b/android/app/src/main/cpp/giac/src/GeoGebraCAS/cpp/GeoGebraCAS.cc new file mode 100644 index 0000000..1929447 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/GeoGebraCAS/cpp/GeoGebraCAS.cc @@ -0,0 +1,30 @@ +#include "GeoGebraCAS.h" +#include +#include + +using namespace std; +using namespace giac; + +#ifndef _WIN32 +#define EXPORT __attribute__((visibility("default"))) +__attribute__((constructor)) +static void initializer(void) { } +__attribute__((destructor)) +static void finalizer(void) { } +#else +#define EXPORT +#endif + +context ct; + +extern "C" { + EXPORT void initializeCAS() { return; } + EXPORT string evaluateCAS(string command) { + gen e(string(command), &ct); + try { + return giac::print(giac::eval(e, &ct), &ct); + } catch (std::runtime_error & err) { + cerr << err.what() << endl; + } + } + } diff --git a/android/app/src/main/cpp/giac/src/GeoGebraCAS/headers/GeoGebraCAS.h b/android/app/src/main/cpp/giac/src/GeoGebraCAS/headers/GeoGebraCAS.h new file mode 100644 index 0000000..84fa35f --- /dev/null +++ b/android/app/src/main/cpp/giac/src/GeoGebraCAS/headers/GeoGebraCAS.h @@ -0,0 +1,17 @@ +#ifdef _WIN32 +#ifdef GEOGEBRACAS_EXPORTS +#define GEOGEBRACAS_API __declspec(dllexport) +#else +#define GEOGEBRACAS_API __declspec(dllimport) +#endif +#else +#define GEOGEBRACAS_API +#endif + +using namespace std; +#include + +extern "C" { + GEOGEBRACAS_API void initializeCAS(); + GEOGEBRACAS_API string evaluateCAS(string command); + }; diff --git a/android/app/src/main/cpp/giac/src/giac.js/ggb.html b/android/app/src/main/cpp/giac/src/giac.js/ggb.html new file mode 100644 index 0000000..e618a6c --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/ggb.html @@ -0,0 +1,107 @@ + + + + + + Webxcas + + + + + + Examples of input:
+ factor(x^4-1); cfactor(x^2+1); normal((x+1)^4) +
solve(x^2-3*x+2=0); csolve(x^2=2*i); solve([x+y=1,x-y=3],[x,y]) +
simplify(sin(3x)/sin(x)); gcd(x^4-1,x^3-1) +
f(x):=sin(x^2):; f(sqrt(pi)); f'(2); f'(y) +
int(1/(x^4-1)); int(1/(x^4+1)^4,x,0,+infinity) +
limit(sin(x)/x,x=0); series(sin(x),x=0,5); +
A:=[[1,2],[3,4]]; inv(A); det(A-x*idn(A)); A[0,0]; rref(A); eigenvalues(A); eigenvectors(A); +
+
+ More documentation. +
+ Giac/Xcas, (c) B. Parisse, R. De Graeve, Institut Fourier, Universitรฉ de Grenoble I., licensed under the GPL3. +
+
+ Input: + +
+ +
+
Downloading...
+
+ +
+
+ + +
+ +
+ + + + + + + + diff --git a/android/app/src/main/cpp/giac/src/giac.js/js/time.js b/android/app/src/main/cpp/giac/src/giac.js/js/time.js new file mode 100644 index 0000000..bf5badf --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/js/time.js @@ -0,0 +1,5 @@ +mergeInto(LibraryManager.library,{ + emcctime: function() { + return Math.floor(Date.now()); + } +}); diff --git a/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.a b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.a new file mode 100644 index 0000000..e13be52 Binary files /dev/null and b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.a differ diff --git a/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.la b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.la new file mode 100644 index 0000000..8bad639 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.la @@ -0,0 +1,41 @@ +# libgmp.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='' + +# Names of this library. +library_names='' + +# The name of the static archive. +old_library='libgmp.a' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs='' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libgmp. +current=14 +age=4 +revision=0 + +# Is this an already installed library? +installed=no + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/usr/local/lib' diff --git a/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.lai b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.lai new file mode 100644 index 0000000..7f717e3 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libgmp.lai @@ -0,0 +1,41 @@ +# libgmp.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='' + +# Names of this library. +library_names='' + +# The name of the static archive. +old_library='libgmp.a' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs='' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libgmp. +current=14 +age=4 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/usr/local/lib' diff --git a/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.a b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.a new file mode 100644 index 0000000..d78f872 Binary files /dev/null and b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.a differ diff --git a/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.la b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.la new file mode 100644 index 0000000..397a0db --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.la @@ -0,0 +1,41 @@ +# libmpfr.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-13+local1 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='' + +# Names of this library. +library_names='' + +# The name of the static archive. +old_library='libmpfr.a' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs=' -L/home/kovzol/workspace/geogebra/giac/gmp-6.2.0/.libs /home/kovzol/workspace/geogebra/giac/gmp-6.2.0/.libs/libgmp.la' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libmpfr. +current=7 +age=1 +revision=0 + +# Is this an already installed library? +installed=no + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/usr/local/lib' diff --git a/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.lai b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.lai new file mode 100644 index 0000000..5b083c8 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/prebuilt/libmpfr.lai @@ -0,0 +1,41 @@ +# libmpfr.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-13+local1 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='' + +# Names of this library. +library_names='' + +# The name of the static archive. +old_library='libmpfr.a' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs=' -L/home/kovzol/workspace/geogebra/giac/gmp-6.2.0/.libs /usr/local/lib/libgmp.la' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libmpfr. +current=7 +age=1 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/usr/local/lib' diff --git a/android/app/src/main/cpp/giac/src/giac.js/webxcas.html b/android/app/src/main/cpp/giac/src/giac.js/webxcas.html new file mode 100644 index 0000000..3d51a42 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/webxcas.html @@ -0,0 +1,116 @@ + + + + + + Webxcas + + + + + + This is a simple web CAS (computer algebra system). + This CAS does not need any server, you are running it locally with the javascript + engine of your browser (need a recent browser, e.g. Firefox 19 or Chrome) + the 6.5M CAS code is downloaded once (giac.js javascript + compiled from native Giac/Xcas by emscripten). + The javascript code is at least 10 times and often 100 times slower than the native + code, it is therefore recommended to run large computations with + Xcas! +
+ Examples of input:
+ factor(x^4-1); cfactor(x^2+1); normal((x+1)^4) +
solve(x^2-3*x+2=0); csolve(x^2=2*i); solve([x+y=1,x-y=3],[x,y]) +
simplify(sin(3x)/sin(x)); gcd(x^4-1,x^3-1) +
f(x):=sin(x^2):; f(sqrt(pi)); f'(2); f'(y) +
int(1/(x^4-1)); int(1/(x^4+1)^4,x,0,+infinity) +
limit(sin(x)/x,x=0); series(sin(x),x=0,5); +
A:=[[1,2],[3,4]]; inv(A); det(A-x*idn(A)); A[0,0]; rref(A); eigenvalues(A); eigenvectors(A); +
+
+ More documentation. +
+ Giac/Xcas, (c) B. Parisse, R. De Graeve, Institut Fourier, Universitรฉ de Grenoble I., licensed under the GPL3. +
+
+ Input: + +
+ +
+
Downloading...
+
+ +
+
+ + +
+ +
+ + + + + + + + diff --git a/android/app/src/main/cpp/giac/src/giac.js/webxcasfr.html b/android/app/src/main/cpp/giac/src/giac.js/webxcasfr.html new file mode 100644 index 0000000..66bcfe3 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/webxcasfr.html @@ -0,0 +1,118 @@ + + + + + + Webxcas + + + + + + Webxcas est un systรจme de calcul formel en javascript (traduit ร  partir de + Giac/Xcas + par emscripten). Il n'a pas besoin de serveur, il s'exรฉcute localement + (avec le moteur javascript de votre navigateur qui doit รชtre rรฉcent, par + exemple Firefox 19 ou Chrome) ร  partir du code du CAS (6.5M) qui est tรฉlรฉchargรฉ + une fois. Le prix ร  payer pour cette simplicitรฉ + est la vitesse, le code est au moins 10 fois plus lent, souvent 100, que + le mรชme code natif, si vous devez exรฉcuter un calcul un peu compliquรฉ, + installez + Xcas! +
+ Exemples d'entrรฉes:
+ factor(x^4-1); cfactor(x^2+1); normal((x+1)^4) +
solve(x^2-3*x+2=0); csolve(x^2=2*i); solve([x+y=1,x-y=3],[x,y]) +
simplify(sin(3x)/sin(x)); gcd(x^4-1,x^3-1) +
f(x):=sin(x^2):; f(sqrt(pi)); f'(2); f'(y) +
int(1/(x^4-1)); int(1/(x^4+1)^4,x,0,+infinity) +
limit(sin(x)/x,x=0); series(sin(x),x=0,5); +
A:=[[1,2],[3,4]]; inv(A); det(A-x*idn(A)); A[0,0]; rref(A); eigenvalues(A); eigenvectors(A); +
+
+ Plus de documentation (attention il faut saisir les commandes en anglais). +
+ Giac/Xcas (c) B. Parisse, R. De Graeve, Institut Fourier, Universitรฉ de Grenoble I, sous licence GPL3. +
+
+ Input: + +
+ +
+
Downloading...
+
+ +
+
+ + +
+ +
+ + + + + + + + diff --git a/android/app/src/main/cpp/giac/src/giac.js/zxcas.html b/android/app/src/main/cpp/giac/src/giac.js/zxcas.html new file mode 100644 index 0000000..cc4f0ce --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/zxcas.html @@ -0,0 +1,158 @@ + + + + + + Webxcas + + + + + + This is a simple web CAS (computer algebra system). + This CAS does not need any server, you are running it locally with the javascript + engine of your browser (need a recent browser, e.g. Firefox 19 or Chrome) + the 1.5M compressed CAS code is downloaded once (giac.js.compress javascript + compiled from native Giac/Xcas by emscripten) then uncompressed. + The javascript code is at least 10 times and often 100 times slower than the native + code, it is therefore recommended to run large computations with + Xcas! +
+ Examples of input:
+ factor(x^4-1); cfactor(x^2+1); normal((x+1)^4) +
solve(x^2-3*x+2=0); csolve(x^2=2*i); solve([x+y=1,x-y=3],[x,y]) +
simplify(sin(3x)/sin(x)); gcd(x^4-1,x^3-1) +
f(x):=sin(x^2):; f(sqrt(pi)); f'(2); f'(y) +
int(1/(x^4-1)); int(1/(x^4+1)^4,x,0,+infinity) +
limit(sin(x)/x,x=0); series(sin(x),x=0,5); +
A:=[[1,2],[3,4]]; inv(A); det(A-x*idn(A)); A[0,0]; rref(A); eigenvalues(A); eigenvectors(A); +
+
+ More documentation. +
+ Giac/Xcas, (c) B. Parisse, R. De Graeve, Institut Fourier, Universitรฉ de Grenoble I, licensed under GPL3. +
+
+ Input: + +
+ +
+
Downloading...
+
+ +
+
+ + +
+ +
+ + + + + + + + diff --git a/android/app/src/main/cpp/giac/src/giac.js/zxcasfr.html b/android/app/src/main/cpp/giac/src/giac.js/zxcasfr.html new file mode 100644 index 0000000..be92477 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac.js/zxcasfr.html @@ -0,0 +1,161 @@ + + + + + + Webxcas + + + + + + Webxcas est un systรจme de calcul formel en javascript (traduit ร  partir de + Giac/Xcas + par emscripten). Il n'a pas besoin de serveur, il s'exรฉcute localement + (avec le moteur javascript de votre navigateur qui doit รชtre rรฉcent, par + exemple Firefox 19 ou Chrome) ร  partir du code compressรฉ du CAS (1.5M) qui est tรฉlรฉchargรฉ + une fois puis dรฉcompressรฉ. Le prix ร  payer pour cette simplicitรฉ + est la vitesse, le code est au moins 10 fois plus lent, souvent 100, que + le mรชme code natif, si vous devez exรฉcuter un calcul un peu compliquรฉ, + installez + Xcas! +
+ Exemples d'entrรฉes:
+ factor(x^4-1); cfactor(x^2+1); normal((x+1)^4) +
solve(x^2-3*x+2=0); csolve(x^2=2*i); solve([x+y=1,x-y=3],[x,y]) +
simplify(sin(3x)/sin(x)); gcd(x^4-1,x^3-1) +
f(x):=sin(x^2):; f(sqrt(pi)); f'(2); f'(y) +
int(1/(x^4-1)); int(1/(x^4+1)^4,x,0,+infinity) +
limit(sin(x)/x,x=0); series(sin(x),x=0,5); +
A:=[[1,2],[3,4]]; inv(A); det(A-x*idn(A)); A[0,0]; rref(A); eigenvalues(A); eigenvectors(A); +
+
+ Plus de documentation (attention il faut saisir les +commandes en anglais). +
+ Giac/Xcas (c) B. Parisse, R. De Graeve, Institut Fourier, Universitรฉ de Grenoble I, sous licence GPL 3. +
+
+ Input: + +
+ +
+
Chargement...
+
+ +
+
+ + +
+ +
+ + + + + + + + diff --git a/android/app/src/main/cpp/giac/src/giac/.npmignore b/android/app/src/main/cpp/giac/src/giac/.npmignore new file mode 100644 index 0000000..2e0b6bf --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/.npmignore @@ -0,0 +1,3 @@ +bison +flex +headers/android diff --git a/android/app/src/main/cpp/giac/src/giac/bison/input_parser.yy b/android/app/src/main/cpp/giac/src/giac/bison/input_parser.yy new file mode 100644 index 0000000..ec401d5 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/bison/input_parser.yy @@ -0,0 +1,1053 @@ +/* -*- mode:Mail; compile-command: "bison -p giac_yy -y -d input_parser.yy ; mv -f y.tab.c input_parser.cc ; mv -f y.tab.h input_parser.h ; make input_parser.o" -*- + * + * Input grammar definition for reading expressions. + * This file must be processed with yacc/bison. */ + +/* + * Copyright (C) 2001,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * The very first version was inspired by GiNaC parser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + + %{ + #define YYPARSE_PARAM scanner + #define YYLEX_PARAM scanner + %} +/* + * Definitions + */ +%pure-parser +%parse-param {void * scanner} +%{ +#include "giacPCH.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "first.h" +#include +#include +#include "giacPCH.h" +#include "index.h" +#include "gen.h" +#define YYSTYPE giac::gen +#define YY_EXTRA_TYPE const giac::context * +#include "lexer.h" +#include "input_lexer.h" +#include "usual.h" +#include "derive.h" +#include "sym2poly.h" +#include "vecteur.h" +#include "modpoly.h" +#include "alg_ext.h" +#include "prog.h" +#include "rpn.h" +#include "intg.h" +#include "plot.h" +#include "maple.h" +using namespace std; + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + +// It seems there is a bison bug when it reallocates space for the stack +// therefore I redefine YYINITDEPTH to 4000 (max size is YYMAXDEPTH) +// instead of 200 +// Feel free to change if you need but then readjust YYMAXDEPTH +#if defined RTOS_THREADX || defined NSPIRE || defined NSPIRE_NEWLIB || defined NUMWORKS +#ifdef RTOS_THREADX +#define YYINITDEPTH 100 +#define YYMAXDEPTH 101 +#else +#define YYINITDEPTH 200 +#define YYMAXDEPTH 201 +#endif +#else // RTOS_THREADX +// Note that the compilation by bison with -v option generates a file y.output +// to debug the grammar, compile input_parser.yy with bison +// then add yydebug=1 in input_parser.cc at the beginning of yyparse ( +#define YYDEBUG 1 +#ifdef GNUWINCE +#define YYINITDEPTH 1000 +#else +#define YYINITDEPTH 4000 +#define YYMAXDEPTH 20000 +#define YYERROR_VERBOSE 1 +#endif // GNUWINCE +#endif // RTOS_THREADX + +#if 0 +#define YYSTACK_USE_ALLOCA 1 +#endif + + +gen polynome_or_sparse_poly1(const gen & coeff, const gen & index){ + if (index.type==_VECT){ + index_t i; + const_iterateur it=index._VECTptr->begin(),itend=index._VECTptr->end(); + i.reserve(itend-it); + for (;it!=itend;++it){ + if (it->type!=_INT_) + return gentypeerr(); + i.push_back(it->val); + } + monomial m(coeff,i); + return polynome(m); + } + else { + sparse_poly1 res; + res.push_back(monome(coeff,index)); + return res; + } +} +%} + +/* Tokens */ +%token T_NUMBER T_SYMBOL T_LITERAL T_DIGITS T_STRING T_END_INPUT + T_EXPRESSION T_UNARY_OP T_OF T_NOT T_TYPE_ID T_VIRGULE + T_AFFECT T_MAPSTO T_BEGIN_PAR T_END_PAR + T_PLUS T_MOINS T_FOIS T_DIV T_MOD T_POW T_QUOTED_BINARY T_QUOTE T_PRIME + T_TEST_EQUAL T_EQUAL + T_INTERVAL T_UNION T_INTERSECT T_MINUS + T_AND_OP T_COMPOSE T_DOLLAR T_DOLLAR_MAPLE + T_INDEX_BEGIN T_VECT_BEGIN T_VECT_DISPATCH T_VECT_END T_SET_BEGIN T_SET_END + T_SEMI T_DEUXPOINTS T_DOUBLE_DEUX_POINTS + T_IF T_RPN_IF T_ELIF T_THEN T_ELSE T_IFTE + T_SWITCH T_CASE T_DEFAULT T_ENDCASE + T_FOR T_FROM T_TO T_DO T_BY T_WHILE T_MUPMAP_WHILE T_RPN_WHILE + T_REPEAT T_UNTIL T_IN + T_START T_BREAK T_CONTINUE + T_TRY T_CATCH T_TRY_CATCH + T_PROC T_BLOC T_BLOC_BEGIN T_BLOC_END T_RETURN + T_LOCAL T_LOCALBLOC T_NAME T_PROGRAM + T_NULL T_ARGS T_FACTORIAL + T_RPN_OP T_RPN_BEGIN T_RPN_END T_STACK + T_GROUPE_BEGIN T_GROUPE_END T_LINE_BEGIN T_LINE_END + T_VECTOR_BEGIN T_VECTOR_END T_CURVE_BEGIN T_CURVE_END + T_ROOTOF_BEGIN T_ROOTOF_END + T_SPOLY1_BEGIN T_SPOLY1_END T_POLY1_BEGIN T_POLY1_END + T_MATRICE_BEGIN T_MATRICE_END T_ASSUME_BEGIN T_ASSUME_END T_HELP + TI_DEUXPOINTS TI_LOCAL TI_LOOP TI_FOR TI_WHILE TI_STO TI_TRY + TI_DIALOG T_PIPE TI_DEFINE TI_PRGM TI_SEMI TI_HASH + T_ACCENTGRAVE T_MAPLELIB + T_INTERROGATION T_UNIT T_BIDON T_LOGO T_SQ T_CASE38 T_IFERR + T_MOINS38 T_NEG38 T_UNARY_OP_38 + +/* Operator precedence and associativity */ +/* %nonassoc T_ELSE +%nonassoc T_IF */ +%nonassoc TI_DEUXPOINTS +%nonassoc T_RETURN +%nonassoc T_FUNCTION +%nonassoc TI_STO +%nonassoc T_PIPE +%right T_AFFECT +%nonassoc T_FOR +%left TI_SEMI +%left T_VIRGULE +%nonassoc T_INTERROGATION +%nonassoc T_LOGO // for repete, must be there w.r.t. T_VIRGULE +%nonassoc T_BIDON +%right T_DEUXPOINTS +%nonassoc T_MAPSTO +%left T_AND_OP +%nonassoc T_IN +%left T_DOLLAR_MAPLE // not the same precedence than for spreadsheet +%right T_EQUAL +%left T_TEST_EQUAL +%left T_UNION +%nonassoc T_MINUS +%left T_INTERSECT +%left T_INTERVAL +%left T_PLUS T_MOINS T_MOINS38 +%nonassoc T_NUMBER +%left T_FOIS T_IMPMULT +%left T_DIV +%nonassoc T_MOD +%nonassoc T_UNIT +%nonassoc T_NEG38 T_NOT +%nonassoc T_DOLLAR // this priority for spreadsheet +%nonassoc T_PRIME +%right T_POW +%nonassoc T_FACTORIAL +%left T_SQ +%nonassoc T_UNARY_OP T_UNARY_OP_38 +%left T_COMPOSE +%nonassoc T_DOUBLE_DEUX_POINTS +%nonassoc TI_HASH + +%start input + + +/* + * Grammar rules + */ + +%% +input : correct_input { const giac::context * contextptr = giac_yyget_extra(scanner); + if ($1._VECTptr->size()==1) + parsed_gen($1._VECTptr->front(),contextptr); + else + parsed_gen(gen(*$1._VECTptr,_SEQ__VECT),contextptr); + } + ; + +correct_input : exp T_END_INPUT { $$=vecteur(1,$1); } + | exp T_SEMI T_END_INPUT { if ($2.val==1) $$=vecteur(1,symbolic(at_nodisp,$1)); else $$=vecteur(1,$1); } + | exp T_SEMI correct_input { if ($2.val==1) $$=mergevecteur(makevecteur(symbolic(at_nodisp,$1)),*$3._VECTptr); else $$=mergevecteur(makevecteur($1),*$3._VECTptr); } + ; + +exp : T_NUMBER {$$ = $1;} + | T_NUMBER symbol_or_literal %prec T_IMPMULT {if (is_one($1)) $$=$2; else $$=symbolic(at_prod,gen(makevecteur($1,$2),_SEQ__VECT));} + | T_NUMBER symbol_or_literal T_POW T_NUMBER %prec T_IMPMULT {if (is_one($1)) $$=symb_pow($2,$4); else $$=symbolic(at_prod,gen(makevecteur($1,symb_pow($2,$4)),_SEQ__VECT));} + | T_NUMBER symbol_or_literal T_POW T_BEGIN_PAR T_NUMBER T_END_PAR %prec T_IMPMULT {if (is_one($1)) $$=symb_pow($2,$5); else $$=symbolic(at_prod,gen(makevecteur($1,symb_pow($2,$5)),_SEQ__VECT));} + | T_NUMBER symbol_or_literal T_SQ %prec T_IMPMULT {$$=symbolic(at_prod,gen(makevecteur($1,symb_pow($2,$3)) ,_SEQ__VECT));} + | T_NUMBER T_UNARY_OP T_BEGIN_PAR exp T_END_PAR { $$ =$1*symbolic(*$2._FUNCptr,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround($4)):os_nary_workaround($4)); } + | T_NUMBER T_UNARY_OP T_BEGIN_PAR exp T_END_PAR T_POW T_NUMBER { $$ =$1*symb_pow(symbolic(*$2._FUNCptr,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround($4)):os_nary_workaround($4)),$7); } + /* | T_LITERAL T_NUMBER {$$=symbolic(at_prod,makevecteur($1,$2));} */ + | T_STRING { $$=$1; } + | T_EXPRESSION { if ($1.type==_FUNC) $$=symbolic(*$1._FUNCptr,gen(vecteur(0),_SEQ__VECT)); else $$=$1; } + /* | T_COMMENT { $$=symb_comment($1); } + | T_COMMENT exp { $$=$2; } */ + | symbol T_BEGIN_PAR suite T_END_PAR T_AFFECT bloc {$$ = symb_program_sto($3,$3*gen_zero,$6,$1,false,giac_yyget_extra(scanner));} + | symbol T_BEGIN_PAR suite T_END_PAR T_AFFECT exp {if (is_array_index($1,$3,giac_yyget_extra(scanner)) || (abs_calc_mode(giac_yyget_extra(scanner))==38 && $1.type==_IDNT && strlen($1._IDNTptr->id_name)==2 && check_vect_38($1._IDNTptr->id_name))) $$=symbolic(at_sto,gen(makevecteur($6,symbolic(at_of,gen(makevecteur($1,$3) ,_SEQ__VECT))) ,_SEQ__VECT)); else { $$ = symb_program_sto($3,$3*gen_zero,$6,$1,true,giac_yyget_extra(scanner)); $$._SYMBptr->feuille.subtype=_SORTED__VECT; } } + | exp TI_STO symbol T_BEGIN_PAR suite T_END_PAR {if (is_array_index($3,$5,giac_yyget_extra(scanner)) || (abs_calc_mode(giac_yyget_extra(scanner))==38 && $3.type==_IDNT && check_vect_38($3._IDNTptr->id_name))) $$=symbolic(at_sto,gen(makevecteur($1,symbolic(at_of,gen(makevecteur($3,$5) ,_SEQ__VECT))) ,_SEQ__VECT)); else $$ = symb_program_sto($5,$5*gen_zero,$1,$3,false,giac_yyget_extra(scanner));} + | exp TI_STO symbol T_INDEX_BEGIN exp T_VECT_END { + const giac::context * contextptr = giac_yyget_extra(scanner); + gen g=symb_at($3,$5,contextptr); $$=parser_symb_sto($1,g); + } + | exp TI_STO symbol T_INDEX_BEGIN T_VECT_DISPATCH exp T_VECT_END T_VECT_END { + const giac::context * contextptr = giac_yyget_extra(scanner); + gen g=symbolic(at_of,gen(makevecteur($3,$6) ,_SEQ__VECT)); $$=parser_symb_sto($1,g); + } + | exp TI_STO symbol { if ($3.type==_IDNT) { string s=$3.print(context0); const char * ch=s.c_str(); if (ch[0]=='_' && unit_conversion_map().find(ch+1) != unit_conversion_map().end()) $$=symbolic(at_convert,gen(makevecteur($1,symbolic(at_unit,makevecteur(1,$3))) ,_SEQ__VECT)); else $$=parser_symb_sto($1,$3); } else $$=parser_symb_sto($1,$3); } + | exp TI_STO T_UNARY_OP { $$=symbolic(at_convert,gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp TI_STO T_PLUS { $$=symbolic(at_convert,gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp TI_STO T_FOIS { $$=symbolic(at_convert,gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp TI_STO T_DIV { $$=symbolic(at_convert,gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp TI_STO T_VIRGULE { $$=symbolic(at_time,$1);} + | exp TI_STO TI_STO { if ($1==16 || $1==10 || $1==8 || $1==2) $$=symbolic(at_integer_format,$1); else $$=symbolic(at_solve,symb_equal($1,0));} + | exp TI_STO T_UNIT exp { $$=symbolic(at_convert,gen(makevecteur($1,symb_unit(gen(1),$4,giac_yyget_extra(scanner))),_SEQ__VECT)); opened_quote(giac_yyget_extra(scanner)) &= 0x7ffffffd;} + | symbol T_BEGIN_PAR suite T_END_PAR {$$ = check_symb_of($1,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround($3)):os_nary_workaround($3),giac_yyget_extra(scanner));} + | exp T_BEGIN_PAR suite T_END_PAR {$$ = check_symb_of($1,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround($3)):os_nary_workaround($3),giac_yyget_extra(scanner));} + | symbol {$$ = $1;} + | T_LITERAL {$$ = $1;} + | T_DIGITS {$$ = $1;} + | T_DIGITS T_AFFECT exp {$$ = symbolic(*$1._FUNCptr,$3);} + | T_DIGITS T_BEGIN_PAR exp T_END_PAR {$$ = symbolic(*$1._FUNCptr,$3);} + | T_DIGITS T_BEGIN_PAR T_END_PAR {$$ = symbolic(*$1._FUNCptr,gen(vecteur(0),_SEQ__VECT));} + | exp TI_STO T_DIGITS {$$ = symbolic(*$3._FUNCptr,$1);} + | exp T_TEST_EQUAL exp {$$=symb_test_equal($1,$2,$3);} + /* | exp T_TEST_EQUAL symbol T_TEST_EQUAL exp {$$ = symb_and(symbolic(*$2._FUNCptr,gen(makevecteur($1,$3),_SEQ__VECT)),symbolic(*$4._FUNCptr,gen(makevecteur($3,$5),_SEQ__VECT)));} */ + | exp T_EQUAL exp {$$ = symbolic(*$2._FUNCptr,makesequence($1,$3)); } + | T_EQUAL exp %prec T_BIDON { + if ($2.type==_SYMB) $$=$2; else $$=symbolic(at_nop,$2); + $$.change_subtype(_SPREAD__SYMB); + const giac::context * contextptr = giac_yyget_extra(scanner); + spread_formula(false,contextptr); + } + | exp T_PLUS exp { if ($1.is_symb_of_sommet(at_plus) && $1._SYMBptr->feuille.type==_VECT){ $1._SYMBptr->feuille._VECTptr->push_back($3); $$=$1; } else + $$ =symbolic(*$2._FUNCptr,gen(makevecteur($1,$3),_SEQ__VECT));} + | exp T_MOINS exp {$$ = symb_plus($1,$3.type<_IDNT?-$3:symbolic(at_neg,$3));} + | exp T_MOINS38 exp {$$ = symb_plus($1,$3.type<_IDNT?-$3:symbolic(at_neg,$3));} + | exp T_FOIS exp {$$ =symbolic(*$2._FUNCptr,gen(makevecteur($1,$3),_SEQ__VECT));} + | exp T_DIV exp {$$ =symbolic(*$2._FUNCptr,gen(makevecteur($1,$3),_SEQ__VECT));} + | exp T_POW exp {if ($1==symbolic(at_exp,1) && $2==at_pow) $$=symbolic(at_exp,$3); else $$ =symbolic(*$2._FUNCptr,gen(makevecteur($1,$3),_SEQ__VECT));} + | exp T_MOD exp {if ($2.type==_FUNC) $$=symbolic(*$2._FUNCptr,gen(makevecteur($1,$3),_SEQ__VECT)); else $$ = symbolic(at_normalmod,gen(makevecteur($1,$3),_SEQ__VECT));} + | exp T_INTERVAL exp {$$ = symbolic(*$2._FUNCptr,gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp T_INTERVAL {$$ = symbolic(*$2._FUNCptr,gen(makevecteur($1,RAND_MAX) ,_SEQ__VECT)); } + | T_INTERVAL exp {$$ = symbolic(*$1._FUNCptr,gen(makevecteur(0,$2) ,_SEQ__VECT)); } + | T_INTERVAL T_VIRGULE exp {$$ = makesequence(symbolic(*$1._FUNCptr,gen(makevecteur(0,RAND_MAX) ,_SEQ__VECT)),$3); } + /* | exp T_PLUS T_PLUS {$$ = symb_sto($1+1,$1);} */ + /* | exp T_MOINS T_MOINS {$$ = symb_sto($1-1,$1);} */ + | exp T_AND_OP exp {$$ = symbolic(*$2._FUNCptr,gen(makevecteur($1,$3),_SEQ__VECT));} + | exp T_DEUXPOINTS exp {$$= symbolic(at_deuxpoints,gen(makevecteur($1,$3) ,_SEQ__VECT));} + | T_MOINS exp %prec T_NEG38 { + if ($2==unsigned_inf) + $$ = minus_inf; + else { if ($2.type==_INT_) $$=(-$2.val); else { if ($2.type==_DOUBLE_) $$=(-$2._DOUBLE_val); else $$=symbolic(at_neg,$2); } } + } + | T_NEG38 exp { + if ($2==unsigned_inf) + $$ = minus_inf; + else { if ($2.type==_INT_ || $2.type==_DOUBLE_ || $2.type==_FLOAT_) $$=-$2; else $$=symbolic(at_neg,$2); } + } + | T_PLUS exp %prec T_NEG38 { + if ($2==unsigned_inf) + $$ = plus_inf; + else + $$ = $2; + } + | T_SPOLY1_BEGIN exp T_VIRGULE exp T_SPOLY1_END {$$ = polynome_or_sparse_poly1(eval($2,1, giac_yyget_extra(scanner)),$4);} + | T_ROOTOF_BEGIN exp T_ROOTOF_END { + if ( ($2.type==_SYMB) && ($2._SYMBptr->sommet==at_deuxpoints) ) + $$ = algebraic_EXTension($2._SYMBptr->feuille._VECTptr->front(),$2._SYMBptr->feuille._VECTptr->back()); + else $$=$2; + } + /* | T_ROOTOF_BEGIN exp T_VIRGULE exp T_ROOTOF_END {if ($2.type==_VECT) $$ = real_complex_rootof(*$2._VECTptr,$4); else $$=gen_zero;} */ + | T_OF { $$=gen(at_of,2); } + | exp T_AFFECT exp {if ($1.type==_FUNC) *logptr(giac_yyget_extra(scanner))<< ("Warning: "+$1.print(context0)+" is a reserved word")<<'\n'; if ($1.type==_INT_) $$=symb_equal($1,$3); else {$$ = parser_symb_sto($3,$1,$2==at_array_sto); if ($3.is_symb_of_sommet(at_program)) *logptr(giac_yyget_extra(scanner))<<"// End defining "<<$1<<'\n';}} + | T_NOT exp { $$ = symbolic(*$1._FUNCptr,$2);} + | T_ARGS T_BEGIN_PAR exp T_END_PAR {$$ = symb_args($3);} + | T_ARGS T_INDEX_BEGIN exp T_VECT_END {$$ = symb_args($3);} + | T_ARGS { $$=symb_args(vecteur(0)); } + | T_UNARY_OP T_BEGIN_PAR exp T_END_PAR { + gen tmp=python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround($3)):os_nary_workaround($3); + // CERR << python_compat(giac_yyget_extra(scanner)) << tmp << '\n'; + $$ = symbolic(*$1._FUNCptr,tmp); + const giac::context * contextptr = giac_yyget_extra(scanner); + if ($3.type==_INT_ && (*$1._FUNCptr==at_maple_mode ||*$1._FUNCptr==at_xcas_mode )){ + xcas_mode(contextptr)=$3.val; + } + if ($3.type==_INT_ && *$1._FUNCptr==at_python_compat) + python_compat(contextptr)=$3.val; + if (*$1._FUNCptr==at_user_operator){ + user_operator($3,contextptr); + } + } + | T_UNARY_OP_38 T_BEGIN_PAR exp T_END_PAR { + if ($3.type==_VECT && $3._VECTptr->empty()) + giac_yyerror(scanner,"void argument"); + $$ = symbolic(*$1._FUNCptr,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround($3)):os_nary_workaround($3)); + } + | T_UNARY_OP T_INDEX_BEGIN exp T_VECT_END { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_at($1,$3,contextptr); + } + | T_UNARY_OP T_BEGIN_PAR T_END_PAR { + $$ = symbolic(*$1._FUNCptr,gen(vecteur(0),_SEQ__VECT)); + if (*$1._FUNCptr==at_rpn) + rpn_mode(giac_yyget_extra(scanner))=1; + if (*$1._FUNCptr==at_alg) + rpn_mode(giac_yyget_extra(scanner))=0; + } + | T_UNARY_OP { + $$ = $1; + } + | exp T_PRIME {$$ = symbolic(at_derive,$1);} + | exp T_FACTORIAL { $$=symbolic(*$2._FUNCptr,$1); } + /* | exp T_IF exp T_ELSE exp %prec T_RETURN {$$=symb_ifte(equaltosame($3),$1,$5);} */ + | T_IF exp T_THEN bloc T_ELSE bloc {$$ = symbolic(*$1._FUNCptr,makevecteur(equaltosame($2),symb_bloc($4),symb_bloc($6)));} + | T_IF exp T_THEN bloc {$$ = symbolic(*$1._FUNCptr,makevecteur(equaltosame($2),$4,0));} + | T_IF exp T_THEN prg_suite elif { + $$ = symbolic(*$1._FUNCptr,makevecteur(equaltosame($2),symb_bloc($4),$5)); + } + | T_IFTE T_BEGIN_PAR exp T_END_PAR {$$ = symbolic(*$1._FUNCptr,$3);} + | T_IFTE {$$ = $1;} + | T_PROGRAM T_BEGIN_PAR exp T_END_PAR {$$ = symb_program($3);} + | T_PROGRAM {$$ = gen(at_program,3);} + | exp T_MAPSTO bloc { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$ = symb_program($1,gen_zero*$1,$3,contextptr); + } + | exp T_MAPSTO exp { + const giac::context * contextptr = giac_yyget_extra(scanner); + if ($3.type==_VECT) + $$ = symb_program($1,gen_zero*$1,symb_bloc(makevecteur(at_nop,$3)),contextptr); + else + $$ = symb_program($1,gen_zero*$1,$3,contextptr); + } + | T_BLOC T_BEGIN_PAR exp T_END_PAR {$$ = symb_bloc($3);} + | T_BLOC {$$ = at_bloc;} + /* | T_RETURN T_BEGIN_PAR exp T_END_PAR {$$ = symb_return($3);} */ + | T_RETURN exp { $$=symbolic(*$1._FUNCptr,$2); } + /* | T_RETURN exp T_IF exp T_ELSE exp { $$=symbolic(*$1._FUNCptr,symb_ifte(equaltosame($4),$2,$6)); } */ + | T_RETURN {$$ = gen(*$1._FUNCptr,0);} + | T_QUOTE T_RETURN T_QUOTE { $$=$2;} + /* | T_RETURN T_SEMI {$$ = gen(*$1._FUNCptr,0);} */ + | T_BREAK {$$ = symbolic(at_break,gen_zero);} + | T_CONTINUE {$$ = symbolic(at_continue,gen_zero);} + | T_FOR symbol_for T_IN exp T_DO prg_suite T_BLOC_END { + /* + gen kk(identificateur("index")); + vecteur v(*$6._VECTptr); + const giac::context * contextptr = giac_yyget_extra(scanner); + v.insert(v.begin(),symb_sto(symb_at($4,kk,contextptr),$2)); + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto(xcas_mode(contextptr)!=0,kk),symb_inferieur_strict(kk,symb_size($4)+(xcas_mode(contextptr)!=0)),symb_sto(symb_plus(kk,gen(1)),kk),symb_bloc(v))); + */ + if ($7.type==_INT_ && $7.val && $7.val!=2 && $7.val!=9) + giac_yyerror(scanner,"missing loop end delimiter"); + bool rg=$4.is_symb_of_sommet(at_range); + gen f=$4.type==_SYMB?$4._SYMBptr->feuille:0,inc=1; + if (rg){ + if (f.type!=_VECT) f=makesequence(0,f); + vecteur v=*f._VECTptr; + if (v.size()==3) inc=v[2]; + if (v.size()>=2) f=makesequence(v.front(),v[1]-inc); + } + if (inc.type==_INT_ && inc.val!=0 && f.type==_VECT && f._VECTptr->size()==2 && (rg || ($4.is_symb_of_sommet(at_interval) + // && f._VECTptr->front().type==_INT_ && f._VECTptr->back().type==_INT_ + ))) + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto(f._VECTptr->front(),$2),inc.val>0?symb_inferieur_egal($2,f._VECTptr->back()):symb_superieur_egal($2,f._VECTptr->back()),symb_sto(symb_plus($2,inc),$2),symb_bloc($6))); + else + $$=symbolic(*$1._FUNCptr,makevecteur(1,symbolic(*$1._FUNCptr,makevecteur($2,$4)),1,symb_bloc($6))); + } + | T_FOR symbol_for T_IN exp T_DO prg_suite T_ELSE prg_suite T_BLOC_END { + if ($9.type==_INT_ && $9.val && $9.val!=2 && $9.val!=9) + giac_yyerror(scanner,"missing loop end delimiter"); + $$=symbolic(*$1._FUNCptr,makevecteur(1,symbolic(*$1._FUNCptr,makevecteur($2,$4,symb_bloc($8))),1,symb_bloc($6))); + } + | T_FOR symbol from T_TO exp step loop38_do prg_suite T_BLOC_END { + if ($9.type==_INT_ && $9.val && $9.val!=2 && $9.val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + gen tmp,st=$6; + if (st==1 && $4!=1) st=$4; + const giac::context * contextptr = giac_yyget_extra(scanner); + if (!lidnt(st).empty()) + *logptr(contextptr) << "Warning, step is not numeric " << st << '\n'; + bool b=has_evalf(st,tmp,1,context0); + if (!b || is_positive(tmp,context0)) + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto($3,$2),symb_inferieur_egal($2,$5),symb_sto(symb_plus($2,b?abs(st,context0):symb_abs(st)),$2),symb_bloc($8))); + else + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto($3,$2),symb_superieur_egal($2,$5),symb_sto(symb_plus($2,st),$2),symb_bloc($8))); + } + | T_FOR symbol from step T_TO exp T_DO prg_suite T_BLOC_END { + if ($9.type==_INT_ && $9.val && $9.val!=2 && $9.val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + gen tmp,st=$4; + if (st==1 && $5!=1) st=$5; + const giac::context * contextptr = giac_yyget_extra(scanner); + if (!lidnt(st).empty()) + *logptr(contextptr) << "Warning, step is not numeric " << st << '\n'; + bool b=has_evalf(st,tmp,1,context0); + if (!b || is_positive(tmp,context0)) + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto($3,$2),symb_inferieur_egal($2,$6),symb_sto(symb_plus($2,b?abs(st,context0):symb_abs(st)),$2),symb_bloc($8))); + else + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto($3,$2),symb_superieur_egal($2,$6),symb_sto(symb_plus($2,st),$2),symb_bloc($8))); + } + | T_FOR symbol from step T_DO prg_suite T_BLOC_END { + if ($7.type==_INT_ && $7.val && $7.val!=2 && $7.val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto($3,$2),gen(1),symb_sto(symb_plus($2,$4),$2),symb_bloc($6))); + } + | T_FOR symbol from step T_MUPMAP_WHILE exp T_DO prg_suite T_BLOC_END { + if ($9.type==_INT_ && $9.val && $9.val!=2 && $9.val!=9 && $9.val!=8) giac_yyerror(scanner,"missing loop end delimiter"); + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto($3,$2),$6,symb_sto(symb_plus($2,$4),$2),symb_bloc($8))); + } + | T_FOR {$$ = gen(*$1._FUNCptr,4);} + /* | T_DO prg_suite T_BLOC_END { + if ($3.type==_INT_ && $3.val && $3.val!=2 && $3.val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + vecteur v=makevecteur(gen_zero,gen(1),gen_zero,symb_bloc($2)); $$=symbolic(*$1._FUNCptr,v); + } */ + | T_REPEAT prg_suite T_UNTIL exp { + vecteur v=gen2vecteur($2); + v.push_back(symb_ifte(equaltosame($4),symbolic(at_break,gen_zero),0)); + $$=symbolic(*$1._FUNCptr,makevecteur(gen_zero,1,gen_zero,symb_bloc(v))); + } + | T_REPEAT prg_suite T_UNTIL exp T_BLOC_END { + if ($5.type==_INT_ && $5.val && $5.val!=2 && $5.val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + vecteur v=gen2vecteur($2); + v.push_back(symb_ifte(equaltosame($4),symbolic(at_break,gen_zero),0)); + $$=symbolic(*$1._FUNCptr,makevecteur(gen_zero,1,gen_zero,symb_bloc(v))); + } + | T_IFERR prg_suite T_THEN prg_suite T_ELSE prg_suite T_BLOC_END { + if ($7.type==_INT_ && $7.val && $7.val!=4) giac_yyerror(scanner,"missing iferr end delimiter"); + $$=symbolic(at_try_catch,makevecteur(symb_bloc($2),0,symb_bloc($4),symb_bloc($6))); + } + | T_IFERR prg_suite T_THEN prg_suite T_BLOC_END { + if ($5.type==_INT_ && $5.val && $5.val!=4) giac_yyerror(scanner,"missing iferr end delimiter"); + $$=symbolic(at_try_catch,makevecteur(symb_bloc($2),0,symb_bloc($4),symb_bloc(0))); + } + | T_CASE38 case38 T_BLOC_END {$$=symbolic(at_piecewise,$2); } + | T_TYPE_ID { + $$=$1; + // $$.subtype=1; + } + | T_QUOTE T_TYPE_ID T_QUOTE { $$=$2; /* $$.subtype=1; */ } + | T_DOLLAR_MAPLE exp { $$ = symb_dollar($2); } + | exp T_DOLLAR_MAPLE symbol T_IN exp {$$=symb_dollar(gen(makevecteur($1,$3,$5) ,_SEQ__VECT));} + | exp T_DOLLAR_MAPLE exp { $$ = symb_dollar(gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp T_DOLLAR exp { $$ = symb_dollar(gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | T_DOLLAR T_SYMBOL { $$=symb_dollar($2); } + | exp T_COMPOSE exp { //CERR << $1 << " compose " << $2 << $3 << '\n'; +$$ = symbolic(*$2._FUNCptr,gen(makevecteur($1,python_compat(giac_yyget_extra(scanner))?denest_sto($3):$3) ,_SEQ__VECT)); } + | T_COMPOSE {$$=symbolic(at_ans,-1);} + | exp T_UNION exp { $$ = symbolic(($2.type==_FUNC?*$2._FUNCptr:*at_union),gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp T_UNION exp T_MOD { $$ = symbolic(($2.type==_FUNC?*$2._FUNCptr:*at_union),gen(makevecteur($1,$1*$3/100) ,_SEQ__VECT)); } + | exp T_INTERSECT exp { $$ = symb_intersect(gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp T_MINUS exp { $$ = symb_minus(gen(makevecteur($1,$3) ,_SEQ__VECT)); } + | exp T_PIPE exp { + $$=symbolic(*$2._FUNCptr,gen(makevecteur($1,$3) ,_SEQ__VECT)); + } + | T_QUOTED_BINARY { $$ = $1; } + | T_QUOTE exp T_QUOTE {if ($2.type==_FUNC) $$=$2; else { + // const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_quote($2); + } + } + | exp T_INDEX_BEGIN exp T_VECT_END { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$ = symb_at($1,$3,contextptr); + } + | exp T_INDEX_BEGIN T_VECT_DISPATCH exp T_VECT_END T_VECT_END { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$ = symbolic(at_of,gen(makevecteur($1,$4) ,_SEQ__VECT)); + } + | T_BEGIN_PAR exp T_END_PAR T_BEGIN_PAR suite T_END_PAR {$$ = check_symb_of($2,$5,giac_yyget_extra(scanner));} + | T_BEGIN_PAR exp T_END_PAR { + if ( ($1==_LIST__VECT && python_compat(giac_yyget_extra(scanner))) || + python_compat(giac_yyget_extra(scanner))==2){ + if (python_compat(giac_yyget_extra(scanner))==2) + $$=change_subtype($2,_TUPLE__VECT); + else + $$=symbolic(at_python_list,$2); + } + else { + if (abs_calc_mode(giac_yyget_extra(scanner))==38 && $2.type==_VECT && $2.subtype==_SEQ__VECT && $2._VECTptr->size()==2 && ($2._VECTptr->front().type<=_DOUBLE_ || $2._VECTptr->front().type==_FLOAT_) && ($2._VECTptr->back().type<=_DOUBLE_ || $2._VECTptr->back().type==_FLOAT_)){ + const giac::context * contextptr = giac_yyget_extra(scanner); + gen a=evalf($2._VECTptr->front(),1,contextptr), + b=evalf($2._VECTptr->back(),1,contextptr); + if ( (a.type==_DOUBLE_ || a.type==_FLOAT_) && + (b.type==_DOUBLE_ || b.type==_FLOAT_)) + $$= a+b*cst_i; + else $$=$2; + } else { + if (calc_mode(giac_yyget_extra(scanner))==1 && $2.type==_VECT && $1!=_LIST__VECT && + $2.subtype==_SEQ__VECT && ($2._VECTptr->size()==2 || $2._VECTptr->size()==3) ) + $$ = gen(*$2._VECTptr,_GGB__VECT); + else + $$=$2; + } + } + } + | T_VECT_DISPATCH suite T_VECT_END { + //cerr << $1 << " " << $2 << '\n'; + $$ = gen(*($2._VECTptr),$1.val); + if ($2._VECTptr->size()==1 && $2._VECTptr->front().is_symb_of_sommet(at_ti_semi) ) { + $$=$2._VECTptr->front(); + } + // cerr << $$ << '\n'; + + } + | exp T_VIRGULE exp { + if ($1.type==_VECT && $1.subtype==_SEQ__VECT && !($3.type==_VECT && $2.subtype==_SEQ__VECT)){ $$=$1; $$._VECTptr->push_back($3); } + else + $$ = makesuite($1,$3); + + } + | T_NULL { $$=gen(vecteur(0),_SEQ__VECT); } + | T_HELP exp {$$=symb_findhelp($2);} + | exp T_INTERROGATION exp { $$=symb_interrogation($1,$3); } + | T_UNIT exp { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_unit(gen(1),$2,contextptr); + opened_quote(giac_yyget_extra(scanner)) &= 0x7ffffffd; + } + | exp T_UNIT exp { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_unit($1,$3,contextptr); + opened_quote(giac_yyget_extra(scanner)) &= 0x7ffffffd; } + | exp T_SQ { $$=symb_pow($1,$2); } + | error { + const giac::context * contextptr = giac_yyget_extra(scanner); +#ifdef HAVE_SIGNAL_H_OLD + messages_to_print += parser_filename(contextptr) + parser_error(contextptr); + /* *logptr(giac_yyget_extra(scanner)) << messages_to_print; */ +#endif + $$=undef; + spread_formula(false,contextptr); + } + | stack { $$=$1; } + | T_LOGO exp { $$=symbolic(*$1._FUNCptr,$2); } + | T_LOGO {$$ = symbolic(*$1._FUNCptr,gen(vecteur(0),_SEQ__VECT));} + | T_LOGO T_BEGIN_PAR T_END_PAR {$$ = symbolic(*$1._FUNCptr,gen(vecteur(0),_SEQ__VECT));} + | T_LOCALBLOC T_BEGIN_PAR exp T_END_PAR { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$ = symb_local($3,contextptr); + } + | T_LOCALBLOC {$$ = gen(at_local,2);} + | T_IF T_BEGIN_PAR exp T_END_PAR bloc else { + $$ = symbolic(*$1._FUNCptr,makevecteur(equaltosame($3),symb_bloc($5),$6)); + } + | T_IF T_BEGIN_PAR exp T_END_PAR exp T_SEMI else { + vecteur v=makevecteur(equaltosame($3),$5,$7); + // *logptr(giac_yyget_extra(scanner)) << v << '\n'; + $$ = symbolic(*$1._FUNCptr,v); + } + | T_RPN_BEGIN rpn_suite T_RPN_END { $$=symb_rpn_prog($2); } + | T_MAPLELIB { $$=$1; } + | T_MAPLELIB T_INDEX_BEGIN exp T_VECT_END { $$=symbolic(at_maple_lib,makevecteur($1,$3)); } + | T_PROC T_BEGIN_PAR suite T_END_PAR entete prg_suite T_BLOC_END { + if ($7.type==_INT_ && $7.val && $7.val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program($3,gen_zero*$3,symb_local($5,$6,contextptr),contextptr); + } + | T_PROC symbol T_BEGIN_PAR suite T_END_PAR entete prg_suite T_BLOC_END { + if ($8.type==_INT_ && $8.val && $8.val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($4,gen_zero*$4,symb_local($6,$7,contextptr),$2,false,contextptr); + } + | T_PROC symbol T_BEGIN_PAR suite T_END_PAR prg_suite T_BLOC_END { + if ($7.type==_INT_ && $7.val && $7.val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($4,gen_zero*$4,symb_bloc($6),$2,false,contextptr); + } + | T_PROC symbol T_BEGIN_PAR suite T_END_PAR T_BLOC_BEGIN entete prg_suite T_BLOC_END { + if ($9.type==_INT_ && $9.val && $9.val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($4,gen_zero*$4,symb_local($7,$8,contextptr),$2,false,contextptr); + } + | T_PROC T_BEGIN_PAR suite T_END_PAR entete T_BLOC_BEGIN prg_suite T_BLOC_END { + if ($8.type==_INT_ && $8.val && $8.val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program($3,gen_zero*$3,symb_local($5,$7,contextptr),contextptr); + } + | symbol T_BEGIN_PAR suite T_END_PAR T_PROC entete prg_suite T_BLOC_END { + if ($8.type==_INT_ && $8.val && $8.val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($3,gen_zero*$3,symb_local($6,$7,contextptr),$1,false,contextptr); + } + | symbol T_BEGIN_PAR suite T_END_PAR T_AFFECT T_PROC entete prg_suite T_BLOC_END { + if ($9.type==_INT_ && $9.val && $9.val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($3,gen_zero*$3,symb_local($7,$8,contextptr),$1,false,contextptr); + } + | T_FOR T_BEGIN_PAR exp_or_empty T_SEMI exp_or_empty T_SEMI exp_or_empty T_END_PAR bloc {$$ = symbolic(*$1._FUNCptr,makevecteur($3,equaltosame($5),$7,symb_bloc($9)));} + | T_FOR T_BEGIN_PAR exp_or_empty T_SEMI exp_or_empty T_SEMI exp_or_empty T_END_PAR exp T_SEMI {$$ = symbolic(*$1._FUNCptr,makevecteur($3,equaltosame($5),$7,$9));} + | T_FOR T_BEGIN_PAR exp T_END_PAR {$$ = symbolic(*$1._FUNCptr,gen2vecteur($3));} + | exp T_IN exp {$$=symbolic(at_member,makesequence($1,$3)); if ($2==at_not) $$=symbolic(at_not,$$);} + | exp T_NOT T_IN exp {$$=symbolic(at_not,symbolic(at_member,makesequence($1,$4)));} + | T_VECT_DISPATCH exp T_FOR suite_symbol T_IN exp T_VECT_END { $$=symbolic(at_apply,makesequence(symbolic(at_program,makesequence($4,0*$4,vecteur(1,$2))),$6)); if ($1==_TABLE__VECT) $$=symbolic(at_table,$$);} + | T_VECT_DISPATCH exp T_FOR suite_symbol T_IN exp T_IF exp T_VECT_END { $$=symbolic(at_apply,symbolic(at_program,makesequence($4,0*$4,vecteur(1,$2))),symbolic(at_select,makesequence(symbolic(at_program,makesequence($4,0*$4,$8)),$6))); if ($1==_TABLE__VECT) $$=symbolic(at_table,$$);} + | T_WHILE T_BEGIN_PAR exp T_END_PAR bloc { + vecteur v=makevecteur(gen_zero,equaltosame($3),gen_zero,symb_bloc($5)); + $$=symbolic(*$1._FUNCptr,v); + } + | T_WHILE T_BEGIN_PAR exp T_END_PAR exp T_SEMI { + $$=symbolic(*$1._FUNCptr,makevecteur(gen_zero,equaltosame($3),gen_zero,$5)); + } + | T_WHILE exp T_DO prg_suite T_BLOC_END { + if ($5.type==_INT_ && $5.val && $5.val!=9 && $5.val!=8) giac_yyerror(scanner,"missing loop end delimiter"); + $$=symbolic(*$1._FUNCptr,makevecteur(gen_zero,equaltosame($2),gen_zero,symb_bloc($4))); + } + | T_MUPMAP_WHILE exp T_DO prg_suite T_BLOC_END { + if ($5.type==_INT_ && $5.val && $5.val!=9 && $5.val!=8) giac_yyerror(scanner,"missing loop end delimiter"); + $$=symbolic(*$1._FUNCptr,makevecteur(gen_zero,equaltosame($2),gen_zero,symb_bloc($4))); + } + | T_TRY bloc T_CATCH T_BEGIN_PAR exp T_END_PAR bloc { $$=symb_try_catch(makevecteur(symb_bloc($2),$5,symb_bloc($7)));} + | T_TRY_CATCH T_BEGIN_PAR exp T_END_PAR {$$=symb_try_catch(gen2vecteur($3));} + | T_TRY_CATCH {$$=gen(at_try_catch,3);} + | T_SWITCH T_BEGIN_PAR exp T_END_PAR T_BLOC_BEGIN switch T_BLOC_END { $$=symb_case($3,$6); } + | T_CASE T_BEGIN_PAR T_SYMBOL T_END_PAR { $$ = symb_case($3); } + | T_CASE exp case T_ENDCASE { $$=symb_case($2,$3); } + | T_ACCENTGRAVE rpn_token T_ACCENTGRAVE { $$=$2; } + | T_RPN_OP { $$=$1; } + | T_RETURN TI_DEUXPOINTS {$$ = gen(*$1._FUNCptr,0);} + | TI_LOOP prg_suite ti_bloc_end { $$=symbolic(*$1._FUNCptr,makevecteur(gen_zero,gen(1),gen_zero,symb_bloc($2))); } + | T_IF exp TI_DEUXPOINTS exp {$$ = symbolic(*$1._FUNCptr,makevecteur(equaltosame($2),$4,0));} + | TI_TRY prg_suite T_ELSE prg_suite ti_bloc_end { $$=symb_try_catch(makevecteur(symb_bloc($2),at_break,symb_bloc($4))); } + | TI_TRY prg_suite T_ELSE ti_bloc_end { $$=symb_try_catch(makevecteur(symb_bloc($2),at_break,0)); } + | TI_TRY prg_suite TI_DEUXPOINTS T_ELSE prg_suite ti_bloc_end { $$=symb_try_catch(makevecteur(symb_bloc($2),at_break,symb_bloc($5))); } + | TI_TRY prg_suite TI_DEUXPOINTS T_ELSE ti_bloc_end { $$=symb_try_catch(makevecteur(symb_bloc($2),at_break,0)); } + | exp TI_SEMI exp { vecteur v1(gen2vecteur($1)),v3(gen2vecteur($3)); $$=symbolic(at_ti_semi,makevecteur(v1,v3)); } + | TI_DEUXPOINTS symbol T_BEGIN_PAR suite T_END_PAR TI_PRGM prg_suite TI_DEUXPOINTS TI_LOCAL suite TI_DEUXPOINTS prg_suite ti_bloc_end { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($4,$4*gen_zero,symb_local($10,mergevecteur(*$7._VECTptr,*$12._VECTptr),contextptr),$2,false,contextptr); + } + | TI_DEUXPOINTS symbol T_BEGIN_PAR suite T_END_PAR TI_PRGM prg_suite TI_LOCAL suite TI_DEUXPOINTS prg_suite ti_bloc_end { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($4,$4*gen_zero,symb_local($9,mergevecteur(*$7._VECTptr,*$11._VECTptr),contextptr),$2,false,contextptr); + } + | TI_DEUXPOINTS symbol T_BEGIN_PAR suite T_END_PAR TI_PRGM TI_DEUXPOINTS TI_LOCAL suite TI_DEUXPOINTS prg_suite ti_bloc_end { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($4,$4*gen_zero,symb_local($9,$11,contextptr),$2,false,contextptr); + } + | TI_DEUXPOINTS symbol T_BEGIN_PAR suite T_END_PAR TI_PRGM prg_suite ti_bloc_end { + $$=symb_program_sto($4,$4*gen_zero,symb_bloc($7),$2,false,giac_yyget_extra(scanner)); + } + | TI_DIALOG prg_suite ti_bloc_end { $$=symbolic(*$1._FUNCptr,$2); } + | TI_DIALOG bloc { $$=symbolic(*$1._FUNCptr,$2); } + | TI_DEUXPOINTS exp { $$=$2; } + | TI_DEFINE symbol T_BEGIN_PAR suite T_END_PAR T_EQUAL exp { $$=symb_program_sto($4,$4*gen_zero,$7,$2,false,giac_yyget_extra(scanner));} + | TI_DEFINE symbol T_BEGIN_PAR suite T_END_PAR T_EQUAL TI_PRGM TI_DEUXPOINTS TI_LOCAL suite TI_DEUXPOINTS prg_suite ti_bloc_end { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_program_sto($4,$4*gen_zero,symb_local($10,$12,contextptr),$2,false,contextptr); + } + | TI_DEFINE symbol T_BEGIN_PAR suite T_END_PAR T_EQUAL TI_PRGM prg_suite ti_bloc_end { $$=symb_program_sto($4,$4*gen_zero,symb_bloc($8),$2,false,giac_yyget_extra(scanner)); } + | TI_FOR suite TI_DEUXPOINTS prg_suite ti_bloc_end { + vecteur & v=*$2._VECTptr; + if ( (v.size()<3) || v[0].type!=_IDNT){ + *logptr(giac_yyget_extra(scanner)) << "Syntax For name,begin,end[,step]" << '\n'; + $$=undef; + } + else { + gen pas(gen(1)); + if (v.size()==4) + pas=v[3]; + gen condition; + if (is_positive(-pas,0)) + condition=symb_superieur_egal(v[0],v[2]); + else + condition=symb_inferieur_egal(v[0],v[2]); + vecteur w=makevecteur(symb_sto(v[1],v[0]),condition,symb_sto(symb_plus(v[0],pas),v[0]),symb_bloc($4)); + $$=symbolic(*$1._FUNCptr,w); + } + } + | TI_WHILE exp TI_DEUXPOINTS prg_suite ti_bloc_end { + vecteur v=makevecteur(gen_zero,equaltosame($2),gen_zero,symb_bloc($4)); + $$=symbolic(*$1._FUNCptr,v); + } + /* + | HP38_2ARGS exp T_SEMI exp { $$=symbolic(*$1._FUNCptr,gen(makevecteur($2,$4),_SEQ__VECT)); } + | HP38_3ARGS exp T_SEMI exp T_SEMI exp { $$=symbolic(*$1._FUNCptr,gen(makevecteur($2,$4,$6),_SEQ__VECT)); } + | HP38_4ARGS exp T_SEMI exp T_SEMI exp T_SEMI exp { $$=symbolic(*$1._FUNCptr,gen(makevecteur($2,$4,$6,$8),_SEQ__VECT)); } + | T_BLOC_BEGIN exp T_BLOC_END { $$=gen(gen2vecteur($2),_LIST__VECT); } + */ + ; + +symbol_for : T_SYMBOL { $$=$1; } + | T_SYMBOL T_VIRGULE T_SYMBOL { $$=makesequence($1,$3);} + | T_UNARY_OP { $$=$1; } + | T_UNARY_OP_38 { $$=$1; } + ; + +symbol : T_SYMBOL { $$=$1; } + | T_SYMBOL T_DOUBLE_DEUX_POINTS T_TYPE_ID { + gen tmp($3); + // tmp.subtype=1; + //$$=symb_check_type(makevecteur(tmp,$1),context0); + $$=symbolic(at_deuxpoints,makesequence($1,$3)); + } + | T_SYMBOL T_DOUBLE_DEUX_POINTS T_UNARY_OP { $$=symb_double_deux_points(makevecteur($1,$3)); } + | T_SYMBOL T_DOUBLE_DEUX_POINTS T_SYMBOL { $$=symb_double_deux_points(makevecteur($1,$3)); } + | T_SYMBOL T_DOUBLE_DEUX_POINTS T_UNARY_OP_38 { $$=symb_double_deux_points(makevecteur($1,$3)); } + | T_SYMBOL T_DOUBLE_DEUX_POINTS T_QUOTE exp T_QUOTE %prec TI_HASH { $$=symb_double_deux_points(makevecteur($1,$4)); } + | T_DOUBLE_DEUX_POINTS T_SYMBOL { $$=symb_double_deux_points(makevecteur(0,$2)); } + | T_NUMBER T_DOUBLE_DEUX_POINTS T_SYMBOL { $$=symb_double_deux_points(makevecteur($1,$3)); } + /* | T_SYMBOL T_DOUBLE_DEUX_POINTS exp { + if ($3.type==_INT_ && $3.subtype==_INT_TYPE){ + $$=symb_check_type(makevecteur($3,$1),context0); + } + else + $$=symb_double_deux_points(makevecteur($1,$3)); + } */ + | T_TYPE_ID T_SYMBOL { + gen tmp($1); + // tmp.subtype=1; + // $$=symb_check_type(makevecteur(tmp,$2),context0); + $$=symbolic(at_deuxpoints,makesequence($2,$1)); + } + | TI_HASH exp {$$=symbolic(*$1._FUNCptr,$2); } + ; + +symbol_or_literal: T_SYMBOL { $$=$1; } + | T_LITERAL { $$=$1; } + ; + +entete : /* empty */ { $$=makevecteur(vecteur(0),vecteur(0)); } + | entete local { vecteur v1 =gen2vecteur($1); vecteur v2=gen2vecteur($2); $$=makevecteur(mergevecteur(gen2vecteur(v1[0]),gen2vecteur(v2[0])),mergevecteur(gen2vecteur(v1[1]),gen2vecteur(v2[1]))); } + | nom entete { $$=$2; } + ; + + +stack: T_STACK T_BEGIN_PAR exp T_END_PAR { if ($3.type==_VECT) $$=gen(*$3._VECTptr,_RPN_STACK__VECT); else $$=gen(vecteur(1,$3),_RPN_STACK__VECT); } + | T_STACK T_NULL { $$=gen(vecteur(0),_RPN_STACK__VECT); } + ; + +local : T_LOCAL suite_symbol T_SEMI { if (!$1.val) $$=makevecteur($2,vecteur(0)); else $$=makevecteur(vecteur(0),$2);} + ; + +nom : T_NAME exp T_SEMI { $$=$2; } + ; + +suite_symbol : affectable_symbol { $$=gen(vecteur(1,$1),_SEQ__VECT); } + | suite_symbol T_VIRGULE affectable_symbol { + vecteur v=*$1._VECTptr; + v.push_back($3); + $$=gen(v,_SEQ__VECT); + } + ; + +affectable_symbol : symbol { $$=$1; } + | T_SYMBOL T_AFFECT exp { $$=parser_symb_sto($3,$1,$2==at_array_sto); } + | T_SYMBOL T_EQUAL exp { $$=symb_equal($1,$3); } + | T_SYMBOL T_DEUXPOINTS exp { $$=symbolic(at_deuxpoints,makesequence($1,$3)); } + | T_BEGIN_PAR affectable_symbol T_END_PAR { $$=$2; } + | T_UNARY_OP { $$=$1; *logptr(giac_yyget_extra(scanner)) << "Error: reserved word "<< $1 <<'\n';} + | T_UNARY_OP T_DOUBLE_DEUX_POINTS exp { $$=symb_double_deux_points(makevecteur($1,$3)); *logptr(giac_yyget_extra(scanner)) << "Error: reserved word "<< $1 <<'\n'; } + | T_TYPE_ID { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=string2gen("_"+$1.print(contextptr),false); + if (!giac::first_error_line(contextptr)){ + giac::first_error_line(giac::lexer_line_number(contextptr),contextptr); + giac:: error_token_name($1.print(contextptr)+ " (reserved word)",contextptr); + } +} + | T_NUMBER { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=string2gen("_"+$1.print(contextptr),false); + if (!giac::first_error_line(contextptr)){ + giac::first_error_line(giac::lexer_line_number(contextptr),contextptr); + giac:: error_token_name($1.print(contextptr)+ " reserved word",contextptr); + } +} + ; + +exp_or_empty: /* empty */ { $$=gen(1);} + | exp { $$=$1; } + ; + +suite: /* empty */ { $$=gen(vecteur(0),_SEQ__VECT); } + | exp { $$=makesuite($1); } + ; + +prg_suite: exp { $$ = gen(makevecteur($1),_PRG__VECT); } + /* | bloc { $$=gen(makevecteur(symb_bloc($1)),_PRG__VECT); } */ + | prg_suite exp { vecteur v(1,$1); + if ($1.type==_VECT) v=*($1._VECTptr); + v.push_back($2); + $$ = gen(v,_PRG__VECT); + } + | prg_suite semi { $$ = $1;} + ; + +rpn_suite : /* empty */ { $$=vecteur(0); } + | rpn_token rpn_suite { $$=mergevecteur(vecteur(1,$1),*($2._VECTptr));} + | rpn_token T_VIRGULE rpn_suite { $$=mergevecteur(vecteur(1,$1),*($3._VECTptr));} + ; + +rpn_token : T_UNARY_OP { $$=$1; } + ; + /* Commented to save space + | T_QUOTE T_UNARY_OP T_QUOTE { $$=$2; } + | T_NUMBER {$$ = $1;} + | symbol {$$ = $1;} + | T_STRING { $$=$1; } + | T_UNIT rpn_token { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_unit(gen(1),$2,contextptr); + } + | T_NUMBER T_UNIT rpn_token { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$=symb_unit($1,$3,contextptr); + } + | T_VECT_DISPATCH rpn_suite T_VECT_END { $$=$2; } + | T_PLUS { $$=gen(at_plus,2); } + | T_MOINS { $$=gen(at_binary_minus,2); } + | T_DIV { $$=gen(at_division,2); } + | T_FOIS { $$=gen(at_prod,2); } + | T_POW { $$=gen(at_pow,2); } + | T_EQUAL { $$=gen(at_equal); } + | T_MOD { $$=gen(*$1._FUNCptr,2); } + | T_INTERVAL { $$=gen(at_interval,2); } + | T_AND_OP {$$ = gen(at_and,2);} + | T_TEST_EQUAL { $$=$1; } + | T_OF { $$=gen(at_of,2); } + | T_DOLLAR { $$ = gen(at_dollar,2); } + | T_COMPOSE { $$ = gen(at_compose,2); } + | T_UNION { $$ = gen(at_union,2); } + | T_INTERSECT { $$ = gen(at_intersect,2); } + | T_MINUS { $$ = gen(at_minus,2); } + | T_RPN_OP { $$=$1; } + | T_QUOTE T_RPN_OP T_QUOTE { $$=$2; } + | T_QUOTED_BINARY { $$=$1; } + | T_RPN_BEGIN rpn_suite T_RPN_END { $$=gen(*$2._VECTptr,_RPN_FUNC__VECT); } + | T_QUOTE exp T_QUOTE {$$ = symb_quote($2);} + | T_IFTE {$$ = gen(at_IFTE,3);} + | T_RPN_IF rpn_suite T_THEN rpn_suite T_BLOC_END { $$=symb_IFTE(makevecteur($2,$4,symb_NOP(vecteur(0)))); } + | T_RPN_IF rpn_suite T_THEN rpn_suite T_ELSE rpn_suite T_BLOC_END { $$=symb_IFTE(makevecteur($2,$4,$6)); } + | T_START rpn_suite T_BY { vecteur v=*$2._VECTptr; gen step(gen(1)); if (!v.empty()) { step=v.back(); v.pop_back();} $$=symb_RPN_FOR(makevecteur(identificateur(" j"),step),gen(v,_RPN_FUNC__VECT)); } + | T_START rpn_suite T_CONTINUE { $$=symb_RPN_FOR(makevecteur(identificateur(" j"),gen(1)),$2); } + | T_FOR symbol rpn_suite T_BY { vecteur v=*$3._VECTptr; gen step(gen(1)); if (!v.empty()) { step=v.back(); v.pop_back();} $$=symb_RPN_FOR(makevecteur($2,step),gen(v,_RPN_FUNC__VECT)); } + | T_FOR symbol rpn_suite T_CONTINUE { $$=symb_RPN_FOR(makevecteur($2,gen(1)),$3); } + | T_RPN_WHILE rpn_suite T_REPEAT rpn_suite T_BLOC_END { $$=symb_RPN_WHILE($2,$4);} + | T_DO rpn_suite T_UNTIL rpn_suite T_BLOC_END { $$=symb_RPN_UNTIL($2,$4); } + | T_MAPSTO symbol_suite rpn_sub_prog { $$=symb_RPN_LOCAL($2,$3); } + | T_CASE rpn_case T_BLOC_END { $$=symb_RPN_CASE($2); } + | T_CASE rpn_case rpn_suite T_BLOC_END { vecteur v(*$2._VECTptr); v.push_back($3); $$=symb_RPN_CASE(v); } + | stack { $$=$1; } + ; + +rpn_sub_prog : T_RPN_BEGIN rpn_suite T_RPN_END { $$=gen(*$2._VECTptr,_RPN_FUNC__VECT); } + | T_QUOTE exp T_QUOTE {$$ = symb_quote($2);} + ; + +symbol_suite : symbol { $$=vecteur(1,$1); } + | symbol_suite symbol { vecteur v=*$1._VECTptr; v.push_back($2); $$=v; } + ; + +rpn_case: { $$=vecteur(0); } + | rpn_case rpn_suite T_THEN rpn_suite T_BLOC_END { + vecteur v(*$1._VECTptr); + v.push_back($2); + v.push_back($4); $$=v; + } + ; + + end rpn_token comment to save space */ + +step: /* empty */ { $$=gen(1); } + | T_BY exp { $$=$2; } + ; + +from: /* empty */ { $$=gen(1); } + | T_AFFECT exp { $$=$2; } + | T_EQUAL exp { $$=$2; } + | T_FROM exp { $$=$2; } + ; + +loop38_do: T_SEMI { $$=gen(1); } + | T_DO { $$=$1; } + ; + +else: /* empty */ { $$=0; } + | ti_else exp T_SEMI { $$=$2; } + | ti_else bloc { $$=symb_bloc($2); } + /* | TI_DEUXPOINTS T_ELSE prg_suite {$$=symb_bloc($3); } */ + ; + +bloc : T_BLOC_BEGIN prg_suite T_BLOC_END { + $$ = $2; + } + | T_BLOC_BEGIN entete prg_suite T_BLOC_END { + const giac::context * contextptr = giac_yyget_extra(scanner); + $$ = symb_local($2,$3,contextptr); + } + /* | T_BLOC_BEGIN T_COMMENT local prg_suite T_BLOC_END { $$ = symb_local($3,$4,contextptr);} */ + ; + +elif: ti_bloc_end { if ($1.type==_INT_ && $1.val && $1.val!=4) giac_yyerror(scanner,"missing test end delimiter"); $$=0; } + | ti_else prg_suite ti_bloc_end { + if ($3.type==_INT_ && $3.val && $3.val!=4) giac_yyerror(scanner,"missing test end delimiter"); + $$=symb_bloc($2); + } + | T_ELIF exp T_THEN prg_suite elif { + $$=symb_ifte(equaltosame($2),symb_bloc($4),$5); + } + | TI_DEUXPOINTS T_ELIF exp T_THEN prg_suite elif { + $$=symb_ifte(equaltosame($3),symb_bloc($5),$6); + } + ; + +ti_bloc_end: T_BLOC_END { $$=$1; } + | TI_DEUXPOINTS T_BLOC_END { $$=$2; } + ; + +ti_else: T_ELSE { $$=0; } + | TI_DEUXPOINTS T_ELSE { $$=0; } + ; + +switch: /* empty */ { $$=vecteur(0); } + | T_DEFAULT T_DEUXPOINTS bloc { $$=makevecteur(symb_bloc($3));} + | T_CASE T_NUMBER T_DEUXPOINTS bloc switch { $$=mergevecteur(makevecteur($2,symb_bloc($4)),*($5._VECTptr));} + ; + +case: /* empty */ { $$=vecteur(0); } + | T_DEFAULT prg_suite { $$=vecteur(1,symb_bloc($2)); } + | T_OF T_NUMBER T_DO prg_suite case { $$=mergevecteur(makevecteur($2,symb_bloc($4)),*($5._VECTptr));} + ; + +case38: /* empty */ { $$=vecteur(0); } + | T_DEFAULT prg_suite { $$=vecteur(1,symb_bloc($2)); } + | T_IF exp T_THEN prg_suite T_BLOC_END case38 { $$=mergevecteur(makevecteur($2,symb_bloc($4)),gen2vecteur($6));} + | T_IF exp T_THEN prg_suite T_BLOC_END T_SEMI case38 { $$=mergevecteur(makevecteur($2,symb_bloc($4)),gen2vecteur($7));} + ; + +semi: T_SEMI { $$=$1; } + ; + +/* + * Routines + */ + +%% + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac + + +#endif // ndef NO_NAMESPACE_GIAC +int giac_yyget_column (yyscan_t yyscanner); + +// Error print routine (store error string in parser_error) +#if 1 +int giac_yyerror(yyscan_t scanner,const char *s) { + const giac::context * contextptr = giac_yyget_extra(scanner); + int col = giac_yyget_column(scanner); + int line = giac::lexer_line_number(contextptr); + const char * scanb=giac::currently_scanned(contextptr); + std::string curline; + if (scanb){ + for (int i=1;isuffix.size() && token_name.compare(token_name.size()-suffix.size(),suffix.size(),suffix)) { + if (col>=token_name.size()-suffix.size()) { + col -= token_name.size()-suffix.size(); + } + } else if (col>=token_name.size()) { + col -= token_name.size(); + } + giac::lexer_column_number(contextptr)=col; + string sy("syntax error "); + if (0 && strlen(s)){ + sy += ": "; + sy += s; + sy +=", "; + } + if (is_at_end) { + parser_error(":" + giac::print_INT_(line) + ": " +sy + " at end of input\n",contextptr); // string(s) replaced with syntax error + giac::parsed_gen(giac::undef,contextptr); + } else { + parser_error( ":" + giac::print_INT_(line) + ": " + sy + " line " + giac::print_INT_(line) + " col " + giac::print_INT_(col) + " at " + token_name +" in "+curline+" \n",contextptr); // string(s) replaced with syntax error + giac::parsed_gen(giac::string2gen(token_name,false),contextptr); + } + if (!giac::first_error_line(contextptr)) { + giac::first_error_line(line,contextptr); + if (is_at_end) { + token_name="end of input"; + } + giac:: error_token_name(token_name,contextptr); + } + return line; +} + +#else + +int giac_yyerror(yyscan_t scanner,const char *s) +{ + const giac::context * contextptr = giac_yyget_extra(scanner); + int col= giac_yyget_column(scanner); + giac::lexer_column_number(contextptr)=col; + if ( (*giac_yyget_text( scanner )) && (giac_yyget_text( scanner )[0]!=-61) && (giac_yyget_text( scanner )[1]!=-65)){ + std::string txt=giac_yyget_text( scanner ); + parser_error( ":" + giac::print_INT_(giac::lexer_line_number(contextptr)) + ": " + string(s) + " line " + giac::print_INT_(giac::lexer_line_number(contextptr)) + " col " + giac::print_INT_(col) + " at " + txt +"\n",contextptr); + giac::parsed_gen(giac::string2gen(txt,false),contextptr); + } + else { + parser_error(":" + giac::print_INT_(giac::lexer_line_number(contextptr)) + ": " +string(s) + " at end of input\n",contextptr); + giac::parsed_gen(giac::undef,contextptr); + } + if (!giac::first_error_line(contextptr)){ + giac::first_error_line(giac::lexer_line_number(contextptr),contextptr); + std::string s=string(giac_yyget_text( scanner )); + if (s.size()==2 && s[0]==-61 && s[1]==-65) + s="end of input"; + giac:: error_token_name(s,contextptr); + } + return giac::lexer_line_number(contextptr); +} +#endif diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/TmpFGLM.cpp b/android/app/src/main/cpp/giac/src/giac/cpp/TmpFGLM.cpp new file mode 100644 index 0000000..b0036b8 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/TmpFGLM.cpp @@ -0,0 +1,226 @@ +/* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -I../include -g -c -Wall TmpFGLM.C" -*- */ +// Copyright (c) 2006 Stefan Kaspar + +// This file is part of the source of CoCoALib, the CoCoA Library. + +// CoCoALib is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License (version 3) +// as published by the Free Software Foundation. A copy of the full +// licence may be found in the file COPYING in this directory. + +// CoCoALib is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with CoCoA; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "first.h" +#ifdef USE_GMP_REPLACEMENTS +#undef HAVE_LIBCOCOA +#endif +#ifdef HAVE_LIBCOCOA +#include "TmpFGLM.H" +#include "TmpLESystemSolver.H" +#include "CoCoA/DenseMatrix.H" +#include "CoCoA/symbol.H" +#include "CoCoA/QBGenerator.H" +#include "CoCoA/RingDistrMPolyInlPP.H" +#include "CoCoA/RingHom.H" +#include "CoCoA/SparsePolyRing.H" + +// #include +using std::size_t; +#include +using std::set; +// #include // Included by QBGenerator.H +using std::list; +#include +using std::map; +// #include // Included by SparsePolyRing.H +using std::auto_ptr; +#include +using std::make_pair; +// #include +using std::vector; + +namespace CoCoADortmund +{ + using namespace CoCoA; + + // Used for constructing matrices to solve linear equation systems + // (Kind of sparse matrix representation) + struct MatrixMapEntry + { + MatrixMapEntry(ConstRefRingElem r): rhs(r) {} + std::vector VarIndices; // Column numbers in linear equation matrix + std::vector coeffs; // Matrix components in linear equation matrix + RingElem rhs; // Right hand side component in linear equation + }; + + + // Embed element p of PPM into another PPM with different term ordering + PPMonoidElem PPIntoOtherPPM(ConstRefPPMonoidElem p, const PPMonoid& OtherPPM) + { + vector expv; + exponents(expv, p); + return PPMonoidElem(OtherPPM, expv); + } + + // Update matrix map during main loop + // !! Weakly exception safe, writable parameters might get rendered useless !! + void UpdateMatrixMap(map& MatrixMap, size_t& NumCols, QBGenerator& NewQB, ConstRefRingElem p, ConstRefPPMonoidElem t) + { + for (SparsePolyIter m = BeginIter(p); !IsEnded(m); ++m) + { + map::iterator entry = MatrixMap.find(PP(m)); + // ToDo: Avoid this tedious if-else block + if (entry == MatrixMap.end()) + { + ring K = CoeffRing(AsSparsePolyRing(owner(p))); + struct MatrixMapEntry NewEntry(zero(K)); + NewEntry.VarIndices.push_back(NumCols); + NewEntry.coeffs.push_back(coeff(m)); + MatrixMap.insert(make_pair(PP(m), NewEntry)); + } + else + { + entry->second.VarIndices.push_back(NumCols); + entry->second.coeffs.push_back(coeff(m)); + } + } + ++NumCols; + + // Update quotient basis NewQB + NewQB.myCornerPPIntoQB(t); + } + + // FGLM implementation + // exception safe + void FGLMBasisConversion(vector& NewGB, const vector& OldGB, const PPOrdering& NewOrdering) + { + if (OldGB.empty()) + CoCoA_ERROR(ERR::nonstandard, "FGLMBasisConversion: empty Groebner Basis vector"); + + // Check if generated ideal is zero-dimensional + const ideal I(AsSparsePolyRing(owner(OldGB.front())), OldGB); + if (!IsZeroDim(I)) + CoCoA_ERROR(ERR::nonstandard, "FGLMBasisConversion: ideal must be 0-dimensional"); + + // Initialization of objects needed for computation + const SparsePolyRing Kx = AsSparsePolyRing(owner(OldGB.front())); + const ring K = CoeffRing(Kx); + const PPMonoid PPMon = PPM(Kx); + const RingElem FieldOne(one(K)); + + // Adjust K[x_1, ..., x_n] and PPM(K[x_1, ..., x_n]) to correct term ordering + const PPMonoid PPMAdjusted = NewPPMonoid(symbols(Kx), NewOrdering); + const SparsePolyRing KxAdjusted = NewPolyRing(CoeffRing(Kx), PPMAdjusted); + +// // Identity mapping Kx -> KxAdjusted +// // (Not yet used) +// RingHom KxToKxAdjusted = PolyRingHom(Kx, KxAdjusted, CoeffEmbeddingHom(KxAdjusted), indets(KxAdjusted)); + + // These will hold the (temporary) basis elements + vector NewGBTmp; // Holds elements in K[x_1, ..., x_n] w.r.t. new term ordering + QBGenerator NewQB(PPMAdjusted); // Holds the new QB in PPM with new term ordering + map MatrixMap; // Used to create the matrices for the linear dependency check + size_t NumCols = 1; + + // FGLM algorithm start + PPMonoidElem t(PPMAdjusted); + t = one(PPMAdjusted); + NewQB.myCornerPPIntoQB(t); + struct MatrixMapEntry entry(zero(K)); + entry.VarIndices.push_back(0); + entry.coeffs.push_back(FieldOne); + MatrixMap.insert(make_pair(PPIntoOtherPPM(t, PPMon), entry)); // Want to keep the keys (PPs) in PPM with old term ordering + + while (!NewQB.myCorners().empty()) + { + t = NewQB.myCorners().front(); // t is element of PPMAdjusted + RingElem h(Kx); + h = NR(monomial(Kx, FieldOne, PPIntoOtherPPM(t, PPMon)), OldGB); + vector< map::iterator > ResetPos; + // Prepare creation of linear equation system and check if a solution can + // exist (simple check if equations like "0 = c" would occur with c not + // equal to 0) + bool RemainderMightBeIndependent = true; + for (SparsePolyIter m = BeginIter(h); !IsEnded(m); ++m) + { + map::iterator entry = MatrixMap.find(PP(m)); + // If h contains a term that is not already in the matrix map + // then h is linearly independent of the previously computed remainders + if (entry == MatrixMap.end()) + { + RemainderMightBeIndependent = false; // Only reset-operations after matrix creation code below need to be carried out + UpdateMatrixMap(MatrixMap, NumCols, NewQB, h, t); + break; + } + else + { + // Right hand side component equals coeff(m) + entry->second.rhs = -coeff(m); + ResetPos.push_back(entry); + } + } + + // If it is not yet clear if the current remainder is linearly dependent on + // the previously computed remainders we have to create a linear equation + // system and try to solve it + if (RemainderMightBeIndependent) + { + // Create a system of linear equations from matrix map + matrix M = NewDenseMat(K, MatrixMap.size(), NumCols), + b = NewDenseMat(K, MatrixMap.size(), 1); + size_t j = 0; // Current row + + for (map::iterator entry = MatrixMap.begin(); entry != MatrixMap.end(); ++entry, ++j) + { + vector& VarIndices = entry->second.VarIndices; + vector& coeffs = entry->second.coeffs; + + // Set matrix components + for (size_t k = 0; k < VarIndices.size(); ++k) + SetEntry(M, j, VarIndices[k], coeffs[k]); + + // Set right hand side component + SetEntry(b, j, 0, entry->second.rhs); + } + + // Check if M*x = b has a solution + matrix x = NewDenseMat(K, NumCols, 1); + if (LESystemSolver(x, M, b)) + { + // Compute new Groebner Basis polynomial + RingElem g(KxAdjusted); // g in K[x_1, ..., x_n] with correct term ordering + g = monomial(KxAdjusted, FieldOne, t); + const vector& QB = NewQB.myQB(); + for (size_t i = 0; i < NumCols; ++i) + g += monomial(KxAdjusted, x(i, 0), QB[i]); + NewGBTmp.push_back(g); + + // Update quotient basis NewQB + NewQB.myCornerPPIntoAvoidSet(t); + } + else + UpdateMatrixMap(MatrixMap, NumCols, NewQB, h, t); + } + + // Reset right hand side components in matrix map + for (size_t i = 0; i < ResetPos.size(); ++i) + ResetPos[i]->second.rhs = zero(K); + } + + // Swap computed Groebner Basis + swap(NewGB, NewGBTmp); + } + +} // End of namespace CoCoA + +#endif diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/TmpLESystemSolver.cpp b/android/app/src/main/cpp/giac/src/giac/cpp/TmpLESystemSolver.cpp new file mode 100644 index 0000000..bb0ba57 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/TmpLESystemSolver.cpp @@ -0,0 +1,157 @@ +/* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -I../include -g -c -Wall TmpLESystemSolver.C" -*- */ +// Copyright (c) 2006 Stefan Kaspar + +// This file is part of the source of CoCoALib, the CoCoA Library. + +// CoCoALib is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License (version 3) +// as published by the Free Software Foundation. A copy of the full +// licence may be found in the file COPYING in this directory. + +// CoCoALib is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with CoCoA; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "first.h" +#ifdef USE_GMP_REPLACEMENTS +#undef HAVE_LIBCOCOA +#endif +#ifdef HAVE_LIBCOCOA +#include "TmpLESystemSolver.H" +#include "CoCoA/DenseMatrix.H" +#include "CoCoA/matrix.H" +#include "CoCoA/ring.H" +#include "CoCoA/error.H" + +// #include // Included by DenseMatrix.H +using std::vector; +#include +using std::pair; +using std::make_pair; +// #include // Included by DenseMatrix.H +using std::size_t; + +namespace CoCoADortmund +{ + using namespace CoCoA; + + // Create a copy of a matrix + void CopyMatrix(matrix& MTarget, const matrix& MSource) + { + const size_t NumRowsMSource = NumRows(MSource); + const size_t NumColsMSource = NumCols(MSource); + + for (size_t row = 0; row < NumRowsMSource; ++row) + for (size_t col = 0; col < NumColsMSource; ++col) + SetEntry(MTarget, row, col, MSource(row, col)); + } + + // Solve the linear system M*x = b by using Gauss' algorithm + bool LESystemSolver(matrix& x0, const matrix& M, const matrix& b) + { + const size_t NumRowsM = NumRows(M); + const size_t NumColsM = NumCols(M); + const size_t NumRowsb = NumRows(b); + const size_t NumColsb = NumCols(b); + + // Dimension check + if (NumRowsM != NumRowsb) + CoCoA_ERROR(ERR::BadMatrixSize, "mySolve: M and b must have same number of rows."); + if (NumColsM != NumRows(x0)) + CoCoA_ERROR(ERR::BadMatrixSize, "mySolve: M and x0 must have same number of columns."); + if (NumCols(x0) != 1) + CoCoA_ERROR(ERR::BadMatrixSize, "mySolve: NumCols(x0) > 1."); + if (NumColsb != 1) + CoCoA_ERROR(ERR::BadMatrixSize, "mySolve: NumCols(b) > 1."); + + // Field check; should we also check if BaseRing(M) = BaseRing(b) = BaseRing(x0)? + ring K(BaseRing(M)); + if (!IsField(K)) + CoCoA_ERROR(ERR::NotField, "mySolve: Gauss' algorithm over non-fields not yet implemented."); + + // Create working copies of M and b + matrix MCopy(NewDenseMat(K, NumRowsM, NumColsM)); + CopyMatrix(MCopy, M); + matrix bCopy(NewDenseMat(K, NumRowsb, NumColsb)); + CopyMatrix(bCopy, b); + + // For solution computation + vector< pair > positions; + + // Apply Gauss' algorithm + RingElem c(K); + size_t row = 0; + for (size_t col = 0; col < NumColsM && row < NumRowsM; ++col) + { + // Check if current column contains an element != 0 + if (IsZero(MCopy(row, col))) + { + size_t i = row+1; + for ( ; i < NumRowsM; ++i) + { + if (!IsZero(MCopy(i, col))) + { + // Switch MCopy and bCopy rows + MCopy->mySwapRows(i, row); + bCopy->mySwapRows(i, row); + break; + } + } + if (i == NumRowsM) + continue; + } + + // For solution computation + positions.push_back(make_pair(row, col)); + + // Found an element != 0 in current column; apply elemination + c = MCopy(row, col); + + for (size_t i = row+1; i < NumRowsM; ++i) + { + // Transform MCopy and bCopy + bCopy->myAddRowMul(i, row, -MCopy(i, col)/c); + MCopy->myAddRowMul(i, row, -MCopy(i, col)/c); + } + + ++row; + } + + // row = rank(MCopy); check if a solution for the equation system exists + for (size_t i = row; i < NumRowsb; ++i) + { + if (!IsZero(bCopy(i, 0))) + return false; + } + + // Compute components (x_1, ..., x_n) of vector x0 backwards from x_n to x_1, + // possibly skipping some components + matrix x0Tmp = NewDenseMat(K, NumRows(x0), 1); + while (!positions.empty()) + { + const size_t i = positions.back().first, j = positions.back().second; + + RingElem x(bCopy(i, 0)); + for (size_t k = j + 1; k < NumColsM; ++k) + { + x -= MCopy(i, k) * x0Tmp(k, 0); + } + SetEntry(x0Tmp, j, 0, x/MCopy(i, j)); + + positions.pop_back(); + } + CopyMatrix(x0, x0Tmp); + + return true; + } + +} // end of namespace CoCoA +#endif diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/alg_ext.cc b/android/app/src/main/cpp/giac/src/giac/cpp/alg_ext.cc new file mode 100644 index 0000000..cf7be42 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/alg_ext.cc @@ -0,0 +1,2124 @@ +// -*- mode:C++ ; compile-command: "g++ -I.. -I../include -DHAVE_CONFIG_H -DIN_GIAC -DGIAC_GENERIC_CONSTANTS -fno-strict-aliasing -g -c alg_ext.cc -Wall" -*- +#include "giacPCH.h" + +/* + * Copyright (C) 2000,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using namespace std; +#include +#include +#include +#include +#include +#include "gen.h" +#include "gausspol.h" +#include "identificateur.h" +#include "poly.h" +#include "usual.h" +#include "sym2poly.h" +#include "vecteur.h" +#include "modpoly.h" +#include "alg_ext.h" +#include "vecteur.h" +#include "solve.h" +#include "subst.h" +#include "plot.h" +#include "derive.h" +#include "ezgcd.h" +#include "prog.h" +#include "intg.h" +#include "csturm.h" +#include "lin.h" +#include "ti89.h" +#include "giacintl.h" + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + bool islesscomplex(const gen & a,const gen & b){ + if (a==b) + return false; + return a.islesscomplexthan(b); + } + + // symbolic_rootof_list() protected with a mutex in multi-thread environment + bool comparegen::operator ()(const gen & a,const gen & b) const { + if (a.type==_INT_ && b.type==_INT_) + return a.valsize()==2 && (A1=a._VECTptr->front()).type==_INT_ && (A2=a._VECTptr->back()).type==_INT_ && b.type==_VECT && b._VECTptr->size()==2 && (B1=b._VECTptr->front()).type==_INT_ && (B2=b._VECTptr->back()).type==_INT_){ + return (A1.val!=B1.val)?A1.valsecond.type==_VECT) + res=*rit->second._VECTptr; + rootof_unlock(); + return !res.empty(); + } + + // cache list of Galois conjugates + bool galoisconj_cache(const vecteur & v,const vecteur & res){ + if (rootof_trylock()) + return false; + rootmap::iterator ritend=galoisconj_list().end(),rit=galoisconj_list().find(v); + if (rit==ritend) + galoisconj_list()[v]=res; + rootof_unlock(); + return true; + } + + gen makeline(const gen & a,const gen &b){ + return gen(makevecteur(a,b),_LINE__VECT); + } + + vecteur galoisconj(const vecteur & v,GIAC_CONTEXT){ + vecteur res; + if (galoisconj_cached(v,res)) + return res; + gen g=symb_horner(v,vx_var); +#ifndef FXCG + if (pari_galoisconj(g,res,contextptr)) + return res; +#endif + if (int(v.size())>MAX_COMMON_ALG_EXT_ORDER_SIZE) return res; + // factor v over rootof(v) if degree is small + g=_factors(makesequence(g,rootof(g,contextptr)),contextptr); + if (g.type!=_VECT) return res; + vecteur w=*g._VECTptr; + for (int i=0;isecond.type==_VECT){ + res=*rit->second._VECTptr; + if (res.size()==2 && res.front().type==_VECT && res.back().type==_DOUBLE_){ + oldeps=res.back()._DOUBLE_val; + res=*res.front()._VECTptr; + } + else + res.clear(); + } + rootof_unlock(); + return !res.empty() && oldeps<=eps; + } + + bool proot_cache(const vecteur & v,double eps,const vecteur & res){ + if (rootof_trylock()) + return false; + rootmap::iterator ritend=proot_list().end(),rit=proot_list().find(v); + if (rit!=ritend){ + if (rit->second.type!=_VECT || rit->second._VECTptr->size()!=2 || rit->second._VECTptr->front().type!=_VECT || rit->second._VECTptr->back().type!=_DOUBLE_ || rit->second._VECTptr->back()._DOUBLE_val>eps) + rit->second=makevecteur(res,eps); + } + else + proot_list()[v]=makevecteur(res,eps); + rootof_unlock(); + return true; + } + + gen algebraic_EXTension(const gen & a_,const gen & v){ + gen a(a_); + if (a.type==_VECT && !a._VECTptr->empty() && is_zero(a._VECTptr->front())){ + a=trim(*a._VECTptr,0); + } + if (is_zero(a) ) + return 0; + if (a.type==_VECT){ + if (a._VECTptr->empty()) + return zero; + if (a._VECTptr->size()==1) + return a._VECTptr->front(); + // a.subtype=_POLY1__VECT; + } + gen res; +#ifdef SMARTPTR64 + * ((ulonglong * ) &res) = ulonglong(new ref_algext) << 16; +#else + res.__EXTptr=new ref_algext; +#endif + res.type=_EXT; + *(res._EXTptr+1) = v; + // if (v.type==_VECT) (res._EXTptr+1)->subtype=_POLY1__VECT; + if (a.type==_FRAC){ + *res._EXTptr = a._FRACptr->num; + return fraction(res,a._FRACptr->den); + } + *res._EXTptr = a; + return res; + } + + gen in_select_root(const vecteur & a,bool reel,GIAC_CONTEXT,double eps){ + if (a.empty() || is_undef(a)) + return undef; + if (reel){ + // bug fix for x1:=sqrt((sqrt(2*(sqrt(17)-1))-2)/2); normal(1+(-x1)^2); + gen amax(minus_inf); + for (int i=0;i (1+eps)*max_re ){ + current=*it; + max_re=cur_re; + max_im=cur_im; + } + else { // same argument + if ( absdouble(cur_re-max_re)max_im) ){ + current=*it; + max_im=cur_im; + } + } + } + if (reel && is_strictly_positive(-im(current,contextptr),contextptr)) + current=conj(current,contextptr); + return current; + } + + gen select_root(const vecteur & v,GIAC_CONTEXT){ + for (int i=0;i=_POLY) + return undef; + } + int n=decimal_digits(contextptr); + if (n<12) n=12; + if (n>307) n=307; + double eps=std::pow(0.1,n); + int rprec=int(n*3.3); + vecteur a=proot(v,eps,rprec,contextptr); + gen r=in_select_root(a,is_real(v,contextptr),contextptr); + return r; + } + + gen alg_evalf(const gen & a,const gen &b,const gen & c,GIAC_CONTEXT){ + if (a.type==_FRAC) + return rdiv(alg_evalf(a._FRACptr->num,b,c,contextptr),alg_evalf(a._FRACptr->den,b,c,contextptr),contextptr); + gen a1=a.evalf(1,contextptr),b1=b.evalf(1,contextptr); + if (a1.type!=_VECT) + return a1; + if (b1.type!=_VECT) + return algebraic_EXTension(a1,b1); + gen r; + if (c.type==_VECT && c._VECTptr->size()>=2) + r=(*c._VECTptr)[1]; + else + r=select_root(*b1._VECTptr,contextptr); + if (is_undef(r)) + return algebraic_EXTension(a1,b1); + r=horner(*a1._VECTptr,r); + gen rr,ri; reim(r,rr,ri,contextptr); + if (!has_i(b) && is_greater(epsilon(contextptr),abs(ri/rr,contextptr),contextptr)) + r=rr; + return r; + } + + gen ext_reduce(const gen & a, const gen & v){ + if (a.type==_FRAC) + return fraction(ext_reduce(a._FRACptr->num,v),ext_reduce(a._FRACptr->den,v)); + if (a.type!=_VECT) + return a;// algebraic_EXTension(a,v); + if (a._VECTptr->empty()) + return zero; + if (a._VECTptr->size()==1) + return a._VECTptr->front(); + if (v.type==_VECT){ + if (a._VECTptr->size()size()) + return algebraic_EXTension(a,v); +#if 1 + // special code for quadratic extension, if v=[1,0,-a] + if (v._VECTptr->size()==3 && v[0]==1 && v[1]==0){ + gen x=-v[2],r1,r0; + if (a._VECTptr->size()==3){ + r0=a._VECTptr->front()*x+a._VECTptr->back(); + r1=(*a._VECTptr)[1]; + } + else { + const_iterateur it=a._VECTptr->begin(),itend=a._VECTptr->end()-1; + for (;itfront()=r1; + c._VECTptr->back()=r0; + return algebraic_EXTension(c,v); + } + gen c=new ref_vecteur; + vecteur & rem=*c._VECTptr; + modpoly quo; + environment env; + DivRem(*a._VECTptr,*v._VECTptr,0,quo,rem); + if (rem.empty()) return 0; + if (rem.size()==1) return rem.front(); + return algebraic_EXTension(c,v); +#endif + return algebraic_EXTension((*a._VECTptr) % (*v._VECTptr),v); + } + if (v.type==_FRAC) + return horner(*a._VECTptr,*v._FRACptr,true); + if (v.type!=_EXT) + return gentypeerr(gettext("ext_reduce")); + gen va=*v._EXTptr,vb=*(v._EXTptr+1); + if (va.type==_FRAC) + return ext_reduce(horner(*a._VECTptr,*va._FRACptr,true),vb); + if (va.type!=_VECT){ + if (vb.type!=_VECT) + return gensizeerr(gettext("alg_ext.cc/ext_reduce")); + return algebraic_EXTension( (*a._VECTptr) % (*vb._VECTptr),v); + } + return ext_reduce(horner(*a._VECTptr,gen(*va._VECTptr,_POLY1__VECT)),vb); + } + + gen ext_reduce(const gen & e){ +#ifdef DEBUG_SUPPORT + if (e.type!=_EXT){ + gensizeerr(gettext("alg_ext.cc/ext_reduce")); + CERR << gettext("alg_ext.cc/ext_reduce"); + return e; + } +#endif + if ( (e._EXTptr->type==_VECT) && ((e._EXTptr+1)->type==_VECT) && + (e._EXTptr->_VECTptr->size()<(e._EXTptr+1)->_VECTptr->size()) ) + return e; + return ext_reduce(*(e._EXTptr),*(e._EXTptr+1)); + } + + static bool polynome2vecteur(const polynome & p,int na,int nb,vecteur & v){ + v=vecteur(na*nb,zero); + int i,j; + if (p.dim!=2){ +#ifdef NO_STDEXCEPT + return false; +#else + setsizeerr(gettext("alg_ext.cc/polynome2vecteur")); + return false; +#endif + } + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + i=it->index.front(); + j=it->index.back(); + // cerr << nb*(na-i-1)+nb-j-1 << " " << na*nb << '\n'; + v[nb*(na-i-1)+nb-j-1]=it->value; + } + return true; + } + + bool is_known_rootof(const vecteur & v_,const vecteur * lvptr,gen & symroot,GIAC_CONTEXT){ + if (!convert_rootof(contextptr)) + lvptr=0; // keep symbolic rootof in answers + vecteur v(v_),lv; + if (lvptr && !lvptr->empty()) + lv=vecteur(lvptr->begin()+1,lvptr->end()); + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (lvptr){ +#if 0 // fails with oim 2018 p1 + if (it->type==_POLY){ + int dim=it->_POLYptr->dim; + for (;;){ + if (lv.empty() || lv.front().type!=_VECT) + return false; + if (lv.front()._VECTptr->size()==dim) + break; + lv.erase(lv.begin()); + } + } +#endif +#ifdef NO_STDEXCEPT + *it=r2e(*it,lv,contextptr); + if (is_undef(*it)) + return false; +#else + try { + *it=r2e(*it,lv,contextptr); + } + catch (std::runtime_error &){ + return false; + } +#endif + } + else { + if (it->type!=_INT_) + return false; + } + } + if (rootof_trylock()) + return false; + rootmap::iterator ritend=symbolic_rootof_list().end(),rit=symbolic_rootof_list().find(v); + if (rit!=ritend) + symroot=rit->second; + rootof_unlock(); + if (rit!=ritend) + return true; + if (v.size()==3){ + vecteur w; + identificateur x(" x"); + in_solve(symb_horner(v,x),x,w,0,contextptr); + if (w.empty()) + return false; + symroot=w.front(); + return true; + } + return false; + } + + // replace _EXT == to ext by g in v + static vecteur replace_ext(const vecteur & v,const vecteur &ext,const gen & g,GIAC_CONTEXT){ + vecteur res; + const_iterateur it=v.begin(),itend=v.end(); + res.reserve(int(itend-it)); + for (;it!=itend;++it){ + gen numtmp=*it,dentmp=1; + if (it->type==_FRAC){ + numtmp=it->_FRACptr->num; + dentmp=it->_FRACptr->den; + } + // if numtmp is an ext, it must be the same ext as a + if (numtmp.type==_EXT){ + if (*(numtmp._EXTptr+1)!=ext) + return vecteur(1,gensizeerr(gettext("Invalid _EXT in replace_ext"))); + res.push_back(horner(*numtmp._EXTptr,g)/dentmp); + } + else + res.push_back(evalf_double(*it,1,contextptr)); + } + return res; + } + + // given theta1 and theta2 with minimal poly va and vb (inside gen ga and gb) + // find k / Q[theta1+ k*theta2 ] contains theta1 and theta2 + // return the minimal poly of theta=theta1+k*theta2 + // and return in a and b theta1 and theta2 as ext (in terms of theta) + gen common_minimal_POLY(const gen & ga,const gen & gb, gen & a,gen & b,int & k,const vecteur * lvptr,GIAC_CONTEXT){ + const vecteur & va=*ga._VECTptr; + const vecteur & vb=*gb._VECTptr; + int na=int(va.size()-1),nb=int(vb.size()-1); + if (nb==1){ + k=0; + vecteur un(2,zero); + un[0]=plus_one; + gen vag(va); + a=algebraic_EXTension(un,vag); + gen tmp=-vb[1]; + if (tmp.type!=_POLY) + b=tmp; + else { + if (tmp._POLYptr->coord.empty()) + b=zero; + else + b=tmp._POLYptr->coord.front().value; + } + return vag; + } + // create minimal polynomial of theta1/theta2 as 2-d polynomials + // with main variable respectively a and b + // (since pb is used for reduction after var reordering of p) + polynome pa(2),pb(2); + const_iterateur it=va.begin(),itend=va.end(); + for (int d=na;it!=itend;++it,--d){ + if (!is_zero(*it)) + pa.coord.push_back(monomial(*it,d,1,2)); // deg=d, var=1, dim=2 + } + it=vb.begin(),itend=vb.end(); + int k_init=0; + for (int d=nb;it!=itend;++it,--d){ + if (!is_zero(*it)){ + gen numtmp=*it,dentmp=1; + if (it->type==_FRAC){ + numtmp=it->_FRACptr->num; + dentmp=it->_FRACptr->den; + } + polynome pbadd(pb.dim); + // if numtmp is an ext, it must be the same ext as a + if (numtmp.type==_EXT){ + pbadd=poly12polynome(*(numtmp._EXTptr->_VECTptr),1,1).untrunc1(d); + k_init=1; + } + else + pbadd.coord.push_back(monomial(numtmp,d,1,2)); + pb = pb + pbadd/dentmp; + } + } + if (k_init){ + vecteur v1=*evalf_double(va,1,contextptr)._VECTptr; + if (is_fully_numeric(v1)){ + // when theta2 depends on theta1, theta1+k*theta2 is not necessarily + // the largest root, because the numeric value of v2 depends + // on the selected root of v1 + // + // we should compute k*theta1+theta2 for a sufficiently large + // value of k to insure largest root, e.g. + // this implies computing approx value of theta1 and theta2 + // + vecteur rac=real_proot(v1,1e-12,contextptr); + if (rac.empty()){ + vecteur rac1=proot(v1,1e-12,contextptr); + gen theta1=in_select_root(rac1,is_real(v1,contextptr),contextptr); + // replace _EXT in vb by r1 and evaluate numerically + vecteur v2=replace_ext(vb,va,theta1,contextptr); + if (!v2.empty() && is_undef(v2)) + return v2.front(); + // find theta2 + if (is_fully_numeric(v2)){ + vecteur rac2=proot(v2,1e-12,contextptr); + if (!rac2.empty() && !is_undef(rac2)){ + gen theta2=in_select_root(rac2,is_real(v2,contextptr),contextptr); + int racs=int(rac1.size()); + for (int i=0;i(1,2)); + polynome q(2),tmpq(2),tmpr(2); + q.coord.push_back(monomial(k,1,1,2)); // k*a: deg=1, var=1, dim=2 + q.coord.push_back(monomial(1,1,2,2)); // b: deg=1, var=2 + // create the matrix + // lines are 1, k*a+b, ..., (k*a+b)^(na*nb) + // in terms of (columns) + // a^(na-1)*b^(nb-1) ... a^(na-1) ... ab^(nb-1) ... ab a b^(nb-1) ... b 1 + m.clear(); + vecteur ligne; + for (int j=0;j<=na*nb;++j){ + if (!polynome2vecteur(p,na,nb,ligne)) + return gensizeerr(gettext("alg_ext.cc/polynome2vecteur")); + // ligne.push_back(pow(theta,j)); + m.push_back(ligne); + p=p*q; + // permutation of indices order before making division by pb + p.reorder(transposition(0,1,2)); + p.TDivRem(pb,tmpq,tmpr,true); p.coord.swap(tmpr.coord); // p=p%pb; // + p.reorder(transposition(0,1,2)); + // division by a after because b might depend on a + p.TDivRem(pa,tmpq,tmpr,true); p.coord.swap(tmpr.coord); // p=p%pa; // + } + // Add the lines corresponding to b and a (i.e. theta2, theta1) + ligne=vecteur(na*nb); + ligne[na*nb-2]=plus_one; + m.push_back(ligne); + ligne=vecteur(na*nb); + ligne[na*nb-nb-1]=plus_one; + m.push_back(ligne); + // Transpose matrix + // then we have the na*nb+3 columns 1, theta, ..., theta^(na*nb), b, a + // in terms of a basis (with na*nb coordinates) + m=mtran(m); + // reduce the matrix m to echelon form and test rank=na*nb + // if ok break, else try another value of k + matrice m_red; + vecteur pivots; + gen det; + int st=step_infolevel(contextptr); + step_infolevel(contextptr)=0; + if (!mrref(m,m_red,pivots,det,0,na*nb,0,na*nb+3, + /* fullreduction */1,0,true,1,0, + contextptr)){ + step_infolevel(contextptr)=st; + return gensizeerr(contextptr); + } + step_infolevel(contextptr)=st; + m=m_red; + // the reduced matrix m should have the form + // * 0 ... 0 * * * + // 0 * ... 0 * * * + // ... + // 0 0 ... 0 * * * + // 0 0 ... 0 * * * + // 0 0 ... ? * * * + // with ? != 0, we check ?, if it is zero we try another value k + vecteur v(m[na*nb-1]._VECTptr->begin(),m[na*nb-1]._VECTptr->end()-1); + if (!is_zero__VECT(v,contextptr)) + break; + } + mdividebypivot(m); + // add a -1 at the end of column na*nb (C convention, index starting at 0) + // to get the min poly + vecteur v(na*nb+1); + for (int i=0;ibegin()+1,lvptr->end()),contextptr); + symbolic_rootof_list()[vexpr]=k*gaa+gbb; + } + else + symbolic_rootof_list()[v]=k*gaa+gbb; + rootof_unlock(); + } + } + } + } + return vg; + } + + // assuming a is the extptr+1 of an ext, return the min pol of + // theta generating the algebraic extension + vecteur min_pol(gen & a){ + if (a.type==_VECT) + return *a._VECTptr; + else { + if ( (a.type!=_EXT) || ((a._EXTptr+1)->type!=_VECT) ) + return vecteur(1,gensizeerr(gettext("alg_ext.cc/min_pol"))); + return *((a._EXTptr+1)->_VECTptr); + } + } + + // Find an evaluation point for p at b where pb=p[b] is squarefree + bool find_good_eval(const polynome & F,polynome & Fb,vecteur & b){ + int Fdeg=F.lexsorted_degree(),nvars=int(b.size()); + gen Fg; + int essai=0; + for (;;++essai){ + Fb=peval_1(F,b,0); + if (Fb.lexsorted_degree()==Fdeg && gcd(Fb,Fb.derivative()).lexsorted_degree()==0 ){ + return true; + } + b=vranm(nvars,0,0); // find another random point + } + } + + static void clean(gen & g); + static void clean(polynome & p){ + vector< monomial >::iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it) + clean(it->value); + } + + static void clean(gen & g){ + if (g.is_symb_of_sommet(at_neg) && is_integer(g._SYMBptr->feuille)) + g=-g._SYMBptr->feuille; + if (g.type==_POLY){ + clean(*g._POLYptr); + return; + } + if (g.type==_VECT){ + iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it) + clean(*it); + return; + } + if (g.type==_EXT){ + clean(*g._EXTptr); + clean(*(g._EXTptr+1)); + } + } + + // in-place reduction of algebraic extensions + void clean_ext_reduce(vecteur & v){ + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + clean_ext_reduce(*it); + } + void clean_ext_reduce(gen & g){ + if (g.type==_EXT){ + g=ext_reduce(g); + return; + } + if (g.type==_VECT){ + clean_ext_reduce(*g._VECTptr); + return; + } + if (g.type==_POLY){ + vector< monomial >::iterator it=g._POLYptr->coord.begin(),itend=g._POLYptr->coord.end(); + for (;it!=itend;++it) + clean_ext_reduce(it->value); + return; + } + if (g.type==_FRAC) + clean_ext_reduce(g._FRACptr->num); + } + + // a and b are supposed to be *(_EXTptr+1) of some algebraic extension + // common_EXT will return a new algebraic extension + // (suitable to be an extptr+1) + // and will modify a and b to be ext of the returned common_EXT + gen common_EXT(gen & a,gen & b,const vecteur * l,GIAC_CONTEXT){ + if (a==b) + return a; + if (0 && a.type==_VECT && b.type==_VECT && *a._VECTptr==*b._VECTptr){ + a.subtype=b.subtype=_POLY1__VECT; + return a; + } + if (a.type==_FRAC) + return common_EXT(a._FRACptr->num,b,l,contextptr); + if (b.type==_FRAC) + return common_EXT(a,b._FRACptr->num,l,contextptr); + // extract minimal polynomials + gen a_orig(a),b_orig(b); + gen a__VECT,b__VECT; + if (a.type==_VECT) + a__VECT=a; + else { + if ( (a.type!=_EXT) || ((a._EXTptr+1)->type!=_VECT) ) + return gensizeerr(gettext("alg_ext.cc/common_EXT")); + a__VECT=*(a._EXTptr+1); + } + if (b.type==_VECT) + b__VECT=b; + else { + if ( (b.type!=_EXT) || ((b._EXTptr+1)->type!=_VECT) ) + return gensizeerr(gettext("alg_ext.cc/common_EXT")); + b__VECT=*(b._EXTptr+1); + } + int innerdim=0; + const_iterateur b_it=b__VECT._VECTptr->begin(),b_itend=b__VECT._VECTptr->end(); + for (;b_it!=b_itend;++b_it){ + if (b_it->type==_POLY) + innerdim=b_it->_POLYptr->dim; + } + int innerdima=0; + const_iterateur a_it=a__VECT._VECTptr->begin(),a_itend=a__VECT._VECTptr->end(); + for (;a_it!=a_itend;++a_it){ + if (a_it->type==_POLY) + innerdima=a_it->_POLYptr->dim; + } + if (innerdima>innerdim) innerdim=innerdima; + int as=int(a__VECT._VECTptr->size()),bs=int(b__VECT._VECTptr->size()); + if (bs>as) // (innerdima>innerdim || (innerdima==innerdim && bs>as)) + return common_EXT(b,a,l,contextptr); + if (as==3 && bs==3 && is_one(a[0]) && is_one(b[0]) && is_zero(a[1]) && is_zero(b[1])){ + if (a[2]==-b[2]){// sqrt(X) and sqrt(-X) + b=algebraic_EXTension(makevecteur(cst_i,0),a); + gen tmp=a; + a=algebraic_EXTension(makevecteur(1,0),a); + return tmp; + } + if (a[2].type==_POLY && b[2].type==_POLY){ + polynome & a2=*a[2]._POLYptr; + polynome & b2=*b[2]._POLYptr; + if (a2.lexsorted_degree()==b2.lexsorted_degree()){ + gen a20=a2.coord.front().value; + gen b20=b2.coord.front().value; + if (is_integer(a20) && is_integer(b20)){ + gen test=b20*a[2]-a20*b[2]; + if (is_zero(test)){ + a=-a[2]; b=-b[2]; + gen common=-simplify(a,b); + if (is_integer(a) && is_integer(b)){ + a=sym2r(sqrt(a,contextptr),vecteur(0),contextptr); + b=sym2r(sqrt(b,contextptr),vecteur(0),contextptr); + common=makevecteur(1,0,common); + a=algebraic_EXTension(makevecteur(a,0),common); + b=algebraic_EXTension(makevecteur(b,0),common); + return common; + } + } + } + } + } + } + // special handling if fractional power of the same object + if (is_one(a__VECT[0]) && is_one(b__VECT[0]) && is_zero(a__VECT[as-1]-b__VECT[bs-1])){ + int i=1; + for (;ifront()=1; + a=algebraic_EXTension(a__VECT,res); + b__VECT=gen(vecteur(cc/bc+1),_POLY1__VECT); + b__VECT._VECTptr->front()=1; + b=algebraic_EXTension(b__VECT,res); + return res; + } + // reduce extension degree by factorizing b__VECT over Q[a] + polynome p(poly12polynome(*b__VECT._VECTptr)); + polynome p_content(p.dim); + factorization f; + gen an,extra_div; + ext_factor(p,algebraic_EXTension(a__VECT,a__VECT),an,p_content,f,false,extra_div); + // now choose in the factorization which factor is relevant for b + // this is done by approximation if possible + // or by choosing the factor of lowest degree + // this way we update b__VECT + int min_deg=int(b__VECT._VECTptr->size()); + factorization::const_iterator f_it=f.begin(),f_itend=f.end(); + bool trouve=false; + if (f_itend-f_it==1) + trouve=true; + vecteur racines; + vector real_racines; + vecteur vb(innerdim); + gen racine_max=undef; + bool deep_emb=false; // marker for deep embedding + if (!trouve){ + // Change for multivariate polynomials p, added evaluation + if (innerdim){ + gen params; + polynome pb(1),px(unsplitmultivarpoly(p,innerdim)); + *logptr(contextptr) << gettext("Warning, need to choose a branch for the root of a polynomial with parameters. This might be wrong.") << '\n'; + if (l && l->size()>=2){ + for (int i=1;isize();++i){ + params=(*l)[i]; + if (params.type==_VECT && !params._VECTptr->empty()) + break; + } + // IMPROVE: using context and *l look for assumptions + if (params.type==_VECT){ + vecteur paramv=*params._VECTptr; + int nessais=5*paramv.size(),essai=0; + for (;essaieval(1,g,contextptr); + if ((g2.type==_VECT) && (g2.subtype==_ASSUME__VECT)){ + vecteur V=*g2._VECTptr; + if (V.size()==2) + vb[j]=V[1]; + if ( V.size()==3 && V[1].type==_VECT && V[2].type==_VECT){ + for (unsigned i=0;isize();++i){ + gen tmp=(*V[1]._VECTptr)[i]; + if (tmp.type==_VECT && tmp._VECTptr->size()==2){ + gen a=tmp._VECTptr->front(),b=tmp._VECTptr->back(); + int decal=1; + if (1 || essai) + decal += int((giac_rand(contextptr)*100.0)/rand_max2); + if (a==minus_inf) + vb[j]=b-decal; + else { + if (b==plus_inf) + vb[j]=a+decal; + else { + if (a+b==0) + vb[j]=(decal%2?a:b)/(decal+1); + else + vb[j]=(decal*a+b)/(decal+1); + } + } + } + } + } // end if V.size()==3 + } // end g2 assume_vect + } // end for j + vecteur vb0=vb; + find_good_eval(px,pb,vb); // additional check, a must be sqrfree + gen A=eval(r2sym(a,vb,contextptr),1,contextptr); + if (A.type==_VECT){ + vecteur V,V1=*A._VECTptr,V2=derivative(V1); + V=gcd(V1,V2,0); + //if (is_zero(vb)) cout << V1 << V2 << V << endl; + if (V.size()>1){ + vb=vranm(vb.size(),0,0); + continue; + } + } + if (vb0==vb) + break; + } // end trying to find a good eval point satisfying assumptions + if (essai==nessais) + return gensizeerr("Too many attempts to find a good evaluation point"); + } // end params.type==_VECT + } + vecteur vb0=vb; + find_good_eval(px,pb,vb); // find_good_eval does not take care of assumptions, but vb should be ok (loop above) + if (vb==vb0) + *logptr(contextptr) << gettext("The choice was done assuming ") << params << "=" << vb << '\n'; + else + *logptr(contextptr) << gettext("Non regular value ") << vb0 << gettext(" was discarded and replaced randomly by ") << params << "=" << vb << '\n'; + // checking for embedded polynomial coefficients + vector< monomial >::const_iterator it=pb.coord.begin(),itend=pb.coord.end(); + for (;0 && it!=itend;++it){ // disabled, computations would be too complex + if (it->value.type==_POLY){ + deep_emb=true; + break; + } + } + if (!deep_emb) + racines=proot(gen2vecteur(evalf(polynome2poly1(pb),1,contextptr)),contextptr); + } + else { + gen tmp=evalf(b__VECT,1,contextptr); + if (is_undef(tmp)) return gensizeerr(contextptr); + racines=proot(*tmp._VECTptr,contextptr); // evalf to avoid recursion if computing exact roots of b__VECT + } + if (is_undef(racines)) return gensizeerr(contextptr); + // racines= list of approx roots if b__VECT is numeric + // empty if not numeric + racine_max=in_select_root(racines,is_real(b__VECT,contextptr),contextptr); + } // if (!trouve) + if (!deep_emb && !trouve && !is_undef(racine_max)){ // select root for b + // now eval each factor over racine_max and choose the one with + // minimal absolute value + double min_abs=0,racine_max_d=evalf_double(abs(racine_max,contextptr),1,contextptr)._DOUBLE_val; + int ndig=14; + while (!trouve){ + for (;f_it!=f_itend;++f_it){ + vecteur vtmp(polynome2poly1(f_it->fact)); + gen tmp; + lcmdeno_converted(vtmp,tmp,contextptr); + int maxsave=max_sum_sqrt(contextptr); + max_sum_sqrt(0,contextptr); + if (innerdim) + tmp=r2sym(vtmp,vecteur(1,vb),contextptr); + else + tmp=r2sym(vtmp,vecteur(1,vecteur(0)),contextptr); + max_sum_sqrt(maxsave,contextptr); +#if defined HAVE_LIBMPFR && defined HAVE_LIBPARI // change for Martin Deraux big extensions + if (ndig<15) + tmp=evalf(tmp,1,contextptr); + else + tmp=_evalf(makesequence(tmp,ndig),contextptr); +#else + tmp=evalf(tmp,1,contextptr); +#endif + if (tmp.type==_VECT && !tmp._VECTptr->empty()) + tmp=tmp/tmp._VECTptr->front(); + gen f_racine_max(evalf_double(abs(horner(tmp,racine_max),contextptr),1,contextptr)); + if (f_racine_max.type!=_DOUBLE_) + continue; + double current_evaluation=fabs(f_racine_max._DOUBLE_val); + if (!trouve){ + trouve=true; + min_abs=current_evaluation; + p=f_it->fact; + } + else { + if (min_abs>current_evaluation){ + min_abs=current_evaluation; + p=f_it->fact; + } + } + } // end for on f_it + if (min_abs>1e-4*racine_max_d){ + *logptr(contextptr) << "Precision problem choosing root in common_EXT, current precision " << ndig << '\n'; + trouve=false; + ndig=2*ndig; + f_it=f.begin(); +#if defined HAVE_LIBMPFR && defined HAVE_LIBPARI + if (ndig>1000) +#endif + break; + } + } // end while !trouve + } // end racine_max defined + if (!trouve) { + for (;f_it!=f_itend;++f_it){ + if ( (b.type==_EXT) && is_zero(horner(polynome2poly1(f_it->fact,1),*b._EXTptr)) ){ + p=f_it->fact; + break; + } + int d=f_it->fact.lexsorted_degree(); + if (d && (d<=min_deg)){ + p=f_it->fact; + min_deg=d; + } + } + } // end choose by degree + clean(p); + b__VECT=polynome2poly1(p/p.coord.front().value); // p must be monic (?) + // compute new minimal polynomial + int k; + gen res1=common_minimal_POLY(a__VECT,b__VECT,a,b,k,l,contextptr); + if ((a_orig.type==_EXT) && (b_orig.type==_EXT) && !is_undef(res1)) + return algebraic_EXTension(a_orig+gen(k)*b_orig,res1); + else + return res1; + } + + gen ext_add(const gen & aa,const gen & bb,GIAC_CONTEXT){ + gen a(ext_reduce(aa)),b(ext_reduce(bb)); + if ( (a.type!=_EXT) || (b.type!=_EXT) ) + return a+b; + if (*(a._EXTptr+2) != *(b._EXTptr+2)) + return gensizeerr("Incompatible algebraic extensions"); + if (*(a._EXTptr+1)==*(b._EXTptr+1)){ + if ( (a._EXTptr->type==_VECT) && (b._EXTptr->type==_VECT)){ + gen c=new ref_vecteur; + addmodpoly(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,*c._VECTptr); + return ext_reduce(c,*(a._EXTptr+1)); + return ext_reduce(*(a._EXTptr->_VECTptr)+ *(b._EXTptr->_VECTptr),*(a._EXTptr+1)); + } + else + return ext_reduce(*a._EXTptr+*b._EXTptr,*(a._EXTptr+1)); + } + gen c=common_EXT(*(a._EXTptr+1),*(b._EXTptr+1),0,contextptr); + if (is_undef(c)) return c; + // if c.type==_INT_/_ZINT, call ichinrem on a.extptr,b.extptr,... + return ext_reduce(a)+ext_reduce(b); + } + + gen ext_sub(const gen & a,const gen & b,GIAC_CONTEXT){ + if (*(a._EXTptr+2) != *(b._EXTptr+2)) + return gensizeerr("Incompatible algebraic extensions"); + if (*(a._EXTptr+1)==*(b._EXTptr+1)){ + if ( (a._EXTptr->type==_VECT) && (b._EXTptr->type==_VECT)){ +#if 1 + gen c=new ref_vecteur; + submodpoly(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,*c._VECTptr); + return ext_reduce(c,*(a._EXTptr+1)); +#endif + return ext_reduce(*(a._EXTptr->_VECTptr)- *(b._EXTptr->_VECTptr),*(a._EXTptr+1)); + } + else + return ext_reduce(*a._EXTptr-*b._EXTptr,*(a._EXTptr+1)); + } + return ext_add(a,-b,contextptr); + } + + gen ext_mul(const gen & aa,const gen & bb,GIAC_CONTEXT){ + gen a(ext_reduce(aa)),b(ext_reduce(bb)); + if ( (a.type!=_EXT) || (b.type!=_EXT) ) + return a*b; + if (*(a._EXTptr+2) != *(b._EXTptr+2)) + return gensizeerr("Incompatible algebraic extensions"); + if (*(a._EXTptr+1)==*(b._EXTptr+1)){ + if ((a._EXTptr->type==_VECT) && (b._EXTptr->type==_VECT)){ +#if 1 + gen c=new ref_vecteur; + operator_times(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,0,*c._VECTptr); + return ext_reduce(c,*(a._EXTptr+1)); +#endif + return ext_reduce( *(a._EXTptr->_VECTptr) * *(b._EXTptr->_VECTptr),*(a._EXTptr+1)); + } + else + return ext_reduce((*a._EXTptr)*(*b._EXTptr),*(a._EXTptr+1)); + } + gen c=common_EXT(*(a._EXTptr+1),*(b._EXTptr+1),0,contextptr); + if (is_undef(c)) return c; + // if c.type==_INT_/_ZINT, call ichinrem on a._EXTptr,b._EXTptr,... + return ext_reduce(a)*ext_reduce(b); + } + + gen inv_EXT(const gen & aa){ + if (aa.type!=_EXT) + return inv(aa,context0); + gen a(ext_reduce(aa)); + if (a.type==_FRAC){ + return a._FRACptr->den*inv_EXT(a._FRACptr->num); + } + if (a.type!=_EXT) + return inv(a,context0); + if (a._EXTptr->type==_VECT){ + vecteur u,v,d; + egcd(*(a._EXTptr->_VECTptr),*((a._EXTptr+1)->_VECTptr),0,u,v,d); + if (d.size()!=1) + return gensizeerr(gettext("inv_EXT")); + gen de=d.front(),du=u; + simplify(du,de); + return fraction(algebraic_EXTension(du,*(a._EXTptr+1)),de); + } + return gentypeerr(gettext("inv_EXT")); + } + + gen horner_rootof(const vecteur & p,const gen & g,GIAC_CONTEXT){ + if (g.type==_SYMB && g._SYMBptr->feuille.type==_VECT && + // false + int(g._SYMBptr->feuille._VECTptr->size())>max_sum_sqrt(contextptr) + ) + return symb_horner(p,g); + const_iterateur it=p.begin(),itend=p.end(); + gen res; + for (;it!=itend;++it){ + res=ratnormal(res*g+*it,contextptr); + } + return ratnormal(res,contextptr); + } + + bool has_rootof_value(const gen & Pmin,gen & value,GIAC_CONTEXT){ + value=undef; + if (contextptr && contextptr->globalcontextptr->rootofs){ + const vecteur & r=*contextptr->globalcontextptr->rootofs; + for (unsigned i=0;isize()==2 && Pmin.type==_VECT && ri._VECTptr->front().type==_VECT && *Pmin._VECTptr==*ri._VECTptr->front()._VECTptr){ + value=ri._VECTptr->back(); + return true; + } + } + } + return !is_undef(value); + } + + static string printasrootof(const gen & g,const char * s,GIAC_CONTEXT){ + if (contextptr && g.type==_VECT && g._VECTptr->size()==2){ + gen value; + if (g._VECTptr->front().type==_VECT && has_rootof_value(g._VECTptr->back(),value,contextptr)){ + value=horner_rootof(*g._VECTptr->front()._VECTptr,value,contextptr); + string res=value.print(contextptr); + if (need_parenthesis(value)) + res=("("+res)+')'; + return res; + } + } + string res(s); + res+='('; + res+=g.print(contextptr); + res+=')'; + return res; + } + + // rootof has 2 args: P(theta) and Pmin(theta) + gen symb_rootof(const gen & p,const gen &pmin,GIAC_CONTEXT){ + if (p.type!=_VECT) + return p; + // first check that pmin is in the list of known rootof + gen value(undef); + if (!rootof_trylock()){ + rootmap::iterator it=symbolic_rootof_list().find(pmin),itend=symbolic_rootof_list().end(); + if (it!=itend) + value=it->second; + rootof_unlock(); + } + if (is_undef(value)) + return symbolic(at_rootof,makevecteur(p,pmin)); + return horner_rootof(*p._VECTptr,value,contextptr); + // return ratnormal(ratnormal(symb_horner(*p._VECTptr,it->second))); + } + gen rootof(const gen & e,GIAC_CONTEXT){ + if (e.type!=_VECT){ + vecteur v=lidnt(e); + if (v.size()==1) + return rootof(_symb2poly(makesequence(e,v.front()),contextptr),contextptr); + return gentypeerr(gettext("rootof")); + } + if (e.type==_VECT && *e._VECTptr==makevecteur(1,0,1)){ + *logptr(contextptr) << "rootof([1,0,1]) was converted to i" << '\n'; + return cst_i; + } + if (e._VECTptr->size()==2 && e._VECTptr->front().type!=_VECT){ + vecteur v=lidnt(e); + if (v.empty()) + return -v.back()/v.front(); + if (v.size()!=1) + return gentypeerr(gettext("rootof")); + return rootof(makesequence(_symb2poly(makesequence(e._VECTptr->front(),v.front()),contextptr),_symb2poly(makesequence(e._VECTptr->back(),v.front()),contextptr)),contextptr); + } + if (e._VECTptr->size()!=2 || e._VECTptr->back().type!=_VECT) + return rootof(makesequence(makevecteur(1,0),e),contextptr); + if (has_num_coeff(e)) + return approx_rootof(e,contextptr); + if (!lop(lvar(e),at_pow).empty()){ + *logptr(contextptr) << gettext("Algebraic extensions not allowed in a rootof")<<'\n'; + return approx_rootof(e,contextptr); + } + // should call factor before returning unevaluated rootof + if (e.type==_VECT && e._VECTptr->size()==2 && e._VECTptr->back().type==_VECT){ + const vecteur & v=*e._VECTptr->back()._VECTptr; + if (!v.empty() && v[0]==1 && is_integer_vecteur(v)) + return symbolic(at_rootof,e); + vecteur v2=v; + gen g(1); + lcmdeno(v2,g,contextptr); + if (is_minus_one(v2[0])) + v2=-v2; + if (!is_one(v2[0])) + return gensizeerr("rootof minimal polynomial must be unitary"); + return symbolic(at_rootof,gen(makevecteur(e._VECTptr->front(),gen(v2,e._VECTptr->back().subtype)),e.subtype)); + } + return symbolic(at_rootof,e); + } + gen approx_rootof(const gen & e,GIAC_CONTEXT){ + if ( (e.type!=_VECT) || (e._VECTptr->size()<2) ) + return gensizeerr(contextptr); + if (!lidnt(e).empty()) + return symbolic(at_rootof,e); + gen a=e._VECTptr->front(),b=(*e._VECTptr)[1],c=0; + if (e._VECTptr->size()>=3) + c=(*e._VECTptr)[2]; + return alg_evalf(a,b,c,contextptr); + } + /* statically in derive.cc + static gen d1_rootof(const gen & args,GIAC_CONTEXT){ + return gentypeerr(contextptr); + return zero; + } + static gen d2_rootof(const gen & args,GIAC_CONTEXT){ + return gentypeerr(contextptr); + return zero; + } + define_unary_function_ptr( D1_rootof,alias_D1_rootof,new unary_function_eval(0,&d1_rootof,"")); + define_unary_function_ptr( D2_rootof,alias_D2_rootof,new unary_function_eval(0,&d2_rootof,"")); + static unary_function_ptr d_rootof(int i){ + if (i==1) + return D1_rootof; + if (i==2) + return D2_rootof; + return gensizeerr(contextptr); + return 0; + } + partial_derivative_multiargs D_rootof(&d_rootof); + */ + static const char _rootof_s []="rootof"; + static define_unary_function_eval2 (__rootof,&rootof,_rootof_s,&printasrootof); + define_unary_function_ptr5( at_rootof ,alias_at_rootof,&__rootof,0,true); + + gen max_algext(const gen & args,GIAC_CONTEXT){ + gen g=args; + if (g.type==_VECT && g._VECTptr->empty()) + return MAX_ALG_EXT_ORDER_SIZE; + if (!is_integral(g) || g.type!=_INT_ || g.val<3) + return gensizeerr(contextptr); + return MAX_ALG_EXT_ORDER_SIZE=g.val; + } + static const char _max_algext_s []="max_algext"; + static define_unary_function_eval (__max_algext,&max_algext,_max_algext_s); + define_unary_function_ptr5( at_max_algext ,alias_at_max_algext,&__max_algext,0,true); + +#ifndef FXCG + // set_timeout(), set_timeout(15), set_timeout(20,30) + gen set_timeout(const gen & args,GIAC_CONTEXT){ + gen g=args; + if (g.type==_VECT && g._VECTptr->empty()){ +#ifdef TIMEOUT + return caseval_mod?makevecteur(caseval_maxtime,caseval_mod):0; +#else + return -1; +#endif + } + if (g.type==_VECT && g._VECTptr->size()==2 && g._VECTptr->front().type==_INT_ && g._VECTptr->back().type==_INT_){ +#ifdef TIMEOUT + caseval_maxtime=giacmax(2,g._VECTptr->front().val); + caseval_n=0; + caseval_mod=giacmax(2,g._VECTptr->back().val); + string S="Max eval time set to "+print_INT_(caseval_maxtime)+", check frequency 1/"+print_INT_(caseval_mod); + return string2gen(S,false); +#else + return -1; +#endif + } + if (!is_integral(g) || g.type!=_INT_ || g.val<3 || g.val>24*60) + return gensizeerr(contextptr); +#ifdef TIMEOUT + caseval_maxtime=g.val; + caseval_n=0; + caseval_mod=10; + string S="Max eval time set to "+g.print()+" , check frequency 1/10"; +#else + string S="Recompile with -DTIMEOUT to have timeout support."; +#endif + return string2gen(S,false); + } + static const char _set_timeout_s []="set_timeout"; + static define_unary_function_eval (__set_timeout,&set_timeout,_set_timeout_s); + define_unary_function_ptr5( at_set_timeout ,alias_at_set_timeout,&__set_timeout,0,true); +#endif + + static vecteur sturm(const gen & g){ + if (g.type!=_POLY) + return vecteur(1,g); + polynome p(*g._POLYptr); + polynome pl(lgcd(p)); + polynome pp=p/pl; + polynome cont(p.dim); + factorization f(sqff(pp)); + factorization::const_iterator it=f.begin(),itend=f.end(); + gen a=p.coord.front().value; + for (;it!=itend;++it){ + if (it->mult %2) + a=a/it->fact.coord.front().value; + } + vecteur v(1,pl.coord.empty()?a:a/pl.coord.front().value*pl); + for (it=f.begin();it!=itend;++it){ + if (it->mult %2) + v.push_back(sturm_seq(it->fact,cont)); + } + return v; + } + vecteur sturm(const gen &g,const gen & x,GIAC_CONTEXT){ + if (g.type==_VECT) + return vecteur(1,gensizeerr(contextptr)); + vecteur l; + if (!is_zero(x)) + l.push_back(x); + lvar(g,l); + fraction fa(e2r(exact(g,contextptr),l,contextptr)); + gen n,d; + fxnd(fa,n,d); + vecteur v=mergevecteur(sturm(n),sturm(d)); + vecteur res,tmp,ll=cdr_VECT(l); + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (it->type==_VECT){ + const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end(); + vecteur tmpres; + tmpres.reserve(int(jtend-jt)); + for (;jt!=jtend;++jt){ + if (jt->type==_POLY){ + tmp=polynome2poly1(*(jt->_POLYptr),1); + tmpres.push_back(r2e(tmp,ll,contextptr)); + } + else + tmpres.push_back(*jt); + } + res.push_back(tmpres); + } + else { // it->type != _VECT but we must convert anyway the cst coeff! + if (it->type==_POLY){ + gen tmpg=polynome2poly1(*(it->_POLYptr),1).front(); + res.push_back(r2e(tmpg,ll,contextptr)); + } + else + res.push_back(*it); + } + } + return res; + } + // v is a sequence of dense polynomials + // each poly is evaluated at a, then we count # of sign changes + // ignoring zeros + // The function modifies a sign variable according to the sign first + // non-zero element of v + static int number_of_sign_changes(const vecteur & v,const gen & a0,int & global_sign,GIAC_CONTEXT){ + gen a=exact(a0,contextptr); + gen w=normal(apply1st(v,a,horner),contextptr); + int previous_sign=0,current_sign,res=0; + const_iterateur it=w._VECTptr->begin(),itend=w._VECTptr->end(); + for (;it!=itend;++it){ + if (is_exactly_zero(*it)) + continue; + if (ck_is_strictly_positive(*it,contextptr)) + current_sign=1; + else + current_sign=-1; + if (!previous_sign) {// assign first non-zero sign + previous_sign=current_sign; + global_sign = global_sign *current_sign; + } + if (previous_sign==current_sign) + continue; + ++res; + previous_sign=current_sign; + } + return res; + } + static int sturmab(const gen & g,const gen & x,const gen & a,const gen & b,bool remove_b_root,GIAC_CONTEXT){ + if (g.type==_VECT){ +#ifdef NO_STDEXCEPT + return -2; +#else + setsizeerr(contextptr); +#endif + } + if (ck_is_strictly_greater(a,b,contextptr)) + return sturmab(g,x,b,a,contextptr); + if (a==b){ + gen tmp; + if (is_inf(a) && x.type==_IDNT) + tmp=limit(g,*x._IDNTptr,a,0,contextptr); + else + tmp=subst(g,x,a,false,contextptr); + int s=fastsign(tmp,contextptr); + if (s==1 || s==-1) + return (s-1)/2; + } +#ifdef NO_STDEXCEPT + vecteur lvarg(lvar(g)); + if (!lvarg.empty() && lvarg!=vecteur(1,x)) + return -2; +#endif + int res=0,dontcare,global_sign=1; + vecteur v=sturm(g,x,contextptr); + if (is_undef(v)) + return -2; + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (it->type==_VECT){ + res += number_of_sign_changes(*it->_VECTptr,a,global_sign,contextptr)-number_of_sign_changes(*it->_VECTptr,b,dontcare,contextptr); + if (remove_b_root && is_zero(horner(it->_VECTptr->front(),b))) + --res; + } + else { + if (!ck_is_positive(*it,contextptr)) + global_sign = -global_sign; + } + } + if (res) + return res; + return (global_sign-1)/2; + } + int sturmab(const gen & g,const gen & x,const gen & a,const gen & b,GIAC_CONTEXT){ + return sturmab(g,x,a,b,false,contextptr); + } + gen _sturmab(const gen & g_orig,GIAC_CONTEXT){ + if ( g_orig.type==_STRNG && g_orig.subtype==-1) return g_orig; + if ( g_orig.type!=_VECT || g_orig._VECTptr->size()<3 ) + return gensizeerr(contextptr); + vecteur v(*g_orig._VECTptr); + int s=int(v.size()); + gen P(v[0]),x(vx_var),a,b; + if (s==3){ a=v[1]; b=v[2]; } + else { + x=v[1]; a=v[2]; b=v[3]; + if (P.type==_VECT) + *logptr(contextptr) << gettext("Warning: variable name ignored: ") << x << '\n'; + } + gen ai=im(a,contextptr); + gen bi=im(b,contextptr); + if (!is_zero(ai) || !is_zero(bi)){ + gen p=_e2r(gen(makevecteur(P,vecteur(1,x)),_SEQ__VECT),contextptr),n,d,g1,g2; + if (is_undef(p)) return p; + fxnd(p,n,d); + vecteur nr; + int n1; +#if 0 // replace by 1 if you want to count complex rational root on the edges + if (n.type==_POLY && n._POLYptr->dim==1){ + polynome nrp=*n._POLYptr; + nr=crationalroot(nrp,true); + n1=csturm_square(nrp,a,b,g1,contextptr); + } + else + n1=csturm_square(n,a,b,g1,contextptr); +#else + n1=csturm_square(n,a,b,g1,contextptr); +#endif + int d1=csturm_square(d,a,b,g2,contextptr); + if (n1==-1 || d1==-1) + return gensizeerr(contextptr); + return int(nr.size())+gen(n1)/2+cst_i*gen(d1)/2; + } + if (s==5 && v[4].type==_INT_) + return sturmab(P,x,a,b,v[4].val!=0,contextptr); + return sturmab(P,x,a,b,contextptr); + } + static const char _sturmab_s []="sturmab"; + static define_unary_function_eval (__sturmab,&_sturmab,_sturmab_s); + define_unary_function_ptr5( at_sturmab ,alias_at_sturmab,&__sturmab,0,true); + + gen _sturm(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + if (g.type!=_VECT || (g.type==_VECT && g.subtype!=_SEQ__VECT) ) + return sturm(g,zero,contextptr); + vecteur & v = *g._VECTptr; + int s=int(v.size()); + if (s==2) + return sturm(v.front(),v.back(),contextptr); + if (s==4) + return _sturmab(g,contextptr); + if (s==3){ + if (v[2].type!=_IDNT) + return gensizeerr(contextptr); + gen S=_e2r(gen(makevecteur(v[0],v[2]),_SEQ__VECT),contextptr); + if (is_undef(S)) return S; + gen R=_e2r(gen(makevecteur(v[1],v[2]),_SEQ__VECT),contextptr); + if (is_undef(R)) return R; + if (S.type==_FRAC) + S=S._FRACptr->num; + if (R.type==_FRAC) + R=R._FRACptr->num; + modpoly r0(gen2vecteur(S)),r1(gen2vecteur(R)); + vecteur listquo,coeffP,coeffR; + gen pgcd=csturm_seq(r0,r1,listquo,coeffP,coeffR,contextptr); + return makevecteur(r0,r1,pgcd,listquo,coeffP,coeffR); + } + return gendimerr(contextptr); + } + static const char _sturm_s []="sturm"; + static define_unary_function_eval (__sturm,&_sturm,_sturm_s); + define_unary_function_ptr5( at_sturm ,alias_at_sturm,&__sturm,0,true); + + gen _sturmseq(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // should return in the same format as maple + return _sturm(g,contextptr); + } + static const char _sturmseq_s []="sturmseq"; + static define_unary_function_eval (__sturmseq,&_sturmseq,_sturmseq_s); + define_unary_function_ptr5( at_sturmseq ,alias_at_sturmseq,&__sturmseq,0,true); + + void recompute_minmax(const vecteur & w,const vecteur & range,const gen & expr,const gen & var,gen & resmin,gen & resmax,vecteur & xmin,vecteur & xmax,int direction,GIAC_CONTEXT){ + const_iterateur it=w.begin(),itend=w.end(); + for (;it!=itend;++it){ + if (ck_is_strictly_greater(*it,range[1],contextptr) || ck_is_strictly_greater(range[0],*it,contextptr)) + continue; +#ifdef NO_STDEXCEPT + gen tmp=limit(expr,*var._IDNTptr,*it,direction,contextptr); +#else + gen tmp; + try { + tmp=limit(expr,*var._IDNTptr,*it,direction,contextptr); + } catch (std::runtime_error & err){ + last_evaled_argptr(contextptr)=NULL; + tmp=undef; + } +#endif + if (is_undef(tmp) || tmp==unsigned_inf) + continue; + if (tmp==resmax && !equalposcomp(xmax,*it)) + xmax.push_back(*it); + else { + if (ck_is_strictly_greater(tmp,resmax,contextptr)){ + resmax=tmp; + xmax=vecteur(1,*it); + } + } + if (tmp==resmin && !equalposcomp(xmin,*it)) + xmin.push_back(*it); + else { + if (ck_is_strictly_greater(resmin,tmp,contextptr)){ + resmin=tmp; + xmin=vecteur(1,*it); + } + } + } + } + + // minmax=0 both 1 min, 2 max, /3 =1 if return x instead of f(x) + gen fminmax(const gen & g,int minmax,GIAC_CONTEXT){ + gen expr,var; + vecteur v(gen2vecteur(g)); + if (v.size()==1) + v.push_back(vx_var); + if (v.size()!=2) + return gensizeerr(contextptr); + expr=v[0]; + var=v[1]; + // avoid inf recursion like g0(x):=ln(abs(ln(x))); + // g1(x,xp):=x/(ln(x))^(xp);g0(g1(x,.3)); + gen varev=eval(var,1,contextptr); + if (varev!=var && contains(varev,var)) + return undef; + if (expr.type==_SYMB){ + unary_function_ptr & u=expr._SYMBptr->sommet; + if (u==at_exp || u==at_ln || u==at_atan || u==at_abs){ + gen tmp=fminmax(makevecteur(expr._SYMBptr->feuille,var),minmax,contextptr); + if (is_undef(tmp)) + return tmp; + if (u==at_abs && tmp.type==_VECT && tmp._VECTptr->size()==2 ){ + gen t1=tmp._VECTptr->front(); + gen t2=tmp._VECTptr->back(); + if (is_positive(t1,contextptr)) + return tmp; + if (is_positive(-t2,contextptr)){ + return gen(makevecteur(-t2,-t1),_LINE__VECT); + } + // t1<=0 t2>=0 + if (is_greater(-t1,t2,contextptr)) + return gen(makevecteur(0,-t1),_LINE__VECT); + else + return gen(makevecteur(0,t2),_LINE__VECT); + } + if (u==at_ln && tmp.type==_VECT && tmp._VECTptr->size()==2 && is_positive(-tmp._VECTptr->front(),contextptr) ) + tmp._VECTptr->front()=zero; + if (minmax/3) + return tmp; + else + return u(tmp,contextptr); + } + } + bool do_find_range=true; + vecteur range; + if (is_equal(var)){ + gen tmp=var._SYMBptr->feuille; + if (tmp.type==_VECT && tmp._VECTptr->size()==2){ + gen varminmax=tmp._VECTptr->back(); + var=tmp._VECTptr->front(); + if (varminmax.is_symb_of_sommet(at_interval) && varminmax._SYMBptr->feuille.type==_VECT){ + range=*varminmax._SYMBptr->feuille._VECTptr; + do_find_range=false; + } + } + } + // gensizeerr replaced by undef because otherwise abs(sin(exp(x))) fails on emcc + if (var.type!=_IDNT) + return undef; // gensizeerr(contextptr); + if (do_find_range){ + find_range(var,range,contextptr); + if (range.size()!=1 || range.front().type!=_VECT) + return gensizeerr(gettext("Or condition not implemented")); + range=*range.front()._VECTptr; + } + if (range.size()!=2) + return gensizeerr(gettext("fminmax, range ")+gen(range).print(contextptr)); + if (range[0]==minus_inf || range[1]==plus_inf){ + // periodic function? + vecteur w=lvarx(trig2exp(expr,contextptr),var); + gen period=0; + for (unsigned i=0;ifeuille,a,b; + if (!is_linear_wrt(tmp,var,a,b,contextptr) || !is_zero(re(a,contextptr))){ + period=0; + break; + } + if (is_zero(a)) + continue; + a=ratnormal(cst_two_pi/im(a,contextptr),contextptr); // current period + if (is_zero(period)) + period=a; + else { // find common period (if it exists) + b=ratnormal(period/a,contextptr); + if (b.type!=_INT_ && b.type!=_FRAC){ + period=0; + break; + } + if (b.type==_FRAC) + period=period*b._FRACptr->den; + } + } + if (!is_zero(period)){ + if (w.size()>1) + expr=simplify(expr,contextptr); + if (range[0]==minus_inf){ + if (range[1]==plus_inf){ + range[1]=period/2; + range[0]=-range[1]; + } + else + range[0]=range[1]-period; + } + else + range[1]=range[0]+period; + } + } + gen df(derive(expr,var,contextptr)); + if (is_undef(df)) + return df; + vecteur w; + if (range==makevecteur(minus_inf,plus_inf)) + w=solve(df,var,2,contextptr); + else { + // FIXME: check if var is quoted, otherwise it will be erased + gen savevar=var; + var._IDNTptr->in_eval(1,var,savevar,contextptr); + // if (var._IDNTptr->in_eval(1,var,savevar,contextptr)) 1; + giac_assume(symbolic(at_and,makevecteur(symb_superieur_egal(var,range[0]),symb_inferieur_egal(var,range[1]))),contextptr); + w=solve(df,var,2,contextptr); + if (savevar==var) + purgenoassume(var,contextptr); + else + sto(savevar,var,contextptr); + } + if (w.empty() && debug_infolevel) + *logptr(contextptr) << gettext("Warning: ") << df << gettext("=0: no solution found") << '\n'; + vecteur wvar=makevecteur(cst_pi); + lidnt(w,wvar,false); + if (wvar.size()>1) + return undef; + gen resmin=plus_inf; + gen resmax=minus_inf; + vecteur xmin,xmax; + // Extrema + recompute_minmax(w,range,expr,var,resmin,resmax,xmin,xmax,0,contextptr); + // Limits at begin and end of range + recompute_minmax(vecteur(1,range[0]),range,expr,var,resmin,resmax,xmin,xmax,1,contextptr); + recompute_minmax(vecteur(1,range[1]),range,expr,var,resmin,resmax,xmin,xmax,-1,contextptr); + // Singularities + vecteur ws=find_singularities(expr,*var._IDNTptr,0,contextptr); + int wss=int(ws.size()); + w.clear(); + for (int i=0;i prog.h + // find extremals values of g + // should be improved (currently return -1..1 for sin and cos + int find_range(const gen & g,vecteur & a,GIAC_CONTEXT){ + if (g.type==_IDNT){ + gen g2=g._IDNTptr->eval(1,g,contextptr); + if ((g2.type==_VECT) && (g2.subtype==_ASSUME__VECT)){ + vecteur v=*g2._VECTptr; + if ( (v.size()==3) && (v.front()==vecteur(0) || v.front()==_DOUBLE_ || v.front()==_ZINT || v.front()==_SYMB || v.front()==0) && (v[1].type==_VECT)){ + a=*v[1]._VECTptr; + if (v.front()==_ZINT) return 3; + return 1; + } + if (v.size()==1 && v.front()==_ZINT){ + return 2; + } + } + } + if (g.type==_SYMB){ +#ifndef NO_STDEXCEPT + try { +#endif + if (g._SYMBptr->feuille.type==_SPOL1) + return 0; + vecteur lv0(lvar(g._SYMBptr->feuille)),lv; // remove cst idnt + for (unsigned i=0;isommet); + if ( (s==at_sin) || (s==at_cos) ){ + a=vecteur(1,gen(makevecteur(minus_one,plus_one),_LINE__VECT)); + return 1; + } + } + a=vecteur(1,gen(makevecteur(minus_inf,plus_inf),_LINE__VECT)); + return 1; + } + + bool is_sqrt(const gen & a,gen & arg){ + if (a.is_symb_of_sommet(at_sqrt)){ + arg=a._SYMBptr->feuille; + return true; + } + if (!a.is_symb_of_sommet(at_pow)) + return false; + gen & f = a._SYMBptr->feuille; + if (f.type!=_VECT || f._VECTptr->size()!=2) + return false; + arg = f._VECTptr->front(); + gen & expo = f._VECTptr->back(); + if (expo.type!=_FRAC || !is_one(expo._FRACptr->num)) + return false; + gen & d =expo._FRACptr->den; + if (d.type!=_INT_ || d.val!=2) + return false; + return true; + } + + static int insturmsign1(const gen & g0,bool strict,GIAC_CONTEXT){ + gen g=recursive_normal(exact(g0,contextptr),contextptr); + if (has_i(g)) + return 0; + vecteur v(lvar(g)); + // search for a sqrt inside v: sign(a+b*sqrt(c))= + // = sign(a) if a^2-c*b^2 > 0, + // = sign(b) if a^2-c*b^2 < 0 + int s=int(v.size()); + if (!s +#ifdef EMCC + || s>1 +#else + || s>4 +#endif + ) + return fastsign(g,contextptr); + gen v0(v[0]); + for (int i=0;ieval(1,v[i],contextptr).type!=_IDNT){ + v0=v[i]; + } + gen a,b,c; + if (is_sqrt(v[i],c)){ + identificateur x(" x"); + gen g1=subst(g,v[i],x,false,contextptr); + if (is_linear_wrt(g1,x,b,a,contextptr)){ + gen s=sign(a*b,contextptr); + if (is_one(s) && (s=sign(a,contextptr)).type==_INT_) + return s.val; + s=sign(a*a-c*b*b,contextptr); + if (s.type!=_INT_ || is_zero(s.val)) + return 0; + s=(is_one(s))?sign(a,contextptr):sign(b,contextptr); + if (is_one(s)) + return 1; + if (is_minus_one(s)) + return -1; + return 0; + } + } + } + vecteur a; + // should be replaced by a call that gives info if a boundaries are strict + if (!find_range(v0,a,contextptr)) + return -2; + if (a.empty()) + a=vecteur(1,gen(makevecteur(minus_inf,plus_inf),_LINE__VECT)); + int previous_sign=2,current_sign=0; +#ifndef NO_STDEXCEPT + try { +#endif + const_iterateur ita=a.begin(),itaend=a.end(); + for (;ita!=itaend;++ita){ + if ( (ita->type!=_VECT) || (ita->subtype!=_LINE__VECT) || (ita->_VECTptr->size()!=2) ) + return 0; + gen last(ita->_VECTptr->back()); + gen gg(g); + identificateur idnttmp("t"); + gen testg(subst(g,v0,idnttmp,false,contextptr)); + if (is_zero(limit(testg,idnttmp,last,-1,contextptr))){ + if (strict && (v0.is_symb_of_sommet(at_sin) || v0.is_symb_of_sommet(at_cos))) + return 0; + gen tmp=_fxnd(gg,contextptr); + if (tmp.type!=_VECT || tmp._VECTptr->size()!=2){ +#ifdef NO_STDEXCEPT + return -2; +#else + setsizeerr(contextptr); +#endif + } + gen num=tmp._VECTptr->front(),den=tmp._VECTptr->back(),tmpden; + tmp=_e2r(makevecteur(num,v0),contextptr); + tmpden=_e2r(makevecteur(den,v0),contextptr); + if (is_undef(tmp) || is_undef(tmpden)) + return -2; + if (is_inf(last) && tmpden.type==_VECT) + den=den/pow(v0,2*int(tmpden._VECTptr->size()/2)); + tmp=gen2vecteur(tmp); + modpoly p(*tmp._VECTptr),q; + if (!is_inf(last)) { + while (is_zero(horner(p,last,0,q))) + p=-q; + } + gg=_r2e(gen(makevecteur(p,v0),_SEQ__VECT),contextptr)/den; + } + current_sign=sturmab(gg,v0,ita->_VECTptr->front(),last,true,contextptr); + if (current_sign>0 || current_sign==-2) + return 0; + if (previous_sign==2) + previous_sign=current_sign; + if (previous_sign!=current_sign) + return 0; + } +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & ){ + last_evaled_argptr(contextptr)=NULL; + return 0; + } +#endif + return 2*current_sign+1; + } + + static int insturmsign(const gen & g0,bool strict,GIAC_CONTEXT){ + //bool absb=eval_abs(contextptr); + //eval_abs(false,contextptr); + int res=insturmsign1(g0,strict,contextptr); + return res; + //eval_abs(absb,contextptr); + } + + int sturmsign(const gen & g0,bool strict,GIAC_CONTEXT){ + int fs=fastsign(g0,contextptr); + if (fs) return fs; + gen g=simplifier(g0,contextptr); + // first check some operators inv, *, exp, sqrt + int tmp; + if (g.is_symb_of_sommet(at_neg)){ + tmp=sturmsign(g._SYMBptr->feuille,strict,contextptr); + return tmp==-2?tmp:-tmp; + } + if (g.is_symb_of_sommet(at_inv)){ + tmp=sturmsign(g._SYMBptr->feuille,strict,contextptr); + return tmp; + } + if (g.is_symb_of_sommet(at_exp)) + return 1; + /* if (g.is_symb_of_sommet(at_pow) && g._SYMBptr->feuille[1]==plus_one_half) + return 1; */ + if (g.is_symb_of_sommet(at_prod)){ + gen &f=g._SYMBptr->feuille; + vecteur v(gen2vecteur(f)); + int s=int(v.size()); + vecteur w; + int res=1,currentsign; + // remove cst coeffs and exp/ + for (int i=0;ifeuille,strict,contextptr)==1) + continue; + if ( (currentsign=fastsign(v[i],contextptr)) ) + res *= currentsign; + else + w.push_back(v[i]); + } + switch (w.size()){ + case 0: + return res; + case 1: + tmp=insturmsign(w.front(),strict,contextptr); return tmp==-2?-2:res*tmp; + default: + tmp=insturmsign(symbolic(at_prod,w),strict,contextptr); return tmp==-2?-2:res*tmp; + } + } + return insturmsign(g,strict,contextptr); + } + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/cocoa.cc b/android/app/src/main/cpp/giac/src/giac/cpp/cocoa.cc new file mode 100644 index 0000000..9fbbab1 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/cocoa.cc @@ -0,0 +1,20172 @@ +/* -*- mode:C++ ; compile-command: "g++ -I.. -I../include -I.. -g -c -fno-strict-aliasing -DGIAC_GENERIC_CONSTANTS -DHAVE_CONFIG_H -DIN_GIAC -Wall cocoa.cc" -*- */ +// Use GIAC_DEBUG_TDEG_T64 to debug potential memory errors with large number of variables +// Thanks to Zoltan Kovacs for motivating this work, in order to improve geogebra theorem proving +// Special thanks to Anna M. Bigatti from CoCoA team for insightfull discussions on how to choose an order for elimination. This file name is kept to remind that the first versions of giac were using CoCoA for Groebner basis computations, before a standalone implementation. +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// vector class by Agner Fog https://github.com/vectorclass +// this might be faster for CPU with AVX512DQ instruction set +// (fast multiplication of Vec4q) +#if defined HAVE_VCL2_VECTORCLASS_H +// https://github.com/vectorclass, compile with -mavx2 -mfma +#include +#ifdef __AVX2__ +#define CPU_SIMD +#endif +#endif + +#include "modint.h" + +#include "giacPCH.h" +//#define EMCC + + +// if GIAC_SHORTSHIFTTYPE is defined, sparse matrix is using shift index +// coded on 2 bytes +#define GIAC_SHORTSHIFTTYPE 16 +// MAXNTHREADS is used for arrays with threads information +#define MAXNTHREADS 64 + +// #define GBASIS_4PRIMES to run 4 primes reduction simultaneously +#if defined __AVX2__ && !defined EMCC && !defined EMCC2 && defined GIAC_SHORTSHIFTTYPE && GIAC_SHORTSHIFTTYPE==16 +#define GBASIS_4PRIMES +#endif + +#ifdef WORDS_BIGENDIAN // autoconf macro defines this (thanks to Julien Puydt for pointing this and checking for s390x architecture) +#define BIGENDIAN +#endif + + +#ifndef WIN32 +#define COCOA9950 +#endif + +#ifdef HAVE_LIBPTHREAD +#endif + +#if 0 // works faster with AVX2 only +#include +#define CPU_SIMD // should be configured in config.h +// add -std=c++17 to the compiler options +#endif + +#ifdef BF2GMP_H +#define USE_GMP_REPLACEMENTS +#endif + +#if defined(USE_GMP_REPLACEMENTS) || defined(GIAC_VECTOR) +#undef HAVE_LIBCOCOA +#endif +#ifdef HAVE_LIBCOCOA +#ifdef COCOA9950 +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +// +#include +#include "TmpFGLM.H" +#endif +/* + * Copyright (C) 2007,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using namespace std; +#ifdef ATOMIC // attempt to make tdeg_t64 ref counter threadsafe, but fails +#include +#endif + +#include +//#include +#if !defined FXCG && !defined KHICAS && !defined SDL_KHICAS +#include +#endif +#include "cocoa.h" +#include "gausspol.h" +#include "identificateur.h" +#include "giacintl.h" +#include "index.h" +#include "modpoly.h" +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#if defined(USE_GMP_REPLACEMENTS) || defined(GIAC_VECTOR) +#undef HAVE_LIBCOCOA +#endif + +#if defined VISUALC && defined x86_64 +#undef x86_64 +#endif + +inline mod4int modulo(mpz_t & z,const mod4int & m){ + mod4int res={giac::modulo(z,m.tab[0]),giac::modulo(z,m.tab[1]),giac::modulo(z,m.tab[2]),giac::modulo(z,m.tab[3])}; + return res; +} +inline mod4int invmod(const mod4int &a,const mod4int & p){ + mod4int res={giac::invmod(a.tab[0],p.tab[0]), + giac::invmod(a.tab[1],p.tab[1]), + giac::invmod(a.tab[2],p.tab[2]), + giac::invmod(a.tab[3],p.tab[3])}; + return res; +} +std::ostream & operator << (std::ostream & os,const mod4int & a){ + return os<< "(" << a.tab[0] << ","< cocoa_idealptr_map; + +#ifdef COCOA9950 + static CoCoA::BigInt gen2ZZ(const gen & g){ + switch (g.type){ + case _INT_: + return CoCoA::BigInt(g.val); + case _ZINT: +#ifdef COCOA9950 + return CoCoA::BigIntFromMPZ(*g._ZINTptr); + //return CoCoA::BigInt(*g._ZINTptr); +#else + return CoCoA::BigInt(CoCoA::CopyFromMPZ,*g._ZINTptr); +#endif + default: + setsizeerr(gettext("Invalid giac gen -> CoCoA ZZ conversion")+g.print()); + return CoCoA::BigInt(0); + } + } + + static gen ZZ2gen(const CoCoA::RingElem & z){ + CoCoA::BigInt n,d; + if (CoCoA::IsInteger(n, z)) + return gen(CoCoA::mpzref(n)); + CoCoA::RingElem znum=CoCoA::num(z),zden=CoCoA::den(z); + if (CoCoA::IsInteger(n, znum) && CoCoA::IsInteger(d, zden)) + return gen(CoCoA::mpzref(n))/gen(CoCoA::mpzref(d)); + setsizeerr(gettext("Unable to convert CoCoA data")); + return undef; + } +#else + static CoCoA::ZZ gen2ZZ(const gen & g){ + switch (g.type){ + case _INT_: + return CoCoA::ZZ(g.val); + case _ZINT: + return CoCoA::ZZ(CoCoA::CopyFromMPZ,*g._ZINTptr); + default: + setsizeerr(gettext("Invalid giac gen -> CoCoA ZZ conversion")+g.print()); + return CoCoA::ZZ(0); + } + } + + static gen ZZ2gen(const CoCoA::RingElem & z){ + CoCoA::ZZ n,d; + if (CoCoA::IsInteger(n, z)) + return gen(CoCoA::mpzref(n)); + CoCoA::RingElem znum=CoCoA::num(z),zden=CoCoA::den(z); + if (CoCoA::IsInteger(n, znum) && CoCoA::IsInteger(d, zden)) + return gen(CoCoA::mpzref(n))/gen(CoCoA::mpzref(d)); + setsizeerr(gettext("Unable to convert CoCoA data")); + return undef; + } +#endif + + static CoCoA::RingElem polynome2ringelem(const polynome & p,const std::vector & x){ + if (unsigned(p.dim)>x.size()) + setdimerr(); + CoCoA::RingElem res(x[0]-x[0]); // how do you construct 0 in CoCoA? + vector >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + CoCoA::RingElem tmp(gen2ZZ(it->value)*power(x[0],0)); + index_t::const_iterator jt=it->index.begin(),jtend=it->index.end(); + for (int i=0;jt!=jtend;++jt,++i) + tmp *= power(x[i],*jt); + res += tmp; + } + return res; + } + + static polynome ringelem2polynome(const CoCoA::RingElem & f,const gen & order){ + CoCoA::SparsePolyIter it=CoCoA::BeginIter(f); + unsigned dim=CoCoA::IsEnded(it)?0:CoCoA::NumIndets(CoCoA::owner(CoCoA::PP(it))); + polynome res(dim); + vector expv; + index_t index(dim); + for (;!CoCoA::IsEnded(it);++it){ + const CoCoA::RingElem & z=CoCoA::coeff(it); + gen coeff=ZZ2gen(z); + const CoCoA::PPMonoidElem & pp=CoCoA::PP(it); + CoCoA::exponents(expv,pp); + for (unsigned i=0;i(coeff,index)); + } + change_monomial_order(res,order); // res.tsort(); + return res; + } + + static void vector_polynome2vector_ringelem(const vectpoly & v,const CoCoA::SparsePolyRing & Qx,vector & g){ + const vector & x = CoCoA::indets(Qx); + g.reserve(v.size()); + vectpoly::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + g.push_back(polynome2ringelem(*it,x)); + } + } +#if 0 + static vector vector_polynome2vector_ringelem(const vectpoly & v,const CoCoA::SparsePolyRing & Qx){ + vector g; + vector_polynome2vector_ringelem(v,Qx,g); + return g; + } + static vectpoly vector_ringelem2vector_polynome(const vector & g,const gen & order){ + vectpoly res; + vector_ringelem2vector_polynome(g,res,order); + return res; + } +#endif + static void vector_ringelem2vector_polynome(const vector & g, vectpoly & res,const gen & order){ + vector::const_iterator it=g.begin(),itend=g.end(); + res.reserve(itend-it); + for (;it!=itend;++it) + res.push_back(ringelem2polynome(*it,order)); + sort(res.begin(),res.end(),tensor_is_strictly_greater); + reverse(res.begin(),res.end()); + } + + static Qx_I get_or_make_idealptr(const vectpoly & v,const gen & order){ + if (order.type!=_INT_ || v.empty()) + settypeerr(); + order_vectpoly ov; + ov.v=v; + ov.order=order.val; + std::map::const_iterator it=cocoa_idealptr_map.find(ov),itend=cocoa_idealptr_map.end(); + if (it!=itend) + return it->second; + int d=v[0].dim; + Qx_I qx_i; + if (order.type==_INT_ && order.val!=0){ + switch (order.val){ + case _PLEX_ORDER: + qx_i.cocoa_order = new CoCoA::PPOrdering(CoCoA::NewLexOrdering(d)); + break; + case _TDEG_ORDER: + qx_i.cocoa_order = new CoCoA::PPOrdering(CoCoA::NewStdDegLexOrdering(d)); + break; + default: + qx_i.cocoa_order = new CoCoA::PPOrdering(CoCoA::NewStdDegRevLexOrdering(d)); + } + qx_i.Qxptr = new CoCoA::SparsePolyRing(CoCoA::NewPolyRing( +#ifdef COCOA9950 + CoCoA::RingQQ(), +#else + CoCoA::RingQ(), +#endif + CoCoA::SymbolRange("x",0,d-1),*qx_i.cocoa_order)); + } + else + qx_i.Qxptr = new CoCoA::SparsePolyRing(CoCoA::NewPolyRing( +#ifdef COCOA9950 + CoCoA::RingQQ(), +#else + CoCoA::RingQ(), +#endif + CoCoA::SymbolRange("x",0,d-1))); + vector g; + vector_polynome2vector_ringelem(v,*qx_i.Qxptr,g); + qx_i.idealptr=new CoCoA::ideal(*qx_i.Qxptr,g); + cocoa_idealptr_map[ov]=qx_i; + // if (cocoa_order) + // delete cocoa_order; + return qx_i; + } + + // add a dimension so that p is homogeneous of degree d + static void homogeneize(polynome & p,int deg){ + vector >::iterator it=p.coord.begin(),itend=p.coord.end(); + int n; + for (;it!=itend;++it){ + index_t i=it->index.iref(); + n=total_degree(i); + i.push_back(deg-n); + it->index=i; + } + ++p.dim; + } + + static void homogeneize(vectpoly & v){ + vectpoly::iterator it=v.begin(),itend=v.end(); + int d=0; + for (;it!=itend;++it){ + d=giacmax(d,total_degree(*it)); + } + for (it=v.begin();it!=itend;++it){ + homogeneize(*it,d); + } + } + + static void unhomogeneize(polynome & p){ + vector >::iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + index_t i=it->index.iref(); + i.pop_back(); + it->index=i; + } + --p.dim; + } + + static void unhomogeneize(vectpoly & v){ + vectpoly::iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + unhomogeneize(*it); + } + } + + bool f5(vectpoly & v,const gen & order){ + homogeneize(v); + CoCoA::SparsePolyRing Qx = CoCoA::NewPolyRing( +#ifdef COCOA9950 + CoCoA::RingQQ(), +#else + CoCoA::RingQ(), +#endif + CoCoA::SymbolRange("x",0,v[0].dim-1)); + vector g; + vector_polynome2vector_ringelem(v,Qx,g); + CoCoA::ideal I(Qx,g); + vector gb; + CoCoA::F5(gb,I); + CoCoA::operator<<(cout,gb); + cout << '\n'; + v.clear(); + vector_ringelem2vector_polynome(gb,v,order); + unhomogeneize(v); + return true; + } + + // order may be 0 (use cocoa default and convert to lex for 0-dim ideals) + // or _PLEX_ORDER (lexicographic) or _TDEG_ORDER (total degree) + // or _REVLEX_ORDER (total degree then reverse of lexicographic) + bool cocoa_gbasis(vectpoly & v,const gen & order){ + Qx_I qx_i = get_or_make_idealptr(v,order); + int d=v[0].dim; + vector gb=TidyGens(*qx_i.idealptr); + // CoCoA::operator<<(cout,gb); + // cout << '\n'; + // 0-dim ideals convert to lexicographic order using CoCoA FGLM routine + // otherwise leaves revlex order + vector NewGBasis; + if (order.type==_INT_ && order.val!=0) + NewGBasis=gb; + else { + CoCoA::PPOrdering NewOrdering = CoCoA::NewLexOrdering(d); + try { + CoCoADortmund::FGLMBasisConversion(NewGBasis, gb, NewOrdering); + } catch (...){ + v.clear(); + vector_ringelem2vector_polynome(gb,v,order); + return false; + } + // CoCoA::operator<<(cout,NewGBasis); + // cout << '\n'; + } + v.clear(); + vector_ringelem2vector_polynome(NewGBasis,v,order); + // reverse(v.begin(),v.end()); + // unhomogeneize(v); + return true; + } + + vecteur cocoa_in_ideal(const vectpoly & r,const vectpoly & v,const gen & order){ + Qx_I qx_i = get_or_make_idealptr(v,order); + vector cocoa_r; + vector_polynome2vector_ringelem(r,*qx_i.Qxptr,cocoa_r); + int s=cocoa_r.size(); + gen tmp(-1); + tmp.subtype=_INT_BOOLEAN; + vecteur res(s,tmp); + for (int i=0;i cocoa_r; + vector_polynome2vector_ringelem(r,*qx_i.Qxptr,cocoa_r); + int s=cocoa_r.size(); + polynome tmp; + for (int i=0;i"; + } + + inline bool operator == (const paire & a,const paire &b){ + return a.first==b.first && a.second==b.second; + } + + + inline bool operator < (const paire & a,const paire &b){ + return a.first!=b.first?a.first & a,const pair &b){ + return a.second1 the pairs are reduced one by one (more iteration) +#endif + +#define GBASIS_POSTF4BUCHBERGER 0 // 0 means final simplification at the end, 1 at each loop + + // #define GIAC_GBASIS_REDUCTOR_MAXSIZE 10 // max size for keeping a reductor even if it should be removed from gbasis + + //#define GIAC_GBASIS_DELAYPAIRS + + void swap_indices(short * tab){ + swap(tab[1],tab[3]); + swap(tab[4],tab[7]); + swap(tab[5],tab[6]); + swap(tab[8],tab[11]); + swap(tab[9],tab[10]); +#if GROEBNER_VARS>11 + swap(tab[12],tab[15]); + swap(tab[13],tab[14]); +#endif + } + + template + void swap_indices14(T * tab){ + swap(tab[2],tab[7]); + swap(tab[3],tab[6]); + swap(tab[4],tab[5]); + swap(tab[8],tab[15]); + swap(tab[9],tab[14]); + swap(tab[10],tab[13]); + swap(tab[11],tab[12]); + } + + void swap_indices11(short * tab){ + swap(tab[1],tab[3]); + swap(tab[4],tab[7]); + swap(tab[5],tab[6]); + swap(tab[8],tab[11]); + swap(tab[9],tab[10]); + } + + void swap_indices15_revlex(short * tab){ + swap(tab[1],tab[3]); + swap(tab[4],tab[7]); + swap(tab[5],tab[6]); + swap(tab[8],tab[11]); + swap(tab[9],tab[10]); + swap(tab[12],tab[15]); + swap(tab[13],tab[14]); + } + + void swap_indices15_3(short * tab){ + swap(tab[1],tab[3]); + swap(tab[5],tab[7]); + swap(tab[8],tab[11]); + swap(tab[9],tab[10]); + swap(tab[12],tab[15]); + swap(tab[13],tab[14]); + } + + void swap_indices15_7(short * tab){ + swap(tab[1],tab[3]); + swap(tab[4],tab[7]); + swap(tab[5],tab[6]); + swap(tab[9],tab[11]); + swap(tab[12],tab[15]); + swap(tab[13],tab[14]); + } + + void swap_indices15_11(short * tab){ + swap(tab[1],tab[3]); + swap(tab[4],tab[7]); + swap(tab[5],tab[6]); + swap(tab[8],tab[11]); + swap(tab[9],tab[10]); + swap(tab[13],tab[15]); + } + + void swap_indices15(short * tab,int o){ + if (o==_REVLEX_ORDER){ + swap_indices15_revlex(tab); + return; + } + if (o==_3VAR_ORDER){ + swap_indices15_3(tab); + return; + } + if (o==_7VAR_ORDER){ + swap_indices15_7(tab); + return; + } + if (o==_11VAR_ORDER){ + swap_indices15_11(tab); + return; + } + } + + // #define GIAC_CHARDEGTYPE should be in solve.h +#if defined BIGENDIAN && defined GIAC_CHARDEGTYPE +#undef GIAC_CHARDEGTYPE +#endif + +#ifdef GIAC_CHARDEGTYPE + typedef unsigned char degtype; // type for degree for large number of variables + #define degratio 8 + #define degratiom1 7 +#else + typedef short degtype; // type for degree for large number of variables + #define degratio 4 + #define degratiom1 3 +#endif + +#ifndef GIAC_64VARS +#define GBASIS_NO_OUTPUT +#endif + +#define GIAC_RDEG + // #define GIAC_HASH +#if defined GIAC_HASH && defined HASH_MAP_NAMESPACE +#define GIAC_RHASH +#endif + +#ifdef GIAC_RHASH + class tdeg_t64; + class tdeg_t64_hash_function_object { + public: + size_t operator () (const tdeg_t64 & ) const; // defined at the end of this file + tdeg_t64_hash_function_object() {}; + }; + + typedef HASH_MAP_NAMESPACE::hash_map< tdeg_t64,int,tdeg_t64_hash_function_object > tdeg_t64_hash_t ; +#endif + +#ifndef VISUALC + #define GIAC_ELIM +#endif + short hash64tab[]={1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411}; + + // storing indices in reverse order to have tdeg_t_greater access them + // in increasing order seems slower (cocoa.cc.64) + struct tdeg_t64 { + bool vars64() const {return true;} +#ifdef GIAC_RHASH + int hash_index(void * ptr_) const { + if (!ptr_) return -1; + tdeg_t64_hash_t & h=*(tdeg_t64_hash_t *) ptr_; + tdeg_t64_hash_t::const_iterator it=h.find(*this),itend=h.end(); + if (it==itend) + return -1; + return it->second; + } + bool add_to_hash(void *ptr_,int no) const { + if (!ptr_) return false; + tdeg_t64_hash_t & h=*(tdeg_t64_hash_t *) ptr_; + h[*this]=no; + return true; + } +#else + int hash_index(void * ptr_) const { return -1; } + bool add_to_hash(void *ptr_,int no) const { return false; } +#endif + void dbgprint() const; + // data +#ifdef GIAC_64VARS + union { + short tab[GROEBNER_VARS+1]; + struct { + short tdeg; // actually it's twice the total degree+1 + short tdeg2; + order_t order_; + longlong * ui; +#ifdef GIAC_HASH + longlong hash; +#endif +#ifdef GIAC_ELIM + ulonglong elim; // used for elimination order (modifies revlex/revlex) +#endif + }; + }; + //int front() const { if (tdeg % 2) return (*(ui+1)) & 0xffff; else return order_.o==_PLEX_ORDER?tab[0]:tab[1];} + tdeg_t64(const tdeg_t64 & a){ + if (a.tab[0]%2){ + tdeg=a.tdeg; + tdeg2=a.tdeg2; + order_=a.order_; + ui=a.ui; +#ifdef GIAC_HASH + hash=a.hash; +#endif +#ifdef GIAC_ELIM + elim=a.elim; +#endif + ++(*ui); + } + else { + longlong * ptr = (longlong *) tab; + longlong * aptr = (longlong *) a.tab; + ptr[0]=aptr[0]; + ptr[1]=aptr[1]; + ptr[2]=aptr[2]; + ptr[3]=aptr[3]; + } + } +#ifdef GIAC_ELIM + void compute_elim(longlong * ptr,longlong * ptrend){ + elim=0; + if (order_.o==_PLEX_ORDER) // don't use elim for plex + return; + if (tdeg>31){ + elim=0x1fffffffffffffffULL; + return; + } + bool tdegcare=false; + if (ptr>16)&0xffff)<<5)+(((x>>32)&0xffff)<<10)+(((x>>48)&0xffff)<<15); + } + } +#endif + void compute_degs(){ + if (tab[0]%2){ + longlong * ptr=ui+1; + tdeg=0; + int firstblock=order_.o; + if (firstblock!=_3VAR_ORDER && firstblock<_7VAR_ORDER) + firstblock=order_.dim; + longlong * ptrend=ui+1+(firstblock+degratiom1)/degratio; +#ifdef GIAC_HASH + hash=0; +#endif +#ifdef GIAC_ELIM + compute_elim(ptr,ptrend); +#endif + int i=0; + for (;ptr!=ptrend;i+=4,++ptr){ + longlong x=*ptr; +#ifdef GIAC_CHARDEGTYPE + tdeg += ((x+(x>>8)+(x>>16)+(x>>24)+(x>>32)+(x>>40)+(x>>48)+(x>>56))&0xff); +#else + tdeg += ((x+(x>>16)+(x>>32)+(x>>48))&0xffff); +#endif +#ifdef GIAC_HASH + hash += (x&0xffff)*hash64tab[i]+((x>>16)&0xffff)*hash64tab[i+1]+((x>>32)&0xffff)*hash64tab[i+2]+(x>>48)*hash64tab[i+3]; +#endif + } +#ifdef GIAC_ELIM + if (tdeg>=16) + elim=0x1fffffffffffffffULL; +#endif + tdeg=2*tdeg+1; + tdeg2=0; + ptrend=ui+1+(order_.dim+degratiom1)/degratio; + for (;ptr!=ptrend;i+=4,++ptr){ + longlong x=*ptr; +#ifdef GIAC_CHARDEGTYPE + tdeg2 += ((x+(x>>8)+(x>>16)+(x>>24)+(x>>32)+(x>>40)+(x>>48)+(x>>56))&0xff); +#else + tdeg2 += ((x+(x>>16)+(x>>32)+(x>>48))&0xffff); +#endif +#ifdef GIAC_HASH + hash += (x&0xffff)*hash64tab[i]+((x>>16)&0xffff)*hash64tab[i+1]+((x>>32)&0xfff)*hash64tab[i+2]+(x>>48)*hash64tab[i+3]; +#endif + } + } + } + ~tdeg_t64(){ + if ((tab[0]%2) && ui){ +#ifdef ATOMIC + if (atomic_fetch_add((atomic *) ui,-1)==0){ + free(ui); + ui=0; + } +#else + --(*ui); + if (*ui==0){ + free(ui); + ui=0; + } +#endif + } + } + tdeg_t64 & operator = (const tdeg_t64 & a){ + if (tab[0]%2 && ui){ +#ifdef ATOMIC + if (atomic_fetch_add((atomic *) ui,-1)==0){ + free(ui); + ui=0; + } +#else + --(*ui); + if (*ui==0){ + free(ui); + ui=0; + } +#endif + if (a.tab[0] % 2){ + tdeg=a.tdeg; + tdeg2=a.tdeg2; + order_=a.order_; + ui=a.ui; +#ifdef GIAC_HASH + hash=a.hash; +#endif +#ifdef GIAC_ELIM + elim=a.elim; +#endif +#ifdef ATOMIC + atomic_fetch_add((atomic *) ui,1); +#else + ++(*ui); +#endif + return *this; + } + } + else { + if (a.tab[0]%2){ +#ifdef ATOMIC + atomic_fetch_add((atomic *) a.ui,1); +#else + ++(*a.ui); +#endif + } + } + longlong * ptr = (longlong *) tab; + longlong * aptr = (longlong *) a.tab; + ptr[0]=aptr[0]; + ptr[1]=aptr[1]; + ptr[2]=aptr[2]; + ptr[3]=aptr[3]; + return *this; + } +#else + short tab[GROEBNER_VARS+1]; + int front(){ return tab[1];} +#endif + // methods + inline unsigned selection_degree(order_t order) const { +#ifdef GBASIS_SELECT_TOTAL_DEGREE + return total_degree(order); +#endif +#ifdef GIAC_64VARS + if (tab[0]%2) + return tdeg/2; +#endif + return tdeg; + } + inline unsigned total_degree(order_t order) const { +#ifdef GIAC_64VARS + if (tab[0]%2) + return tdeg/2+tdeg2; +#endif + // works only for revlex and tdeg +#if 0 + if (order==_REVLEX_ORDER || order==_TDEG_ORDER) + return tab[0]; + if (order==_3VAR_ORDER) + return (tab[0] << 16)+tab[4]; + if (order==_7VAR_ORDER) + return (tab[0] << 16) +tab[8]; + if (order==_11VAR_ORDER) + return (tab[0] << 16) +tab[12]; +#endif + return tab[0]; + } + // void set_total_degree(unsigned d) { tab[0]=d;} + tdeg_t64() { + longlong * ptr = (longlong *) tab; + ptr[2]=ptr[1]=ptr[0]=0; +#if GROEBNER_VARS>11 + ptr[3]=0; +#endif + } + tdeg_t64(int i){ + longlong * ptr = (longlong *) tab; + ptr[2]=ptr[1]=ptr[0]=0; +#if GROEBNER_VARS>11 + ptr[3]=0; +#endif + } + void get_tab(short * ptr,order_t order) const { +#ifdef GIAC_64VARS + if (tab[0]%2){ // copy only 16 first + degtype * ptr_=(degtype *)(ui+1); + for (unsigned i=0;i<=GROEBNER_VARS;++i) + ptr[i]=ptr_[i]; + return; + } +#endif + for (unsigned i=0;i<=GROEBNER_VARS;++i) + ptr[i]=tab[i]; +#ifdef GIAC_64VARS + ptr[0]/=2; +#endif +#ifdef GBASIS_SWAP + swap_indices(ptr); +#endif + } + tdeg_t64(const index_m & lm,order_t order){ +#ifdef GIAC_64VARS + if (lm.size()>GROEBNER_VARS){ + ui=(longlong *)malloc((1+(lm.size()+degratiom1)/degratio)*sizeof(longlong)); + longlong* ptr=ui; + *ptr=1; ++ ptr; +#ifdef GIAC_CHARDEGTYPE + for (int i=0;i>48) | (((x>>32)&0xffff)<<16) | (((x>>16)&0xffff)<<32) | ((x&0xffff)<<48); +#endif + *ptr = x; + ++ptr; + ++i; + } +#endif // GIAC_CHARDEGTYPE + if (order.o==_3VAR_ORDER || order.o>=_7VAR_ORDER){ + tdeg=2*nvar_total_degree(lm,order.o)+1; + tdeg2=sum_degree_from(lm,order.o); + } + else { + tdeg=short(2*lm.total_degree()+1); + tdeg2=0; + } + order_=order; +#if 1 // def GIAC_HASH + compute_degs(); // for hash +#else +#ifdef GIAC_ELIM + ptr=ui+1; + int firstblock=order_.o; + if (firstblock!=_3VAR_ORDER && firstblock<_7VAR_ORDER) + firstblock=order_.dim; + compute_elim(ptr,ptr+(firstblock+degratiom1)/degratio); +#endif +#endif + return; + } +#endif // GIAC_64VARS + longlong * ptr_ = (longlong *) tab; + ptr_[2]=ptr_[1]=ptr_[0]=0; + short * ptr=tab; +#if GROEBNER_VARS>11 + ptr_[3]=0; +#endif + // tab[GROEBNER_VARS]=order; +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER){ +#ifdef GIAC_64VARS + ptr[0]=2*(lm[0]+lm[1]+lm[2]); +#else + ptr[0]=lm[0]+lm[1]+lm[2]; +#endif + ptr[1]=lm[2]; + ptr[2]=lm[1]; + ptr[3]=lm[0]; + ptr +=5; + short t=0; + vector::const_iterator it=lm.begin()+3,itend=lm.end(); + for (--itend,--it;it!=itend;++ptr,--itend){ + t += *itend; + *ptr=*itend; + } + tab[4]=t; + return; + } + if (order.o==_7VAR_ORDER){ +#ifdef GIAC_64VARS + ptr[0]=2*(lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]); +#else + ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]; +#endif + ptr[1]=lm[6]; + ptr[2]=lm[5]; + ptr[3]=lm[4]; + ptr[4]=lm[3]; + ptr[5]=lm[2]; + ptr[6]=lm[1]; + ptr[7]=lm[0]; + ptr +=9; + short t=0; + vector::const_iterator it=lm.begin()+7,itend=lm.end(); + for (--itend,--it;it!=itend;++ptr,--itend){ + t += *itend; + *ptr=*itend; + } + tab[8]=t; + return; + } + if (order.o==_11VAR_ORDER){ +#ifdef GIAC_64VARS + ptr[0]=2*(lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]+lm[7]+lm[8]+lm[9]+lm[10]); +#else + ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]+lm[7]+lm[8]+lm[9]+lm[10]; +#endif + ptr[1]=lm[10]; + ptr[2]=lm[9]; + ptr[3]=lm[8]; + ptr[4]=lm[7]; + ptr[5]=lm[6]; + ptr[6]=lm[5]; + ptr[7]=lm[4]; + ptr[8]=lm[3]; + ptr[9]=lm[2]; + ptr[10]=lm[1]; + ptr[11]=lm[0]; + ptr += 13; + short t=0; + vector::const_iterator it=lm.begin()+11,itend=lm.end(); + for (--itend,--it;it!=itend;++ptr,--itend){ + t += *itend; + *ptr=*itend; + } + tab[12]=t; + return; + } +#endif + vector::const_iterator it=lm.begin(),itend=lm.end(); + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ + *ptr=sum_degree(lm); + ++ptr; + } + if (order.o==_REVLEX_ORDER){ + for (--itend,--it;it!=itend;++ptr,--itend) + *ptr=*itend; + } + else { + for (;it!=itend;++ptr,++it) + *ptr=*it; + } +#ifdef GBASIS_SWAP + swap_indices(tab); +#endif +#ifdef GIAC_64VARS + *tab *=2; +#endif + } + }; + + typedef map annuaire; + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const tdeg_t64 & x){ +#ifdef GIAC_64VARS + if (x.tab[0]%2){ + os << "["; + const longlong * ptr=x.ui+1,*ptrend=ptr+(x.order_.dim+degratiom1)/degratio; + for (;ptr!=ptrend;++ptr){ + longlong x=*ptr; +#ifdef BIGENDIAN + os << ((x>>48) &0xffff)<< "," << ((x>>32) & 0xffff) << "," << ((x>>16) & 0xffff) << "," << ((x) & 0xffff) << ","; +#else + os << ((x) &0xffff)<< "," << ((x>>16) & 0xffff) << "," << ((x>>32) & 0xffff) << "," << ((x>>48) & 0xffff) << ","; +#endif + } + return os << "]"; + } +#endif + os << "["; + for (unsigned i=0; i<=GROEBNER_VARS;++i){ + os << x.tab[i] << ","; + } + return os << "]"; + } +#else + ostream & operator << (ostream & os,const tdeg_t64 & x){ +#ifdef GIAC_64VARS + if (x.tab[0]%2){ + // debugging + tdeg_t64 xsave(x); xsave.compute_degs(); + if (xsave.tdeg!=x.tdeg || xsave.tdeg2!=x.tdeg2) + os << "degree error " ; + os << "["; + const longlong * ptr=x.ui+1,*ptrend=ptr+(x.order_.dim+degratiom1)/degratio; + for (;ptr!=ptrend;++ptr){ + longlong x=*ptr; +#ifdef BIGENDIAN + os << ((x>>48) &0xffff)<< "," << ((x>>32) & 0xffff) << "," << ((x>>16) & 0xffff) << "," << ((x) & 0xffff) << ","; +#else + os << ((x) &0xffff)<< "," << ((x>>16) & 0xffff) << "," << ((x>>32) & 0xffff) << "," << ((x>>48) & 0xffff) << ","; +#endif + } + return os << "]"; + } +#endif + os << "["; + for (unsigned i=0; i<=GROEBNER_VARS;++i){ + os << x.tab[i] << ","; + } + return os << "]"; + } +#endif + void tdeg_t64::dbgprint() const { COUT << * this << '\n'; } + tdeg_t64 operator + (const tdeg_t64 & x,const tdeg_t64 & y); + tdeg_t64 & operator += (tdeg_t64 & x,const tdeg_t64 & y){ +#ifdef GIAC_64VARS + if (x.tab[0]%2){ +#ifdef GIAC_DEBUG_TDEG_T64 + if (!(y.tab[0]%2)){ + y.dbgprint(); + COUT << "erreur" << '\n'; + } +#endif + return x=x+y; + } +#ifdef GIAC_DEBUG_TDEG_T64 + if ((y.tab[0]%2)){ + y.dbgprint(); + COUT << "erreur" << '\n'; + } +#endif +#endif +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + xtab[0]+=ytab[0]; + xtab[1]+=ytab[1]; + xtab[2]+=ytab[2]; +#if GROEBNER_VARS>11 + xtab[3]+=ytab[3]; +#endif +#else + for (unsigned i=0;i<=GROEBNER_VARS;++i) + x.tab[i]+=y.tab[i]; +#endif + return x; + } + + inline tdeg_t64 dynamic_plus(const tdeg_t64 & x,const tdeg_t64 & y){ + tdeg_t64 res; + res.order_=x.order_; + res.ui=(longlong *)malloc((1+(x.order_.dim+degratiom1)/degratio)*sizeof(longlong)); + res.ui[0]=1; + const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1; + longlong * resptr=res.ui+1; + for (;xptr!=xend;++resptr,++yptr,++xptr) + *resptr=*xptr+*yptr; +#if 1 + res.tdeg=1+2*(x.tdeg/2+y.tdeg/2); + res.tdeg2=x.tdeg2+y.tdeg2; +#ifdef GIAC_HASH + res.hash=x.hash+y.hash; +#endif +#ifdef GIAC_ELIM + if (res.tdeg>=33) + res.elim=0x1fffffffffffffffULL; + else + res.elim=x.elim+y.elim; +#endif +#else + res.tdeg=1; + res.compute_degs(); +#endif + return res; + } + + tdeg_t64 operator + (const tdeg_t64 & x,const tdeg_t64 & y){ +#ifdef GIAC_64VARS + if (x.tab[0]%2){ +#ifdef GIAC_DEBUG_TDEG_T64 + if (!(y.tab[0]%2)) + COUT << "erreur" << '\n'; +#endif + return dynamic_plus(x,y); + } +#endif +#ifdef GIAC_DEBUG_TDEG_T64 + if (y.tab[0]%2){ + y.dbgprint(); + COUT << "erreur" << '\n'; + } +#endif + tdeg_t64 res(x); + return res += y; +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]+ytab[0]; + ztab[1]=xtab[1]+ytab[1]; + ztab[2]=xtab[2]+ytab[2]; +#if GROEBNER_VARS>11 + ztab[3]=xtab[3]+ytab[3]; +#endif +#else + for (unsigned i=0;i<=GROEBNER_VARS;++i) + res.tab[i]=x.tab[i]+y.tab[i]; +#endif + return res; + } + inline void add(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & res,int dim){ +#ifdef GIAC_64VARS + if (x.tab[0]%2){ +#ifdef GIAC_DEBUG_TDEG_T64 + if (!(y.tab[0]%2)) + COUT << "erreur" << '\n'; +#endif + if (res.tab[0]%2 && res.ui[0]==1){ + const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1; + longlong * resptr=res.ui+1; +#ifndef GIAC_CHARDEGTYPE + *resptr=*xptr+*yptr;++resptr,++yptr,++xptr; + *resptr=*xptr+*yptr;++resptr,++yptr,++xptr; + *resptr=*xptr+*yptr;++resptr,++yptr,++xptr; + *resptr=*xptr+*yptr;++resptr,++yptr,++xptr; +#endif + for (;xptr!=xend;++resptr,++yptr,++xptr) + *resptr=*xptr+*yptr; +#if 1 + res.tdeg=1+2*(x.tdeg/2+y.tdeg/2); + res.tdeg2=x.tdeg2+y.tdeg2; +#ifdef GIAC_HASH + res.hash=x.hash+y.hash; +#endif +#ifdef GIAC_ELIM + if (res.tdeg>=33) + res.elim=0x1fffffffffffffffULL; + else + res.elim=x.elim+y.elim; +#endif +#else + res.tdeg=1; + res.compute_degs(); +#endif + } + else + res=dynamic_plus(x,y); + return; + } +#endif +#if 0 // def GIAC_64VARS + if (x.tab[0]%2){ + res = x; + res += y; + return; + } +#endif +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]+ytab[0]; + ztab[1]=xtab[1]+ytab[1]; + ztab[2]=xtab[2]+ytab[2]; +#if GROEBNER_VARS>11 + ztab[3]=xtab[3]+ytab[3]; +#endif +#else + for (unsigned i=0;i<=dim;++i) + res.tab[i]=x.tab[i]+y.tab[i]; +#endif + } + + tdeg_t64 operator - (const tdeg_t64 & x,const tdeg_t64 & y){ +#ifdef GIAC_64VARS + if (x.tab[0]%2){ +#ifdef GIAC_DEBUG_TDEG_T64 + if (!(y.tab[0]%2)) + COUT << "erreur" << '\n'; +#endif + tdeg_t64 res; + res.order_=x.order_; + res.ui=(longlong *)malloc((1+(x.order_.dim+degratiom1)/degratio)*sizeof(longlong)); + res.ui[0]=1; + const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1; + longlong * resptr=res.ui+1; + for (;xptr!=xend;++resptr,++yptr,++xptr) + *resptr=*xptr-*yptr; + res.tdeg=1; + res.compute_degs(); + return res; + } +#ifdef GIAC_DEBUG_TDEG_T64 + if ((y.tab[0]%2)){ + y.dbgprint(); + COUT << "erreur" << '\n'; + } +#endif +#endif // GIAC_64VARS + tdeg_t64 res; +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]-ytab[0]; + ztab[1]=xtab[1]-ytab[1]; + ztab[2]=xtab[2]-ytab[2]; +#if GROEBNER_VARS>11 + ztab[3]=xtab[3]-ytab[3]; +#endif +#else + for (unsigned i=0;i<=GROEBNER_VARS;++i) + res.tab[i]=x.tab[i]-y.tab[i]; +#endif + return res; + } + inline bool operator == (const tdeg_t64 & x,const tdeg_t64 & y){ + longlong X=((longlong *) x.tab)[0]; + if (X!= ((longlong *) y.tab)[0]) + return false; +#ifdef GIAC_HASH + if (x.hash!=y.hash) + return false; +#endif +#ifdef GIAC_ELIM + if (x.elim!=y.elim) return false; +#endif +#ifdef GIAC_64VARS + if ( +#ifdef BIGENDIAN + x.tab[0]%2 +#else + X%2 +#endif + ){ + //if (x.ui==y.ui) return true; + const longlong * xptr=x.ui+1,*xend=xptr+(x.order_.dim+degratiom1)/degratio,*yptr=y.ui+1; +#ifndef GIAC_CHARTABDEG + // dimension+3 is at least 16 otherwise the alternative code would be called + if (*xptr!=*yptr) + return false; + ++yptr,++xptr; + if (*xptr!=*yptr) + return false; + ++yptr,++xptr; + if (*xptr!=*yptr) + return false; + ++yptr,++xptr; + if (*xptr!=*yptr) + return false; + ++yptr,++xptr; +#endif + for (;xptr!=xend;++yptr,++xptr){ + if (*xptr!=*yptr) + return false; + } + return true; + } +#endif + return ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1] && + ((longlong *) x.tab)[2] == ((longlong *) y.tab)[2] +#if GROEBNER_VARS>11 + && ((longlong *) x.tab)[3] == ((longlong *) y.tab)[3] +#endif + ; + } + inline bool operator != (const tdeg_t64 & x,const tdeg_t64 & y){ + return !(x==y); + } + + static inline int tdeg_t64_revlex_greater (const tdeg_t64 & x,const tdeg_t64 & y){ +#ifdef GBASIS_SWAP + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + if (xtab[0]!=ytab[0]) // tdeg test already donne by caller + return xtab[0]<=ytab[0]?1:0; + if (xtab[1]!=ytab[1]) + return xtab[1]<=ytab[1]?1:0; + if (xtab[2]!=ytab[2]) + return xtab[2]<=ytab[2]?1:0; +#if GROEBNER_VARS>11 + return xtab[3]<=ytab[3]?1:0; +#endif + return 2; +#else // GBASIS_SWAP + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]<=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; + } +#if GROEBNER_VARS>11 + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ + if (x.tab[12]!=y.tab[12]) + return x.tab[12]<=y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; + } +#endif + return 2; +#endif // GBASIS_SWAP + } + + // inline bool operator < (const tdeg_t64 & x,const tdeg_t64 & y){ return !tdeg_t64_revlex_greater(x,y); } + // inline bool operator > (const tdeg_t64 & x,const tdeg_t64 & y){ return !tdeg_t64_revlex_greater(y,x); } + // inline bool operator <= (const tdeg_t64 & x,const tdeg_t64 & y){ return tdeg_t64_revlex_greater(y,x); } + // inline bool operator >= (const tdeg_t64 & x,const tdeg_t64 & y){ return tdeg_t64_revlex_greater(x,y); } + +#if GROEBNER_VARS==15 + + int tdeg_t64_3var_greater (const tdeg_t64 & x,const tdeg_t64 & y){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[4]!=y.tab[4]) + return x.tab[4]>=y.tab[4]?1:0; + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]<=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; + } + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ + if (x.tab[12]!=y.tab[12]) + return x.tab[12]<=y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; + } + return 2; + } + + int tdeg_t64_7var_greater (const tdeg_t64 & x,const tdeg_t64 & y){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[8]!=y.tab[8]) + return x.tab[8]>=y.tab[8]?1:0; + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; + } + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ + if (x.tab[12]!=y.tab[12]) + return x.tab[12]<=y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; + } + return 2; + } + + int tdeg_t64_11var_greater (const tdeg_t64 & x,const tdeg_t64 & y){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[12]!=y.tab[12]) + return x.tab[12]>=y.tab[12]?1:0; + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]<=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; + } + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; + } + return 2; + } +#endif // GROEBNER_VARS==15 + + int tdeg_t64_lex_greater (const tdeg_t64 & x,const tdeg_t64 & y){ +#ifdef GBASIS_SWAP + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + ulonglong X=*xtab, Y=*ytab; + if (X!=Y){ + if ( (X & 0xffff) != (Y &0xffff)) + return (X&0xffff)>=(Y&0xffff)?1:0; + return X>=Y?1:0; + } + if (xtab[1]!=ytab[1]) + return xtab[1]>=ytab[1]?1:0; + if (xtab[2]!=ytab[2]) + return xtab[2]>=ytab[2]?1:0; +#if GROEBNER_VARS>11 + return xtab[3]>=ytab[3]?1:0; +#endif + return 2; +#else + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]>y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]>y.tab[2]?1:0; + return x.tab[3]>y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]>y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]>y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]>y.tab[6]?1:0; + return x.tab[7]>y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]>y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]>y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]>y.tab[10]?1:0; + return x.tab[11]>=y.tab[11]?1:0; + } +#if GROEBNER_VARS>11 + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ + if (x.tab[12]!=y.tab[12]) + return x.tab[12]>y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]>y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]>y.tab[14]?1:0; + return x.tab[15]>=y.tab[15]?1:0; + } +#endif + return 2; +#endif + } + + inline int tdeg_t_greater_dyn(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){ + const longlong * it1=x.ui,* it2=y.ui,*it1beg; + longlong a=0; + switch (order.o){ + case _REVLEX_ORDER: + it1beg=x.ui; + it1=x.ui+(x.order_.dim+degratiom1)/degratio; + it2=y.ui+(y.order_.dim+degratiom1)/degratio; + it1beg += 3; + for (;it1>it1beg;){ + a=*it1-*it2; + if (a) + return a<=0?1:0; + --it2;--it1; + a=*it1-*it2; + if (a) + return a<=0?1:0; + --it2;--it1; + a=*it1-*it2; + if (a) + return a<=0?1:0; + --it2;--it1; + a=*it1-*it2; + if (a) + return a<=0?1:0; + --it2;--it1; + } + it1beg -= 3; + for (;it1!=it1beg;--it2,--it1){ + a=*it1-*it2; + if (a) + return a<=0?1:0; + } + return 2; + case _64VAR_ORDER: + a=it1[16]-it2[16]; + if (a) + return a<=0?1:0; + a=it1[15]-it2[15]; + if (a) + return a<=0?1:0; + a=it1[14]-it2[14]; + if (a) + return a<=0?1:0; + a=it1[13]-it2[13]; + if (a) + return a<=0?1:0; + case _48VAR_ORDER: + a=it1[12]-it2[12]; + if (a) + return a<=0?1:0; + a=it1[11]-it2[11]; + if (a) + return a<=0?1:0; + a=it1[10]-it2[10]; + if (a) + return a<=0?1:0; + a=it1[9]-it2[9]; + if (a) + return a<=0?1:0; + case _32VAR_ORDER: + a=it1[8]-it2[8]; + if (a) + return a<=0?1:0; + a=it1[7]-it2[7]; + if (a) + return a<=0?1:0; + a=it1[6]-it2[6]; + if (a) + return a<=0?1:0; + a=it1[5]-it2[5]; + if (a) + return a<=0?1:0; + case _16VAR_ORDER: + a=it1[4]-it2[4]; + if (a) + return a<=0?1:0; + case _11VAR_ORDER: + a=it1[3]-it2[3]; + if (a) + return a<=0?1:0; + case _7VAR_ORDER: + a=it1[2]-it2[2]; + if (a) + return a<=0?1:0; + case _3VAR_ORDER: + a=it1[1]-it2[1]; + if (a) + return a<=0?1:0; + if (x.tdeg2!=y.tdeg2) + return x.tdeg2>y.tdeg2?1:0; + it1beg=it1+(x.order_.o+degratiom1)/degratio; + it1 += (x.order_.dim+degratiom1)/degratio;; + it2 += (x.order_.dim+degratiom1)/degratio;; + for (;;){ + a=*it1-*it2; + if (a) + return a<=0?1:0; + --it2;--it1; + if (it1<=it1beg) + return 2; + } + case _TDEG_ORDER: case _PLEX_ORDER: { + const degtype * it1=(degtype *)(x.ui+1),*it1end=it1+x.order_.dim,*it2=(degtype *)(y.ui+1); + for (;it1!=it1end;++it2,++it1){ + if (*it1!=*it2) + return *it1>=*it2?1:0; + } + return 2; + } + } // end swicth + return -1; + } + + inline int tdeg_t_greater(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){ + short X=x.tab[0]; + if (order.o!=_PLEX_ORDER && X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex +#ifdef GIAC_64VARS + if (X%2){ + if (order.o!=_PLEX_ORDER && x.tdeg2!=y.tdeg2) return x.tdeg2>y.tdeg2?1:0; +#ifdef GIAC_ELIM + if ( x.elim!=y.elim) return x.elim=_7VAR_ORDER || order.o==_3VAR_ORDER){ + int n=(order.o+degratiom1)/degratio; + const longlong * it1beg=x.ui,*it1=x.ui+n,*it2=y.ui+n; + longlong a=0,b=0; +#ifdef BIGENDIAN + for (;it1!=it1beg;--it2,--it1){ + a=*it1; + b=*it2; + if (a!=b) + break; + } + if (a!=b){ + if ( ((a)&0xffff) != ((b)&0xffff) ) + return ((a)&0xffff) <= ((b)&0xffff)?1:0; + if ( ((a>>16)&0xffff) != ((b>>16)&0xffff) ) + return ((a>>16)&0xffff) <= ((b>>16)&0xffff)?1:0; + if ( ((a>>32)&0xffff) != ((b>>32)&0xffff) ) + return ((a>>32)&0xffff) <= ((b>>32)&0xffff)?1:0; + return a <= b?1:0; + } +#else + for (;it1!=it1beg;--it2,--it1){ + a=*it1-*it2; + if (a) + return a<=0?1:0; + } +#endif + // if (x.tdeg2!=y.tdeg2) return x.tdeg2>=y.tdeg2; + it1beg=x.ui+n; + n=(x.order_.dim+degratiom1)/degratio; + it1=x.ui+n; + it2=y.ui+n; +#ifdef BIGENDIAN + for (a=0,b=0;it1!=it1beg;--it2,--it1){ + a=*it1; b=*it2; + if (a!=b) + break; + } + if (a!=b){ + if ( ((a)&0xffff) != ((b)&0xffff) ) + return ((a)&0xffff) <= ((b)&0xffff)?1:0; + if ( ((a>>16)&0xffff) != ((b>>16)&0xffff) ) + return ((a>>16)&0xffff) <= ((b>>16)&0xffff) ?1:0; + if ( ((a>>32)&0xffff) != ((b>>32)&0xffff) ) + return ((a>>32)&0xffff) <= ((b>>32)&0xffff) ?1:0; + return a <= b?1:0; + } +#else + for (;it1!=it1beg;--it2,--it1){ + a=*it1-*it2; + if (a) + return a<=0?1:0; + } +#endif + return 2; + } + if (order.o==_REVLEX_ORDER){ + //if (x.tdeg!=y.tdeg) return x.tdeg>y.tdeg?1:0; + const longlong * it1beg=x.ui,*it1=x.ui+(x.order_.dim+degratiom1)/degratio,*it2=y.ui+(y.order_.dim+degratiom1)/degratio; + longlong a=0,b=0; +#ifdef BIGENDIAN + for (;it1!=it1beg;--it2,--it1){ + a=*it1; b=*it2; + if (a!=b) + break; + } + if (a!=b){ + if ( ((a)&0xffff) != ((b)&0xffff) ) + return ((a)&0xffff) <= ((b)&0xffff)?1:0; + if ( ((a>>16)&0xffff) != ((b>>16)&0xffff) ) + return ((a>>16)&0xffff) <= ((b>>16)&0xffff)?1:0; + if ( ((a>>32)&0xffff) != ((b>>32)&0xffff) ) + return ((a>>32)&0xffff) <= ((b>>32)&0xffff)?1:0; + return a <= b?1:0; + } +#else + for (;it1!=it1beg;--it2,--it1){ + a=*it1-*it2; + if (a) + return a<=0?1:0; + } +#endif + return 2; + } + // plex and tdeg share the same code since total degree already checked + const degtype * it1=(degtype *)(x.ui+1),*it1end=it1+x.order_.dim,*it2=(degtype *)(y.ui+1); + for (;it1!=it1end;++it2,++it1){ + if (*it1!=*it2) + return *it1>=*it2?1:0; + } + return 2; +#endif // BIGENDIAN, GIAC_CHARDEGTYPE + } // end if X%2 +#endif // GIAC_64VARS + if (order.o==_REVLEX_ORDER) + return tdeg_t64_revlex_greater(x,y); +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER) + return tdeg_t64_3var_greater(x,y); + if (order.o==_7VAR_ORDER) + return tdeg_t64_7var_greater(x,y); + if (order.o==_11VAR_ORDER) + return tdeg_t64_11var_greater(x,y); +#endif + return tdeg_t64_lex_greater(x,y); + } + inline bool tdeg_t_strictly_greater (const tdeg_t64 & x,const tdeg_t64 & y,order_t order){ + return !tdeg_t_greater(y,x,order); // total order + } + + inline bool tdeg_t_all_greater(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){ + if ((*((ulonglong*)&x)-*((ulonglong*)&y)) & 0x8000800080008000ULL) + return false; +#ifdef GIAC_64VARS + if (x.tab[0]%2){ +#ifdef GIAC_ELIM + //bool debug=false; + if ( !( (x.elim | y.elim) & 0x1000000000000000ULL) && +#if 0 // ndef BESTA_OS // Keil compiler, for some reason does not like the 0b syntax! + ( (x.elim-y.elim) & 0b1111100001000010000100001000010000100001000010000100001000010000ULL) ) +#else + ( (x.elim-y.elim) & 0xf842108421084210ULL) ) +#endif + { + //debug=true; + return false; + } +#endif +#ifdef GIAC_DEBUG_TDEG_T64 + if (!(y.tab[0]%2)) + COUT << "erreur" << '\n'; +#endif +#ifdef GIAC_HASH + if (x.hash11 + if ((xtab[3]-ytab[3]) & 0x8000800080008000ULL) + return false; +#endif + return true; + } + + const longlong mask2=0x8080808080808080ULL; +#ifdef GIAC_CHARDEGTYPE + const longlong mask=0x8080808080808080ULL; +#else + const longlong mask=0x8000800080008000ULL; +#endif + + // 1 (all greater), 0 (unknown), -1 (all smaller) + int tdeg_t_compare_all(const tdeg_t64 & x,const tdeg_t64 & y,order_t order){ +#ifdef GIAC_64VARS + if (x.tab[0]%2){ +#ifdef GIAC_DEBUG_TDEG_T64 + if (!(y.tab[0]%2)) + COUT << "erreur" << '\n'; +#endif + if ( (x.tdeg11 + tmp=xtab[3]-ytab[3]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } +#endif + return res; + } + + void index_lcm(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & z,order_t order){ +#ifdef GIAC_64VARS + if (x.tdeg%2){ +#ifdef GIAC_DEBUG_TDEG_T64 + if (!(y.tab[0]%2)) + COUT << "erreur" << '\n'; +#endif + z=tdeg_t64(); + z.tdeg=1; + z.order_=x.order_; + int nbytes=(1+(x.order_.dim+degratiom1)/degratio)*sizeof(longlong); + z.ui=(longlong *)malloc(nbytes); + z.ui[0]=1; + const degtype * xptr=(degtype *)(x.ui+1),*xend=xptr+degratio*((x.order_.dim+degratiom1)/degratio),*yptr=(degtype *)(y.ui+1); + degtype * resptr=(degtype *)(z.ui+1); + for (;xptr!=xend;++resptr,++yptr,++xptr) + *resptr=*xptr>*yptr?*xptr:*yptr; + z.tdeg=1; + z.compute_degs(); + return ; + } +#endif + int t=0; + const short * xtab=&x.tab[1],*ytab=&y.tab[1]; + short *ztab=&z.tab[1]; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 1 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3 + ++xtab; ++ytab; ++ztab; +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER){ +#ifdef GIAC_64VARS + z.tab[0]=2*t; +#else + z.tab[0]=t; +#endif + t=0; + ++xtab;++ytab;++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 + z.tab[4]=t; // 4 + return; + } +#endif + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7 + ++xtab; ++ytab; ++ztab; +#if GROEBNER_VARS==15 + if (order.o==_7VAR_ORDER){ +#ifdef GIAC_64VARS + z.tab[0]=2*t; +#else + z.tab[0]=t; +#endif + t=0; + ++xtab;++ytab;++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 + z.tab[8]=t; // 8 + return; + } +#endif + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 +#if GROEBNER_VARS>11 + ++xtab; ++ytab; ++ztab; +#if GROEBNER_VARS==15 + if (order.o==_11VAR_ORDER){ +#ifdef GIAC_64VARS + z.tab[0]=2*t; +#else + z.tab[0]=t; +#endif + t=0; + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 + z.tab[12]=t; // 12 + return; + } +#endif + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 +#endif + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ +#ifdef GIAC_64VARS + z.tab[0]=2*t; +#else + z.tab[0]=t; +#endif + } + else { +#ifdef GIAC_64VARS + z.tab[0]=2*((x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0]); +#else + z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0]; +#endif + } + } + + void index_lcm_overwrite(const tdeg_t64 & x,const tdeg_t64 & y,tdeg_t64 & z,order_t order){ + if (z.tdeg%2==0){ + index_lcm(x,y,z,order); + return; + } + const degtype * xptr=(degtype *)(x.ui+1),*xend=xptr+degratio*((x.order_.dim+degratiom1)/degratio),*yptr=(degtype *)(y.ui+1); + degtype * resptr=(degtype *)(z.ui+1); + for (;xptr!=xend;++resptr,++yptr,++xptr) + *resptr=*xptr>*yptr?*xptr:*yptr; + z.tdeg=1; + z.compute_degs(); + } + + void get_index(const tdeg_t64 & x_,index_t & idx,order_t order,int dim){ +#ifdef GIAC_64VARS + if (x_.tab[0]%2){ + idx.resize(dim); + if (dim && sizeof(degtype)==sizeof(idx.front())){ + memcpy(&idx.front(),x_.ui+1,dim*sizeof(degtype)); + return; + } + const degtype * ptr=(degtype *)(x_.ui+1),*ptrend=ptr+x_.order_.dim; + index_t::iterator target=idx.begin(); + for (;ptr!=ptrend;++target,++ptr) + *target=*ptr; + return; + } +#endif + idx.resize(dim); +#ifdef GBASIS_SWAP + tdeg_t64 x(x_); + swap_indices(x.tab); +#else + const tdeg_t64 & x= x_; +#endif + const short * ptr=x.tab; +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER){ + ++ptr; + for (int i=1;i<=3;++ptr,++i) + idx[3-i]=*ptr; + ++ptr; + for (int i=1;i<=dim-3;++ptr,++i) + idx[dim-i]=*ptr; + return; + } + if (order.o==_7VAR_ORDER){ + ++ptr; + for (int i=1;i<=7;++ptr,++i) + idx[7-i]=*ptr; + ++ptr; + for (int i=1;i<=dim-7;++ptr,++i) + idx[dim-i]=*ptr; + return; + } + if (order.o==_11VAR_ORDER){ + ++ptr; + for (int i=1;i<=11;++ptr,++i) + idx[11-i]=*ptr; + ++ptr; + for (int i=1;i<=dim-11;++ptr,++i) + idx[dim-i]=*ptr; + return; + } +#endif + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER) + ++ptr; + if (order.o==_REVLEX_ORDER){ + for (int i=1;i<=dim;++ptr,++i) + idx[dim-i]=*ptr; + } + else { + for (int i=0;i > + template + struct poly8 { + std::vector< T_unsigned > coord; + // lex order is implemented using tdeg_t as a list of degrees + // tdeg uses total degree 1st then partial degree in lex order, max 7 vars + // revlex uses total degree 1st then opposite of partial degree in reverse ordre, max 7 vars + order_t order; // _PLEX_ORDER, _REVLEX_ORDER or _TDEG_ORDER or _7VAR_ORDER or _11VAR_ORDER + short int dim; + unsigned sugar; + double logz; // unused, it's here for tripolymod_tri + int age; // unused, it's here for tripolymod_tri + void dbgprint() const; + poly8():dim(0),sugar(0),logz(0),age(-1) {order.o=_PLEX_ORDER; order.lex=0; order.dim=0;} + poly8(order_t o_,int dim_): order(o_),dim(dim_),sugar(0),logz(0),age(-1) {order.dim=dim_;} + poly8(const polynome & p,order_t o_){ + order=o_; + dim=p.dim; + order.dim=p.dim; + logz=0; + age=-1; + if (order.o%4!=3){ + if (p.is_strictly_greater==i_lex_is_strictly_greater) + order.o=_PLEX_ORDER; + if (p.is_strictly_greater==i_total_revlex_is_strictly_greater) + order.o=_REVLEX_ORDER; + if (p.is_strictly_greater==i_total_lex_is_strictly_greater) + order.o=_TDEG_ORDER; + } + if ( +#ifdef GIAC_64VARS + 0 && +#endif + p.dim>GROEBNER_VARS) + CERR << "Number of variables is too large to be handled by giac"; + else { + coord.reserve(p.coord.size()); + for (unsigned i=0;i(p.coord[i].value,tdeg_t(p.coord[i].index,order))); + } + } + if (coord.empty()) + sugar=0; + else + sugar=coord.front().u.total_degree(order); + } + void get_polynome(polynome & p) const { + p.dim=dim; + switch (order.o){ + case _REVLEX_ORDER: + p.is_strictly_greater=i_total_revlex_is_strictly_greater; + break; + case _3VAR_ORDER: + p.is_strictly_greater=i_3var_is_strictly_greater; + break; + case _7VAR_ORDER: + p.is_strictly_greater=i_7var_is_strictly_greater; + break; + case _11VAR_ORDER: + p.is_strictly_greater=i_11var_is_strictly_greater; + break; + case _TDEG_ORDER: + p.is_strictly_greater=i_total_lex_is_strictly_greater; + break; + default: + case _PLEX_ORDER: + p.is_strictly_greater=i_lex_is_strictly_greater; + break; + } + p.coord.clear(); + p.coord.reserve(coord.size()); + index_t idx(dim); + for (unsigned i=0;i(coord[i].g,idx)); + } + // if (order==_3VAR_ORDER || order==_7VAR_ORDER || order==_11VAR_ORDER) p.tsort(); + } + }; + template + bool operator == (const poly8 & p,const poly8 &q){ + if (p.coord.size()!=q.coord.size()) + return false; + for (unsigned i=0;i nio::ios_base & operator << (nio::ios_base & os, const poly8 & p) +#else + template + ostream & operator << (ostream & os, const poly8 & p) +#endif + { + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + int t2; + if (it==itend) + return os << 0 ; + for (;it!=itend;){ + os << it->g ; +#ifndef GBASIS_NO_OUTPUT + if (it->u.vars64()){ + if (it->u.tdeg%2){ + degtype * i=(degtype *)(it->u.ui+1); + int s=it->u.order_.dim; + for (int j=0;ju.get_tab(tab,p.order); + switch (p.order.o){ + case _PLEX_ORDER: + for (int i=0;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2) + os << "*x"<< i << "^" << t2 ; + } + break; + case _REVLEX_ORDER: + for (int i=1;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; +#if GROEBNER_VARS==15 + case _3VAR_ORDER: + for (int i=1;i<=3;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 3-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=5;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 7+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; + case _7VAR_ORDER: + for (int i=1;i<=7;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 7-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=9;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 11+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; + case _11VAR_ORDER: + for (int i=1;i<=11;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 11-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=13;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 15+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; +#endif + case _TDEG_ORDER: + for (int i=1;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2==0) + continue; + if (t2) + os << "*x"<< i-1 << "^" << t2 ; + } + break; + } + ++it; + if (it==itend) + break; + os << " + "; + } + return os; + } + + + template + void poly8::dbgprint() const { + CERR << *this << '\n'; + } + + template + class vectpoly8:public vector >{ + public: + void dbgprint() const { CERR << *this << '\n'; } + }; + + template + void vectpoly_2_vectpoly8(const vectpoly & v,order_t order,vectpoly8 & v8){ + v8.clear(); + v8.reserve(v.size()); if (debug_infolevel>1000){ v8.dbgprint(); v8[0].dbgprint();} + for (unsigned i=0;i(v[i],order)); + } + } + + template + void vectpoly8_2_vectpoly(const vectpoly8 & v8,vectpoly & v){ + v.clear(); + v.reserve(v8.size()); + for (unsigned i=0;i + gen inplace_ppz(poly8 & p,bool divide=true,bool quick=false){ + typename vector< T_unsigned >::iterator it=p.coord.begin(),itend=p.coord.end(); + if (it==itend) + return 1; + gen res=(itend-1)->g; + for (;it!=itend;++it){ + if (it->g.type==_INT_){ + res=it->g; + if (quick) + return 1; + break; + } + } + if (res.type==_ZINT) + res=*res._ZINTptr; // realloc for inplace gcd + for (it=p.coord.begin();it!=itend;++it){ + if (res.type==_ZINT && it->g.type==_ZINT){ + mpz_gcd(*res._ZINTptr,*res._ZINTptr,*it->g._ZINTptr); + } + else + res=gcd(res,it->g); + if (is_one(res)) + return 1; + } + if (!divide) + return res; +#ifndef USE_GMP_REPLACEMENTS + if (res.type==_INT_ && res.val>0){ + for (it=p.coord.begin();it!=itend;++it){ + if (it->g.type!=_ZINT || it->g.ref_count()>1) + it->g=it->g/res; + else + mpz_divexact_ui(*it->g._ZINTptr,*it->g._ZINTptr,res.val); + } + return res; + } + if (res.type==_ZINT){ + for (it=p.coord.begin();it!=itend;++it){ + if (it->g.type!=_ZINT || it->g.ref_count()>1) + it->g=it->g/res; + else + mpz_divexact(*it->g._ZINTptr,*it->g._ZINTptr,*res._ZINTptr); + } + return res; + } +#endif + for (it=p.coord.begin();it!=itend;++it){ + it->g=it->g/res; + } + return res; + } + + template + void inplace_mult(const gen & g,vector< T_unsigned > & v){ + typename std::vector< T_unsigned >::iterator it1=v.begin(),it1end=v.end(); + for (;it1!=it1end;++it1){ +#if 0 + it1->g=g*(it1->g); +#else + type_operator_times(g,it1->g,it1->g); +#endif + } + } + +#define GBASIS_HEAP +#ifdef GBASIS_HEAP + // heap: remove bitfields if that's not enough + template + struct heap_t { + unsigned i:16; // index in pairs of quotients/divisors + unsigned qi:24; + unsigned gj:24; // monomial index for quotient and divisor + tdeg_t u; // product + }; + + // inline bool operator > (const heap_t & a,const heap_t & b){ return a.u>b.u; } + + // inline bool operator < (const heap_t & a,const heap_t & b){ return b>a; } + template + struct heap_t_compare { + order_t order; + const heap_t * ptr; + inline bool operator () (unsigned a,unsigned b){ + return !tdeg_t_greater((ptr+a)->u,(ptr+b)->u,order); + // return (ptr+a)->u<(ptr+b)->u; + } + heap_t_compare(const vector > & v,order_t o):order(o),ptr(v.empty()?0:&v.front()){}; + }; + + template + struct compare_heap_t { + order_t order; + inline bool operator () (const heap_t & a,const heap_t & b){ + return !tdeg_t_greater(a.u,b.u,order); + // return (ptr+a)->u<(ptr+b)->u; + } + compare_heap_t(order_t o):order(o) {} + }; + + template + struct heap_t_ptr { + heap_t * ptr; + }; + + template + void heap_reduce(const poly8 & f,const vectpoly8 & g,const vector & G,unsigned excluded,vectpoly8 & q,poly8 & rem,poly8& R,gen & s,environment * env){ + // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]] + // first implementation: use quotxsient heap for all quotient/divisor + // do not use heap chain + // ref Monaghan Pearce if g.size()==1 + // R is a temporary polynomial, should be different from f + if (&rem==&f){ + R.dim=f.dim; R.order=f.order; + heap_reduce(f,g,G,excluded,q,R,R,s,env); + swap(rem.coord,R.coord); + if (debug_infolevel>1000) + g.dbgprint(); // instantiate dbgprint() + return; + } + rem.coord.clear(); + if (f.coord.empty()) + return ; + if (q.size() > H; + compare_heap_t key(f.order); + H.reserve(guess); + vecteur invlcg(G.size()); + if (env && env->moduloon){ + for (unsigned i=0;imodulo); + } + } + s=1; + gen c,numer,denom; + longlong C; + unsigned k=0,i; // k=position in f + tdeg_t m; + bool finish=false; + bool small0=env && env->moduloon && env->modulo.type==_INT_ && env->modulo.val; + int p=env?env->modulo.val:0; + while (!H.empty() || k & current=H.back(); // was root node of the heap + const poly8 & gcurrent = g[G[current.i]]; + if (small0) + C -= extend(q[current.i].coord[current.qi].g.val) * smod(gcurrent.coord[current.gj].g,p).val; + else { + if (env && env->moduloon){ + c -= q[current.i].coord[current.qi].g * gcurrent.coord[current.gj].g; + } + else { + fxnd(q[current.i].coord[current.qi].g,numer,denom); + if (denom==s) + c -= numer*gcurrent.coord[current.gj].g; + else { + if (denom==1) + c -= s*numer*gcurrent.coord[current.gj].g; + else + c -= (s/denom)*numer*gcurrent.coord[current.gj].g; + } + } + } + if (current.gjmoduloon) + c=smod(c,env->modulo); + if (c==0) + continue; + } + // divide (c,m) by one of the g if possible, otherwise push in remainder + if (finish) + i=unsigned(G.size()); + else { + finish=true; + for (i=0;i(c,m)); // add c/s*m to remainder + else { + //rem.coord.push_back(T_unsigned(c/s,m)); // add c/s*m to remainder + rem.coord.push_back(T_unsigned(Tfraction(c,s),m)); // add c/s*m to remainder + } + continue; + } + // add c/s*m/leading monomial of g[G[i]] to q[i] + tdeg_t monom=m-g[G[i]].coord.front().u; + if (env && env->moduloon){ + if (invlcg[i]!=1){ + if (invlcg[i]==-1) + c=-c; + else + c=smod(c*invlcg[i],env->modulo); + } + q[i].coord.push_back(T_unsigned(c,monom)); + } + else { + gen lcg=g[G[i]].coord.front().g; + gen pgcd=simplify3(lcg,c); + if (is_positive(-lcg,context0)){ + lcg=-lcg; + c=-c; + } + s=s*lcg; + if (s==1) + q[i].coord.push_back(T_unsigned(c,monom)); + else + q[i].coord.push_back(T_unsigned(Tfraction(c,s),monom)); + } + // push in heap + if (g[G[i]].coord.size()>1){ + heap_t current={i,int(q[i].coord.size())-1,1,g[G[i]].coord[1].u+monom}; + H.push_back(current); + push_heap(H.begin(),H.end(),key); + } + } // end main heap pseudo-division loop + } + + template + void heap_reduce(const poly8 & f,const vectpoly8 & g,const vector & G,unsigned excluded,vectpoly8 & q,poly8 & rem,poly8& TMP1,environment * env){ + gen s; + if (debug_infolevel>2) + CERR << f << " = " << '\n'; + heap_reduce(f,g,G,excluded,q,rem,TMP1,s,env); + // end up by multiplying rem by s (so that everything is integer) + if (debug_infolevel>2){ + for (unsigned i=0;imoduloon){ + if (!rem.coord.empty() && rem.coord.front().g!=1) + smallmult(invmod(rem.coord.front().g,env->modulo),rem.coord,rem.coord,env->modulo.val); + return; + } + if (s!=1) + smallmult(s,rem.coord,rem.coord); + gen tmp=inplace_ppz(rem); + if (debug_infolevel>1) + CERR << "ppz was " << tmp << '\n'; + } + +#endif // GBASIS_HEAP + + + template + void smallmult(const gen & a,poly8 & p,gen & m){ + typename std::vector< T_unsigned >::iterator pt=p.coord.begin(),ptend=p.coord.end(); + if (a.type==_INT_ && m.type==_INT_){ + for (;pt!=ptend;++pt){ + if (pt->g.type==_INT_) + pt->g=(extend(pt->g.val)*a.val)%m.val; + else + pt->g=smod(a*pt->g,m); + } + } + else { + for (;pt!=ptend;++pt){ + pt->g=smod(a*pt->g,m); + } + } + } + + // p - a*q shifted mod m -> r + template + void smallmultsub(const poly8 & p,unsigned pos,int a,const poly8 & q,const tdeg_t & shift,poly8 & r,int m){ + r.coord.clear(); + r.coord.reserve(p.coord.size()+q.coord.size()); + typename vector< T_unsigned >::const_iterator it=p.coord.begin()+pos,itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end(); + for (;jt!=jtend;++jt){ + tdeg_t v=jt->u+shift; + for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){ + r.coord.push_back(*it); + } + if (it!=itend && it->u==v){ + if (it->g.type==_INT_ && jt->g.type==_INT_){ + int tmp=(it->g.val-extend(a)*jt->g.val)%m; + if (tmp) + r.coord.push_back(T_unsigned(tmp,v)); + } + else + r.coord.push_back(T_unsigned(smod(it->g-a*jt->g,m),v)); + ++it; + } + else { + if (jt->g.type==_INT_){ + int tmp=(-extend(a)*jt->g.val)%m; + r.coord.push_back(T_unsigned(tmp,v)); + } + else + r.coord.push_back(T_unsigned(smod(-a*jt->g,m),v)); + } + } + for (;it!=itend;++it){ + r.coord.push_back(*it); + } + } + + // a and b are assumed to be _ZINT + template + void linear_combination(const gen & a,const poly8 &p,tdeg_t * ashift,const gen &b,const poly8 & q,tdeg_t * bshift,poly8 & r,environment * env){ + r.coord.clear(); + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end(); + r.coord.reserve((itend-it)+(jtend-jt)); + mpz_t tmpz; + mpz_init(tmpz); + if (jt!=jtend){ + tdeg_t v=jt->u; + if (bshift) + v=v+*bshift; + for (;it!=itend;){ + tdeg_t u=it->u; + if (ashift) + u=u+*ashift; + if (u==v){ + gen g; +#ifndef USE_GMP_REPLACEMENTS + if ( (it->g.type==_INT_ || it->g.type==_ZINT) && + (jt->g.type==_INT_ || jt->g.type==_ZINT) ){ + if (it->g.type==_INT_) + mpz_mul_si(tmpz,*a._ZINTptr,it->g.val); + else + mpz_mul(tmpz,*a._ZINTptr,*it->g._ZINTptr); + if (jt->g.type==_INT_){ + if (jt->g.val>=0) + mpz_addmul_ui(tmpz,*b._ZINTptr,jt->g.val); + else + mpz_submul_ui(tmpz,*b._ZINTptr,-jt->g.val); + } + else + mpz_addmul(tmpz,*b._ZINTptr,*jt->g._ZINTptr); + if (mpz_sizeinbase(tmpz,2)<31) + g=int(mpz_get_si(tmpz)); + else { + ref_mpz_t * ptr =new ref_mpz_t; + mpz_swap(ptr->z,tmpz); + g=ptr; // g=tmpz; + } + } + else +#endif + g=a*it->g+b*jt->g; + if (env && env->moduloon) + g=smod(g,env->modulo); + if (!is_zero(g)) + r.coord.push_back(T_unsigned(g,u)); + ++it; ++jt; + if (jt==jtend) + break; + v=jt->u; + if (bshift) + v=v+*bshift; + continue; + } + if (tdeg_t_strictly_greater(u,v,p.order)){ + gen g=a*it->g; + if (env && env->moduloon) + g=smod(g,env->modulo); + r.coord.push_back(T_unsigned(g,u)); + ++it; + } + else { + gen g=b*jt->g; + if (env && env->moduloon) + g=smod(g,env->modulo); + r.coord.push_back(T_unsigned(g,v)); + ++jt; + if (jt==jtend) + break; + v=jt->u; + if (bshift) + v=v+*bshift; + } + } + } + for (;it!=itend;++it){ + tdeg_t u=it->u; + if (ashift) + u=u+*ashift; + gen g=a*it->g; + if (env && env->moduloon) + g=smod(g,env->modulo); + r.coord.push_back(T_unsigned(g,u)); + } + for (;jt!=jtend;++jt){ + tdeg_t v=jt->u; + if (bshift) + v=v+*bshift; + gen g=b*jt->g; + if (env && env->moduloon) + g=smod(g,env->modulo); + r.coord.push_back(T_unsigned(g,v)); + } + mpz_clear(tmpz); + } + + // check that &v1!=&v and &v2!=&v + template + void sub(const poly8 & v1,const poly8 & v2,poly8 & v,environment * env){ + typename std::vector< T_unsigned >::const_iterator it1=v1.coord.begin(),it1end=v1.coord.end(),it2=v2.coord.begin(),it2end=v2.coord.end(); + gen g; + v.coord.clear(); + v.coord.reserve((it1end-it1)+(it2end-it2)); // worst case + for (;it1!=it1end && it2!=it2end;){ + if (it1->u==it2->u){ + g=it1->g-it2->g; + if (env && env->moduloon) + g=smod(g,env->modulo); + if (!is_zero(g)) + v.coord.push_back(T_unsigned(g,it1->u)); + ++it1; + ++it2; + } + else { + if (tdeg_t_strictly_greater(it1->u,it2->u,v1.order)){ + v.coord.push_back(*it1); + ++it1; + } + else { + v.coord.push_back(T_unsigned(-it2->g,it2->u)); + ++it2; + } + } + } + for (;it1!=it1end;++it1) + v.coord.push_back(*it1); + for (;it2!=it2end;++it2) + v.coord.push_back(T_unsigned(-it2->g,it2->u)); + } + + template + void reduce(const poly8 & p,const vectpoly8 & res,const vector & G,unsigned excluded,vectpoly8 & quo,poly8 & rem,poly8 & TMP1, poly8 & TMP2,gen & lambda,environment * env,vector * Gusedptr=0){ + lambda=1; + // last chance of improving = modular method for reduce or modular algo + if (&p!=&rem) + rem=p; + if (p.coord.empty()) + return ; + typename std::vector< T_unsigned >::const_iterator pt,ptend; + unsigned i,rempos=0; + bool small0=env && env->moduloon && env->modulo.type==_INT_ && env->modulo.val; + TMP1.order=p.order; TMP1.dim=p.dim; TMP2.order=p.order; TMP2.dim=p.dim; TMP1.coord.clear(); + for (unsigned count=0;;++count){ + ptend=rem.coord.end(); + // this branch search first in all leading coeff of G for a monomial + // <= to the current rem monomial + pt=rem.coord.begin()+rempos; + if (pt>=ptend) + break; + for (i=0;iu,res[G[i]].coord.front().u,p.order)) + break; + } + if (i==G.size()){ // no leading coeff of G is smaller than the current coeff of rem + ++rempos; + // if (small0) TMP1.coord.push_back(*pt); + continue; + } + if (Gusedptr) + (*Gusedptr)[i]=true; + gen a(pt->g),b(res[G[i]].coord.front().g); + if (small0){ + smallmultsub(rem,0,smod(a*invmod(b,env->modulo),env->modulo).val,res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env->modulo.val); + // smallmultsub(rem,rempos,smod(a*invmod(b,env->modulo),env->modulo).val,res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env->modulo.val); + // rempos=0; // since we have removed the beginning of rem (copied in TMP1) + swap(rem.coord,TMP2.coord); + continue; + } + TMP1.coord.clear(); + TMP2.coord.clear(); + tdeg_t resshift=pt->u-res[G[i]].coord.front().u; + if (env && env->moduloon){ + gen ab=a; + if (b!=1) + ab=a*invmod(b,env->modulo); + ab=smod(ab,env->modulo); + smallshift(res[G[i]].coord,resshift,TMP1.coord); + if (ab!=1) + smallmult(ab,TMP1,env->modulo); + sub(rem,TMP1,TMP2,env); + } + else { + // -b*rem+a*shift(res[G[i]]) + simplify(a,b); + if (b==-1){ + b=-b; + a=-a; + } + gen c=-b; + if (a.type==_ZINT && c.type==_ZINT && !is_one(a) && !is_one(b)){ + linear_combination(c,rem,0,a,res[G[i]],&resshift,TMP2,0); + lambda=c*lambda; + } + else { + smallshift(res[G[i]].coord,resshift,TMP1.coord); + if (!is_one(a)) + inplace_mult(a,TMP1.coord); + if (!is_one(b)){ + inplace_mult(b,rem.coord); + lambda=b*lambda; + } + sub(rem,TMP1,TMP2,0); + } + //if (count % 6==5) inplace_ppz(TMP2,true,true); // quick gcd check + } + swap(rem.coord,TMP2.coord); + } + if (env && env->moduloon){ + // if (small0) swap(rem.coord,TMP1.coord); + if (!rem.coord.empty() && rem.coord.front().g!=1) + smallmult(invmod(rem.coord.front().g,env->modulo),rem.coord,rem.coord,env->modulo.val); + return; + } + gen g=inplace_ppz(rem); + lambda=lambda/g; + if (debug_infolevel>2){ + if (rem.coord.empty()) + CERR << "0 reduction" << '\n'; + if (g.type==_ZINT && mpz_sizeinbase(*g._ZINTptr,2)>16) + CERR << "ppz size was " << mpz_sizeinbase(*g._ZINTptr,2) << '\n'; + } + } + + template + void reduce(const poly8 & p,const vectpoly8 & res,const vector & G,unsigned excluded,vectpoly8 & quo,poly8 & rem,poly8 & TMP1, poly8 & TMP2,environment * env,vector * Gusedptr=0){ + gen lambda; + reduce(p,res,G,excluded,quo,rem,TMP1,TMP2,lambda,env,Gusedptr); + } + + template + void reduce1small(poly8 & p,const poly8 & q,poly8 & TMP1, poly8 & TMP2,environment * env){ + if (p.coord.empty()) + return ; + typename std::vector< T_unsigned >::const_iterator pt,ptend; + unsigned rempos=0; + TMP1.coord.clear(); + const tdeg_t & u = q.coord.front().u; + const gen g=q.coord.front().g; + for (unsigned count=0;;++count){ + ptend=p.coord.end(); + // this branch search first in all leading coeff of G for a monomial + // <= to the current rem monomial + pt=p.coord.begin()+rempos; + if (pt>=ptend) + break; + if (!tdeg_t_all_greater(pt->u,u,p.order)){ + ++rempos; + // TMP1.coord.push_back(*pt); + continue; + } + smallmultsub(p,0,smod(pt->g*invmod(g,env->modulo),env->modulo).val,q,pt->u-u,TMP2,env->modulo.val); + // smallmultsub(p,rempos,smod(a*invmod(b,env->modulo),env->modulo).val,q,pt->u-u,TMP2,env->modulo.val); + // rempos=0; // since we have removed the beginning of rem (copied in TMP1) + swap(p.coord,TMP2.coord); + } + // if (small0) swap(p.coord,TMP1.coord); + if (env && env->moduloon && !p.coord.empty() && p.coord.front().g!=1) + smallmult(invmod(p.coord.front().g,env->modulo),p.coord,p.coord,env->modulo.val); + } + + // reduce with respect to itself the elements of res with index in G + template + void reduce(vectpoly8 & res,vector G,environment * env){ + if (res.empty() || G.empty()) + return; + poly8 pred(res.front().order,res.front().dim), + TMP1(res.front().order,res.front().dim), + TMP2(res.front().order,res.front().dim); + vectpoly8 q; + // reduce res + for (unsigned i=0;i & p=res[i]; + reduce(p,res,G,i,q,pred,TMP1,TMP2,env); + swap(res[i].coord,pred.coord); + pred.sugar=res[i].sugar; + } + } + + template + void spoly(const poly8 & p,const poly8 & q,poly8 & res,poly8 & TMP1, environment * env){ + if (p.coord.empty()){ + res=q; + return ; + } + if (q.coord.empty()){ + res= p; + return; + } + const tdeg_t & pi = p.coord.front().u; + const tdeg_t & qi = q.coord.front().u; + tdeg_t lcm; + index_lcm(pi,qi,lcm,p.order); + tdeg_t pshift=lcm-pi; + unsigned sugarshift=pshift.total_degree(p.order); + // adjust sugar for res + res.sugar=p.sugar+sugarshift; + // CERR << "spoly " << res.sugar << " " << pi << qi << '\n'; + gen a=p.coord.front().g,b=q.coord.front().g; + simplify3(a,b); + if (debug_infolevel>2) + CERR << "spoly " << a << " " << b << '\n'; + if (a.type==_ZINT && b.type==_ZINT){ + tdeg_t u=lcm-pi,v=lcm-qi; + linear_combination(b,p,&u,a,q,&v,res,env); + } + else { + poly8 tmp1(p),tmp2(q); + smallshift(tmp1.coord,lcm-pi,tmp1.coord); + smallmult(b,tmp1.coord,tmp1.coord); + smallshift(tmp2.coord,lcm-qi,tmp2.coord); + smallmult(a,tmp2.coord,tmp2.coord); + sub(tmp1,tmp2,res,env); + } + a=inplace_ppz(res); + if (debug_infolevel>2) + CERR << "spoly ppz " << a << '\n'; + } + + template + void gbasis_update(vector & G,vector< paire > & B,vectpoly8 & res,unsigned pos,poly8 & TMP1,poly8 & TMP2,vectpoly8 & vtmp,environment * env){ + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin gbasis update " << '\n'; + const poly8 & h = res[pos]; + order_t order=h.order; + vector C; + C.reserve(G.size()); + const tdeg_t & h0=h.coord.front().u; + tdeg_t tmp1,tmp2; + // C is used to construct new pairs + // create pairs with h and elements g of G, then remove + // -> if g leading monomial is prime with h, remove the pair + // -> if g leading monomial is not disjoint from h leading monomial + // keep it only if lcm of leading monomial is not divisible by another one + for (unsigned i=0;ij) + break; + } + } // end for j + if (j==G.size()) + C.push_back(G[i]); + } + vector< paire > B1; + B1.reserve(B.size()+C.size()); + for (unsigned i=0;i= leading monomial of h + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin Groebner interreduce " << '\n'; + C.clear(); + C.reserve(G.size()); + vector hG(1,pos); + bool small0=env && env->moduloon && env->modulo.type==_INT_ && env->modulo.val; + for (unsigned i=0;i1) + CERR << CLOCK()*1e-6 << " end Groebner interreduce " << '\n'; + C.push_back(pos); + swap(C,G); + } + + template + bool in_gbasis(vectpoly8 & res,vector & G,environment * env,bool sugar){ + poly8 TMP1(res.front().order,res.front().dim),TMP2(res.front().order,res.front().dim); + vectpoly8 vtmp; + vector< paire > B; + order_t order=res.front().order; + //if (order==_PLEX_ORDER) + sugar=false; // otherwise cyclic6 fails (bus error), don't know why + for (unsigned l=0;l1) + CERR << CLOCK()*1e-6 << " number of pairs: " << B.size() << ", base size: " << G.size() << '\n'; + // find smallest lcm pair in B + tdeg_t small0,cur; + unsigned smallpos,smallsugar=0,cursugar=0; + for (smallpos=0;smallpos cursugar; + else + doswap=tdeg_t_strictly_greater(small0,cur,order); + } + if (doswap){ + // CERR << "swap " << cursugar << " " << res[B[i].first].coord.front().u << " " << res[B[i].second].coord.front().u << '\n'; + swap(small0,cur); // small0=cur; + swap(smallsugar,cursugar); + smallpos=i; + } + } + paire bk=B[smallpos]; + if (debug_infolevel>1 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0)) + CERR << CLOCK()*1e-6 << " reducing pair with 1 element not in basis " << bk << '\n'; + B.erase(B.begin()+smallpos); + poly8 h(res.front().order,res.front().dim); + spoly(res[bk.first],res[bk.second],h,TMP1,env); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " reduce begin, pair " << bk << " remainder size " << h.coord.size() << '\n'; + reduce(h,res,G,-1,vtmp,h,TMP1,TMP2,env); + if (debug_infolevel>1){ + if (debug_infolevel>3){ CERR << h << '\n'; } + CERR << CLOCK()*1e-6 << " reduce end, remainder size " << h.coord.size() << '\n'; + } + if (!h.coord.empty()){ + res.push_back(h); + gbasis_update(G,B,res,unsigned(res.size()-1),TMP1,TMP2,vtmp,env); + if (debug_infolevel>2) + CERR << CLOCK()*1e-6 << " basis indexes " << G << " pairs indexes " << B << '\n'; + } + } + return true; + } + + longlong invmod(longlong a,longlong b){ + if (a==1 || a==-1 || a==1-b) + return a; + longlong aa(1),ab(0),ar(0); +#ifdef VISUALC + longlong q,r; + while (b){ + q=a/b; + r=a-q*b; + ar=aa-q*ab; + a=b; + b=r; + aa=ab; + ab=ar; + } +#else + lldiv_t qr; + while (b){ + qr=lldiv(a,b); + ar=aa-qr.quot*ab; + a=b; + b=qr.rem; + aa=ab; + ab=ar; + } +#endif + if (a==1) + return aa; + if (a!=-1){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Not invertible")); +#endif + return 0; + } + return -aa; + } + + longlong smod(longlong a,longlong b){ + longlong r=a%b; + if (r>b/2) + r -= b; + else { + if (r<=-b/2) + r += b; + } + return r; + } + +#ifdef x86_64 + // typedef longlong modint; + // typedef int128_t modint2; + longlong smod(int128_t a,longlong b){ + longlong r=a%b; + if (r>b/2) + r -= b; + else { + if (r<=-b/2) + r += b; + } + return r; + } +#endif + + + template + struct polymod { + std::vector< T_unsigned > coord; + // lex order is implemented using tdeg_t as a list of degrees + // tdeg uses total degree 1st then partial degree in lex order, max 7 vars + // revlex uses total degree 1st then opposite of partial degree in reverse ordre, max 7 vars + order_t order; // _PLEX_ORDER, _REVLEX_ORDER or _TDEG_ORDER or _7VAR_ORDER or _11VAR_ORDER + short int dim; + unsigned sugar; + int fromleft,fromright,age; + double logz; // trace origin as a s-polynomial + void dbgprint() const; + void swap(polymod & q){ + order_t tmp; + tmp=order; order=q.order; q.order=tmp; + int tmp2=dim; dim=q.dim; q.dim=tmp2; + tmp2=sugar; sugar=q.sugar; q.sugar=tmp2; + coord.swap(q.coord); + tmp2=fromleft; fromleft=q.fromleft; q.fromleft=tmp2; + tmp2=fromright; fromright=q.fromright; q.fromright=tmp2; + tmp2=age; age=q.age; q.age=tmp2; + double tmp3=logz; logz=q.logz; q.logz=tmp3; + } + polymod():dim(0),fromleft(-1),fromright(-1),logz(1) {order_t tmp={_PLEX_ORDER,0}; order=tmp;} + polymod(order_t o_,int dim_): dim(dim_),fromleft(-1),fromright(-1),logz(1) {order=o_; order.dim=dim_;} + polymod(const polynome & p,order_t o_,modint_t m):fromleft(-1),fromright(-1),logz(1){ + order=o_; + dim=p.dim; + order.dim=dim; + if (order.o%4!=3){ + if (p.is_strictly_greater==i_lex_is_strictly_greater) + order.o=_PLEX_ORDER; + if (p.is_strictly_greater==i_total_revlex_is_strictly_greater) + order.o=_REVLEX_ORDER; + if (p.is_strictly_greater==i_total_lex_is_strictly_greater) + order.o=_TDEG_ORDER; + } + if (p.dim>GROEBNER_VARS-(order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER)) + CERR << "Number of variables is too large to be handled by giac"; + else { + if (!p.coord.empty()){ + coord.reserve(p.coord.size()); + for (unsigned i=0;i(n,tdeg_t(p.coord[i].index,order))); + } + sugar=coord.front().u.total_degree(order); + } + } + } + void get_polynome(polynome & p) const { + p.dim=dim; + switch (order.o){ + case _PLEX_ORDER: + p.is_strictly_greater=i_lex_is_strictly_greater; + break; + case _REVLEX_ORDER: + p.is_strictly_greater=i_total_revlex_is_strictly_greater; + break; + case _3VAR_ORDER: + p.is_strictly_greater=i_3var_is_strictly_greater; + break; + case _7VAR_ORDER: + p.is_strictly_greater=i_7var_is_strictly_greater; + break; + case _11VAR_ORDER: + p.is_strictly_greater=i_11var_is_strictly_greater; + break; + case _TDEG_ORDER: + p.is_strictly_greater=i_total_lex_is_strictly_greater; + break; + } + p.coord.clear(); + p.coord.reserve(coord.size()); + index_t idx(dim); + for (unsigned i=0;i(coord[i].g,idx)); + } + // if (order==_3VAR_ORDER || order==_7VAR_ORDER || order==_11VAR_ORDER) p.tsort(); + } + }; // end polymod + + template void convert(const polymod & src, polymod & target){ + typename std::vector< T_unsigned >::const_iterator it=src.coord.begin(),itend=src.coord.end(); + target.coord.clear(); target.coord.reserve(itend-it); + for (;it!=itend;++it){ + mod4int m4={it->g,it->g,it->g,it->g}; + target.coord.push_back(T_unsigned(m4,it->u)); + } + } + + template void convert(const polymod & src, polymod & target,int pos){ + target=src; + } + template void convert(const polymod & src, polymod & target,int pos){ + target.dim=src.dim; target.order=src.order; target.sugar=src.sugar; target.fromleft=src.fromleft; target.fromright=src.fromright; target.age=src.age; target.logz=src.logz; + typename std::vector< T_unsigned >::const_iterator it=src.coord.begin(),itend=src.coord.end(); + target.coord.clear(); target.coord.reserve(itend-it); + for (;it!=itend;++it){ + if (it->g.tab[pos]!=0) target.coord.push_back(T_unsigned(it->g.tab[pos],it->u)); + } + } + + template + void increase(vector &v){ + if (v.size()!=v.capacity()) + return; + vector w; + w.reserve(v.size()*2); + for (unsigned i=0;i + struct polymod_sort_t { + polymod_sort_t() {} + bool operator () (const polymod & p,const polymod & q) const { + if (q.coord.empty()) + return false; + if (p.coord.empty()) + return true; + if (p.coord.front().u==q.coord.front().u) + return false; + return tdeg_t_greater(q.coord.front().u,p.coord.front().u,p.order); // p.coord.front().u + inline modint_t makepositive(modint_t a,modint_t n){ + return a+((a>>31)&n); + // return a-(a>>31)*n; // return a<0?a+n:a; + } + + template + void smallmultmod(modint_t a,polymod & p,modint_t m,bool mkpositive=true){ +#if 1 // ndef GBASIS_4PRIMES + if (a==1 || a==create(1)-m) + return; +#endif + typename std::vector< T_unsigned >::iterator pt=p.coord.begin(),ptend=p.coord.end(); + if (mkpositive){ + for (;pt!=ptend;++pt){ + modint_t tmp=(extend(pt->g)*a)%m; + pt->g=makepositive(tmp,m); // if (tmp<0) tmp += m; pt->g=tmp; + } + } + else { + for (;pt!=ptend;++pt){ + modint_t tmp=(extend(pt->g)*a)%m; + pt->g=tmp; + } + } + } + + template + struct tdeg_t_sort_t { + order_t order; + tdeg_t_sort_t() {order_t tmp={_REVLEX_ORDER,0}; order=tmp;} + tdeg_t_sort_t(order_t o):order(o) {} + bool operator ()(const T_unsigned & a,const T_unsigned & b) const {return !tdeg_t_greater(b.u,a.u,order);} + bool operator ()(const T_unsigned & a,const T_unsigned & b) const {return !tdeg_t_greater(b.u,a.u,order);} + bool operator ()(const T_unsigned & a,const T_unsigned & b) const {return !tdeg_t_greater(b.u,a.u,order);} + bool operator ()(const tdeg_t & a,const tdeg_t & b) const {return !tdeg_t_greater(b,a,order);} + bool operator ()(const pair & a,const pair & b) const {return !tdeg_t_greater(b.second,a.second,order);} + }; + + template + void convert(const poly8 & p,polymod &q,modint_t env,bool unitarize=true){ +#if 0 + q.coord.reserve(p.coord.size()); + q.dim=p.dim; + q.order=p.order; + q.sugar=0; + for (unsigned i=0;i(g,p.coord[i].u)); + } +#else + q.coord.reserve(p.coord.size()); + q.dim=p.dim; + q.order=p.order; + q.age=q.sugar=0; + for (unsigned i=0;i(1); + else { + if (p.coord[i].g.type==_ZINT) + g=modulo(*p.coord[i].g._ZINTptr,env); + else + g=(p.coord[i].g.val)%env; + } + if (!is_zero(g)) + q.coord.push_back(T_unsigned(g,p.coord[i].u)); + } +#endif + if (!is_zero(env) && unitarize && !q.coord.empty()){ + q.sugar=q.coord.front().u.total_degree(p.order); +#if 1 // ndef GBASIS_4PRIMES + if (q.coord.front().g!=1) +#endif + smallmultmod(invmod(q.coord.front().g,env),q,env); + q.coord.front().g=create(1); + } + sort(q.coord.begin(),q.coord.end(),tdeg_t_sort_t(p.order)); + } + template + void convert(const polymod & p,poly8 &q,modint_t env){ + q.coord.resize(p.coord.size()); + q.dim=p.dim; + q.order=p.order; + for (unsigned i=0;i + bool operator == (const polymod & p,const polymod &q){ + if (p.coord.size()!=q.coord.size()) + return false; + for (unsigned i=0;i + nio::ios_base & operator << (nio::ios_base & os, const polymod & p) +#else + template + ostream & operator << (ostream & os, const polymod & p) +#endif + { + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + int t2; + if (it==itend) + return os << 0 ; + for (;it!=itend;){ + os << it->g ; +#ifndef GBASIS_NO_OUTPUT + if (it->u.vars64()){ + if (it->u.tdeg%2){ + degtype * i=(degtype *)(it->u.ui+1); + for (int j=0;ju.order_.dim;++j){ + t2=i[j]; + if (t2) + os << "*x"<< j << "^" << t2 ; + } + ++it; + if (it==itend) + break; + os << " + "; + continue; + } + } +#endif + short tab[GROEBNER_VARS+1]; + tab[GROEBNER_VARS]=0; + it->u.get_tab(tab,p.order); + switch (p.order.o){ + case _PLEX_ORDER: + for (int i=0;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2) + os << "*x"<< i << "^" << t2 ; + } + break; + case _TDEG_ORDER: + for (int i=1;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2==0) + continue; + if (t2) + os << "*x"<< i-1 << "^" << t2 ; + } + break; + case _REVLEX_ORDER: + for (int i=1;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; +#if GROEBNER_VARS==15 + case _3VAR_ORDER: + for (int i=1;i<=3;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 3-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=5;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 7+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; + case _7VAR_ORDER: + for (int i=1;i<=7;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 7-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=9;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 11+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; + case _11VAR_ORDER: + for (int i=1;i<=11;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 11-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=13;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 15+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; +#endif + } + ++it; + if (it==itend) + break; + os << " + "; + } + return os; + } + + template + void polymod::dbgprint() const { + CERR << *this << '\n'; + } + + template + class vectpolymod:public vector< polymod >{ + public: + void dbgprint() const { CERR << *this << '\n'; } + }; + + template void convert(const vectpolymod & src, vectpolymod & target,int pos){ + target.resize(src.size()); + for (int i=0;i + void vectpoly_2_vectpolymod(const vectpoly & v,order_t order,vectpolymod & v8,modint_t m){ + v8.clear(); + v8.reserve(v.size()); + for (unsigned i=0;i(v[i],order,m)); + v8.back().order=order; + } + } + + template + void convert(const vectpoly8 & v,vectpolymod & w,modint_t env,int n=0,bool unitarize=true){ + if (n==0) + n=v.size(); + if (w.size() + void convert(const vectpolymod & v,vectpoly8 & w,modint_t env){ + w.resize(v.size()); + for (unsigned i=0;i + void convert(const vectpolymod & v,const vector & G,vectpoly8 & w,modint_t env){ + w.resize(v.size()); + for (unsigned i=0;i + void in_heap_reducemod(const polymod & f,const vectpolymod & g,const vector & G,unsigned excluded,vectpolymod & q,polymod & rem,polymod * R,modint env){ + // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]] + // first implementation: use quotxsient heap for all quotient/divisor + // do not use heap chain + // ref Monaghan Pearce if g.size()==1 + // R is the list of all monomials + if (R){ + R->dim=f.dim; R->order=f.order; + R->coord.clear(); + } + if (&rem==&f){ + polymod TMP; + in_heap_reducemod(f,g,G,excluded,q,TMP,R,env); + swap(rem.coord,TMP.coord); + if (debug_infolevel>1000) + g.dbgprint(); // instantiate dbgprint() + return; + } + rem.coord.clear(); + if (f.coord.empty()) + return ; + if (q.size() > H; + compare_heap_t key(f.order); + H.reserve(guess); + vector invlcg(G.size()); + for (unsigned i=0;icoord.push_back(T_unsigned(1,m)); + // extract from heap all terms having m as monomials, subtract from c + while (!H.empty() && H.front().u==m){ + std::pop_heap(H.begin(),H.end(),key); + heap_t & current=H.back(); // was root node of the heap + const polymod & gcurrent = g[G[current.i]]; + if (!R){ +#ifdef x86_64 + C -= extend(q[current.i].coord[current.qi].g) * gcurrent.coord[current.gj].g; +#else + C = (C-extend(q[current.i].coord[current.qi].g) * gcurrent.coord[current.gj].g) % env; +#endif + } + if (current.gj(c,m)); // add c*m to remainder + continue; + } + finish=true; +#if 0 + for (i=G.size()-1;i!=-1;--i){ + if (i==excluded || g[G[i]].coord.empty()) + continue; + if (tdeg_t_greater(m,g[G[i]].coord.front().u,f.order)){ + finish=false; + if (tdeg_t_all_greater(m,g[G[i]].coord.front().u,f.order)) + break; + } + } + if (i==-1){ + rem.coord.push_back(T_unsigned(c,m)); // add c*m to remainder + continue; + } +#else + for (i=0;i(c,m)); // add c*m to remainder + continue; + } +#endif + // add c*m/leading monomial of g[G[i]] to q[i] + tdeg_t monom=m-g[G[i]].coord.front().u; + if (!R){ + if (invlcg[i]!=1){ + if (invlcg[i]==-1) + c=-c; + else + c=(extend(c)*invlcg[i]) % env; + } + } + q[i].coord.push_back(T_unsigned(c,monom)); + // push in heap + if (g[G[i]].coord.size()>1){ + heap_t current={i,unsigned(q[i].coord.size())-1,1,g[G[i]].coord[1].u+monom}; + H.push_back(current); + push_heap(H.begin(),H.end(),key); + } + } // end main heap pseudo-division loop + } + + template + void heap_reducemod(const polymod & f,const vectpolymod & g,const vector & G,unsigned excluded,vectpolymod & q,polymod & rem,modint_t env){ + in_heap_reducemod(f,g,G,excluded,q,rem,0,env); + // end up by multiplying rem by s (so that everything is integer) + if (debug_infolevel>2){ + for (unsigned i=0;i + void symbolic_preprocess(const polymod & f,const vectpolymod & g,const vector & G,unsigned excluded,vectpolymod & q,polymod & rem,polymod * R){ + // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]] + // first implementation: use quotient heap for all quotient/divisor + // do not use heap chain + // ref Monaghan Pearce if g.size()==1 + // R is the list of all monomials + if (R){ + R->dim=f.dim; R->order=f.order; + R->coord.clear(); + } + rem.coord.clear(); + if (f.coord.empty()) + return ; + if (q.size() > H_; + vector H; + H_.reserve(guess); + H.reserve(guess); + heap_t_compare keyheap(H_,f.order); + unsigned k=0,i; // k=position in f + tdeg_t m; + bool finish=false; + while (!H.empty() || kcoord.push_back(T_unsigned(1,m)); + // extract from heap all terms having m as monomials, subtract from c + while (!H.empty() && H_[H.front()].u==m){ + std::pop_heap(H.begin(),H.end(),keyheap); + heap_t & current=H_[H.back()]; // was root node of the heap + const polymod & gcurrent = g[G[current.i]]; + if (current.gj(1,m)); // add to remainder + continue; + } + finish=true; + for (i=0;i > & gGicoord=g[G[i]].coord; + if (i==excluded || gGicoord.empty()) + continue; + if (tdeg_t_greater(m,gGicoord.front().u,f.order)){ + finish=false; + if (tdeg_t_all_greater(m,gGicoord.front().u,f.order)) + break; + } + } + if (i==G.size()){ + rem.coord.push_back(T_unsigned(1,m)); // add to remainder + continue; + } + // add m/leading monomial of g[G[i]] to q[i] + tdeg_t monom=m-g[G[i]].coord.front().u; + q[i].coord.push_back(T_unsigned(1,monom)); + // push in heap + if (g[G[i]].coord.size()>1){ + heap_t current={i,unsigned(q[i].coord.size())-1,1,g[G[i]].coord[1].u+monom}; + H.push_back(unsigned(H_.size())); + H_.push_back(current); + keyheap.ptr=&H_.front(); + std::push_heap(H.begin(),H.end(),keyheap); + } + } // end main heap pseudo-division loop + // CERR << H_.size() << '\n'; + } + + // p - a*q shifted mod m -> r + template + void smallmultsubmodshift(const polymod & p,unsigned pos,modint_t a,const polymod & q,const tdeg_t & shift,polymod & r,modint_t m){ + r.coord.clear(); + r.coord.reserve(p.coord.size()+q.coord.size()); + typename vector< T_unsigned >::const_iterator it0=p.coord.begin(),it=it0+pos,itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end(); + // for (;it0!=it;++it0){ r.coord.push_back(*it0); } + tdeg_t v=shift+shift; // new memory slot + int dim=p.dim; + for (;jt!=jtend;++jt){ + //CERR << "dbg " << jt->u << " " << shift << "\n"; + add(jt->u,shift,v,dim); + for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){ + r.coord.push_back(*it); + } + if (it!=itend && it->u==v){ + modint_t tmp=(it->g-extend(a)*jt->g)%m; + if (!is_zero(tmp)) + r.coord.push_back(T_unsigned(tmp,v)); + ++it; + } + else { + modint_t tmp=(-extend(a)*jt->g)%m; + r.coord.push_back(T_unsigned(tmp,v)); + } + } + for (;it!=itend;++it){ + r.coord.push_back(*it); + } + } + +#ifdef HASH_MAP_NAMESPACE + // p -= a*q shifted mod m -> r + template + void mapmultsubmodshift(HASH_MAP_NAMESPACE::hash_map & p,modint_t a,const polymod & q,const tdeg_t & shift,modint_t m){ + typename vector< T_unsigned >::const_iterator jt=q.coord.begin(),jtend=q.coord.end(); + // for (;it0!=it;++it0){ r.coord.push_back(*it0); } + tdeg_t v=shift+shift; // new memory slot + int dim=q.dim; + for (;jt!=jtend;++jt){ + //CERR << "dbg " << jt->u << " " << shift << "\n"; + add(jt->u,shift,v,dim); + typename HASH_MAP_NAMESPACE::hash_map::iterator it=p.find(v),itend=p.end(); + if (it!=itend){ + modint_t tmp=(it->second-extend(a)*jt->g)%m; + it->second=tmp; + } + else { + modint_t tmp=(-extend(a)*jt->g)%m; + p[v]=tmp; + } + } + } + + template + void poly2map(const polymod & p,HASH_MAP_NAMESPACE::hash_map & m){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it) + m[it->u]=it->g; + } + + template + void map2poly(const HASH_MAP_NAMESPACE::hash_map & m,polymod & p){ + p.coord.clear(); + typename HASH_MAP_NAMESPACE::hash_map::const_iterator it=m.begin(),itend=m.end(); + for (;it!=itend;++it){ + if (!is_zero(it->second)) + p.coord.push_back(T_unsigned(it->second,it->first)); + } + sort(p.coord.begin(),p.coord.end(),tdeg_t_sort_t(p.order)); + } + +#endif + + // p -= a*q shifted mod m -> r + template + void mapmultsubmodshift(map > & p,modint_t a,const polymod & q,const tdeg_t & shift,modint_t m){ + typename vector< T_unsigned >::const_iterator jt=q.coord.begin(),jtend=q.coord.end(); + // for (;it0!=it;++it0){ r.coord.push_back(*it0); } + tdeg_t v=shift+shift; // new memory slot + int dim=q.dim; + for (;jt!=jtend;++jt){ + //CERR << "dbg " << jt->u << " " << shift << "\n"; + add(jt->u,shift,v,dim); + typename map >::iterator it=p.find(v),itend=p.end(); + if (it!=itend){ + modint_t tmp=(it->second-extend(a)*jt->g)%m; + it->second=tmp; + } + else { + modint_t tmp=(-extend(a)*jt->g)%m; + p[v]=tmp; + } + } + } + + template + void poly2map(const polymod & p,map > & m){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it) + m[it->u]=it->g; + } + + template + void map2poly(const map > & m,polymod & p){ + p.coord.clear(); + typename map >::const_iterator it=m.begin(),itend=m.end(); + for (;it!=itend;++it){ + if (!is_zero(it->second)) + p.coord.push_back(T_unsigned(it->second,it->first)); + } + } + + // p - a*q mod m -> r + template + void smallmultsubmod(const polymod & p,modint_t a,const polymod & q,polymod & r,modint_t m){ + r.coord.clear(); + r.coord.reserve(p.coord.size()+q.coord.size()); + typename vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end(); + for (;jt!=jtend;++jt){ + const tdeg_t & v=jt->u; + for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){ + r.coord.push_back(*it); + } + if (it!=itend && it->u==v){ + modint_t tmp=(it->g-extend(a)*jt->g)%m; + if (!is_zero(tmp)) + r.coord.push_back(T_unsigned(tmp,v)); + ++it; + } + else { + modint_t tmp=(-extend(a)*jt->g)%m; + r.coord.push_back(T_unsigned(tmp,v)); + } + } + for (;it!=itend;++it){ + r.coord.push_back(*it); + } + } + + // p + q -> r + template + void smallmerge(polymod & p,polymod & q,polymod & r){ + if (p.coord.empty()){ + swap(q.coord,r.coord); + return; + } + if (q.coord.empty()){ + swap(p.coord,r.coord); + return; + } + r.coord.clear(); + r.coord.reserve(p.coord.size()+q.coord.size()); + typename vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end(); + for (;jt!=jtend;++jt){ + const tdeg_t & v=jt->u; + for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){ + r.coord.push_back(*it); + } + r.coord.push_back(*jt); + } + for (;it!=itend;++it){ + r.coord.push_back(*it); + } + } + + template + void smalladd(polymod & p,polymod & q,polymod & r,modint_t env){ + if (p.coord.empty()){ + q.coord.swap(r.coord); + return; + } + if (q.coord.empty()){ + p.coord.swap(r.coord); + return; + } + r.coord.clear(); + r.coord.reserve(p.coord.size()+q.coord.size()); + typename vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=q.coord.begin(),jtend=q.coord.end(); + for (;jt!=jtend;++jt){ + const tdeg_t & v=jt->u; + for (;it!=itend && tdeg_t_strictly_greater(it->u,v,p.order);++it){ + r.coord.push_back(*it); + } + if (it!=itend && it->u==jt->u){ + modint_t s=(it->g+extend(jt->g))%env; + if (!is_zero(s)) + r.coord.push_back(T_unsigned(s,it->u)); + ++it; + } + else + r.coord.push_back(*jt); + } + for (;it!=itend;++it){ + r.coord.push_back(*it); + } + } + + template + void reducemod(const polymod & p,const vectpolymod & res,const vector & G,unsigned excluded,polymod & rem,modint_t env,bool topreduceonly=false){ + if (&p!=&rem) + rem=p; + if (p.coord.empty()) + return ; + polymod TMP2(p.order,p.dim); + unsigned i,rempos=0; + for (unsigned count=0;;++count){ + // this branch search first in all leading coeff of G for a monomial + // <= to the current rem monomial + typename std::vector< T_unsigned >::const_iterator pt=rem.coord.begin()+rempos; + if (pt>=rem.coord.end()) + break; + for (i=0;iu,res[G[i]].coord.front().u,p.order)) + break; + } + if (i==G.size()){ // no leading coeff of G is smaller than the current coeff of rem + ++rempos; + if (topreduceonly) + break; + // if (small0) TMP1.coord.push_back(*pt); + continue; + } + modint_t a(pt->g),b(res[G[i]].coord.front().g); + if (pt->u==res[G[i]].coord.front().u){ + smallmultsubmod(rem,smod(extend(a)*invmod(b,env),env),res[G[i]],TMP2,env); + // Gpos=i; // assumes basis element in G are sorted wrt > + } + else + smallmultsubmodshift(rem,0,smod(extend(a)*invmod(b,env),env),res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env); + swap(rem.coord,TMP2.coord); + } + if (!rem.coord.empty() +#if 1 // ndef GBASIS_4PRIMES + && rem.coord.front().g!=1 +#endif + ){ + smallmultmod(invmod(rem.coord.front().g,env),rem,env); + rem.coord.front().g=create(1); + } + } + +#if 0 + // reduce with respect to itself the elements of res with index in G + template + void reducemod(vectpolymod & res,vector G,modint env){ + if (res.empty() || G.empty()) + return; + polymod pred(res.front().order,res.front().dim), + TMP2(res.front().order,res.front().dim); + vectpolymod q; + // reduce res + for (unsigned i=0;i & p=res[i]; + reducemod(p,res,G,i,q,pred,TMP2,env); + swap(res[i].coord,pred.coord); + pred.sugar=res[i].sugar; + } + } +#endif + + template + modint_t spolymod(const polymod & p,const polymod & q,polymod & res,polymod & TMP1,modint_t env){ + if (p.coord.empty()){ + res=q; + return create(1); + } + if (q.coord.empty()){ + res= p; + return create(1); + } + const tdeg_t & pi = p.coord.front().u; + const tdeg_t & qi = q.coord.front().u; + tdeg_t lcm; + index_lcm(pi,qi,lcm,p.order); + //polymod TMP1(p); + TMP1=p; + // polymod TMP2(q); + const polymod &TMP2=q; + modint_t a=p.coord.front().g,b=q.coord.front().g; + tdeg_t pshift=lcm-pi; + unsigned sugarshift=pshift.total_degree(p.order); + // adjust sugar/logz for res + res.sugar=p.sugar+sugarshift; + res.logz=p.logz+q.logz; + // CERR << "spoly mod " << res.sugar << " " << pi << qi << '\n'; + if (p.order.o==_PLEX_ORDER || sugarshift!=0) + smallshift(TMP1.coord,pshift,TMP1.coord); + // smallmultmod(b,TMP1,env); + if (lcm==qi) + smallmultsubmod(TMP1,smod(extend(a)*invmod(b,env),env),TMP2,res,env); + else + smallmultsubmodshift(TMP1,0,smod(extend(a)*invmod(b,env),env),TMP2,lcm-qi,res,env); + modint_t d=create(1); + if (!res.coord.empty() +#if 1 // ndef GBASIS_4PRIMES + && res.coord.front().g!=1 +#endif + ){ + d=invmod(res.coord.front().g,env); + smallmultmod(d,res,env); + res.coord.front().g=create(1); + } + if (debug_infolevel>2) + CERR << "spolymod " << res << '\n'; + return d; + } + + template + void reduce1smallmod(polymod & p,const polymod & q,polymod & TMP2,modint_t env){ + if (p.coord.empty()) + return ; + unsigned rempos=0; + const tdeg_t & u = q.coord.front().u; + const modint_t invg=invmod(q.coord.front().g,env); + for (unsigned count=0;;++count){ + // this branch search first in all leading coeff of G for a monomial + // <= to the current rem monomial + typename std::vector< T_unsigned >::const_iterator pt=p.coord.begin()+rempos; + if (pt>=p.coord.end()) + break; + if (pt->u==u){ + smallmultsubmodshift(p,0,smod(extend(pt->g)*invg,env),q,pt->u-u,TMP2,env); + swap(p.coord,TMP2.coord); + break; + } + if (!tdeg_t_all_greater(pt->u,u,p.order)){ + ++rempos; + // TMP1.coord.push_back(*pt); + continue; + } + smallmultsubmodshift(p,0,smod(extend(pt->g)*invg,env),q,pt->u-u,TMP2,env); + // smallmultsubmodshift(p,rempos,smod(extend(pt->g)*invmod(g,env),env),q,pt->u-u,TMP2,env); + rempos=0; + swap(p.coord,TMP2.coord); + } + // if (small0) swap(p.coord,TMP1.coord); + if (!p.coord.empty() && p.coord.front().g!=1){ + smallmultmod(invmod(p.coord.front().g,env),p,env); + p.coord.front().g=create(1); + } + } + +#define GIAC_GBASIS_PERMUTATION1 +#define GIAC_GBASIS_PERMUTATION2 + template + struct zsymb_data { + unsigned pos; + tdeg_t deg; + order_t o; + unsigned terms; + int age; + double coeffs; + }; + +#ifdef GIAC_GBASIS_PERMUTATION2 + template + bool tri(const zsymb_data & z1,const zsymb_data & z2){ + int d1=z1.deg.total_degree(z1.o),d2=z2.deg.total_degree(z2.o); + // beware that ordering must be stable across successives modular runs + //if (z1.coeffs*d1!=z2.coeffs*d2) return z1.coeffs*d1 + bool operator < (const zsymb_data & z1,const zsymb_data & z2){ + // reductor choice: less terms is better + // but small degree gives a reductor sooner + // e.g. less terms is faster for botana* but slower for cyclic* + // if (z1.terms!=z2.terms){ return z1.termsZ1; + //double Z1=z1.terms*double(z1.terms)/d1; double Z2=z2.terms*double(z2.terms)/d2; if (Z1!=Z2) return Z1Z1; + //double Z1=double(z1.terms)/d1; double Z2=double(z2.terms)/d2; if (Z1!=Z2) return Z2>Z1; + //double Z1=double(z1.terms)*d1; double Z2=double(z2.terms)*d2; if (Z1!=Z2) return Z2>Z1; + if (z1.terms!=z2.terms) return z2.terms>z1.terms; + if (z1.deg!=z2.deg) + return tdeg_t_greater(z1.deg,z2.deg,z1.o)!=0; + if (z1.pos!=z2.pos) + return z2.pos>z1.pos; + return false; + } + + // rewrite sum(A[i]*F[i]) mod env. By decreasing degree of A[i]*F[i] + // if a monomial of A[i] is divisible by the leading monomial of F[j] + // and A[j]*F[j] has a monomial of same degree + // replace A[i] by A[i]-quotient*F[j] and A[j] by A[j]+quotient*F[i] + // this will modify only monomials with smaller degree + template + void reduceAF(vectpolymod & A,const vectpolymod & F,modint_t env,order_t order){ + return; // no visible effect + polymod tmp; + int s=F.size(); + vector lF; + for (unsigned i=0;i startpos(s); + while (1){ + tdeg_t aifideg; + bool prev=false; + vector pos; + // find degree + for (int i=0;i + double sumdegcoeffs(const vectpolymod & V,const order_t & o){ + double res=0; + for (size_t j=0;j + double sumtermscoeffs(const vectpolymod & V){ + double res=0; + for (size_t j=0;j list l=lift(i,1); + red: redLiftstd + posInT: posInT_EcartpLength + posInL: posInL15 + enterS: enterSBba + initEcart: initEcartBBA + initEcartPair: initEcartPairMora + homog=0, LazyDegree=1, LazyPass=2, ak=15, + honey=1, sugarCrit=0, Gebauer=0, noTailReduction=0, use_buckets=1 + chainCrit: chainCritNormal + posInLDependsOnLength=0 + //options: redTail redThrough intStrategy redefine usage prompt 53 55 + LDeg: pLDegb / pLDegb + currRing->pFDeg: ? (7f04a96862a0) + syzring:1, syzComp(strat):1 limit:1 + +Here: + T: is the set of reductors, sorted by length(number of monomials), then Ecart + L: the set of pairs, sorted by deg(leading term)+Ecart, then by monomial order + S: the Grรถbner basis (subset of T) + redLiftstd: the reduction of S-Polynomial s: + chosen first element p from T such that divides + +Bis hierhin ist "Polynom" das eigentliche Polynom und (als hintere +Terme) die Herleitung (das geht insbesonderer in die Laenge mit ein). +Fuer die Reduktion wird es jedoch wieder geteilt und mit den +"Herleitungsteil" nur eine "lazy computation" durchgefuehrt. +Nur bei Erfolg (d.h. der Anfang redziert nicht zu 0) +wird dieese ausgefuehrt (siehe redLiftstd) + +Until this point "Polynom" is the actual polynomial and (as terms behind) +the coefficients (this is very important for the length). +For reduction it will be, however, divided again, and with the "coefficients part" +there will be only a "lazy computation" done. +This will be performed only in case of success (i.e. the leading will be reduced not to 0) +(see redLiftstd). + */ + template + void reducesmallmod(polymod & rem,const vectpolymod & res,const vector & G,unsigned excluded,modint_t env,polymod & TMP1,bool normalize,int start_index=0,bool topreduceonly=false,vectpolymod*remcoeffsptr=0,vector< vectpolymod > * coeffsmodptr=0,int strategy=0){ + vector< polymod > addtoremcoeffs(remcoeffsptr?remcoeffsptr->size():0); + bool usemap=strategy/10000000; +#ifdef HASHMAP_NAMESPACE + vector< map> > mapremcoeffs; + if (remcoeffsptr && usemap){ + HASHMAP_NAMESPACE::hash_map m(obj); + mapremcoeffs=vector< HASHMAP_NAMESPACE::hash_map >(remcoeffsptr->size(),m); + for (size_t k=0;ksize();++k){ + poly2map((*remcoeffsptr)[k],mapremcoeffs[k]); + } + } +#else + vector< map > > mapremcoeffs; + if (remcoeffsptr && usemap){ + tdeg_t_sort_t obj(rem.order); + map > m(obj); + mapremcoeffs=vector< map > >(remcoeffsptr->size(),m); + for (size_t k=0;ksize();++k){ + poly2map((*remcoeffsptr)[k],mapremcoeffs[k]); + } + } +#endif + if (strategy>=0){ + strategy /= 1000; + strategy %= 1000; + } + if (debug_infolevel>1000){ + rem.dbgprint(); + if (!rem.coord.empty()) rem.coord.front().u.dbgprint(); + } + typename std::vector< T_unsigned >::const_iterator pt,ptend; + unsigned i,rempos=0; + TMP1.coord.clear(); + unsigned Gs=unsigned(G.size()); + const order_t o=rem.order; + int Gstart_index=0; + // starting at excluded may fail because the batch of new basis element created + // by f4mod is reduced with respect to the previous batches but not necessarily + // with respect to itself + if (start_index && excluded=0;--i){ + int Gi=G[i]; + if (Gi<=start_index){ + Gstart_index=i; + break; + } + } + } +#ifdef GIAC_GBASIS_PERMUTATION2 + if (excluded > zsGi(Gs); + for (unsigned i=0;i & cur=res[Gi]; + zsymb_data tmp={(unsigned)Gi,cur.coord.empty()?0:cur.coord.front().u,o,(unsigned)cur.coord.size(),0,0.0}; + if (coeffsmodptr && strategy>=0){ + double D=sumdegcoeffs((*coeffsmodptr)[Gi],o),T=sumtermscoeffs((*coeffsmodptr)[Gi]),N=(*coeffsmodptr)[Gi].size(),d=cur.coord.front().u.total_degree(o),t=cur.coord.size(); + if (strategy==1 || strategy==0) + tmp.coeffs = D; + else if (strategy==11) + tmp.coeffs = T*t*double(d); + else if (strategy==2) + tmp.coeffs = D*T; + else if (strategy==3) + tmp.coeffs = (N*d+D)*(N*t+T); + else if (strategy==4) + tmp.coeffs = N*d+D; + else if (strategy==5) + tmp.coeffs = N*t+T; + else if (strategy==6) + tmp.coeffs = T; + else if (strategy==7) + tmp.coeffs = D*t; + else if (strategy==8) + tmp.coeffs = D*(N*t+T); + else if (strategy==9) + tmp.coeffs = D*t*T; + else if (strategy==10) + tmp.coeffs = D*d*t*T; + } + zsGi[i]=tmp; + } + sort(zsGi.begin(),zsGi.end(),tri); //reverse(zsGi.begin(),zsGi.end()); +#else + const tdeg_t ** resGi=(const tdeg_t **) malloc(Gs*sizeof(tdeg_t *)); + for (unsigned i=0;i=ptend) + break; + const tdeg_t &ptu=pt->u; +#ifdef GIAC_GBASIS_PERMUTATION2 + for (i=0;i & zs=zsGi[i]; + if (zs.terms && zs.pos!=excluded && tdeg_t_all_greater(ptu,zs.deg,o)) + break; + } +#else // GIAC_GBASIS_PERMUTATION2 + if (excludedg),b(res[Gi].coord.front().g),c(smod(a*extend(invmod(b,env)),env)); + tdeg_t du(pt->u-res[Gi].coord.front().u); + smallmultsubmodshift(rem,0,c,res[Gi],du,TMP1,env); + // smallmultsub(rem,rempos,smod(a*invmod(b,env->modulo),env->modulo).val,res[G[i]],pt->u-res[G[i]].coord.front().u,TMP2,env->modulo.val); + // rempos=0; // since we have removed the beginning of rem (copied in TMP1) + swap(rem.coord,TMP1.coord); + if (debug_infolevel>3) + CERR << "du=" << du << "\n"; + if (remcoeffsptr){ + // reflect linear combination on remcoeffs + if (usemap){ + for (size_t k=0;k(mapremcoeffs[k],c,(*coeffsmodptr)[Gi][k],du,env); + } + } + else { + vectpolymod & remcoeffs=*remcoeffsptr; + for (size_t k=0;kremcoeffs[k].coord.size()){ + smalladd(remcoeffs[k],addtoremcoeffs[k],TMP1,env); + swap(remcoeffs[k].coord,TMP1.coord); + addtoremcoeffs[k].coord.clear(); + } + } + } // end else usemap + } + continue; + } + if (remcoeffsptr){ + // reflect linear combination on remcoeffs + vectpolymod & remcoeffs=*remcoeffsptr; + if (usemap){ + for (size_t k=0;k(1); + if (remcoeffsptr){ + // reflect on remcoeffs + vectpolymod & remcoeffs=*remcoeffsptr; + for (size_t k=0;k + static void reducemod(vectpolymod &resmod,modint env){ + if (resmod.empty()) + return; + // Initial interreduce step + polymod TMP1(resmod.front().order,resmod.front().dim); + vector G(resmod.size()); + for (unsigned j=0;j + void gbasis_updatemod(vector & G,vector< paire > & B,vectpolymod & res,unsigned pos,polymod & TMP2,modint_t env,bool reduce,const vector & oldG){ + if (debug_infolevel>2) + CERR << CLOCK()*1e-6 << " mod begin gbasis update " << G.size() << '\n'; + if (debug_infolevel>3) + CERR << G << '\n'; + const polymod & h = res[pos]; + if (h.coord.empty()) + return; + order_t order=h.order; + vector C; + C.reserve(G.size()+1); + const tdeg_t & h0=h.coord.front().u; + // FIXME: should use oldG instead of G here + for (unsigned i=0;i if g leading monomial is prime with h, remove the pair + // -> if g leading monomial is not disjoint from h leading monomial + // keep it only if lcm of leading monomial is not divisible by another one +#if 1 + size_t tmpsize=G.size(); + vector tmp(tmpsize); + for (unsigned i=0;i is not generated + unsigned tmpsize=G.empty()?0:G.back()+1; + vector tmp(tmpsize); + for (unsigned i=0;itab[0]<0) + continue; + if (tdeg_t_all_greater(*tmp1,*tmp2,order)) + break; // found another pair, keep the smallest, or the first if equal + } + if (tmp2!=tmp1) + continue; + for (++tmp2;tmp2tab[0]<0) + continue; + if (tdeg_t_all_greater(*tmp1,*tmp2,order) && *tmp1!=*tmp2){ + break; + } + } + if (tmp2==tmpend) + C.push_back(G[i]); + } + vector< paire > B1; + B1.reserve(B.size()+C.size()); + for (unsigned i=0;i= leading monomial of h + if (debug_infolevel>2){ + CERR << CLOCK()*1e-6 << " end, pairs:"<< '\n'; + if (debug_infolevel>3) + CERR << B << '\n'; + CERR << "mod begin Groebner interreduce " << '\n'; + } + C.clear(); + C.reserve(G.size()+1); + // bool pos_pushed=false; + for (unsigned i=0;i2) + CERR << CLOCK()*1e-6 << " mod end Groebner interreduce " << '\n'; + C.push_back(pos); + swap(C,G); +#if 0 + // clear in res polymod that are no more referenced + vector used(res.size(),false); + for (unsigned i=0;i clearer; + swap(res[i].coord,clearer.coord); + } + } +#endif + } + +#if 0 + // update G, G is a list of index of the previous gbasis + new spolys + // new spolys index are starting at debut + template + void gbasis_multiupdatemod(vector & G,vector< paire > & B,vectpolymod & res,unsigned debut,polymod & TMP2,modint_t env){ + if (debug_infolevel>2) + CERR << CLOCK()*1e-6 << " mod begin gbasis update " << G.size() << "+" << add.size() << '\n'; + if (debug_infolevel>3) + CERR << G << '\n'; + vector C; + // C is used to construct new pairs + tdeg_t tmp1,tmp2; + order_t order; + for (unsigned pos=debut;pos & h = res[pos]; + const tdeg_t & h0=h.coord.front().u; + // create pairs with h and elements g of G, then remove + // -> if g leading monomial is prime with h, remove the pair + // -> if g leading monomial is not disjoint from h leading monomial + // keep it only if lcm of leading monomial is not divisible by another one + for (unsigned i=0;ij) + break; + } + } // end for j + if (j==G.size()) + C.push_back(G[i]); + } + } + vector< paire > B1; + B1.reserve(B.size()+C.size()); + for (unsigned i=0;i= leading monomial of h + if (debug_infolevel>2){ + CERR << CLOCK()*1e-6 << " end, pairs:"<< '\n'; + if (debug_infolevel>3) + CERR << B << '\n'; + CERR << "mod begin Groebner interreduce " << '\n'; + } + vector C; + C.reserve(G.size()); + for (unsigned i=0;i2) + CERR << CLOCK()*1e-6 << " mod end Groebner interreduce " << '\n'; + swap(C,G); + } +#endif + + template + bool in_gbasismod(vectpoly8 & res8,vectpolymod &res,vector & G,modint_t env,bool sugar,vector< paire > * pairs_reducing_to_zero){ + convert(res8,res,env); + unsigned ressize=unsigned(res8.size()); + unsigned learned_position=0; + bool learning=pairs_reducing_to_zero && pairs_reducing_to_zero->empty(); + if (debug_infolevel>1000) + res.dbgprint(); // instantiate dbgprint() + polymod TMP1(res.front().order,res.front().dim),TMP2(res.front().order,res.front().dim); + vector< paire > B; + order_t order=res.front().order; + if (order.o==_PLEX_ORDER) + sugar=false; + vector oldG(G); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " initial reduction/gbasis_updatemod: " << ressize << '\n'; + for (unsigned l=0;l1) + CERR << CLOCK()*1e-6 << " mod number of pairs: " << B.size() << ", base size: " << G.size() << '\n'; + // find smallest lcm pair in B + tdeg_t small0,cur; + unsigned smallpos,smallsugar=0,cursugar=0; + for (smallpos=0;smallpos cursugar; + else + doswap=tdeg_t_strictly_greater(small0,cur,order); + } + if (doswap){ + // CERR << "swap mod " << cursugar << " " << res[B[i].first].coord.front().u << " " << res[B[i].second].coord.front().u << '\n'; + swap(small0,cur); // small0=cur; + swap(smallsugar,cursugar); + smallpos=i; + } + } + paire bk=B[smallpos]; + B.erase(B.begin()+smallpos); + if (pairs_reducing_to_zero && learned_positionsize() && bk==(*pairs_reducing_to_zero)[learned_position]){ + ++learned_position; + continue; + } + if (debug_infolevel>1 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0)) + CERR << CLOCK()*1e-6 << " mod reducing pair with 1 element not in basis " << bk << '\n'; + // polymod h(res.front().order,res.front().dim); + spolymod(res[bk.first],res[bk.second],TMP1,TMP2,env); + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " mod reduce begin, pair " << bk << " spoly size " << TMP1.coord.size() << " sugar deg " << TMP1.sugar << " degree " << TMP1.coord.front().u << '\n'; + } + reducemod(TMP1,res,G,-1,TMP1,env); + if (debug_infolevel>1){ + if (debug_infolevel>2){ CERR << TMP1 << '\n'; } + CERR << CLOCK()*1e-6 << " mod reduce end, remainder size " << TMP1.coord.size() << '\n'; + } + if (!TMP1.coord.empty()){ + if (ressize==res.size()) + res.push_back(polymod(TMP1.order,TMP1.dim)); + swap(res[ressize],TMP1); + ++ressize; + gbasis_updatemod(G,B,res,ressize-1,TMP2,env,true,oldG); + if (debug_infolevel>2) + CERR << CLOCK()*1e-6 << " mod basis indexes " << G << " pairs indexes " << B << '\n'; + } + else { + if (learning && pairs_reducing_to_zero) + pairs_reducing_to_zero->push_back(bk); + } + } + if (ressize); + convert(res,G,res8,env); + return true; + } + + // F4BUCHBERGER algorithm + template + struct heap_tt { + bool left; + unsigned f4buchbergervpos:31; + unsigned polymodpos; + tdeg_t u; + heap_tt(bool l,unsigned a,unsigned b,tdeg_t t):left(l),f4buchbergervpos(a),polymodpos(b),u(t){}; + heap_tt(unsigned a,unsigned b,tdeg_t t):left(true),f4buchbergervpos(a),polymodpos(b),u(t){}; + heap_tt():left(true),f4buchbergervpos(0),polymodpos(0),u(){}; + }; + + template + struct heap_tt_compare { + order_t order; + const heap_tt * ptr; + inline bool operator () (unsigned a,unsigned b){ + return !tdeg_t_greater((ptr+a)->u,(ptr+b)->u,order); + // return (ptr+a)->u<(ptr+b)->u; + } + heap_tt_compare(const vector > & v,order_t o):order(o),ptr(v.empty()?0:&v.front()){}; + }; + + + template + struct compare_heap_tt { + order_t order; + inline bool operator () (const heap_tt & a,const heap_tt & b){ + return !tdeg_t_greater(a.u,b.u,order); + // return (ptr+a)->u<(ptr+b)->u; + } + compare_heap_tt(order_t o):order(o) {} + }; + + + // inline bool operator > (const heap_tt & a,const heap_tt & b){ return a.u>b.u; } + + // inline bool operator < (const heap_tt & a,const heap_tt & b){ return b>a;} + + template + struct heap_tt_ptr { + heap_tt * ptr; + heap_tt_ptr(heap_tt * ptr_):ptr(ptr_){}; + heap_tt_ptr():ptr(0){}; + }; + + + // inline bool operator > (const heap_tt_ptr & a,const heap_tt_ptr & b){ return a.ptr->u > b.ptr->u; } + + // inline bool operator < (const heap_tt_ptr & a,const heap_tt_ptr & b){ return b>a; } + template + struct compare_heap_tt_ptr { + order_t order; + inline bool operator () (const heap_tt_ptr & a,const heap_tt_ptr & b){ + return !tdeg_t_greater(a.ptr->u,b.ptr->u,order); + // return (ptr+a)->u<(ptr+b)->u; + } + compare_heap_tt_ptr(order_t o):order(o) {} + }; + + + template + void collect(const vectpolymod & f4buchbergerv,polymod & allf4buchberger,int start=0){ + typename vectpolymod::const_iterator it=f4buchbergerv.begin(),itend=f4buchbergerv.end(); + vector > Ht; + vector > H; + Ht.reserve(itend-it); + H.reserve(itend-it); + unsigned s=0; + order_t keyorder={_REVLEX_ORDER,0}; + for (unsigned i=0;it!=itend;++i,++it){ + keyorder=it->order; + if (int(it->coord.size())>start){ + s=giacmax(s,unsigned(it->coord.size())); + Ht.push_back(heap_tt(i,start,it->coord[start].u)); + H.push_back(heap_tt_ptr(&Ht.back())); + } + } + allf4buchberger.coord.reserve(s); // int(s*std::log(1+H.size()))); + compare_heap_tt_ptr key(keyorder); + make_heap(H.begin(),H.end(),key); + while (!H.empty()){ + std::pop_heap(H.begin(),H.end(),key); + // push root node of the heap in allf4buchberger + heap_tt & current = *H.back().ptr; + if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u) + allf4buchberger.coord.push_back(T_unsigned(create(1),current.u)); + ++current.polymodpos; + if (current.polymodpos>=f4buchbergerv[current.f4buchbergervpos].coord.size()){ + H.pop_back(); + continue; + } + current.u=f4buchbergerv[current.f4buchbergervpos].coord[current.polymodpos].u; + std::push_heap(H.begin(),H.end(),key); + } + } + + template + void collect(const vectpolymod & f4buchbergerv,const vector & G,polymod & allf4buchberger,unsigned start=0){ + unsigned Gsize=unsigned(G.size()); + if (!Gsize) return; + vector > H; + compare_heap_tt key(f4buchbergerv[G[0]].order); + H.reserve(Gsize); + for (unsigned i=0;istart) + H.push_back(heap_tt(i,start,f4buchbergerv[G[i]].coord[start].u)); + } + make_heap(H.begin(),H.end(),key); + while (!H.empty()){ + std::pop_heap(H.begin(),H.end(),key); + // push root node of the heap in allf4buchberger + heap_tt & current =H.back(); + if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u) + allf4buchberger.coord.push_back(T_unsigned(1,current.u)); + ++current.polymodpos; + if (current.polymodpos>=f4buchbergerv[G[current.f4buchbergervpos]].coord.size()){ + H.pop_back(); + continue; + } + current.u=f4buchbergerv[G[current.f4buchbergervpos]].coord[current.polymodpos].u; + std::push_heap(H.begin(),H.end(),key); + } + } + + template + void leftright(const vectpolymod & res,vector< paire > & B,vector & leftshift,vector & rightshift){ + for (unsigned i=0;i & p=res[B[i].first]; + const polymod & q=res[B[i].second]; + if (debug_infolevel>2) + CERR << "leftright " << p << "," << q << '\n'; + tdeg_t l(p.coord.front().u); + index_lcm(p.coord.front().u,q.coord.front().u,l,p.order); + leftshift[i]=l-p.coord.front().u; + rightshift[i]=l-q.coord.front().u; + } + } + + // collect monomials from pairs of res (vector of polymods), shifted by lcm + // does not collect leading monomial (since they cancel) + template + void collect(const vectpolymod & res,vector< paire > & B,polymod & allf4buchberger,vector & leftshift,vector & rightshift){ + int start=1; + vector > Ht; + vector > H; + Ht.reserve(2*B.size()); + H.reserve(2*B.size()); + unsigned s=0; + order_t keyorder={_REVLEX_ORDER,0}; + for (unsigned i=0;i & p=res[B[i].first]; + const polymod & q=res[B[i].second]; + keyorder=p.order; + if (int(p.coord.size())>start){ + s=giacmax(s,unsigned(p.coord.size())); + Ht.push_back(heap_tt(true,i,start,p.coord[start].u+leftshift[i])); + H.push_back(heap_tt_ptr(&Ht.back())); + } + if (int(q.coord.size())>start){ + s=giacmax(s,unsigned(q.coord.size())); + Ht.push_back(heap_tt(false,i,start,q.coord[start].u+rightshift[i])); + H.push_back(heap_tt_ptr(&Ht.back())); + } + } + allf4buchberger.coord.reserve(s); // int(s*std::log(1+H.size()))); + compare_heap_tt_ptr key(keyorder); + make_heap(H.begin(),H.end(),key); + while (!H.empty()){ + std::pop_heap(H.begin(),H.end(),key); + // push root node of the heap in allf4buchberger + heap_tt & current = *H.back().ptr; + if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u) + allf4buchberger.coord.push_back(T_unsigned(1,current.u)); + ++current.polymodpos; + unsigned vpos; + if (current.left) + vpos=B[current.f4buchbergervpos].first; + else + vpos=B[current.f4buchbergervpos].second; + if (current.polymodpos>=res[vpos].coord.size()){ + H.pop_back(); + continue; + } + if (current.left) + current.u=res[vpos].coord[current.polymodpos].u+leftshift[current.f4buchbergervpos]; + else + current.u=res[vpos].coord[current.polymodpos].u+rightshift[current.f4buchbergervpos]; + std::push_heap(H.begin(),H.end(),key); + } + } + + struct sparse_element { + modint val; + unsigned pos; + sparse_element(modint v,size_t u):val(v),pos(unsigned(u)){}; + sparse_element():val(0),pos(-1){}; + }; + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const sparse_element & s){ + return os << '{' << s.val<<',' << s.pos << '}' ; + } +#else + ostream & operator << (ostream & os,const sparse_element & s){ + return os << '{' << s.val<<',' << s.pos << '}' ; + } +#endif + +#ifdef GBASISF4_BUCHBERGER + bool reducef4buchbergerpos(vector &v,const vector< vector > & M,vector pivotpos,modint env){ + unsigned pos=0; + bool res=false; + for (unsigned i=0;i & m=M[i]; + pos=pivotpos[i]; + if (pos==-1) + return res; + modint c=v[pos]; + if (!c) + continue; + res=true; + c=(extend(invmod(m[pos],env))*c)%env; + vector::const_iterator jt=m.begin()+pos+1; + vector::iterator it=v.begin()+pos,itend=v.end(); + *it=0; ++it; + for (;it!=itend;++jt,++it){ + if (*jt) + *it=(*it-extend(c)*(*jt))%env; + } + } + return res; + } + +#ifdef x86_64 + unsigned reducef4buchberger_64(vector &v,const vector< vector > & M,modint env,vector & w){ + w.resize(v.size()); + vector::iterator vt=v.begin(),vtend=v.end(); + vector::iterator wt=w.begin(); + for (;vt!=vtend;++wt,++vt){ + *wt=*vt; + } + for (unsigned i=0;i & m=M[i]; + const sparse_element * it=&m.front(),*itend=it+m.size(),*it2; + if (it==itend) + continue; + int128_t & ww=w[it->pos]; + if (ww==0) + continue; + modint c=(extend(invmod(it->val,env))*ww)%env; + // CERR << "multiplier ok line " << i << " value " << c << " " << w << '\n'; + if (!c) + continue; + ww=0; + ++it; + it2=itend-8; + for (;it<=it2;){ +#if 0 + w[it[0].pos] -= extend(c)*(it[0].val); + w[it[1].pos] -= extend(c)*(it[1].val); + w[it[2].pos] -= extend(c)*(it[2].val); + w[it[3].pos] -= extend(c)*(it[3].val); + w[it[4].pos] -= extend(c)*(it[4].val); + w[it[5].pos] -= extend(c)*(it[5].val); + w[it[6].pos] -= extend(c)*(it[6].val); + w[it[7].pos] -= extend(c)*(it[7].val); + it+=8; +#else + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; +#endif + } + for (;it!=itend;++it){ + w[it->pos] -= extend(c)*(it->val); + } + } + for (vt=v.begin(),wt=w.begin();vt!=vtend;++wt,++vt){ + if (*wt) + *vt=*wt % env; + else + *vt=0; + } + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + return vt-v.begin(); + } + return v.size(); + } + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const int128_t & i){ + return os << extend(i) ; + // return os << "(" << extend(i>>64) <<","<< extend(i) <<")" ; + } +#else + ostream & operator << (ostream & os,const int128_t & i){ + return os << extend(i) ; + // return os << "(" << extend(i>>64) <<","<< extend(i) <<")" ; + } +#endif + +#endif + // sparse element if prime is < 2^24 + // if shift == 0 the position is absolute in the next sparse32 of the vector + struct sparse32 { + modint val:25; + unsigned shift:7; + sparse32(modint v,unsigned s):val(v),shift(s){}; + sparse32():val(0),shift(0){}; + }; + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const sparse32 & s){ + return os << "(" << s.val << "," << s.shift << ")" ; + } +#else + ostream & operator << (ostream & os,const sparse32 & s){ + return os << "(" << s.val << "," << s.shift << ")" ; + } +#endif + + unsigned reducef4buchberger_32(vector &v,const vector< vector > & M,modint env,vector & w){ + w.resize(v.size()); + vector::iterator vt=v.begin(),vtend=v.end(); + vector::iterator wt=w.begin(); + for (;vt!=vtend;++wt,++vt){ + *wt=*vt; + } + for (unsigned i=0;i & m=M[i]; + vector::const_iterator it=m.begin(),itend=m.end(),it2=itend-16; + if (it==itend) + continue; + unsigned p=0; + modint val; + if (it->shift){ + p += it->shift; + val=it->val; + } + else { + val=it->val; + ++it; + p=*(unsigned *)&(*it); + } + modint2 & ww=w[p]; + if (ww==0) + continue; + modint c=(extend(invmod(val,env))*ww)%env; + if (!c) + continue; + ww=0; + ++it; + for (;it<=it2;){ + sparse32 se = *it; + unsigned seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + se = *it; + seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + se = *it; + seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + se = *it; + seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + se = *it; + seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + se = *it; + seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + se = *it; + seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + se = *it; + seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + ++it; + } + for (;it!=itend;++it){ + const sparse32 & se = *it; + unsigned seshift=se.shift; + if (seshift){ + p += seshift; + w[p] -= extend(c)*se.val; + } + else { + ++it; + p = *(unsigned *) &*it; + w[p] -= extend(c)*se.val; + } + } + } + for (vt=v.begin(),wt=w.begin();vt!=vtend;++wt,++vt){ + if (*wt) + *vt = *wt % env; + else + *vt =0; + } + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + return unsigned(vt-v.begin()); + } + return unsigned(v.size()); + } + +#ifdef PSEUDO_MOD + // find pseudo remainder of x mod p, 2^nbits>=p>2^(nbits-1) + // assumes invp=2^(2*nbits)/p+1 has been precomputed + // and abs(x)<2^(31+nbits) + // |remainder| <= max(2^nbits,|x|*p/2^(2nbits)), <=2*p if |x|<=p^2 + inline int pseudo_mod(longlong x,int p,unsigned invp,unsigned nbits){ + return int(x - (((x>>nbits)*invp)>>(nbits))*p); + } + // a <- (a+b*c) mod or smod p + inline void pseudo_mod(int & a,int b,int c,int p,unsigned invp,unsigned nbits){ + a=pseudo_mod(a+((longlong)b)*c,p,invp,nbits); + } +#endif + + unsigned reducef4buchberger(vector &v,const vector< vector > & M,modint env){ +#ifdef PSEUDO_MOD + int nbits=sizeinbase2(env); + unsigned invmodulo=((1ULL<<(2*nbits)))/env+1; +#endif + for (unsigned i=0;i & m=M[i]; + vector::const_iterator it=m.begin(),itend=m.end(); + if (it==itend) + continue; + modint c=(extend(invmod(it->val,env))*v[it->pos])%env; + v[it->pos]=0; + if (!c) + continue; +#ifdef PSEUDO_MOD + if (env<(1<<29)){ + c=-c; + for (++it;it!=itend;++it){ + pseudo_mod(v[it->pos],c,it->val,env,invmodulo,nbits); + } + continue; + } +#endif + for (++it;it!=itend;++it){ + modint &x=v[it->pos]; + x=(x-extend(c)*(it->val))%env; + } + } + vector::iterator vt=v.begin(),vtend=v.end(); +#ifdef PSEUDO_MOD + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + *vt %= env; + } +#endif + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + return unsigned(vt-v.begin()); + } + return unsigned(v.size()); + } + + +#if GIAC_SHORTSHIFTTYPE==8 + typedef unsigned char shifttype; + // assumes that all shifts are less than 2^(3*sizeof()), + // and almost all shifts are less than 2^sizeof()-1 + // for unsigned char here matrix density should be significantly above 0.004 + + inline void next_index(unsigned & pos,const shifttype * & it){ + if (*it) + pos+=(*it); + else { // next 3 will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += (*it << 8); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos+=(*it); + else { // next 3 will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += (*it << 8); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos+=(*it); + else { // next 3 will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += (*it << 8); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos+=(*it); + else { // next 3 will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += (*it << 8); + ++it; + pos += *it; + } + ++it; + } + +#ifdef x86_64 + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos+=(*it); + else { // next 3 will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += (*it << 8); + ++it; + pos += *it; + } + ++it; + } +#endif + + + unsigned first_index(const vector & v){ + if (v.front()) + return v.front(); + return (v[1]<<16)+(v[2]<<8)+v[3]; + } + + inline void pushsplit(vector & v,unsigned & pos,unsigned newpos){ + unsigned shift=newpos-pos; + if (shift && (shift <(1<<8))) + v.push_back(shift); + else { + v.push_back(0); + v.push_back(shift >> 16 ); + v.push_back(shift >> 8); + v.push_back(shift); + } + pos=newpos; + } +#endif + +#if GIAC_SHORTSHIFTTYPE==16 + typedef unsigned short shifttype; + + inline void next_index(unsigned & pos,const shifttype * & it){ + if (*it) + pos += (*it); + else { // next will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos += (*it); + else { // next will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos += (*it); + else { // next will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos += (*it); + else { // next will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos += (*it); + else { // next will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += *it; + } + ++it; + } + + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos += (*it); + else { // next will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += *it; + } + ++it; + } + +#ifdef x86_64 + inline void next_index(vector::iterator & pos,const shifttype * & it){ + if (*it) + pos += (*it); + else { // next will make the shift + ++it; + pos += (*it << 16); + ++it; + pos += *it; + } + ++it; + } +#endif + + unsigned first_index(const vector & v){ + if (v.front()) + return v.front(); + return (v[1]<<16)+v[2]; + } + + inline void pushsplit(vector & v,unsigned & pos,unsigned newpos){ + unsigned shift=newpos-pos; + if ( shift && (shift < (1<<16)) ) + v.push_back(shift); + else { + v.push_back(0); + v.push_back(shift >> 16 ); + v.push_back(shift); + } + pos=newpos; + } +#endif + +#ifndef GIAC_SHORTSHIFTTYPE + typedef unsigned shifttype; + inline void next_index(unsigned & pos,const shifttype * & it){ + pos=(*it); + ++it; + } + inline unsigned first_index(const vector & v){ + return v.front(); + } + inline void pushsplit(vector & v,unsigned & pos,unsigned newpos){ + v.push_back(pos=newpos); + } + +#endif + + struct coeffindex_t { + bool b; + unsigned u:24; + coeffindex_t(bool b_,unsigned u_):b(b_),u(u_) {}; + coeffindex_t():b(false),u(0) {}; + }; + +#ifdef x86_64 + unsigned reducef4buchbergersplit128(vector &v,const vector< vector > & M,const vector & firstpos,vector< vector > & coeffs,vector & coeffindex,modint env,vector & v128){ + vector::iterator vt=v.begin(),vtend=v.end(); + v128.resize(v.size()); + vector::iterator wt=v128.begin(),wt0=wt; + for (;vt!=vtend;++wt,++vt) + *wt=*vt; + vector::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(); + for (;fit!=fitend;++fit){ + if (*(wt0+*fit)==0) + continue; + unsigned i=fit-fit0; + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jtend-8; + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + wt=wt0+pos; + // if (*wt==0) continue; + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=(invmod(*jt,env)*(*wt))%env; + *wt=0; + if (!c) + continue; + ++jt; +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ +#if 0 + if (jt &v,const vector< vector > & M,vector< vector > & coeffs,vector & coeffindex,modint env,vector & v128){ + vector::iterator vt=v.begin(),vtend=v.end(); + v128.resize(v.size()); + vector::iterator wt=v128.begin(); + for (;vt!=vtend;++wt,++vt) + *wt=*vt; + for (unsigned i=0;i & mcoeff=coeffs[coeffindex[i].u]; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jtend-8; + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const unsigned * it=&mindex.front(); + unsigned pos=*it; + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=(invmod(*jt,env)*v128[pos])%env; + v128[pos]=0; + if (!c) + continue; + ++it;++jt; + for (;jt &v,const vector< vector > & M,vector< vector > & coeffs,vector & coeffindex,modint env,vector & v128){ + vector::iterator vt=v.begin(),vtend=v.end(); + v128.resize(v.size()); + vector::iterator wt=v128.begin(); + for (;vt!=vtend;++wt,++vt) + *wt=*vt; + for (unsigned i=0;i & mcoeff=coeffs[coeffindex[i].u]; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jtend-8; + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const short unsigned * it=&mindex.front(); + unsigned pos=*it; + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=(invmod(*jt,env)*v128[pos])%env; + v128[pos]=0; + if (!c) + continue; + ++it;++jt; + for (;jt &v,const vector< vector > & M,const vector & firstpos,vector< vector > & coeffs,vector & coeffindex,modint env,vector & v64){ + vector::iterator vt=v.begin(),vt0=vt,vtend=v.end(); + vector::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(); + if (env<(1<<24)){ + v64.resize(v.size()); + vector::iterator wt=v64.begin(),wt0=wt,wtend=v64.end(); + for (;vt!=vtend;++wt,++vt){ + *wt=*vt; + *vt=0; + } + bool fastcheck = (fitend-fit0)<=0xffff; + for (;fit!=fitend;++fit){ + if (fastcheck && *(wt0+*fit)==0) + continue; + unsigned i=unsigned(fit-fit0); + if (!fastcheck){ + if ((i&0xffff)==0xffff){ + // reduce the line mod env + for (wt=v64.begin();wt!=wtend;++wt){ + if (*wt) + *wt %= env; + } + } + if (v64[*fit]==0) + continue; + } + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + wt=wt0+pos; + // if (*wt==0) continue; + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + if (mcoeff.empty()) + continue; + const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + // if (pos>v.size()) CERR << "error" <<'\n'; + // if (*jt!=1) CERR << "not normalized" << '\n'; + modint c=(extend(invmod(*jt,env))*(*wt % env))%env; + *wt=0; + if (!c) + continue; + ++jt; +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ + for (;jt=env || i<=-env) + i %= env; + *vt = shrink(i); + if (i){ + res=unsigned(vt-v.begin()); + break; + } + } + for (;vt!=vtend;++wt,++vt){ + if (modint2 i=*wt) // if (i>=env || i<=-env) + *vt = i % env; + } + return res; + } +#ifdef PSEUDO_MOD + int nbits=sizeinbase2(env); + unsigned invmodulo=((1ULL<<(2*nbits)))/env+1; +#endif + for (;fit!=fitend;++fit){ + if (*(vt0+*fit)==0) + continue; + unsigned i=unsigned(fit-fit0); + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(),jt_=jt-8; + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + vt=v.begin()+pos; + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=(extend(invmod(*jt,env))*(*vt))%env; + *vt=0; + if (!c) + continue; + ++jt; +#ifdef PSEUDO_MOD + if (env<(1<<29)){ + c=-c; +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ + for (;jtv.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + ++jt; + } + for (;jt!=jtend;++jt){ + vt += *it; ++it; + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + } + } + else { + for (;jtv.size()) CERR << "error" <<'\n'; + pseudo_mod(*vt,c,*jt,env,invmodulo,nbits); + } + } + continue; +#else + for (;jt!=jtend;++jt){ + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(v[*it],c,*jt,env,invmodulo,nbits); + ++it; + } + continue; +#endif // GIAC_SHORTSHIFTTYPES + } // end if env<1<<29 +#endif // PSEUDOMOD + for (;jt!=jtend;++jt){ +#ifdef GIAC_SHORTSHIFTTYPE + next_index(vt,it); + *vt = (*vt-extend(c)*(*jt))%env; +#else + modint &x=v[*it]; + ++it; + x=(x-extend(c)*(*jt))%env; +#endif + } + } + vt=v.begin();vtend=v.end(); +#ifdef PSEUDO_MOD + unsigned res=v.size(); + for (;vt!=vtend;++vt){ // or if (*vt) *vt %= env; + if (!*vt) continue; + *vt %= env; + if (*vt){ + res=vt-v.begin(); + break; + } + } + for (;vt!=vtend;++vt){ // or if (*vt) *vt %= env; + modint v=*vt; + if (v>-env && v>63) & env2); +#else + register modint2 y=x-c*d; // 1 read, 1 write, 5 instr + x = y + ((y>>63)&env2); +#endif + //x=y%env; + //if (y<0) x = y+env2; else x=y;// if y is negative make it positive by adding env^2 + // x = y - (y>>63)*env2; + } + + inline void special_mod(modint2 & x,const modint & c,const modint & d,const modint2 & env2){ + register modint2 y=x-extend(c)*d; + x = y + ((y>>63)&env2); + } + + inline void special_mod(double & x,double c,modint d,modint env,double env2){ + register modint2 y=x-c*d; + if (y<0) x = double(y+env2); else x=double(y);// if y is negative make it positive by adding env^2 + } + + typedef char used_t; + // typedef bool used_t; + + void f4_innerloop_(modint2 * wt,const modint * jt,const modint * jtend,modint c,const shifttype* it){ + jtend -= 8; + for (;jt<=jtend;){ + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + wt += *it; ++it; + *wt-=extend(c)*(*jt); + ++jt; + } + jtend+=8; + for (;jt!=jtend;++jt){ + wt += *it; ++it; + *wt-=extend(c)*(*jt); + } + } + + inline void f4_innerloop(modint2 * wt,const modint * jt,const modint * jtend,modint C,const shifttype* it){ + jtend -= 16; + for (;jt<=jtend;){ +#if 1 + wt += it[0]; int b=it[1]; + *wt -= extend(C)*jt[0]; + wt[b] -= extend(C)*jt[1]; + wt += b+it[2]; b=it[3]; + *wt -= extend(C)*jt[2]; + wt[b] -= extend(C)*jt[3]; + wt += b+it[4]; b=it[5]; + *wt -= extend(C)*jt[4]; + wt[b] -= extend(C)*jt[5]; + wt += b+it[6]; b=it[7]; + *wt -= extend(C)*jt[6]; + wt[b] -= extend(C)*jt[7]; + wt += b+it[8]; b=it[9]; + *wt -= extend(C)*jt[8]; + wt[b] -= extend(C)*jt[9]; + wt += b+it[10]; b=it[11]; + *wt -= extend(C)*jt[10]; + wt[b] -= extend(C)*jt[11]; + wt += b+it[12]; b=it[13]; + *wt -= extend(C)*jt[12]; + wt[b] -= extend(C)*jt[13]; + wt += b+it[14]; b=it[15]; + *wt -= extend(C)*jt[14]; + wt[b] -= extend(C)*jt[15]; + wt += b; + it += 16; jt+=16; +#else + wt += it[0]; *wt -= extend(C)*jt[0]; + wt += it[1]; *wt -= extend(C)*jt[1]; + wt += it[2]; *wt -= extend(C)*jt[2]; + wt += it[3]; *wt -= extend(C)*jt[3]; + wt += it[4]; *wt -= extend(C)*jt[4]; + wt += it[5]; *wt -= extend(C)*jt[5]; + wt += it[6]; *wt -= extend(C)*jt[6]; + wt += it[7]; *wt -= extend(C)*jt[7]; + wt += it[8]; *wt -= extend(C)*jt[8]; + wt += it[9]; *wt -= extend(C)*jt[9]; + wt += it[10]; *wt -= extend(C)*jt[10]; + wt += it[11]; *wt -= extend(C)*jt[11]; + wt += it[12]; *wt -= extend(C)*jt[12]; + wt += it[13]; *wt -= extend(C)*jt[13]; + wt += it[14]; *wt -= extend(C)*jt[14]; + wt += it[15]; *wt -= extend(C)*jt[15]; + it += 16; jt+=16; +#endif + } + jtend += 16; + for (;jt!=jtend;++jt){ + wt += *it; ++it; + *wt-=extend(C)*(*jt); + } + } + + void f4_innerloop_special_mod(modint2 * wt,const modint * jt,const modint * jtend,modint C,const shifttype* it,modint env){ + modint2 env2=extend(env)*env; + if (jtend-jt>3 && ((ulonglong) it &0x2)){ // align it address + // should be always true (since we have already read one time) + wt += *it; ++it; + special_mod(*wt,C,*jt,env2); ++jt; + if (0 && (ulonglong) it &0x4){ + wt += *it; ++it; + special_mod(*wt,C,*jt,env2); ++jt; + wt += *it; ++it; + special_mod(*wt,C,*jt,env2); ++jt; + } + } + jtend -= 16; +#ifndef BIDGENDIAN // it address is 32 bits aligned +#if 0 // def CPU_SIMD// vectorization is not faster + unsigned * IT=(unsigned *)it; + Vec4q CC(C),P(env2); + for (;jt<=jtend;){ // 6 pointers (4wt, 1jt, 1IT), 1 unsigned, 1 modint, 1 modint2 + unsigned B; modint2 * wt0,*wt1,*wt2; + B=*IT; + wt += (B&0xffff); + wt0=wt; + wt += (B>>16); + wt1=wt; + B=IT[1]; + wt += (B&0xffff); + wt2=wt; + wt += (B>>16); // 12 instr, 2 read + Vec4q A(*wt0,*wt1,*wt2,*wt); // 1 load, 4 reads + Vec4i D; D.load(jt); // 1 load from 1 pointer + A -= CC*extend(D); // simd 1* 1- + A += ((A>>63)&P); // simd 1>> 1& 1+ + *wt0=A.extract(0); // 6 instr, 4 write + *wt1=A.extract(1); + *wt2=A.extract(2); + *wt=A.extract(3); + IT+=2; jt+=4; // 18 instr + 6 reads + 4 write + 5 simd + 1 simd read + } + it=(shifttype *) IT; +#else // simd instructions + unsigned * IT=(unsigned *) it; + for (;jt<=jtend;){ + unsigned B; + B=*IT; //1+1read + wt += (B&0xffff); // 2 + special_mod(*wt,C,*jt,env2); // 5+2read/1write + wt += (B>>16); // 2 + special_mod(*wt,C,jt[1],env2); //5+2R+1W + B=IT[1]; // 1+1read + wt += (B&0xffff); // 2 + special_mod(*wt,C,jt[2],env2); // 5+2R+1W + wt += (B>>16); // 2 + special_mod(*wt,C,jt[3],env2); //5+2R+1W => 30 instr + 10 reads + 4 write + B=IT[2]; + wt += (B&0xffff); + special_mod(*wt,C,jt[4],env2); + wt += (B>>16);; + special_mod(*wt,C,jt[5],env2); + B=IT[3]; + wt += (B&0xffff); + special_mod(*wt,C,jt[6],env2); + wt += (B>>16);; + special_mod(*wt,C,jt[7],env2); + B=IT[4]; + wt += (B&0xffff); + special_mod(*wt,C,jt[8],env2); + wt += (B>>16);; + special_mod(*wt,C,jt[9],env2); + B=IT[5]; + wt += (B&0xffff); + special_mod(*wt,C,jt[10],env2); + wt += (B>>16);; + special_mod(*wt,C,jt[11],env2); + B=IT[6]; + wt += (B&0xffff); + special_mod(*wt,C,jt[12],env2); + wt += (B>>16);; + special_mod(*wt,C,jt[13],env2); + B=IT[7]; + wt += (B&0xffff); + special_mod(*wt,C,jt[14],env2); + wt += (B>>16);; + special_mod(*wt,C,jt[15],env2); + IT += 8; jt+=16; + } + it=(shifttype *) IT; +#endif // simd instructions +#else + for (;jt<=jtend;){ + wt += it[0]; int b=it[1]; + special_mod(*wt,C,*jt,env2); + special_mod(wt[b],C,jt[1],env2); + wt += b+it[2]; b=it[3]; + special_mod(*wt,C,jt[2],env2); + special_mod(wt[b],C,jt[3],env2); + wt += b+it[4]; b=it[5]; + special_mod(*wt,C,jt[4],env2); + special_mod(wt[b],C,jt[5],env2); + wt += b+it[6]; b=it[7]; + special_mod(*wt,C,jt[6],env2); + special_mod(wt[b],C,jt[7],env2); + wt += b+it[8]; b=it[9]; + special_mod(*wt,C,jt[8],env2); + special_mod(wt[b],C,jt[9],env2); + wt += b+it[10]; b=it[11]; + special_mod(*wt,C,jt[10],env2); + special_mod(wt[b],C,jt[11],env2); + wt += b+it[12]; b=it[13]; + special_mod(*wt,C,jt[12],env2); + special_mod(wt[b],C,jt[13],env2); + wt += b+it[14]; b=it[15]; + special_mod(*wt,C,jt[14],env2); + special_mod(wt[b],C,jt[15],env2); + wt += b; + it += 16; jt+=16; + } +#endif + jtend += 16; + for (;jt!=jtend;++jt){ + wt += *it; ++it; + special_mod(*wt,C,*jt,env2); + } + } + + void f4_innerloop_special_mod(double * wt,const modint * jt,const modint * jtend,modint C,const shifttype* it,modint env){ + double env2=double(env)*env; + jtend -= 16; + for (;jt<=jtend;){ + wt += it[0]; int b=it[1]; + special_mod(*wt,C,*jt,env,env2); + special_mod(wt[b],C,jt[1],env,env2); + wt += b+it[2]; b=it[3]; + special_mod(*wt,C,jt[2],env,env2); + special_mod(wt[b],C,jt[3],env,env2); + wt += b+it[4]; b=it[5]; + special_mod(*wt,C,jt[4],env,env2); + special_mod(wt[b],C,jt[5],env,env2); + wt += b+it[6]; b=it[7]; + special_mod(*wt,C,jt[6],env,env2); + special_mod(wt[b],C,jt[7],env,env2); + wt += b+it[8]; b=it[9]; + special_mod(*wt,C,jt[8],env,env2); + special_mod(wt[b],C,jt[9],env,env2); + wt += b+it[10]; b=it[11]; + special_mod(*wt,C,jt[10],env,env2); + special_mod(wt[b],C,jt[11],env,env2); + wt += b+it[12]; b=it[13]; + special_mod(*wt,C,jt[12],env,env2); + special_mod(wt[b],C,jt[13],env,env2); + wt += b+it[14]; b=it[15]; + special_mod(*wt,C,jt[14],env,env2); + special_mod(wt[b],C,jt[15],env,env2); + wt += b; + it += 16; jt+=16; + } + jtend += 16; + for (;jt!=jtend;++jt){ + wt += *it; ++it; + special_mod(*wt,C,*jt,env,env2); + } + } + + template + unsigned store_coeffs(vector &v64or32,unsigned firstcol,vector & lescoeffs,unsigned * bitmap,vector & used,modint_t env){ + unsigned res=0; + used_t * uit=&used.front(); + typename vector::iterator wt0=v64or32.begin(),wt=v64or32.begin()+firstcol,wtend=v64or32.end(); + typename vector::iterator wt1=wtend-4; +#if 1 + for (;wt<=wt1;wt+=4){ + if (!is_zero(wt[0]) | !is_zero(wt[1]) | !is_zero(wt[2]) | !is_zero(wt[3]) ) + break; + } +#endif + if (!res){ + for (;wt(0); + i %= env; + if (is_zero(i)) + continue; + unsigned I=unsigned(wt-wt0); + res=I; + *(uit+I)=1; // used[i]=1; + bitmap[I>>5] |= (1<<(I&0x1f)); + lescoeffs.push_back(shrink(i)); + break; + } + if (!res) + res=unsigned(v64or32.size()); + } +#if 1 + for (;wt<=wt1;){ + modt i=*wt; + if (is_zero(i)){ + if (is_zero(wt[1]) && is_zero(wt[2]) && is_zero(wt[3])){ + wt += 4; + continue; + } + ++wt; i=*wt; + if (is_zero(i)){ + ++wt; i=*wt; + if (is_zero(i)){ + ++wt; i=*wt; + } + } + } + *wt = create(0); + i %= env; + if (is_zero(i)){ + wt++; continue; + } + unsigned I=unsigned(wt-wt0); + *(uit+I)=1; // used[i]=1; + bitmap[I>>5] |= (1<<(I&0x1f)); + lescoeffs.push_back(shrink(i)); + wt++; + } +#endif + for (;wt(0); + i %= env; + if (is_zero(i)) continue; + unsigned I=unsigned(wt-wt0); + *(uit+I)=1; // used[i]=1; + bitmap[I>>5] |= (1<<(I&0x1f)); + lescoeffs.push_back(shrink(i)); + } + return res; + } + +#if 1 && defined PSEUDO_MOD && GIAC_SHORTSHIFTTYPE==16 && !defined BIGENDIAN + inline void special_mod32(modint & a,int b,int c,int p,unsigned invp,unsigned nbits){ + a=pseudo_mod(a-((longlong)b)*c,p,invp,nbits); + } + + void f4_innerloop_special_mod32(modint * wt,const modint * jt,const modint * jtend,modint C,const shifttype* it,modint env,unsigned invp,unsigned nbits){ + if (jtend-jt>3 && ((ulonglong) it &0x2)){ // align it address + // should be always true (since we have already read one time) + wt += *it; ++it; + special_mod32(*wt,C,*jt,env,invp,nbits); ++jt; + } + jtend -= 16; + for (;jt<=jtend;){ + unsigned B; + unsigned * IT=(unsigned *) it; + B=*IT; + wt += (B&0xffff); + special_mod32(*wt,C,*jt,env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[1],env,invp,nbits); + B=IT[1]; + wt += (B&0xffff); + special_mod32(*wt,C,jt[2],env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[3],env,invp,nbits); + B=IT[2]; + wt += (B&0xffff); + special_mod32(*wt,C,jt[4],env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[5],env,invp,nbits); + B=IT[3]; + wt += (B&0xffff); + special_mod32(*wt,C,jt[6],env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[7],env,invp,nbits); + B=IT[4]; + wt += (B&0xffff); + special_mod32(*wt,C,jt[8],env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[9],env,invp,nbits); + B=IT[5]; + wt += (B&0xffff); + special_mod32(*wt,C,jt[10],env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[11],env,invp,nbits); + B=IT[6]; + wt += (B&0xffff); + special_mod32(*wt,C,jt[12],env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[13],env,invp,nbits); + B=IT[7]; + wt += (B&0xffff); + special_mod32(*wt,C,jt[14],env,invp,nbits); + wt += (B>>16);; + special_mod32(*wt,C,jt[15],env,invp,nbits); + it += 16; jt+=16; + } + jtend += 16; + for (;jt!=jtend;++jt){ + wt += *it; ++it; + special_mod32(*wt,C,*jt,env,invp,nbits); + } + } + + unsigned reducef4buchbergersplit32(vector &v32,const vector< vector > & M,const vector & firstpos,unsigned firstcol,const vector< vector > & coeffs,const vector & coeffindex,vector & lescoeffs,unsigned * bitmap,vector & used,modint env){ + vector::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(),fit1=fit+firstcol,fit2; + if (fit1>fitend) + fit1=fitend; + vector::iterator wt=v32.begin(),wt0=wt,wt1,wtend=v32.end(); + unsigned skip=0; + while (fit+1firstcol) + fit1=fit2; + else + fit=fit2; + } + if (debug_infolevel>2) + CERR << "Firstcol " << firstcol << "/" << v32.size() << " ratio skipped " << (fit-fit0)/double(fitend-fit0) << '\n'; + int nbits=sizeinbase2(env); + unsigned invp=((1ULL<<(2*nbits)))/env+1; + for (;fit!=fitend;++fit){ + if (v32[*fit]==0) + continue; + unsigned i=unsigned(fit-fit0); + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + skip=pos; + wt=wt0+pos; + // if (*wt==0) continue; + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + if (mcoeff.empty()) + continue; + const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + modint c=*wt % env; + if (c<0) c += env; + *wt=0; + if (!c) + continue; + ++jt; + if (shortshifts){ + f4_innerloop_special_mod32(&*wt,jt,jtend,c,it,env,invp,nbits); + } + else { + for (;jt &v64,const vector< vector > & M,const vector & firstpos,unsigned firstcol,const vector< vector > & coeffs,const vector & coeffindex,vector & lescoeffs,unsigned * bitmap,vector & used,modint env){ + vector::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(),fit1=fit+firstcol,fit2; + if (fit1>fitend) + fit1=fitend; + vector::iterator wt=v64.begin(),wt0=wt,wt1,wtend=v64.end(); + unsigned skip=0; + while (fit+1firstcol) + fit1=fit2; + else + fit=fit2; + } + if (debug_infolevel>2) + CERR << "Firstcol " << firstcol << "/" << v64.size() << " ratio skipped " << (fit-fit0)/double(fitend-fit0) << '\n'; + if (env<(1<<24)){ +#ifdef PSEUDO_MOD + int nbits=sizeinbase2(env); + unsigned invmodulo=((1ULL<<(2*nbits)))/env+1; +#endif + bool fastcheck = (fitend-fit)<32768; + unsigned redno=0; + for (;fit & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + skip=pos; + wt=wt0+pos; + //if (*wt==0) continue; // test already done with v64[*fit]==0 + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + if (mcoeff.empty()) + continue; + const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + // if (pos>v.size()) CERR << "error" <<'\n'; + // if (*jt!=1) CERR << "not normalized " << i << '\n'; +#if 0 // def PSEUDO_MOD, does not work for cyclic8m + modint c=pseudo_mod(*wt,env,invmodulo,nbits); // *jt should be 1 +#else + modint c=*wt % env; // (extend(*jt)*(*wt % env))%env; +#endif + *wt=0; + if (!c) + continue; + if (!fastcheck){ + ++redno; + if (redno==32768){ + redno=0; + // reduce the line mod env + //CERR << "reduce line" << '\n'; + for (vector::iterator wt=v64.begin()+pos;wt!=wtend;++wt){ + // 2^63-1-p*p*32768 where p:=prevprime(2^24) + modint2 tmp=*wt; + if (tmp>=3298534588415LL || tmp<=-3298534588415LL) + *wt = tmp % env; + // if (*wt) *wt %= env; // does not work pseudo_mod(*wt,env,invmodulo,nbits); + } + } + } + ++jt; +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ + f4_innerloop(&*wt,jt,jtend,c,it); + } + else { + for (;jt 2^24 + modint2 env2=extend(env)*env; + for (;fit!=fitend;++fit){ + if (v64[*fit]==0) + continue; + unsigned i=unsigned(fit-fit0); + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + skip=pos; + wt=wt0+pos; + // if (*wt==0) continue; + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + if (mcoeff.empty()) + continue; + const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + // if (pos>v.size()) CERR << "error" <<'\n'; + // if (*jt!=1) CERR << "not normalized" << '\n'; + modint c=*wt % env; // (extend(*jt)*(*wt % env))%env; + if (c<0) c += env; + *wt=0; + if (!c) + continue; + ++jt; +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ + f4_innerloop_special_mod(&*wt,jt,jtend,c,it,env); + } + else { + for (;jt>63)&P); + A.store(&x); + } +#else + inline void special_mod(mod4int2 & x,const mod4int2 & c,const mod4int & d,const mod4int2 & env2){ + mod4int2 y=x-c*d; + x = y + ((y>>63)&env2); + } +#endif + + void f4_innerloop_special_mod( +#ifdef CPU_SIMD + mod4int2 * wt,const mod4int * jt,const mod4int * jtend,const Vec4q & C,const shifttype* it,const Vec4q & P +#else + mod4int2 * wt,const mod4int * jt,const mod4int * jtend,const mod4int2 & C,const shifttype* it,const mod4int2 & P +#endif + ){ + if (jtend-jt>3 && ((ulonglong) it &0x2)){ // align it address + // should be always true (since we have already read one time) + wt += *it; ++it; + special_mod(*wt,C,*jt,P); ++jt; + } + jtend -= 16; +#ifndef BIDGENDIAN // it address is 32 bits aligned + unsigned * IT=(unsigned *) it; + for (;jt<=jtend;){ + unsigned B; + B=*IT; //1+1read + wt += (B&0xffff); // 2 + special_mod(*wt,C,*jt,P); // 5+2read/1write + wt += (B>>16); // 2 + special_mod(*wt,C,jt[1],P); //5+2R+1W + B=IT[1]; // 1+1read + wt += (B&0xffff); // 2 + special_mod(*wt,C,jt[2],P); // 5+2R+1W + wt += (B>>16); // 2 + special_mod(*wt,C,jt[3],P); //5+2R+1W => 30 instr + 10 reads + 4 write + B=IT[2]; + wt += (B&0xffff); + special_mod(*wt,C,jt[4],P); + wt += (B>>16);; + special_mod(*wt,C,jt[5],P); + B=IT[3]; + wt += (B&0xffff); + special_mod(*wt,C,jt[6],P); + wt += (B>>16);; + special_mod(*wt,C,jt[7],P); + B=IT[4]; + wt += (B&0xffff); + special_mod(*wt,C,jt[8],P); + wt += (B>>16);; + special_mod(*wt,C,jt[9],P); + B=IT[5]; + wt += (B&0xffff); + special_mod(*wt,C,jt[10],P); + wt += (B>>16);; + special_mod(*wt,C,jt[11],P); + B=IT[6]; + wt += (B&0xffff); + special_mod(*wt,C,jt[12],P); + wt += (B>>16);; + special_mod(*wt,C,jt[13],P); + B=IT[7]; + wt += (B&0xffff); + special_mod(*wt,C,jt[14],P); + wt += (B>>16);; + special_mod(*wt,C,jt[15],P); + IT += 8; jt+=16; + } + it=(shifttype *) IT; +#else + for (;jt<=jtend;){ + wt += it[0]; int b=it[1]; + special_mod(*wt,C,*jt,P); + special_mod(wt[b],C,jt[1],P); + wt += b+it[2]; b=it[3]; + special_mod(*wt,C,jt[2],P); + special_mod(wt[b],C,jt[3],P); + wt += b+it[4]; b=it[5]; + special_mod(*wt,C,jt[4],P); + special_mod(wt[b],C,jt[5],P); + wt += b+it[6]; b=it[7]; + special_mod(*wt,C,jt[6],P); + special_mod(wt[b],C,jt[7],P); + wt += b+it[8]; b=it[9]; + special_mod(*wt,C,jt[8],P); + special_mod(wt[b],C,jt[9],P); + wt += b+it[10]; b=it[11]; + special_mod(*wt,C,jt[10],P); + special_mod(wt[b],C,jt[11],P); + wt += b+it[12]; b=it[13]; + special_mod(*wt,C,jt[12],P); + special_mod(wt[b],C,jt[13],P); + wt += b+it[14]; b=it[15]; + special_mod(*wt,C,jt[14],P); + special_mod(wt[b],C,jt[15],P); + wt += b; + it += 16; jt+=16; + } +#endif + jtend += 16; + for (;jt!=jtend;++jt){ + wt += *it; ++it; + special_mod(*wt,C,*jt,P); + } + } + + unsigned reducef4buchbergersplit(vector &v64,const vector< vector > & M,const vector & firstpos,unsigned firstcol,const vector< vector > & coeffs,const vector & coeffindex,vector & lescoeffs,unsigned * bitmap,vector & used,mod4int env){ + vector::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(),fit1=fit+firstcol,fit2; + if (fit1>fitend) + fit1=fitend; + vector::iterator wt=v64.begin(),wt0=wt,wt1,wtend=v64.end(); + unsigned skip=0; + while (fit+1firstcol) + fit1=fit2; + else + fit=fit2; + } + if (debug_infolevel>2) + CERR << "Firstcol " << firstcol << "/" << v64.size() << " ratio skipped " << (fit-fit0)/double(fitend-fit0) << '\n'; + mod4int2 env2=extend(env)*env; + for (;fit!=fitend;++fit){ + if (is_zero(v64[*fit])) + continue; + unsigned i=unsigned(fit-fit0); + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + skip=pos; + wt=wt0+pos; + // if (*wt==0) continue; + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + if (mcoeff.empty()) + continue; + const mod4int * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + // if (pos>v.size()) CERR << "error" <<'\n'; + // if (*jt!=1) CERR << "not normalized" << '\n'; + mod4int c=*wt % env; // (extend(*jt)*(*wt % env))%env; + c=makepositive(c,env); // if (c<0) c += env; + mod4int2 cc=extend(c); +#ifdef CPU_SIMD + Vec4q C; C.load(&cc); + Vec4q P; P.load(&env2); +#else + mod4int2 & C=cc; + mod4int2 & P=env2; +#endif + *wt=create(0); + if (is_zero(c)) + continue; + ++jt; + if (shortshifts){ + f4_innerloop_special_mod(&*wt,jt,jtend,C,it,P); + } + else { + for (;jt &v64,const vector< vector > & M,const vector & firstpos,unsigned firstcol,const vector< vector > & coeffs,const vector & coeffindex,vector & lescoeffs,unsigned * bitmap,vector & used,modint env){ + vector::const_iterator fit=firstpos.begin(),fit0=fit,fitend=firstpos.end(),fit1=fit+firstcol,fit2; + if (fit1>fitend) + fit1=fitend; + vector::iterator wt=v64.begin(),wt0=wt,wt1,wtend=v64.end(); + unsigned skip=0; + while (fit+1firstcol) + fit1=fit2; + else + fit=fit2; + } + if (debug_infolevel>2) + CERR << "Firstcol " << firstcol << "/" << v64.size() << " ratio skipped " << (fit-fit0)/double(fitend-fit0) << '\n'; + double env2=double(env)*env; + for (;fit!=fitend;++fit){ + if (v64[*fit]==0) + continue; + unsigned i=unsigned(fit-fit0); + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + skip=pos; + wt=wt0+pos; + // if (*wt==0) continue; + const vector & mcoeff=coeffs[coeffindex[i].u]; + bool shortshifts=coeffindex[i].b; + if (mcoeff.empty()) + continue; + const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + // if (pos>v.size()) CERR << "error" <<'\n'; + // if (*jt!=1) CERR << "not normalized" << '\n'; + modint c=longlong(*wt) % env; // (extend(*jt)*(*wt % env))%env; + if (c<0) c += env; + *wt=0; + if (!c) + continue; + ++jt; +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ + f4_innerloop_special_mod(&*wt,jt,jtend,c,it,env); + } + else { + for (;jt>5] |= (1<<(I&0x1f)); + lescoeffs.push_back(modint(i)); + break; + } + if (!res) + res=unsigned(v64.size()); + } +#if 1 + for (;wt<=wt1;++wt){ + modint2 i=*wt; + if (!i){ + ++wt; i=*wt; + if (!i){ + ++wt; i=*wt; + if (!i){ + ++wt; i=*wt; + if (!i) + continue; + } + } + } + *wt = 0; + i %= env; + if (!i) continue; + unsigned I=unsigned(wt-wt0); + *(uit+I)=1; // used[i]=1; + bitmap[I>>5] |= (1<<(I&0x1f)); + lescoeffs.push_back(modint(i)); + } +#endif + for (;wt>5] |= (1<<(I&0x1f)); + lescoeffs.push_back(modint(i)); + } + return res; + } + + unsigned reducef4buchbergersplitu(vector &v,const vector< vector > & M,vector< vector > & coeffs,vector & coeffindex,modint env,vector & v64){ + vector::iterator vt=v.begin(),vtend=v.end(); + if (env<(1<<24)){ + v64.resize(v.size()); + vector::iterator wt=v64.begin(),wtend=v64.end(); + for (;vt!=vtend;++wt,++vt) + *wt=*vt; + for (unsigned i=0;i & mcoeff=coeffs[coeffindex[i].u]; + if (mcoeff.empty()) + continue; + const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + const vector & mindex=M[i]; + const unsigned * it=&mindex.front(); + unsigned pos=*it; + // if (pos>v.size()) CERR << "error" <<'\n'; + // if (*jt!=1) CERR << "not normalized" << '\n'; + modint c=(extend(invmod(*jt,env))*(v64[pos] % env))%env; + v64[pos]=0; + if (!c) + continue; + ++it; ++jt; + for (;jt & mcoeff=coeffs[coeffindex[i].u]; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(); + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const unsigned * it=&mindex.front(); + unsigned pos=*it; + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=(extend(invmod(*jt,env))*v[pos])%env; + v[pos]=0; + if (!c) + continue; + ++it; ++jt; +#ifdef PSEUDO_MOD + if (env<(1<<29)){ + c=-c; + for (;jt!=jtend;++jt){ + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(v[*it],c,*jt,env,invmodulo,nbits); + ++it; + } + continue; + } +#endif + for (;jt!=jtend;++jt){ + modint &x=v[*it]; + ++it; + x=(x-extend(c)*(*jt))%env; + } + } + vector::iterator vt=v.begin(),vtend=v.end(); +#ifdef PSEUDO_MOD + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + *vt %= env; + } +#endif + } // end else based on modulo size + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + return unsigned(vt-v.begin()); + } + return unsigned(v.size()); + } + + unsigned reducef4buchbergersplits(vector &v,const vector< vector > & M,vector< vector > & coeffs,vector & coeffindex,modint env,vector & v64){ + vector::iterator vt=v.begin(),vtend=v.end(); + if (env<(1<<24)){ + v64.resize(v.size()); + vector::iterator wt=v64.begin(),wtend=v64.end(); + for (;vt!=vtend;++wt,++vt) + *wt=*vt; + for (unsigned i=0;i & mcoeff=coeffs[coeffindex[i].u]; + if (mcoeff.empty()) + continue; + const modint * jt=&mcoeff.front(),*jtend=jt+mcoeff.size(),*jt_=jtend-8; + const vector & mindex=M[i]; + const unsigned short * it=&mindex.front(); + unsigned pos=*it; + // if (pos>v.size()) CERR << "error" <<'\n'; + // if (*jt!=1) CERR << "not normalized" << '\n'; + modint c=(extend(invmod(*jt,env))*(v64[pos] % env))%env; + v64[pos]=0; + if (!c) + continue; + ++it; ++jt; + for (;jt & mcoeff=coeffs[coeffindex[i].u]; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(); + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const unsigned short * it=&mindex.front(); + unsigned pos=*it; + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=(extend(invmod(*jt,env))*v[pos])%env; + v[pos]=0; + if (!c) + continue; + ++it; ++jt; +#ifdef PSEUDO_MOD + if (env<(1<<29)){ + c=-c; + for (;jt!=jtend;++jt){ + // if (pos>v.size()) CERR << "error" <<'\n'; + pseudo_mod(v[*it],c,*jt,env,invmodulo,nbits); + ++it; + } + continue; + } +#endif + for (;jt!=jtend;++jt){ + modint &x=v[*it]; + ++it; + x=(x-extend(c)*(*jt))%env; + } + } + vector::iterator vt=v.begin(),vtend=v.end(); +#ifdef PSEUDO_MOD + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + *vt %= env; + } +#endif + } // end else based on modulo size + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + return unsigned(vt-v.begin()); + } + return unsigned(v.size()); + } + + bool tri(const vector & v1,const vector & v2){ + return v1.front().pos::iterator it,vector::iterator itend){ + sort(it,itend,sparse_element_tri1()); + } + + // if sorting with presumed size, adding reconstructed generators will + // not work... + template + struct tripolymod_tri { + int sort_by_logz_age; + tripolymod_tri(int b):sort_by_logz_age(b){} + bool operator() (const poly & v1,const poly & v2){ + if (sort_by_logz_age==1 && v1.logz!=v2.logz) + return v1.logz + void makeline(const polymod & p,const tdeg_t * shiftptr,const polymod & R,vector & v,int start=0){ + v.resize(R.coord.size()); + v.assign(R.coord.size(),0); + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(),jt=R.coord.begin(),jtbeg=jt,jtend=R.coord.end(); + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v[jt-jtbeg]=it->g; + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v[jt-jtbeg]=it->g; + ++jt; + break; + } + } + } + } + } + + template + void makelinesub(const polymod & p,const tdeg_t * shiftptr,const polymod & R,vector & v,int start,modint_t env){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(),jt=R.coord.begin(),jtbeg=jt,jtend=R.coord.end(); + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + // v[jt-jtbeg] -= it->g; + modint_t & vv=v[jt-jtbeg]; + vv = (vv-extend(it->g))%env; + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + // v[jt-jtbeg]-=it->g; + modint_t & vv=v[jt-jtbeg]; + vv = (vv-extend(it->g))%env; + ++jt; + break; + } + } + } + } + } + + // put in v coeffs of polymod corresponding to R, and in rem those who do not match + // returns false if v is null + template + bool makelinerem(const polymod & p,polymod & rem,const polymod & R,vector & v){ + rem.coord.clear(); + v.clear(); + v.resize(R.coord.size()); + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end(); + bool res=false; + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (tdeg_t_greater(u,jt->u,p.order) + // u>=jt->u + ){ + if (u==jt->u){ + res=true; + v[jt-R.coord.begin()]=it->g; + ++jt; + } + else + rem.coord.push_back(*it); + break; + } + } + } + return res; + } + + template + void makeline(const polymod & p,const tdeg_t * shiftptr,const polymod & R,vector & v){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end(); + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v.push_back(sparse_element(it->g,jt-R.coord.begin())); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v.push_back(sparse_element(it->g,jt-R.coord.begin())); + ++jt; + break; + } + } + } + } + } + + +#if 1 + void convert(const vector & v,vector & w,vector & used){ + unsigned count=0; + vector::const_iterator it=v.begin(),itend=v.end(); + vector::iterator ut=used.begin(); + for (;it!=itend;++ut,++it){ + if (!*it) + continue; + *ut=1; + ++count; + } + w.clear(); + w.reserve(count); + for (count=0,it=v.begin();it!=itend;++count,++it){ + if (*it) + w.push_back(sparse_element(*it,count)); + } + } + +#else + void convert(const vector & v,vector & w,vector & used){ + unsigned count=0; + vector::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (*it){ +#if 1 + used[it-v.begin()]=1; +#else + ++used[it-v.begin()]; + if (used[it-v.begin()]>100) + used[it-v.begin()]=100; +#endif + ++count; + } + } + w.clear(); + w.reserve(count); + for (it=v.begin();it!=itend;++it){ + if (*it) + w.push_back(sparse_element(*it,it-v.begin())); + } + } +#endif + + // add to w non-zero coeffs of v, set bit i in bitmap to 1 if v[i]!=0 + // bitmap size is rounded to a multiple of 32 + void zconvert(const vector & v,vector::iterator & coeffit,unsigned * bitmap,vector & used){ + vector::const_iterator it=v.begin(),itend=v.end(); + used_t * uit=&used.front(); + for (unsigned i=0;it!=itend;++i,++it){ + if (!*it) + continue; + *(uit+i)=1; // used[i]=1; + bitmap[i>>5] |= (1<<(i&0x1f)); + *coeffit=*it; + ++coeffit; + } + } + + template + void zconvert_(vector & v,vector & lescoeffs,unsigned * bitmap,vector & used){ + typename vector::iterator it0=v.begin(),it=it0,itend=v.end(),itend4=itend-4; + used_t * uit=&used.front(); + for (;it<=itend4;++it){ + if (!*it ){ + ++it; + if (!*it){ + ++it; + if (!*it){ + ++it; + if (!*it) + continue; + } + } + } + unsigned i=unsigned(it-it0); + *(uit+i)=1; // used[i]=1; + bitmap[i>>5] |= (1<<(i&0x1f)); + lescoeffs.push_back(*it); + *it=0; + } + for (;it!=itend;++it){ + if (!*it) + continue; + unsigned i=unsigned(it-it0); + *(uit+i)=1; // used[i]=1; + bitmap[i>>5] |= (1<<(i&0x1f)); + lescoeffs.push_back(*it); + *it=0; + } + } + + // create matrix from list of coefficients and bitmap of non-zero positions + // M must already have been created with the right number of rows + template + void create_matrix(const vector & lescoeffs,const unsigned * bitmap,unsigned bitmapcols,const vector & used,vector< vector > & M){ + unsigned nrows=unsigned(M.size()); + int ncols=0; + vector::const_iterator ut=used.begin(),utend=used.end(); + unsigned jend=unsigned(utend-ut); + typename vector::const_iterator it=lescoeffs.begin(); + for (;ut!=utend;++ut){ + ncols += *ut; + } + // do all memory allocation at once, trying to speed up threaded execution + for (unsigned i=0;i::iterator mi=M[i].begin(); + unsigned j=0; + for (;j>5] & (1<<(j&0x1f))){ + *mi=*it; + ++it; + } + ++mi; + } + } + } + + template + unsigned create_matrix(const unsigned * bitmap,unsigned bitmapcols,const vector & used,vector< vector > & M){ + unsigned nrows=unsigned(M.size()),zeros=0; + int ncols=0; + vector::const_iterator ut=used.begin(),utend=used.end(); + unsigned jend=unsigned(utend-ut); + for (;ut!=utend;++ut){ + ncols += *ut; + } + vector tmp; + for (unsigned i=0;i::iterator mi=M[i].begin(),it=tmp.begin(); + unsigned j=0; + for (;j>5] & (1<<(j&0x1f))){ + *mi=*it; + ++it; + } + ++mi; + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " " << zeros << " null lines over " << M.size() << '\n'; + return zeros; + } + + inline void push32(vector & v,modint val,unsigned & pos,unsigned newpos){ + unsigned shift=newpos-pos; + if (newpos && (shift <(1<<7))) + v.push_back(sparse32(val,shift)); + else { + v.push_back(sparse32(val,0)); + v.push_back(sparse32()); + * (unsigned *) & v.back() =newpos; + } + pos=newpos; + } + + template + void makeline32(const polymod & p,const tdeg_t * shiftptr,const polymod & R,vector & v){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end(); + unsigned pos=0; + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + push32(v,it->g,pos,unsigned(jt-R.coord.begin())); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + push32(v,it->g,pos,unsigned(jt-R.coord.begin())); + ++jt; + break; + } + } + } + } + } + + void convert32(const vector & v,vector & w,vector & used){ + unsigned count=0; + vector::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (*it){ +#if 1 + used[it-v.begin()]=1; +#else + ++used[it-v.begin()]; + if (used[it-v.begin()]>100) + used[it-v.begin()]=100; +#endif + ++count; + } + } + w.clear(); + w.reserve(1+int(count*1.1)); + unsigned pos=0; + for (it=v.begin();it!=itend;++it){ + if (*it) + push32(w,*it,pos,unsigned(it-v.begin())); + } + } + +template + void rref_f4buchbergermod_interreduce(vectpolymod & f4buchbergerv,const vector & f4buchbergervG,vectpolymod & res,const vector & G,unsigned excluded,const vectpolymod & quo,const polymod & R,modint_t env,vector & permutation){ + // step2: for each monomials of quo[i], shift res[G[i]] by monomial + // set coefficient in a line of a matrix M, columns are R monomials indices + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin build M" << '\n'; + unsigned N=unsigned(R.coord.size()),i,j=0; + unsigned c=N; + double sknon0=0; + vector used(N,0); + unsigned usedcount=0,zerolines=0,Msize=0; + vector< vector > K(f4buchbergervG.size()); + for (i=0;i > M; + M.reserve(N); + vector atrier; + atrier.reserve(N); + for (i=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + M.push_back(vector(0)); + M[j].reserve(1+int(1.1*res[G[i]].coord.size())); + makeline32(res[G[i]],&jt->u,R,M[j]); + // CERR << M[j] << '\n'; + if (M[j].front().shift) + atrier.push_back(sparse_element(M[j].front().shift,j)); + else + atrier.push_back(sparse_element(*(unsigned *) &M[j][1],j)); + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end build M32" << '\n'; + // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted + // CERR << "before sort " << M << '\n'; + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector< vector > M1(atrier.size()); + double mem=0; // mem*4=number of bytes allocated for M1 + for (i=0;i4e7; // should depend on real memory available + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " M32 sorted, rows " << M.size() << " columns " << N << " terms " << mem << " ratio " << (mem/M.size())/N <<'\n'; + // CERR << "after sort " << M << '\n'; + // step3 reduce + vector v(N); vector w(N); + vector< vector > SK(f4buchbergerv.size()); + for (i=0;i(f4buchbergerv[f4buchbergervG[i]],0,R,v); + if (freemem){ + polymod clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord); + } + c=giacmin(c,reducef4buchberger_32(v,M,env,w)); + // convert v to a sparse vector in SK and update used + convert32(v,SK[i],used); + //CERR << v << '\n' << SK[i] << '\n'; + } + } + M.clear(); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv reduced " << f4buchbergervG.size() << " polynoms over " << N << " monomials, start at " << c << '\n'; + for (i=0;i0); + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows + if (debug_infolevel>2) + CERR << " column32 used " << used << '\n'; + } + // create dense matrix K + for (i=0; i & v =K[i]; + if (SK[i].empty()){ + ++zerolines; + continue; + } + v.resize(usedcount); + typename vector::iterator vt=v.begin(); + vector::const_iterator ut=used.begin(),ut0=ut; + vector::const_iterator st=SK[i].begin(),stend=SK[i].end(); + unsigned p=0; + for (j=0;st!=stend;++j,++ut){ + if (!*ut) + continue; + if (st->shift){ + if (j==p + st->shift){ + p += st->shift; + *vt=st->val; + ++st; + ++sknon0; + } + } + else { + if (j==* (unsigned *) &(*(st+1))){ + *vt=st->val; + ++st; + p = * (unsigned *) &(*st); + ++st; + ++sknon0; + } + } + ++vt; + } +#if 0 + vector clearer; + swap(SK[i],clearer); // clear SK[i] memory +#endif + } + } + else { + vector< vector > M; + M.reserve(N); + vector atrier; + atrier.reserve(N); + for (i=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + M.push_back(vector(0)); + M[j].reserve(res[G[i]].coord.size()); + makeline(res[G[i]],&jt->u,R,M[j]); + atrier.push_back(sparse_element(M[j].front().pos,j)); + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end build M" << '\n'; + // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted + // CERR << "before sort " << M << '\n'; + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector< vector > M1(atrier.size()); + double mem=0; // mem*8=number of bytes allocated for M1 + unsigned firstpart=0; + for (i=0;i4e7; // should depend on real memory available + // sort(M.begin(),M.end(),tri); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " M sorted, rows " << M.size() << " columns " << N << "[" << firstpart << "] terms " << mem << " ratio " << (mem/N)/M.size() << '\n'; + // CERR << "after sort " << M << '\n'; + // step3 reduce + vector v(N); + vector< vector > SK(f4buchbergerv.size()); +#ifdef x86_64 + vector v128(N); + vector multiplier(M.size()); vector pos(M.size()); +#endif + for (i=0;i(f4buchbergerv[f4buchbergervG[i]],0,R,v); + if (freemem){ + polymod clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord); + } +#ifdef x86_64 + /* vector w(v); + // CERR << "reduce " << v << '\n' << M << '\n'; + c=giacmin(c,reducef4buchbergerslice(w,M,env,v128,multiplier,pos)); + c=giacmin(c,reducef4buchberger_64(v,M,env,v128)); + if (w!=v) CERR << w << '\n' << v << '\n'; else CERR << "ok" << '\n'; + */ + // c=giacmin(c,reducef4buchbergerslice(v,M,env,v128,multiplier,pos)); + if (0 && env<(1<<29) && N>10000) // it's slower despite v128 not in cache + c=giacmin(c,reducef4buchberger(v,M,env)); + else + c=giacmin(c,reducef4buchberger_64(v,M,env,v128)); +#else // x86_64 + c=giacmin(c,reducef4buchberger(v,M,env)); +#endif // x86_64 + // convert v to a sparse vector in SK and update used + convert(v,SK[i],used); + // CERR << v << '\n' << SK[i] << '\n'; + } + } + M.clear(); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv reduced " << f4buchbergervG.size() << " polynoms over " << N << " monomials, start at " << c << '\n'; + for (i=0;i0); + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows + // if (debug_infolevel>2) CERR << " column use " << used << '\n'; + } + // create dense matrix K + for (i=0; i & v =K[i]; + if (SK[i].empty()){ + ++zerolines; + continue; + } + sknon0 += SK[i].size(); + v.resize(usedcount); + typename vector::iterator vt=v.begin(); + vector::const_iterator ut=used.begin(),ut0=ut; + vector::const_iterator st=SK[i].begin(),stend=SK[i].end(); + for (j=0;st!=stend;++j,++ut){ + if (!*ut) + continue; + if (j==st->pos){ + *vt=st->val; + ++st; + } + ++vt; + } +#if 1 + vector clearer; + swap(SK[i],clearer); // clear SK[i] memory +#endif + // CERR << used << '\n' << SK[i] << '\n' << K[i] << '\n'; + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " rref " << K.size() << "x" << usedcount << " non0 " << sknon0 << " ratio " << (sknon0/K.size())/usedcount << " nulllines " << zerolines << '\n'; + vecteur pivots; vector maxrankcols; longlong idet; + // CERR << K << '\n'; + smallmodrref(1,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,1/* fullreduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,true,0,true,-1); + //CERR << K << "," << permutation << '\n'; + typename vector< T_unsigned >::const_iterator it=R.coord.begin(),itend=R.coord.end(); + vector permu=perminv(permutation); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n'; + for (i=0;i tmpP(f4buchbergerv[f4buchbergervG[i]].order,f4buchbergerv[f4buchbergervG[i]].dim); + vector & v =K[permu[i]]; + if (v.empty()) + continue; + unsigned vcount=0; + vector::const_iterator vt=v.begin(),vtend=v.end(); + for (;vt!=vtend;++vt){ + if (*vt) + ++vcount; + } + vector< T_unsigned > & Pcoord=tmpP.coord; + Pcoord.reserve(vcount); + vector::const_iterator ut=used.begin(); + for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){ + if (!*ut) + continue; + modint_t coeff=*vt; + ++vt; + if (coeff!=0) + Pcoord.push_back(T_unsigned(coeff,it->u)); + } + if (!Pcoord.empty() && Pcoord.front().g!=1){ + smallmultmod(invmod(Pcoord.front().g,env),tmpP,env); + Pcoord.front().g=1; + } + swap(tmpP.coord,f4buchbergerv[f4buchbergervG[i]].coord); +#else + // CERR << v << '\n'; + vector< T_unsigned > & Pcoord=f4buchbergerv[f4buchbergervG[i]].coord; + Pcoord.clear(); + vector & v =K[permu[i]]; + if (v.empty()) + continue; + unsigned vcount=0; + typename vector::const_iterator vt=v.begin(),vtend=v.end(); + for (;vt!=vtend;++vt){ + if (*vt) + ++vcount; + } + Pcoord.reserve(vcount); + vector::const_iterator ut=used.begin(); + for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){ + if (!*ut) + continue; + modint_t coeff=*vt; + ++vt; + if (coeff!=0) + Pcoord.push_back(T_unsigned(coeff,it->u)); + } + if (!Pcoord.empty() && Pcoord.front().g!=1){ + smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[f4buchbergervG[i]],env); + Pcoord.front().g=1; + } +#endif + } + } + + + template + void copycoeff(const polymod & p,vector & v){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + v.clear(); + v.reserve(itend-it); + for (;it!=itend;++it) + v.push_back(it->g); + } + + template + void copycoeff(const poly8 & p,vector & v){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + v.clear(); + v.reserve(itend-it); + for (;it!=itend;++it) + v.push_back(it->g); + } + + // dichotomic seach for jt->u==u in [jt,jtend[ + template + bool dicho(typename std::vector< T_unsigned >::const_iterator & jt,typename std::vector< T_unsigned >::const_iterator jtend,const tdeg_t & u,order_t order){ + if (jt->u==u) return true; + for (;;){ + int step=int((jtend-jt)/2); + typename std::vector< T_unsigned >::const_iterator j=jt+step; + if (j==jt) + return j->u==u; + //PREFETCH(&*(j+step/2)); + //PREFETCH(&*(jt+step/2)); + if (int res=tdeg_t_greater(j->u,u,order)){ + jt=j; + if (res==2) + return true; + } + else + jtend=j; + } + } + + template + void makelinesplit(const polymod & p,const tdeg_t * shiftptr,const polymod & R,vector & v){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jtend=R.coord.end(); + unsigned pos=0; + double nop1=double(R.coord.size()); + double nop2=4*p.coord.size()*std::log(nop1)/std::log(2.0); + bool dodicho=nop2u+*shiftptr; + /* new faster code */ + if (dodicho && dicho(jt,jtend,u,R.order)){ + pushsplit(v,pos,unsigned(jt-R.coord.begin())); + ++jt; + continue; + } + /* end new faster code */ + for (;jt!=jtend;++jt){ + if (jt->u==u){ + pushsplit(v,pos,unsigned(jt-R.coord.begin())); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + /* new faster code */ + if (dodicho && dicho(jt,jtend,u,R.order)){ + pushsplit(v,pos,unsigned(jt-R.coord.begin())); + ++jt; + continue; + } + /* end new faster code */ + for (;jt!=jtend;++jt){ + if (jt->u==u){ + pushsplit(v,pos,unsigned(jt-R.coord.begin())); + ++jt; + break; + } + } + } + } + } + + // return true if all shifts are <=0xffff + bool checkshortshifts(const vector & v){ + if (v.empty()) + return false; + const shifttype * it=&v.front(),*itend=it+v.size(); + // ignore first, it's not a shift + unsigned pos; + next_index(pos,it); + for (;it!=itend;++it){ + if (!*it) + return false; + } + return true; + } + + template + void makelinesplit(const poly8 & p,const tdeg_t * shiftptr,const polymod & R,vector & v){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + typename std::vector< T_unsigned >::const_iterator jt=R.coord.begin(),jt0=jt,jtend=R.coord.end(); + unsigned pos=0; + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + pushsplit(v,pos,unsigned(jt-jt0)); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + pushsplit(v,pos,unsigned(jt-jt0)); + ++jt; + break; + } + } + } + } + } + + template + void makelinesplitu(const polymod & p,const tdeg_t * shiftptr,const polymod & R,vector & vu){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jt0=jt,jtend=R.coord.end(); + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + vu.push_back(hashgcd_U(jt-jt0)); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + vu.push_back(hashgcd_U(jt-jt0)); + ++jt; + break; + } + } + } + } + } + + template + void makelinesplits(const polymod & p,const tdeg_t * shiftptr,const polymod & R,vector & vu){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(),jt=R.coord.begin(),jt0=jt,jtend=R.coord.end(); + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + vu.push_back(hashgcd_U(jt-jt0)); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + vu.push_back(hashgcd_U(jt-jt0)); + ++jt; + break; + } + } + } + } + } + + +#define GIAC_Z + + // cache protection for rur ideal dim computation +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t rur_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + + template + void rref_f4buchbergermodsplit_interreduce(vectpolymod & f4buchbergerv,const vector & f4buchbergervG,vectpolymod & res,const vector & G,unsigned excluded,const vectpolymod & quo,const polymod & R,modint_t env,vector & permutation){ + // step2: for each monomials of quo[i], shift res[G[i]] by monomial + // set coefficient in a line of a matrix M, columns are R monomials indices + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin build M" << '\n'; + unsigned N=unsigned(R.coord.size()),i,j=0; + if (N==0) return; +#if GIAC_SHORTSHIFTTYPE==16 + bool useshort=true; +#else + bool useshort=N<=0xffff; +#endif + unsigned nrows=0; + for (i=0;i used(N,0); + unsigned usedcount=0,zerolines=0; + vector< vector > K(f4buchbergervG.size()); + vector > Mindex; + vector > Muindex; + vector< vector > Mcoeff(G.size()); + vector coeffindex; + if (useshort) + Mindex.reserve(nrows); + else + Muindex.reserve(nrows); + coeffindex.reserve(nrows); + vector atrier; + atrier.reserve(nrows); + for (i=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + if (useshort){ + for (;jt!=jtend;++j,++jt){ + Mindex.push_back(vector(0)); +#if GIAC_SHORTSHIFTTYPE==16 + Mindex[j].reserve(int(1.1*res[G[i]].coord.size())); +#else + Mindex[j].reserve(res[G[i]].coord.size()); +#endif + } + } + else { + for (;jt!=jtend;++j,++jt){ + Muindex.push_back(vector(0)); + Muindex[j].reserve(res[G[i]].coord.size()); + } + } + } + for (i=0,j=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + coeffindex.push_back(coeffindex_t(N<=0xffff,i)); + if (useshort){ +#if GIAC_SHORTSHIFTTYPE==16 + makelinesplit(res[G[i]],&jt->u,R,Mindex[j]); + if (!coeffindex.back().b) + coeffindex.back().b=checkshortshifts(Mindex[j]); + atrier.push_back(sparse_element(first_index(Mindex[j]),j)); +#else + makelinesplits(res[G[i]],&jt->u,R,Mindex[j]); + atrier.push_back(sparse_element(Mindex[j].front(),j)); +#endif + } + else { + makelinesplitu(res[G[i]],&jt->u,R,Muindex[j]); + atrier.push_back(sparse_element(Muindex[j].front(),j)); + } + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end build Mindex/Mcoeff rref_f4buchbergermodsplit_interreduce" << '\n'; + // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted + // CERR << "before sort " << M << '\n'; + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector coeffindex1(atrier.size()); + double mem=0; // mem*4=number of bytes allocated for M1 + if (useshort){ + vector< vector > Mindex1(atrier.size()); + for (i=0;i > Muindex1(atrier.size()); + for (i=0;i firstpos(atrier.size()); + for (i=0;i < atrier.size();++i){ + firstpos[i]=atrier[i].val; + } + bool freemem=true; // mem>4e7; // should depend on real memory available + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " Mindex sorted, rows " << nrows << " columns " << N << " terms " << mem << " ratio " << (mem/nrows)/N <<'\n'; + // CERR << "after sort " << M << '\n'; + // step3 reduce + vector v(N); + vector v64(N); +#ifdef x86_64 + vector v128(N); +#endif +#ifdef GIAC_Z + if (N lescoeffs; + lescoeffs.reserve(Kcols*effectivef4buchbergervGsize); + // vector lescoeffs(Kcols*effectivef4buchbergervGsize); + // vector::iterator coeffit=lescoeffs.begin(); + if (debug_infolevel>1) + CERR << "Capacity for coeffs " << lescoeffs.size() << '\n'; + vector lebitmap(((N>>5)+1)*effectivef4buchbergervGsize); + unsigned * bitmap=&lebitmap.front(); +#else + vector< vector > SK(f4buchbergerv.size()); +#endif + for (i=0;i(f4buchbergerv[f4buchbergervG[i]],0,R,v); + //CERR << v << '\n'; +#ifdef x86_64 + if (useshort){ + if (env<(1<<24)){ +#if GIAC_SHORTSHIFTTYPE==16 + c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64)); +#else + c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64)); +#endif + } + else { +#if GIAC_SHORTSHIFTTYPE==16 + c=giacmin(c,reducef4buchbergersplit128(v,Mindex,firstpos,Mcoeff,coeffindex,env,v128)); +#else + c=giacmin(c,reducef4buchbergersplit128s(v,Mindex,Mcoeff,coeffindex,env,v128)); +#endif + } + } + else { + if (env<(1<<24)) + c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64)); + else + c=giacmin(c,reducef4buchbergersplit128u(v,Muindex,Mcoeff,coeffindex,env,v128)); + } +#else + if (useshort){ +#if GIAC_SHORTSHIFTTYPE==16 + c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64)); +#else + c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64)); +#endif + } + else + c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64)); +#endif + // convert v to a sparse vector in SK and update used + if (freemem){ + polymod clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord); + } +#ifdef GIAC_Z + // zconvert(v,coeffit,bitmap,used); bitmap += (N>>5)+1; + zconvert_(v,lescoeffs,bitmap,used); bitmap += (N>>5)+1; +#else + convert(v,SK[i],used); +#endif + //CERR << v << '\n' << SK[i] << '\n'; + } + } +#if 0 // def GIAC_Z + if (debug_infolevel>1) CERR << "Total size for coeffs " << coeffit-lescoeffs.begin() << '\n'; + if (freemem){ + for (i=0;i clearer; swap(f4buchbergerv[f4buchbergervG[i]].coord,clearer.coord); + } + } +#endif + Mindex.clear(); Muindex.clear(); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv split reduced " << f4buchbergervG.size() << " polynoms over " << N << " monomials, start at " << c << '\n'; + for (i=0;i0); + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows + if (debug_infolevel>3) + CERR << " column split used " << used << '\n'; + } + // create dense matrix K +#ifdef GIAC_Z + bitmap=&lebitmap.front(); + create_matrix(lescoeffs,bitmap,(N>>5)+1,used,K); + if (freemem){ + // clear memory required for lescoeffs + vector tmp; lescoeffs.swap(tmp); + vector tmp1; lebitmap.swap(tmp1); + } +#else + for (i=0; i & v =K[i]; + if (SK[i].empty()){ + ++zerolines; + continue; + } + sknon0 += SK[i].size(); + v.resize(usedcount); + vector::iterator vt=v.begin(); + vector::const_iterator ut=used.begin(),ut0=ut; + vector::const_iterator st=SK[i].begin(),stend=SK[i].end(); + for (j=0;st!=stend;++j,++ut){ + if (!*ut) + continue; + if (j==st->pos){ + *vt=st->val; + ++st; + } + ++vt; + } +#if 1 + vector clearer; + swap(SK[i],clearer); // clear SK[i] memory +#endif + // CERR << used << '\n' << SK[i] << '\n' << K[i] << '\n'; + } // end create dense matrix K +#endif // GIAC_Z + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " rref " << K.size() << "x" << usedcount << " non0 " << sknon0 << " ratio " << (sknon0/K.size())/usedcount << " nulllines " << zerolines << '\n'; + vecteur pivots; vector maxrankcols; longlong idet; + //CERR << K << '\n'; + smallmodrref(1,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,1/* fullreduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,true,0,true,-1); + //CERR << K << "," << permutation << '\n'; + typename vector< T_unsigned >::const_iterator it=R.coord.begin(),itend=R.coord.end(); + vector permu=perminv(permutation); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n'; + for (i=0;i > & Pcoord=f4buchbergerv[f4buchbergervG[i]].coord; + Pcoord.clear(); + vector & v =K[permu[i]]; + if (v.empty()) + continue; + unsigned vcount=0; + typename vector::const_iterator vt=v.begin(),vtend=v.end(); + for (;vt!=vtend;++vt){ + if (*vt) + ++vcount; + } + Pcoord.reserve(vcount); + vector::const_iterator ut=used.begin(); + for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){ + if (!*ut) + continue; + modint_t coeff=*vt; + ++vt; + if (coeff!=0) + Pcoord.push_back(T_unsigned(coeff,it->u)); + } + if (!Pcoord.empty() && Pcoord.front().g!=1){ + smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[f4buchbergervG[i]],env); + Pcoord.front().g=1; + } + } + } + + template + void rref_f4buchbergermod_nointerreduce(vectpolymod & f4buchbergerv,const vector & f4buchbergervG,vectpolymod & res,const vector & G,unsigned excluded,const vectpolymod & quo,const polymod & R,modint_t env,vector & permutation){ + unsigned N=unsigned(R.coord.size()),i,j=0; + for (i=0;i1) + CERR << CLOCK()*1e-6 << " No inter-reduction" << '\n'; + return; + } + // step2: for each monomials of quo[i], shift res[G[i]] by monomial + // set coefficient in a line of a matrix M, columns are R monomials indices + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin build M" << '\n'; + vector< vector > M; + M.reserve(N); + vector atrier; + atrier.reserve(N); + for (i=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + M.push_back(vector(0)); + M[j].reserve(res[G[i]].coord.size()); + makeline(res[G[i]],&jt->u,R,M[j]); + atrier.push_back(sparse_element(M[j].front().pos,j)); + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end build M" << '\n'; + // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted + // CERR << "before sort " << M << '\n'; + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector< vector > M1(atrier.size()); + for (i=0;i1) + CERR << CLOCK()*1e-6 << " M sorted, rows " << M.size() << " columns " << N << " #basis to reduce" << f4buchbergervG.size() << '\n'; + // CERR << "after sort " << M << '\n'; + // step3 reduce + unsigned c=N; + vector v(N); + typename vector< T_unsigned >::const_iterator it=R.coord.begin(),itend=R.coord.end(); +#ifdef x86_64 + vector v128(N); +#endif + for (i=0;i(f4buchbergerv[f4buchbergervG[i]],0,R,v); + // CERR << v << '\n'; +#ifdef x86_64 + /* if (N>=4096) + c=giacmin(c,reducef4buchberger(v,M,env)); + else */ + c=giacmin(c,reducef4buchberger_64(v,M,env,v128)); +#else + c=giacmin(c,reducef4buchberger(v,M,env)); +#endif + vector< T_unsigned > & Pcoord=f4buchbergerv[f4buchbergervG[i]].coord; + Pcoord.clear(); + unsigned vcount=0; + typename vector::const_iterator vt=v.begin(),vtend=v.end(); + for (;vt!=vtend;++vt){ + if (*vt) + ++vcount; + } + Pcoord.reserve(vcount); + for (vt=v.begin(),it=R.coord.begin();it!=itend;++it){ + modint_t coeff=*vt; + ++vt; + if (coeff!=0) + Pcoord.push_back(T_unsigned(coeff,it->u)); + } + if (!Pcoord.empty() && Pcoord.front().g!=1){ + smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[f4buchbergervG[i]],env); + Pcoord.front().g=1; + } + } + } + } + + template + void rref_f4buchbergermod(vectpolymod & f4buchbergerv,vectpolymod & res,const vector & G,unsigned excluded,const vectpolymod & quo,const polymod & R,modint_t env,vector & permutation,bool split){ + vector f4buchbergervG(f4buchbergerv.size()); + for (unsigned i=0;i(f4buchbergerv,f4buchbergervG,res,G,excluded,quo,R,env,permutation); + else + rref_f4buchbergermod_interreduce(f4buchbergerv,f4buchbergervG,res,G,excluded,quo,R,env,permutation); +#endif + } + + template + struct info_t { + vectpolymod quo,quo2; + polymod R,R2; + vector permu; + vector< paire > B; + vector G; + unsigned nonzero; + }; + + template + void reducemodf4buchberger(vectpolymod & f4buchbergerv,vectpolymod & res,const vector & G,unsigned excluded, modint_t env,info_t & info_tmp){ + polymod allf4buchberger(f4buchbergerv.front().order,f4buchbergerv.front().dim),rem(f4buchbergerv.front().order,f4buchbergerv.front().dim); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchberger begin collect monomials on #polys " << f4buchbergerv.size() << '\n'; + // collect all terms in f4buchbergerv + collect(f4buchbergerv,allf4buchberger); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchberger symbolic preprocess" << '\n'; + // find all monomials required to reduce all polymod in f4buchberger with res[G[.]] + symbolic_preprocess(allf4buchberger,res,G,excluded,info_tmp.quo,rem,&info_tmp.R); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchberger end symbolic preprocess" << '\n'; + // build a matrix with first lines res[G[.]]*quo[.] in terms of monomials in S + // and finishing with lines of f4buchbergerv + // rref (below) the matrix and find the last lines in f4buchbergerv + rref_f4buchbergermod(f4buchbergerv,res,G,excluded,info_tmp.quo,info_tmp.R,env,info_tmp.permu,true); // do splitting + } + + // v -= v1, assumes that no overflow can happen (modulo must be 2^30) + void sub(vector & v,const vector & v1,modint env){ + vector::const_iterator jt=v1.begin(); + vector::iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++jt,++it){ + *it -= *jt; + if (*it>-env && *itenv) + *it -=env; + else + *it += env; + } +#if 0 + // normalize first element to 1 + for (it=v.begin();it!=itend;++it){ + if (*it) + break; + } + if (it!=itend){ + modint c=invmod(*it,env); + *it=1; + for (++it;it!=itend;++it){ + if (*it) + *it=(extend(c)*(*it))%env; + } + } +#endif + } + + void sub(vector & v,const vector & v1){ + vector::const_iterator jt=v1.begin(); + vector::iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++jt,++it){ + *it -= *jt; + } + } + + void sub(vector & v,const vector & v1){ + vector::const_iterator jt=v1.begin(); + vector::iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++jt,++it){ + *it -= *jt; + } + } + + template + int f4mod(vectpolymod & res,const vector & G,modint_t env,vector< paire > & B,vectpolymod & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector< info_t >* f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR){ + if (B.empty()) + return 0; + vector leftshift(B.size()); + vector rightshift(B.size()); + leftright(res,B,leftshift,rightshift); + f4buchbergerv.resize(B.size()); + info_t info_tmp; + unsigned nonzero=unsigned(B.size()); + info_t * info_ptr=&info_tmp; + if (!learning && f4buchberger_info && f4buchberger_info_positionsize()){ + info_ptr=&(*f4buchberger_info)[f4buchberger_info_position]; + ++f4buchberger_info_position; + nonzero=info_ptr->nonzero; + } + else { + polymod all(res[B[0].first].order,res[B[0].first].dim),rem; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchberger begin collect monomials on #polys " << f4buchbergerv.size() << '\n'; + collect(res,B,all,leftshift,rightshift); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchberger symbolic preprocess" << '\n'; + symbolic_preprocess(all,res,G,-1,info_tmp.quo,rem,&info_tmp.R); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end symbolic preprocess, rem size " << rem.coord.size() << '\n'; + } + polymod & R = info_ptr->R; + vectpolymod & quo = info_ptr->quo; + unsigned N = unsigned(R.coord.size()), i, j = 0; + if (N==0){ + if (learning && f4buchberger_info) + f4buchberger_info->push_back(*info_ptr); + return 1; + } +#if GIAC_SHORTSHIFTTYPE==16 + bool useshort=true; +#else + bool useshort=N<=0xffff; +#endif + unsigned nrows=0; + for (i=0;i used(N,0); + unsigned usedcount=0,zerolines=0; + vector< vector > K(B.size()); + vector > Mindex; + vector > Muindex; + vector< vector > Mcoeff(G.size()); + vector coeffindex; + if (useshort) + Mindex.reserve(nrows); + else + Muindex.reserve(nrows); + coeffindex.reserve(nrows); + vector atrier; + atrier.reserve(nrows); + for (i=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + if (useshort){ + for (;jt!=jtend;++j,++jt){ + Mindex.push_back(vector(0)); +#if GIAC_SHORTSHIFTTYPE==16 + Mindex[j].reserve(int(1.1*res[G[i]].coord.size())); +#else + Mindex[j].reserve(res[G[i]].coord.size()); +#endif + } + } + else { + for (;jt!=jtend;++j,++jt){ + Muindex.push_back(vector(0)); + Muindex[j].reserve(res[G[i]].coord.size()); + } + } + } + for (i=0,j=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + coeffindex.push_back(coeffindex_t(N<=0xffff,i)); + if (useshort){ +#if GIAC_SHORTSHIFTTYPE==16 + makelinesplit(res[G[i]],&jt->u,R,Mindex[j]); + if (!coeffindex.back().b) + coeffindex.back().b=checkshortshifts(Mindex[j]); + atrier.push_back(sparse_element(first_index(Mindex[j]),j)); +#else + makelinesplits(res[G[i]],&jt->u,R,Mindex[j]); + atrier.push_back(sparse_element(Mindex[j].front(),j)); +#endif + } + else { + makelinesplitu(res[G[i]],&jt->u,R,Muindex[j]); + atrier.push_back(sparse_element(Muindex[j].front(),j)); + } + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end build Mindex/Mcoeff f4mod" << '\n'; + // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted + // CERR << "before sort " << M << '\n'; + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector coeffindex1(atrier.size()); + double mem=0; // mem*4=number of bytes allocated for M1 + if (useshort){ + vector< vector > Mindex1(atrier.size()); + for (i=0;i > Muindex1(atrier.size()); + for (i=0;i firstpos(atrier.size()); + for (i=0;i < atrier.size();++i){ + firstpos[i]=atrier[i].val; + } + bool freemem=mem>4e7; // should depend on real memory available + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " Mindex sorted, rows " << nrows << " columns " << N << " terms " << mem << " ratio " << (mem/nrows)/N <<'\n'; + // CERR << "after sort " << M << '\n'; + // step3 reduce + vector v(N); + vector v64(N); +#ifdef x86_64 + vector v128(N); +#endif + if (N lebitmap(((N>>5)+1)*B.size()); + unsigned * bitmap=&lebitmap.front(); + for (i=0;isize() && bk==(*pairs_reducing_to_zero)[learned_position]){ + if (debug_infolevel>2) + CERR << bk << " f4buchberger learned " << learned_position << '\n'; + ++learned_position; + unsigned tofill=(N>>5)+1; + fill(bitmap,bitmap+tofill,0); + bitmap += tofill; + continue; + } + makeline(res[bk.first],&leftshift[i],R,v,1); + makelinesub(res[bk.second],&rightshift[i],R,v,1,env); + // CERR << v << '\n' << v2 << '\n'; + // sub(v,v2,env); + // CERR << v << '\n'; +#ifdef x86_64 + if (useshort){ + if (env<(1<<24)){ +#if GIAC_SHORTSHIFTTYPE==16 + c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64)); +#else + c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64)); +#endif + } + else { +#if GIAC_SHORTSHIFTTYPE==16 + c=giacmin(c,reducef4buchbergersplit128(v,Mindex,firstpos,Mcoeff,coeffindex,env,v128)); +#else + c=giacmin(c,reducef4buchbergersplit128s(v,Mindex,Mcoeff,coeffindex,env,v128)); +#endif + } + } + else { + if (env<(1<<24)) + c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64)); + else + c=giacmin(c,reducef4buchbergersplit128u(v,Muindex,Mcoeff,coeffindex,env,v128)); + } +#else // x86_64 + if (useshort){ +#if GIAC_SHORTSHIFTTYPE==16 + c=giacmin(c,reducef4buchbergersplit(v,Mindex,firstpos,Mcoeff,coeffindex,env,v64)); +#else + c=giacmin(c,reducef4buchbergersplits(v,Mindex,Mcoeff,coeffindex,env,v64)); +#endif + } + else + c=giacmin(c,reducef4buchbergersplitu(v,Muindex,Mcoeff,coeffindex,env,v64)); +#endif // x86_64 + // zconvert(v,coeffit,bitmap,used); bitmap += (N>>5)+1; + K[i].reserve(Kcols); + zconvert_(v,K[i],bitmap,used); bitmap += (N>>5)+1; + //CERR << v << '\n' << SK[i] << '\n'; + } // end for (i=0;i1) + CERR << CLOCK()*1e-6 << " f4buchbergerv split reduced " << B.size() << " polynoms over " << N << " monomials, start at " << c << '\n'; + for (i=0;i0); + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows + if (debug_infolevel>3) + CERR << " column split used " << used << '\n'; + } + // create dense matrix K + bitmap=&lebitmap.front(); + unsigned zeros=create_matrix(bitmap,(N>>5)+1,used,K); + // clear memory required for lescoeffs + //vector tmp; lescoeffs.swap(tmp); + { vector tmp1; lebitmap.swap(tmp1); } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " dense_rref " << K.size()-zeros << "(" << K.size() << ")" << "x" << usedcount << " ncoeffs=" << double(K.size()-zeros)*usedcount*1e-6 << "*1e6\n"; + vecteur pivots; vector permutation,maxrankcols; longlong idet; + // CERR << K << '\n'; + smallmodrref(1,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,1/* fullreduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,true,0,true,-1); + //CERR << K << '\n'; + unsigned first0 = unsigned(pivots.size()); + if (first0 & tmpv=K[first0]; + for (i=0;ipermu[j]){ + CERR << "learning failed"<<'\n'; + return -1; + } + } + } + if (learning) + info_ptr->permu=permutation; + // CERR << K << "," << permutation << '\n'; + typename vector< T_unsigned >::const_iterator it=R.coord.begin(),itend=R.coord.end(); + // vector permu=perminv(permutation); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n'; + for (i=0;i > & Pcoord=f4buchbergerv[permutation[i]].coord; + Pcoord.clear(); + vector & v =K[i]; + if (v.empty()){ + continue; + } + unsigned vcount=0; + typename vector::const_iterator vt=v.begin(),vtend=v.end(); + for (;vt!=vtend;++vt){ + if (*vt) + ++vcount; + } + Pcoord.reserve(vcount); + vector::const_iterator ut=used.begin(); + for (vt=v.begin(),it=R.coord.begin();it!=itend;++ut,++it){ + if (!*ut) + continue; + modint_t coeff=*vt; + ++vt; + if (coeff!=0) + Pcoord.push_back(T_unsigned(coeff,it->u)); + } + if (!Pcoord.empty() && Pcoord.front().g!=1){ + smallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[permutation[i]],env); + Pcoord.front().g=1; + } + if (freemem){ + vector tmp; tmp.swap(v); + } + } + if (learning && f4buchberger_info){ +#if 0 + f4buchberger_info->push_back(*info_ptr); +#else + info_t tmp; + f4buchberger_info->push_back(tmp); + info_t & i=f4buchberger_info->back(); + swap(i.quo,info_ptr->quo); + swap(i.permu,info_ptr->permu); + swap(i.R.coord,info_ptr->R.coord); + i.R.order=info_ptr->R.order; + i.R.dim=info_ptr->R.dim; +#endif + } + return 1; + } + + template + bool apply(vector permu,vectpolymod & res){ + vectpolymod tmp; + for (unsigned i=0;i(res.front().order,res.front().dim)); + swap(tmp[i].coord,res[permu[i]].coord); + tmp[i].sugar=res[permu[i]].sugar; + } + swap(tmp,res); + return true; + } + + template + int f4mod(vectpolymod & res,const vector & G,modint_t env,vector< paire > & smallposp,vectpolymod & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,info_t & information,vector< info_t >* f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR, polymod & TMP1,polymod & TMP2){ + // Improve: we don't really need to compute the s-polys here + // it's sufficient to do that at linalg step + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " Computing s-polys " << smallposp.size() << '\n'; + if (f4buchbergerv.size()size() && bk==(*pairs_reducing_to_zero)[learned_position]){ + if (debug_infolevel>2) + CERR << bk << " f4buchberger learned " << learned_position << '\n'; + ++learned_position; + f4buchbergerv[i].coord.clear(); + continue; + } + if (debug_infolevel>2) + CERR << bk << " f4buchberger not learned " << learned_position << '\n'; + if (debug_infolevel>2 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0)) + CERR << CLOCK()*1e-6 << " mod reducing pair with 1 element not in basis " << bk << '\n'; + // polymod h(res.front().order,res.front().dim); + spolymod(res[bk.first],res[bk.second],TMP1,TMP2,env); + f4buchbergerv[i].coord.swap(TMP1.coord); + } + if (f4buchbergerv.empty()) + return 0; + // reduce spolys in f4buchbergerv + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " base size " << G.size() << " reduce f4buchberger begin on " << f4buchbergerv.size() << " pairs" << '\n'; + if (!learning && f4buchberger_info && f4buchberger_info_positionsize()){ + info_t & info=(*f4buchberger_info)[f4buchberger_info_position]; + // apply(perminv(info.permu),f4buchbergerv); + if (recomputeR){ + swap(information.permu,info.permu); + reducemodf4buchberger(f4buchbergerv,res,G,-1,env,info); + swap(information.permu,info.permu); + } + else + rref_f4buchbergermod(f4buchbergerv,res,G,-1,info.quo,info.R,env,information.permu,false); // don't split + // apply(info.permu,f4buchbergerv); + // information.permu should be identity, otherwise the whole learning process failed + for (unsigned j=0;jpush_back(information); +#else + info_t tmp; + f4buchberger_info->push_back(tmp); + info_t & i=f4buchberger_info->back(); + swap(i.quo,information.quo); + swap(i.permu,information.permu); + swap(i.R.coord,information.R.coord); + i.R.order=information.R.order; + i.R.dim=information.R.dim; +#endif + } + } + return 1; + } + + template + bool in_gbasisf4buchbergermod(vectpolymod &res,unsigned ressize,vector & G,modint_t env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< info_t > * f4buchberger_info,bool recomputeR){ + unsigned cleared=0; + unsigned learned_position=0,f4buchberger_info_position=0; + bool sugar=false,learning=pairs_reducing_to_zero && pairs_reducing_to_zero->empty(); + if (debug_infolevel>1000) + res.dbgprint(); // instantiate dbgprint() + int capa=512; + if (f4buchberger_info) + capa=int(f4buchberger_info->capacity()); + polymod TMP1(res.front().order,res.front().dim),TMP2(res.front().order,res.front().dim); + vector< paire > B,BB; + B.reserve(256); BB.reserve(256); + vector smallposv; + smallposv.reserve(256); + info_t information; + order_t order=res.front().order; + if (order.o==_PLEX_ORDER) // if (order!=_REVLEX_ORDER && order!=_TDEG_ORDER) + totdeg=false; + vector oldG(G); + for (unsigned l=0;l=capa) + return false; // otherwise reallocation will make pointers invalid + oldG=G; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin new iteration mod, " << env << " number of pairs: " << B.size() << ", base size: " << G.size() << '\n'; + if (1){ + // mem clear: remove res[i] if i is not in G nor in B + vector clean(G.back()+1,true); + for (unsigned i=0;i1 && !res[i].coord.empty()){ + cleared += unsigned(res[i].coord.capacity()) - 1; + polymod clearer; + clearer.coord.push_back(res[i].coord.front()); + clearer.coord.swap(res[i].coord); + } + } + } + // find smallest lcm pair in B + tdeg_t small0,cur; + unsigned smallpos,smalltotdeg=0,curtotdeg=0,smallsugar=0,cursugar=0; + smallposv.clear(); + for (smallpos=0;smallpos cursugar; + } + else { + if (smalltotdeg!=curtotdeg) + doswap = smalltotdeg > curtotdeg; + } + } + if (doswap){ + smallsugar=cursugar; + smalltotdeg=curtotdeg; + // CERR << "swap mod " << curtotdeg << " " << res[B[i].first].coord.front().u << " " << res[B[i].second].coord.front().u << '\n'; + swap(small0,cur); // small=cur; + smallpos=i; + smallposv.clear(); + smallposv.push_back(i); + } + else { + if (totdeg && curtotdeg==smalltotdeg && (!sugar || cursugar==smallsugar)) + smallposv.push_back(i); + } + } + if (smallposv.size()<=GBASISF4_BUCHBERGER){ + unsigned i=smallposv[0]; + paire bk=B[i]; + B.erase(B.begin()+i); + if (!learning && pairs_reducing_to_zero && learned_positionsize() && bk==(*pairs_reducing_to_zero)[learned_position]){ + if (debug_infolevel>2) + CERR << bk << " learned " << learned_position << '\n'; + ++learned_position; + continue; + } + if (debug_infolevel>2) + CERR << bk << " not learned " << learned_position << '\n'; + if (debug_infolevel>2 && (equalposcomp(G,bk.first)==0 || equalposcomp(G,bk.second)==0)) + CERR << CLOCK()*1e-6 << " mod reducing pair with 1 element not in basis " << bk << '\n'; + // polymod h(res.front().order,res.front().dim); + spolymod(res[bk.first],res[bk.second],TMP1,TMP2,env); + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " mod reduce begin, pair " << bk << " spoly size " << TMP1.coord.size() << " sugar degree " << TMP1.sugar << " totdeg deg " << TMP1.coord.front().u.total_degree(order) << " degree " << TMP1.coord.front().u << '\n'; + } +#if 0 // def GBASIS_HEAP + heap_reducemod(TMP1,res,G,-1,information.quo,TMP2,env); + swap(TMP1.coord,TMP2.coord); +#else + reducemod(TMP1,res,G,-1,TMP1,env); +#endif + if (debug_infolevel>1){ + if (debug_infolevel>3){ CERR << TMP1 << '\n'; } + CERR << CLOCK()*1e-6 << " mod reduce end, remainder size " << TMP1.coord.size() << " begin gbasis update" << '\n'; + } + if (!TMP1.coord.empty()){ + increase(res); + if (ressize==res.size()) + res.push_back(polymod(TMP1.order,TMP1.dim)); + swap(res[ressize].coord,TMP1.coord); + ++ressize; +#if GBASIS_POSTF4BUCHBERGER==0 + // this does not warrant full interreduced answer + // because at the final step we assume that each spoly + // is reduced by the previous spolys in res + // either by the first reduction or by inter-reduction + // here at most GBASISF4_BUCHBERGER spolys may not be reduced by the previous ones + // it happens for example for cyclic8, element no 97 + gbasis_updatemod(G,B,res,ressize-1,TMP2,env,false,oldG); +#else + gbasis_updatemod(G,B,res,ressize-1,TMP2,env,true,oldG); +#endif + if (debug_infolevel>3) + CERR << CLOCK()*1e-6 << " mod basis indexes " << G << " pairs indexes " << B << '\n'; + } + else { + if (learning && pairs_reducing_to_zero){ + if (debug_infolevel>2) + CERR << "learning " << bk << '\n'; + pairs_reducing_to_zero->push_back(bk); + } + } + continue; + } + vector< paire > smallposp; + if (smallposv.size()==B.size()){ + swap(smallposp,B); + B.clear(); + } + else { + for (unsigned i=0;i=0;--i) + B.erase(B.begin()+smallposv[i]); + } + vectpolymod f4buchbergerv; // collect all spolys + int f4res=-1; + f4res=f4mod(res,G,env,smallposp,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR); + if (f4res==-1) + return false; + if (f4res==0) + continue; + // update gbasis and learning + // requires that Gauss pivoting does the same permutation for other primes + if (learning && pairs_reducing_to_zero){ + for (unsigned i=0;i2) + CERR << "learning f4buchberger " << smallposp[i] << '\n'; + pairs_reducing_to_zero->push_back(smallposp[i]); + } + } + } + unsigned added=0; + for (unsigned i=0;i1) + CERR << CLOCK()*1e-6 << " reduce f4buchberger end on " << added << " from " << f4buchbergerv.size() << " pairs, gbasis update begin" << '\n'; + for (unsigned i=0;i(TMP1.order,TMP1.dim)); + swap(res[ressize].coord,f4buchbergerv[i].coord); + ++ressize; +#ifdef GBASIS_POSTF4BUCHBERGER +#if GBASIS_POSTF4BUCHBERGER==0 + if (learning || !f4buchberger_info || f4buchberger_info_position-1>=f4buchberger_info->size()) + gbasis_updatemod(G,B,res,ressize-1,TMP2,env,false,oldG); +#else + gbasis_updatemod(G,B,res,ressize-1,TMP2,env,added<=GBASISF4_BUCHBERGER,oldG); +#endif +#else + gbasis_updatemod(G,B,res,ressize-1,TMP2,env,true,oldG); +#endif + } + else { + // if (!learning && pairs_reducing_to_zero) CERR << " error learning "<< '\n'; + } + } +#if GBASIS_POSTF4BUCHBERGER==0 + if (!learning && f4buchberger_info && f4buchberger_info_position-1size()){ + B=(*f4buchberger_info)[f4buchberger_info_position-1].B; + G=(*f4buchberger_info)[f4buchberger_info_position-1].G; + continue; + } + if (learning && f4buchberger_info){ + f4buchberger_info->back().B=B; + f4buchberger_info->back().G=G; + f4buchberger_info->back().nonzero=added; + } +#endif + unsigned debut = unsigned(G.size()) - added; +#if GBASIS_POSTF4BUCHBERGER>0 + if (added>GBASISF4_BUCHBERGER){ + // final interreduce + vector G1(G.begin(),G.begin()+debut); + vector G2(G.begin()+debut,G.end()); + vector permu2; + if (!learning && f4buchberger_info){ + const info_t & info=(*f4buchberger_info)[f4buchberger_info_position-1]; + rref_f4buchbergermod_nointerreduce(res,G1,res,G2,-1,info.quo2,info.R2,env,permu2); + } + else { + information.R2.order=TMP1.order; + information.R2.dim=TMP1.dim; + TMP1.coord.clear(); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " collect monomials from old basis" << '\n'; + collect(res,G1,TMP1); // collect all monomials in res[G[0..debut-1]] + // in_heap_reducemod(TMP1,res,G2,-1,info_tmp.quo2,TMP2,&info_tmp.R2,env); + in_heap_reducemod(TMP1,res,G2,-1,information.quo2,TMP2,&information.R2,env); + rref_f4buchbergermod_nointerreduce(res,G1,res,G2,-1,information.quo2,information.R2,env,permu2); + if (f4buchberger_info){ + info_t & i=f4buchberger_info->back(); + swap(i.quo2,information.quo2); + swap(i.R2.coord,information.R2.coord); + i.R2.order=TMP1.order; + i.R2.dim=TMP1.dim; + } + } + } +#endif + // CERR << "finish loop G.size "<1){ + unsigned t=0; + for (unsigned i=0;i); + return true; + } +#endif // GBASISF4_BUCHBERGER + + template + bool in_gbasisf4buchbergermod(vectpoly8 & res8,vectpolymod &res,vector & G,modint env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< info_t > * f4buchberger_info,bool recomputeR){ + convert(res8,res,env); + unsigned ressize = unsigned(res8.size()); + bool b=in_gbasisf4buchbergermod(res,ressize,G,env,totdeg,pairs_reducing_to_zero,f4buchberger_info,recomputeR); + convert(res,res8,env); + return b; + } + + template + bool in_gbasisf4buchbergermod(vectpoly8 & res8,vectpolymod &res,vector & G,mod4int env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< info_t > * f4buchberger_info,bool recomputeR){ + return false; + } + + // set P mod p*q to be chinese remainder of P mod p and Q mod q + template + bool chinrem(poly8 &P,const gen & pmod,poly8 & Q,const gen & qmod,poly8 & tmp){ + gen u,v,d,pqmod(pmod*qmod); + egcd(pmod,qmod,u,v,d); + if (u.type==_ZINT && qmod.type==_INT_) + u=modulo(*u._ZINTptr,qmod.val); + if (d==-1){ u=-u; v=-v; d=1; } + if (d!=1) + return false; + int qmodval=0,U=0; + mpz_t tmpz; + mpz_init(tmpz); + if (qmod.type==_INT_ && u.type==_INT_ && pmod.type==_ZINT){ + qmodval=qmod.val; + U=u.val; + } + typename vector< T_unsigned >::iterator it=P.coord.begin(),itend=P.coord.end(),jt=Q.coord.begin(),jtend=Q.coord.end(); + if (P.coord.size()==Q.coord.size()){ +#ifndef USE_GMP_REPLACEMENTS + if (qmodval){ + for (;it!=itend;++it,++jt){ + if (it->u!=jt->u || jt->g.type!=_INT_) + break; + } + if (it==itend){ + for (it=P.coord.begin(),jt=Q.coord.begin();it!=itend;++jt,++it){ + if (it->g.type==_ZINT){ + mpz_set_si(tmpz,jt->g.val); + mpz_sub(tmpz,tmpz,*it->g._ZINTptr); + mpz_mul_si(tmpz,*pmod._ZINTptr,(extend(U)*modulo(tmpz,qmodval))%qmodval); + mpz_add(*it->g._ZINTptr,*it->g._ZINTptr,tmpz); + } + else { + mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(extend(jt->g.val)-it->g.val))%qmodval); + if (it->g.val>=0) + mpz_add_ui(tmpz,tmpz,it->g.val); + else + mpz_sub_ui(tmpz,tmpz,-it->g.val); + it->g=tmpz; + } + } + return true; + } + else { + if (debug_infolevel) + CERR << "warning chinrem: exponent mismatch " << it->u << "," << jt->u << '\n'; + } + } +#endif + } + else { + if (debug_infolevel) + CERR << "warning chinrem: sizes differ " << P.coord.size() << "," << Q.coord.size() << '\n'; + } + tmp.coord.clear(); tmp.dim=P.dim; tmp.order=P.order; + tmp.coord.reserve(P.coord.size()+3); // allow 3 more terms in Q without realloc + for (it=P.coord.begin(),jt=Q.coord.begin();it!=itend && jt!=jtend;){ + if (it->u==jt->u){ + gen g; +#ifndef USE_GMP_REPLACEMENTS + if (qmodval && jt->g.type==_INT_){ + if (it->g.type==_ZINT){ + mpz_set_si(tmpz,jt->g.val); + mpz_sub(tmpz,tmpz,*it->g._ZINTptr); + mpz_mul_si(tmpz,*pmod._ZINTptr,(extend(U)*modulo(tmpz,qmodval))%qmodval); + mpz_add(tmpz,tmpz,*it->g._ZINTptr); + } + else { + mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(extend(jt->g.val)-it->g.val))%qmodval); + if (it->g.val>=0) + mpz_add_ui(tmpz,tmpz,it->g.val); + else + mpz_sub_ui(tmpz,tmpz,-it->g.val); + } + g=tmpz; + } + else +#endif + g=it->g+u*(jt->g-it->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),it->u)); + ++it; ++jt; + continue; + } + if (tdeg_t_strictly_greater(it->u,jt->u,P.order)){ + if (debug_infolevel) + CERR << "chinrem: exponent mismatch using first " << '\n'; + gen g=it->g-u*(it->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),it->u)); + ++it; + } + else { + if (debug_infolevel) + CERR << "chinrem: exponent mismatch using second " << '\n'; + gen g=u*(jt->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),jt->u)); + ++jt; + } + } + if (it!=itend && debug_infolevel) + CERR << "chinrem (gen): exponent mismatch at end using first, # " << itend-it << '\n'; + for (;it!=itend;++it){ + gen g=it->g-u*(it->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),it->u)); + } + if (jt!=jtend && debug_infolevel) + CERR << "chinrem (gen): exponent mismatch at end using second " << jtend-jt << '\n'; + for (;jt!=jtend;++jt){ + gen g=u*(jt->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),jt->u)); + } + swap(P.coord,tmp.coord); + mpz_clear(tmpz); + return true; + } + + // set P mod p*q to be chinese remainder of P mod p and Q mod q + // P and Q must have same leading monomials, + // otherwise returns 0 and leaves P unchanged + template + int chinrem(vectpoly8 &P,const gen & pmod,vectpoly8 & Q,const gen & qmod,poly8 & tmp){ + if (P.size()!=Q.size()) + return 0; + for (unsigned i=0;i + struct chinrem_t { + poly8 * Pptr; + const polymod * Qptr; + size_t start,end; + int U,qmodval; + mpz_t * pmodptr,*tmpzptr; + }; + + template + void * thread_chinrem(void * _ptr){ + chinrem_t * ptr=(chinrem_t *) _ptr; + poly8 & P=*ptr->Pptr; + const polymod & Q=*ptr->Qptr; + size_t start=ptr->start,end=ptr->end; + if (end>P.coord.size()) + end=P.coord.size(); + int U=ptr->U,qmodval=ptr->qmodval; + mpz_t * pmodptr=ptr->pmodptr,*tmpzptr=ptr->tmpzptr; + typename vector< T_unsigned >::iterator it=P.coord.begin()+start,itend=P.coord.begin()+end; + typename vector< T_unsigned >::const_iterator jt=Q.coord.begin()+start; + for (;it!=itend;++it,++jt){ + if (it->g.type==_ZINT){ + int amodq=modulo(*it->g._ZINTptr,qmodval); + if (amodq==jt->g) + continue; + mpz_mul_si(*tmpzptr,*pmodptr,(U*(jt->g-extend(amodq)))%qmodval); + mpz_add(*it->g._ZINTptr,*it->g._ZINTptr,*tmpzptr); + } + else { + mpz_mul_si(*tmpzptr,*pmodptr,(U*(extend(jt->g)-it->g.val))%qmodval); + if (it->g.val>=0) + mpz_add_ui(*tmpzptr,*tmpzptr,it->g.val); + else + mpz_sub_ui(*tmpzptr,*tmpzptr,-it->g.val); + it->g=*tmpzptr; + } + } + return ptr; + } + + // set P mod p*q to be chinese remainder of P mod p and Q mod q + template + bool chinrem(poly8 &P,const gen & pmod,const polymod & Q,int qmodval,poly8 & tmp,int nthreads=1){ + if (pmod.type!=_ZINT) + nthreads=1; + if (pmod.type!=_ZINT) + nthreads=1; + else { + double work=P.coord.size(); + work=work*sizeinbase2(pmod)/256/29; // correction of number of monomials by a factor corresponding to 256 primes of size 29 bits + if (work/nthreads<128) + nthreads=giacmin(nthreads,giacmax(1,work/128)); + } + if (nthreads>MAXNTHREADS) + nthreads=MAXNTHREADS; + gen u,v,d,pqmod(qmodval*pmod); + egcd(pmod,qmodval,u,v,d); + if (u.type==_ZINT) + u=modulo(*u._ZINTptr,qmodval); + if (d==-1){ u=-u; v=-v; d=1; } + if (d!=1) + return false; + int U=u.val; + mpz_t tmpz; + mpz_init(tmpz); + typename vector< T_unsigned >::iterator it=P.coord.begin(),itend=P.coord.end(); + typename vector< T_unsigned >::const_iterator jt=Q.coord.begin(),jtend=Q.coord.end(); +#ifndef USE_GMP_REPLACEMENTS + if (P.coord.size()==Q.coord.size()){ + for (;it!=itend;++it,++jt){ + if (it->u!=jt->u) + break; + } + if (it==itend){ +#if !defined USE_GMP_REPLACEMENTS && defined HAVE_LIBPTHREAD + if (//0 && + nthreads>1 + // && P.coord.size()>=64*nthreads + ){ + // realloc mpz_t inside P ? + size_t cur=sizeinbase2(pqmod); + int N=sizeinbase2(cur)-1; + size_t N2=(1ULL << N); + gen N3=pow(2,N2+31); + if (is_greater(N3,pqmod,context0)){ + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " parallel chinrem realloc bits=" << 2*N2 << "\n"; + for (it=P.coord.begin();it!=itend;++it){ + if (it->g.type!=_ZINT) continue; + mpz_t & z=*it->g._ZINTptr; + size_t taille=mpz_size(z)*sizeof(mp_limb_t)*8; + if (taille<2*N2) + mpz_realloc2(z,2*N2); + } + } + // parallel chinese remaindering + chinrem_t chinrem_param[MAXNTHREADS]; mpz_t tmptab[MAXNTHREADS]; + pthread_t tab[MAXNTHREADS]; + for (int j=0;j tmp={&P,&Q,j*P.coord.size()/nthreads,(j+1)*P.coord.size()/nthreads,U,qmodval,pmod._ZINTptr,&tmptab[j]}; + chinrem_param[j]=tmp; + mpz_init2(tmptab[j],cur); + bool res=true; + if (j,(void *) &chinrem_param[j]); + if (res) + thread_chinrem((void *)&chinrem_param[j]); + } // end creating threads + for (unsigned j=0;jg=it->g+u*(jt->g-it->g)*pmod; + continue; + } + if (it->g.type==_ZINT){ +#if 1 + int amodq=modulo(*it->g._ZINTptr,qmodval); + if (amodq==jt->g) + continue; + mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(jt->g-extend(amodq)))%qmodval); + mpz_add(*it->g._ZINTptr,*it->g._ZINTptr,tmpz); +#else + mpz_set_si(tmpz,jt->g); + mpz_sub(tmpz,tmpz,*it->g._ZINTptr); + mpz_mul_si(tmpz,*pmod._ZINTptr,(extend(U)*modulo(tmpz,qmodval))%qmodval); + mpz_add(*it->g._ZINTptr,*it->g._ZINTptr,tmpz); +#endif + } + else { + mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(extend(jt->g)-it->g.val))%qmodval); + if (it->g.val>=0) + mpz_add_ui(tmpz,tmpz,it->g.val); + else + mpz_sub_ui(tmpz,tmpz,-it->g.val); + it->g=tmpz; + } + } + mpz_clear(tmpz); + return true; + } + } +#endif + tmp.coord.clear(); tmp.dim=P.dim; tmp.order=P.order; + tmp.coord.reserve(P.coord.size()+3); // allow 3 more terms in Q without realloc + for (it=P.coord.begin(),jt=Q.coord.begin();it!=itend && jt!=jtend;){ + if (it->u==jt->u){ + gen g; +#ifndef USE_GMP_REPLACEMENTS + if (pmod.type==_ZINT){ + if (it->g.type==_ZINT){ + mpz_set_si(tmpz,jt->g); + mpz_sub(tmpz,tmpz,*it->g._ZINTptr); + mpz_mul_si(tmpz,*pmod._ZINTptr,(extend(U)*modulo(tmpz,qmodval))%qmodval); + mpz_add(tmpz,tmpz,*it->g._ZINTptr); + } + else { + mpz_mul_si(tmpz,*pmod._ZINTptr,(U*(extend(jt->g)-it->g.val))%qmodval); + if (it->g.val>=0) + mpz_add_ui(tmpz,tmpz,it->g.val); + else + mpz_sub_ui(tmpz,tmpz,-it->g.val); + } + g=tmpz; + } + else +#endif + g=it->g+u*(jt->g-it->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),it->u)); + ++it; ++jt; + continue; + } + if (tdeg_t_strictly_greater(it->u,jt->u,P.order)){ + if (debug_infolevel) + CERR << "chinrem: exponent mismatch using first " << '\n'; + gen g=it->g-u*(it->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),it->u)); + ++it; + } + else { + if (debug_infolevel) + CERR << "chinrem: exponent mismatch using second " << '\n'; + gen g=u*((jt->g)*pmod); + tmp.coord.push_back(T_unsigned(smod(g,pqmod),jt->u)); + ++jt; + } + } + if (it!=itend && debug_infolevel) + CERR << "chinrem (int): exponent mismatch at end using first #" << itend-it << '\n'; + for (;it!=itend;++it){ + gen g=it->g-u*(it->g)*pmod; + tmp.coord.push_back(T_unsigned(smod(g,pqmod),it->u)); + } + if (jt!=jtend && debug_infolevel) + CERR << "chinrem (int): exponent mismatch at end using second #" << jtend-jt << '\n'; + for (;jt!=jtend;++jt){ + gen g=u*((jt->g)*pmod); + tmp.coord.push_back(T_unsigned(smod(g,pqmod),jt->u)); + } + swap(P.coord,tmp.coord); + mpz_clear(tmpz); + return true; + } + + // set P mod p*q to be chinese remainder of P mod p and Q mod q + // P and Q must have same leading monomials, + // otherwise returns 0 and leaves P unchanged + template + int chinrem(vectpoly8 &P,const gen & pmod,const vectpolymod & Q,int qmod,poly8 & tmp,int start=0,int nthreads=1){ + if (P.size()!=Q.size()) + return 0; + for (unsigned i=start;i a*u+b*v=r, Bezout with a and b + bool fracmod(int a,int b,int & n,int & d){ + if (a<0){ + if (!fracmod(-a,b,n,d)) + return false; + n=-n; + return true; + } + int r=b,u=0; // v=1 + int r1=a,u1=1,r2,u2,q; // v1=0 + for (;double(2*r1)*r1>b;){ + q=r/r1; + u2=u-q*u1; + r2=r-q*r1; + u=u1; + u1=u2; + r=r1; + r1=r2; + } + if (double(2*u1)*u1>b) + return false; + if (u1<0){ u1=-u1; r1=-r1; } + n=r1; d=u1; + return true; + } + + // search for d such that d*P mod p has small coefficients + // call with d set to 1, + template + bool findmultmod(const poly8 & P,int p,int & d){ + int n,s=int(P.coord.size()); + for (int i=0;ip){ + if (debug_infolevel) + COUT << "findmultmod failure " << a << " mod " << p << '\n'; + return false; + } + d=d*d1; + } + if (debug_infolevel){ + for (int i=0;i=p){ + COUT << "possible findmultmod failure " << P.coord[i].g.val << " " << d << " " << a << " " << p << '\n'; + //return false; + } + } + } + return true; + } + + bool chk_equal_mod(const gen & a,const vector & p,int m){ + if (a.type!=_VECT || a._VECTptr->size()!=p.size()) + return false; + const_iterateur it=a._VECTptr->begin(),itend=a._VECTptr->end(); + vector::const_iterator jt=p.begin(); + for (;it!=itend;++jt,++it){ + if (it->type==_INT_ && it->val==*jt) continue; + if (!chk_equal_mod(*it,*jt,m)) + return false; + } + return true; + } + + bool chk_equal_mod(const vecteur & v,const vector< vector >& p,int m){ + if (v.size()!=p.size()) + return false; + for (unsigned i=0;i + bool chk_equal_mod(const poly8 & v,const polymod & p,int m){ + // sizes may differ if a coeff of v is 0 mod m + if (v.coord.size() + bool chk_equal_mod(const vectpoly8 & v,const vectpolymod & p,const vector & G,int m){ + if (v.size()!=G.size()) + return false; + for (unsigned i=0;i + bool chk_equal_mod(const poly8 & v,const poly8 & p,int m){ + if (v.coord.size()!=p.coord.size()) + return false; + unsigned s=unsigned(p.coord.size()); + int lc=smod(v.coord[0].g,m).val; + for (unsigned i=0;i + bool chk_equal_mod(const vectpoly8 & v,const vectpoly8 & p,const vector & G,int m){ + if (v.size()!=G.size()) + return false; + for (unsigned i=0;i + int fracmod(const poly8 &P,const gen & p, + mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t &u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t &sqrtm,mpz_t & tmp, + poly8 & Q, + polymod * chkptr=0,int chkp=0){ + Q.coord.clear(); + Q.coord.reserve(P.coord.size()); + Q.dim=P.dim; + Q.order=P.order; + Q.sugar=P.sugar; + gen L=1; + bool tryL=true; + for (unsigned i=0;i(g,P.coord[i].u)); + continue; + } + } + if (!in_fracmod(p,g,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp,num,den)) + return 0; + if (num.type==_ZINT && mpz_sizeinbase(*num._ZINTptr,2)<=30) + num=int(mpz_get_si(*num._ZINTptr)); + if (den.type==_ZINT && mpz_sizeinbase(*den._ZINTptr,2)<=30) + den=int(mpz_get_si(*den._ZINTptr)); + if (!is_positive(den,context0)){ // ok + den=-den; + num=-num; + } + g=fraction(num,den); + if (tryL){ + L=lcm(L,den); + tryL=is_greater(p,L*L,context0); + } + Q.coord.push_back(T_unsigned(g,P.coord[i].u)); + if (chkptr && !chk_equal_mod(g,chkptr->coord[i].g,chkp)){ + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " early fracmod chk failure position " << i << " (" << P.coord.size() << ")\n"; + return 2; + } + } + return 1; + } + + template + bool fracmod(const vectpoly8 & P,const gen & p_, + mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t &u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t &sqrtm,mpz_t & tmp, + vectpoly8 & Q){ + Q.resize(P.size()); + gen p=p_; + if (p.type==_INT_) + p.uncoerce(); + bool ok=true; + for (unsigned i=0;i + void cleardeno(poly8 &P){ + gen g=1; + for (unsigned i=0;iden); + } + if (g!=1){ + for (unsigned i=0;i + void cleardeno(vectpoly8 & P){ + if (debug_infolevel) + COUT << "clearing denominators of revlex gbasis "; + for (unsigned i=0;i + void collect(const vectpoly8 & f4buchbergerv,polymod & allf4buchberger){ + typename vectpoly8::const_iterator it=f4buchbergerv.begin(),itend=f4buchbergerv.end(); + vector > H; + H.reserve(itend-it); + order_t keyorder={_REVLEX_ORDER,0}; + for (unsigned i=0;it!=itend;++i,++it){ + keyorder=it->order; + if (!it->coord.empty()) + H.push_back(heap_tt(i,0,it->coord.front().u)); + } + compare_heap_tt key(keyorder); + make_heap(H.begin(),H.end(),key); + while (!H.empty()){ + std::pop_heap(H.begin(),H.end(),key); + // push root node of the heap in allf4buchberger + heap_tt & current =H.back(); + if (allf4buchberger.coord.empty() || allf4buchberger.coord.back().u!=current.u) + allf4buchberger.coord.push_back(T_unsigned(1,current.u)); + ++current.polymodpos; + if (current.polymodpos>=f4buchbergerv[current.f4buchbergervpos].coord.size()){ + H.pop_back(); + continue; + } + current.u=f4buchbergerv[current.f4buchbergervpos].coord[current.polymodpos].u; + std::push_heap(H.begin(),H.end(),key); + } + } + + template + void makeline(const poly8 & p,const tdeg_t * shiftptr,const polymod & R,vecteur & v){ + v=vecteur(R.coord.size(),0); + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + typename std::vector< T_unsigned >::const_iterator jt=R.coord.begin(),jtbeg=jt,jtend=R.coord.end(); + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v[jt-jtbeg]=it->g; + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v[jt-jtbeg]=it->g; + ++jt; + break; + } + } + } + } + } + + unsigned firstnonzero(const vecteur & v){ + for (unsigned i=0;i + void makeline(const poly8 & p,const tdeg_t * shiftptr,const polymod & R,vector & v){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + typename std::vector< T_unsigned >::const_iterator jt=R.coord.begin(),jtend=R.coord.end(); + if (shiftptr){ + for (;it!=itend;++it){ + tdeg_t u=it->u+*shiftptr; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v.push_back(sparse_gen(it->g,int(jt-R.coord.begin()))); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (jt->u==u){ + v.push_back(sparse_gen(it->g,int(jt-R.coord.begin()))); + ++jt; + break; + } + } + } + } + } + +#ifdef x86_64 + bool checkreducef4buchberger_64(vector &v,vector & coeff,const vector< vector > & M,modint env,vector & w){ + w.resize(v.size()); + vector::iterator vt=v.begin(),vtend=v.end(); + vector::iterator wt=w.begin(); + for (;vt!=vtend;++wt,++vt){ + *wt=*vt; + } + for (unsigned i=0;i & m=M[i]; + const sparse_element * it=&m.front(),*itend=it+m.size(),*it2; + if (it==itend) + continue; + int128_t & ww=w[it->pos]; + if (ww==0){ + coeff[i]=0; + continue; + } + modint c=coeff[i]=(extend(invmod(it->val,env))*ww)%env; + // CERR << "multiplier ok line " << i << " value " << c << " " << w << '\n'; + if (!c) + continue; + ww=0; + ++it; + it2=itend-8; + for (;it<=it2;){ + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + w[it->pos] -= extend(c)*(it->val); + ++it; + } + for (;it!=itend;++it){ + w[it->pos] -= extend(c)*(it->val); + } + } + for (vt=v.begin(),wt=w.begin();vt!=vtend;++wt,++vt){ + if (*wt && (*wt % env)) + return false; + } + return true; + } + + bool checkreducef4buchbergersplit_64(vector &v,vector & coeff,const vector< vector > & M,vector > & coeffs,vector & coeffindex,modint env,vector & w){ + w.resize(v.size()); + vector::iterator vt=v.begin(),vtend=v.end(); + vector::iterator wt=w.begin(),wtend=w.end(); + for (;vt!=vtend;++wt,++vt){ + *wt=*vt; + } + for (unsigned i=0;i & mcoeff=coeffs[coeffindex[i].u]; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(); + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=coeff[i]=(extend(invmod(*jt,env))*w[pos])%env; + w[pos]=0; + if (!c) + continue; + for (++jt;jt!=jtend;++jt){ +#ifdef GIAC_SHORTSHIFTTYPE + next_index(pos,it); + int128_t &x=w[pos]; + x -= extend(c)*(*jt); +#else + w[*it] -= extend(c)*(*jt); + ++it; +#endif + } + } + for (wt=w.begin();wt!=wtend;++wt){ + if (*wt % env) + return false; + } + return true; + } + +#endif + + // return true if v reduces to 0 + // in addition to reducef4buchberger, compute the coeffs + bool checkreducef4buchberger(vector &v,vector & coeff,const vector< vector > & M,modint env){ + for (unsigned i=0;i & m=M[i]; + vector::const_iterator it=m.begin(),itend=m.end(),it1=itend-8; + if (it==itend) + continue; + modint c=coeff[i]=v[it->pos]; + if (!c) + continue; + c=coeff[i]=(extend(invmod(it->val,env))*c)%env; + v[it->pos]=0; + for (++it;itpos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + x=&v[it->pos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + x=&v[it->pos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + x=&v[it->pos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + x=&v[it->pos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + x=&v[it->pos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + x=&v[it->pos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + x=&v[it->pos]; + *x=(*x-extend(c)*(it->val))%env; + ++it; + } + for (;it!=itend;++it){ + modint &x=v[it->pos]; + x=(x-extend(c)*(it->val))%env; + } + } + vector::iterator vt=v.begin(),vtend=v.end(); + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + return false; + } + return true; + } + + // return true if v reduces to 0 + // in addition to reducef4buchberger, compute the coeffs + bool checkreducef4buchbergersplit(vector &v,vector & coeff,const vector< vector > & M,vector > & coeffs,vector & coeffindex,modint env){ + for (unsigned i=0;i & mcoeff=coeffs[coeffindex[i].u]; + vector::const_iterator jt=mcoeff.begin(),jtend=mcoeff.end(); + if (jt==jtend) + continue; + const vector & mindex=M[i]; + const shifttype * it=&mindex.front(); + unsigned pos=0; + next_index(pos,it); + // if (pos>v.size()) CERR << "error" <<'\n'; + modint c=coeff[i]=(extend(invmod(*jt,env))*v[pos])%env; + v[pos]=0; + if (!c) + continue; + for (++jt;jt!=jtend;++jt){ +#ifdef GIAC_SHORTSHIFTTYPE + next_index(pos,it); + modint &x=v[pos]; +#else + modint &x=v[*it]; + ++it; +#endif + x=(x-extend(c)*(*jt))%env; + } + } + vector::iterator vt=v.begin(),vtend=v.end(); + for (vt=v.begin();vt!=vtend;++vt){ + if (*vt) + return false; + } + return true; + } + + // Find x=a mod amod and =b mod bmod + // We have x=a+A*amod=b+B*Bmod + // hence A*amod-B*bmod=b-a + // let u*amod+v*bmod=1 + // then A=(b-a)*u is a solution + // hence x=a+(b-a)*u*amod mod (amod*bmod) is the solution + // hence x=a+((b-a)*u mod bmod)*amod + static bool ichinrem_inplace(matrice & a,const vector< vector > &b,const gen & amod, int bmod){ + gen U,v,d; + egcd(amod,bmod,U,v,d); + if (!is_one(d) || U.type!=_ZINT) + return false; + int u=mpz_get_si(*U._ZINTptr); + longlong q; + for (unsigned i=0;ifront(), * aiend=ai+a[i]._VECTptr->size(); + const modint * bi = &b[i].front(); + for (;ai!=aiend;++bi,++ai){ + if (*bi==0 && ai->type==_INT_ && ai->val==0) + continue; + q=extend(*bi)-(ai->type==_INT_?ai->val:modulo(*ai->_ZINTptr,bmod)); + q=(q*u) % bmod; + if (amod.type==_ZINT && ai->type==_ZINT){ + if (q>=0) + mpz_addmul_ui(*ai->_ZINTptr,*amod._ZINTptr,int(q)); + else + mpz_submul_ui(*ai->_ZINTptr,*amod._ZINTptr,-int(q)); + } + else + *ai += int(q)*amod; + } + } + return true; + } + + template + gen linfnorm(const poly8 & p,GIAC_CONTEXT){ + gen B=0; + for (unsigned i=0;i + gen linfnorm(const vectpoly8 & v,GIAC_CONTEXT){ + gen B=0; + for (unsigned i=0;i0 the check is probabilistic + template + bool checkf4buchberger(vectpoly8 & f4buchbergerv,const vectpoly8 & res,vector & G,unsigned excluded,double eps){ + if (f4buchbergerv.empty()) + return true; + polymod allf4buchberger(f4buchbergerv.front().order,f4buchbergerv.front().dim),rem(allf4buchberger); + vectpolymod resmod,quo; + convert(res,resmod,0); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " checkf4buchberger begin collect monomials on #polys " << f4buchbergerv.size() << '\n'; + // collect all terms in f4buchbergerv + collect(f4buchbergerv,allf4buchberger); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " checkf4buchberger symbolic preprocess" << '\n'; + // find all monomials required to reduce allf4buchberger with res[G[.]] + polymod R; + in_heap_reducemod(allf4buchberger,resmod,G,excluded,quo,rem,&R,0); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " checkf4buchberger end symbolic preprocess" << '\n'; + // build a matrix with rows res[G[.]]*quo[.] in terms of monomials in allf4buchberger + // sort the matrix + // checking reduction to 0 is equivalent to + // write a line from f4buchbergerv[] + // as a linear combination of the lines of this matrix + // we will do that modulo a list of primes + // and keep track of the coefficients of the linear combination (the quotients) + // we reconstruct the quotients in Q by fracmod + // once they stabilize, we compute the lcm l of the denominators + // we multiply by l to have an equality on Z + // we compute bounds on the coefficients of the products res*quo + // and on l*f4buchbergerv, and we check further the equality modulo additional + // primes until the equality is proved + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin build M" << '\n'; + vector< vector > M; + vector atrier; + unsigned N=unsigned(R.coord.size()),i,j=0,nterms=0; + M.reserve(N); // actual size is at most N (difference is the remainder part size) + for (i=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + M.push_back(vector(0)); + makeline(res[G[i]],&jt->u,R,M[j]); + nterms += unsigned(M[j].size()); + atrier.push_back(sparse_element(M[j].front().pos,j)); + } + } + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector< vector > M1(atrier.size()); + for (i=0;i0) + CERR << CLOCK()*1e-6 << " rows, columns, terms: " << M.size() << "x" << N << "=" << nterms << '\n'; + // PSEUDO_MOD is not interesting here since there is no inter-reduction + gen p(int(extend(1<<31)-1)); + gen pip(1); + vectpolymod f4buchbergervmod; + matrice coeffmat; + vector< vector > coeffmatmodp(f4buchbergerv.size(),vector(M.size())); + gen bres=linfnorm(res,context0); + gen bf4buchberger=linfnorm(f4buchbergerv,context0); + matrice prevmatq; + bool stable=false; + gen bound=0; + for (int iter=0;;++iter){ + if (eps>0 && is_greater(eps*pip,1,context0)) + return true; + p=prevprime(p-1); + int env=p.val; + // check that p does not divide a leading monomial in M + unsigned j; + for (j=0;j > Mp(M.size()); + for (unsigned i=0;i & Mi=M[i]; + vector Ni; + Ni.reserve(Mi.size()); + for (unsigned j=0;j0) + CERR << CLOCK()*1e-6 << " checking mod " << p << '\n'; + vector v; + unsigned countres=0; +#ifdef x86_64 + vector v128; +#endif + for (unsigned i=0;i(f4buchbergervmod[i],0,R,v); +#if 0 // def x86_64 + if (!checkreducef4buchberger_64(v,coeffmatmodp[i],Mp,env,v128)) + return false; +#else + if (!checkreducef4buchberger(v,coeffmatmodp[i],Mp,env)) + return false; +#endif + if (iter==0){ + unsigned countrescur=0; + vector & coeffi=coeffmatmodp[i]; + for (unsigned j=0;jcountres) + countres=countrescur; + } + } + // if (iter==0) bound=pow(bres,int(countres),context0); + if (stable){ + if (!chk_equal_mod(prevmatq,coeffmatmodp,env)) + stable=false; + // if stable compute bounds and compare with product of primes + // if 2*bounds < product of primes recheck stabilization and return true + if (is_strictly_greater(pip,bound,context0)){ + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " modular check finished " << '\n'; + return true; + } + } + // combine coeffmat with previous one by chinese remaindering + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " chinrem mod " << p << '\n'; + if (iter) + ichinrem_inplace(coeffmat,coeffmatmodp,pip,p.val); + else + vectvector_int2vecteur(coeffmatmodp,coeffmat); + pip=pip*p; + if (is_greater(bound,pip,context0)) + continue; + if (!stable){ + // check stabilization + matrice checkquo; + checkquo.reserve(coeffmat.size()); + for (unsigned k=0;kk && chk_equal_mod(prevmatq[k],coeffmatmodp[k],env)) + checkquo.push_back(prevmatq[k]); + else + checkquo.push_back(fracmod(coeffmat[k],pip)); + if (prevmatq.size()>k && checkquo[k]!=prevmatq[k]) + break; + if (k>(prevmatq.size()*3)/2+2) + break; + } + if (checkquo!=prevmatq){ + swap(prevmatq,checkquo); + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " unstable mod " << p << " reconstructed " << prevmatq.size() << '\n'; + continue; + } + matrice coeffmatq=*_copy(checkquo,context0)._VECTptr; + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " full stable mod " << p << '\n'; + stable=true; + gen lall=1; vecteur l(coeffmatq.size()); + for (unsigned i=0;i0) + CERR << CLOCK()*1e-6 << " lcmdeno ok/start bound " << p << '\n'; + gen ball=1,bi; // ball is the max bound of all coeff in coeffmatq + for (unsigned i=0;i0 the check is probabilistic + template + bool checkf4buchbergersplit(vectpoly8 & f4buchbergerv,const vectpoly8 & res,vector & G,unsigned excluded,double eps){ + if (f4buchbergerv.empty()) + return true; + polymod allf4buchberger(f4buchbergerv.front().order,f4buchbergerv.front().dim),rem(allf4buchberger); + vectpolymod resmod,quo; + convert(res,resmod,0); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " checkf4buchberger split begin collect monomials on #polys " << f4buchbergerv.size() << '\n'; + // collect all terms in f4buchbergerv + collect(f4buchbergerv,allf4buchberger); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " checkf4buchberger split symbolic preprocess" << '\n'; + // find all monomials required to reduce allf4buchberger with res[G[.]] + polymod R; + in_heap_reducemod(allf4buchberger,resmod,G,excluded,quo,rem,&R,0); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " checkf4buchberger split end symbolic preprocess" << '\n'; + // build a matrix with rows res[G[.]]*quo[.] in terms of monomials in allf4buchberger + // sort the matrix + // checking reduction to 0 is equivalent to + // write a line from f4buchbergerv[] + // as a linear combination of the lines of this matrix + // we will do that modulo a list of primes + // and keep track of the coefficients of the linear combination (the quotients) + // we reconstruct the quotients in Q by fracmod + // once they stabilize, we compute the lcm l of the denominators + // we multiply by l to have an equality on Z + // we compute bounds on the coefficients of the products res*quo + // and on l*f4buchbergerv, and we check further the equality modulo additional + // primes until the equality is proved + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin build Mcoeff/Mindex" << '\n'; + vector< vector > Mcoeff(G.size()); + vector > Mindex; + vector coeffindex; + vector atrier; + unsigned N=unsigned(R.coord.size()),i,j=0,nterms=0; + Mindex.reserve(N); + atrier.reserve(N); + coeffindex.reserve(N); + for (i=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + Mindex.push_back(vector(0)); +#ifdef GIAC_SHORTSHIFTTYPE + Mindex[j].reserve(1+int(1.1*res[G[i]].coord.size())); +#else + Mindex[j].reserve(res[G[i]].coord.size()); +#endif + } + } + for (i=0,j=0;i >::const_iterator jt=quo[i].coord.begin(),jtend=quo[i].coord.end(); + for (;jt!=jtend;++j,++jt){ + coeffindex.push_back(coeffindex_t(N<0xffff,i)); + makelinesplit(res[G[i]],&jt->u,R,Mindex[j]); + atrier.push_back(sparse_element(first_index(Mindex[j]),j)); + } + } + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector< vector > Mindex1(atrier.size()); + vector coeffindex1(atrier.size()); + for (i=0;i0) + CERR << CLOCK()*1e-6 << " rows, columns, terms: " << Mindex.size() << "x" << N << "=" << nterms << '\n'; + // PSEUDO_MOD is not interesting here since there is no inter-reduction + gen p(int(extend(1<<31)-1)); + gen pip(1); + vectpolymod f4buchbergervmod; + matrice coeffmat; + vector< vector > coeffmatmodp(f4buchbergerv.size(),vector(Mindex.size())); + gen bres=linfnorm(res,context0); + gen bf4buchberger=linfnorm(f4buchbergerv,context0); + matrice prevmatq; + bool stable=false; + gen bound=0; + vector< vector > Mcoeffp(Mcoeff.size()); + for (int iter=0;;++iter){ + if (eps>0 && is_greater(eps*pip,1,context0)) + return true; + p=prevprime(p-1); + int env=p.val; + // check that p does not divide a leading monomial in M + unsigned j; + for (j=0;j & Mi=Mcoeff[i]; + vector & Ni=Mcoeffp[i]; + Ni.clear(); + Ni.reserve(Mi.size()); + for (unsigned j=0;j0) + CERR << CLOCK()*1e-6 << " checking mod " << p << '\n'; + vector v; + unsigned countres=0; +#ifdef x86_64 + vector v128; +#endif + for (unsigned i=0;i & coeffi=coeffmatmodp[i]; + for (unsigned j=0;jcountres) + countres=countrescur; + } + } + // if (iter==0) bound=pow(bres,int(countres),context0); + if (stable){ + if (!chk_equal_mod(prevmatq,coeffmatmodp,env)) + stable=false; + // if stable compute bounds and compare with product of primes + // if 2*bounds < product of primes recheck stabilization and return true + if (is_strictly_greater(pip,bound,context0)){ + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " modular check finished " << '\n'; + return true; + } + } + // combine coeffmat with previous one by chinese remaindering + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " chinrem mod " << p << '\n'; + if (iter) + ichinrem_inplace(coeffmat,coeffmatmodp,pip,p.val); + else + vectvector_int2vecteur(coeffmatmodp,coeffmat); + pip=pip*p; + if (is_greater(bound,pip,context0)) + continue; + if (!stable){ + // check stabilization + matrice checkquo; + checkquo.reserve(coeffmat.size()); + for (unsigned k=0;kk && chk_equal_mod(prevmatq[k],coeffmatmodp[k],env)) + checkquo.push_back(prevmatq[k]); + else + checkquo.push_back(fracmod(coeffmat[k],pip)); + if (prevmatq.size()>k && checkquo[k]!=prevmatq[k]) + break; + if (k>(prevmatq.size()*3)/2+2) + break; + } + if (checkquo!=prevmatq){ + swap(prevmatq,checkquo); + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " unstable mod " << p << " reconstructed " << prevmatq.size() << '\n'; + continue; + } + matrice coeffmatq=*_copy(checkquo,context0)._VECTptr; + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " full stable mod " << p << '\n'; + stable=true; + gen lall=1; vecteur l(coeffmatq.size()); + for (unsigned i=0;i0) + CERR << CLOCK()*1e-6 << " lcmdeno ok/start bound " << p << '\n'; + gen ball=1,bi; // ball is the max bound of all coeff in coeffmatq + for (unsigned i=0;i)=28 or 36 + // typedef T_unsigned zmodint; + template + struct zpolymod { + order_t order; + short int dim; + bool in_gbasis; // set to false in zgbasis_updatemod for "small" reductors that we still want to use for reduction + short int age:15; + vector< T_unsigned > coord; + const vector * expo; + tdeg_t ldeg; + int maxtdeg; + int fromleft,fromright; + double logz; + zpolymod():in_gbasis(true),dim(0),expo(0),ldeg(),age(0),fromleft(-1),fromright(-1),logz(1) {order.o=0; order.lex=0; order.dim=0; maxtdeg=-1;} + zpolymod(order_t o,int d): in_gbasis(true),dim(d),expo(0),ldeg(),age(0),fromleft(-1),fromright(-1),logz(1) {order=o; order.dim=d; maxtdeg=-1;} + zpolymod(order_t o,int d,const tdeg_t & l): in_gbasis(true),dim(d),expo(0),ldeg(l),age(0),fromleft(-1),fromright(-1),logz(1) {order=o; order.dim=d; maxtdeg=-1;} + zpolymod(order_t o,int d,const vector * e,const tdeg_t & l): in_gbasis(true),dim(d),expo(e),ldeg(l),age(0),fromleft(-1),fromright(-1),logz(1) {order=o; order.dim=d; maxtdeg=-1;} + void dbgprint() const; + void compute_maxtdeg(){ + if (expo){ + typename std::vector< T_unsigned >::iterator pt=coord.begin(),ptend=coord.end(); + for (;pt!=ptend;++pt){ + int tmp=(*expo)[pt->u].total_degree(order); + if (tmp>maxtdeg) + maxtdeg=tmp; + } + } + } + }; + + template + struct zinfo_t { + vector< vector > quo; + vector R,rem; + vector permu; + vector< paire > B; + vector G,permuB; + unsigned nonzero,Ksizes; + }; + + template + void zsmallmultmod(modint_t a,zpolymod & p,modint_t m){ + typename std::vector< T_unsigned >::iterator pt=p.coord.begin(),ptend=p.coord.end(); +#if 1 // ndef GBASIS_4PRIMES + if (a==1 || a==create(1)-m){ + for (;pt!=ptend;++pt){ + modint_t tmp=pt->g; + pt->g=makepositive(tmp,m); + // if (tmp<0) tmp += m; pt->g=tmp; + } + return; + } +#endif + for (;pt!=ptend;++pt){ + modint_t tmp=(extend(pt->g)*a)%m; + pt->g=makepositive(tmp,m); // if (tmp<0) tmp += m; pt->g=tmp; + } + } + + template + bool operator == (const zpolymod & p,const zpolymod &q){ + if (p.coord.size()!=q.coord.size() || p.expo!=q.expo) + return false; + for (unsigned i=0;i + nio::ios_base & operator << (nio::ios_base & os, const zpolymod & p) +#else + template + ostream & operator << (ostream & os, const zpolymod & p) +#endif + { + if (!p.expo) + return os << "error, null pointer in expo " ; + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + int t2; + os << "zpolymod(" << p.logz << "," << p.age << ":" << p.fromleft << "," << p.fromright << "): "; + if (it==itend) + return os << 0 ; + for (;it!=itend;){ + os << it->g ; +#ifndef GBASIS_NO_OUTPUT + if ((*p.expo)[it->u].vars64()){ + if ((*p.expo)[it->u].tdeg%2){ + degtype * i=(degtype *)((*p.expo)[it->u].ui+1); + for (int j=0;j<(*p.expo)[it->u].order_.dim;++j){ + t2=i[j]; + if (t2) + os << "*x"<< j << "^" << t2 ; + } + ++it; + if (it==itend) + break; + os << " + "; + continue; + } + } +#endif + short tab[GROEBNER_VARS+1]; + (*p.expo)[it->u].get_tab(tab,p.order); + switch (p.order.o){ + case _PLEX_ORDER: + for (int i=0;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2) + os << "*x"<< i << "^" << t2 ; + } + break; + case _TDEG_ORDER: + for (int i=1;i<=GROEBNER_VARS;++i){ + t2 = tab[i]; + if (t2==0) + continue; + if (t2) + os << "*x"<< i-1 << "^" << t2 ; + } + break; + case _REVLEX_ORDER: + for (int i=1;i<=GROEBNER_VARS && i<=p.dim;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; +#if GROEBNER_VARS==15 + case _3VAR_ORDER: + for (int i=1;i<=3;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 3-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=5;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 7+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; + case _7VAR_ORDER: + for (int i=1;i<=7;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 7-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=9;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 11+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; + case _11VAR_ORDER: + for (int i=1;i<=11;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 11-i; + if (t2!=1) + os << "^" << t2; + } + for (int i=13;i<=15;++i){ + t2 = tab[i]; + if (t2==0) + continue; + os << "*x"<< 15+p.dim-i; + if (t2!=1) + os << "^" << t2; + } + break; +#endif + } + ++it; + if (it==itend) + break; + os << " + "; + } + return os; + } + + template + void zpolymod::dbgprint() const { + CERR << *this << '\n'; + } + + template + class vectzpolymod:public vector< zpolymod >{ + public: + void dbgprint() const { CERR << *this << '\n'; } + }; + + template + void zleftright(const vectzpolymod & res,const vector< paire > & B,vector & leftshift,vector & rightshift){ + tdeg_t l; + for (unsigned i=0;i & p=res[B[i].first]; + const zpolymod & q=res[B[i].second]; + if (debug_infolevel>2) + CERR << "zleftright " << p << "," << q << '\n'; + index_lcm_overwrite(p.ldeg,q.ldeg,l,p.order); + leftshift[i]=l-p.ldeg; + rightshift[i]=l-q.ldeg; + } + } + + // collect monomials from pairs of res (vector of polymods), shifted by lcm + // does not collect leading monomial (since they cancel) + template + bool zcollect(const vectzpolymod & res,const vector< paire > & B,const vector & permuB,vector & allf4buchberger,vector & leftshift,vector & rightshift){ + int start=1,countdiscarded=0; + vector > Ht; + heap_tt heap_elem; + vector > H; + Ht.reserve(2*B.size()+1); + H.reserve(2*B.size()); + unsigned s=0; + order_t keyorder={_REVLEX_ORDER,0}; + for (unsigned i=0;i & p=res[Bi.first]; + const zpolymod & q=res[Bi.second]; + keyorder=p.order; + bool eq=i>0 && Bi.second==B[permuB[i-1]].second && rightshift[truei]==rightshift[permuB[i-1]]; + if (int(p.coord.size())>start){ + s = giacmax(s, unsigned(p.coord.size())); + Ht.push_back(heap_tt(true,truei,start,(*p.expo)[p.coord[start].u]+leftshift[truei])); + H.push_back(heap_tt_ptr(&Ht.back())); + } + if (!eq && int(q.coord.size())>start){ + s = giacmax(s, unsigned(q.coord.size())); + Ht.push_back(heap_tt(false,truei,start,(*q.expo)[q.coord[start].u]+rightshift[truei])); + H.push_back(heap_tt_ptr(&Ht.back())); + } + } + allf4buchberger.reserve(s); // int(s*std::log(1+H.size()))); + compare_heap_tt_ptr key(keyorder); + make_heap(H.begin(),H.end(),key); + while (!H.empty()){ + // push root node of the heap in allf4buchberger + heap_tt & current = *H.front().ptr; + if (int(current.u.total_degree(keyorder))>GBASISF4_MAX_TOTALDEG){ + CERR << "Error zcollect total degree too large" << current.u.total_degree(keyorder) << '\n'; + return false; + } + if (allf4buchberger.empty() || allf4buchberger.back()!=current.u) + allf4buchberger.push_back(current.u); + unsigned vpos; + if (current.left) + vpos=B[current.f4buchbergervpos].first; + else + vpos=B[current.f4buchbergervpos].second; + ++current.polymodpos; + const zpolymod & resvpos=res[vpos]; + for (int startheappos=1;current.polymodpos & heapcurrent=*H[heappos].ptr; + int heapcurtdeg=heapcurrent.u.total_degree(keyorder); + if (heapcurtdeg(¤t)); + std::push_heap(H.begin(),H.end(),key); // ?clang + } + std::pop_heap(H.begin(),H.end(),key); + H.pop_back(); + } + if (debug_infolevel>1) + CERR << "pairs " << B.size() << ", discarded monomials " << countdiscarded << '\n'; + return true; + } + + // returns heap actual size, 0 means no quotients (all elements of q empty()) +template + size_t zsymbolic_preprocess(const vector & f,const vectzpolymod & g,const vector & G,unsigned excluded,vector< vector > & q,vector & rem,vector & R){ + int countdiscarded=0; + // divides f by g[G[0]] to g[G[G.size()-1]] except maybe g[G[excluded]] + // CERR << f << "/" << g << '\n'; + // first implementation: use quotient heap for all quotient/divisor + // do not use heap chain + // ref Monaghan Pearce if g.size()==1 + // R is the list of all monomials + if (f.empty() || G.empty()) + return 0; + int dim=g[G.front()].dim; + order_t order=g[G.front()].order; +#ifdef GIAC_GBASIS_PERMUTATION1 + // First reorder G in order to use the "best" possible reductor + // This is done using the ldegree of g[G[i]] (should be minmal) + // and the number of terms (should be minimal) + vector > GG(G.size()); + for (unsigned i=0;i zz={i,g[G[i]].ldeg,g[G[i]].order,unsigned(g[G[i]].coord.size()),g[G[i]].age,0.0}; + GG[i]=zz; + } + sort(GG.begin(),GG.end()); +#endif + tdeg_t minldeg(g[G.front()].ldeg); + R.clear(); + rem.clear(); + // if (G.size()>q.size()) q.clear(); + q.resize(G.size()); + unsigned guess=0; + for (unsigned i=0;i > H_; + vector H; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " Heap reserve " << 3*f.size() << " * " << sizeof(heap_t)+sizeof(unsigned) << ", number of monomials in basis " << guess << '\n'; + // H_.reserve(guess); + // H.reserve(guess); + H_.reserve(3*f.size()); + H.reserve(3*f.size()); + heap_t_compare key(H_,order); + unsigned k=0,i; // k=position in f + tdeg_t m; + bool finish=false; + while (!H.empty() || k & current=H_[H.front()]; // was root node of the heap + const zpolymod & gcurrent = g[G[current.i]]; + ++current.gj; + for (int startheappos=1;current.gj & heapcurrent=H_[H[heappos]]; + int heapcurtdeg=heapcurrent.u.total_degree(order); + if (heapcurtdegmtot){ + ii=G.size(); break; + } +#endif + if (tdeg_t_all_greater(m,deg,order)) + break; + } + if (ii==G.size()){ + rem.push_back(m); // add to remainder + // no monomial divide m, check if m is greater than one of the monomial of G + // if not we can push all remaining monomials in rem + finish=!tdeg_t_greater(m,minldeg,order); + continue; + } + // add m/leading monomial of g[G[i]] to q[i] + const zpolymod & gGi=g[G[i]]; + tdeg_t monom=m-gGi.ldeg; + q[i].push_back(monom); + // CERR << i << " " << q[i] << '\n'; + // push in heap + int startheappos=0; + for (int pos=1;pos & current=H_[H[heappos]]; + int curtdeg=current.u.total_degree(order); + if (curtdeg current = { i, unsigned(q[i].size()) - 1, pos, newmonom }; +#else + heap_t current = { i, unsigned(q[i].size()) - 1, unsigned(pos), (*gGi.expo)[gGi.coord[pos].u] + monom }; +#endif + H.push_back(hashgcd_U(H_.size())); + H_.push_back(current); + key.ptr=&H_.front(); + std::push_heap(H.begin(),H.end(),key); + break; + } + } // end main heap pseudo-division loop + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " Heap actual size was " << H_.size() << " discarded monomials " << countdiscarded << '\n'; + return H_.size(); + } + + template + void zcopycoeff(const zpolymod & p,vector & v,modint_t env,int start){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(); + v.clear(); + v.reserve(itend-it); + for (;it!=itend;++it){ + modint_t g=it->g; + if (g<0) g += env; + v.push_back(g); + } + } + + template + void zcopycoeff(const zpolymod & p,vector & v,int start){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(); + v.clear(); + v.reserve(itend-it); + for (;it!=itend;++it){ + modint_t g=it->g; + v.push_back(g); + } + } + + // dichotomic seach for jt->u==u in [jt,jtend[ + template + bool dicho(typename std::vector::const_iterator & jt,typename std::vector::const_iterator jtend,const tdeg_t & u,order_t order){ + if (*jt==u) return true; + if (jtend-jt<=6){ ++jt; return false; }// == test faster + for (;;){ + int step=int((jtend-jt)/2); + typename std::vector::const_iterator j=jt+step; + if (j==jt) + return *j==u; + //PREFETCH(&*(j+step/2)); + //PREFETCH(&*(jt+step/2)); + if (int res=tdeg_t_greater(*j,u,order)){ + jt=j; + if (res==2) + return true; + } + else + jtend=j; + } + } + +#if 1 // #if 0 for old versions of gcc + template<> + bool dicho(std::vector::const_iterator & jt,std::vector::const_iterator jtend,const tdeg_t64 & u,order_t order){ + if (*jt==u) return true; + if (jtend-jt<=6){ ++jt; return false; }// == test faster +#ifdef GIAC_ELIM + if (u.tab[0]%2){ + int utdeg=u.tab[0],utdeg2=u.tdeg2; + ulonglong uelim=u.elim; + for (;;){ + int step=(jtend-jt)/2; + std::vector::const_iterator j=jt+step; + if (j==jt) + return *j==u; + if (j->tab[0]!=utdeg){ + if (j->tdeg>utdeg) + jt=j; + else + jtend=j; + continue; + } + if (j->tdeg2!=utdeg2){ + if (j->tdeg2>utdeg2) + jt=j; + else + jtend=j; + continue; + } + if (j->elim!=uelim){ + if (j->elim::const_iterator j=jt+step; + if (j==jt) + return *j==u; + if (int res=tdeg_t_greater(*j,u,order)){ + jt=j; + if (res==2) + return true; + } + else + jtend=j; + } + } +#endif + + template + void zmakelinesplit(const zpolymod & p,const tdeg_t * shiftptr,const vector & R,void * Rhashptr,const vector & Rdegpos,vector & v,vector * prevline,int start=0){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(); + typename std::vector::const_iterator Rbegin=R.begin(),jt=Rbegin,jtend=R.end(); + double nop1=double(R.size()); + double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0); + bool dodicho=nop2 & expo=*p.expo; + unsigned pos=0,Rpos=0; + if (shiftptr){ + tdeg_t u=*shiftptr+*shiftptr; // create a new memory slot + const shifttype * st=prevline?&prevline->front():0; + for (;it!=itend;++it){ + add(expo[it->u],*shiftptr,u,p.dim); +#ifdef GIAC_RHASH + int hashi=u.hash_index(Rhashptr); + if (hashi>=0){ + pushsplit(v,pos,hashi); + ++jt; + continue; + } +#endif + if (dodicho){ + typename std::vector::const_iterator end=jtend; + if (st){ + next_index(Rpos,st); + end=Rbegin+Rpos; + } +#ifdef GIAC_RDEG + int a=Rdegpos[u.tdeg+1],b=Rdegpos[u.tdeg]; + if (jt-Rbeginb) + end=Rbegin+b; +#endif + if (dicho(jt,end,u,p.order)){ + pushsplit(v,pos,unsigned(jt-Rbegin)); + ++jt; + continue; + } + } + for (;jt!=jtend;++jt){ + if (*jt==u){ + pushsplit(v,pos,int(jt-Rbegin)); + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=expo[it->u]; +#ifdef GIAC_RHASH + int hashi=u.hash_index(Rhashptr); + if (hashi>=0){ + pushsplit(v,pos,hashi); + ++jt; + continue; + } +#endif +#if 1 + if (dodicho && dicho(jt,jtend,u,p.order)){ + pushsplit(v,pos,unsigned(jt-Rbegin)); + ++jt; + continue; + } +#endif + for (;jt!=jtend;++jt){ + if (*jt==u){ + pushsplit(v,pos,int(jt-Rbegin)); + ++jt; + break; + } + } + } + } + } + + template + void zmakeline(const zpolymod & p,const tdeg_t * shiftptr,const vector & R,vector & v,int start=0){ + int Rs=int(R.size()); + // if (v.size()!=Rs) v.resize(Rs); + // v.assign(Rs,0); + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(); + typename std::vector::const_iterator jt=R.begin(),jtbeg=jt,jtend=R.end(); + double nop1=double(R.size()); + double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0); + bool dodicho=nop2 & expo=*p.expo; + if (shiftptr){ + tdeg_t u=R.front()+R.front(); // create u with refcount 1 + for (;it!=itend;++it){ + add(expo[it->u],*shiftptr,u,p.dim); + if (dodicho && dicho(jt,jtend,u,p.order)){ + v[jt-jtbeg]=it->g; + ++jt; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==u){ + v[jt-jtbeg]=it->g; + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=expo[it->u]; + if (dodicho && dicho(jt,jtend,u,p.order)){ + v[jt-jtbeg]=it->g; + ++jt; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==u){ + v[jt-jtbeg]=it->g; + ++jt; + break; + } + } + } + } + } + + template + void zmakelinesub(const zpolymod & p,const tdeg_t * leftshift,const zpolymod & q,const tdeg_t * rightshift,const vector & R,vector & v,int start,modint_t env){ + typename std::vector< T_unsigned >::const_iterator pt=p.coord.begin()+start,ptend=p.coord.end(); + typename std::vector< T_unsigned >::const_iterator qt=q.coord.begin()+start,qtend=q.coord.end(); + typename std::vector::const_iterator jt=R.begin(),jtbeg=jt,jtend=R.end(); + const std::vector & pexpo=*p.expo; + const std::vector & qexpo=*q.expo; + double nop1=double(R.size()); + double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0); + bool dodicho=nop2u],*leftshift,ul,dim); + updatep=false; + } + if (updateq){ + add(qexpo[qt->u],*rightshift,ur,dim); + updateq=false; + } + if (tdeg_t_greater(ul,ur,order)){ + if (dodicho && dicho(jt,jtend,ul,order)){ + if (ul==ur){ + v[jt-jtbeg] = (pt->g-extend(qt->g)); // %env; + ++jt; ++pt; ++qt; + updatep=updateq=true; + continue; + } + v[jt-jtbeg] = pt->g; + ++jt; ++pt; + updatep=true; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==ul){ + if (ul==ur){ + v[jt-jtbeg] = (pt->g-extend(qt->g)); // %env; + ++jt; ++pt; ++qt; + updatep=updateq=true; + } + else { + v[jt-jtbeg] = pt->g; + ++jt; ++pt; + updatep=true; + } + break; + } + } + continue; + } // end if ul>=ur + if (dodicho && dicho(jt,jtend,ur,order)){ + v[jt-jtbeg] = -qt->g; + ++jt; ++qt; + updateq=true; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==ur){ + v[jt-jtbeg] = -qt->g; + ++jt; ++qt; + updateq=true; + break; + } + } + } // for (pt!=ptend && qt!=qtend) + for (;pt!=ptend;){ + add(pexpo[pt->u],*leftshift,ul,dim); + if (dodicho && dicho(jt,jtend,ul,order)){ + v[jt-jtbeg] = pt->g; + ++jt; ++pt; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==ul){ + v[jt-jtbeg] = pt->g; + ++jt; ++pt; + break; + } + } + } + for (;qt!=qtend;){ + add(qexpo[qt->u],*rightshift,ur,dim); + if (dodicho && dicho(jt,jtend,ur,order)){ + v[jt-jtbeg] = -qt->g; + ++jt; ++qt; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==ur){ + v[jt-jtbeg] = -qt->g; + ++jt; ++qt; + break; + } + } + } + } + } + + template + void zmakelinesub(const zpolymod & p,const tdeg_t * shiftptr,const vector & R,vector & v,int start,modint_t env){ + typename std::vector< T_unsigned >::const_iterator it=p.coord.begin()+start,itend=p.coord.end(); + typename std::vector::const_iterator jt=R.begin(),jtbeg=jt,jtend=R.end(); + const std::vector & expo=*p.expo; + double nop1=double(R.size()); + double nop2=2*p.coord.size()*std::log(nop1)/std::log(2.0); + bool dodicho=nop2u],*shiftptr,u,p.dim); + if (dodicho && dicho(jt,jtend,u,p.order)){ +#if 1 + v[jt-jtbeg] -= it->g; +#else + modint_t & vv=v[jt-jtbeg]; + if (vv) + vv = (vv-extend(it->g))%env; + else + vv=-it->g; +#endif + ++jt; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==u){ +#if 1 + v[jt-jtbeg] -= it->g; +#else + modint_t & vv=v[jt-jtbeg]; + if (vv) + vv = (vv-extend(it->g));//%env; + else + vv = -it->g; +#endif + ++jt; + break; + } + } + } + } + else { + for (;it!=itend;++it){ + const tdeg_t & u=expo[it->u]; + if (dodicho && dicho(jt,jtend,u,p.order)){ +#if 1 + v[jt-jtbeg] -= it->g; +#else + modint_t & vv=v[jt-jtbeg]; + vv = (vv-extend(it->g))%env; +#endif + ++jt; + continue; + } + for (;jt!=jtend;++jt){ + if (*jt==u){ +#if 1 + v[jt-jtbeg]-=it->g; +#else + modint_t & vv=v[jt-jtbeg]; + vv = (vv-extend(it->g))%env; +#endif + ++jt; + break; + } + } + } + } + } + + template + void zsub(vector & v64,const vector & subcoeff,const vector & subindex){ + if (subcoeff.empty()) return; + typename vector::iterator wt=v64.begin(); + const modint_t * jt=&subcoeff.front(),*jtend=jt+subcoeff.size(),*jt_=jtend-8; + const shifttype * it=&subindex.front(); + // first shift + unsigned pos=0; next_index(pos,it); wt += pos; + *wt -= (*jt); ++jt; + bool shortshifts=v64.size()<0xffff?true:checkshortshifts(subindex); +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ +#if GIAC_SHORTSHIFTTYPE==16 && !defined BIGENDIAN + if ( jt>16); + *wt -= (*jt); ++jt; + it+=2; + } + jtend+=2; +#endif + for (;jt!=jtend;++jt){ + wt += *it; ++it; + *wt -= (*jt); + } + } + else { + for (;jt!=jtend;++jt){ + next_index(wt,it); + *wt -= (*jt); + } + } +#else // def GIAC_SHORTSHIFTTYPE + for (;jt!=jtend;++jt){ + v64[*it] -= (*jt); + ++it; ++jt; + } +#endif // def GIAC_SHORTSHIFTTYPE + } + + template + void zadd(vector & v64,const zpolymod & subcoeff,const vector & subindex,int start,modint_t env){ + if (subcoeff.coord.size()<=start) return; + typename vector::iterator wt=v64.begin(); + const T_unsigned * jt=&subcoeff.coord.front(),*jtend=jt+subcoeff.coord.size(); + jt += start; + const shifttype * it=&subindex.front(); + // first shift + unsigned pos=0; next_index(pos,it); wt += pos; + *wt = extend(makepositive(jt->g,env)); ++jt; + bool shortshifts=v64.size()<0xffff?true:checkshortshifts(subindex); +#ifdef GIAC_SHORTSHIFTTYPE + if (shortshifts){ +#if 1 && GIAC_SHORTSHIFTTYPE==16 && !defined BIGENDIAN + if ( jtg,env)); + ++jt; + } + jtend-=2; + for (;jt<=jtend;){ + unsigned * IT=(unsigned *) it; + wt += ((*IT)&0xffff); + *wt = extend(makepositive(jt->g,env)); + ++jt; + wt += ((*IT)>>16); + *wt = extend(makepositive(jt->g,env)); + ++jt; + it+=2; + } + jtend+=2; +#endif + for (;jt!=jtend;++jt){ + wt += *it; ++it; + *wt = extend(makepositive(jt->g,env)); + } + } + else { + for (;jt!=jtend;++jt){ + next_index(wt,it); + *wt = extend(makepositive(jt->g,env)); + } + } +#else // def GIAC_SHORTSHIFTTYPE + for (;jt!=jtend;++jt){ + v64[*it] = extend(makepositive(jt->g,env)); + ++it; ++jt; + } +#endif // def GIAC_SHORTSHIFTTYPE + } + + template + void zcollect_interreduce(const vectzpolymod & res,const vector< unsigned > & G,vector & allf4buchberger,int start){ + vector< heap_tt > Ht; + heap_tt heap_elem; + vector< heap_tt_ptr > H; + Ht.reserve(2*G.size()+1); + H.reserve(2*G.size()); + unsigned s=0; + order_t keyorder={_REVLEX_ORDER,0}; + for (unsigned i=0;i & p=res[G[i]]; + keyorder=p.order; + if (int(p.coord.size())>start){ + s = giacmax(s, unsigned(p.coord.size())); + Ht.push_back(heap_tt(true,i,start,(*p.expo)[p.coord[start].u])); + H.push_back(heap_tt_ptr(&Ht.back())); + } + } + allf4buchberger.reserve(s); // int(s*std::log(1+H.size()))); + compare_heap_tt_ptr key(keyorder); + make_heap(H.begin(),H.end(),key); + while (!H.empty()){ + // push root node of the heap in allf4buchberger + heap_tt & current = *H.front().ptr; + if (allf4buchberger.empty() || allf4buchberger.back()!=current.u) + allf4buchberger.push_back(current.u); + ++current.polymodpos; + unsigned vpos; + vpos=G[current.f4buchbergervpos]; + if (current.polymodpos>=res[vpos].coord.size()){ + std::pop_heap(H.begin(),H.end(),key); + H.pop_back(); + continue; + } + const zpolymod & resvpos=res[vpos]; + current.u=(*resvpos.expo)[resvpos.coord[current.polymodpos].u]; + // push_back ¤t into heap so that pop_heap will bubble out the + // modified root node (initialization will exchange two identical pointers) + H.push_back(heap_tt_ptr(¤t)); + std::push_heap(H.begin(),H.end(),key); //?clang + std::pop_heap(H.begin(),H.end(),key); + H.pop_back(); + } + } + + template + int zf4mod(vectzpolymod & res,const vector & G,modint_t env,const vector< paire > & B,const vector * & permuBptr,vectzpolymod & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector > & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,int interreduce); + + template + int zinterreduce_convert(vectzpolymod & res,vector< unsigned > & G,modint_t env,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector > & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,vectpolymod & resmod,bool interred){ + if (!interred) + return 12345; + if (res.empty()){ resmod.clear(); return 0; } + order_t order=res.front().order; + int dim=res.front().dim; + unsigned Gs=G.size(); + // if (parallel<2 || Gs<200 || !threads_allowed ) return -1; // or fix in computeK1 non parallel case + vector B; // not used + const vector * permuBptr=0; // not used + vectzpolymod f4buchbergerv; + int tmp=zf4mod(res,G,env,B,permuBptr,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,1); + //CERR << "interreduce " << tmp << '\n'; + if (tmp<0 || tmp==12345) + return tmp; + // build resmod from res leading monomial of res and f4buchbergerv + ulonglong tot=0; + for (unsigned i=0;i & q=resmod[G[i]]; + zpolymod & p=f4buchbergerv[i]; + const vector & expo=*p.expo; + q.dim=res[G[i]].dim; + q.order=res[G[i]].order; + q.fromleft=res[G[i]].fromleft; + q.fromright=res[G[i]].fromright; + q.age=res[G[i]].age; + q.logz=res[G[i]].logz; + q.coord.clear(); + q.coord.reserve(1+p.coord.size()); + if (res[G[i]].coord.empty()) + return -1; + q.coord.push_back(T_unsigned(res[G[i]].coord[0].g,(*res[G[i]].expo)[res[G[i]].coord[0].u])); + for (unsigned j=0;j(g,expo[p.coord[j].u])); + } + } + return 0; + } + + template + void Rtorem(const vector & R,const vector & rem,vector & v){ + v.resize(R.size()); + typename vector::const_iterator it=R.begin(),itend=R.end(),jt=rem.begin(),jt0=jt,jtend=rem.end(); + vector::iterator vt=v.begin(); + for (;jt!=jtend;++jt){ + const tdeg_t & t=*jt; + for (;it!=itend;++vt,++it){ + if (*it==t) + break; + } + *vt=hashgcd_U(jt-jt0); + } + } + + template + struct thread_buchberger_t { + const vectzpolymod * resptr; + vector< vector< modint_t> > * Kptr; + const vector * G; + const vector< paire > * Bptr; + const vector * permuBptr; + const vector *leftshiftptr,*rightshiftptr,*Rptr; + void * Rhashptr; + const vector * Rdegposptr; + modint_t env; + int debut,fin,N,colonnes; + const vector * firstposptr; + const vector > * Mindexptr; + const vector< vector > * Mcoeffptr; + const vector * coeffindexptr; + vector< vector > * indexesptr; + vector * usedptr; + unsigned * bitmap; + bool displayinfo; + bool learning; + short int interreduce; + const vector * pairs_reducing_to_zero; // read-only! + int learned_position; + }; + + template + void * thread_buchberger(void * ptr_){ + thread_buchberger_t * ptr=(thread_buchberger_t *) ptr_; + const vectzpolymod & res=*ptr->resptr; + vector< vector > & K =*ptr->Kptr; + const vector< paire > & B = *ptr->Bptr; + const vector & G = *ptr->G; + const vector & permuB = *ptr->permuBptr; + const vector & leftshift=*ptr->leftshiftptr; + const vector & rightshift=*ptr->rightshiftptr; + const vector & R=*ptr->Rptr; + void * Rhashptr=ptr->Rhashptr; + const vector & Rdegpos=*ptr->Rdegposptr; + modint_t env=ptr->env; + int debut=ptr->debut,fin=ptr->fin,N=ptr->N; + const vector & firstpos=*ptr->firstposptr; + int & colonnes=ptr->colonnes; + const vector > &Mindex = *ptr->Mindexptr; + const vector< vector > &Mcoeff = *ptr->Mcoeffptr; + const vector &coeffindex = *ptr->coeffindexptr; + vector< vector > & indexes=*ptr->indexesptr; + vector & used = *ptr->usedptr; + bool learning=ptr->learning; + int interreduce=ptr->interreduce; + int pos=ptr->learned_position; + const vector * pairs_reducing_to_zero=ptr->pairs_reducing_to_zero; + bool displayinfo=ptr->displayinfo; + unsigned * bitmap=ptr->bitmap+debut*((N>>5)+1); + vector v64(N); + unsigned bk_prev=-1; + const tdeg_t * rightshift_prev =0; + vector subcoeff2; + int effi=-1,Bs=int(B.size()); + if (interreduce){ + // tdeg_t nullshift(res[G[0]].dim); + for (int i=debut;i>5)+1; + } + return ptr_; + } + for (int i=debut;isize() && bk==(*pairs_reducing_to_zero)[pos]){ + ++pos; + continue; + } + // no learning with parallel + zmakelinesplit(res[bk.first],&leftshift[permuB[i]],R,Rhashptr,Rdegpos,indexes[i],0,1); + if (bk_prev!=bk.second || !rightshift_prev || *rightshift_prev!=rightshift[permuB[i]]){ + zmakelinesplit(res[bk.second],&rightshift[permuB[i]],R,Rhashptr,Rdegpos,indexes[Bs+i],0,1); + bk_prev=bk.second; + rightshift_prev=&rightshift[permuB[i]]; + } + } + bk_prev=-1; rightshift_prev=0; + pos=ptr->learned_position; + for (int i=debut;isize() && bk==(*pairs_reducing_to_zero)[pos]){ + ++pos; + unsigned tofill=(N>>5)+1; + fill(bitmap,bitmap+tofill,0); + bitmap += tofill; + continue; + } + if (bk.second!=bk_prev || !rightshift_prev || *rightshift_prev!=rightshift[permuB[i]]){ + subcoeff2.clear(); + zcopycoeff(res[bk.second],subcoeff2,1); + bk_prev=bk.second; + rightshift_prev=&rightshift[permuB[i]]; + } + // zcopycoeff(res[bk.first],subcoeff1,1);zadd(v64,subcoeff1,indexes[i]); + zadd(v64,res[bk.first],indexes[i],1,env); + effi=Bs+i; + while (indexes[effi].empty() && effi) + --effi; + zsub(v64,subcoeff2,indexes[effi]); + int firstcol=indexes[i].empty()?0:indexes[i].front(); + if (effi>=0 && !indexes[effi].empty()) + firstcol=giacmin(firstcol,indexes[effi].front()); + K[i].clear(); + colonnes=giacmin(colonnes,reducef4buchbergersplit(v64,Mindex,firstpos,firstcol,Mcoeff,coeffindex,K[i],bitmap,used,env)); + bitmap += (N>>5)+1; + } + return ptr_; + } + + template + struct pair_compare { + const vector< paire > * Bptr; + const vectzpolymod * resptr ; + const vector * leftshiftptr; + const vector * rightshiftptr; + order_t o; + inline bool operator ()(unsigned a,unsigned b){ + unsigned Ba=(*Bptr)[a].second,Bb=(*Bptr)[b].second; + const tdeg_t & adeg=(*resptr)[Ba].ldeg; + const tdeg_t & bdeg=(*resptr)[Bb].ldeg; + if (adeg!=bdeg) + return tdeg_t_greater(bdeg,adeg,o)!=0; // return tdeg_t_greater(adeg,bdeg,o); + const tdeg_t & aleft=(*rightshiftptr)[a]; + const tdeg_t & bleft=(*rightshiftptr)[b]; + return tdeg_t_strictly_greater(bleft,aleft,o);// return tdeg_t_strictly_greater(aleft,bleft,o); + } + pair_compare(const vector< paire > * Bptr_, + const vectzpolymod * resptr_ , + const vector * leftshiftptr_, + const vector * rightshiftptr_, + const order_t & o_):Bptr(Bptr_),resptr(resptr_),rightshiftptr(rightshiftptr_),leftshiftptr(leftshiftptr_),o(o_){} + }; + + // #define GIAC_CACHE2ND 1; // cache 2nd pair reduction, slower + // Linear algebra is done in 2 steps: 1st step is reduce the s-pairs + // wrt Mindex/Mcoeff in sparse linalg, without modification + // then build a dense matrix and reduce it + // It would be faster to do all at once, but that means modifying + // Mindex/Mcoeff to add new reducers, would work well on 1 thread + // but would probably not work well in parallel (memory locks) + // and it would also be harder to trace reducers added. + // This code is also optimized for memory. For this reason, coefficients + // and indices storage are separated, because coefficients are the same + // for each element of the gbasis multiplied by any element of the + // corresponding quotient. Indices storage are also optimized in + // memory using relative 2 bytes shifts instead of + // 4 bytes absolute positions. The main loop + // for sparse linear algebra (f4_innerloop_special_mod) must + // maintain 2 iterators (instead of 1) and read in 3 areas + // (instead of 2), this slows down the speed. + // But the memory footprint is almost divided by a factor of 4 or 2: + // instead of 1 modint=4 bytes + 1 absolute shift=4 bytes + // or instead of 1 absolute shift=4 bytes + // we have 1 relative shift=2 bytes + template + int zf4computeK1(const unsigned N,const unsigned nrows,const double mem,const unsigned Bs,vectzpolymod & res,const vector & G,modint_t env,const vector< paire > & B,const vector & permuB,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,const vector & leftshift,const vector & rightshift, const vector & R ,void * Rhashptr,const vector & Rdegpos,const vector &firstpos,vector > & Mindex, const vector & coeffindex,vector< vector > & Mcoeff,zinfo_t * info_ptr,vector &used,unsigned & usedcount,unsigned * bitmap,vector< vector > & K,int parallel,int interreduce){ + //parallel=1; + bool freemem=mem>4e7; // should depend on real memory available + bool large=N>8000; + // CERR << "after sort " << Mindex << '\n'; + // step3 reduce + unsigned colonnes=N; + vector v(N); + vector v64(N); + // vector v32(N); + vector v64d(N); +#if 0 // def x86_64 + vector v128; + if (!large) + v128.resize(N); +#endif + unsigned Kcols=N-nrows; + unsigned Ksizes=Kcols; + if (info_ptr && !learning) + Ksizes=giacmin(info_ptr->Ksizes+3,Kcols); + bool Kdone=false; +#ifdef GIAC_CACHE2ND + vector subcoeff2; +#else + vector subcoeff2; +#endif + vector< vector > indexes(2*Bs); +#ifdef HAVE_LIBPTHREAD + if (Bs>=200 && threads_allowed && parallel>1 + //&& (learning || !pairs_reducing_to_zero) + /*parallel*/){ + int th=giacmin(parallel,MAXNTHREADS)-1; // giacmin(threads,64)-1; + vector positions(1),learned_parallel(1); + if (interreduce){ + for (unsigned i=0;i=effend){ + positions.push_back(i); // end position for this thread + learned_parallel.push_back(pos); // learned position for next thread + effend += effstep; + } + } + // fix last pair number + while (positions.size() buchberger_param[MAXNTHREADS]; + int colonnes=N; + for (int j=0;j<=th;++j){ + thread_buchberger_t tmp={&res,&K,&G,&B,&permuB,&leftshift,&rightshift,&R,Rhashptr,&Rdegpos,env,positions[j],positions[j+1],int(N),int(Kcols),&firstpos,&Mindex,&Mcoeff,&coeffindex,&indexes,&used,bitmap,j==th && debug_infolevel>1,learning,(short int)interreduce,pairs_reducing_to_zero,learned_parallel[j]}; + buchberger_param[j]=tmp; + bool res=true; + // CERR << "write " << j << " " << p << '\n'; + if (j,(void *) &buchberger_param[j]); + if (res) + thread_buchberger((void *)&buchberger_param[j]); + } + Kdone=true; + colonnes=buchberger_param[th].colonnes; + for (unsigned j=0;j * ptr = (thread_buchberger_t *) ptr_; + colonnes=giacmin(colonnes,ptr->colonnes); + } + } // end parallelization +#endif + if (!Kdone){ + if (interreduce){ + for (unsigned i=0;i tmp={&res,&K,&G,&B,&permuB,&leftshift,&rightshift,&R,Rhashptr,&Rdegpos,env,0,(int)Bs,int(N),int(Kcols),&firstpos,&Mindex,&Mcoeff,&coeffindex,&indexes,&used,bitmap,debug_infolevel>1,learning,(short int)interreduce,pairs_reducing_to_zero,0}; + thread_buchberger((void *)&tmp); + return 0; + } + unsigned bk_prev=-1; + const tdeg_t * rightshift_prev=0; + int pos=learned_position; + for (unsigned i=0;isize() && bk==(*pairs_reducing_to_zero)[pos]){ + ++pos; + continue; + } + bool done=false; + const tdeg_t & curleft=leftshift[permuB[i]]; +#ifdef GIAC_MAKELINECACHE // does not seem faster + pair ij=zmakelinecache[bk.first]; + if (ij.first!=-1){ + // look in quo[ij.first] if leftshift[permuB[i]] is there, if true copy from Mindex + // except first index + typename std::vector::const_iterator cache_it=quo[ij.first].begin(),cache_end=quo[ij.first].end(); + if (cache_it5) + cache_it=cache_end; + else { + for (;cache_it2) + CERR << "cached " << ij << '\n'; + int pos=ij.second+cache_it-quo[ij.first].begin(); + pos=permuM[pos]; + vector & source=Mindex[pos]; + vector & target=indexes[i]; + target.reserve(source.size()); + unsigned sourcepos=0,targetpos=0; + const shifttype * sourceptr=&source.front(),*sourceend=sourceptr+source.size(); + next_index(sourcepos,sourceptr); // skip position 0 + next_index(sourcepos,sourceptr); + pushsplit(target,targetpos,sourcepos); + for (;sourceptr1) + CERR << CLOCK()*1e-6 << " pairs indexes computed over " << R.size() << " monomials"<<'\n'; + bk_prev=-1; rightshift_prev=0; + vector Ki; Ki.reserve(Ksizes); + int effi=-1; + for (unsigned i=0;i1){ + if (i%10==9) {COUT << "+"; COUT.flush(); } + if (i%500==499) COUT << " " << CLOCK()*1e-6 << " remaining " << Bs-i << '\n'; + } + paire bk=B[permuB[i]]; + if (!learning && pairs_reducing_to_zero && learned_positionsize() && bk==(*pairs_reducing_to_zero)[learned_position]){ + if (debug_infolevel>2) + CERR << bk << " f4buchberger learned " << learned_position << '\n'; + ++learned_position; + unsigned tofill=(N>>5)+1; + fill(bitmap,bitmap+tofill,0); + bitmap += tofill; + continue; + } + // zmakelinesub(res[bk.first],&leftshift[i],res[bk.second],&rightshift[i],R,v,1,env); + // CERR << bk.first << " " << leftshift[i] << '\n'; + // v64.assign(N,0); // + reset v64 to 0, already done by zconvert_ + if (bk.second!=bk_prev || !rightshift_prev || *rightshift_prev!=rightshift[permuB[i]]){ + subcoeff2.clear(); +#ifdef GIAC_CACHE2ND + subcoeff2.resize(N); + zadd(subcoeff2,res[bk.second],indexes[i+Bs],1,env); + reducef4buchbergersplit(subcoeff2,Mindex,firstpos,0,Mcoeff,coeffindex,Ki,0 /* no bitmap, answer in subcoeff2 */,used,env); +#else + zcopycoeff(res[bk.second],subcoeff2,1); +#endif + bk_prev=bk.second; + rightshift_prev=&rightshift[permuB[i]]; + if (effi>=0) + indexes[effi].clear(); + effi=i+Bs; + } + int firstcol=indexes[i].empty()?0:indexes[i].front(); + if (effi>=0 && !indexes[effi].empty()) + firstcol=giacmin(firstcol,indexes[effi].front()); + // zcopycoeff(res[bk.first],subcoeff1,1);zadd(v64,subcoeff1,indexes[i]); + if ( +#if defined(EMCC) || defined(EMCC2) + env>(1<<24) && env<=94906249 +#else + 0 +#endif + ){ +#ifndef GBASIS_4PRIMES + // using doubles instead of 64 bits integer not supported in JS + zadd(v64d,res[bk.first],indexes[i],1,env); + indexes[i].clear(); +#ifdef GIAC_CACHE2ND + sub(v64d,subcoeff2); +#else + zsub(v64d,subcoeff2,indexes[effi]); +#endif + Ki.clear(); + colonnes=giacmin(colonnes,reducef4buchbergersplitdouble(v64d,Mindex,firstpos,firstcol,Mcoeff,coeffindex,Ki,bitmap,used,env)); +#endif + } + else { +#if 0 && defined PSEUDO_MOD && !defined BIGENDIAN && GIAC_SHORTSHIFTTYPE==16 + // this code is slower : the innerloop does more operations with pseudo-mod + zadd(v32,res[bk.first],indexes[i],1,env); + indexes[i].clear(); + zsub(v32,subcoeff2,indexes[effi]); + Ki.clear(); + colonnes=giacmin(colonnes,reducef4buchbergersplit32(v32,Mindex,firstpos,firstcol,Mcoeff,coeffindex,Ki,bitmap,used,env)); +#else + zadd(v64,res[bk.first],indexes[i],1,env); + indexes[i].clear(); +#ifdef GIAC_CACHE2ND + sub(v64,subcoeff2); +#else + zsub(v64,subcoeff2,indexes[effi]); +#endif + Ki.clear(); + colonnes=giacmin(colonnes,reducef4buchbergersplit(v64,Mindex,firstpos,firstcol,Mcoeff,coeffindex,Ki,bitmap,used,env)); +#endif // 32 bits intermediate vector + } + bitmap += (N>>5)+1; + if (KsizesKi.capacity()*.8){ + K[i].swap(Ki); + Ki.reserve(giacmin(Kcols,int(Kis*1.1))); + } + else { +#if 0 + vector & target=K[i]; + target.reserve(giacmin(Kcols,int(Kis*1.1))); + vector::const_iterator kit=Ki.begin(),kitend=Ki.end(); + for (;kit!=kitend;++kit) + target.push_back(*kit); +#else + K[i]=Ki; +#endif + } + //CERR << v << '\n' << SK[i] << '\n'; + } // end for (i=0;i1) + CERR << CLOCK()*1e-6 << " f4buchbergerv split reduced " << Bs << " polynoms over " << N << " monomials, start at " << colonnes << '\n'; + return 0; + } + + template + struct zbuildM_t { + const vectzpolymod * res; + const vector * G; + modint_t env; + bool multimodular; + const vector< vector > * quo; + const vector * R; + const vector * Rdegpos; + void * Rhashptr; + vector * coeffindex; + unsigned N; + vector > * Mindex; + vector< vector > * Mcoeff; + vector * atrier; + int i,iend,j; + }; + + template + void do_zbuildM(const vectzpolymod & res,const vector & G,modint_t env,bool multimodular,const vector< vector > & quo,const vector & R,const vector & Rdegpos,void * Rhashptr,vector & coeffindex,unsigned N,vector > & Mindex,vector< vector > & Mcoeff,vector & atrier,int i,int iend,int j){ + for (;i::const_iterator jt=quo[i].end()-1; + int quos=int(quo[i].size()); + int Gi=G[i]; + for (int k=quos-1;k>=0;--k,--jt){ + zmakelinesplit(res[Gi],&*jt,R,Rhashptr,Rdegpos,Mindex[j+k],k==quos-1?0:&Mindex[j+k+1],0); + } + for (int k=0;k + void * zbuildM_(void * ptr_){ + zbuildM_t * ptr=(zbuildM_t *) ptr_; + do_zbuildM(*ptr->res,*ptr->G,ptr->env,ptr->multimodular,*ptr->quo,*ptr->R,*ptr->Rdegpos,ptr->Rhashptr,*ptr->coeffindex,ptr->N,*ptr->Mindex,*ptr->Mcoeff,*ptr->atrier,ptr->i,ptr->iend,ptr->j); + return ptr_; + } + + template + void zbuildM(const vectzpolymod & res,const vector & G,modint_t env,bool multimodular,int parallel,const vector< vector > & quo,const vector & R,const vector & Rdegpos,void * & Rhashptr,vector & coeffindex,unsigned N,vector > & Mindex,vector< vector > & Mcoeff,vector & atrier,int nrows){ +#ifdef HAVE_LIBPTHREAD +#if 1 // IMPROVE parallel + parallel=giacmax(1,giacmin(parallel,nrows/16)); +#else + if (nrows<16) parallel=1; +#endif + pthread_t tab[parallel]; + zbuildM_t zbuildM_param[parallel]; + int istart=0,iend=0,jstart=0,jend=0; + for (int j=0;j((j+1)*nrows/parallel)){ + ++iend; + break; + } + } + } + zbuildM_t tmp={&res,&G,env,multimodular,&quo,&R,&Rdegpos,Rhashptr,&coeffindex,N,&Mindex,&Mcoeff,&atrier,istart,iend,jstart}; + zbuildM_param[j]=tmp; + bool res=true; + if (j,(void *) &zbuildM_param[j]); + if (res) + zbuildM_((void *)&zbuildM_param[j]); + istart=iend; + jstart=jend; + } + for (unsigned j=0;j tmp={&res,&G,env,multimodular,&quo,&R,&Rdegpos,Rhashptr,&coeffindex,N,&Mindex,&Mcoeff,&atrier,0,int(G.size()),0}; + zbuildM_((void *)&tmp); +#endif + } // end parallelization + + template + int zf4denselinalg(vector & lebitmap,vector< vector > & K,modint_t env,vectzpolymod & f4buchbergerv,zinfo_t * info_ptr,vector & Rtoremv,unsigned N,unsigned Bs,unsigned nrows,vector &used,unsigned usedcount,double mem,const order_t &order,int dim,int age,bool learning,bool multimodular,int parallel,int interreduce){ + //parallel=1; + // create dense matrix K + unsigned * bitmap=&lebitmap.front(); + unsigned zeros=create_matrix(bitmap,(N>>5)+1,used,K); + // clear memory required for lescoeffs + { vector tmp1; lebitmap.swap(tmp1); } + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " nthreads=" << parallel << " dense_rref " << K.size()-zeros << "(" << K.size() << ")" << "x" << usedcount << " ncoeffs=" << double(K.size()-zeros)*usedcount*1e-6 << "*1e6\n"; + double nz=0,nzrow=0; + for (unsigned i=0;i & Ki=K[i]; + if (!Ki.size()) + continue; + nzrow+=usedcount; + for (unsigned j=0;jpermu.size()==Bs){ + vector permutation=info_ptr->permu; + vector< vector > K1(Bs); + for (unsigned i=0;i permutation,maxrankcols; longlong idet; + int th=giacmin(parallel,MAXNTHREADS)-1; // giacmin(threads,64)-1; + if (interreduce){ // interreduce==true means final interreduction + ; + } + else { + smallmodrref(parallel,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,0/* lower reduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,permutation.empty()/* reset */,0,!multimodular/* allow_block*/,-1); + // FIXME allow_block fails with parallel>1 + //smallmodrref(parallel,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,0/* lower reduction*/,0/*dontswapbelow*/,env,0/* rrefordetorlu*/,permutation.empty()/* reset */,0,true,-1); + if (1){ + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " rref_upper " << '\n'; + int Ksize=int(K.size()); + if (//1 + usedcount<=2*Ksize + || parallel==1 || Ksize<50 + ) + smallmodrref_upper(K,0,Ksize,0,usedcount,env); + else { + thread_smallmodrref_upper(K,0,Ksize,0,usedcount,env,parallel); + } + } + } // end if !interreduce + unsigned Kcols=N-nrows; + free_null_lines(K,0,Bs,0,Kcols); + unsigned first0 = unsigned(pivots.size()); + int i; + if (!interreduce && first0 & tmpv=K[first0]; + for (i=0;i permutation; + bool copy=false; + for (unsigned j=0;jpermu[j]){ + copy=true; + if (K[permutation[j]].empty() && K[info_ptr->permu[j]].empty()) + continue; + CERR << "learning failed"<<'\n'; + return -1; + } + } + if (copy) + permutation=info_ptr->permu; + } + if (learning) + info_ptr->permu=permutation; + // CERR << K << "," << permutation << '\n'; + // vector permu=perminv(permutation); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n'; + for (i=0;irem; + f4buchbergerv[pi].order=order; + f4buchbergerv[pi].dim=dim; + f4buchbergerv[pi].age=age; + vector< T_unsigned > & Pcoord=f4buchbergerv[pi].coord; + Pcoord.clear(); + vector & v =K[i]; + if (v.empty()){ + continue; + } + unsigned vcount=0; + typename vector::const_iterator vt=v.begin(),vtend=v.end(); + for (;vt!=vtend;++vt){ + if (*vt!=0) + ++vcount; + } + Pcoord.reserve(vcount); + vector::const_iterator ut=used.begin(); + unsigned pos=0; + for (vt=v.begin();pos (coeff,Rtoremv[pos])); + } + if (!Pcoord.empty()) + f4buchbergerv[pi].ldeg=(*f4buchbergerv[pi].expo)[Pcoord.front().u]; + if (!interreduce && !Pcoord.empty() && ( (env > (1<< 24)) || Pcoord.front().g!=1) ){ + zsmallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[pi],env); + Pcoord.front().g=1; + } + bool freemem=mem>4e7; // should depend on real memory available + if (freemem){ + vector tmp; tmp.swap(v); + } + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv stored" << '\n'; + return 1; + } + + void extract(const vector< vector > & K,vector< vector > & K0,int pos){ + K0.resize(K.size()); + for (int i=0;i & Ki=K[i]; + vector & K0i=K0[i]; + int s=Ki.size(); + K0i.reserve(s); K0i.clear(); + for (int j=0;j + int zf4denselinalg(vector & lebitmap,vector< vector > & K4,mod4int env,vectzpolymod & f4buchbergerv,zinfo_t * info_ptr,vector & Rtoremv,unsigned N,unsigned Bs,unsigned nrows,vector &used,unsigned usedcount,double mem,const order_t &order,int dim,int age,bool learning,bool multimodular,int parallel,int interreduce){ + unsigned * bitmap=&lebitmap.front(); + vector< vector > K; + int last_line=-1; vector permutation0; + if (!learning && info_ptr) + permutation0=info_ptr->permu; + for (int pos=0;pos>5)+1,used,K); + if (!permutation0.empty()){ + // apply permutation0 and clear lines that reduced to 0 for prime at pos=0 + apply_permutation(K,permutation0); + if (pos>0){ + for (int l=last_line+1;l1){ + CERR << CLOCK()*1e-6 << " dense_rref[0] " << K.size()-zeros << "(" << K.size() << ")" << "x" << usedcount << " ncoeffs=" << double(K.size()-zeros)*usedcount*1e-6 << "*1e6\n"; + double nz=0,nzrow=0; + for (unsigned i=0;i & Ki=K[i]; + if (!Ki.size()) + continue; + nzrow+=usedcount; + for (unsigned j=0;j permutation,maxrankcols; longlong idet; + int th=giacmin(parallel,MAXNTHREADS)-1; // giacmin(threads,64)-1; + if (!interreduce){ + smallmodrref(parallel,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,0/* lower reduction*/,0/*dontswapbelow*/,env.tab[pos],0/* rrefordetorlu*/,permutation.empty()/* reset */,0,!multimodular,-1); + //smallmodrref(parallel,K,pivots,permutation,maxrankcols,idet,0,int(K.size()),0,usedcount,0/* lower reduction*/,0/*dontswapbelow*/,env.tab[pos],0/* rrefordetorlu*/,permutation.empty()/* reset */,0,true,-1); + if (permutation0.empty()) + permutation0=permutation; + else { // check for identity permutation + for (int j=0;j Kchk=K[permutation[j]]; + for (k=0;k1) + CERR << CLOCK()*1e-6 << " rref_upper " << '\n'; + int Ksize=int(K.size()); + if (//1 + usedcount<=2*Ksize + || parallel==1 || Ksize<50 + ) + smallmodrref_upper(K,0,Ksize,0,usedcount,env.tab[pos]); + else { + thread_smallmodrref_upper(K,0,Ksize,0,usedcount,env.tab[pos],parallel); + } + } + } // end if !interreduce + unsigned Kcols=N-nrows; + if (pos==0){ // set last non 0 line of K for next primes + permutation0=permutation; // save for pos 1 to 3 + for (last_line=K.size()-1;last_line>=0;--last_line){ + int C; + vector & KL=K[last_line]; + for (C=KL.size()-1;C>=0;--C){ + if (KL[C]) break; + } + if (C>=0) + break; + } + } + unsigned first0 = unsigned(pivots.size()); + int i; + if (!interreduce && first0 & tmpv=K[first0]; + for (i=0;ipermu=permutation; + // CERR << K << "," << permutation << '\n'; + // vector permu=perminv(permutation); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv interreduced" << '\n'; + for (i=0;irem; + f4buchbergerv[pi].order=order; + f4buchbergerv[pi].dim=dim; + f4buchbergerv[pi].age=age; + } + vector< T_unsigned > & Pcoord=f4buchbergerv[pi].coord; + if (pos==0) + Pcoord.clear(); + vector & v =K[i]; + if (v.empty()) + continue; + if (pos==0){ + Pcoord.reserve(v.size()); + for (int i=0;i(create(0),0)); + } + vector::const_iterator ut=used.begin(); + typename vector::const_iterator vt=v.begin(),vtend=v.end(); + unsigned pcoordpos=0; + for (vt=v.begin();vt!=vtend;++ut){ + if (!*ut) + continue; + modint coeff=*vt; ++vt; + Pcoord[pcoordpos].g.tab[pos]=coeff; + if (pos==0) + Pcoord[pcoordpos].u=Rtoremv[ut-used.begin()]; + ++pcoordpos; + } + if (pos==sizeof(mod4int)/sizeof(modint)-1){ + vector< T_unsigned > trimPcoord; + unsigned vcount=0; + vector< T_unsigned > ::const_iterator Pit=Pcoord.begin(),Pitend=Pcoord.end(); + for (;Pit!=Pitend;++Pit) + if (!is_zero(Pit->g)) + ++vcount; + trimPcoord.reserve(vcount); + for (Pit=Pcoord.begin();Pit!=Pitend;++Pit) + if (!is_zero(Pit->g)) + trimPcoord.push_back(*Pit); + trimPcoord.swap(Pcoord); + if (!Pcoord.empty()) + f4buchbergerv[pi].ldeg=(*f4buchbergerv[pi].expo)[Pcoord.front().u]; + if (!interreduce && !Pcoord.empty() && ( (env > (1<< 24)) || Pcoord.front().g!=1) ){ + zsmallmultmod(invmod(Pcoord.front().g,env),f4buchbergerv[pi],env); + Pcoord.front().g=create(1); + } + } + } + } // end for loop on pos + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " f4buchbergerv stored" << '\n'; + return 1; + } +#endif + + // interreduce==0 normal F4 algo reduction, ==1 final gb auto-interreduction + // to be done ==2 reduction of res[G.size()...] by gbasis in res, + // G should be identity, res[0] to res[G.size()-1] the gbasis + template + int zf4mod(vectzpolymod & res,const vector & G,modint_t env,const vector< paire > & B,const vector * & permuBptr,vectzpolymod & f4buchbergerv,bool learning,unsigned & learned_position,vector< paire > * pairs_reducing_to_zero,vector > & f4buchberger_info,unsigned & f4buchberger_info_position,bool recomputeR,int age,bool multimodular,int parallel,int interreduce){ + unsigned Bs=unsigned(interreduce?(interreduce==2?res.size()-G.size():G.size()):B.size()); + if (!Bs) + return 0; + vector G2; + if (interreduce==2){ + for (unsigned i=G.size();i leftshift(Bs); + vector rightshift(Bs); + if (!interreduce) + zleftright(res,B,leftshift,rightshift); + // IMPROVEMENT: sort pairs in B according to right term of the pair + // If several pairs share the same right term, + // reduce the right term without leading monomial once + // reduce corresponding left terms without leading monomial + // subtract + f4buchbergerv.resize(Bs); + zinfo_t info_tmp; + unsigned nonzero = unsigned(Bs); + zinfo_t * info_ptr=0; + if (!learning && f4buchberger_info_positionnonzero; + if (nonzero==0 && !interreduce){ + for (int i=0;irem; + f4buchbergerv[i].order=order; + f4buchbergerv[i].dim=dim; + vector< T_unsigned > & Pcoord=f4buchbergerv[i].coord; + Pcoord.clear(); + } + return 1; + } + } + else { + vector all; + vector permuB(Bs); + for (unsigned i=0;i trieur(&B,&res,&leftshift,&rightshift,order); + sort(permuB.begin(),permuB.end(),trieur); + if (debug_infolevel>2){ + unsigned egales=0; + for (unsigned i=1;i1) + CERR << CLOCK()*1e-6 << " zf4buchberger symbolic preprocess" << '\n'; + zsymbolic_preprocess(all,res,G,-1,info_tmp.quo,info_tmp.rem,info_tmp.R); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " zend symbolic preprocess" << '\n'; +#if 0 + f4buchberger_info->push_back(*info_ptr); +#else + zinfo_t tmp; tmp.nonzero=0; tmp.Ksizes=0; + f4buchberger_info.push_back(tmp); + zinfo_t & i=f4buchberger_info.back(); + swap(i.quo,info_tmp.quo); + swap(i.R,info_tmp.R); + swap(i.rem,info_tmp.rem); + swap(i.permuB,permuB); + info_ptr=&f4buchberger_info.back(); +#endif + } + const vector & permuB =info_ptr->permuB ; + permuBptr=&permuB; + const vector & R = info_ptr->R; + vector Rtoremv; + Rtorem(R,info_ptr->rem,Rtoremv); // positions of R degrees in rem + const vector< vector > & quo = info_ptr->quo; + //CERR << quo << '\n'; + unsigned N = unsigned(R.size()), i, j = 0; + if (N==0) return 1; + void * Rhashptr=0; +#ifdef GIAC_RHASH // default disabled + tdeg_t64_hash_t Rhash; + if (R.front().vars64()){ + Rhashptr=&Rhash; + //Rhash.reserve(N); + for (unsigned i=0;i Rdegpos(Rcurdeg+2); +#ifdef GIAC_RDEG // default enabled + for (unsigned i=0;itmp;--Rcurdeg){ + Rdegpos[Rcurdeg]=i; + } + } + for (;Rcurdeg>=0;--Rcurdeg){ + Rdegpos[Rcurdeg]=N; + } +#endif + unsigned nrows=0; + for (i=0;inonzero=G.size(); + return 12345; // special code, already interreduced + } + double sknon0=0; + unsigned usedcount=0,zerolines=0; + vector< vector > K(Bs); + vector > Mindex; + vector< vector > Mcoeff(G.size()); + vector coeffindex(nrows); + Mindex.reserve(nrows); + vector atrier(nrows); + // atrier.reserve(nrows); + for (i=0;i::const_iterator jt=quo[i].begin(),jtend=quo[i].end(); + if (jt!=jtend) + Mcoeff[i].reserve(res[G[i]].coord.size()); + for (;jt!=jtend;++j,++jt){ + Mindex.push_back(vector(0)); + Mindex[j].reserve(int(1.1*res[G[i]].coord.size())); + } + } +#ifndef GIAC_MAKELINECACHE + zbuildM(res,G,env,multimodular,parallel,quo,R,Rdegpos,Rhashptr,coeffindex,N,Mindex,Mcoeff,atrier,nrows); +#else // ZBUILDM +#ifdef GIAC_MAKELINECACHE + vector< pair > zmakelinecache(res.size(),pair(-1,-1)); // -1 if res[k] is not in G, (i,j) if k==G[i] where j is the first index in Mindex of the part corresponding to res[G[i]] +#endif + for (i=0,j=0;i::const_iterator jt=quo[i].end()-1; + int quos=int(quo[i].size()); + int Gi=G[i]; +#ifdef GIAC_MAKELINECACHE + zmakelinecache[Gi]=pair(i,j); +#endif + for (int k=quos-1;k>=0;--k,--jt){ + zmakelinesplit(res[Gi],&*jt,R,Rhashptr,Rdegpos,Mindex[j+k],k==quos-1?0:&Mindex[j+k+1],0); + } + for (int k=0;k::const_iterator jt=quo[i].begin(),jtend=quo[i].end(); + for (;jt!=jtend;++j,++jt){ + coeffindex[j]=coeffindex_t(N<=0xffff,i); + zmakelinesplit(res[G[i]],&*jt,R,Rhashptr,Rdegpos,Mindex[j],0,0); + if (!coeffindex[j].b) + coeffindex[j].b=checkshortshifts(Mindex[j]); + // atrier.push_back(sparse_element(first_index(Mindex[j]),j)); + atrier[j]=sparse_element(first_index(Mindex[j]),j); + } +#endif + } +#endif // ZBUILM + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end build Mindex/Mcoeff zf4mod" << '\n'; + // should not sort but compare res[G[i]]*quo[i] monomials to build M already sorted + // CERR << "before sort " << Mindex << '\n'; + sort_vector_sparse_element(atrier.begin(),atrier.end()); // sort(atrier.begin(),atrier.end(),tri1); + vector coeffindex1(atrier.size()); + double mem=0; // mem*4=number of bytes allocated for M1 + vector< vector > Mindex1(atrier.size()); +#ifdef GIAC_MAKELINECACHE + vector permuM(atrier.size()); +#endif + for (i=0;i firstpos(atrier.size()); + for (i=0;i < atrier.size();++i){ + firstpos[i]=atrier[i].val; + } + double ratio=(mem/nrows)/N; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " Mindex sorted, rows " << nrows << " columns " << N << " terms " << mem << " ratio " << ratio <<'\n'; + if (N>5)+1)*Bs should not exceed 2e9 otherwise this will segfault + if (double(Bs)*(N>>5)>2e9){ + CERR << "Error, problem too large. Try again after running gbasis_max_pairs(n) with n<" << 2e9/(N>>5) << '\n'; + return -1; + } + vector used(N,0); + vector lebitmap(((N>>5)+1)*Bs); + unsigned * bitmap=&lebitmap.front(); + int zres=zf4computeK1(N,nrows,mem,Bs,res,G,env, B,permuB,learning,learned_position,pairs_reducing_to_zero,leftshift,rightshift, R ,Rhashptr,Rdegpos,firstpos,Mindex, coeffindex,Mcoeff,info_ptr,used,usedcount,bitmap,K,parallel,interreduce); + if (zres!=0) + return zres; + if (debug_infolevel>1){ + CERR << '\n' << CLOCK()*1e-6 << " Memory usage: " << memory_usage()*1e-6 << "M" << '\n'; + } + size_t Mindexsize=Mindex.size(); + Mindex.clear(); + Mcoeff.clear(); + { + vector > Mindexclear; + vector< vector > Mcoeffclear; + Mindex.swap(Mindexclear); + Mcoeff.swap(Mcoeffclear); + } + if (!pairs_reducing_to_zero){ + vector clearer; + info_ptr->R.swap(clearer); + } + for (unsigned i=0;i0); + if (learning && info_ptr) + info_ptr->Ksizes=usedcount; + if (debug_infolevel>1){ + CERR << CLOCK()*1e-6 << " number of non-zero columns " << usedcount << " over " << N-Mindexsize << " (N " << N << ", Mindex size " << Mindexsize << ")" << '\n'; // usedcount should be approx N-M.size()=number of cols of M-number of rows + if (debug_infolevel>3) + CERR << " column split used " << used << '\n'; + } + //vector tmp; lescoeffs.swap(tmp); + return zf4denselinalg(lebitmap,K,env,f4buchbergerv,info_ptr,Rtoremv,N,Bs,nrows,used,usedcount,mem,order,dim,age,learning,multimodular,parallel,interreduce); + } + + template + int zsimult_reduce(vector< polymod > & v,const vector< polymod > & gbmod,int env,bool multimodular,int parallel){ + if (v.empty()){ return 0; } + vectpolymod all; all.reserve(gbmod.size()+v.size()); polymod TMP1; + for (int i=0;i R0(TMP1.coord.size()); + for (unsigned l=0;l zall; zall.resize(all.size()); + for (unsigned l=0;l G; + for (int i=0;i B; // not used + const vector * permuBptr=0; // not used + vector > f4buchberger_info;unsigned f4buchberger_info_position=0; + vectzpolymod f4buchbergerv; + bool learning=false;unsigned learned_position=0; + vector< paire > * pairs_reducing_to_zero=0; + bool recomputeR=false; int age=0; + int tmp=zf4mod( + zall,G,env,B,permuBptr,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,2); + //CERR << "interreduce " << tmp << '\n'; + if (tmp<0 || tmp==12345) + return tmp; + for (unsigned i=0;i + void zgbasis_updatemod(vector & G,vector< paire > & B,const vectzpolymod & res,unsigned pos,const vector & oldG,bool multimodular){ + if (debug_infolevel>2) + CERR << CLOCK()*1e-6 << " zmod begin gbasis update " << G.size() << '\n'; + if (debug_infolevel>3) + CERR << "G=" << G << "B=" << B << '\n'; + const zpolymod & h = res[pos]; + order_t order=h.order; + short dim=h.dim; + vector C,Ccancel; + C.reserve(G.size()+1); + const tdeg_t & h0=h.ldeg; + for (unsigned i=0;i if g leading monomial is prime with h, remove the pair + // -> if g leading monomial is not disjoint from h leading monomial + // keep it only if lcm of leading monomial is not divisible by another one +#if 1 + unsigned tmpsize = unsigned(G.size()); + vector tmp(tmpsize); + for (unsigned i=0;i is not generated + unsigned tmpsize=G.empty()?0:G.back()+1; + vector tmp(tmpsize); + for (unsigned i=0;i cancellables; + for (unsigned i=0;itab[0]==-1) + continue; + if (tdeg_t_all_greater(*tmp1,*tmp2,order)) + break; // found another pair, keep the smallest, or the first if equal + } + if (tmp2!=tmp1){ + tmp1->tab[0]=-1; // desactivate tmp1 since it is >=tmp2 + continue; + } + for (++tmp2;tmp2tab[0]==-1) + continue; + if (tdeg_t_all_greater(*tmp1,*tmp2,order) && *tmp1!=*tmp2){ + tmp1->tab[0]=-1; // desactivate tmp1 since it is >tmp2 + break; + } + } + if (tmp2==tmpend) + C.push_back(G[i]); + } + vector< paire > B1; + B1.reserve(B.size()+C.size()); + for (unsigned i=0;i= leading monomial of h + if (debug_infolevel>2){ + CERR << CLOCK()*1e-6 << " end, pairs:"<< '\n'; + if (debug_infolevel>3) + CERR << B << '\n'; + CERR << "mod begin Groebner interreduce " << '\n'; + } + C.clear(); + C.reserve(G.size()+1); + // bool pos_pushed=false; + for (unsigned i=0;i2) + CERR << CLOCK()*1e-6 << " zmod end gbasis update " << '\n'; + for (unsigned i=0;i + void convert(const polymod & p,zpolymod & q,const vector & R){ + q.order=p.order; + q.dim=p.dim; + q.coord.clear(); + q.coord.reserve(p.coord.size()); + typename vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + typename vector::const_iterator jt=R.begin(),jt0=jt,jtend=R.end(); + for (;it!=itend;++it){ + const tdeg_t & u=it->u; + for (;jt!=jtend;++jt){ + if (*jt==u) + break; + } + if (jt!=jtend){ + q.coord.push_back( T_unsigned (it->g,int(jt-jt0))); + ++jt; + } + else + COUT << "not found" << '\n'; + } + q.expo=&R; + if (!q.coord.empty()) + q.ldeg=R[q.coord.front().u]; + q.fromleft=p.fromleft; + q.fromright=p.fromright; + q.age=p.age; + q.logz=p.logz; + } + + template + void convert(const zpolymod & p,polymod & q){ + q.dim=p.dim; + q.order=p.order; + q.coord.clear(); + q.coord.reserve(p.coord.size()); + typename vector< T_unsigned >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + const vector & expo=*p.expo; + for (;it!=itend;++it){ + q.coord.push_back(T_unsigned(it->g,expo[it->u])); + } + q.fromleft=p.fromleft; + q.fromright=p.fromright; + q.age=p.age; + q.logz=p.logz; + } + + template + void zincrease(vector > &v){ + if (v.size()!=v.capacity()) + return; + vector > w; + w.reserve(v.size()*2); + for (unsigned i=0;i(v[i].order,v[i].dim,v[i].expo,v[i].ldeg)); + w[i].coord.swap(v[i].coord); + w[i].age=v[i].age; + w[i].fromleft=v[i].fromleft; + w[i].fromright=v[i].fromright; + w[i].age=v[i].age; + w[i].logz=v[i].logz; + } + v.swap(w); + } + + template + void smod(polymod & resmod,modint_t env){ + typename std::vector< T_unsigned >::iterator it=resmod.coord.begin(),itend=resmod.coord.end(); + for (;it!=itend;++it){ + modint_t n=it->g; +#ifdef GBASIS_4PRIMES + n = smod(n,env); +#else + if (n*2LL>env) + it->g -= env; + else { + if (n*2LL<=-env) + it->g += env; + } +#endif + } + } + + template + void smod(vectpolymod & resmod,modint_t env){ + for (unsigned i=0;i + double sumdegcoeffs2(const vector< vectpolymod > * coeffsmodptr,const order_t & o,const vectzpolymod &res,const paire & bk,int strategy){ + if (!coeffsmodptr) return 0; + strategy %= 1000; + int t1=res[bk.first].coord.size(); + int t2=res[bk.second].coord.size(); + if (t1==0 || t2==0) + return 0; + const tdeg_t & pi = res[bk.first].coord.front().u; + const tdeg_t & qi = res[bk.second].coord.front().u; + tdeg_t lcm; + index_lcm(pi,qi,lcm,o); + tdeg_t pshift=lcm-pi; + tdeg_t qshift=lcm-qi; + int N=(*coeffsmodptr)[bk.first].size(); + double T1=sumtermscoeffs((*coeffsmodptr)[bk.first]),T2=sumtermscoeffs((*coeffsmodptr)[bk.second]); + double D1=sumdegcoeffs((*coeffsmodptr)[bk.first],o),D2=sumdegcoeffs((*coeffsmodptr)[bk.second],o); + double d1=pshift.total_degree(o)+1,d2=qshift.total_degree(o)+1; + if (strategy==17) + return (N*t1+T1)*d1*D1+(N*t2+T2)*d2*D2; + if (strategy==16) + return t1*T1*d1+t2*T2*d2; + if (strategy==15) + return t1*T1*D1+t2*T2*D2; + if (strategy==14) + return (D1+N*d1)*T1+(D2+N*d2)*T2; + if (strategy==13) + return d1*T1+d2*T2; + if (strategy==12) + return D1*T1+D2*T2; + if (strategy==11) + return t1+t2; + if (strategy==9) + return N*t1+T1+N*t2+T2; + if (strategy==8) + return d1*(N*t1+T1)+d2*(N*t2+T2); + if (strategy==10) + return t1*T1*d1*D1+t2*T2*d2*D2; + if (strategy==7) + return (D1+N*d1)*(N*t1+T1)+(D2+N*d2)*(N*t2+T2); + if (strategy==6)// || strategy==0) was default with topreduceonly=true + return t1*T1+t2*T2; + if (strategy==5) + return D1*T1+D2*T2; + // if (strategy==4) + return t1*(D1+N*d1)*T1+t2*(D2+N*d2)*T2; + } + + template + void reduce_syzygy(vector< vectpolymod > & coeffs,const vectpolymod & resmodorig,modint_t env){ + if (resmodorig.empty()) return; + int dim=resmodorig[0].dim; + order_t order=resmodorig[0].order; + // try to reduce coeffs degrees using the identity f_i*f_j-f_j*f_i=0 + // assumes that the initial generator are sorted wrt the monomial order + // resmod is the gbasis, let coeffs=*coeffsmodptr, f_j=resmodorig[j] + // we have + // resmod[k] = sum(coeffs[k][j]*f_j,j,0,resmod.size()-1) + // f is sorted by decreasing order + // if i TMP1; + TMP1.dim=dim, TMP1.order=order; + for (int k=0;k & coeffsk=coeffs[k]; + for (int i=N-2;i>=0;--i){ + // we will modify coeffsk[i] + for (int j=i+1;j + bool in_zgbasis(vectpolymod &resmod,unsigned ressize,vector & G,modint_t env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< zinfo_t > & f4buchberger_info,bool recomputeR,bool eliminate_flag,bool multimodular,int parallel,bool interred,const gbasis_param_t & gparam,vector< vectpolymod > * coeffsmodptr){ + int strategy=gparam.buchberger_select_strategy; + if (0 && multimodular && strategy>=0){ // safe multimodular strategies + int s1=strategy/1000000,s2=(strategy/1000)%1000,s3=strategy%1000; + if (s2==0 || s2==1 || s2==4) ; else s2=0; + if (s3==999 || s3==1 || s3==2) ; else s3=0; + strategy=s1*1000000+s2*1000+s3; + } + bool topreduceonly=strategy/1000000; + vectpolymod resmodorig(resmod); resmodorig.resize(ressize); + unsigned generators=ressize; + bool seldeg=true; int sel1=0; + ulonglong cleared=0; + unsigned learned_position=0,f4buchberger_info_position=0; + bool learning=(coeffsmodptr && pairs_reducing_to_zero)?pairs_reducing_to_zero->empty():f4buchberger_info.empty(); + if (0 && learning && coeffsmodptr){ + // do a learning run with F4? + // requires pairs_reducing_to_zero to be the same (permutation...) + // and comment multimodular after zf4mod call below + vectpolymod resmodcopy(resmod); vector Gcopy(G); + in_zgbasis(resmodcopy,ressize,Gcopy,env,totdeg,pairs_reducing_to_zero,f4buchberger_info,recomputeR,eliminate_flag,multimodular,parallel,interred, gparam,(vector< vectpolymod > *) 0); + learning=false; + } + unsigned capa = unsigned(f4buchberger_info.capacity()); + order_t order=resmod.front().order; + short dim=resmod.front().dim; + // if (order.dim-order.o==1) seldeg=false; + polymod TMP2(order,dim); + vector< paire > B,BB; + B.reserve(256); BB.reserve(256); + vector smallposv; + smallposv.reserve(256); + info_t information; + if (order.o!=_REVLEX_ORDER && order.o!=_TDEG_ORDER) + totdeg=false; + vector oldG(G); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " initial reduction: " << ressize << " memory " << memory_usage()*1e-6 << '\n'; + if (coeffsmodptr){ // initialize to "identity" + coeffsmodptr->clear(); + coeffsmodptr->resize(ressize); + tdeg_t dg(index_t(dim),order); + TMP2.coord.push_back(T_unsigned(create(1),dg)); + for (unsigned l=0;l _TMP1=resmod[l],_TMP2(order,dim); + vector< vectpolymod > & v = *coeffsmodptr; + int s=v.front().size(); + vectpolymod & newcoeffs=v[l]; + for (size_t k=0;k1) + CERR << CLOCK()*1e-6 << " initial collect, pairs " << B.size() << '\n'; + // init zpolymod before main loop + collect(resmod,TMP2); + // R0 stores monomials for the initial basis + vector R0(TMP2.coord.size()); + for (unsigned l=0;l > Rbuchberger; + const int maxage=65535; + Rbuchberger.reserve(maxage+1); + vectzpolymod res; + res.resize(ressize); + for (unsigned l=0;l(1),res[l],env); + } + resmod.clear(); + if (debug_infolevel>1000){ + res.dbgprint(); res[0].dbgprint(); // instantiate + } + double timebeg=CLOCK(),autodebug=5e8; + vector start_index_v; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin loop, mem " << memory_usage()*1e-6 << '\n'; + int age; + for (age=1;!B.empty() && !interrupted && !ctrl_c;++age){ + if (f4buchberger_info.size()>=capa-2 || age>maxage){ + CERR << "Error zgbasis too many iterations" << '\n'; + return false; // otherwise reallocation will make pointers invalid + } + if (debug_infolevel<2 && (CLOCK()-timebeg)>autodebug) + debug_infolevel=multimodular?1:2; + start_index_v.push_back(int(res.size())); // store size for final interreduction +#ifdef TIMEOUT + control_c(); +#endif + if (f4buchberger_info_position>=capa-1){ + CERR << "Error f4 info exhausted" << '\n'; + return false; + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin new iteration " << age << " zmod, " << env << " number of pairs: " << B.size() << ", base size: " << G.size() << '\n'; + vector clean(res.size(),true); + for (unsigned i=0;i Blcm(B.size()); + vector Blcmdeg(B.size()),Blogz(B.size()); + vector nterms(B.size()); + for (unsigned i=0;i1){ + cleared += int(res[i].coord.capacity())-1; + zpolymod clearer; + clearer.coord.swap(res[i].coord); + } + } +#endif + vector< paire > smallposp; + vector smallposv; + if (!totdeg){ + // find smallest lcm pair in B + // could also take nterms[i] in account + unsigned firstdeg=RAND_MAX-1; + for (unsigned i=0;ifirstdeg) + continue; + if (f1) + CERR << CLOCK()*1e-6 << " zpairs min " << (seldeg?"total degree ":"elimination degree ") << firstdeg << " #pairs " << smallposv.size() << '\n'; + if ( seldeg && (smallposv.size()GBASISF4_MAX_TOTALDEG){ + CERR << "Error zgbasis degree too large" << '\n'; + return false; + } + } + else { + // find smallest lcm pair in B + unsigned smallnterms=RAND_MAX,firstdeg=RAND_MAX-1,ismallnterms=-1; + for (unsigned i=0;ifirstdeg) + continue; + if (f1) + CERR << CLOCK()*1e-6 << " zpairs min total degrees, nterms " << firstdeg << "," << smallnterms << " #pairs " << smallposv.size() << '\n'; + } + if (debug_infolevel>3) + CERR << "pairs reduced " << B << " indices " << smallposv << '\n'; +#if 1 + // note that this is too slow for I0:=[2*v7-v3-v1,2*v8-v4-v2,2*v9-v5-v1,2*v10-v6-v2,-v12+v10-v5+v1,-v11+v9+v6-v2,-v14+v8+v3-v1,-v13+v7-v4+v2,v15*v12-v16*v11-v15*v10+v11*v10+v16*v9-v12*v9,v15*v14-v16*v13-v15*v8+v13*v8+v16*v7-v14*v7,v17*v14-v18*v13-v17*v8+v13*v8+v18*v7-v14*v7,-v18^2-v17^2+2*v18*v16+2*v17*v15-2*v16*v2+v2^2-2*v15*v1+v1^2,v19*v12-v20*v11-v19*v10+v11*v10+v20*v9-v12*v9,-v20^2-v19^2+2*v20*v16+2*v19*v15-2*v16*v2+v2^2-2*v15*v1+v1^2,-v21*v4+v22*v3+v21*v2-v3*v2-v22*v1+v4*v1,v21*v20-v22*v19-v21*v18+v19*v18+v22*v17-v20*v17,v23*v6-v24*v5-v23*v2+v5*v2+v24*v1-v6*v1,v23*v20-v24*v19-v23*v18+v19*v18+v24*v17-v20*v17,-1+v27*v24^2+v27*v23^2-v27*v22^2-v27*v21^2-2*v27*v24*v2+2*v27*v22*v2-2*v27*v23*v1+2*v27*v21*v1,-1+v28*v6^2-2*v28*v6^3+v28*v6^4+v28*v5^2-2*v28*v6*v5^2+2*v28*v6^2*v5^2+v28*v5^4]:;I1:=subst(I0,[v4=1,v3=0,v2=0,v1=0]):;v:=[v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v27,v28,v1,v2,v3,v4,v5,v6]:;G,M:=gbasis(I1,v,coeffs):; + vector< paire > coeffszeropairs; + const vector * coeffpermuBptr=0; + bool usef4=false; + //usef4=true; + // dry run with F4 is not optimal, probably because it discards + // some pairs that would be nice reducers instead of other + if (// 1 || // FIXME comment 1 || + (strategy % 1000 ==2 || strategy % 1000 ==99) && + (coeffsmodptr || (order.o!=_REVLEX_ORDER && smallposv.size()<=GBASISF4_BUCHBERGER) ) + ){ + int Rbuchbergersize=Rbuchberger.size(); + vector oldG(G); + // pairs not handled by f4 + int modsize=int(resmod.size()); + if (modsize TMP1(order,dim),TMP2(order,dim); + zpolymod TMP; + paire bk; + int np=smallposv.size(); // number of s-pairs + if (coeffsmodptr){ + if (strategy%1000==99){ + vector< pair > V(np); + for (int count=0;count(order)); + reverse(V.begin(),V.end()); + for (int count=0;count=0;--i) + B.erase(B.begin()+smallposv[i]); + } + else { + // sort pairs ? + vector< pair > V(np); + for (int count=0;count toremove; + for (int count=0;count=logV0) + break; + int pos=smallposv[V[count].first]; + smallposp.push_back(B[pos]); + toremove.push_back(pos); + } + sort(toremove.begin(),toremove.end()); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << "Reducing " << toremove.size() << " pairs, from " << np << " pairs of minimal degree\n"; + // remove selected pairs from B + for (int i=int(toremove.size())-1;i>=0;--i) + B.erase(B.begin()+toremove[i]); + } + } + else { + smallposp.clear(); + for (int count=0;count=0;--i) + B.erase(B.begin()+smallposv[i]); + } + if (usef4 && coeffsmodptr && (learning || !multimodular)){ + // make a "dry" F4 run, not computing coefficients + // and update pairs_reducing_to_zero + vectzpolymod new_res(res); + vectzpolymod f4buchbergerv; // collect all spolys + unsigned int coeffs_learned_position(learned_position); + int f4res=-1; + f4res=zf4mod(new_res,G,env,smallposp,coeffpermuBptr,f4buchbergerv,true /* learning*/,coeffs_learned_position,&coeffszeropairs,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,0); + if (f4res==-1) + return false; + if (coeffpermuBptr){ + if (debug_infolevel>1) + CERR << "learning f4buchberger [" ; + for (unsigned i=0;i1) + CERR << smallposp[(*coeffpermuBptr)[i]] << ','; + coeffszeropairs.push_back(smallposp[(*coeffpermuBptr)[i]]); + } + } + if (debug_infolevel>1) + CERR << "]\n"; + sort(coeffszeropairs.begin(),coeffszeropairs.end()); + // sort pairs using remsize + int S=f4buchbergerv.size(); + vector< pair > usef4v(S); + for (int i=0;i(f4buchbergerv[i].coord.size(),(*coeffpermuBptr)[i]); + } + sort(usef4v.begin(),usef4v.end()); + vector P(smallposp); smallposp.clear(); + for (int i=0;i1) + CERR << "learning from dry prerun " << bk << '\n'; + pairs_reducing_to_zero->push_back(bk); + } + continue; + } + if (!learning && pairs_reducing_to_zero && learned_positionsize() && bk==(*pairs_reducing_to_zero)[learned_position]){ + if (debug_infolevel>2) + CERR << bk << " learned " << learned_position << '\n'; + ++learned_position; + continue; + } + if (debug_infolevel>2) + CERR << bk << " not learned " << learned_position << '\n'; + if (resmod[bk.first].coord.empty()) + convert(res[bk.first],resmod[bk.first]); + if (resmod[bk.second].coord.empty()) + convert(res[bk.second],resmod[bk.second]); + modint_t d=spolymod(resmod[bk.first],resmod[bk.second],TMP1,TMP2,env); + if (!usef4 && coeffsmodptr){ + if (learning || !multimodular){ + polymod TMP3(TMP1); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " to "; + reducesmallmod(TMP3,resmod,G,-1,env,TMP2,true,0,true); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " dry reduction " << bk << " remsize=" << TMP3.coord.size() << " pairs " << B.size() << " basis " << G.size() << "\n"; + if (TMP3.coord.empty()){ + if (learning && pairs_reducing_to_zero){ + if (debug_infolevel>2) + CERR << "learning " << bk << '\n'; + pairs_reducing_to_zero->push_back(bk); + } + continue; + } + } + } + vectpolymod newcoeffs; + if (coeffsmodptr){ + vector< vectpolymod > & v = *coeffsmodptr; + int s=v.front().size(); + newcoeffs.resize(s); + int i1=bk.first,i2=bk.second; + const polymod &p=resmod[i1]; + const polymod &q=resmod[i2]; + if (p.coord.empty() || q.coord.empty()) + return false; + modint_t a=p.coord.front().g,b=q.coord.front().g; + modint_t c=smod(extend(a)*invmod(b,env),env); + const tdeg_t & pi = p.coord.front().u; + const tdeg_t & qi = q.coord.front().u; + tdeg_t lcm; + index_lcm(pi,qi,lcm,p.order); + tdeg_t pshift=lcm-pi; + tdeg_t qshift=lcm-qi; + polymod _TMP1(order,dim),_TMP2(order,dim),_TMP3(order,dim); + vectpolymod & curfirst=v[i1]; + vectpolymod & cursecond=v[i2]; + for (size_t k=0;k2){ + CERR << CLOCK()*1e-6 << " mod reduce begin, pair " << bk << " spoly size " << TMP1.coord.size() << " totdeg deg " << TMP1.coord.front().u.total_degree(order) << " degree " << TMP1.coord.front().u << ", pair degree " << resmod[bk.first].coord.front().u << resmod[bk.second].coord.front().u << '\n'; + } + reducesmallmod(TMP1,resmod,G,-1,env,TMP2,true,0,topreduceonly,&newcoeffs,coeffsmodptr,strategy); // strategy might be modified to usemap=true if previous reducesmallmod returned a large size remainder (in that case it is expected that the computation is large) + // insure that new basis element has positive coord, required by zf4mod + typename vector< T_unsigned >::iterator it=TMP1.coord.begin(),itend=TMP1.coord.end(); + for (;it!=itend;++it){ + // if (it->g<0) it->g += env; + it->g += ((it->g>>31)&env); + } + // reducemod(TMP1,resmod,G,-1,TMP1,env,true); + if (debug_infolevel>3){ + if (debug_infolevel>4){ CERR << TMP1 << '\n'; } + CERR << CLOCK()*1e-6 << " mod reduce end, remainder degree " << (TMP1.coord.empty()?0:TMP1.coord.front().u) << " size " << TMP1.coord.size() << " begin gbasis update" << '\n'; + } + if (!TMP1.coord.empty()){ + resmod.push_back(TMP1); + reduceAF(newcoeffs,resmodorig,env,order); + if (coeffsmodptr){ + coeffsmodptr->push_back(newcoeffs); + // if coeffsmodptr, we need TMP and res only to run zgbasis_updatemod, maybe we could run gbasis_updatemod without zpolymod with reduce=false argument + } + Rbuchberger.push_back(vector(TMP1.coord.size())); + vector & R0=Rbuchberger.back(); + for (unsigned l=0;l(order,dim,TMP.ldeg)); + res[ressize].expo=TMP.expo; + res[ressize].age=age; + res[ressize].logz=res[bk.first].logz+res[bk.second].logz; + swap(res[ressize].coord,TMP.coord); + ++ressize; + zgbasis_updatemod(G,B,res,ressize-1,oldG,multimodular); + if (debug_infolevel>4) + CERR << CLOCK()*1e-6 << " mod basis indexes " << G << " pairs indexes " << B << '\n'; + } + else { + if (learning && pairs_reducing_to_zero){ + if (debug_infolevel>2) + CERR << "learning " << bk << '\n'; + pairs_reducing_to_zero->push_back(bk); + } + } + } // end for loop on all spairs + if (1 && coeffsmodptr){ + if (0 && usef4){ + // upper interreduction + for (int i=G.size()-2;i>=0;--i){ + reducesmallmod(resmod[G[i]],resmod,G,i,env,TMP2,true,0,false,coeffsmodptr?&(*coeffsmodptr)[G[i]]:0,coeffsmodptr,strategy); // strategy==2 + } + } + // update res: keep only 1 monomial pointee + if (Rbuchberger.size()>Rbuchbergersize+1){ + TMP2.coord.clear(); + collect(resmod,TMP2); + Rbuchberger.resize(Rbuchbergersize); + Rbuchberger.push_back(vector(TMP2.coord.size())); + vector & R0=Rbuchberger.back(); + for (unsigned l=0;l TMP1(order,dim),TMP2(order,dim); + zpolymod TMP; + paire bk; int curlogz=1; double sumdeg=0; + if (coeffsmodptr){ + if (strategy % 1000==999){ + int lcmpos=smallposv[0]; + tdeg_t deg(Blcm[lcmpos]); + for (int i=1;i(coeffsmodptr,order,res,B[smallposv.front()],strategy); + for (int i=1;i(coeffsmodptr,order,res,B[smallposv[i]],strategy); + if (cur=2) + CERR << CLOCK()*1e-6 << " cur pair " << bk << ",logz=" << curlogz << ", deg/terms=" << sumdeg << " (strategy=" << strategy << ")\n"; + if (!learning && pairs_reducing_to_zero && learned_positionsize() && bk==(*pairs_reducing_to_zero)[learned_position]){ + if (debug_infolevel>2) + CERR << bk << " learned " << learned_position << '\n'; + ++learned_position; + continue; + } + if (debug_infolevel>2) + CERR << bk << " not learned " << learned_position << '\n'; + if (resmod[bk.first].coord.empty()) + convert(res[bk.first],resmod[bk.first]); + if (resmod[bk.second].coord.empty()) + convert(res[bk.second],resmod[bk.second]); + modint_t d=spolymod(resmod[bk.first],resmod[bk.second],TMP1,TMP2,env); + vectpolymod newcoeffs; + if (coeffsmodptr){ + if (learning || !multimodular){ + polymod TMP3(TMP1); + reducesmallmod(TMP3,resmod,G,-1,env,TMP2,true,0,true); + if (debug_infolevel>=2) + CERR << CLOCK()*1e-6 << " dry reduction " << bk << " remsize=" << TMP3.coord.size() << "\n"; + if (TMP3.coord.empty()){ + if (learning && pairs_reducing_to_zero){ + if (debug_infolevel>2) + CERR << "learning " << bk << '\n'; + pairs_reducing_to_zero->push_back(bk); + } + continue; + } + } + vector< vectpolymod > & v = *coeffsmodptr; + int s=v.front().size(); + newcoeffs.resize(s); + int i1=bk.first,i2=bk.second; + const polymod &p=resmod[i1]; + const polymod &q=resmod[i2]; + if (p.coord.empty() || q.coord.empty()) + return false; + modint_t a=p.coord.front().g,b=q.coord.front().g; + modint_t c=smod(extend(a)*invmod(b,env),env); + const tdeg_t & pi = p.coord.front().u; + const tdeg_t & qi = q.coord.front().u; + tdeg_t lcm; + index_lcm(pi,qi,lcm,p.order); + tdeg_t pshift=lcm-pi; + tdeg_t qshift=lcm-qi; + polymod _TMP1(order,dim),_TMP2(order,dim),_TMP3(order,dim); + vectpolymod & curfirst=v[i1]; + vectpolymod & cursecond=v[i2]; + for (size_t k=0;k2){ + CERR << CLOCK()*1e-6 << " mod reduce begin, pair " << bk << " spoly size " << TMP1.coord.size() << " totdeg deg " << TMP1.coord.front().u.total_degree(order) << " degree " << TMP1.coord.front().u << ", pair degree " << resmod[bk.first].coord.front().u << resmod[bk.second].coord.front().u << '\n'; + } + reducesmallmod(TMP1,resmod,G,-1,env,TMP2,true /* normalize */,0/* start index*/,topreduceonly,&newcoeffs,coeffsmodptr,strategy); + // insure that new basis element has positive coord, required by zf4mod + typename vector< T_unsigned >::iterator it=TMP1.coord.begin(),itend=TMP1.coord.end(); + for (;it!=itend;++it){ + // if (it->g<0) it->g += env; + it->g += ((it->g>>31)&env); + } + // reducemod(TMP1,resmod,G,-1,TMP1,env,true); + if (debug_infolevel>2){ + if (debug_infolevel>3){ CERR << TMP1 << '\n'; } + CERR << CLOCK()*1e-6 << " mod reduce end, remainder degree " << (TMP1.coord.empty()?0:TMP1.coord.front().u) << " size " << TMP1.coord.size() << " begin gbasis update" << '\n'; + } + if (!TMP1.coord.empty()){ + resmod.push_back(TMP1); + reduceAF(newcoeffs,resmodorig,env,order); + if (coeffsmodptr){ + coeffsmodptr->push_back(newcoeffs); + // if coeffsmodptr, we need TMP and res only to run zgbasis_updatemod, maybe we could run gbasis_updatemod without zpolymod with reduce=false argument + // if (!gparam.rawcoeffs) reduce_syzygy(*coeffsmodptr,resmodorig,env); + } + Rbuchberger.push_back(vector(TMP1.coord.size())); + vector & R0=Rbuchberger.back(); + for (unsigned l=0;l(order,dim,TMP.ldeg)); + res[ressize].expo=TMP.expo; + res[ressize].fromleft=bk.first; + res[ressize].fromright=bk.second; + res[ressize].logz=curlogz; + res[ressize].age=age; + swap(res[ressize].coord,TMP.coord); + ++ressize; + zgbasis_updatemod(G,B,res,ressize-1,G,multimodular); + if (debug_infolevel>3) + CERR << CLOCK()*1e-6 << " mod basis indexes " << G << " pairs indexes " << B << '\n'; + } + else { + if (learning && pairs_reducing_to_zero){ + if (debug_infolevel>2) + CERR << "learning " << bk << '\n'; + pairs_reducing_to_zero->push_back(bk); + } + } + continue; + } // end if smallposp.size() small (<=GBASISF4_BUCHBERGER) + unsigned np=smallposv.size(); + if (np==B.size() && np<=max_pairs_by_iteration){ + swap(smallposp,B); + B.clear(); + } + else { + // multiply by parallel? + if (//!pairs_reducing_to_zero && + np>max_pairs_by_iteration) + np=max_pairs_by_iteration; + for (unsigned i=0;i=0;--i) + B.erase(B.begin()+smallposv[i]); + } + vectzpolymod f4buchbergerv; // collect all spolys + int f4res=-1; + const vector * permuBptr=0; +#if 0 + unsigned Galls=G.back(); + vector Gall; + Gall.reserve(Galls); + for (unsigned i=0;i(res,Gall,env,smallposp,permuBptr,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,0); +#else + f4res=zf4mod(res,G,env,smallposp,permuBptr,f4buchbergerv,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,age,multimodular,parallel,0); +#endif + if (f4res==-1) + return false; + if (f4res==0) + continue; + if (!permuBptr && !learning && f4buchberger_info_position-12) + CERR << "learning f4buchberger " << smallposp[(*permuBptr)[i]] << '\n'; + pairs_reducing_to_zero->push_back(smallposp[(*permuBptr)[i]]); + } + } + } + unsigned added=0; + for (unsigned i=0;i1) + CERR << CLOCK()*1e-6 << " reduce f4buchberger end on " << added << " from " << f4buchbergerv.size() << " pairs, zgbasis update begin" << '\n'; + vector oldG(G); + for (int i=0;i=0;--i){ + if (!f4buchbergerv[i].coord.empty()){ + zincrease(res); + if (debug_infolevel>2) + CERR << CLOCK()*1e-6 << " adding to basis leading degree " << f4buchbergerv[i].ldeg << '\n'; + if (ressize==res.size()) + res.push_back(zpolymod(order,dim,f4buchbergerv[i].ldeg)); + res[ressize].expo=f4buchbergerv[i].expo; + swap(res[ressize].coord,f4buchbergerv[i].coord); + res[ressize].age=f4buchbergerv[i].age; + res[ressize].fromleft=f4buchbergerv[i].fromleft; + res[ressize].fromright=f4buchbergerv[i].fromright; + res[ressize].logz=f4buchbergerv[i].logz; + ++ressize; + if (!multimodular || learning || f4buchberger_info_position-1>=f4buchberger_info.size()) + zgbasis_updatemod(G,B,res,ressize-1,oldG,multimodular); + } + else { + // if (!learning && pairs_reducing_to_zero) CERR << " error learning "<< '\n'; + } + } + if (!multimodular) continue; + if (!learning && f4buchberger_info_position-1 G1; + for (unsigned i=0;i to polymod + // if eliminate_flag is true, keep only basis element that do not depend + // on variables to eliminate + if (eliminate_flag && (order.o==_3VAR_ORDER || order.o>=_7VAR_ORDER)){ + resmod.clear(); + resmod.reserve(res.size()); + for (unsigned l=0;l TMP1(order,dim); + for (unsigned j=0; j1) + CERR << CLOCK()*1e-6 << " zfinal interreduction begin " << G.size() << '\n'; + resmod.resize(res.size()); + for (unsigned l=0;l1 && threads_allowed && G.size()>=200 + ){ // FIXME interreduce with coeffsmodptr + val=zinterreduce_convert(res,G,env,learning,learned_position,pairs_reducing_to_zero,f4buchberger_info,f4buchberger_info_position,recomputeR,-1/* age*/,multimodular,parallel,resmod,interred); + if (debug_infolevel && val<0) + CERR << "zinterreduce failure" << '\n'; + // zfinal_interreduce(resmod,G,env,parallel); // res->resmod must be done. discarded because too slow mem locks + } + if (val<0 || val==12345){ + for (unsigned l=0;l TMP1(order,dim); + for (int j=int(G.size())-1; j>=0;--j){ + if (debug_infolevel>1){ + if (j%10==0){ CERR << "+"; CERR.flush();} + if (j%500==0){ CERR << CLOCK()*1e-6 << " remaining " << j << '\n';} + } + if (!start_index_v.empty() && G[j]1) + CERR << CLOCK()*1e-6 << " zfinal interreduction end " << G.size() << '\n'; + } + if (ressize1 + unsigned t=0; + for (unsigned i=0;i > & v=(*coeffsmodptr)[G[i]]; + for (unsigned j=0;j + void remove_zero(vectpolymod &gbmod){ + for (int i=0;i + int rur_quotient_ideal_dimension(const vectpolymod & gbmod,polymod & lm,polymod * rurgblmptr=0,polymod * rurlmptr=0); + +void G_idn(vector & G,size_t s){ + G.resize(s); + for (size_t i=0;i + bool rur_compute(vectpolymod & gbmod,polymod & lm,polymod & lmmodradical,mod4int p,polymod & s,vector * initsep,vectpolymod & rur); + template + bool rur_compute(vectpolymod & gbmod,polymod & lm,polymod & lmmodradical,int p,polymod & s,vector * initsep,vectpolymod & rur); + + + template + bool zgbasisrur(vectpoly8 & res8,vectpolymod &resmod,vector & G,modint_t env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< zinfo_t > & f4buchberger_info,bool recomputeR,bool convertpoly8,bool eliminate_flag,bool multimodular,int parallel,bool interred,int & rurinzgbasis,vectpolymod &rurv,polymod & rurs,vector * initsep,polymod & rurlm,polymod &rurlmmodradical,polymod * rurgblmptr,polymod * rurlmptr,const gbasis_param_t & gparam,vector< vectpolymod > * coeffsmodptr){ + if (1 || + rurinzgbasis>=0){ + for (unsigned i=0;i(resmod,ressize,G,env,totdeg,pairs_reducing_to_zero,f4buchberger_info,recomputeR,eliminate_flag,multimodular,parallel,interred,gparam,coeffsmodptr); + if (rurinzgbasis==1 || rurinzgbasis<0){ + vectpolymod gbmod; + if (rurinzgbasis==1){ + gbmod.resize(G.size()); + for (int i=0;i >(0)); + } + else { + G_idn(G,res8.size()); + gbmod=resmod; + gbmod.resize(G.size()); + } + int rqi=rur_quotient_ideal_dimension(gbmod,rurlm,rurgblmptr,rurlmptr); + rurinzgbasis=rur_compute(gbmod,rurlm,rurlmmodradical,env,rurs,initsep,rurv); + } + else + rurinzgbasis=0; +#ifndef GBASIS_4PRIMES + if (convertpoly8) + convert(resmod,res8,env); +#endif + return b; + } + + // Improvements planned for the future for computations over Q + // Group primes by 4 using mod4int and mod4int2 types + // for modint_t and modint_t2 instead of modint and modint2 + // The first part of linear algebra (sparse part) would be done + // with the 4 primes in parallel, with little cost using SIMD instructions + // This would also increase confidence that a monomial is not missing + // during the computation (accidental cancellation for the 1st prime used) + // and that all the learned stuff is correct + // The second part of linear algebra (dense part) would be run individually + // first (later we could make a 4 primes rref at the cost of a larger memory + // footprint, but probably not too large since later runs have much less + // non-0 rows than the initial run) + // + // Rur improvements: see https://arxiv.org/abs/2402.07141 + template + bool zgbasis(vectpoly8 & res8,vectpolymod &resmod,vector & G,modint env,bool totdeg,vector< paire > * pairs_reducing_to_zero,vector< zinfo_t > & f4buchberger_info,bool recomputeR,bool convertpoly8,bool eliminate_flag,bool multimodular,int parallel,bool interred,vector * initsep,const gbasis_param_t & gparam,vector< vectpolymod > * coeffsmodptr){ + vectpolymod rurv; + polymod rurs; + polymod rurlm,rurlmmodradical; + int rurinzgbasis=0; + polymod * Nullptr=0; + return zgbasisrur(res8,resmod,G,env,totdeg,pairs_reducing_to_zero,f4buchberger_info,recomputeR,convertpoly8,eliminate_flag,multimodular,parallel,interred,rurinzgbasis,rurv,rurs,initsep,rurlm,rurlmmodradical,Nullptr,Nullptr,gparam,coeffsmodptr); + } +#endif // GIAC_SHORTSHIFTTYPE==16 + /* ************* + END ZPOLYMOD + ************* */ + template + bool is_gbasis(const vectpoly8 & res,double eps,bool modularcheck){ + if (res.empty()) + return false; + if (debug_infolevel>0) + CERR << "basis size " << res.size() << '\n'; + // build possible pairs (i,j) with i > lcmpairs(res.size()); + vector G; G_idn(G,res.size()); + vectpoly8 vtmp,tocheck; + vector< paire > tocheckpairs; + if (eps>0 && eps<2e-9) + modularcheck=true; + if (modularcheck) + tocheck.reserve(res.size()*10); // wild guess + else + tocheckpairs.reserve(res.size()*10); + order_t order=res.front().order; + int dim=res.front().dim; + poly8 TMP1(order,res.front().dim),TMP2(TMP1), + spol(TMP1),spolred(TMP1); + polymod spolmod(order,dim),TMP1mod(order,dim); + vectpolymod resmod; + for (unsigned i=0;i & h = res[i]; + const tdeg_t & h0=h.coord.front().u; + vector tmp(res.size()); + for (unsigned j=i+1;j1) + CERR << "checking pairs for i="<(order,dim)); + swap(tocheck.back(),spol); + } + else + tocheckpairs.push_back(paire(i,j)); + } // end j loop + if (debug_infolevel>1) + CERR << '\n'; + } + if (debug_infolevel>0) + CERR << "Number of critical pairs to check " << (modularcheck?tocheck.size():tocheckpairs.size()) << '\n'; + if (modularcheck) // modular check is sometimes slow + return checkf4buchberger(tocheck,res,G,-1,eps); // split version is slower! + // integer check or modular check for one modulus (!= from first prime already used) + modint p=(prevprime((1<<29)-30000000)).val; + if (eps>0) + convert(res,resmod,p); + // FIXME should be parallelized + for (unsigned i=0;i0){ + spolymod(resmod[tocheckpairs[i].first],resmod[tocheckpairs[i].second],spolmod,TMP1mod,p); + reducemod(spolmod,resmod,G,-1,TMP1mod,p); + // gen den; heap_reduce(spol,res,G,-1,vtmp,spolred,TMP1,den,0); + if (!TMP1mod.coord.empty()) + return false; + } + else { + spoly(res[tocheckpairs[i].first],res[tocheckpairs[i].second],spol,TMP1,0); + reduce(spol,res,G,-1,vtmp,spolred,TMP1,TMP2,0); + // gen den; heap_reduce(spol,res,G,-1,vtmp,spolred,TMP1,den,0); + if (!spolred.coord.empty()) + return false; + } + if (debug_infolevel>0){ + CERR << "+"; + if (i%512==511) + CERR << tocheckpairs.size()-i << " remaining" << '\n'; + } + } + if (debug_infolevel) + CERR << '\n' << "Successful check of " << tocheckpairs.size() << " critical pairs" << '\n'; + return true; + } + + + /* ************* + RUR UTILITIES (rational univariate representation for 0 dimension ideals) + ************* */ + int rur_dim(int dim,order_t order){ + if (order.o==_3VAR_ORDER) return 3; + if (order.o==_7VAR_ORDER) return 7; + if (order.o==_11VAR_ORDER) return 11; + if (order.o==_16VAR_ORDER) return 16; + if (order.o==_32VAR_ORDER) return 32; + if (order.o==_48VAR_ORDER) return 48; + if (order.o==_64VAR_ORDER) return 64; + return dim; + } + + template int compare_gblm(const polymod & a,const polymod & b){ + int as=a.coord.size(),bs=b.coord.size(); + order_t order=a.order; + for (int i=0;ibs?1:-1; + } + // list of leadings coefficients of the gbasis + template void rur_gblm(const vectpolymod & gbmod,polymod & gblm){ + gblm.coord.clear(); + unsigned S = unsigned(gbmod.size()); + if (S){ + gblm.order=gbmod[0].order; + gblm.dim=gbmod[0].dim; + } + for (unsigned i=0;i void rur_gblm1(const vectpolymod & gbmod,polymod & gblm){ + unsigned S = unsigned(gbmod.size()); + for (unsigned i=0;i + int rur_quotient_ideal_dimension(const vectpolymod & gbmod,polymod & lm,polymod * rurgblmptr,polymod * rurlmptr){ + if (gbmod.empty()) + return -1; + order_t order=gbmod.front().order; + int dim=gbmod.front().dim; + unsigned S = unsigned(gbmod.size()); + lm.order=order; lm.dim=dim; lm.coord.clear(); + polymod gblm(order,dim); + rur_gblm(gbmod,gblm); + if (rurgblmptr && rurlmptr){ + bool chk; +#ifdef HAVE_LIBPTHREAD + int locked=pthread_mutex_trylock(&rur_mutex); + if (locked) + chk = false; + else + chk = gblm==*rurgblmptr; +#else + chk = gblm==*rurgblmptr; +#endif + if (chk) + lm=*rurlmptr; +#ifdef HAVE_LIBPTHREAD + if (locked) pthread_mutex_unlock(&rur_mutex); +#endif + if (chk) + return lm.coord.size(); + } + //#define RUR_IDEAL_JSTOP +#ifdef RUR_IDEAL_JSTOP + vector jstart; + if (order.o==_REVLEX_ORDER){ + // record positions where total degree appears first in gblm + jstart.resize(gblm.coord.back().u.total_degree(order)+1); + int prevtdeg=-1; + for (int j=0;jprevtdeg){ + ++prevtdeg; + for (;;){ + jstart[prevtdeg]=j; + if (prevtdeg==curtdeg) + break; + ++prevtdeg; + } + } + } + } +#endif + // for 3var, 7var, 11 var search in the first 3 var, 7 var or 11 var + // for revlex search for all variables + // we must find a leading monomial in gbmod that contains only this variable + int d=rur_dim(dim,order); + vector v(d); + for (unsigned i=0;i1e10) + return -RAND_MAX; // overflow + // the ideal is finite dimension, now we will compute the exact dimension + // a monomial degree is associated to an integer with + // [l_0,l_1,...,l_{d-1}] -> ((l_0*v1+l_1)*v2+...+l_{d-1} < v0*v1*... + // perhaps a sieve would be faster, but it's harder to implement + // and we won't consider too high order anyway... + index_t cur(d); + for (longlong I=0;I cur -> tdeg_t + for (int j=int(v.size())-1;j>=0;--j){ + longlong q=i/v[j]; + cur[j]=i-q*v[j]; + i=q; + } + tdeg_t curu(cur,order); + // then search if > to one of the leading monomials for all indices + unsigned j=-1; + if (order.o==_3VAR_ORDER){ + for (j=0;j=u.tab[1] && curu.tab[2]>=u.tab[2] && curu.tab[3]>=u.tab[3]) + break; + } + } + if (order.o==_7VAR_ORDER){ + } + if (order.o==_11VAR_ORDER){ + } + if (order.o==_REVLEX_ORDER){ + int curtdeg=curu.total_degree(order),jstop; + j=0; jstop=S; +#ifdef RUR_IDEAL_JSTOP + //if (curtdeg>=jstart.size()) j=S; + if (curtdeg+1>=jstart.size()) + jstop=S; + else + jstop=jstart[curtdeg+1]; + //CERR << "jstop " << jstop << '\n'; +#endif + for (;j(create(1),curu)); + else { + int D=d; + while (D>=2 && cur[D-1]==0) --D; + if (D!=d || cur[D-1]!=v[D-1]-1){ + // increase I to the next multiple + longlong prod=v[d-1]; + for (;D(order)); + if (rurgblmptr && rurlmptr){ +#ifdef HAVE_LIBPTHREAD + int locked=pthread_mutex_trylock(&rur_mutex); + if (locked) + return unsigned(lm.coord.size()); +#endif + *rurgblmptr=gblm; + *rurlmptr=lm; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&rur_mutex); +#endif + } + return unsigned(lm.coord.size()); + } + + template + void rur_mult(const polymod & a,const polymod & b,modint p,polymod & res,polymod &tmp){ + res.coord.clear(); + for (unsigned i=0;i + void rur_mult(const polymod & a,const polymod & b,modint p,polymod & res){ + polymod tmp(b.order,b.dim); + rur_mult(a,b,p,res,tmp); + } + + // coordinates of cur w.r.t. lm + template + void rur_coordinates(const polymod & cur,const polymod & lm,vecteur & tmp,vector * ptr=0){ + unsigned k=0,j=0; + for (;j + void rur_coordinates(const polymod & cur,const polymod & lm,vector & tmp,vector * ptr=0){ + unsigned k=0,j=0; + for (;j + bool rur_linsolve(const vectpolymod & gbmod,const polymod & lm,const polymod & s,const matrice & M,modint_t p,matrice & res){ + int S=int(lm.coord.size()),dim=lm.dim; + if (M.size()==1+dim){ + // M is not the matrix of the system, it is already a kernel + for (int i=1;i<=dim;++i){ + gen g=M[i]; + if (g.type!=_VECT) return false; + vecteur m(*g._VECTptr); + if (m.size()>S){ + rur_cleanmod(m); + if (m[m.size()-(dim-i)-1]!=-1) return false; + m[m.size()-(dim-i)-1]=0; + } + reverse(m.begin(),m.end()); + m=trim(m,0); + res.push_back(m); + } + return true; + } + order_t order=lm.order; + polymod TMP1(order,dim); + vector G; G_idn(G,gbmod.size()); + matrice N(M); + polymod si(order,dim); + int d=rur_dim(dim,order); + vecteur tmp(lm.coord.size()); + for (unsigned i=0;int(i) & v, const vector & w,int p,longlong res=0){ + longlong p2=extend(p)*p,p4=4*p2; + vector::const_iterator it=v.begin(),itend=v.end(),it4=itend-4,jt=w.begin(),jtend=w.end(); + if (p2<(1ULL<<59)){ + for (;it>63)&p4; + } + } + for (; it!=itend;++jt,++it){ + //if (!*it) continue; + res += extend(*it)*(*jt); + res -= p2; + res += (res>>63)&p2; + } + res %= p; + //if (res<0) CERR << "bug\n"; + return res; + } + + + void multmod_positive4(const vector & v1, const vector & v2,const vector & v3,const vector & v4,const vector & w,int p,int &res1,int & res2,int & res3,int & res4){ + longlong r1=res1,r2=res2,r3=res3,r4=res4; + longlong p2=extend(p)*p,p4=4*p2; + vector::const_iterator it1=v1.begin(),itend=v1.end(),itend4=itend-4,it2=v2.begin(),it3=v3.begin(),it4=v4.begin(),jt=w.begin(),jtend=w.end(); +#if defined CPU_SIMD && defined __AVX2__ + Vec4q R1(0),R2(0),R3(0),R4(0),p44(4*p2),V1,V2,V3,V4,w4,w4s; + itend4=itend-15; // itend8 + if (p2<(1ULL<<59)){ + for (;it1>32; + V1.load(&*it1); + R1 += _mm256_mul_epi32(w4,V1); // 4 products + V1 >>= 32; + R1 += _mm256_mul_epi32(w4s,V1); // 4 products + V2.load(&*it2); + R2 += _mm256_mul_epi32(w4,V2); // 4 products + V2 >>= 32; + R2 += _mm256_mul_epi32(w4s,V2); // 4 products + V3.load(&*it3); + R3 += _mm256_mul_epi32(w4,V3); // 4 products + V3 >>= 32; + R3 += _mm256_mul_epi32(w4s,V3); // 4 products + V4.load(&*it4); + R4 += _mm256_mul_epi32(w4,V4); // 4 products + V4 >>= 32; + R4 += _mm256_mul_epi32(w4s,V4); // 4 products + jt+=8;it4+=8;it3+=8;it2+=8;it1+=8; + w4.load(&*jt); // load 8 values + w4s = w4>>32; + V1.load(&*it1); + R1 += _mm256_mul_epi32(w4,V1); // 4 products + V1 >>= 32; + R1 += _mm256_mul_epi32(w4s,V1); // 4 products + R1 -= p44; + R1 += (R1>>63)&p44; + V2.load(&*it2); + R2 += _mm256_mul_epi32(w4,V2); // 4 products + V2 >>= 32; + R2 += _mm256_mul_epi32(w4s,V2); // 4 products + R2 -= p44; + R2 += (R2>>63)&p44; + V3.load(&*it3); + R3 += _mm256_mul_epi32(w4,V3); // 4 products + V3 >>= 32; + R3 += _mm256_mul_epi32(w4s,V3); // 4 products + R3 -= p44; + R3 += (R3>>63)&p44; + V4.load(&*it4); + R4 += _mm256_mul_epi32(w4,V4); // 4 products + V4 >>= 32; + R4 += _mm256_mul_epi32(w4s,V4); // 4 products + R4 -= p44; + R4 += (R4>>63)&p44; + } + } +#else + if (p2<(1ULL<<59)){ + for (;it1>63)&p4; + r2 += (*it2)*j0+it2[1]*j1+it2[2]*j2+it2[3]*j3; + r2 -= p4; + r2 += (r2>>63)&p4; + r3 += (*it3)*j0+it3[1]*j1+it3[2]*j2+it3[3]*j3; + r3 -= p4; + r3 += (r3>>63)&p4; + r4 += (*it4)*j0+it4[1]*j1+it4[2]*j2+it4[3]*j3; + r4 -= p4; + r4 += (r4>>63)&p4; + } + } +#endif +#if defined CPU_SIMD && defined __AVX2__ + p4 = 2*p2; + r1 = res1+R1.extract(0)+R1.extract(1); + r1 -= p4; + r1 += (r1>>63)&p4; + r1 += R1.extract(2)+R1.extract(3); + r1 -= p4; + r1 += (r1>>63)&p4; + r2 = res2+R2.extract(0)+R2.extract(1); + r2 -= p4; + r2 += (r2>>63)&p4; + r2 += R2.extract(2)+R2.extract(3); + r2 -= p4; + r2 += (r2>>63)&p4; + r3 = res3+R3.extract(0)+R3.extract(1); + r3 -= p4; + r3 += (r3>>63)&p4; + r3 += R3.extract(2)+R3.extract(3); + r3 -= p4; + r3 += (r3>>63)&p4; + r4 = res4+R4.extract(0)+R4.extract(1); + r4 -= p4; + r4 += (r4>>63)&p4; + r4 += R4.extract(2)+R4.extract(3); + r4 -= p4; + r4 += (r4>>63)&p4; +#endif + for (; it1!=itend;++jt,++it4,++it3,++it2,++it1){ + longlong j=*jt; + r1 += *it1*j; + r1 -= p2; + r1 += (r1>>63)&p2; + r2 += *it2*j; + r2 -= p2; + r2 += (r2>>63)&p2; + r3 += *it3*j; + r3 -= p2; + r3 += (r3>>63)&p2; + r4 += *it4*j; + r4 -= p2; + r4 += (r4>>63)&p2; + } + res1 = r1%p; + res2 = r2%p; + res3 = r3%p; + res4 = r4%p; + } + +// matrix vector multiplication assuming all coordinates are positive + void multmod_positive(const vector< vector > &m,const vector & v,int p,vector & mv){ + mv.resize(m.size()); + for (int i=0;i > &m,const vector &ms,const vector & v,int p,vector & mv){ + mv.resize(m.size()); + for (int i=0;i w; + // set mv and w using ms + for (int i=0;i & v,const vector< vector > &m,const vector &ms,int p,vector & mv){ + mv.resize(v.size()); + int j=0; + int i4[8],i4pos=0; // vector i4; + for (int i=0;i=0) + mv[i]=v[ms[i]]; + else { + i4[i4pos]=i; ++i4pos; // i4.push_back(i); + i4[i4pos]=j; ++i4pos; // i4.push_back(j); + mv[i]=0; + if (i4pos==8){ + multmod_positive4(m[i4[1]],m[i4[3]],m[i4[5]],m[i4[7]],v,p,mv[i4[0]],mv[i4[2]],mv[i4[4]],mv[i4[6]]); + i4pos=0; + } + ++j; + } + } + for (int i=0;i + bool rur_minpoly(const vectpolymod & gbmod,const polymod & lm,const polymod & s,modint_t p,vecteur & m,matrice & M){ + int S=int(lm.coord.size()),dim=lm.dim; + order_t order=lm.order; + polymod TMP1(order,dim),TMP2(order,dim); + vector G; G_idn(G,gbmod.size()); + bool done=false; + matrice chk; + if (1){ + M.clear(); + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " rur separate " << s << " * monomial matrix computation " << S << '\n'; + // matrix of multiplication by s of all monomials in lm + // stored as a partially sparse matrix in mults/multv + polymod cur(order,dim); + vector tmp(S),tmp1; + vecteur tmpv(S); + vector< vector > mults(S,vector(S)),tmpm; int multspos=0; + vector multv(S); + polymod gblm(order,dim); + vector< polymod > missed; + rur_gblm(gbmod,gblm); + reverse(gblm.coord.begin(),gblm.coord.end()); + int miss=0; bool missed_at_end=true; vector missed_pos; + for (int i=0;i >::const_iterator jt=lm.coord.begin(),jtend=lm.coord.end(),jt_=jt; + if (dicho(jt_,jtend,cur.coord.front().u,order)){ + multv[i]=jt_-jt; + continue; + } + jt=gblm.coord.begin();jtend=gblm.coord.end(); + if (dicho(jt,jtend,cur.coord.front().u,order)){ + int curpos=jtend-jt; + const polymod & curgb=gbmod[curpos-1]; + jt=curgb.coord.begin()+1; jtend=curgb.coord.end(); + cur.coord.clear(); cur.coord.reserve(jtend-jt); + for (;jt!=jtend;++jt){ + cur.coord.push_back(T_unsigned(-jt->g,jt->u)); + } + red=true; + } + } + if (!red){ + miss++; + if (missed_at_end){ + missed.push_back(cur); + missed_pos.push_back(multspos); + cur.coord.clear(); + } + else + reducesmallmod(cur,gbmod,G,-1,p,TMP1,false); + } + multv[i]=-1; + rur_coordinates(cur,lm,tmp); + make_positive(tmp,p); + mults[multspos].swap(tmp); ++multspos; // mults.push_back(tmp); + } + if (missed_at_end){ + bool doit=true; + if (//0 && + miss>=0.1*S){ + doit=zsimult_reduce(missed,gbmod,p,false,1); // done if it returns 0 + } + if (doit) { + for (int i=0;i > Kxi(d,vector(S)); Kxi.reserve(d); + polymod si(order,dim); + polymod one(order,dim); + one.coord.push_back(T_unsigned(1,tdeg_t(index_m(dim),order))); + vector nonzero(S,false); vector posxi(d,-1); + index_t l(dim); + for (unsigned i=0;int(i) >::const_iterator jt=lm.coord.begin(),jtend=lm.coord.end(),jt_=jt; + if (dicho(jt_,jtend,si.coord.front().u,order)){ + tmp.clear(); tmp.resize(S); tmp[jt_-jt]=1; + nonzero[jt_-jt]=true; + posxi[i]=jt_-jt; + } + else { + jt=gblm.coord.begin();jtend=gblm.coord.end(); + if (dicho(jt,jtend,si.coord.front().u,order)){ + int curpos=jtend-jt; + const polymod & curgb=gbmod[curpos-1]; + jt=curgb.coord.begin()+1; jtend=curgb.coord.end(); + si.coord.clear(); si.coord.reserve(jtend-jt); + for (;jt!=jtend;++jt){ + si.coord.push_back(T_unsigned(-jt->g,jt->u)); + } + } + else + reducesmallmod(si,gbmod,G,-1,p,TMP1,false); + // get coordinates of cur in tmp (make them mod p) + rur_coordinates(si,lm,tmp,&nonzero); + make_positive(tmp,p); + } + Kxi[i].swap(tmp); + } + int count=0; + for (int i=0;i1) CERR << CLOCK()*1e-6 << "Hankel start\n" ; + // IMPROVE: compute s^0 to s^[2S-1] (instead of s^0 to s^S) + // take coordinate of index corresponding to 1 in lm + // and find minpoly q using reverse_rsolve + // Simultaneously, for each coordinate x1..x_d, + // find coordinates of x_i reduced in the list of monomials lm, + // make scalar product with s^k + // then solve Hankel system of SxS matrix with antidiagonals + // the 1st coordinates above, and second member a vector with + // components the scalar products with s^k for 0<=k=1 g_i z^(-i)=p/q at z=infinity, deg(q)=S, deg(p)(S); + for (int i=0;i g(2*S); + vector< vector > hankelsystb(d,vector(S)); // second members of Hankel systems + for (int i=0;i=0) + hankelsystb[j][i]=tmp[posxi[j]]; + else + hankelsystb[j][i]=multmod_positive(Kxi[j],tmp,p); + } + g[i]=tmp.back(); + multmod_positive(tmp,tmpm,multv,p,tmp1); + tmp.swap(tmp1); + } + if (debug_infolevel>1) CERR << CLOCK()*1e-6 << " Hankel mult part 2\n" ; + for (int i=S;i<2*S;++i){ + g[i]=tmp.back(); + multmod_positive(tmp,tmpm,multv,p,tmp1); + tmp.swap(tmp1); + } + if (debug_infolevel>1) CERR << CLOCK()*1e-6 << " Hankel mult end\n" ; + vecteur V; vector_int2vecteur(g,V); + reverse(V.begin(),V.end()); // degree(V)=2S-1, size(V)=2S + V=trim(V,0); + vecteur x2n(2*S+1),A,B,G,U,unused,D,tmp1,tmp2; x2n[0]=1; // x2n=x^(2*S) + environment env; env.modulo=p; env.moduloon=true; + if ( + hgcd(x2n,V,p,G,U,D,B,unused,A,tmp1,tmp2) + ){ + if (A.empty()){ + // A=D*x2n+B*V + operator_times(B,V,&env,A); + // keep S terms (lower part) + if (A.size()>S) + A.erase(A.begin(),A.end()-S); + } + //egcd_pade(x2n,V,S,A,B,&env); + if (debug_infolevel) CERR << CLOCK()*1e-6 << " Hankel after Pade degrees " << S << "," << A.size() << "," << B.size() << "\n" ; + reverse(B.begin(),B.end()); + while (B.size() u,b; + vecteur2vector_int(U,p,u); + make_positive(u,p); + vecteur2vector_int(B,p,b); + make_positive(b,p); + reverse(u.begin(),u.end()); reverse(b.begin(),b.end()); + while (u.size() > bez(S,vector(S)); + // initialization + for (int i=0;i>63) & p2; // make r positive + bez[i][j]=r%p; + } + } + // recursion + for (int i=1;i<=S-2;++i){ + for (int j=i;j<=S-2;++j){ + int r = bez[i][j]; + r += bez[i-1][j+1]-p; + r += (r>>31) & p; // make r positive + bez[i][j] = r; + } + } + // symmetry + for (int i=1;i1) CERR << CLOCK()*1e-6 << " Hankel *\n" ; + vector< vector > Ker(d+1); + vecteur2vector_int(m,p,Ker[0]); + for (int i=0;i1) CERR << CLOCK()*1e-6 << "Hankel end\n" ; + return true; + } // end D.size()==1 + else { + if (1 && D.back()==0 && D[D.size()-2]==0){ + DivRem(m,D,&env,unused,U);m=unused;//m.clear(); + return true; + } + else + m.clear(); + } + } // end B.front()!=0 + } // end B.size()==S+1 + } + } // end optimization with Hankel system + tmp=vector(S); + tmp[S-1]=1; + vector< vector > K; K.reserve(S+1+d); + K.push_back(tmp); + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " rur start v<-M*v\n"; + for (int i=0;i > Ker; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin rur ker" << '\n'; + if (!mker(K,Ker,p) || Ker.empty() ) + return false; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end rur ker" << '\n'; + vector_int2vecteur(Ker.front(),m); + reverse(m.begin(),m.end()); + m=trim(m,0); + // Ker->M + vectvector_int2vecteur(Ker,M); + if (m.size()>S+1) return false; + if (debug_infolevel>2) + CERR << "Minpoly for " << s << ":" << m << '\n'; + return true; +#endif + // s^i is obtained by multiplying mults by the coordinates of s^[i-1] + tmpv[0]=makemod(0,p); + tmpv[S-1]=1; + M.push_back(tmpv); + tmp=vector(S); + tmp[S-1]=1; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << "rur start v<-M*v\n"; + for (int i=0;i cur(s); + for (unsigned i=1;i<=lm.coord.size();++i){ + reducesmallmod(cur,gbmod,G,-1,p,TMP1,false); + // get coordinates of cur in tmp (make them mod p) + rur_coordinates(cur,lm,tmp); + M.push_back(tmp); + // multiply cur and s + rur_mult(cur,s,p,TMP1); + cur.coord.swap(TMP1.coord); + } + } +#if 1 + if (!chk.empty() && !is_zero(smod(chk-M,p))) + CERR << "bug\n" ; + // add coordinates to avoid a separate linsolve with the same matrix + matrice N(M); + M.pop_back(); // remove the last one (for further computations, assuming max rank) + polymod si(order,dim); + int d=rur_dim(dim,order); + vecteur tmp(lm.coord.size()); + polymod one(order,dim); + one.coord.push_back(T_unsigned(1,0)); + for (unsigned i=0;int(i)1) + CERR << CLOCK()*1e-6 << " begin rur ker" << '\n'; + if (!mker(N,K,1,context0) || K.empty() || K.front().type!=_VECT) + return false; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end rur ker" << '\n'; + m=*K.front()._VECTptr; + rur_cleanmod(m); + reverse(m.begin(),m.end()); + m=trim(m,0); + K.swap(M); + if (m.size()>S+1) return false; + if (debug_infolevel>2) + CERR << "Minpoly for " << s << ":" << m << '\n'; + return true; +#else + if (!chk.empty() && !is_zero(smod(chk-M,p))) + CERR << "bug\n" ; + matrice N(M); + M.pop_back(); // remove the last one (for further computations, assuming max rank) + if (!N.empty() && !N.front()._VECTptr->empty()) N=mtran(N); + vecteur K; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " begin rur ker" << '\n'; + if (!mker(N,K,1,context0) || K.empty() || K.front().type!=_VECT) + return false; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " end rur ker" << '\n'; + m=*K.front()._VECTptr; + for (unsigned i=0;i2) + CERR << "Minpoly for " << s << " degree " << m.size() << " :" << m << '\n'; + return true; +#endif + } + + template + void rur_convert_univariate(const vecteur & v,int varno,polymod & tmp){ + int vs=int(v.size()); + order_t order=tmp.order; + tmp.coord.clear(); + index_t l(tmp.dim); + for (unsigned j=0;int(j)(v[j].val,tdeg_t(index_m(l),order))); + } + } + + template + void rur_convert_univariate(const vector & v,int varno,polymod & tmp){ + int vs=int(v.size()); + order_t order=tmp.order; + tmp.coord.clear(); + index_t l(tmp.dim); + for (unsigned j=0;int(j)(v[j],tdeg_t(index_m(l),order))); + } + } + + // if radical==-1, shrink the ideal to radical part + // if radical==1, the ideal is already radical + // if radical==0, also tries with radical ideal + // find a separating element, given the groebner basis and the list of leading + // monomials of a basis of the quotient ideal + // if true, then separating element is s + // and s has m as minimal polynomial, + // M is the list of rows coordinates of powers of s in lm + // or is already the rur (computed by using Hankel matrices) + // (cf. rur_linsolve) + template + bool rur_separate(vectpolymod & gbmod,polymod & lm,modint_t p,polymod & s,vector * initsep,vecteur & m,matrice & M,int radical){ + order_t order=lm.order; + int dim=lm.dim,d=rur_dim(dim,order); + s.order=order; s.dim=dim; + vecteur minp(d); + if (initsep && !initsep->empty()){ + s.coord.clear(); m.clear(); M.clear(); + for (unsigned i=0;int(i)(r1,tdeg_t(l,order))); + } + if (!rur_minpoly(gbmod,lm,s,p,m,M)) + return false; + if (m.size()==lm.coord.size()+1) + return true; + return false; + } + // first try coordinates + for (int i=d-1;i>=0;--i){ + s.coord.clear(); m.clear(); M.clear(); + index_t l(dim); + l[i]=1; + s.coord.push_back(T_unsigned(1,tdeg_t(l,order))); + if (!rur_minpoly(gbmod,lm,s,p,m,M)) + return false; + if (m.size()==lm.coord.size()+1) + return true; + // keep m in order to shrink to the radical ideal if separation fails + if (radical<=0) + minp[i]=m; + } + bool tryseparate=radical!=-1; + environment env; + env.modulo=p; + env.moduloon=true; + if (radical==0){ + // additional check for non sqrfree minp, + // for solve([3*x^2-3*z^2,3*y^2-3*z^2,x*y+y*z+x*z-x*y*z],[x,y,z]); + for (int i=0;i1){ + tryseparate=false; + break; + } + } + } + // now try a random small integer linear combination + if (tryseparate){ + // 6 july 2020: # of tries 40->100 for + // eqs:=[c^2 - 3, -a^14 + 85/6*a^12 - 13465/144*a^10 + 54523/144*a^8 - 20819/18*a^6 + 8831/3*a^4 - 7384*a^2 + 10800, -b^14 + 59/4*b^12 - 459/4*b^10 + 8159/16*b^8 - 11777/8*b^6 + 40395/16*b^4 - 10971/4*b^2 + 3267, -1/599040*(53136*b^14 - 692236*b^12 + 4886796*b^10 - 20593959*b^8 + 57747314*b^6 - 116274195*b^4 + 186055404*b^2 - 162887472)*(1008*a^13 - 12240*a^11 + 67325*a^9 - 218092*a^7 + 499656*a^5 - 847776*a^3 + 1063296*a) - 1/112320*(111024*a^14 - 1310760*a^12 + 7843395*a^10 - 35101603*a^8 + 158038072*a^6 - 630801328*a^4 + 1561088256*a^2 - 1489593600)*(56*b^13 - 708*b^11 + 4590*b^9 - 16318*b^7 + 35331*b^5 - 40395*b^3 + 21942*b)]; + // pour j de 1 jusque 100 faire gb:=gbasis(eqs,[c,a,b],rur);fpour; + // 40 was insufficient for the 11th gbasis rur computation + unsigned essai=0; + int testall1=gbmod.size()<=dim+5?0:rur_separate_max_tries/8; + for (;essai(r1,tdeg_t(l,order))); + } + if (s.coord.size()<2) // monomials already done + continue; + if (!rur_minpoly(gbmod,lm,s,p,m,M)) + return false; + if (m.size()==lm.coord.size()+1) + return true; + } + if (radical==1) + return false; + if (essai==rur_separate_max_tries){ + gensizeerr("Unable to find a separation form for the RUR computation. Try rur_separate_max_tries(n) with n larger than "+print_INT_(rur_separate_max_tries)); + return false; + } + } + // shrink ideal and try again + bool shrinkit=false; + for (unsigned i=0;int(i)1){ + if (debug_infolevel) + CERR << "Adding sqrfree part degree " << m1.size()-1 << " " << m1 << " coordinate " << i << '\n'; + m1=operator_div(m,m1,&env); // m1 is the square free part + polymod m1mod(order,dim); + rur_convert_univariate(m1,i,m1mod); + unsigned j; + for (j=0;j G; + if (!in_gbasisf4buchbergermod(gbmod,unsigned(gbmod.size()),G,p,/* totdeg */ true,0,0,true)) + return false; + vectpolymod newgb; + for (unsigned i=0;i(gbmod,lm,p,s,initsep,m,M,1); + } + + template + bool rur_convert(const vecteur & v,const polymod & lm,polymod & res){ + res.coord.clear(); + res.order=lm.order; res.dim=lm.dim; + if (v.size()>lm.coord.size()) + return false; + for (unsigned i=0;i(coeff.val,lm.coord[i].u)); + } + return true; + } + + + template + bool rur_compute(vectpolymod & gbmod,polymod & lm,polymod & lmmodradical,mod4int p,polymod & s,vector * initsep,vectpolymod & rur){ + // FIXME, call 4 modint rur_compute + return false; + } + + // set rur to be the list of s, + // m the minimal polynomial of s as a polymod wrt the 1st var + // and for each coordinate (sqrfree part of m) * coordinate + // expressed as a polynomial in s (stored in a polymod wrt 1st var) + // Current method (not optimal if there are multiplicities) + // Try each coordinate as a separating form s, then random linear combination + // If minpoly of s is squarefree and max degree, the ideal is cyclic + // If minpoly of s is not squarefree, shrink the ideal by adding + // the squarefree part of the minpoly of s to the ideal + // This will make the ideal radical but may be too costly. + // + // Improvement to be implemented + // F. Rouillier et al: https://arxiv.org/pdf/2402.07141 (Maple code zds.mpl) + // + // check if s is separating on bivariate ideals + // requires computing minpoly of s, and lex gbasis of bivariate ideals + // for all coordinates X=X[1] to X[j], find polynomials in s and X in ideal + // gbasis=(minpoly(s),sum(a[k,i](s)*X^i,i=0..k)) + // gbasis contains may 0 polynomial, so that degree(gbasis[k])==k if non 0 + // + // Algo 2: check separating for X=X[j] + // f[0]=sqrfree(minpoly of s) + // for k=1 to sizeof(gbasis) + // if (gbasis[k]==0) continue; + // f[k]=f[k-1]/gcd(f[k-1],lcoeff(gbasis[k])) + // for i=0 to k-1 + // if (k*(k-i)/(i+1)*a[k,k]*a[k,i] != a[k,k-1]*a[k,i+1] mod f[k]) + // return false; + // end_if + // end_for + // end_for + // + // Algo 3: find bivariate parametrization (for all coord X=X[1]to X[k]) + // n=0, d=0, rho=1, f[0]=sqrfree(f) + // for k from 1 to sizeof(gbasis) + // if (gbasis[k]==0) continue; + // f[k] = f[k-1]/gcd(f[k-1],lcoeff(gbasis[k])) + // rho *= f[k] + // d += k*a[k,k]*rho mod f[0] + // n += a[k,k-1]*rho mod f[0] + // end_for + // + // Algo 4: check a candidate separating form and return rur + // arg: do_check (if false we don't check), s (separating form), gbasis + // find minpoly(s) and store the list of rref-ed s^k for later computations + // for each coordinate X[j] + // compute a lex gbasis for algo2, using the list above (FGLM algo) + // if (do_check) check with algo2, if not return failure and coordinate # + // compute rational parametrization then rur for this coordinate + // return rur + // + // Algo 6: run algo 4 first on coordinates, then on a linear combination + // constructed using the previous candidate and modifying the coeff + // of the coordinate number that returns the failure + // if coeff<0 change sign, if coeff>=0 replace by -coeff-1 + // + // Algo 1: from rational param to rur + // Arg=(f(s)==0 not necessarily sqrfree, d[k](s)*X[k]+n[k](s) + // compute F=sqrfree(f), F1=diff(F) + // for k=1 to dim to rur[k]=-n[k]*inv(d[k] mod F)*F1 mod F + template + bool rur_compute(vectpolymod & gbmod,polymod & lm,polymod & lmmodradical,int p,polymod & s,vector * initsep,vectpolymod & rur){ + vecteur m,M,res; + int dim=lm.dim; + order_t order=lm.order; + if (s.coord.empty()){ + // find separating element + if (!rur_separate(gbmod,lm,p,s,initsep,m,M,0)) + return false; + } + else { + // if lm!=lmmodradical, ideal is not radical, recompute radical part + if (!(lm==lmmodradical)){ + polymod s1(s.order,s.dim); + if (!rur_separate(gbmod,lm,p,s1,initsep,m,M,-1)) + return false; + } + // separating element is already known + if (!rur_minpoly(gbmod,lm,s,p,m,M) || m.size()!=lm.coord.size()+1) + return false; + } + // find the square-free part of m, express it as a polymod using M + environment env; + env.modulo=p; + env.moduloon=true; + vecteur m1=derivative(m,&env); + m1=gcd(m,m1,&env); + bool sqf=m1.size()>1; + m1=operator_div(m,m1,&env); // m1 is the square free part + if (debug_infolevel && sqf) + CERR << CLOCK()*1e-6 << " sqrfree mod " << p << " degree " << m1.size()-1 << " " << m1 << '\n'; + vecteur m2=derivative(m1,&env); // m2 is the derivative, prime with m1 + // multiply by m2 at the end + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " rur linsolve" << '\n'; + polymod one(order,dim); + one.coord.push_back(T_unsigned(1,0)); + if (!rur_linsolve(gbmod,lm,one,M,p,res)) + return false; + // rur=[separating element,sqrfree part of minpoly,derivative of sqrfree part, + // derivative of sqrfree part*other coordinates] + rur.clear(); + rur.push_back(s); + polymod tmp(order,dim); + rur_convert_univariate(m1,0,tmp); + rur.push_back(tmp); + rur_convert_univariate(m2,0,tmp); + rur.push_back(tmp); + vector m2i; vecteur2vector_int(m2,0,m2i); + vector m1i; vecteur2vector_int(m1,0,m1i); + // convert res to rur + for (unsigned i=0;i v,w,q; + vecteur2vector_int(*res[i]._VECTptr,0,v); + operator_times(v,m2i,p,w); + DivRem(w,m1i,p,q,v); + rur_convert_univariate(v,0,tmp); + rur.push_back(tmp); + continue; +#endif + vecteur V(*res[i]._VECTptr),W,Q; + mulmodpoly(V,m2,&env,W); + DivRem(W,m1,&env,Q,V); + rur_convert_univariate(V,0,tmp); + rur.push_back(tmp); + } + return true; + } + + // returns -1 if lm1 is not contained in lm2 and lm2 is not contained in lm1 + // returns 0 if lm1==lm2 + // returns 1 if lm1 contains lm2 + // returns 2 if lm2 contains lm1 + template + int rur_compare(polymod & lm1,polymod & lm2){ + unsigned s1=unsigned(lm1.coord.size()),s2=unsigned(lm2.coord.size()); + if (s1==s2){ + if (lm1==lm2) + return 0; + return -1; + } + if (s1>s2){ + unsigned i=0; + for (unsigned j=0;j + struct thread_gbasis_t { + vectpoly8 * currentptr; + vectpolymod resmod,rurv; + polymod rurlm,rurlmmodradical,*rurgblmptr,*rurlmptr; + polymod rurs; + vector * initsep; + vector< vectpolymod > * coeffsmodptr; + vector G; + modint_t p; + vector< paire > * reduceto0; + vector< info_t > * f4buchberger_info; + vector< zinfo_t > * zf4buchberger_info; + bool zdata; + bool eliminate_flag; // if true, for double revlex order returns only the gbasis part made of polynomials that do not depend on variables to eliminate + bool interred; + gbasis_param_t gparam; + int rurinzgbasis; + int parallel; // max number of parallel threads for 1 modular computation + }; + + template + void * thread_gbasis(void * ptr_){ + thread_gbasis_t * ptr=(thread_gbasis_t *) ptr_; + ptr->G.clear(); + if (ptr->zdata){ + if (!zgbasisrur(*ptr->currentptr,ptr->resmod,ptr->G,ptr->p,true, + ptr->reduceto0,*ptr->zf4buchberger_info,false,false,ptr->eliminate_flag,true,ptr->parallel,ptr->interred, + ptr->rurinzgbasis,ptr->rurv,ptr->rurs,ptr->initsep,ptr->rurlm,ptr->rurlmmodradical,ptr->rurgblmptr,ptr->rurlmptr,ptr->gparam,ptr->coeffsmodptr)) + return 0; + ptr->zdata=0; + } + else { +#if 1 // ndef GBASIS_4PRIMES + if (!in_gbasisf4buchbergermod(*ptr->currentptr,ptr->resmod,ptr->G,ptr->p,true/*totaldeg*/, + ptr->reduceto0,ptr->f4buchberger_info,false)) +#endif + return 0; + } + return ptr_; + } +#endif + + template + bool check_initial_generators(vectpoly8 & res,const vectpoly8 & Wi,vector & G,double eps){ + int initial=int(res.size()); + poly8 tmp0,tmp1,tmp2; + vectpoly8 wtmp; + unsigned j=0,finalchecks=initial; + if (eps>0) + finalchecks=giacmin(2*Wi.front().dim,initial); + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " begin final check, checking that " << finalchecks << " initial generators belongs to the ideal" << '\n'; + G.resize(Wi.size()); + for (j=0;j Gused(G.size()); + for (j=0;j(res[j].order)); + reduce(res[j],Wi,G,-1,wtmp,tmp0,tmp1,tmp2,0,&Gused); + if (!tmp0.coord.empty()){ + break; + } + if (debug_infolevel && (j%10==9)) + CERR << j+1 << '\n'; + } + if (debug_infolevel){ + CERR << '\n' << " Elements used for reduction "; + for (size_t i=0;i + void convert_univariate(const poly8 & p,modpoly & P){ + P.clear(); if (p.coord.empty()) return; + unsigned char pdim=p.dim; const order_t order={(short) _REVLEX_ORDER,pdim}; + int deg=p.coord.front().u.total_degree(order); + P.resize(deg+1); + for (unsigned i=0;i + struct rur_certify_t { + const vectpoly8 * syst; + const modpoly * minp; + const modpoly * dminp; + const vector * v; + const gen * dminpden; + const vecteur * vden; + vector chk_index; + order_t order; + int dim; + bool ans; + int threadno; + const context * contextptr; + }; + + modpoly free_copy(const modpoly & v){ + modpoly res(v.size()); + for (int i=0;i + void * thread_rur_certify(void * ptr) { + rur_certify_t * Rptr=(rur_certify_t *) ptr; + const vectpoly8 & syst =*Rptr->syst; + modpoly minp=free_copy(*Rptr->minp); + modpoly dminp=free_copy(*Rptr->dminp); + modpoly tmp,rem; + vector v(Rptr->v->size()); + for (int i=0;iv)[i]); + vecteur vden=free_copy(*Rptr->vden); + const vector & chk_index=Rptr->chk_index; + const order_t & order=Rptr->order; + int dim=Rptr->dim,locked=false; + const context * contextptr=Rptr->contextptr; + const gen dminpden=*Rptr->dminpden; + for (int i_=0;i_ & cur=syst[i]; + if (cur.coord.empty()) continue; + int deg=cur.coord.front().u.total_degree(order); +#ifdef HAVE_LIBPTHREAD + locked=pthread_mutex_trylock(&rur_mutex); +#endif + if (rur_do_certify>0 && deg>rur_do_certify){ + *logptr(locked?context0:contextptr) << "rur_certify: equation not checked, degree too large " << deg << " run rur_certify(1) to check all equations\n"; + continue; + } +#ifdef HAVE_LIBPTHREAD + if (locked) pthread_mutex_unlock(&rur_mutex); +#endif + if (Rptr->threadno==0 && + debug_infolevel) *logptr(contextptr) << clock_realtime() << " rur_certify checking equation "<< i << " degree " << deg << "\n"; + modpoly sum; gen sumden(1); + for (int j=0;j vp; vp.reserve(deg); + for (int k=0;kthreadno==0?debug_infolevel:0); + mulmodpoly(prod,cur.coord[j].g,0,prod); + // sum/sumden = sum/sumden+prod/prodden + // = (sum*(prodden/g)+prod*(sumden/g)) / (g*prodden/g*sumden/g) + gen g=simplify3(sumden,prodden); + mulmodpoly(sum,prodden,0,sum); + mulmodpoly(prod,sumden,0,prod); + addmodpoly(sum,prod,0,tmp); sum.swap(tmp); + sumden=g*sumden*prodden; + } + // remainder + if (!DivRem(sum,minp,0,tmp,rem,true) || !rem.empty()){ + Rptr->ans=false; +#ifdef HAVE_LIBPTHREAD + locked=pthread_mutex_trylock(&rur_mutex); +#endif + *logptr(locked?context0:contextptr) << "rur_certify failure equation " << i << "\n"; +#ifdef HAVE_LIBPTHREAD + if (locked) pthread_mutex_unlock(&rur_mutex); +#endif + return ptr; + } +#ifdef HAVE_LIBPTHREAD + locked=pthread_mutex_trylock(&rur_mutex); +#endif + if (debug_infolevel) + *logptr(contextptr) << clock_realtime() << " rur_certify equation "<< i << " degree " << deg << " check success.\n"; + } + Rptr->ans=true; + return ptr; + } + + template + bool rur_certify(const vectpoly8 & syst,vectpoly8 & val,int gbshift,GIAC_CONTEXT){ + if (rur_do_certify<0) return true; + // rur final check could be performed by replacing + // val[gbshift+3..end]/val[gbshift+2] + // in the initial syst system variables + // and check if it's 0 mod val[gbshift+1] + // u.total_degree(order), get_index(u,index_t,order,dim) + if (syst.empty()) return true; + unsigned char pdim=syst[0].dim; const order_t order={(short) _REVLEX_ORDER,pdim}; + int dim=val.size()-gbshift-3; + modpoly minp,dminp,rem,tmp; vector v(dim); gen minpden,dminpden; vecteur vden(dim); + cpureal_t t1=clock_realtime(); + size_t nm=0; + for (int i=0;i1){ + if (nthreads>rur_certify_maxthreads) nthreads=rur_certify_maxthreads; // don't use too much memory + if (debug_infolevel) + *logptr(contextptr) << "rur_certify: multi-thread check, info displayed on may miss some threads info. Threads in use: " << nthreads << "\n"; + pthread_t tab[MAXNTHREADS]; + vector< rur_certify_t > rur_certify_param; rur_certify_param.reserve(nthreads); + for (int j=0;j chk_index; + for (int k=j;k cur={&syst,&minp,&dminp,&v,&dminpden,&vden,chk_index,order,dim,true,j,contextptr}; + rur_certify_param.push_back(cur); + bool res=true; + if (j,(void *) &rur_certify_param[j]); + if (res) + thread_rur_certify((void *)&rur_certify_param[j]); + } + bool ans=true; + void * threadretval[MAXNTHREADS]; + for (int j=0;j & cur=syst[i]; + if (cur.coord.empty()) continue; + int deg=cur.coord.front().u.total_degree(order); + if (debug_infolevel) *logptr(contextptr) << CLOCK()*1e-6 << " rur_certify cheking equation "<< i << " degree " << deg << "\n"; + modpoly sum; gen sumden(1); + for (int j=0;j vp; vp.reserve(deg); + for (int k=0;k void copy(const polymod & src, polymod & target){ + convert(src,target); + } + + inline int getint(qmodint p, int pos){ return p.tab[pos]; } + +#else // GBASIS_4PRIMES + + typedef modint qmodint; + typedef modint2 qmodint2; + qmodint prevprime_qmodint(qmodint & p,const gen & llcm){ + // find a prime not dividing llcm (the lcm of the leading coeffs of the initial basis) + for (;;){ + p=prevprime(p-1).val; + if (!is_zero(llcm % p)) + break; + } + return p; + } + inline int getint(qmodint p, int pos){ return p; } + template void copy(const polymod & src, polymod & target){ + target=src; + } + +#endif // GBASIS_4PRIMES + + // return 0 (failure), 1 (success), -1: parts of the gbasis reconstructed + template + int in_mod_gbasis(vectpoly8 & res,bool modularcheck,bool zdata,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_par,int gbasis_logz_age,vector< vectpoly8 > * coeffsmodptr=0){ + gen llcm=1; + for (int i=0;i & cur=res[i]; + if (!cur.coord.empty()) + llcm=lcm(llcm,cur.coord.front().g); + } + if (debug_infolevel) + CERR << "Lcm of leading coefficients of initial generators " << llcm << "\n"; + cpureal_t init_time=clock_realtime(); + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " modular gbasis algorithm start, mem " << memory_usage() << '\n'; + if (coeffsmodptr && !zdata) + return 0; + bool & eliminate_flag=gbasis_par.eliminate_flag; + bool interred=gbasis_logz_age==0; // final interreduce + if (interred) + interred=gbasis_par.interred; + unsigned initial=unsigned(res.size()); + double eps=proba_epsilon(contextptr); int rechecked=0; + order_t order={0,0}; + bool multithread_enabled=true; + // multithread was disabled for more than 14 vars because otherwise + // threads:=2; n:=9;P:=mul(1+x[j]*t,j=0..n-1); + // X:=[seq(x[j],j=0..n-1)]; + // S:=seq(p[j]-coeff(P,t,j), j=1..n-1); + // N:=sum(x[j]^(n-1),j=0..n-1); + // I:=[N,S]:;eliminate(I,X) + // segfaults and valgrind does not help... seems to work now but not z8 + for (unsigned i=0;i & P=res[i]; + if (multithread_enabled && !P.coord.empty()){ +#ifdef ATOMIC +#else + multithread_enabled=!P.coord.front().u.vars64(); +#endif + } + order=P.order; + for (unsigned j=0;j toreinject; + if (gbasis_par.reinject_begin>=0 && gbasis_par.reinject_end>gbasis_par.reinject_begin){ + toreinject=res; //vectpoly8(res.begin()+gbasis_par.reinject_begin,res.begin()+gbasis_par.reinject_end); + if (gbasis_par.reinject_for_calc>0 && gbasis_par.reinject_for_calc >(gbasis_logz_age)); + } + // if (order!=_REVLEX_ORDER) zdata=false; + vectpoly8 current,current_orig,current_gbasis,vtmp,afewpolys; + vectpolymod resmod; + vectpolymod gbmod; + poly8 poly8tmp; +#if defined(EMCC) || defined(EMCC2) + // use smaller primes + int pstart=94906249-_floor(giac_rand(contextptr)/32e3,contextptr).val; + // gen p=(1<<24)-_floor(giac_rand(contextptr)/32e3,contextptr); +#else + int pstart=(1<<29)-_floor(giac_rand(contextptr)/1e3,contextptr).val; +#endif +#ifdef GBASIS_4PRIMES + qmodint_t p_qmodint=mkmod4int(pstart); +#else + qmodint_t p_qmodint=pstart; +#endif + int pcur; + // unless we are unlucky these lists should contain only 1 element + vector< vectpoly8 > V; // list of (chinrem reconstructed) modular groebner basis + vector< vectpoly8 > W; // list of rational reconstructed groebner basis + vector< vectpoly8 > Wlast; + int dim=0; vectpoly8 Wrur; // rur reconstruction part + vecteur P; // list of associate (product of) modulo + // variables for rational univar. reconstr. + polymod lmmod,lmmodradical,prevgblm,mainthrurlm,mainthrurlmsave,mainthrurlmmodradical,mainthrurgblm; + vectpolymod mainthrurv; + polymod rurs,cur_gblm,prev_gblm,zlmmod,zlmmodradical; + vectpolymod rurv; + // zrur is !=0 if rur computation was already done in zgbasis + int prevrqi; int zrur=0,rurinzgbasis=0,mainthrurinzgbasis=0; + // environment env; + // env.moduloon=true; + vector G; + vector< paire > reduceto0; + vector< info_t > f4buchberger_info; + f4buchberger_info.reserve(GBASISF4_MAXITER); + vector > zf4buchberger_info; + zf4buchberger_info.reserve(GBASISF4_MAXITER); + mpz_t zu,zd,zu1,zd1,zabsd1,zsqrtm,zq,zur,zr,ztmp; + mpz_init(zu); + mpz_init(zd); + mpz_init(zu1); + mpz_init(zd1); + mpz_init(zabsd1); + mpz_init(zsqrtm); + mpz_init(zq); + mpz_init(zur); + mpz_init(zr); + mpz_init(ztmp); + bool ok=true; +#ifdef HAVE_LIBPTHREAD + int nthreads=(threads_allowed && multithread_enabled)?giacmin(threads,MAXNTHREADS):1,th,parallel=1; + pthread_t tab[MAXNTHREADS]; + thread_gbasis_t gbasis_param[MAXNTHREADS]; +#else + int nthreads=1,th,parallel=1; +#endif + bool rur_gbasis=rur_do_gbasis>=0 || gbasis_par.gbasis; + bool chk_initial_generator=true; + // for more than 2 threads, real time is currently better without + // reason might be that the gbasis is large, reduction mod p for + // all threads has bad cache performances? + // IMPROVE 1: compute resmod for all threads simult in main thread + // IMPROVE 2: check whether the rur stabilizes before the gbasis! + int initgensize=0; // number of initial generators (if computing coeffs) + ulonglong nmonoms; // number of monoms in gbasis + int recon_n2=-1,recon_n1=-1,recon_n0=-1,recon_added=0,recon_count=0,gbasis_size=-1,jpos_start=-1; // reconstr. gbasis element number history + double augmentgbasis=gbasis_reinject_ratio,prevreconpart=1.0,time1strun=-1.0,time2ndrun=-1.0; current_orig=res; current_gbasis=res; + int primecount=0; + // if the ratio of reconstructed is more than augmentgbasis, + // we clear info and add reconstruction to the gbasis + for (int count=0;ok;++count,++recon_count){ + if (count==0 || nthreads==1 || (zdata && augmentgbasis && reduceto0.empty())){ + th=0; + parallel=nthreads; + } + else { + unsigned sp=simult_primes; + if (count>=simult_primes_seuil2) + sp=simult_primes2; + if (count>=simult_primes_seuil3) + sp=simult_primes3; + th=giacmin(nthreads-1,sp-1); // no more than simult_primes + th=giacmin(th,MAXNTHREADS-1); + parallel=nthreads/(th+1); + } + int effth=sizeof(qmodint_t)/sizeof(modint)*(th+1); + /* ************************* + * FIND PRIMES AND COMPUTE + **************************** */ + // FIXME we should avoid primes that divide one of leading coeff of current_gbasis + // compute gbasis mod p + // env.modulo=p; + if (th==0) rurinzgbasis=0; + copy(zlmmodradical,lmmodradical); + mainthrurinzgbasis=lmmodradical.coord.empty()?0:rur; + mainthrurlmmodradical=lmmodradical; + vector< vector< vectpolymod > > gbasiscoeffv(th+1); +#ifdef HAVE_LIBPTHREAD + vector pthread_p(th+1); vector< vector > *> pthread_mod(th+1); + for (unsigned j=0;j(lmmodradical.order,lmmodradical.dim); + gbasis_param[j].rurlmmodradical=lmmodradical; + gbasis_param[j].rurs=rurs; + gbasis_param[j].initsep=&gbasis_par.initsep; + gbasis_param[j].rurgblmptr=&mainthrurgblm; + gbasis_param[j].rurlmptr=&mainthrurlmsave; + gbasis_param[j].gparam=gbasis_par; + gbasis_param[j].coeffsmodptr=coeffsmodptr?&gbasiscoeffv[j]:0; + if (count==1) + gbasis_param[j].resmod.reserve(resmod.size()); + pthread_p[j]=p_qmodint; pthread_mod[j]=&gbasis_param[j].resmod; + } + p_qmodint=prevprime_qmodint(p_qmodint,llcm); + pthread_p[th]=p_qmodint; pthread_mod[th]=&resmod; + for (unsigned j=0;j,(void *) &gbasis_param[j]); + if (res) + thread_gbasis((void *)&gbasis_param[j]); + } +#else // PTHREAD + p_qmodint=prevprime_qmodint(p_qmodint,llcm); +#endif // PTHREAD + if (!zdata) current=current_gbasis; + G.clear(); + double t_0=CLOCK()*1e-6; +#if !defined KHICAS && !defined SDL_KHICAS + if (debug_infolevel) + CERR << std::setprecision(15) << clock_realtime() << " begin computing basis modulo " << p_qmodint << " batch/threads " << th+1 << "/" << parallel << '\n'; +#endif + // CERR << "write " << th << " " << p << '\n'; +#ifdef GBASISF4_BUCHBERGER + if (zdata){ + if (!zgbasisrur(current_gbasis,resmod,G,p_qmodint,true,&reduceto0,zf4buchberger_info,false,false,eliminate_flag,true,parallel,interred,mainthrurinzgbasis,mainthrurv,rurs,&gbasis_par.initsep,mainthrurlm,mainthrurlmmodradical,&mainthrurgblm,&mainthrurlmsave,gbasis_par,coeffsmodptr?&gbasiscoeffv[th]:0)){ + if (augmentgbasis>0) + augmentgbasis=2; + reduceto0.clear(); + zf4buchberger_info.clear(); + zf4buchberger_info.reserve(4*zf4buchberger_info.capacity()); + G.clear(); + if (!zgbasisrur(current_gbasis,resmod,G,p_qmodint,true/*totaldeg*/,&reduceto0,zf4buchberger_info,false,false,eliminate_flag,true,parallel,interred,mainthrurinzgbasis,mainthrurv,rurs,&gbasis_par.initsep,mainthrurlm,mainthrurlmmodradical,&mainthrurgblm,&mainthrurlmsave,gbasis_par,coeffsmodptr?&gbasiscoeffv[th]:0)){ + ok=false; + break; + } + } + } + else { +#if 0 // def GBASIS_4PRIMES + return 0; +#else + resmod.clear(); + if (!in_gbasisf4buchbergermod(current,resmod,G,p_qmodint,true/*totaldeg*/, + // 0,0 + &reduceto0,&f4buchberger_info, +#if 1 + false /* not useful */ +#else + (count==1) /* recompute R and quo at 2nd iteration*/ +#endif + )){ + // retry + reduceto0.clear(); + f4buchberger_info.clear(); G.clear(); + if (!in_gbasisf4buchbergermod(current,resmod,G,p_qmodint,true/*totaldeg*/,&reduceto0,&f4buchberger_info,false)){ + ok=false; + break; + } + reduceto0.clear(); + f4buchberger_info.clear(); + } +#endif // GBASIS_4PRIMES + } // end else zdata +#else // GBASISF4_BUCHBERGER + if (!in_gbasismod(current,resmod,G,p.val,true,&reduceto0)){ + ok=false; + break; + } + // CERR << "reduceto0 " << reduceto0.size() << '\n'; + //if (!in_gbasis(current,G,&env)) return false; +#endif // GBASISF4_BUCHBERGER +#ifdef HAVE_LIBPTHREAD + // finish threads before chinese remaindering + void * threadretval[MAXNTHREADS]; + for (int t=0;t=1 || debug_infolevel) + CERR << "// Timing for 2nd run " << time2ndrun << " 1st run " << time1strun << " speed ratio " << time2ndrun/time1strun << " [current reconstructed ratio for reinjection=" << gbasis_reinject_ratio << " speed_ratio for reinjection=" << gbasis_reinject_speed_ratio << " modifiable by gbasis_reinject(reconstructed_ratio,speed_ratio) command]" << '\n'; + if (time2ndrun0 + //|| time2ndrun<0.5 + ){ + // learning is fast enough, don't try reinjection + if (augmentgbasis>0) + augmentgbasis=2; + } + } + } + if (debug_infolevel){ + CERR << t_1 << " end, basis size " << G.size() << " prime number " << primecount+1 << '\n'; + } + /* *************************************************** + * EXTRACT to gbmod, zlmmod, zlmmodradical and rurv + ***************************************************** */ + unsigned i=0; // effth==th+1 or ==(th+1)*4 + for (int efft=0;efft * ptr = (thread_gbasis_t *) ptr_; + // extract from current + zrur=ptr->rurinzgbasis; + if (zrur){ + convert(ptr->rurlm,zlmmod,ttab); // zlmmod=ptr->rurlm; + convert(ptr->rurlmmodradical,zlmmodradical,ttab); // zlmmodradical=ptr->rurlmmodradical; + convert(ptr->rurv,rurv,ttab); // rurv.swap(ptr->rurv); + } + if (coeffsmodptr){ + initgensize=gbasiscoeffv[th].front().size(); + gbmod.resize(ptr->G.size()*(1+initgensize)); + int pos=0; + for (i=0;iG.size();++i){ + convert(ptr->resmod[ptr->G[i]],gbmod[pos],ttab); // gbmod[pos]=ptr->resmod[ptr->G[i]]; + ++pos; + for (int j=0;jG[i]][j],gbmod[pos],ttab); // gbmod[pos]=gbasiscoeffv[t][ptr->G[i]][j]; + ++pos; + } + } +#if 0 + if (0){ + ofstream l((string("log_")+print_INT_(gbasis_param[t].p)).c_str()); + for (int i=0;iG.size()) + gbmod.resize(ptr->G.size()); + for (i=0;iG.size();++i) + convert(ptr->resmod[ptr->G[i]],gbmod[i],ttab); // gbmod[i]=ptr->resmod[ptr->G[i]]; + } + pcur=getint(ptr->p,ttab); + // CERR << "read " << t << " " << p << '\n'; + ++count; + ++recon_count; + } +#endif + /* ************************* + * RECONSTRUCT + **************************** */ + if (!ok) + continue; + if (!coeffsmodptr){ + // remove 0 from gbmod + remove_zero(gbmod); + // if augmentgbasis>0 (at least) gbmod must be sorted + //if (augmentgbasis>0) + sort(gbmod.begin(),gbmod.end(),tripolymod_tri >(gbasis_logz_age)); + } + rur_gblm(gbmod,cur_gblm); + if (prev_gblm.coord.empty()) + prev_gblm=cur_gblm; + else { + int cmp=compare_gblm(cur_gblm,prev_gblm); + if (cmp==1){ + if (debug_infolevel) CERR << "Unlucky prime " << pcur << "\n"; + continue; // bad prime + } + if (cmp==-1){ // clear and restart! + recon_n1=-1; + prev_gblm.coord.clear(); + gbasis_size=G.size(); + f4buchberger_info.clear(); + zf4buchberger_info.clear(); + reduceto0.clear(); + V.clear(); W.clear(); Wlast.clear(); P.clear(); Wrur.clear(); + } + } + if (gbasis_size==-1 || gbasis_size=0 && gbasis_par.reinject_end>gbasis_par.reinject_begin){ + // initial reinjection + int K=gbasis_par.reinject_end-gbasis_par.reinject_begin; + Wlast.push_back(vectpoly8()); + reverse(toreinject.begin(),toreinject.end()); + toreinject.resize(K); + Wlast[0].swap(toreinject); + for (int k=0;k()); + W.push_back(vectpoly8()); + convert(gbmod,V.back(),pcur); + recon_added=gbasis_par.reinject_end-gbasis_par.reinject_begin; + prevreconpart=recon_added/double(gbmod.size()); + for (int k=0;k1) CERR << j << "(" << gbmod[j].age << "," << gbmod[j].logz << ":" << gbmod[j].fromleft << "," << gbmod[j].fromright << ")" << '\n'; + nmonoms += gbmod[j].coord.size(); + } + if (rur_do_gbasis>0 && nmonoms>rur_do_gbasis) + rur_gbasis=false; + if (debug_infolevel && count==0 && ttab==0){ + CERR << "G= index_in_gbasis:index_computed(age,logz,fromleft,fromright)\n"; + int maxlogz=0; + for (size_t i=0;i mainthrurgblm_,mainthrurlmsave_; + convert(mainthrurgblm,mainthrurgblm_,ttab); + convert(mainthrurlmsave,mainthrurlmsave_,ttab); + rqi=rur_quotient_ideal_dimension(gbmod,zlmmod,&mainthrurgblm_,&mainthrurlmsave_); + // FIXME?? + // convert(mainthrurgblm_,mainthrurgblm); + // convert(mainthrurlmsave_,mainthrurlmsave); +#else + rqi=rur_quotient_ideal_dimension(gbmod,zlmmod,&mainthrurgblm,&mainthrurlmsave); +#endif + } + if (rqi==-RAND_MAX) + *logptr(contextptr) << "Overflow in rur, computing revlex gbasis\n"; + if (rqi<0){ + if (rur_error_ifnot0dimensional){ + res.clear(); + mpz_clear(zd); + mpz_clear(zu); + mpz_clear(zu1); + mpz_clear(zd1); + mpz_clear(zabsd1); + mpz_clear(zsqrtm); + mpz_clear(zq); + mpz_clear(zur); + mpz_clear(zr); + mpz_clear(ztmp); + return 1; + } + rur=0; + continue; + } + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " begin modular rur check" << '\n'; + if (rur==2){ + vecteur m,M,res; + polymod s(order,dim); + index_t l(dim); + l[dim-1]=1; + s.coord.push_back(T_unsigned(1,tdeg_t(l,order))); + ok=rur_minpoly(gbmod,zlmmod,s,pcur,m,M); + rur_convert_univariate(m,dim-1,gbmod[0]); + gbmod.resize(1); + } + else { + bool ok=true; + if (!zrur) + ok=rur_compute(gbmod,zlmmod,zlmmodradical,pcur,rurs,&gbasis_par.initsep,rurv); + if (!ok){ + if (zlmmodradical.coord.empty()){ + CERR << CLOCK()*1e-6 << " Unable to compute modular rur\n"; + ok = false; rur = 0; + } + else + CERR << CLOCK()*1e-6 << " Bad prime, ignored\n"; + continue; + } + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " end modular rur check" << '\n'; + if (rur_gbasis){ // reconstruct gbasis and rur + for (int r=0;r2) + CERR << "p=" << pcur << ":" << gbmod << '\n'; + for (i=0;i=0 && eps>1e-20) + jpos_start=giacmax(0,giacmin(recon_n0,giacmin(recon_n1,recon_n2))); + else + jpos_start=recon_added; // 0 or recon_added (do not check already reconstructed) + jpos=jpos_start; + // check existing Wlast + for (;jpos0 && P[i].type==_INT_ && recon_added==0 && gbasis_stop!=0){ + // check for non modular gb with early reconstruction */ + // first build a candidate in early with V[i] + vectpoly8 early(V[i]); + int d; + for (jpos=0;jpos1) + COUT << "early reconstr. failure pos " << jpos << " P=" << early[jpos] << " d=" << d << " modulo " << P[i].val << '\n'; + break; + } + int s=int(early[jpos].coord.size()); + for (int k=0;k tmp(gbmod[jpos]); + smallmultmod(early[jpos].coord.front().g.val,tmp,pcur); + if (!chk_equal_mod(early[jpos],tmp,pcur)){ + if (debug_infolevel>1) + COUT << "early recons. failure jpos=" << jpos << " " << early[jpos] << " " << tmp << " modulo " << pcur << '\n'; + break; + } + } + rechecked=0; + if (jpos==early.size() && (eliminate_flag || check_initial_generators(res,early,G,eps))){ + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " end final check " << '\n'; + swap(res,early); + mpz_clear(zd); + mpz_clear(zu); + mpz_clear(zu1); + mpz_clear(zd1); + mpz_clear(zabsd1); + mpz_clear(zsqrtm); + mpz_clear(zq); + mpz_clear(zur); + mpz_clear(zr); + mpz_clear(ztmp); + if (debug_infolevel) + *logptr(contextptr) << "#Primes " << count <<'\n'; + return 1; + } + } // end jpos==early.size() + } // end if !rur ... + break; // find another prime + } + if (debug_infolevel && (rur || t==th)) + CERR << CLOCK()*1e-6 << " checking\n"; + for (;jpos1) + CERR << "chinrem size mismatch " << jpos << '\n'; + break; + } + //Vijs=1; + bool dobrk=false; + int chks[]={int(.1*Vijs),int(Vijs/2), int(.9*Vijs)}; + //int chks[]={Vijs/2, int(.9*Vijs)}; + for (int chk=0;chk1) + CERR << jpos << '\n'; + dobrk=true; + break; + } + modint gg=gbmod[jpos].coord[Vijs].g; + if (!chk_equal_mod(num/den,gg,pcur)){ + rechecked=0; + if (debug_infolevel>1) + CERR << jpos << '\n'; + dobrk=true; + break; + } + } + } + if (dobrk){ + if (rur_gbasis && rur>0 && jpos0 && jpos0 && jpos tmptmp(poly8tmp.order,poly8tmp.dim); + if (rur_gbasis && rur>0 && jpos>=gbasis_size){ + if (jpos>=gbasis_size+Wrur.size()){ + Wrur.push_back(tmptmp); + Wrur.back().coord.swap(poly8tmp.coord); + } + } + else { + Wlast[i].push_back(tmptmp); + Wlast[i].back().coord.swap(poly8tmp.coord); + } + } + if (debug_infolevel>0){ + CERR << CLOCK()*1e-6 << " unstable mod " << pcur << " from " << gbasis_size ; + if (coeffsmodptr) + CERR << "*(1+" << initgensize << ")"; + CERR << " reconstructed " << Wlast[i].size() << " (#" << i << ")" << '\n'; + } + // possible improvement: if t==th and i==0 and Wlast.size()/V[i].size() + // has increased significantly + // it might be a good idea to add it's component + // to current, and clear info (if zdata: reduceto0, zf4buchberger_info) + recon_n2=recon_n1; + recon_n1=recon_n0; + recon_n0=Wlast[i].size(); + if (eps>1e-20 && !gbasis_par.gbasis && + ttab==sizeof(qmodint_t)/sizeof(modint)-1 && // check only for the last prime of parallel threads + // recon_n2==recon_n1 && recon_n1==recon_n0 && + zdata && augmentgbasis && t==th && i==0){ + if (rur_gbasis && rur==1 && recon_n2>=gbasis_size){ // the gbasis is known + rur=-gbasis_size; recon_added=gbasis_size; + current_gbasis=Wlast[i]; + current_gbasis.erase(current_gbasis.begin()+gbasis_size,current_gbasis.end()); + cleardeno(current_gbasis); + } + double reconpart=recon_n2/double(V[i].size()); + if (!rur && !coeffsmodptr && + recon_n0/double(V[i].size())<0.95 && + (reconpart-prevreconpart>augmentgbasis + // || (reconpart>prevreconpart && recon_count>=giacmax(128,th*4)) + ) + ){ + double tt=CLOCK()*1e-6; + if (tt>2 || debug_infolevel) + CERR << "// " << tt << " adding reconstructed ideal generators " << recon_n2 << " (reconpart " << reconpart << " prev " << prevreconpart << " augment " << augmentgbasis << " recon_count " << recon_count << " th " << th << " recon_n2 " << recon_n2 << " V[i] " << V[i].size() << ")" << '\n'; + recon_count=0; + prevreconpart=reconpart; + if (rur && recon_added>gbasis_size) + recon_added=gbasis_size; + //current_gbasis=current_orig; + int insertpos=0; + for (int k=recon_added;k tmp=Wlast[i][k]; + cleardeno(tmp); + for (;insertpos2 || debug_infolevel) + CERR << "// " << tt << " # new ideal generators " << current_gbasis.size() << '\n'; + reduceto0.clear(); + zf4buchberger_info.clear(); + if (gbasis_logz_age){ + res.swap(current_gbasis); + mpz_clear(zd); + mpz_clear(zu); + mpz_clear(zu1); + mpz_clear(zd1); + mpz_clear(zabsd1); + mpz_clear(zsqrtm); + mpz_clear(zq); + mpz_clear(zur); + mpz_clear(zr); + mpz_clear(ztmp); + return -1; + } + } + } + break; + } // end for loop on i + if (i==V.size()){ + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " creating reconstruction #" << i << '\n'; + // not found + V.push_back(vectpoly8()); + convert(gbmod,V.back(),pcur); + W.push_back(vectpoly8()); // no reconstruction yet, wait at least another prime + Wlast.push_back(vectpoly8()); + P.push_back(pcur); + continue; // next prime + } + if (!rur && + gbasis_stop<0 && recon_n0>=-gbasis_stop){ + if (recon_n2<-gbasis_stop) + continue; + // stop here + W[i]=Wlast[i]; + W[i].resize(recon_n2); + cleardeno(W[i]); // clear denominators + CERR << CLOCK()*1e-6 << " Max number of generators reconstructed " << jpos << ">=" << -gbasis_stop << '\n'; + swap(res,W[i]); + mpz_clear(zd); + mpz_clear(zu); + mpz_clear(zu1); + mpz_clear(zd1); + mpz_clear(zabsd1); + mpz_clear(zsqrtm); + mpz_clear(zq); + mpz_clear(zur); + mpz_clear(zr); + mpz_clear(ztmp); + if (debug_infolevel) + *logptr(contextptr) << "#Primes " << count <<'\n'; + return 1; + } + if (jpos5) + *logptr(contextptr) << "// Groebner basis computation time=" << clock_realtime()-init_time << " memory " << memory_usage()*1e-6 << "M" << (chk_initial_generator?": end rational reconstruction ":": end additional prime check") << '\n'; + efft=effth; // avoid unlucky prime messages + // now check if W[i] is a Groebner basis over Q, if so it's the answer + if (rur && rur!=2 && !gbasis_par.gbasis && rur_certify(res,W[i],rur_gbasis?gbasis_size:0,contextptr)){ // rur!=2 was added otherwise crash for eliminate([-v5+1,-v6,v7-1,v8-1,v10^2-v6^2-v5^2+2*v6-1,v9^2-1,v9*m-v10,v9*n-1],[v1,v2,v3,v4,v5,v6,v7,v8,v10,v9,n]) + swap(res,W[i]); + if (rur_gbasis) + res.erase(res.begin(),res.begin()+gbasis_size); + goto cleanup; + } + if (rur && rur!=2 && gbasis_par.gbasis && rur_certify(res,rur_gbasis?Wrur:W[i],0,contextptr)){ // rur!=2 was added otherwise crash for eliminate([-v5+1,-v6,v7-1,v8-1,v10^2-v6^2-v5^2+2*v6-1,v9^2-1,v9*m-v10,v9*n-1],[v1,v2,v3,v4,v5,v6,v7,v8,v10,v9,n]) + if (rur_gbasis){ + swap(res,Wrur); + for (int k=0;k & cur=W[i]; + res.clear(); + int pos=0; + coeffsmodptr->resize(G.size()); + for (int i=0;i0 && eps2<1){ + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " Final check successful, running another prime to increase confidence." << '\n'; + chk_initial_generator=false; + continue; + } + if (eps>0){ + double terms=0; + int termsmin=RAND_MAX; // estimate of the number of terms of a reduced non-0 spoly + for (unsigned k=0;ktermsmin) + epsp=termsmin; + *logptr(contextptr) << "// Non determinisitic Groebner basis algorithm over the rationals. " << + (eps<1.01e-10?gettext("Reconstructed Groebner basis checked with an additional prime. If successful, error"):"Error") + << " probability is less than " << eps << gettext(" and is estimated to be less than 10^-") << epsp << gettext(". Use proba_epsilon:=0 to certify (this takes more time).") << '\n'; + } + G.clear(); + if (eps<1.01e-10){ + // check modulo another prime that W[i] is a gbasis + vector G; + vectpoly8 res_(W[i]); + vectpolymod resmod; + vector< zinfo_t > zf4buchberger_info; + int p=268435399; + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " Checking that the basis is a gbasis modulo " << p << '\n'; + if (!zgbasis(res_,resmod,G,p,true,0,zf4buchberger_info,false,false,false,false,threads /* parallel*/,true,&gbasis_par.initsep,gbasis_par,0)) + return 0; + sort(resmod.begin(),resmod.end(),tripolymod_tri >(false)); + sort(W[i].begin(),W[i].end(),tripolymod_tri >(false)); + for (size_t jpos=0;jposjpos && chk_equal_mod(Wlast[i][jpos],gb[jpos],pcur)){ + if (afewpolys.size()<=jpos) + afewpolys.push_back(Wlast[i][jpos]); + else { + if (!(afewpolys[jpos]==Wlast[i][jpos])) + afewpolys[jpos]=Wlast[i][jpos]; + } + } + else { + if (!fracmod(V[i][jpos],P[i], + zd,zd1,zabsd1,zu,zu1,zur,zq,zr,zsqrtm,ztmp, + poly8tmp)){ + CERR << CLOCK()*1e-6 << " reconstruction failure at position " << jpos << '\n'; + break; + } + if (afewpolys.size()<=jpos){ + poly8 tmp(poly8tmp.order,poly8tmp.dim); + afewpolys.push_back(tmp); + } + afewpolys[jpos].coord.swap(poly8tmp.coord); + } + if (Wlast[i].size()>jpos && !(afewpolys[jpos]==Wlast[i][jpos])){ + if (debug_infolevel){ + unsigned j=0,js=giacmin(afewpolys[jpos].coord.size(),Wlast[i][jpos].coord.size()); + for (;j Wlast[i].size()*1.35+2 ) + break; + } + if (afewpolys!=Wlast[i]){ + swap(afewpolys,Wlast[i]); + if (debug_infolevel>0) + CERR << CLOCK()*1e-6 << " unstable mod " << p << " from " << V[i].size() << " reconstructed " << Wlast[i].size() << '\n'; + break; + } + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " stable, clearing denominators " << '\n'; + W[i]=Wlast[i]; + cleardeno(W[i]); // clear denominators + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " end rational reconstruction " << '\n'; + // now check if W[i] is a Groebner basis over Q, if so it's the answer + // first verify that the initial generators reduce to 0 + poly8 tmp0,tmp1,tmp2; + vectpoly8 wtmp; + unsigned j=0,finalchecks=initial; + if (eps>0) + finalchecks=giacmin(2*W[i].front().dim,initial); + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " begin final check, checking that " << finalchecks << " initial generators belongs to the ideal" << '\n'; + G.resize(W[i].size()); + for (j=0;j0){ + double terms=0; + int termsmin=RAND_MAX; // estimate of the number of terms of a reduced non-0 spoly + for (unsigned k=0;ktermsmin) + epsp=termsmin; + *logptr(contextptr) << gettext("Running a probabilistic check for the reconstructed Groebner basis. If successful, error probability is less than ") << eps << gettext(" and is estimated to be less than 10^-") << epsp << gettext(". Use proba_epsilon:=0 to certify (this takes more time).") << '\n'; + } + G.clear(); + if (eps<6e-8 && !is_gbasis(W[i],eps*1.677e7,modularcheck)){ + ok=false; + break; // in_gbasis(W[i],G,0,true); + } +#endif + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " end final check " << '\n'; + swap(res,W[i]); + mpz_clear(zd); + mpz_clear(zu); + mpz_clear(zu1); + mpz_clear(zd1); + mpz_clear(zabsd1); + mpz_clear(zsqrtm); + mpz_clear(zq); + mpz_clear(zur); + mpz_clear(zr); + mpz_clear(ztmp); + return 1; + } // end for (i()); // no reconstruction yet, wait at least another prime + Wlast.push_back(vectpoly8()); + P.push_back(p); + } +#endif + } // end loop on threads + } //end for int count + mpz_clear(zd); + mpz_clear(zu); + mpz_clear(zu1); + mpz_clear(zd1); + mpz_clear(zabsd1); + mpz_clear(zsqrtm); + mpz_clear(zq); + mpz_clear(zur); + mpz_clear(zr); + mpz_clear(ztmp); + return 0; + } + + template + bool mod_gbasis(vectpoly8 & res,bool modularcheck,bool zdata,int & rur,GIAC_CONTEXT,gbasis_param_t gbasis_param,vector< vectpoly8 > * coeffsmodptr=0){ + int gbasis_logz_age=gbasis_logz_age_sort; + for (;;){ + int tmp=in_mod_gbasis(res,modularcheck,zdata,rur,contextptr,gbasis_param,gbasis_logz_age,coeffsmodptr); +#if 0 // def GIAC_4PRIMES + // retry on error if zdata was enabled, maybe compressed monomials failed + // FIXME use code -2 instead of 0 + if (zdata && tmp==0 && sizeof(qmodint_t)!=sizeof(modint)) + tmp=in_mod_gbasis(res,modularcheck,false /* zdata*/,rur,contextptr,gbasis_param,gbasis_logz_age,coeffsmodptr); +#endif + if (tmp!=-1) // -1 means part of the gbasis has been reconstructed + return tmp; + if (gbasis_logz_age) + gbasis_logz_age=0; // special sorting is not meaningfull after 1 reinjection, and we want to have interreduction + } + } +#ifndef BIGENDIAN +#define GBASIS_SWAP +#endif + +#if !defined NO_STDEXCEPT && !defined BIGENDIAN + #define GIAC_TDEG_T14 +#endif + + // other tdeg_t types +#ifdef GIAC_TDEG_T14 +#undef INT128 // it's slower! + struct tdeg_t14 { + bool vars64() const { return false;} + int hash_index(void * ptr_) const { + // if (!ptr_) + return -1; + } + bool add_to_hash(void *ptr_,int no) const { + return false; + } + void dbgprint() const; + // data + union { + unsigned char tab[16]; // tab[0] and 1 is for total degree + struct { + unsigned char tdeg; + unsigned char tdeg2; + order_t order_; + longlong * ui; + }; + }; + int front(){ return tab[2];} + // methods + inline unsigned selection_degree(order_t order) const { +#ifdef GBASIS_SELECT_TOTAL_DEGREE + return total_degree(order); +#endif + return tdeg; + } + inline unsigned total_degree(order_t order) const { + return tdeg+tdeg2; + } + // void set_total_degree(unsigned d) { tab[0]=d;} + tdeg_t14() { + longlong * ptr = (longlong *) tab; + ptr[1]=ptr[0]=0; + } + tdeg_t14(int i){ + longlong * ptr = (longlong *) tab; + ptr[1]=ptr[0]=0; + } + void get_tab(short * ptr,order_t order) const { +#ifdef GBASIS_SWAP + tdeg_t14 t(*this); + swap_indices14(t.tab); +#else + const tdeg_t14 & t=*this; +#endif + ptr[0]=t.tab[0]; + for (unsigned i=1;i<15;++i) + ptr[i]=t.tab[i+1]; + } + tdeg_t14(const index_m & lm,order_t order){ + longlong * ptr_ = (longlong *) tab; + ptr_[1]=ptr_[0]=0; + unsigned char * ptr=tab; + vector::const_iterator it=lm.begin(),itend=lm.end(); + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ + unsigned td=sum_degree(lm); + if (td>=128) + gensizeerr("Degree too large"); + *ptr=td; + ++ptr; + *ptr=0; + ++ptr; + } + if (order.o==_REVLEX_ORDER){ + for (--itend,--it;it!=itend;++ptr,--itend) + *ptr=*itend; + } + else { + for (;it!=itend;++ptr,++it) + *ptr=*it; + } +#ifdef GBASIS_SWAP + swap_indices14(tab); +#endif + } + }; + + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const tdeg_t14 & x){ + os << "["; + for (unsigned i=0; i<14;++i){ + os << unsigned(x.tab[i+2]) << ","; + } + return os << "]"; + } +#else + ostream & operator << (ostream & os,const tdeg_t14 & x){ + os << "["; + for (unsigned i=0; i<14;++i){ + os << unsigned(x.tab[i+2]) << ","; + } + return os << "]"; + } +#endif + void tdeg_t14::dbgprint() const { COUT << * this << '\n'; } + inline tdeg_t14 & operator += (tdeg_t14 & x,const tdeg_t14 & y){ +#ifdef INT128 + * (uint128_t *) &x += * (const uint128_t *) &y; +#else + // ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + *((ulonglong *)&x) += *((ulonglong *)&y); + ((ulonglong *)&x)[1] += ((ulonglong *)&y)[1]; +#endif + if (x.tab[0]>=128){ + gensizeerr("Degree too large"); + } + return x; + } + inline tdeg_t14 operator + (const tdeg_t14 & x,const tdeg_t14 & y){ + tdeg_t14 res(x); + return res += y; + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]+ytab[0]; + ztab[1]=xtab[1]+ytab[1]; + return res; + } + inline void add(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & res,int dim){ +#ifdef INT128 + * (uint128_t *) &res = * (const uint128_t *) &x + * (const uint128_t *) &y; +#else + // ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + *((ulonglong *)&res)=*((ulonglong *)&x)+*((ulonglong *)&y); + ((ulonglong *)&res)[1]=((ulonglong *)&x)[1]+((ulonglong *)&y)[1]; +#endif + if (res.tab[0]>=128) + gensizeerr("Degree too large"); + } + tdeg_t14 operator - (const tdeg_t14 & x,const tdeg_t14 & y){ + tdeg_t14 res; + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]-ytab[0]; + ztab[1]=xtab[1]-ytab[1]; + return res; + } + inline bool operator == (const tdeg_t14 & x,const tdeg_t14 & y){ +#ifdef INT128 + return * (const uint128_t *) &x == * (uint128_t *) &y; +#else + return ((longlong *) x.tab)[0] == ((longlong *) y.tab)[0] && ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1]; +#endif + } + inline bool operator != (const tdeg_t14 & x,const tdeg_t14 & y){ + return !(x==y); + } + + static inline int tdeg_t14_revlex_greater (const tdeg_t14 & x,const tdeg_t14 & y){ +#ifdef GBASIS_SWAP +#if 0 + longlong *xtab=(longlong *)&x,*ytab=(longlong *)&y; + if (longlong a=*xtab-*ytab) // tdeg test already donne by caller + return a<=0?1:0; + if (longlong a=xtab[1]-ytab[1]) + return a<=0?1:0; +#else + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + if (xtab[0]!=ytab[0]) // tdeg test already donne by caller + return xtab[0]<=ytab[0]?1:0; + if (xtab[1]!=ytab[1]) + return xtab[1]<=ytab[1]?1:0; +#endif + return 2; +#else // GBASIS_SWAP + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + if (x.tab[3]!=y.tab[3]) + return x.tab[3]<=y.tab[3]?1:0; + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]>=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + if (x.tab[11]!=y.tab[11]) + return x.tab[11]<=y.tab[11]?1:0; + if (x.tab[12]!=y.tab[12]) + return x.tab[12]<=y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; + } + return 2; +#endif // GBASIS_SWAP + } + + int tdeg_t14_lex_greater (const tdeg_t14 & x,const tdeg_t14 & y){ +#ifdef GBASIS_SWAP + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + ulonglong X=*xtab, Y=*ytab; + if (X!=Y){ + if ( (X & 0xffff) != (Y &0xffff)) + return (X&0xffff)>=(Y&0xffff)?1:0; + return X>=Y?1:0; + } + if (xtab[1]!=ytab[1]) + return xtab[1]>=ytab[1]?1:0; + return 2; +#else + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]>y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]>y.tab[2]?1:0; + if (x.tab[3]!=y.tab[3]) + return x.tab[2]>y.tab[2]?1:0; + if (x.tab[4]!=y.tab[4]) + return x.tab[4]>y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]>y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]>y.tab[6]?1:0; + return x.tab[7]>y.tab[7]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]>y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]>y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]>y.tab[10]?1:0; + if (x.tab[11]!=y.tab[11]) + return x.tab[11]>y.tab[11]?1:0; + if (x.tab[12]!=y.tab[12]) + return x.tab[12]>y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]>y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]>y.tab[14]?1:0; + return x.tab[15]>y.tab[15]?1:0; + } + return 2; +#endif + } + + inline int tdeg_t_greater(const tdeg_t14 & x,const tdeg_t14 & y,order_t order){ + short X=x.tab[0]; + if (//order.o!=_PLEX_ORDER && + X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex + if (order.o==_REVLEX_ORDER) + return tdeg_t14_revlex_greater(x,y); + return tdeg_t14_lex_greater(x,y); + } + inline bool tdeg_t_strictly_greater (const tdeg_t14 & x,const tdeg_t14 & y,order_t order){ + return !tdeg_t_greater(y,x,order); // total order + } + +#ifdef INT128 + uint128_t mask4=(((uint128_t) mask2)<<64)|mask2; +#endif + + inline bool tdeg_t_all_greater(const tdeg_t14 & x,const tdeg_t14 & y,order_t order){ +#ifdef INT128 + return !((* (const uint128_t *) &x - * (const uint128_t *) &y) & mask4); +#else + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + if ((xtab[0]-ytab[0]) & mask2) + return false; + if ((xtab[1]-ytab[1]) & mask2) + return false; + return true; +#endif + } + + // 1 (all greater), 0 (unknown), -1 (all smaller) + int tdeg_t_compare_all(const tdeg_t14 & x,const tdeg_t14 & y,order_t order){ + int res=0; + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + longlong tmp=xtab[0]-ytab[0]; + if (tmp & mask2){ + if (res==1 || ((-tmp) & mask2)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } + tmp=xtab[1]-ytab[1]; + if (tmp & mask2){ + if (res==1 || ((-tmp) & mask2)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } + return res; + } + + void index_lcm(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & z,order_t order){ + int t=0; + const unsigned char * xtab=&x.tab[2],*ytab=&y.tab[2]; + unsigned char *ztab=&z.tab[2]; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 + if (t>=128){ + gensizeerr("Degree too large"); + } + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ + z.tab[0]=t; + } + else { + z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0]; + } + } + + void index_lcm_overwrite(const tdeg_t14 & x,const tdeg_t14 & y,tdeg_t14 & z,order_t order){ + index_lcm(x,y,z,order); + } + + void get_index(const tdeg_t14 & x_,index_t & idx,order_t order,int dim){ + idx.resize(dim); +#ifdef GBASIS_SWAP + tdeg_t14 x(x_); + swap_indices14(x.tab); +#else + const tdeg_t14 & x= x_; +#endif + const unsigned char * ptr=x.tab+2; + if (order.o==_REVLEX_ORDER){ + for (int i=1;i<=dim;++ptr,++i) + idx[dim-i]=*ptr; + } + else { + for (int i=0;i::const_iterator it=lm.begin(),itend=lm.end(); + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ + *ptr=sum_degree(lm); + ++ptr; + } + if (order.o==_REVLEX_ORDER){ + for (--itend,--it;it!=itend;++ptr,--itend) + *ptr=*itend; + } + else { + for (;it!=itend;++ptr,++it) + *ptr=*it; + } +#ifdef GBASIS_SWAP + swap_indices11(tab); +#endif + } + }; + + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const tdeg_t11 & x){ + os << "["; + for (unsigned i=0; i<=GROEBNER_VARS;++i){ + os << x.tab[i] << ","; + } + return os << "]"; + } +#else + ostream & operator << (ostream & os,const tdeg_t11 & x){ + os << "["; + for (unsigned i=0; i<=GROEBNER_VARS;++i){ + os << x.tab[i] << ","; + } + return os << "]"; + } +#endif + void tdeg_t11::dbgprint() const { COUT << * this << '\n'; } + tdeg_t11 operator + (const tdeg_t11 & x,const tdeg_t11 & y); + tdeg_t11 & operator += (tdeg_t11 & x,const tdeg_t11 & y){ + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + xtab[0]+=ytab[0]; + xtab[1]+=ytab[1]; + xtab[2]+=ytab[2]; + return x; + } + tdeg_t11 operator + (const tdeg_t11 & x,const tdeg_t11 & y){ + tdeg_t11 res(x); + return res += y; + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]+ytab[0]; + ztab[1]=xtab[1]+ytab[1]; + ztab[2]=xtab[2]+ytab[2]; + return res; + } + inline void add(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & res,int dim){ + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]+ytab[0]; + ztab[1]=xtab[1]+ytab[1]; + ztab[2]=xtab[2]+ytab[2]; + } + tdeg_t11 operator - (const tdeg_t11 & x,const tdeg_t11 & y){ + tdeg_t11 res; + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]-ytab[0]; + ztab[1]=xtab[1]-ytab[1]; + ztab[2]=xtab[2]-ytab[2]; + return res; + } + inline bool operator == (const tdeg_t11 & x,const tdeg_t11 & y){ + return ((longlong *) x.tab)[0] == ((longlong *) y.tab)[0] && + ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1] && + ((longlong *) x.tab)[2] == ((longlong *) y.tab)[2] + ; + } + inline bool operator != (const tdeg_t11 & x,const tdeg_t11 & y){ + return !(x==y); + } + + static inline int tdeg_t11_revlex_greater (const tdeg_t11 & x,const tdeg_t11 & y){ +#ifdef GBASIS_SWAP +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + if (xtab[0]!=ytab[0]) // tdeg test already donne by caller + return xtab[0]<=ytab[0]?1:0; + if (xtab[1]!=ytab[1]) + return xtab[1]<=ytab[1]?1:0; + if (xtab[2]!=ytab[2]) + return xtab[2]<=ytab[2]?1:0; +#else + longlong *xtab=(longlong *)&x,*ytab=(longlong *)&y; + if (longlong a=*xtab-*ytab) // tdeg test already donne by caller + return a<=0?1:0; + if (longlong a=xtab[1]-ytab[1]) + return a<=0?1:0; + if (longlong a=xtab[2]-ytab[2]) + return a<=0?1:0; +#endif + return 2; +#else // GBASIS_SWAP + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]<=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; + } + return 2; +#endif // GBASIS_SWAP + } + + int tdeg_t11_lex_greater (const tdeg_t11 & x,const tdeg_t11 & y){ +#ifdef GBASIS_SWAP + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + ulonglong X=*xtab, Y=*ytab; + if (X!=Y){ + if ( (X & 0xffff) != (Y &0xffff)) + return (X&0xffff)>=(Y&0xffff)?1:0; + return X>=Y?1:0; + } + if (xtab[1]!=ytab[1]) + return xtab[1]>=ytab[1]?1:0; + if (xtab[2]!=ytab[2]) + return xtab[2]>=ytab[2]?1:0; + return 2; +#else + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]>y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]>y.tab[2]?1:0; + return x.tab[3]>y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]>y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]>y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]>y.tab[6]?1:0; + return x.tab[7]>y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]>y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]>y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]>y.tab[10]?1:0; + return x.tab[11]>=y.tab[11]?1:0; + } + return 2; +#endif + } + + inline int tdeg_t_greater(const tdeg_t11 & x,const tdeg_t11 & y,order_t order){ + short X=x.tab[0]; + if (//order.o!=_PLEX_ORDER && + X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex + if (order.o==_REVLEX_ORDER) + return tdeg_t11_revlex_greater(x,y); + return tdeg_t11_lex_greater(x,y); + } + inline bool tdeg_t_strictly_greater (const tdeg_t11 & x,const tdeg_t11 & y,order_t order){ + return !tdeg_t_greater(y,x,order); // total order + } + + inline bool tdeg_t_all_greater(const tdeg_t11 & x,const tdeg_t11 & y,order_t order){ + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + if ((xtab[0]-ytab[0]) & 0x8000800080008000ULL) + return false; + if ((xtab[1]-ytab[1]) & 0x8000800080008000ULL) + return false; + if ((xtab[2]-ytab[2]) & 0x8000800080008000ULL) + return false; + return true; + } + + // 1 (all greater), 0 (unknown), -1 (all smaller) + int tdeg_t_compare_all(const tdeg_t11 & x,const tdeg_t11 & y,order_t order){ + int res=0; + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + longlong tmp=xtab[0]-ytab[0]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } + tmp=xtab[1]-ytab[1]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } + tmp=xtab[2]-ytab[2]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } + return res; + } + + void index_lcm(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & z,order_t order){ + int t=0; + const short * xtab=&x.tab[1],*ytab=&y.tab[1]; + short *ztab=&z.tab[1]; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 1 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ + z.tab[0]=t; + } + else { + z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0]; + } + } + + inline void index_lcm_overwrite(const tdeg_t11 & x,const tdeg_t11 & y,tdeg_t11 & z,order_t order){ + index_lcm(x,y,z,order); + } + + void get_index(const tdeg_t11 & x_,index_t & idx,order_t order,int dim){ + idx.resize(dim); +#ifdef GBASIS_SWAP + tdeg_t11 x(x_); + swap_indices11(x.tab); +#else + const tdeg_t11 & x= x_; +#endif + const short * ptr=x.tab; + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER) + ++ptr; + if (order.o==_REVLEX_ORDER){ + for (int i=1;i<=dim;++ptr,++i) + idx[dim-i]=*ptr; + } + else { + for (int i=0;i11 + ptr[3]=0; +#endif + } + tdeg_t15(int i){ + longlong * ptr = (longlong *) tab; + ptr[2]=ptr[1]=ptr[0]=0; +#if GROEBNER_VARS>11 + ptr[3]=0; +#endif + } + void get_tab(short * ptr,order_t order) const { + for (unsigned i=0;i<=GROEBNER_VARS;++i) + ptr[i]=tab[i]; +#ifdef GBASIS_SWAP + swap_indices15(ptr,order.o); +#endif + } + tdeg_t15(const index_m & lm,order_t order){ + longlong * ptr_ = (longlong *) tab; + ptr_[2]=ptr_[1]=ptr_[0]=0; + short * ptr=tab; +#if GROEBNER_VARS>11 + ptr_[3]=0; +#endif + // tab[GROEBNER_VARS]=order; +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER){ + ptr[0]=lm[0]+lm[1]+lm[2]; + ptr[1]=lm[2]; + ptr[2]=lm[1]; + ptr[3]=lm[0]; + ptr +=5; + short t=0; + vector::const_iterator it=lm.begin()+3,itend=lm.end(); + for (--itend,--it;it!=itend;++ptr,--itend){ + t += *itend; + *ptr=*itend; + } + tab[4]=t; +#ifdef GBASIS_SWAP + swap_indices15(tab,order.o); +#endif + return; + } + if (order.o==_7VAR_ORDER){ + ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]; + ptr[1]=lm[6]; + ptr[2]=lm[5]; + ptr[3]=lm[4]; + ptr[4]=lm[3]; + ptr[5]=lm[2]; + ptr[6]=lm[1]; + ptr[7]=lm[0]; + ptr +=9; + short t=0; + vector::const_iterator it=lm.begin()+7,itend=lm.end(); + for (--itend,--it;it!=itend;++ptr,--itend){ + t += *itend; + *ptr=*itend; + } + tab[8]=t; +#ifdef GBASIS_SWAP + swap_indices15(tab,order.o); +#endif + return; + } + if (order.o==_11VAR_ORDER){ + ptr[0]=lm[0]+lm[1]+lm[2]+lm[3]+lm[4]+lm[5]+lm[6]+lm[7]+lm[8]+lm[9]+lm[10]; + ptr[1]=lm[10]; + ptr[2]=lm[9]; + ptr[3]=lm[8]; + ptr[4]=lm[7]; + ptr[5]=lm[6]; + ptr[6]=lm[5]; + ptr[7]=lm[4]; + ptr[8]=lm[3]; + ptr[9]=lm[2]; + ptr[10]=lm[1]; + ptr[11]=lm[0]; + ptr += 13; + short t=0; + vector::const_iterator it=lm.begin()+11,itend=lm.end(); + for (--itend,--it;it!=itend;++ptr,--itend){ + t += *itend; + *ptr=*itend; + } + tab[12]=t; +#ifdef GBASIS_SWAP + swap_indices15(tab,order.o); +#endif + return; + } +#endif + vector::const_iterator it=lm.begin(),itend=lm.end(); + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ + *ptr=sum_degree(lm); + ++ptr; + } + if (order.o==_REVLEX_ORDER){ + for (--itend,--it;it!=itend;++ptr,--itend) + *ptr=*itend; + } + else { + for (;it!=itend;++ptr,++it) + *ptr=*it; + } +#ifdef GBASIS_SWAP + swap_indices15(tab,order.o); +#endif + } + }; + + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const tdeg_t15 & x){ + os << "["; + for (unsigned i=0; i<=GROEBNER_VARS;++i){ + os << x.tab[i] << ","; + } + return os << "]"; + } +#else + ostream & operator << (ostream & os,const tdeg_t15 & x){ + os << "["; + for (unsigned i=0; i<=GROEBNER_VARS;++i){ + os << x.tab[i] << ","; + } + return os << "]"; + } +#endif + void tdeg_t15::dbgprint() const { COUT << * this << '\n'; } + tdeg_t15 operator + (const tdeg_t15 & x,const tdeg_t15 & y); + tdeg_t15 & operator += (tdeg_t15 & x,const tdeg_t15 & y){ + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + xtab[0]+=ytab[0]; + xtab[1]+=ytab[1]; + xtab[2]+=ytab[2]; +#if GROEBNER_VARS>11 + xtab[3]+=ytab[3]; +#endif + return x; + } + tdeg_t15 operator + (const tdeg_t15 & x,const tdeg_t15 & y){ + tdeg_t15 res(x); + return res += y; +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]+ytab[0]; + ztab[1]=xtab[1]+ytab[1]; + ztab[2]=xtab[2]+ytab[2]; +#if GROEBNER_VARS>11 + ztab[3]=xtab[3]+ytab[3]; +#endif +#else + for (unsigned i=0;i<=GROEBNER_VARS;++i) + res.tab[i]=x.tab[i]+y.tab[i]; +#endif + return res; + } + inline void add(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & res,int dim){ +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]+ytab[0]; + ztab[1]=xtab[1]+ytab[1]; + ztab[2]=xtab[2]+ytab[2]; +#if GROEBNER_VARS>11 + ztab[3]=xtab[3]+ytab[3]; +#endif +#else + for (unsigned i=0;i<=dim;++i) + res.tab[i]=x.tab[i]+y.tab[i]; +#endif + } + tdeg_t15 operator - (const tdeg_t15 & x,const tdeg_t15 & y){ + tdeg_t15 res; +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y,*ztab=(ulonglong *)&res; + ztab[0]=xtab[0]-ytab[0]; + ztab[1]=xtab[1]-ytab[1]; + ztab[2]=xtab[2]-ytab[2]; +#if GROEBNER_VARS>11 + ztab[3]=xtab[3]-ytab[3]; +#endif +#else + for (unsigned i=0;i<=GROEBNER_VARS;++i) + res.tab[i]=x.tab[i]-y.tab[i]; +#endif + return res; + } + inline bool operator == (const tdeg_t15 & x,const tdeg_t15 & y){ + return ((longlong *) x.tab)[0] == ((longlong *) y.tab)[0] && + ((longlong *) x.tab)[1] == ((longlong *) y.tab)[1] && + ((longlong *) x.tab)[2] == ((longlong *) y.tab)[2] +#if GROEBNER_VARS>11 + && ((longlong *) x.tab)[3] == ((longlong *) y.tab)[3] +#endif + ; + } + inline bool operator != (const tdeg_t15 & x,const tdeg_t15 & y){ + return !(x==y); + } + + static inline int tdeg_t15_revlex_greater (const tdeg_t15 & x,const tdeg_t15 & y){ +#ifdef GBASIS_SWAP +#if 1 + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + if (xtab[0]!=ytab[0]) // tdeg test already donne by caller + return xtab[0]<=ytab[0]?1:0; + if (xtab[1]!=ytab[1]) + return xtab[1]<=ytab[1]?1:0; + if (xtab[2]!=ytab[2]) + return xtab[2]<=ytab[2]?1:0; +#else + longlong *xtab=(longlong *)&x,*ytab=(longlong *)&y; + if (longlong a=*xtab-*ytab) // tdeg test already donne by caller + return a<=0?1:0; + if (longlong a=xtab[1]-ytab[1]) + return a<=0?1:0; + if (longlong a=xtab[2]-ytab[2]) + return a<=0?1:0; +#endif +#if GROEBNER_VARS>11 + return xtab[3]<=ytab[3]?1:0; +#endif + return 2; +#else // GBASIS_SWAP + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]<=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; + } +#if GROEBNER_VARS>11 + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ + if (x.tab[12]!=y.tab[12]) + return x.tab[12]<=y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; + } +#endif + return 2; +#endif // GBASIS_SWAP + } + + +#if GROEBNER_VARS==15 + + int tdeg_t15_3var_greater (const tdeg_t15 & x,const tdeg_t15 & y){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[4]!=y.tab[4]) + return x.tab[4]>=y.tab[4]?1:0; + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[0] <= ((longlong *) y.tab)[0]; +#else + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; +#endif + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[1] <= ((longlong *) y.tab)[1]; +#else + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; +#endif + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[2] <= ((longlong *) y.tab)[2]; +#else + if (x.tab[8]!=y.tab[8]) + return x.tab[8]<=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; +#endif + } + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[3] <= ((longlong *) y.tab)[3]; +#else + if (x.tab[12]!=y.tab[12]) + return x.tab[12]<=y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; +#endif + } + return 2; + } + + int tdeg_t15_7var_greater (const tdeg_t15 & x,const tdeg_t15 & y){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[8]!=y.tab[8]) + return x.tab[8]>=y.tab[8]?1:0; + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[0] <= ((longlong *) y.tab)[0]; +#else + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; +#endif + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[1] <= ((longlong *) y.tab)[1]; +#else + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; +#endif + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[2] <= ((longlong *) y.tab)[2]; +#else + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; +#endif + } + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[3] <= ((longlong *) y.tab)[3]; +#else + if (x.tab[12]!=y.tab[12]) + return x.tab[12]<=y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; +#endif + } + return 2; + } + + int tdeg_t15_11var_greater (const tdeg_t15 & x,const tdeg_t15 & y){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>=y.tab[0]?1:0; + if (x.tab[12]!=y.tab[12]) + return x.tab[12]>=y.tab[12]?1:0; + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[0] <= ((longlong *) y.tab)[0]; +#else + if (x.tab[1]!=y.tab[1]) + return x.tab[1]<=y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]<=y.tab[2]?1:0; + return x.tab[3]<=y.tab[3]?1:0; +#endif + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[1] <= ((longlong *) y.tab)[1]; +#else + if (x.tab[4]!=y.tab[4]) + return x.tab[4]<=y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]<=y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]<=y.tab[6]?1:0; + return x.tab[7]<=y.tab[7]?1:0; +#endif + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[2] <= ((longlong *) y.tab)[2]; +#else + if (x.tab[8]!=y.tab[8]) + return x.tab[8]<=y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]<=y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]<=y.tab[10]?1:0; + return x.tab[11]<=y.tab[11]?1:0; +#endif + } + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ +#ifdef GBASIS_SWAP + return ((longlong *) x.tab)[3] <= ((longlong *) y.tab)[3]; +#else + if (x.tab[13]!=y.tab[13]) + return x.tab[13]<=y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]<=y.tab[14]?1:0; + return x.tab[15]<=y.tab[15]?1:0; +#endif + } + return 2; + } +#endif // GROEBNER_VARS==15 + + int tdeg_t15_lex_greater (const tdeg_t15 & x,const tdeg_t15 & y){ +#if 0 // def GBASIS_SWAP + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + ulonglong X=*xtab, Y=*ytab; + if (X!=Y){ + if ( (X & 0xffff) != (Y &0xffff)) + return (X&0xffff)>=(Y&0xffff)?1:0; + return X>=Y?1:0; + } + if (xtab[1]!=ytab[1]) + return xtab[1]>=ytab[1]?1:0; + if (xtab[2]!=ytab[2]) + return xtab[2]>=ytab[2]?1:0; +#if GROEBNER_VARS>11 + return xtab[3]>=ytab[3]?1:0; +#endif + return 2; +#else + if (((longlong *) x.tab)[0] != ((longlong *) y.tab)[0]){ + if (x.tab[0]!=y.tab[0]) + return x.tab[0]>y.tab[0]?1:0; + if (x.tab[1]!=y.tab[1]) + return x.tab[1]>y.tab[1]?1:0; + if (x.tab[2]!=y.tab[2]) + return x.tab[2]>y.tab[2]?1:0; + return x.tab[3]>y.tab[3]?1:0; + } + if (((longlong *) x.tab)[1] != ((longlong *) y.tab)[1]){ + if (x.tab[4]!=y.tab[4]) + return x.tab[4]>y.tab[4]?1:0; + if (x.tab[5]!=y.tab[5]) + return x.tab[5]>y.tab[5]?1:0; + if (x.tab[6]!=y.tab[6]) + return x.tab[6]>y.tab[6]?1:0; + return x.tab[7]>y.tab[7]?1:0; + } + if (((longlong *) x.tab)[2] != ((longlong *) y.tab)[2]){ + if (x.tab[8]!=y.tab[8]) + return x.tab[8]>y.tab[8]?1:0; + if (x.tab[9]!=y.tab[9]) + return x.tab[9]>y.tab[9]?1:0; + if (x.tab[10]!=y.tab[10]) + return x.tab[10]>y.tab[10]?1:0; + return x.tab[11]>=y.tab[11]?1:0; + } +#if GROEBNER_VARS>11 + if (((longlong *) x.tab)[3] != ((longlong *) y.tab)[3]){ + if (x.tab[12]!=y.tab[12]) + return x.tab[12]>y.tab[12]?1:0; + if (x.tab[13]!=y.tab[13]) + return x.tab[13]>y.tab[13]?1:0; + if (x.tab[14]!=y.tab[14]) + return x.tab[14]>y.tab[14]?1:0; + return x.tab[15]>=y.tab[15]?1:0; + } +#endif + return 2; +#endif + } + + inline int tdeg_t_greater(const tdeg_t15 & x,const tdeg_t15 & y,order_t order){ + short X=x.tab[0]; + if (//order.o!=_PLEX_ORDER && + X!=y.tab[0]) return X>y.tab[0]?1:0; // since tdeg is tab[0] for plex + if (order.o==_REVLEX_ORDER) + return tdeg_t15_revlex_greater(x,y); +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER) + return tdeg_t15_3var_greater(x,y); + if (order.o==_7VAR_ORDER) + return tdeg_t15_7var_greater(x,y); + if (order.o==_11VAR_ORDER) + return tdeg_t15_11var_greater(x,y); +#endif + return tdeg_t15_lex_greater(x,y); + } + inline bool tdeg_t_strictly_greater (const tdeg_t15 & x,const tdeg_t15 & y,order_t order){ + return !tdeg_t_greater(y,x,order); // total order + } + + bool tdeg_t_all_greater(const tdeg_t15 & x,const tdeg_t15 & y,order_t order){ + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + if ((xtab[0]-ytab[0]) & 0x8000800080008000ULL) + return false; + if ((xtab[1]-ytab[1]) & 0x8000800080008000ULL) + return false; + if ((xtab[2]-ytab[2]) & 0x8000800080008000ULL) + return false; +#if GROEBNER_VARS>11 + if ((xtab[3]-ytab[3]) & 0x8000800080008000ULL) + return false; +#endif + return true; + } + + // 1 (all greater), 0 (unknown), -1 (all smaller) + int tdeg_t_compare_all(const tdeg_t15 & x,const tdeg_t15 & y,order_t order){ + int res=0; + ulonglong *xtab=(ulonglong *)&x,*ytab=(ulonglong *)&y; + longlong tmp=xtab[0]-ytab[0]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } + tmp=xtab[1]-ytab[1]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } + tmp=xtab[2]-ytab[2]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } +#if GROEBNER_VARS>11 + tmp=xtab[3]-ytab[3]; + if (tmp & mask){ + if (res==1 || ((-tmp) & mask)) return 0; + res=-1; + } + else { + if (res==-1) return 0; else res=1; + } +#endif + return res; + } + + void index_lcm(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & z,order_t order){ + int t=0; + const short * xtab=&x.tab[1],*ytab=&y.tab[1]; + short *ztab=&z.tab[1]; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 1 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 2 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 3 + ++xtab; ++ytab; ++ztab; +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER){ + z.tab[0]=t; + t=0; + ++xtab;++ytab;++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 + z.tab[4]=t; // 4 + return; + } +#endif + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 4 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 5 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 6 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 7 + ++xtab; ++ytab; ++ztab; +#if GROEBNER_VARS==15 + if (order.o==_7VAR_ORDER){ + z.tab[0]=t; + t=0; + ++xtab;++ytab;++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 + z.tab[8]=t; // 8 + return; + } +#endif + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 8 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 9 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 10 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 11 +#if GROEBNER_VARS>11 + ++xtab; ++ytab; ++ztab; +#if GROEBNER_VARS==15 + if (order.o==_11VAR_ORDER){ + z.tab[0]=t; + t=0; + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 + z.tab[12]=t; // 12 + return; + } +#endif + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 12 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 13 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 14 + ++xtab; ++ytab; ++ztab; + t += (*ztab=(*xtab>*ytab)?*xtab:*ytab); // 15 +#endif + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER){ + z.tab[0]=t; + } + else { + z.tab[0]=(x.tab[0]>y.tab[0])?x.tab[0]:y.tab[0]; + } + } + + inline void index_lcm_overwrite(const tdeg_t15 & x,const tdeg_t15 & y,tdeg_t15 & z,order_t order){ + index_lcm(x,y,z,order); + } + + void get_index(const tdeg_t15 & x_,index_t & idx,order_t order,int dim){ + idx.resize(dim); +#ifdef GBASIS_SWAP + tdeg_t15 x(x_); + swap_indices15(x.tab,order.o); +#else + const tdeg_t15 & x= x_; +#endif + const short * ptr=x.tab; +#if GROEBNER_VARS==15 + if (order.o==_3VAR_ORDER){ + ++ptr; + for (int i=1;i<=3;++ptr,++i) + idx[3-i]=*ptr; + ++ptr; + for (int i=1;i<=dim-3;++ptr,++i) + idx[dim-i]=*ptr; + return; + } + if (order.o==_7VAR_ORDER){ + ++ptr; + for (int i=1;i<=7;++ptr,++i) + idx[7-i]=*ptr; + ++ptr; + for (int i=1;i<=dim-7;++ptr,++i) + idx[dim-i]=*ptr; + return; + } + if (order.o==_11VAR_ORDER){ + ++ptr; + for (int i=1;i<=11;++ptr,++i) + idx[11-i]=*ptr; + ++ptr; + for (int i=1;i<=dim-11;++ptr,++i) + idx[dim-i]=*ptr; + return; + } +#endif + if (order.o==_REVLEX_ORDER || order.o==_TDEG_ORDER) + ++ptr; + if (order.o==_REVLEX_ORDER){ + for (int i=1;i<=dim;++ptr,++i) + idx[dim-i]=*ptr; + } + else { + for (int i=0;i + static void get_newres(const T & resmod,vectpoly & newres,const vectpoly & v,const vector & G){ + newres=vectpoly(G.size(),polynome(v.front().dim,v.front())); + for (unsigned i=0;i + static void get_newres(const vectpoly8 & resmod,vectpoly & newres,const vectpoly & v,vector< vectpoly8 > * coeffsmodptr,vector * coeffsptr){ + newres=vectpoly(resmod.size(),polynome(v.front().dim,v.front())); + for (unsigned i=0;iclear(); + coeffsptr->resize(resmod.size()); + for (unsigned i=0;i & src = (*coeffsmodptr)[i]; + vectpoly & target = (*coeffsptr)[i]; + target.resize(src.size()); + for (unsigned j=0;j + static void get_newres_ckrur(const vectpolymod & resmod,vectpoly & newres,const vectpoly & v,const vector & G,modint env,int & rur,vector *initsep,vector< vectpolymod > * coeffsmodptr,vector * coeffsptr){ + if (rur && !resmod.empty()){ + vectpolymod gbmod; gbmod.reserve(G.size()); + for (int i=0;i lmtmp(order,dim),lmmodradical(order,dim); + polymod s(order,dim); + vectpolymod rurv; + if (rur_quotient_ideal_dimension(gbmod,lmtmp)<0) + rur=0; + else { + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " begin modular rur computation" << '\n'; + bool ok; + if (rur==2){ + vecteur m,M,res; + s.coord.clear(); + index_t l(dim); + l[dim-1]=1; + s.coord.push_back(T_unsigned(1,tdeg_t(l,order))); + ok=rur_minpoly(gbmod,lmtmp,s,env,m,M); + rur_convert_univariate(m,dim-1,gbmod[0]); + gbmod.resize(1); + } + else { + ok=rur_compute(gbmod,lmtmp,lmmodradical,env,s,initsep,rurv); + if (ok) + gbmod.swap(rurv); + } + if (!ok) + rur=0; + } + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " end modular rur computation" << '\n'; + newres=vectpoly(gbmod.size(),polynome(v.front().dim,v.front())); + for (unsigned i=0;iclear(); + coeffsptr->resize(G.size()); + for (unsigned i=0;i & src = (*coeffsmodptr)[G[i]]; + vectpoly & target = (*coeffsptr)[i]; + target.resize(src.size()); + for (unsigned j=0;j * coeffsptr){ + bool & eliminate_flag=gbasis_param.eliminate_flag; + if (gbasis_param.buchberger_select_strategy==-1 && !v.empty()){ + if (GBASIS_COEFF_STRATEGY) + gbasis_param.buchberger_select_strategy=GBASIS_COEFF_STRATEGY; + else { + gbasis_param.buchberger_select_strategy=(coeffsptr && v.front().dim<=10)?2/* topreduceonly=true */:11000; + // gbasis_param.buchberger_select_strategy=(coeffsptr && v.front().dim<=8)?1000001/* topreduceonly=true */:0; + } + if (debug_infolevel) + CERR << "strategy " << gbasis_param.buchberger_select_strategy << "\n"; } + bool interred=gbasis_param.interred; + int parallel=1; +#ifdef HAVE_LIBPTHREAD + if (threads_allowed && threads>1) + parallel=threads; +#endif + int save_debuginfo=debug_infolevel; + if (v.empty()){ newres.clear(); return true;} +#ifdef GIAC_TDEG_T14 + // do not use tdeg_t14 for rur because monomials have often large degrees + if (v.front().dim<=14 && order.o==_REVLEX_ORDER && !rur){ + try { + vectpoly8 res; + vectpolymod resmod; + vector G; + vectpoly_2_vectpoly8(v,order,res); + // Temporary workaround until rur_compute support parametric rur + if (rur && absint(order.o)!=-_RUR_REVLEX){ + rur=0; + order.o=absint(order.o); + } + CLOCK_T c=CLOCK(); + if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){ + std::vector > gbasis_coeffs; + if (mod_gbasis(res,modularcheck, + //order.o==_REVLEX_ORDER /* zdata*/, + 1 || !rur /* zdata*/, + rur,contextptr,gbasis_param,coeffsptr?&gbasis_coeffs:0)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << 'M'<<'\n'; + get_newres(res,newres,v,&gbasis_coeffs,coeffsptr); + debug_infolevel=save_debuginfo; return true; + } + } + if (env && env->moduloon && env->modulo.type==_INT_){ + if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){ + vector > f4buchberger_info; + vector< vectpolymod > gbasiscoeff; + vector< paire > pairs_reducing_to_zero; + f4buchberger_info.reserve(GBASISF4_MAXITER); + if (zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,&pairs_reducing_to_zero,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false /* 1 mod only */,parallel,interred,&gbasis_param.initsep,gbasis_param,coeffsptr?&gbasiscoeff:0)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" <<'\n'; + get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur,&gbasis_param.initsep,&gbasiscoeff,coeffsptr); + debug_infolevel=save_debuginfo; return true; + } + } + else { + if (in_gbasisf4buchbergermod(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" <<'\n'; + get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur,&gbasis_param.initsep,0,0); + debug_infolevel=save_debuginfo; return true; + } + } + } // end if gbasis computation modulo integer + else { +#ifdef GIAC_REDUCEMODULO + vectpoly w(v); + reduce(w,env); + sort_vectpoly(w.begin(),w.end()); + vectpoly_2_vectpoly8(w,order,res); +#endif + if (in_gbasis(res,G,env,true)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; + get_newres(res,newres,v,G); + debug_infolevel=save_debuginfo; return true; + } + } + } catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + CERR << "Degree too large for compressed monomials. Using uncompressed monomials instead." << '\n'; + } + } +#endif + if (v.front().dim<=11 && order.o==_REVLEX_ORDER){ + vectpoly8 res; + vectpolymod resmod; + vector G; + vectpoly_2_vectpoly8(v,order,res); + // Temporary workaround until rur_compute support parametric rur + if (rur && absint(order.o)!=-_RUR_REVLEX){ + rur=0; + order.o=absint(order.o); + } + CLOCK_T c=CLOCK(); + if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){ + std::vector > gbasis_coeffs; + if (mod_gbasis(res,modularcheck, + //order.o==_REVLEX_ORDER /* zdata*/, + 1 || !rur /* zdata*/, + rur,contextptr,gbasis_param,coeffsptr?&gbasis_coeffs:0)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; + get_newres(res,newres,v,&gbasis_coeffs,coeffsptr); + debug_infolevel=save_debuginfo; return true; + } + } + if (env && env->moduloon && env->modulo.type==_INT_){ + if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){ + vector > f4buchberger_info; + vector< vectpolymod > gbasiscoeff; + vector< paire > pairs_reducing_to_zero; + f4buchberger_info.reserve(GBASISF4_MAXITER); + if (zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,&pairs_reducing_to_zero,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false /* 1 mod only */,parallel,interred,&gbasis_param.initsep,gbasis_param,coeffsptr?&gbasiscoeff:0)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; + get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur,&gbasis_param.initsep,&gbasiscoeff,coeffsptr); + debug_infolevel=save_debuginfo; return true; + } + } + else { + if (in_gbasisf4buchbergermod(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; + get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur,&gbasis_param.initsep,0,0); + debug_infolevel=save_debuginfo; return true; + } + } + } // end if gbasis modulo integer + else { +#ifdef GIAC_REDUCEMODULO + vectpoly w(v); + reduce(w,env); + sort_vectpoly(w.begin(),w.end()); + vectpoly_2_vectpoly8(w,order,res); +#endif + if (in_gbasis(res,G,env,true)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; + get_newres(res,newres,v,G); + debug_infolevel=save_debuginfo; return true; + } + } + } + if (v.front().dim<=15 + //&& order.o==_REVLEX_ORDER + &&order.o<_16VAR_ORDER + ){ + vectpoly8 res; + vectpolymod resmod; + vector G; + vectpoly_2_vectpoly8(v,order,res); + // Temporary workaround until rur_compute support parametric rur + if (rur && absint(order.o)!=-_RUR_REVLEX){ + rur=0; + order.o=absint(order.o); + } + CLOCK_T c=CLOCK(); + if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){ + std::vector > gbasis_coeffs; + if (mod_gbasis(res,modularcheck, + //order.o==_REVLEX_ORDER /* zdata*/, + 1 || !rur /* zdata*/, + rur,contextptr,gbasis_param,coeffsptr?&gbasis_coeffs:0)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; + get_newres(res,newres,v,&gbasis_coeffs,coeffsptr); + debug_infolevel=save_debuginfo; return true; + } + } + if (env && env->moduloon && env->modulo.type==_INT_){ +#ifdef GBASISF4_BUCHBERGER + if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){ + vector > f4buchberger_info; + vector< vectpolymod > gbasiscoeff; + vector< paire > pairs_reducing_to_zero; + f4buchberger_info.reserve(GBASISF4_MAXITER); + if (!zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,&pairs_reducing_to_zero,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false/* 1 mod only*/,parallel,interred,&gbasis_param.initsep,gbasis_param,coeffsptr?&gbasiscoeff:0)) + return false; + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; +#if 1 + get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur,&gbasis_param.initsep,&gbasiscoeff,coeffsptr); +#else + newres=vectpoly(G.size(),polynome(v.front().dim,v.front())); + for (unsigned i=0;i(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false); +#else + in_gbasismod(res,resmod,G,env->modulo.val,true,0); +#endif + if (debug_infolevel) + CERR << "G=" << G << '\n'; + } + else { // env->modoloon etc. +#ifdef GIAC_REDUCEMODULO + vectpoly w(v); + reduce(w,env); + sort_vectpoly(w.begin(),w.end()); + vectpoly_2_vectpoly8(w,order,res); +#endif + in_gbasis(res,G,env,true); + } + newres=vectpoly(G.size(),polynome(v.front().dim,v.front())); + for (unsigned i=0;i res; + vectpolymod resmod; + vector G; + vectpoly_2_vectpoly8(v,order,res); + // Temporary workaround until rur_compute support parametric rur + if (rur && absint(order.o)!=-_RUR_REVLEX){ + rur=0; + order.o=absint(order.o); + } + CLOCK_T c=CLOCK(); + if (modularalgo && (!env || env->modulo==0 || env->moduloon==false)){ + std::vector > gbasis_coeffs; + if (mod_gbasis(res,modularcheck, + //order.o==_REVLEX_ORDER /* zdata*/, + 1 || !rur /* zdata*/, + rur,contextptr,gbasis_param,coeffsptr?&gbasis_coeffs:0)){ + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; + get_newres(res,newres,v,&gbasis_coeffs,coeffsptr); + debug_infolevel=save_debuginfo; return true; + } + } + if (env && env->moduloon && env->modulo.type==_INT_){ +#ifdef GBASISF4_BUCHBERGER + if (!res.empty() && (res.front().order.o==_REVLEX_ORDER || res.front().order.o==_3VAR_ORDER || res.front().order.o==_7VAR_ORDER || res.front().order.o==_11VAR_ORDER)){ + vector > f4buchberger_info; + vector< vectpolymod > gbasiscoeff; + vector< paire > pairs_reducing_to_zero; + f4buchberger_info.reserve(GBASISF4_MAXITER); + zgbasis(res,resmod,G,env->modulo.val,true/*totaldeg*/,&pairs_reducing_to_zero,f4buchberger_info,false/* recomputeR*/,false /* don't compute res8*/,eliminate_flag,false/* 1 mod only*/,parallel,interred,&gbasis_param.initsep,gbasis_param,coeffsptr?&gbasiscoeff:0); + if (debug_infolevel) + *logptr(contextptr) << "// Groebner basis computation time " << (CLOCK()-c)*1e-6 << " Memory " << memory_usage()*1e-6 << "M" << '\n'; +#if 1 + get_newres_ckrur(resmod,newres,v,G,env->modulo.val,rur,&gbasis_param.initsep,&gbasiscoeff,coeffsptr); +#else + newres=vectpoly(G.size(),polynome(v.front().dim,v.front())); + for (unsigned i=0;i(res,resmod,G,env->modulo.val,true/*totaldeg*/,0,0,false); +#else + in_gbasismod(res,resmod,G,env->modulo.val,true,0); +#endif + if (debug_infolevel) + CERR << "G=" << G << '\n'; + } + else { +#ifdef GIAC_REDUCEMODULO + vectpoly w(v); + reduce(w,env); + sort_vectpoly(w.begin(),w.end()); + vectpoly_2_vectpoly8(w,order,res); +#endif + in_gbasis(res,G,env,true); + } + newres=vectpoly(G.size(),polynome(v.front().dim,v.front())); + for (unsigned i=0;i red,gb,quo; + vectpoly_2_vectpoly8(v,order,red); + vectpoly_2_vectpoly8(gb_,order,gb); + poly8 rem,TMP1,TMP2; + vector G; G_idn(G,gb_.size()); + int dim; + for (int i=0;i1) + COUT << CLOCK()*1e-6 << " begin reduce poly no " << i << " #monomials " << red[i].coord.size() << '\n'; + gen lambda; + reduce(red[i],gb,G,-1,quo,rem,TMP1,TMP2,lambda,env); + if (debug_infolevel>1) + COUT << CLOCK()*1e-6 << " end reduce poly no " << i << " #monomials " << rem.coord.size() << '\n'; + for (int j=0;j. + */ +using namespace std; +#include +#include +#include +#include "gen.h" +#include "csturm.h" +#include "vecteur.h" +#include "modpoly.h" +#include "unary.h" +#include "symbolic.h" +#include "usual.h" +#include "sym2poly.h" +#include "solve.h" +#include "prog.h" +#include "subst.h" +#include "permu.h" +#include "series.h" +#include "alg_ext.h" +#include "ti89.h" +#include "plot.h" +#include "modfactor.h" +#include"giacintl.h" +#include +#define MPFI_CERT +#ifdef HAVE_LIBMPS +#include +#include +#include +#include +#include +#endif + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + // compute Sturm sequence of r0 and r1, + // returns gcd (without content) + // and compute list of quotients, coeffP, coeffR + // such that coeffR*r_(k+2) = Q_k*r_(k+1) - coeffP_k*r_k + gen csturm_seq(modpoly & r0,modpoly & r1,vecteur & listquo,vecteur & coeffP, vecteur & coeffR,GIAC_CONTEXT){ + listquo.clear(); + coeffP.clear(); + coeffR.clear(); + if (r0.empty()) + return r1; + if (r1.empty()) + return r0; + gen tmp; + lcmdeno(r0,tmp,contextptr); + if (ck_is_positive(-tmp,contextptr)) + r0=-r0; + r0=r0/abs(lgcd(r0),contextptr); + lcmdeno(r1,tmp,contextptr); + if (ck_is_positive(-tmp,contextptr)) + r1=-r1; + r1=r1/abs(lgcd(r0),contextptr); + // set auxiliary constants g and h to 1 + gen g(1),h(1); + modpoly a(r0),b(r1),quo,r; + gen b0(1); + for (int loop_counter=0;;++loop_counter){ + int m=int(a.size())-1; + int n=int(b.size())-1; + int ddeg=m-n; // should be 1 generically + if (!n) { // if b is constant, gcd=1 + return 1; + } + b0=b.front(); + if (b.front().type==_VECT) { + // ddeg should be even if b0 is a _POLY1 + if (ddeg%2==0) + *logptr(contextptr) << gettext("Singular parametric Sturm sequence ") << a << "/" << b << '\n'; + } + else + b0=abs(b.front(),contextptr); + coeffP.push_back(pow(b0,ddeg+1)); + DivRem(coeffP.back()*a,b,0,quo,r); + listquo.push_back(quo); + coeffR.push_back(g*pow(h,ddeg)); + if (r.empty()){ + return b/abs(lgcd(b),contextptr); + } + // remainder is non 0, loop continue: a <- b + a=b; + // now divides r by g*h^(m-n) and change sign, result is the new b + b= -r/coeffR.back(); + g=b0; + h=pow(b0,ddeg)/pow(h,ddeg-1); + } // end while loop + } + + static gen csturm_horner(const modpoly & p,const gen & a){ + if (p.size()==1 && p.front().type==_POLY && p.front()._POLYptr->dim==1){ + // patch for "sparse modpoly" + vector< monomial >::const_iterator it=p.front()._POLYptr->coord.begin(),itend=p.front()._POLYptr->coord.end(); + gen res=0,anum=a,aden=1,den=1; + int oldpui=0,pui; + if (a.type==_FRAC){ + anum=a._FRACptr->num; + aden=a._FRACptr->den; + } + for (;it!=itend;++it){ + pui=it->index.front(); + if (oldpui){ + res = res * pow(anum,oldpui-pui,context0); + den = den * pow(aden,oldpui-pui,context0); + } + res += it->value*den; + oldpui=pui; + } + if (oldpui){ + res = res *pow(a,oldpui,context0); + den = den *pow(a,oldpui,context0); + } + return res/den; + } + else + return horner(p,a); + } + + static int csturm_vertex_ab(const modpoly & r0,const modpoly & r1,const vecteur & listquo,const vecteur & coeffP, const vecteur & coeffR,const gen & a,int start,GIAC_CONTEXT){ + int n=int(listquo.size()),j,k,res=0; + vecteur R(n+2); + R[0]=csturm_horner(r0,a); + R[1]=csturm_horner(r1,a); + for (j=0;j=0;--i){ + if (p[i].type==_INT_) + mpz_set_si(pi,p[i].val); + else + mpz_set(pi,*p[i]._ZINTptr); + if (lb<0) + mpz_tdiv_q_2exp(pi,pi,(-lb)*(n-1-i)); // was mpz_fdiv_q_2exp + else + mpz_mul_2exp(pi,pi,lb*(n-1-i)); + p[i] = pi; + } + mpz_clear(pi); + //chk=p; p=save; + return; + } + gen lton(l); + for (int i=n-2;i>=0;--i){ + p[i] = p[i] * lton; + lton = lton * l; + } + //if (p!=chk) CERR << "bug\n"; + } + + void back_change_scale(modpoly & p,const gen & l,longlong lb){ + if (lb!=(1<<31)){ + change_scale(p,l,-lb); + return; + } + int n=int(p.size()); + gen lton(l); + for (int i=n-2;i>=0;--i){ + p[i] = p[i] / lton; + lton = lton * l; + } + } + + // p(x)->p(a*x+b) + modpoly linear_changevar(const modpoly & p,const gen & a,const gen & b){ + modpoly res(taylor(p,b)); + change_scale(res,a); + return res; + } + + // p(a*x+b)->p(x) + // t=a*x+b -> pgcd(t)=g((t-b)/a) + modpoly inv_linear_changevar(const modpoly & p,const gen & a,const gen & b){ + gen A=inv(a,context0); + gen B=-b/a; + modpoly res(taylor(p,B)); + change_scale(res,A); + return res; + } + + // Find roots of R, S=R' at precision eps, returns number of roots + // if eps==0 does not compute intervals for roots + static int csturm_realroots(const modpoly & S,const modpoly & R,const vecteur & listquo,const vecteur & coeffP, const vecteur & coeffR,const gen & a,const gen & b,const gen & t0, const gen & t1,vecteur & realroots,double eps,GIAC_CONTEXT){ + if (is_inf(t0)) // replace with max(R) + return csturm_realroots(S,R,listquo,coeffP,coeffR,a,b,-linfnorm(R,contextptr),t1,realroots,eps,contextptr); + if (is_inf(t1)) // replace with max(R) + return csturm_realroots(S,R,listquo,coeffP,coeffR,a,b,t0,linfnorm(R,contextptr),realroots,eps,contextptr); + int n1=csturm_vertex_ab(S,R,listquo,coeffP,coeffR,t0,1,contextptr); + int n2=csturm_vertex_ab(S,R,listquo,coeffP,coeffR,t1,1,contextptr); + int n=(n2-n1); + if (!eps || !n) + return n; + /* disabled localization of roots, do isolation of roots instead + if (is_strictly_greater(eps,(t1-t0)*abs(b,contextptr),contextptr)){ + realroots.push_back(makevecteur(makevecteur(a+t0*b,a+t1*b),n)); + return n; + } + */ + if (n==1){ + gen T0=t0,T1=t1,T2; + int s0=fastsign(csturm_horner(R,T0),contextptr); + // int s1=fastsign(csturm_horner(R,T1),contextptr); + int s2; + gen delta=evalf_double(log((T1-T0)*abs(b,contextptr)/eps,contextptr)/log(2.,contextptr),1,contextptr); + if (delta.type!=_DOUBLE_){ + realroots=vecteur(1,gentypeerr(contextptr)); + return -2; + } + int nstep=int(delta._DOUBLE_val+1); + for (int step=0;step0 put roots in [a,b] + // at precision eps inside realroots + // returns a,b,R,S,g,listquo,coeffP,coeffR,typeseq + // with typeseq=0 (complex Sturm) or 1 (limit) + // If b-a is real and horiz_sturm is not empty, it tries to replace + // the variable by im(a)*i in horiz_sturm and if no quotient in horiz_sturm + // has a leading 0 coefficient, + // it returns im(a)*i,im(a)*i+1,R,S,g,listquo,coeffP,coeffR,typeseq + // If b-a is pure imaginary and vert_sturm is not empty, it tries to replace + // the variable by re(a) and returns re(a),re(a)+i,R,S,g,listquo,coeffP,coeffR,typeseq + static vecteur csturm_segment_seq(const modpoly & P,const gen & a,const gen & b,vecteur & realroots,double eps,vecteur & horiz_sturm,vecteur & vert_sturm,GIAC_CONTEXT){ + // try with horiz_sturm and vert_sturm + gen ab(b-a); + /* // Optimization fails for sturmab(x^3-1,-1-i,1+i) + if (is_zero(re(ab,contextptr))){ // b-a is pure imaginary + if (vert_sturm.empty()){ + gen A=gen(makevecteur(1,0),_POLY1__VECT); + vert_sturm.push_back(undef); + vecteur tmp; + vert_sturm=csturm_segment_seq(P,A,A+cst_i,tmp,eps,horiz_sturm,vert_sturm,contextptr); + if (is_undef(vert_sturm)) + return vert_sturm; + } + if (vert_sturm.size()==9){ + vecteur res(vert_sturm); + gen A=re(a,contextptr); + res[0]=A; // re(a) + res[1]=A+cst_i; // re(a)+i + res[2]=apply1st(res[2],A,horner); // R + res[3]=apply1st(res[3],A,horner); // S + res[4]=horner(res[4],A); // g + vecteur tmp(*res[5]._VECTptr); + int tmps=tmp.size(); + for (int j=0;jsize()==P.size()){ + // if g==P (up to a constant), use real Sturm sequences + if (debug_infolevel) + *logptr(contextptr) << "Real-kind roots: " << g << '\n'; + R=*g._VECTptr; + S=derivative(R); + g=csturm_seq(S,R,listquo,coeffP,coeffR,contextptr); + typeseq=csturm_realroots(S,R,listquo,coeffP,coeffR,a,b-a,0,1,realroots,eps,contextptr); + if (typeseq==-2) + return realroots; + } + if (g.type==_VECT) + g=inv_linear_changevar(*g._VECTptr,b-a,a); + vecteur res= makevecteur(a,b,R,S,g,listquo,coeffP,coeffR,typeseq); + return res; + } + + // index for segment a,b (2* number of roots when summed over a closed + // polygon). Note that if S=ImP along the segment is 0 we remove + // the roots on [a,b] using real Sturm sequences + // If S=0 at a or b, this is simply ignored + // Indeed the computed index is then the same as if S was of the + // sign of R, and since R!=0 if S is 0 this is a property of the vertex + // not of the segment (note that contrary to counting real roots + // on an interval, S can vanish as many times as long as R keeps + // the same sign, without modifying the algebraic number of Im=0 + // cuts if S has the same sign on both end) + static int csturm_segment(const vecteur & seq,const gen & a,const gen & b,GIAC_CONTEXT){ + gen t0,t1; + if (seq.size()!=9) + return -(RAND_MAX/2); + gen aseq=seq[0]; + gen bseq=seq[1]; + gen directeur=(b-a)/(bseq-aseq); + t0=(a-aseq)/(bseq-aseq); + if ( !is_zero(im(directeur,contextptr)) || !is_zero(im(t0,contextptr)) ) + return -(RAND_MAX/2); + t0=re(t0,contextptr); // t0=normal(t0); + t1=re(t0+directeur,contextptr); // t1=normal(t0+directeur); + int signe=1; + if (is_strictly_greater(t0,t1,contextptr)){ + signe=-1; + swapgen(t0,t1); + } + const modpoly & R=*seq[2]._VECTptr; + const modpoly & S=*seq[3]._VECTptr; + gen g=seq[4]; + const modpoly & listquo=*seq[5]._VECTptr; + const modpoly & coeffP=*seq[6]._VECTptr; + const modpoly & coeffR=*seq[7]._VECTptr; + int debut=(seq[8].val==-1)?0:1; + int tmp = csturm_vertex_ab(S,R,listquo,coeffP,coeffR,t0,debut,contextptr); + int res = tmp; + tmp = csturm_vertex_ab(S,R,listquo,coeffP,coeffR,t1,debut,contextptr); + res -= tmp; + // tmp = (-csturm_vertex_a(S,R,t0,1,contextptr)+csturm_vertex_a(S,R,t1,-1,contextptr)); + // res += tmp; + res=(debut?1:signe)*res; + if (debug_infolevel) + *logptr(contextptr) << "segment " << a << ".." << b << " index contribution " << res << '\n'; + return res; + } + + static bool csturm_square_seq(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,gen & pgcd,vecteur & realroots,double eps,vecteur & seq1,vecteur & seq2,vecteur & seq3,vecteur & seq4,vecteur & horiz_sturm,vecteur & vert_sturm,GIAC_CONTEXT){ + gen A=a0+cst_i*b0,B=a1+cst_i*b0; + vecteur rroots; + seq1=csturm_segment_seq(P,A,B,rroots,eps,horiz_sturm,vert_sturm,contextptr); + if (is_undef(seq1)) + return false; + pgcd=seq1[4]; + if (!is_one(pgcd)){ + return false; + } + A=a1+cst_i*b0; B=a1+cst_i*b1; + seq2=csturm_segment_seq(P,A,B,rroots,eps,horiz_sturm,vert_sturm,contextptr); + if (is_undef(seq2)) + return false; + pgcd=seq2[4]; + if (!is_one(pgcd)){ + return false; + } + A=a1+cst_i*b1; B=a0+cst_i*b1; + seq3=csturm_segment_seq(P,A,B,rroots,eps,horiz_sturm,vert_sturm,contextptr); + if (is_undef(seq3)) + return false; + pgcd=seq3[4]; + if (!is_one(pgcd)){ + return false; + } + A=a0+cst_i*b1; B=a0+cst_i*b0; + seq4=csturm_segment_seq(P,A,B,rroots,eps,horiz_sturm,vert_sturm,contextptr); + if (is_undef(seq4)) + return false; + pgcd=seq4[4]; + if (!is_one(pgcd)){ + return false; + } + realroots=mergevecteur(realroots,rroots); + return true; + } + + // find 2* number of roots of P inside the square of vertex of affixes a,b + // roots on the square are not counted. P must not vanish at the vertices. + // The complex Sturm sequences must be known + // returns -1 on error + static int csturm_square(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,const vecteur & seq1,const vecteur & seq2,const vecteur & seq3,const vecteur & seq4,GIAC_CONTEXT){ + int ind,tmp; + ind = 0; + gen A=a0+cst_i*b0,B=a1+cst_i*b0; + tmp = csturm_segment(seq1,A,B,contextptr); + if (tmp==-(RAND_MAX/2)) + return -1; + ind += tmp; + A=a1+cst_i*b0; B=a1+cst_i*b1; + tmp = csturm_segment(seq2,A,B,contextptr); + if (tmp==-(RAND_MAX/2)) + return -1; + ind += tmp; + A=a1+cst_i*b1; B=a0+cst_i*b1; + tmp = csturm_segment(seq3,A,B,contextptr); + if (tmp==-(RAND_MAX/2)) + return -1; + ind += tmp; + A=a0+cst_i*b1; B=a0+cst_i*b0; + tmp = csturm_segment(seq4,A,B,contextptr); + if (tmp==-(RAND_MAX/2)) + return -1; + ind += tmp; + return ind; + } + + static void csturm_normalize(modpoly & p,const gen & a0,const gen & b0,const gen & a1,const gen & b1,vecteur & roots){ + int n=int(p.size())-1; + // Make sure that x->a+i*x does not return a multiple + // of a real polynomial with the multiple non real + // If degree of p is even the multiple will be a real (because of lcoeff) + if (n%2){ + // If degree is odd then look at q=p(x-a_{n-1}/n*an) + // it has the same property + // if its cst coeff is zero remove + gen an=p.front(); + gen b=p[1]; + gen shift=-b/n/an; + modpoly q(taylor(p,shift)); + gen q0; + // remove valuation + int qs=int(q.size()); + int n1=0; + for (;qs>0;--qs,++n1){ + if (!is_zero(q0=q[qs-1])) + break; + } + if (is_zero(re(q0,context0))){ + q=cst_i*q; + p=cst_i*p; + } + if (n1){ + q=modpoly(q.begin(),q.begin()+qs); + gen a=re(shift,context0),b=im(shift,context0); + if (is_greater(a,a0,context0) && is_greater(b,b0,context0) && is_greater(a1,a,context0) && is_greater(b1,b,context0)) + roots.push_back(makevecteur(shift,n1)); + p=taylor(q,-shift); + } + } + } + + void ab2a0b0a1b1(const gen & a,const gen & b,gen & a0,gen & b0,gen & a1,gen & b1,GIAC_CONTEXT){ + a0=re(a,contextptr); b0=im(a,contextptr); + a1=re(b,contextptr); b1=im(b,contextptr); + if (ck_is_greater(a0,a1,contextptr)) swapgen(a0,a1); + if (ck_is_greater(b0,b1,contextptr)) swapgen(b0,b1); + } + + // find 2* number of roots of P inside the square of vertex of affixes a,b + // excluding those on the square + // returns -1 on error + int csturm_square(const gen & p,const gen & a,const gen & b,gen& pgcd,GIAC_CONTEXT){ + if (p.type==_POLY){ + int res=0; + factorization f(sqff(*p._POLYptr)); + factorization::const_iterator it=f.begin(),itend=f.end(); + for (;it!=itend;++it){ + int tmp=csturm_square(polynome2poly1(it->fact),a,b,pgcd,contextptr); + if (tmp==-1) + return -1; + res += it->mult*tmp; + } + return res; + } + if (p.type!=_VECT) + return 0; + modpoly P=*p._VECTptr; + vecteur realroots; + gen a0,b0,a1,b1; + ab2a0b0a1b1(a,b,a0,b0,a1,b1,contextptr); + csturm_normalize(P,a0,b0,a1,b1,realroots); + int evident=0; + if (!realroots.empty()){ + gen r=realroots.front(); + if (r.type==_VECT && r._VECTptr->size()==2) + r=r._VECTptr->front(); + gen rx=re(r,contextptr),ry=im(r,contextptr); + if ( ( is_zero(ry) && (rx==a0 || rx==a1) ) || + ( is_zero(rx) && (ry==b0 || ry==b1) ) ) + ; + else + evident=1; + } + if (P.size()<2) + return evident; + vecteur seq1,seq2,seq3,seq4,horiz_seq,vert_seq; + if (!csturm_square_seq(P,a0,b0,a1,b1,pgcd,realroots,0.0,seq1,seq2,seq3,seq4,horiz_seq,vert_seq,contextptr)){ + if (pgcd.type!=_VECT) + return -1; + modpoly g=(*pgcd._VECTptr)/pgcd[0]; + // true factorization found, restart with each factor + modpoly p1=P/g; + int n1=csturm_square(p1,a,b,pgcd,contextptr); + if (n1==-1) + return -1; + int n2=csturm_square(g,a,b,pgcd,contextptr); + if (n2==-1) + return -1; + return evident+n1+n2; + } + int tmp=csturm_square(P,a0,b0,a1,b1,seq1,seq2,seq3,seq4,contextptr); + if (tmp==-1) + return tmp; + return evident+tmp; + } + + static void complex_roots(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,vecteur & realroots,vecteur & complexroots,double eps); + + static bool complex_roots_split(const modpoly & P,const gen & pgcd,const gen & a0,const gen & b0,const gen & a1,const gen & b1,vecteur & realroots,vecteur & complexroots,double eps){ + if (pgcd.type!=_VECT) + return false; + modpoly g=(*pgcd._VECTptr)/pgcd[0]; + // true factorization found, restart with each factor + modpoly p1=P/g; + csturm_normalize(p1,a0,b0,a1,b1,realroots); + csturm_normalize(g,a0,b0,a1,b1,realroots); + complex_roots(p1,a0,b0,a1,b1,realroots,complexroots,eps); + complex_roots(g,a0,b0,a1,b1,realroots,complexroots,eps); + return true; + } + +#if 0 + // check that arg is >=pi/8 (assumes im(g)>=0) + static bool arg_geq_pi_8(const gen & g){ + gen gr=re(g,context0),gi=im(g,context0); + if (is_positive(-gr,context0)) + return true; + // ? gi/gr>=sqrt(2)-1 + gen r=gi/gr+1; + if (is_positive(r*r-2,context0)) + return true; + return false; + } + + // is im(b/a)>=0, tested without quotient + static bool arg_in_0_pi(const gen & a,const gen & b){ + gen A(a),B(b); + if (A.type==_FRAC && is_integer(A._FRACptr->den) && is_positive(A._FRACptr->den,context0)) + A=A._FRACptr->num; + if (B.type==_FRAC && is_integer(B._FRACptr->den) && is_positive(B._FRACptr->den,context0)) + B=B._FRACptr->num; + gen c=re(A,context0)*im(B,context0)+re(B,context0)*im(A,context0); + return is_positive(c,context0); + } + + static gen hornerarg(const modpoly & p,const gen & x){ + if (p.empty()) + return 0; + if (x.type!=_FRAC || !is_integer(x._FRACptr->den)) + return horner(p,x); + fraction & f =*x._FRACptr; + gen num=f.num,den=f.den,d=den; + if (is_positive(-f.den,context0)){ + num=-num; den=-den; d=den; + } + modpoly::const_iterator it=p.begin(),itend=p.end(); + gen res(*it); + ++it; + if (it==itend) + return res; + for (;;){ + res=res*num+(*it)*d; + ++it; + if (it==itend) + break; + d=d*den; + } + return res; + } + + // Find one complex root inside a0,b0->a1,b1, return false if not found + static bool complex_1root(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,vecteur & complexroots,double eps){ + return false; // disabled since it is not faster!! + int step,nstep =int(evalf_double(log(max(a1-a0,b1-b0,context0)/eps,context0)/log(2.0,context0),1,context0)._DOUBLE_val+0.5); + if (nstep<4) + return false; + // First compute P at the 4 vertex and check whether P[vertex_n+1]/P[vertex_n] is in C^+ + gen P0=hornerarg(P,a0+cst_i*b0),P2=hornerarg(P,a1+cst_i*b0), + P4=hornerarg(P,a1+cst_i*b1),P6=hornerarg(P,a0+cst_i*b1); + if (!(arg_in_0_pi(P0,P2) && arg_in_0_pi(P2,P4) && arg_in_0_pi(P4,P6) && arg_in_0_pi(P6,P0))) + return false; + gen A0(a0),A2(a1),B0(b0),B2(b1),A1,B1; + for (step=0;step<2*nstep;step++){ + A1=(A0+A2)/2; + B1=(B0+B2)/2; + gen P1=hornerarg(P,A1+cst_i*B0),P7=hornerarg(P,A0+cst_i*B1),P8=hornerarg(P,A1+cst_i*B1),P3,P5; + bool found=false; + /* + P6(A0,B2) - P5(A1,B2) - P4(A2,B2) + | | | + P7(A0,B1) - P8(A1,B1) - P3(A2,B1) + | | | + P0(A0,B0) - P1(A1,B0) - P2(A2,B0) + */ + // ? P0, P1, P8, P7 + if (arg_in_0_pi(P0,P1) && arg_in_0_pi(P1,P8) && arg_in_0_pi(P8,P7) && arg_in_0_pi(P7,P0)){ + A2=A1; + B2=B1; + P2=P1; + P4=P8; + P6=P7; + if (step= pi/8 and degree of (P)*max square length/distance to original square <= pi/8 + gen dist=min(min(A0-a0,a1-A2,context0),min(B0-b0,b1-B2,context0),context0); + if (is_zero(dist)) + continue; + gen max_sq=max(A2-A0,B2-B0,context0); + if (is_greater((int(P.size())-2)*max_sq/dist,cst_pi/8,context0)) + continue; + gen r1=P2/P0, r2=P4/P2, r3=P6/P4, r4=P0/P6; + if (arg_geq_pi_8(r1) && arg_geq_pi_8(r2) && arg_geq_pi_8(r3) && arg_geq_pi_8(r4)){ + complexroots.push_back(makevecteur(makevecteur(A0+cst_i*B0,A2+cst_i*B2),1)); + return true; + } + } + return false; + } +#endif + + static gen round2util(const gen & num,const gen & den,int n){ + if (num.type==_CPLX){ + gen r=round2util(*num._CPLXptr,den,n); + gen i=round2util(*(num._CPLXptr+1),den,n); + return r+cst_i*i; + } + // num must be a _ZINT + mpz_t tmp1,tmp2; + mpz_init_set(tmp1,*num._ZINTptr); + mpz_mul_2exp(tmp1,tmp1,n+1); // tmp1=2^(n+1)*num + mpz_add(tmp1,tmp1,*den._ZINTptr); // + den + mpz_init_set(tmp2,*den._ZINTptr); + mpz_mul_ui(tmp2,tmp2,2); // tmp2=2*den + mpz_fdiv_q(tmp1,tmp1,tmp2); + gen res=tmp1; + mpz_clear(tmp1); mpz_clear(tmp2); + return res; + } + + void in_round2(gen & x,const gen & deuxn, int n){ + if (x.type==_INT_ || x.type==_ZINT) + return ; + if (x.type==_FRAC && x._FRACptr->den.type==_CPLX) + x=fraction(x._FRACptr->num*conj(x._FRACptr->den,context0),x._FRACptr->den.squarenorm(context0)); + if (x.type==_FRAC && x._FRACptr->den.type==_ZINT && + (x._FRACptr->num.type==_ZINT || + (x._FRACptr->num.type==_CPLX && x._FRACptr->num._CPLXptr->type==_ZINT && (x._FRACptr->num._CPLXptr+1)->type==_ZINT)) + ){ + gen num=x._FRACptr->num,d=x._FRACptr->den; + x=round2util(num,d,n); + x=x/deuxn; + return; + } + x=_floor(x*deuxn+plus_one_half,context0)/deuxn; + } + + void round2(gen & x,int n){ + if (x.type==_INT_ || x.type==_ZINT) + return ; + gen deuxn; + if (n<30) + deuxn = (1<num,d=x._FRACptr->den; + if (d.type==_INT_){ + int di=d.val,ni=1; + while (di>1){ di=di>>1; ni=ni<<1;} + if (ni==d.val) + return; + } + n=2*n*deuxn+d; + x=iquo(n,2*d)/deuxn; + } + } + + // Find one complex root inside a0,b0->a1,b1, return false if not found + // algo: Newton method in exact mode starting from center + bool newton_complex_1root(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,vecteur & complexroots,double eps){ + if (is_positive(a1-a0-0.01,context0) || + is_positive(b1-b0-0.01,context0)) + return false; + gen x0=(a0+a1)/2+cst_i*(b0+b1)/2; + modpoly Pprime=derivative(P); + int n=int(-std::log(eps)/std::log(2.0)+.5); // for rounding + gen eps2=pow(2,-(n+1),context0); + for (int ii=0;ii a1,b1 + static int complex_roots(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,const vecteur & seq1,const vecteur & seq2,const vecteur & seq3,const vecteur & seq4,vecteur & realroots,vecteur & complexroots,double eps,vecteur & horiz_sturm,vecteur & vert_sturm){ + int n=csturm_square(P,a0,b0,a1,b1,seq1,seq2,seq3,seq4,context0); + if (debug_infolevel && n) + CERR << a0 << "," << b0 << ".." << a1 << "," << b1 << ":" << n/2 << '\n'; + if (n<=0) + return 2*n; + if (eps<=0){ + *logptr(context0) << gettext("Bad precision, using 1e-12 instead of ")+print_DOUBLE_(eps,14) << '\n'; + eps=1e-12; + } + if (is_strictly_greater(eps,a1-a0,context0) && is_strictly_greater(eps,b1-b0,context0)){ + gen r(makevecteur(a0+cst_i*b0,a1+cst_i*b1)); + complexroots.push_back(makevecteur(r,gen(n)/2)); + return n; + } + if (n==2 && newton_complex_1root(P,a0,b0,a1,b1,complexroots,eps)) + return n; + gen a01=(a0+a1)/2,b01=(b0+b1)/2,pgcd; + vecteur seqvert,seqhoriz; + gen A=a0+cst_i*b01,B=a1+cst_i*b01; + seqhoriz=csturm_segment_seq(P,A,B,realroots,eps,horiz_sturm,vert_sturm,context0); + if (is_undef(seqhoriz)){ + realroots=seqhoriz; + return -2; + } + pgcd=seqhoriz[4]; + if (is_one(pgcd)){ + A=a01+cst_i*b0; B=a01+cst_i*b1; + seqvert=csturm_segment_seq(P,A,B,realroots,eps,horiz_sturm,vert_sturm,context0); + if (is_undef(seqvert)){ + realroots=seqvert; + return -2; + } + pgcd=seqvert[4]; + } + if (!is_one(pgcd)){ + complex_roots_split(P,pgcd,a0,b0,a1,b1,realroots,complexroots,eps); + return n; + } + /* + (a0,b1) - (a01,b1) - (a1,b1) seq3 seq3 + | n4 | n3 | seq4 n4 seqvert n3 seq2 + (a0,b01) - (a01,b01) - (a1,b01) seqhoriz seqhoriz + | n1 | n2 | seq4 n1 seqvert n2 seq2 + (a0,b0) - (a01,b0) - (a1,b0) seq1 seq1 + */ + int n1=complex_roots(P,a0,b0,a01,b01,seq1,seqvert,seqhoriz,seq4,realroots,complexroots,eps,horiz_sturm,vert_sturm),nadd; + if (n1==-2) + return -2; + if (n1==n) + return n; + n1 += (nadd=complex_roots(P,a01,b0,a1,b01,seq1,seq2,seqhoriz,seqvert,realroots,complexroots,eps,horiz_sturm,vert_sturm)); + if (nadd==-2) + return -2; + if (n1==n) + return n; + n1 += (nadd=complex_roots(P,a01,b01,a1,b1,seqhoriz,seq2,seq3,seqvert,realroots,complexroots,eps,horiz_sturm,vert_sturm)); + if (nadd==-2) + return -2; + if (n1==n) + return n; + n1 += (nadd=complex_roots(P,a0,b01,a01,b1,seqhoriz,seqvert,seq3,seq4,realroots,complexroots,eps,horiz_sturm,vert_sturm)); + if (nadd==-2) + return -2; + return n; + } + + // Find complex roots of P in a0,b0 -> a1,b1 + static void complex_roots(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,vecteur & realroots,vecteur & complexroots,double eps){ + if (P.size()<2) + return; + vecteur Seq1,Seq2,Seq3,Seq4,horiz_sturm,vert_sturm; + gen pgcd; + if (!csturm_square_seq(P,a0,b0,a1,b1,pgcd,realroots,eps,Seq1,Seq2,Seq3,Seq4,horiz_sturm,vert_sturm,context0)) + complex_roots_split(P,pgcd,a0,b0,a1,b1,realroots,complexroots,eps); + else + complex_roots(P,a0,b0,a1,b1,Seq1,Seq2,Seq3,Seq4,realroots,complexroots,eps,horiz_sturm,vert_sturm); + } + + // Find complex roots of P in a0,b0 -> a1,b1 + bool complex_roots(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,gen & pgcd,vecteur & roots,double eps){ + vecteur realroots,complexroots; + complex_roots(P,a0,b0,a1,b1,realroots,complexroots,eps); + if (is_undef(realroots)) + return false; + roots=mergevecteur(roots,mergevecteur(realroots,complexroots)); + return true; + } + + vecteur crationalroot(polynome & p,bool complexe){ + vectpoly v; + int i=1; + polynome qrem; + environment * env= new environment; + env->complexe=complexe || !is_zero(im(p,context0)); + vecteur w; + if (!do_linearfind(p,env,qrem,v,w,i)) + w.clear(); + delete env; + p=qrem; + return w; + } + + vecteur keep_in_rectangle(const vecteur & croots,const gen A0,const gen & B0,const gen & A1,const gen & B1,bool embed,GIAC_CONTEXT){ + vecteur roots; + const_iterateur it=croots.begin(),itend=croots.end(); + for (;it!=itend;++it){ + gen a=re(*it,contextptr),b=im(*it,contextptr); + if (is_greater(a,A0,contextptr)&&is_greater(A1,a,contextptr)&&is_greater(b,B0,contextptr)&&is_greater(B1,b,contextptr)) + roots.push_back(embed?makevecteur(*it,1):*it); + } + return roots; + } + + gen square_modulus(const gen & g,GIAC_CONTEXT){ + return g.squarenorm(contextptr); + } + + // P is the polynomial, P1 derivative, v list of approx roots + // (initially should have at least n bits precision), + // epsn is the target number of bits precision int(std::log(eps)/std::log(2.)-.5); + // epsg2surdeg2 is eps^2/degree(P)^2 as a gen, epsg is the target precision + // v[i] is set by newton_improve to be at distance at most vradius[i] of a root + // kmax is the maximal number of Newton iterations + bool newton_improve(const vecteur & P,const vecteur & P1,bool Preal,vecteur & v,vecteur & vradius,int i,int kmax,int n,int epsn,const gen & epsg2surdeg2,const gen & epsg){ + gen r=v[i]; + bool nextconj=false; + if (Preal && i+1inf)>N) + N=mpfr_get_prec(r._REALptr->inf); + if (r.type==_CPLX && r._CPLXptr->type==_REAL && mpfr_get_prec(r._CPLXptr->_REALptr->inf)>N) + N=mpfr_get_prec(r._CPLXptr->_REALptr->inf); +#endif +#if 0 // def HAVE_LIBMPFI + gen deuxN=pow(2,N,context0); + gen rr,ri,dr,di; + reim(r,rr,ri,context0); + if (Preal && !nextconj) + r=eval(gen(makevecteur(rr-plus_one/deuxN,rr+plus_one/deuxN),_INTERVAL__VECT),1,context0); + else + r=eval(gen(makevecteur(rr-plus_one/deuxN,rr+plus_one/deuxN),_INTERVAL__VECT),1,context0)+cst_i*eval(gen(makevecteur(ri-plus_one/deuxN,ri+plus_one/deuxN),_INTERVAL__VECT),1,context0); + for (int k=0;k(delta._REALptr)){ + mpfr_t tmp; mpfr_init(tmp); + mpfi_get_right(tmp,ptr->infsup); + delta=real_object(tmp); + mpfr_clear(tmp); + } + } + sumdr2 += delta; + if (!is_greater(deltar*deltar,sumdr2,context0)){ + CERR << "Unable to certify " << v[i] << '\n' ; + return false; + } + if (N(rr._REALptr)) + mpfi_set_prec(ptr->infsup,N); + } + if (ri.type==_REAL){ + if (real_interval * ptr=dynamic_cast(ri._REALptr)) + mpfi_set_prec(ptr->infsup,N); + } + r=rr+cst_i*ri; + } // end for k +#else + if (N>int(P.size())/4-epsn/2) + N=int(P.size())/4-epsn/2; + gen deuxN=pow(2,N,context0); + for (int k=0;kinf); + ad=real_object(a._REALptr->inf); + au=real_object(a._REALptr->inf); + mpfr_set_prec(ad._REALptr->inf,n+1); + mpfr_set_prec(au._REALptr->inf,n+1); + mpfr_set(ad._REALptr->inf,a._REALptr->inf,MPFR_RNDD); + mpfr_sub(ad._REALptr->inf,ad._REALptr->inf,r._REALptr->inf,MPFR_RNDD); + mpfr_set(au._REALptr->inf,a._REALptr->inf,MPFR_RNDU); + mpfr_add(au._REALptr->inf,au._REALptr->inf,r._REALptr->inf,MPFR_RNDU); + } + else { + ad=a-r; + au=a+r; + } + } +#else + void round1downup(const gen & a,const gen & r,gen & ad,gen & au){ + ad=au=a; + } +#endif + + // find roots of polynomial P at precision eps using proot or + // complex Sturm sequences + // P must have numeric coefficients, in Q[i] and should be squarefree + vecteur complex_roots(const modpoly & P,const gen & a0,const gen & b0,const gen & a1,const gen & b1,bool complexe,double eps,bool use_proot){ + if (P.empty()) + return P; + bool mps=eps<0; + eps=absdouble(eps); + if (eps>1e-6) + eps=1e-6; + if (eps<=0) + eps=1e-12; + { + vecteur v,res,vradius; + bool b; + if (mps) + b=mps_solve(P,v,vradius,-eps,1/* isolate*/,true/*secular algo*/,context0)==0; + else + b=aberth(P,v,vradius,ABERTH_NMAX,eps,3/* isolate*/,false/* exact*/,context0); + if (b){ + for (unsigned j=0;jnum; + if (P2.type==_FRAC) P2=P2._FRACptr->num; + if (is_strictly_positive(-P1*P2,context0)){ + if (is_greater(v[j],a0,context0) && is_greater(a1,v[j],context0) && is_greater(0,b0,context0) && is_greater(b1,0,context0)) + res.push_back(makevecteur(eval(change_subtype(makevecteur(v[j]-vradius[j],v[j]+vradius[j]),_INTERVAL__VECT),1,context0),1)); + continue; + } + } + gen R,I; + reim(v[j],R,I,context0); + if (is_greater(R,a0,context0) && is_greater(a1,R,context0) && is_greater(I,b0,context0) && is_greater(b1,I,context0)){ + if (is_exactly_zero(vradius[j])) + res.push_back(makevecteur(v[j],1)); + else { +#ifdef HAVE_LIBMPFI + gen a,b; + reim(v[j],a,b,context0); + res.push_back(makevecteur(eval(change_subtype(makevecteur(a-vradius[j],a+vradius[j]),_INTERVAL__VECT),1,context0)+cst_i*eval(change_subtype(makevecteur(b-vradius[j],b+vradius[j]),_INTERVAL__VECT),1,context0),1)); +#else + res.push_back(makevecteur(makevecteur(ratnormal(v[j]-vradius[j]*(1+cst_i)),ratnormal(v[j]+vradius[j]*(1+cst_i))),1)); +#endif + } + } + } + return res; + } // end if i==v.size() + } // end for n + CERR << "proot isolation did not work, trying complex Sturm sequences" << '\n'; + } + bool aplati=(a0==a1) && (b0==b1); + if (!aplati && complexe && (a0==a1 || b0==b1) ) + return vecteur(1,gensizeerr(gettext("Square is flat!"))); + gen A0(a0),B0(b0),A1(a1),B1(b1); + { + // initial rectangle: |roots|< 1+ max(|a_i|)/|a_n| + gen maxai=_max(*apply(P,abs,context0)._VECTptr,context0); + gen tmp=1+maxai/abs(P.front(),context0); + if (aplati){ + A0=-tmp; + B0=-tmp; + A1=tmp; + B1=tmp; + } + if (is_inf(A0)) A0=-tmp; + if (is_inf(B0)) B0=-tmp; + if (is_inf(A1)) A1=tmp; + if (is_inf(B1)) B1=tmp; + } + gen tmp; + modpoly p(*apply(P,exact,context0)._VECTptr); + lcmdeno(p,tmp,context0); + polynome pp(poly12polynome(p)); + if (!complexe){ + gen tmp=gcd(re(pp,context0),im(pp,context0)); + if (tmp.type!=_POLY) + return vecteur(0); + pp=*tmp._POLYptr; + } + vecteur croots=crationalroot(pp,complexe); + vecteur roots=keep_in_rectangle(croots,A0,B0,A1,B1,true,context0); + p=polynome2poly1(pp); + gen an=p.front(); + if (!is_zero(im(an,context0))) + p=conj(p.front(),context0)*p; + if (!complexe){ // real root isolation + modpoly R=p; + modpoly S=derivative(R); + vecteur listquo,coeffP,coeffR; + csturm_seq(S,R,listquo,coeffP,coeffR,context0); + // sparse polynomial patch + if (pp.coord.size()=1.0) + eps=std::pow(10.,-eps); + if (v[0].type==_VECT && has_num_coeff(v[0])){ + v=proot(*v[0]._VECTptr,eps,contextptr); + vecteur w; + for (unsigned i=0;i3){ + A=v[2]; + B=v[3]; + a0=re(A,contextptr); b0=im(A,contextptr); + a1=re(B,contextptr);b1=im(B,contextptr); + } + if (is_greater(a0,a1,contextptr)) + swapgen(a0,a1); + if (is_greater(b0,b1,contextptr)) + swapgen(b0,b1); + vecteur vas_res; + if (p.type==_VECT){ + if (use_vas && vas(*p._VECTptr,a0,a1,isolation?1e300:eps,vas_res,true,contextptr)) + return vas_res; + return complex_roots(*p._VECTptr,a0,b0,a1,b1,complexe,eps,use_proot); + } + if (use_vas && vas(symb2poly_num(v[0],contextptr),a0,a1,isolation?1e300:eps,vas_res,true,contextptr)) + return vas_res; + vecteur l,l0; + lidnt(p,l0,false); + if (l0.size()!=1) + return gentypeerr(contextptr); + l=alg_lvar(p); + gen px=_e2r(makesequence(p,l),contextptr); + if (px.type==_FRAC) + px=px._FRACptr->num; + if (px.type!=_POLY) + return vecteur(0); + factorization f(sqff(*px._POLYptr)); + factorization::const_iterator it=f.begin(),itend=f.end(); + vecteur res; + for (;it!=itend;++it){ + gen P=_poly2symb(makesequence(it->fact,l),contextptr); + P=_e2r(makesequence(P,l0.front()),contextptr); + if (P.type!=_VECT) + continue; + vecteur tmp=complex_roots(*P._VECTptr,a0,b0,a1,b1,complexe,eps,use_proot); + if (is_undef(tmp)) + return tmp; + iterateur jt=tmp.begin(),jtend=tmp.end(); + for (;jt!=jtend;++jt){ + if (jt->type==_VECT && jt->_VECTptr->size()==2) + jt->_VECTptr->back()=it->mult*jt->_VECTptr->back(); + } + res=mergevecteur(res,tmp); + } + return res; + } + + gen _complexroot(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + gen res=complexroot(g,true,contextptr); + if (res.type==_VECT) + gen_sort_f_context(res._VECTptr->begin(),res._VECTptr->end(),complex_sort,contextptr); + return res; + // return _sorta(complexroot(g,true,contextptr),contextptr); + } + static const char _complexroot_s []="complexroot"; + static define_unary_function_eval (__complexroot,&_complexroot,_complexroot_s); + define_unary_function_ptr5( at_complexroot ,alias_at_complexroot,&__complexroot,0,true); + + gen _realroot(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + gen res; bool evalf_after=false; + if (g.type==_VECT && !g._VECTptr->empty() && g._VECTptr->back()==at_evalf){ + res=complexroot(gen(vecteur(g._VECTptr->begin(),g._VECTptr->end()-1),g.subtype),false,contextptr); + evalf_after=true; + } + else + res=complexroot(g,false,contextptr); + if (res.type!=_VECT) + return res; + vecteur v=*res._VECTptr; + for (unsigned i=0;isize()==2){ + gen a=v[i]._VECTptr->front(),b=v[i]._VECTptr->back(); + if (a.type==_VECT && a.subtype==_INTERVAL__VECT){ + if (evalf_after) + v[i]=evalf((a._VECTptr->front()+a._VECTptr->back())/2,1,contextptr); + else { + a=eval(a,1,contextptr); + v[i]=makevecteur(a,b); + } + } + else { + if (evalf_after) + v[i]=evalf(a,1,contextptr); + } + } + } + return v; + } + static const char _realroot_s []="realroot"; + static define_unary_function_eval (__realroot,&_realroot,_realroot_s); + define_unary_function_ptr5( at_realroot ,alias_at_realroot,&__realroot,0,true); + + static vecteur crationalroot(const gen & g0,bool complexe){ + gen g(g0),a,b; + if (g.type==_VECT){ + if (g.subtype==_SEQ__VECT){ + vecteur & tmp=*g._VECTptr; + if (tmp.size()!=3) + return vecteur(1,gendimerr(context0)); + g=tmp[0]; + a=tmp[1]; + b=tmp[2]; + } + else { + g=poly12polynome(*g._VECTptr); + } + } + gen a0,b0,a1,b1; + ab2a0b0a1b1(a,b,a0,b0,a1,b1,context0); + vecteur l; + lvar(g,l); + if (l.empty()) + return vecteur(0); + if (l.size()!=1) + return vecteur(1,gentypeerr(context0)); + gen px=_e2r(makevecteur(g,l),context0); + if (px.type==_FRAC) + px=px._FRACptr->num; + if (px.type!=_POLY) + return vecteur(0); + factorization f(sqff(*px._POLYptr)); + factorization::const_iterator it=f.begin(),itend=f.end(); + vecteur res; + for (;it!=itend;++it){ + polynome p=it->fact; + vecteur tmp=crationalroot(p,complexe); + res=mergevecteur(res,tmp); + } + if (a0!=a1 || b0!=b1) + res=keep_in_rectangle(res,a0,b0,a1,b1,false,context0); + return res; + } + gen _crationalroot(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + return crationalroot(g,true); + } + static const char _crationalroot_s []="crationalroot"; + static define_unary_function_eval (__crationalroot,&_crationalroot,_crationalroot_s); + define_unary_function_ptr5( at_crationalroot ,alias_at_crationalroot,&__crationalroot,0,true); + + gen _rationalroot(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + return crationalroot(g,false); + } + static const char _rationalroot_s []="rationalroot"; + static define_unary_function_eval (__rationalroot,&_rationalroot,_rationalroot_s); + define_unary_function_ptr5( at_rationalroot ,alias_at_rationalroot,&__rationalroot,0,true); + + // convert numerator of g to a list + vecteur symb2poly_num(const gen & g_,GIAC_CONTEXT){ + gen g(g_); + if (g.type!=_VECT) + g=makesequence(g,ggb_var(g)); + gen tmp=_symb2poly(g,contextptr); + if (tmp.type==_FRAC) + tmp=tmp._FRACptr->num; + if (tmp.type!=_VECT) + return vecteur(1,gensizeerr(contextptr)); + return *tmp._VECTptr; + } + // VAS implementation. Based on Xcas implementation by Alkiviadis G. Akritas, + // A first C++ implementation was written by Spyros Kehagias and others + // but it was too close to the Xcas code + // This implementation is much faster, using basic data structures of giac + // number of sign changes of the coefficients of P, returns -1 on error + int variations(const modpoly & P,GIAC_CONTEXT){ + int res=0,n=int(P.size()); + if (!n) + return -1; + int previous=fastsign(P.front(),contextptr); + if (previous==0) + return -1; + for (int i=1;i & cllnabsmant,vector & clexpo,vector & clsign,GIAC_CONTEXT){ + int k=int(cl.size()); + cllnabsmant.resize(k); + clexpo.resize(k); + clsign.resize(k); + for (int i=0;i cllnabsmant; + vector clexpo; + vector clsign; + if (!compute_lnabsmantexpo(cl,cllnabsmant,clexpo,clsign,contextptr)) + return gensizeerr(contextptr); + gen tempmax=minus_inf; + vector timesused(k+1,1); + for (int m=k-1;m>=1;--m){ + if (clsign[m-1]==-1){ // is_strictly_positive(-cl[m-1],contextptr) + gen tempmin=plus_inf; + for (int n=k;n>m;--n){ + if (clsign[n-1]==1){ // is_strictly_positive(cl[n-1],contextptr) + gen temp= (cllnabsmant[m-1]-cllnabsmant[n-1] + (clexpo[m-1]-clexpo[n-1]+timesused[n-1])*M_LN2)/(n-m);// LMQ_evalf(cl[m-1],cl[n-1],timesused[n-1],n-m,contextptr); + // gen temp=pow(-cl[m-1]/cl[n-1]*pow(plus_two,timesused[n-1]),inv(n-m,contextptr),contextptr); + // temp=evalf(temp,1,contextptr); + ++timesused[n-1]; + if (is_strictly_greater(tempmin,temp,contextptr)) + tempmin=temp; + } + } + if (is_strictly_greater(tempmin,tempmax,contextptr)) + tempmax=tempmin; + } + } + return _ceil(65*exp(tempmax,contextptr)/64,contextptr); // small margin + } + + gen _posubLMQ(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + vecteur v; + if (g.type==_VECT && g.subtype!=_SEQ__VECT) + v=*g._VECTptr; + else + v=symb2poly_num(g,contextptr); + return posubLMQ(v,contextptr); + } + static const char _posubLMQ_s []="posubLMQ"; + static define_unary_function_eval (__posubLMQ,&_posubLMQ,_posubLMQ_s); + define_unary_function_ptr5( at_posubLMQ ,alias_at_posubLMQ,&__posubLMQ,0,true); + + gen poslbdLMQ(const modpoly & P,int & res,GIAC_CONTEXT){ + //---implements the Local_Max_Quadratic method (LMQ) to compute a + //---lower bound on the values of the POSITIVE roots of p(x). + + //---Reference:"Linear and Quadratic Complexity Bounds on the Values of the + //---Positive Roots of Polynomials" by Alkiviadis G. Akritas. + //---Journal of Universal Computer Science, Vol. 15, No. 3, 523-537, 2009. + int k=int(P.size()); + if (k<=1) + return 0; + vecteur cl(P); + reverse(cl.begin(),cl.end()); + if (is_strictly_positive(-cl.front(),contextptr)) + cl=-cl; + vector cllnabsmant; + vector clexpo; + vector clsign; + if (!compute_lnabsmantexpo(cl,cllnabsmant,clexpo,clsign,contextptr)) + return gensizeerr(contextptr); + gen tempmax=symbolic(at_neg,_IDNT_infinity()); + vector timesused(k,1); + for (int m=1;msize()==2) + a1=a._VECTptr->front(); + if (b.type==_VECT && b._VECTptr->size()==2) + b1=b._VECTptr->front(); + return is_strictly_greater(b1,a1,context0); + } + + // P is assumed to be squarefree and without rational roots + // find roots of P((ax+b)/(cx+d)) + vecteur VAS_positive_roots(const modpoly & P,const gen & ap,const gen & bp,const gen & cp,const gen & dp,GIAC_CONTEXT){ + matrice Pascal; + //---The steps below correspond to the steps described in the reference below. + + //---Reference: "A Comparative Study of Two Real Root Isolation Methods" + //---by Alkiviadis G. Akritas and Adam W. Strzebonski. + //---Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. + vecteur res; // root isolation intervals + vecteur intervals_to_process; + // STEP 1 + int v0=variations(P,contextptr); + if (!v0) + return res; + gen ub=posubLMQ(P,contextptr); + if (v0==1) + return vecteur(1,makeinterval(0,ap*ub)); + intervals_to_process.push_back(makevecteur(ap, bp, cp, dp, P,v0)); + + // STEP 2 + while (!intervals_to_process.empty()){ + gen tmp=intervals_to_process.back(); + intervals_to_process.pop_back(); + if (tmp.type!=_VECT || tmp._VECTptr->size()!=6) + return vecteur(1,gensizeerr("VAS interval"+tmp.print())); + vecteur & tmpv=*tmp._VECTptr; + gen a=tmpv[0],b=tmpv[1],c=tmpv[2],d=tmpv[3], genf=tmpv[4],genv=tmpv[5]; + if (genf.type!=_VECT || genv.type!=_INT_) + return vecteur(1,gensizeerr("VAS interval"+tmp.print())); + int v=genv.val; + modpoly f = *genf._VECTptr; + + // STEP 3 + int lbi; + gen lb=poslbdLMQ(f,lbi,contextptr); + + // STEP 4 + if (is_strictly_greater(lb,16,contextptr)){ + change_scale(f,lb,lbi); + a=lb*a; c=lb*c; lb=1; lbi=0; + } + + // STEP 5 + if (is_greater(lb,1,contextptr)){ + // f=taylor(f,lb); + change_scale(f,lb,lbi); + f=taylor(f,1,0,&Pascal); + back_change_scale(f,lb,lbi); + b = lb*a + b; d = lb*c + d; + if (is_zero(f.back())){ + res.push_back(b/d); + f.pop_back(); + } + v=variations(f,contextptr); + if (!v) + continue; + if (v==1){ + if (!is_zero(c)) + res.push_back(makeinterval(a/c,b/d)); + else + res.push_back(makeinterval(b,b+a*posubLMQ(f,contextptr))); + continue; + } + } + + // STEP 6 + modpoly f1=taylor(f,1,0,&Pascal),f2; + gen a1=a, b1=a+b, c1=c, d1=c+d; + int r=0; + if (is_zero(f1.back())){ + f1.pop_back(); + res.push_back(b1/d1); + r=1; + } + int v1=variations(f1,contextptr); + int v2=v-v1-r; + gen a2=b, b2=a+b, c2=d, d2=c+d; + + // STEP 7 + if (v2>1){ + f2=f; + reverse(f2.begin(),f2.end()); + f2=taylor(f2,1,0,&Pascal); + if (is_zero(f2.back())) + f2.pop_back(); + v2=variations(f2,contextptr); + } + + // STEP 8 + if (v1v=VAS_positive_roots(*ptr->P,ptr->a,ptr->b,ptr->c,ptr->d,ptr->contextptr); + return ptr_; + } + + gen _VAS_positive(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + vecteur v; + if (g.type==_VECT && g.subtype!=_SEQ__VECT) + v=*g._VECTptr; + else + v=symb2poly_num(g,contextptr); + return VAS_positive_roots(v,1,0,0,1,contextptr); + } + static const char _VAS_positive_s []="VAS_positive"; + static define_unary_function_eval (__VAS_positive,&_VAS_positive,_VAS_positive_s); + define_unary_function_ptr5( at_VAS_positive ,alias_at_VAS_positive,&__VAS_positive,0,true); + + // square-free factorization of p, then remove all exponents + // optionally remove factors with even multiplicities + modpoly remove_multiplicities(const modpoly & p,factorization & f,bool odd_only,GIAC_CONTEXT){ + vecteur res(1,1),tmp; + polynome P; + poly12polynome(p,1,P,1); + P=P/lgcd(P); + f=sqff(P); + factorization::const_iterator it=f.begin(),itend=f.end(); + for (;it!=itend;++it){ + if (odd_only && it->mult%2==0) + continue; + polynome2poly1(it->fact,1,tmp); + res=operator_times(res,tmp,0); + } + return res; + } + + gen vas(const modpoly & p,GIAC_CONTEXT){ + vecteur v(p); + vecteur res1,res2; + bool has_zero=false; + if (is_zero(v.back())){ + has_zero=true; + v.pop_back(); + } + vecteur w(v); + change_scale(w,-1); + if (w.size()%2==0) + w=-w; + if (w==v){ + res1=VAS_positive_roots(v,1,0,0,1,contextptr); + res2=-res1; + reverse(res2.begin(),res2.end()); + iterateur it=res2.begin(),itend=res2.end(); + for (;it!=itend;++it){ + if (it->type==_VECT) + reverse(it->_VECTptr->begin(),it->_VECTptr->end()); + } + if (has_zero) + res2.push_back(0); + res1=mergevecteur(res2,res1); + } + else { +#ifdef HAVE_LIBPTHREAD + int nthreads=threads_allowed?threads:1; + if (nthreads>1 && p.size()>64){ + pthread_t tab0; + thread_vas_t tmp0={&v,&res1,1,0,0,1,contextptr}; + for (int i=0;ia0 + // res+epssize()==2){ + for (;it!=itend;++it){ + if (is_strictly_positive(-it->fact(interval._VECTptr->front())*it->fact(interval._VECTptr->back()),contextptr)) + return it->mult; + } + for (it=f.begin();it!=itend;++it){ + if (is_positive(-it->fact(interval._VECTptr->front())*it->fact(interval._VECTptr->back()),contextptr)) + return it->mult; + } + } + else { + for (;it!=itend;++it){ + if (is_zero(it->fact(interval))) + return it->mult; + } + } + return 0; + } + + static void add_vasres(vecteur & vasres,const gen & a,const gen & a0,const gen & b0,int mult,bool with_mult,GIAC_CONTEXT){ + if (a0==b0 || (is_greater(a,a0,contextptr) && is_greater(b0,a,contextptr)) ) + vasres.push_back(with_mult?gen(makevecteur(a,mult)):a); + } + + // isolate and find real roots of P at precision eps between a and b + // returns a list of intervals or of rationals + bool vas(const modpoly & P,const gen & a0,const gen &b0,double eps,vecteur & vasres,bool with_mult,GIAC_CONTEXT){ + if (eps<=0) + eps=1e-12; + if (P.size()<=3){ + if (P.size()<2) + return true; + gen a(P[0]),b(P[1]); + if (P.size()==2){ + a=-b/a; + add_vasres(vasres,a,a0,b0,1,with_mult,contextptr); + return true; + } + gen c(P[2]); + gen delta=b*b-4*a*c; + if (is_zero(delta)){ + a=-b/a/2; + add_vasres(vasres,a,a0,b0,2,with_mult,contextptr); + return true; + } + if (is_positive(delta,contextptr)){ + delta=sqrt(delta,contextptr)/a/2; + c=-b/a/2; + add_vasres(vasres,c-delta,a0,b0,1,with_mult,contextptr); + add_vasres(vasres,c+delta,a0,b0,1,with_mult,contextptr); + } + return true; + } + gen a(a0),b(b0); + if (a==b){ + a=minus_inf; + b=plus_inf; + } + // check and convert coeffs of P + modpoly p(P); + iterateur it=p.begin(),itend=p.end(); + for (;it!=itend;++it){ + *it=exact(*it,contextptr); + } + gen tmp; + lcmdeno(p,tmp,contextptr); + for (it=p.begin();it!=itend;++it){ + if (!is_integer(*it)) + return false; + } + p=divvecteur(p,lgcd(p)); + factorization f; + p=remove_multiplicities(p,f,false,contextptr); + tmp=vas(p,contextptr); + if (tmp.type!=_VECT) + return false; + vecteur v=*tmp._VECTptr; + // now improve precision by bisection + it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (it->type!=_VECT){ + if (is_greater(*it,a,contextptr) && is_greater(b,*it,contextptr)){ + if (with_mult){ + int n=multiplicity(f,*it,contextptr); + vasres.push_back(makevecteur(*it,n)); + } + else + vasres.push_back(*it); + } + continue; + } + if (it->_VECTptr->size()!=2) + return false; + gen A=it->_VECTptr->front(),B=it->_VECTptr->back(); + if (is_strictly_greater(a,B,contextptr) || is_strictly_greater(A,b,contextptr)) + continue; + gen interval=bisection(p,max(A,a,contextptr),min(B,b,contextptr),eps,contextptr); + if (is_undef(interval)) + continue; + if (interval.type==_VECT) + interval.subtype=_INTERVAL__VECT; + if (with_mult) + vasres.push_back(makevecteur(interval,multiplicity(f,interval,contextptr))); + else + vasres.push_back( (interval.type==_VECT && interval._VECTptr->size()==2)?evalf((interval._VECTptr->front()+interval._VECTptr->back())/2,1,contextptr):interval); + } + return true; + } + + /* +********************************* +numerical root localization +********************************* +*/ + + double cluster_step=1e-4; // if step>cluster_step, no cluster analysis, export GIAC_STEP=1e-3 + double cluster_dp=0.2; // if step*sum_{j!=i}(inv(approx_root[i]-approx_root[j])>cluster_dp, then do cluster analysis, export GIAC_DP=.1 + //int debug_infolevel=0; // export GIAC_DEBUG=1 or 2 + double MINREAL=-1e307; + +// single precision +#if defined __x86_64__ || defined __i386__ // || defined EMCC +#define LDBL80 // 80 bit long double + typedef long double longdouble; +#else + typedef double longdouble; +#endif + +typedef complex fdbl; +//typedef complex fdbl; + +inline double absdbl(const fdbl & x){ + return abs(x); +} +inline fdbl re(const fdbl & x){ + return fdbl(x.real(),0); +} +inline fdbl conj(const fdbl & x){ + return fdbl(x.real(),x.imag()); +} +inline double redbl(const fdbl & x){ + return x.real(); +} +inline double imdbl(const fdbl & x){ + return x.imag(); +} +inline bool is_exactly_zero(const fdbl & x){ + return x.real()==0 && x.imag()==0; +} +fdbl inv(const fdbl z){ + return fdbl(1.0)/z; +} + +bool fdbl_less(const fdbl & x,const fdbl & y){ + if (x.real()!=y.real()) + return x.real() vfdbl; +#ifdef LDBL80 +ostream & operator << (ostream & os,const vfdbl & P){ + os << "["; + for (int i=0;iclear(); + if (P.empty()) + return 0.0; + size_t s=P.size(); + if (Q) + Q->reserve(s-1); + fdbl r=0; + if (Q){ + for (size_t i=0;;){ + r=r*x+P[i]; + ++i; + if (i==s) + break; + Q->push_back(r); + } + } + else { + for (size_t i=0;iD){ + d=0; + return P0; // no shift, it would increase the l1 norm + } + R.push_back(Pz); + P.swap(Q); + } + reverse(R.begin(),R.end()); + return R; +} + +fdbl sum(const vfdbl & P){ + fdbl r(0.0); + for (size_t i=0;i & x,const vector & y,double & a,double &b,double & r){ + size_t n=x.size(); + if (n!=y.size()) + return false; + double X=0,Y=0,XY=0,X2=0,Y2=0; + for (size_t i=0;i x,y; + for (int i=0;i<=n;++i){ + double a=absdbl(P[i]); + if (a==0) + continue; + if (isinf(a)) + return 1; + x.push_back(n-i); + y.push_back(std::log(a)); + } + if (x.empty()) + return 1; + double a,b,r; + linreg(x,y,a,b,r); + return std::exp(-a); +} + +void rescale(vfdbl & P, fdbl l){ + if (l==fdbl(1)) return; + fdbl ll=l; + for (int i=P.size()-2;i>=0;--i){ + P[i] = ll*P[i]; + ll = ll*l; + } + fdbl c=P[0]; + for (size_t i=0;idy){ + double z=dy/dx; + return dx*std::sqrt(1+z*z); + } + else { + double z=dx/dy; + return dy*std::sqrt(1+z*z); + } +} + +bool graham_sort_function(const int_2double & a,const int_2double & b){ + if (a.theta==b.theta) + return b.norm>a.norm; + return b.theta>a.theta; +} + +double cross_prod(const vfdbl & v,int a,int b,int c){ + fdbl ab=v[b]-v[a],ac=v[c]-v[a]; + double A=redbl(ab),B=imdbl(ab),C=redbl(ac),D=imdbl(ac); + return A*D-B*C; +} + +vector convexhull(const vfdbl & v){ + int s=v.size(),imin=0; + if (s==1) + return vector(1,0); + // find origin + double ymin=imdbl(v[0]),ycur,xmin=redbl(v[0]),xcur; + for (int i=1;iycur || (ymin==ycur && xmin>xcur) ){ + imin=i; ymin=ycur; xmin=xcur; + } + } + vector ls; + for (int j=0;j res; res.push_back(imin); res.push_back(ls[0].i); + int ress=2; + for (int j=1;j0){ + res.push_back(icur); + ++ress; + } + else { + while (ress>2 && o<0){ + res.pop_back(); + ress--; + o=cross_prod(v,res[ress-2],res[ress-1],icur); + } + res.push_back(icur); + ++ress; + } + } + } + return res; +} + +double init_R(const vfdbl & P,vfdbl & R){ + R.clear(); + int n=P.size()-1; + if (n && is_exactly_zero(P[n])){ + vfdbl P1(P); + P1.pop_back(); + double res=init_R(P1,R); + R.insert(R.begin(),0); + return res; + } + vfdbl l; + vector lpos; + double M=0; + for (int i=0;i<=n;++i){ + longdouble ai=abs(P[n-i]); + if (ai==0) + continue; + l.push_back(fdbl(double(i),std::log(ai))); + lpos.push_back(i); + } + vector pos=convexhull(l); + // find real positions (since coeffs==0 were removed) + for (int i=0;ipos[i+1]){ + pos.erase(pos.begin(),pos.begin()+i); + break; + } + } + // now pos starts with highest value in x + for (int i=0;i+1M) + M=uk; + double sigma=0.7; + for (int j=0;j1 this may overflow +void horner2(const vfdbl & P,fdbl x,fdbl & r,fdbl & r1){ + r=r1=0; + if (P.empty()) + return ; + size_t s=P.size()-1; + for (size_t i=0;i5 && abs(1-R/oldR)> z; + if (i.eof()) + break; + P.push_back(z); + } + return true; +} + +vfdbl p_coeff(const vfdbl & R){ + vfdbl P; + P.reserve(R.size()+1); + P.push_back(fdbl(1)); + for (size_t i=0;i=1;--j){ + P[j] -= z*P[j-1]; + } + } + return P; +} + +// max distance between 2 elements of R +double ecart(const vfdbl & R){ + int n=R.size(); + double d=1e307; + for (int i=0;iclear(); + if (P.empty()) + return 0.0; + size_t s=P.size(); + if (Q) + Q->reserve(s-1); + dbl r=0; + if (Q){ + for (size_t i=0;;){ + r=r*x+P[i]; + ++i; + if (i==s) + break; + Q->push_back(r); + } + } + else { + for (size_t i=0;iD){ + d=0; + return P0; + } + vdbl res=taylor(P0,d); + for (int i=0;iD){ + d=0; + return P0; // no shift, it would increase the linf norm of the polynomial + } + } + return res; +#endif + vdbl P(P0),Q,R; + int n=P.size(); + for (int i=0;iD){ + d=0; + return P0; // no shift, it would increase the linf norm of the polynomial + } + R.push_back(Pz); + P.swap(Q); + } + reverse(R.begin(),R.end()); + return R; +} + +dbl sum(const vdbl & P){ + dbl r(0.0); + for (size_t i=0;i x,y; + for (int i=0;i<=n;++i){ + double a=logabsdbl(P[i]); + if (a==MINREAL) + continue; + x.push_back(n-i); + y.push_back(a); + } + if (x.empty()) + return 1; + double a,b,r; + linreg(x,y,a,b,r); + return std::exp(-a); +} + +void rescale(vdbl & P, dbl l){ + if (l==dbl(1)) return; + dbl ll=l; + for (int i=P.size()-2;i>=0;--i){ + P[i] = ll*P[i]; + ll = ll*l; + } + dbl c=P[0]; + for (size_t i=0;i1 this may overflow +void horner2(const vdbl & P,dbl x,dbl & r,dbl & r1){ + r=r1=0; + if (P.empty()) + return ; + size_t s=P.size()-1; + for (size_t i=0;isize) + size=rr0; + if (Pi.type==_REAL){ + mpfr_t & inf=Pi._REALptr->inf; + if (mpfr_zero_p(inf)) + return ; + mpfr_get_d_2exp(&rr1,inf,MPFR_RNDN); + if (rr1>rr0){ + if (rr1>size) + size=rr1; + delta=rr1-rr0; + rr0=rr1; + } + mpfr_add(rr,rr,Pi._REALptr->inf,MPFR_RNDN); + } + else if (Pi.type==_CPLX){ + mpfr_t & rinf=Pi._CPLXptr->_REALptr->inf; + mpfr_get_d_2exp(&rr1,rinf,MPFR_RNDN); + if (rr1>rr0){ + if (rr1>size) + size=rr1; + delta=rr1-rr0; + rr0=rr1; + } + mpfr_add(rr,rr,rinf,MPFR_RNDN); + mpfr_add(ri,ri,(Pi._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + } + else if (Pi.type==_INT_){ + mpfr_add_si(rr,rr,Pi.val,MPFR_RNDN); + return ; + } + else exit(1); + mpfr_get_d_2exp(&rr1,rr,MPFR_RNDN); + if (delta>nbits) + delta=nbits; + if (loss>delta) + loss -= delta; + else + loss = 0; + if (rr1inf,MPFR_RNDN); + //if (!mpfr_zero_p(ri)) + mpfr_mul(ri,ri,x._REALptr->inf,MPFR_RNDN); + return; + } + if (x.type==_CPLX){ +#if 0 + mpfr_fmms(tmp1,rr,x._CPLXptr->_REALptr->inf,ri,(x._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + mpfr_fmma(ri,rr,(x._CPLXptr+1)->_REALptr->inf,ri,x._CPLXptr->_REALptr->inf,MPFR_RNDN); + mpfr_swap(tmp1,rr); + return; +#endif +#if 0 + // (rr+i*ri)*(xr+i*xi)=rr*xr-ri*xi+i*(rr*xi+ri*xr) + mpfr_mul(tmp1,rr,x._CPLXptr->_REALptr->inf,MPFR_RNDN); + mpfr_mul(tmp2,ri,(x._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + // imag part = (rr+ri)*(xr+xi)-(rr*xr+ri*xi) + mpfr_add(rr,rr,ri,MPFR_RNDN); + mpfr_add(ri,x._CPLXptr->_REALptr->inf,(x._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + mpfr_mul(tmp,rr,ri,MPFR_RNDN); + mpfr_sub(tmp,tmp,tmp1,MPFR_RNDN); + mpfr_sub(ri,tmp,tmp2,MPFR_RNDN); + mpfr_sub(rr,tmp1,tmp2,MPFR_RNDN); + return; +#endif + mpfr_mul(tmp1,rr,x._CPLXptr->_REALptr->inf,MPFR_RNDN); + mpfr_mul(tmp2,ri,(x._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + mpfr_sub(tmp,tmp1,tmp2,MPFR_RNDN); + mpfr_mul(tmp1,rr,(x._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + mpfr_mul(tmp2,ri,x._CPLXptr->_REALptr->inf,MPFR_RNDN); + mpfr_swap(tmp,rr); + mpfr_add(ri,tmp1,tmp2,MPFR_RNDN); + return; + } + if (x.type==_INT_){ + mpfr_mul_si(rr,rr,x.val,MPFR_RNDN); + //if (!mpfr_zero_p(ri)) + mpfr_mul_si(ri,ri,x.val,MPFR_RNDN); + return; + } + exit(1); +} + +void mult(mpfr_t & rr,mpfr_t & ri,const mpfr_t & xr,const mpfr_t & xi,mpfr_t & tmp,mpfr_t & tmp1, mpfr_t & tmp2){ + if (mpfr_zero_p(xi)){ + mpfr_mul(rr,rr,xr,MPFR_RNDN); + mpfr_mul(ri,ri,xr,MPFR_RNDN); + return; + } + mpfr_mul(tmp1,rr,xr,MPFR_RNDN); + mpfr_mul(tmp2,ri,xi,MPFR_RNDN); + mpfr_sub(tmp,tmp1,tmp2,MPFR_RNDN); + mpfr_mul(tmp1,rr,xi,MPFR_RNDN); + mpfr_mul(tmp2,ri,xr,MPFR_RNDN); + mpfr_swap(tmp,rr); + mpfr_add(ri,tmp1,tmp2,MPFR_RNDN); +} + +// find r=P(x) and r1=diff(P)(x) +// returns largest number of bits of mantissa in intermediate computations +long horner2_mpfr(const vdbl & P,const dbl & x,dbl & r,dbl & r1,int nbits,long & size,bool pdiff){ + if (P.empty()) + return 0; + long loss=0; + size=-RAND_MAX; + size_t s=P.size()-1; + mpfr_t rr,ri,r1r,r1i,tmp,tmp1,tmp2; + mpfr_init2(rr,nbits); mpfr_set_si(rr,0,MPFR_RNDN); + mpfr_init2(ri,nbits); mpfr_set_si(ri,0,MPFR_RNDN); + mpfr_init2(r1r,nbits); mpfr_set_si(r1r,0,MPFR_RNDN); + mpfr_init2(r1i,nbits); mpfr_set_si(r1i,0,MPFR_RNDN); + mpfr_init2(tmp,nbits); + mpfr_init2(tmp1,nbits); + mpfr_init2(tmp2,nbits); + for (size_t i=0;iinf,MPFR_RNDN); +#else + z=mpf_get_d(g._REALptr->inf); +#endif + return true; + } +#endif + if (g.type==_FRAC){ + longdouble n,d; + if (convert(g._FRACptr->num,n) && convert(g._FRACptr->den,d)){ + z=n/d; + return true; + } + return false; + } + if (g.type!=_ZINT) + return false; + int s=mpz_cmp_si(*g._ZINTptr,0); + int l=mpz_sizeinbase(*g._ZINTptr,2); + if (l>=(1<<15)) + return false; + mpz_t zz; mpz_init(zz); + if (l>64){ + // we have 64 bits of mantissa +#if defined USE_GMP_REPLACEMENTS || defined BF2GMP_H + mpz_tdiv_q_2exp(zz,*g._ZINTptr,l-64); +#else + mpz_div_2exp(zz,*g._ZINTptr,l-64); +#endif + } + else + mpz_set(zz,*g._ZINTptr); + ulonglong u; + u=mpz_get_ui(zz); + mpz_clear(zz); + z=u; + if (l>64) + z=z*std::pow((longdouble) 2,l-64); + if (s<0) + z=-z; + return true; +} + +bool convert(const vdbl & P,vfdbl & fP,GIAC_CONTEXT){ + int s=P.size(); + fP.clear(); fP.reserve(s); + for (int i=0;i1000) + return false; + if (imag.type==_ZINT && mpz_sizeinbase(*imag._ZINTptr,2)>1000) + return false; + fP.push_back(fdbl(evalf_double(real,1,contextptr)._DOUBLE_val,evalf_double(imag,1,contextptr)._DOUBLE_val)); +#endif + } + return true; +} + +void Convert(const vfdbl & fP,vdbl & P){ + int s=fP.size(); + P.clear(); P.reserve(s); + for (int i=0;iinf,fP[i].real(),MPFR_RNDN); + mpfr_set_ld(im._REALptr->inf,fP[i].imag(),MPFR_RNDN); + P.push_back(dbl(re,im)); +#else + P.push_back(dbl(double(fP[i].real()),double(fP[i].imag()))); +#endif + } +} + +double l1norm(const vdbl & v){ + double r=0; + for (int i=0;i5 && abs(1-R/oldR) convexhull(const vdbl & v){ + int s=v.size(),imin=0; + if (s==1) + return vector(1,0); + // find origin + double ymin=imdbl(v[0]),ycur,xmin=redbl(v[0]),xcur; + for (int i=1;iycur || (ymin==ycur && xmin>xcur) ){ + imin=i; ymin=ycur; xmin=xcur; + } + } + vector ls; + for (int j=0;j res; res.push_back(imin); res.push_back(ls[0].i); + int ress=2; + for (int j=1;j0){ + res.push_back(icur); + ++ress; + } + else { + while (ress>2 && o<0){ + res.pop_back(); + ress--; + o=cross_prod(v,res[ress-2],res[ress-1],icur); + } + res.push_back(icur); + ++ress; + } + } + } + return res; +} + +void init_R(const vdbl & P,vdbl & R){ + R.clear(); + int n=P.size()-1; + if (n && is_exactly_zero(P[n])){ + vdbl P1(P); + P1.pop_back(); + init_R(P1,R); + R.insert(R.begin(),0); + return; + } + vdbl l; + vector lpos; + for (int i=0;i<=n;++i){ + double ai=logabsdbl(P[n-i]); + if (ai==MINREAL) + continue; + l.push_back(dbl(double(i),ai)); + lpos.push_back(i); + } + vector pos=convexhull(l); + // find real positions (since coeffs==0 were removed) + for (int i=0;ipos[i+1]){ + pos.erase(pos.begin(),pos.begin()+i); + break; + } + } + // now pos starts with highest value in x + for (int i=0;i+1 dkuk; + for (int i=1;i_REALptr->inf,MPFR_RNDN); + mpfr_sub(ri,ri,(Pi._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + } + else if (Pi.type==_REAL) + mpfr_sub(rr,rr,Pi._REALptr->inf,MPFR_RNDN); + else if (Pi.type==_INT_) + mpfr_sub_si(rr,rr,Pi.val,MPFR_RNDN); + else exit(1); +} + +// product of R[i]-R[j] for j!=i +bool product(mpfr_t & rr,mpfr_t & ri,const vdbl & R,int i,mpfr_t & tmp,mpfr_t & tmp1,mpfr_t & tmp2,mpfr_t & tmp3,mpfr_t & tmp4){ + mpfr_set_si(rr,1,MPFR_RNDN); + mpfr_set_si(ri,0,MPFR_RNDN); + for (int j=0;jinf,MPFR_RNDN); + mpfr_set_si(tmp4,0,MPFR_RNDN); + } + else if (R[i].type==_CPLX){ + mpfr_set(tmp3,R[i]._CPLXptr->_REALptr->inf,MPFR_RNDN); + mpfr_set(tmp4,(R[i]._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + } + else return false; + sub(tmp3,tmp4,R[j]); + mult(rr,ri,tmp3,tmp4,tmp,tmp1,tmp2); + } + return true; +} + +bool product(gen & p,const vdbl & R,int i,int nbits){ + mpfr_t rr,ri,tmp,tmp1,tmp2,tmp3,tmp4; + mpfr_init2(rr,nbits); + mpfr_init2(ri,nbits); + mpfr_init2(tmp,nbits); + mpfr_init2(tmp1,nbits); + mpfr_init2(tmp2,nbits); + mpfr_init2(tmp3,nbits); + mpfr_init2(tmp4,nbits); + bool b=product(rr,ri,R,i,tmp,tmp1,tmp2,tmp3,tmp4); + p=gen(real_object(rr),real_object(ri)); + mpfr_clear(rr); + mpfr_clear(ri); + mpfr_clear(tmp); + mpfr_clear(tmp1); + mpfr_clear(tmp2); + mpfr_clear(tmp3); + mpfr_clear(tmp4); + return b; +} + +void inv(mpfr_t & r,mpfr_t & i,mpfr_t & tmp,mpfr_t & tmp1, mpfr_t & tmp2){ + if (mpfr_zero_p(i)){ + mpfr_set_si(tmp,1,MPFR_RNDN); + mpfr_div(r,tmp,r,MPFR_RNDN); + } + else { // gen dbg; dbg=gen(real_object(r),real_object(i)); + mpfr_sqr(tmp1,r,MPFR_RNDN); + mpfr_sqr(tmp2,i,MPFR_RNDN); //dbg=gen(real_object(tmp1),real_object(tmp2)); + mpfr_add(tmp,tmp1,tmp2,MPFR_RNDN); + //dbg=gen(real_object(tmp),0); +#if 0 + mpfr_ui_div(tmp1,1,tmp,MPFR_RNDN); + mpfr_mul(r,r,tmp1,MPFR_RNDN); + mpfr_neg(tmp1,tmp1,MPFR_RNDN); + mpfr_mul(i,i,tmp1,MPFR_RNDN); +#else + mpfr_div(r,r,tmp,MPFR_RNDN); + // dbg=gen(real_object(r),0); + mpfr_neg(tmp,tmp,MPFR_RNDN); + mpfr_div(i,i,tmp,MPFR_RNDN); +#endif + } +} + +bool mpfr_sum_inv_diff(const gen & z,const vdbl & R,int i,gen & p,int nbits,GIAC_CONTEXT){ + mpfr_t tmp,tmp1,tmp2,zr,zi,pr,pi; + mpfr_init2(pr,nbits); mpfr_set_si(pr,0,MPFR_RNDN); + mpfr_init2(pi,nbits); mpfr_set_si(pi,0,MPFR_RNDN); + mpfr_init2(zr,nbits); + mpfr_init2(zi,nbits); + mpfr_init2(tmp,nbits); + mpfr_init2(tmp1,nbits); + mpfr_init2(tmp2,nbits); + for (int j=0;jinf,MPFR_RNDN); + mpfr_set_si(zi,0,MPFR_RNDN); + } + else if (z.type==_CPLX){ + mpfr_set(zr,z._CPLXptr->_REALptr->inf,MPFR_RNDN); + mpfr_set(zi,(z._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + } + else if (z.type==_INT_){ + mpfr_set_si(zr,z.val,MPFR_RNDN); + mpfr_set_si(zi,0,MPFR_RNDN); + } + else exit(1); + sub(zr,zi,R[j]); + if (mpfr_zero_p(zr) && mpfr_zero_p(zi)){ + mpfr_clear(pr); + mpfr_clear(pi); + mpfr_clear(zr); + mpfr_clear(zi); + mpfr_clear(tmp); + mpfr_clear(tmp1); + mpfr_clear(tmp2); + if (debug_infolevel>1) + *logptr(contextptr) << "sum_inv_diff equal R index i=" << i << ", j=" << j << ", z=" << z << "\n"; + return false; + } + inv(zr,zi,tmp,tmp1,tmp2); + // p += inv(dz); + mpfr_add(pr,pr,zr,MPFR_RNDN); + mpfr_add(pi,pi,zi,MPFR_RNDN); + //p=gen(real_object(pr),real_object(pi)); // debug + } + p=gen(real_object(pr),real_object(pi)); + mpfr_clear(pr); + mpfr_clear(pi); + mpfr_clear(zr); + mpfr_clear(zi); + mpfr_clear(tmp); + mpfr_clear(tmp1); + mpfr_clear(tmp2); + return true; +} + +// sum(1/(z-bi)), -1+sum(a_i/(z-b_i)), -sum(a_i/(z-b_i)^2) +bool mpfr_node_sum(const vdbl & A,const vdbl & B,const gen & z,gen & A0,gen & A1,gen & A2,int nbits,GIAC_CONTEXT){ + mpfr_t tmp,tmp1,tmp2,tmp3,tmp4,zr,zi,a0r,a0i,a1r,a1i,a2r,a2i,a1rcorr,a1icorr; + mpfr_init2(zr,nbits); + mpfr_init2(zi,nbits); + mpfr_init2(a0r,nbits); mpfr_set_si(a0r,0,MPFR_RNDN); + mpfr_init2(a0i,nbits); mpfr_set_si(a0i,0,MPFR_RNDN); + mpfr_init2(a1r,nbits); mpfr_set_si(a1r,-1,MPFR_RNDN); + mpfr_init2(a1i,nbits); mpfr_set_si(a1i,0,MPFR_RNDN); + mpfr_init2(a1rcorr,nbits); mpfr_set_si(a1rcorr,0,MPFR_RNDN); + mpfr_init2(a1icorr,nbits); mpfr_set_si(a1icorr,0,MPFR_RNDN); + mpfr_init2(a2r,nbits); mpfr_set_si(a2r,0,MPFR_RNDN); + mpfr_init2(a2i,nbits); mpfr_set_si(a2i,0,MPFR_RNDN); + mpfr_init2(tmp,nbits); + mpfr_init2(tmp1,nbits); + mpfr_init2(tmp2,nbits); + mpfr_init2(tmp3,nbits); + mpfr_init2(tmp4,nbits); + for (int j=0;jinf,MPFR_RNDN); + mpfr_set_si(zi,0,MPFR_RNDN); + } + else if (z.type==_CPLX){ + mpfr_set(zr,z._CPLXptr->_REALptr->inf,MPFR_RNDN); + mpfr_set(zi,(z._CPLXptr+1)->_REALptr->inf,MPFR_RNDN); + } + else if (z.type==_INT_){ + mpfr_set_si(zr,z.val,MPFR_RNDN); + mpfr_set_si(zi,0,MPFR_RNDN); + } + else exit(1); + sub(zr,zi,B[j]); + if (mpfr_zero_p(zr) && mpfr_zero_p(zi)){ + mpfr_clear(a0r); + mpfr_clear(a0i); + mpfr_clear(a1r); + mpfr_clear(a1i); + mpfr_clear(a1rcorr); + mpfr_clear(a1icorr); + mpfr_clear(a2r); + mpfr_clear(a2i); + mpfr_clear(zr); + mpfr_clear(zi); + mpfr_clear(tmp); + mpfr_clear(tmp1); + mpfr_clear(tmp2); + mpfr_clear(tmp3); + mpfr_clear(tmp4); + if (debug_infolevel>1) + *logptr(contextptr) << "mpfr_node_sum equal B index j=" << j << ", z=" << z << "\n"; + return false; + } + inv(zr,zi,tmp,tmp1,tmp2); + mpfr_set(tmp3,zr,MPFR_RNDN); + mpfr_set(tmp4,zi,MPFR_RNDN); + // A0=sum(1/(z-zi) + // FIXME increase sum accuracy using + // s :=0; c :=0; + // loop: x=1/(z-zi), c += (x-((s+x)-s); s +=x; + // s += c + mpfr_add(a0r,a0r,zr,MPFR_RNDN); + mpfr_add(a0i,a0i,zi,MPFR_RNDN); + //A0=gen(real_object(a0r),real_object(a0i)); + mult(zr,zi,A[j],tmp,tmp1,tmp2); + // A1 precision correction, requires 8 more + or - in O(n) bits + // vs multiplications that are slower + // A1corr += (b-((A1+b)-A1)); + // prepare by keeping a copy of A1 + mpfr_set(tmp1,a1r,MPFR_RNDN); + mpfr_set(tmp2,a1i,MPFR_RNDN); + // A1 += b where b=a/(z-zi) is in zr,zi + mpfr_add(a1r,a1r,zr,MPFR_RNDN); + mpfr_add(a1i,a1i,zi,MPFR_RNDN); + // A1=gen(real_object(a1r),real_object(a1i)); +#if 1 + // precision correction: compute (A1+b)-A1 in tmp1/tmp2, + // A1+b was just computed in a1r/a1i + // tmp1/tmp2 contains a copy of A1 + mpfr_sub(tmp1,a1r,tmp1,MPFR_RNDN); + mpfr_sub(tmp2,a1i,tmp2,MPFR_RNDN); + // precision correction: compute b-((A1+b)-A1) in tmp1/tmp2 + mpfr_sub(tmp1,zr,tmp1,MPFR_RNDN); + mpfr_sub(tmp2,zi,tmp2,MPFR_RNDN); + // precision correction: add correction tmp1/tmp2 to A1corr + mpfr_add(a1rcorr,a1rcorr,tmp1,MPFR_RNDN); + mpfr_add(a1icorr,a1icorr,tmp2,MPFR_RNDN); +#endif + // A2=-sum(a/(z-zi)^2) + mult(zr,zi,tmp3,tmp4,tmp,tmp1,tmp2); + mpfr_sub(a2r,a2r,zr,MPFR_RNDN); + mpfr_sub(a2i,a2i,zi,MPFR_RNDN); + // A2=gen(real_object(a2r),real_object(a2i)); + } + A0=gen(real_object(a0r),real_object(a0i)); + mpfr_add(a1r,a1r,a1rcorr,MPFR_RNDN); + mpfr_add(a1i,a1i,a1icorr,MPFR_RNDN); + A1=gen(real_object(a1r),real_object(a1i)); + A2=gen(real_object(a2r),real_object(a2i)); + mpfr_clear(a0r); + mpfr_clear(a0i); + mpfr_clear(a1r); + mpfr_clear(a1i); + mpfr_clear(a1rcorr); + mpfr_clear(a1icorr); + mpfr_clear(a2r); + mpfr_clear(a2i); + mpfr_clear(zr); + mpfr_clear(zi); + mpfr_clear(tmp); + mpfr_clear(tmp1); + mpfr_clear(tmp2); + mpfr_clear(tmp3); + mpfr_clear(tmp4); + return true; +} +bool secular_mpfr(const vdbl & A,const vdbl & B,const dbl & x,dbl & d,int nbits,GIAC_CONTEXT){ + if (A.empty()) + return 0; + gen A0,A1,A2; + if (!mpfr_node_sum(A,B,x,A0,A1,A2,nbits,contextptr)) + return false; + d=A1/(A1*A0+A2); + return true; +} +#endif // MPFR + +// sum(1/(z-bi)), -1+sum(a_i/(z-b_i)), -sum(a_i/(z-b_i)^2) +bool singleprec_node_sum(const vfdbl & A,const vfdbl & B,const fdbl & z,fdbl & A0,fdbl & A1,fdbl & A2,GIAC_CONTEXT){ + A2=A0=fdbl(0.0); + A1=fdbl(-1.0); + fdbl A0corr=0,A1corr=0,A2corr=0; + // FIXME increase sum accuracy using + // s :=0; c :=0; + // loop: x=1/(z-zi), c += (x-((s+x)-s); s +=x; + // s += c + for (size_t i=0;i & zi_done,int afteriter,bool secular,GIAC_CONTEXT){ + int deg=P0.size()-1; + bool doing_cluster=cluster_start>0 || cluster_afterend1){ + fdbl gamma(inv(zi)); + horner2(Prev,gamma,d,d1); + if (!is_exactly_zero(d)){ + d=gamma*(fdbl(deg)-gamma*d1/d); + if (is_exactly_zero(d)){ + translate_shift(R,l,dr); + if (debug_infolevel) + *logptr(contextptr) << "Aberth_single precision |z|>1 trying to invert 0\n"; + return false; + } + d=inv(d); + } + } + else { + horner2(P,zi,d,d1); + if (is_exactly_zero(d1)){ + translate_shift(R,l,dr); + if (debug_infolevel) + *logptr(contextptr) << "Aberth_single precision |z|<=1 trying to invert 0\n"; + return false; + } + d=d/d1; + } + fdbl p(0); bool binv=true; + for (int j=0;j2) + *logptr(contextptr) << "cluster? i=" << i << ", delta=" << dd << ", cluster_step=" << cluster_step << ", p=" << pp << ", d*p=" << dd*pp << " " << cluster_dp << "\n"; + if (!ok + && k>8 + && !doing_cluster && dd<=cluster_step*abszi && dd*pp>=cluster_dp){ + // if (ok) continue; + // cluster of roots, find all roots in this cluster + int cend=i+1; + fdbl sumR=zi; + for (int k=cend;k1){ + int Nc=cend-i; + // cluster is from i to cend-1 included + fdbl z=sumR/fdbl(Nc); // center of gravity of cluster + vfdbl Pdiff; + --Nc; + for (int l=0;l<=deg-Nc;++l){ + fdbl h=P[l]; + for (int k=deg-l;k>deg-l-Nc;--k){ + h=((longdouble) k)*h; + } + Pdiff.push_back(h); + } + fdbl z1,z2; + horner2(Pdiff,z,z1,z2); + if (!is_exactly_zero(z2)){ + fdbl delta=z1/z2; + z=z-delta; + for (;0;){ // disabled + horner2(P,z,z1,z2); + if (!is_exactly_zero(z1)) + break; + z += fdbl(1-1e-17)*z; + } + } + // shift P and reverse (roots become inverse of roots) + vfdbl Pcluster(shift(P,z,false)),Rcluster(deg),initR(deg); + reverse(Pcluster.begin(),Pcluster.end()); + if (is_exactly_zero(Pcluster[0])){ + Pcluster[0]=z/pow(fdbl(2),64); + } + init_R(Pcluster,initR); + int count=deg-1; + for (int k=0;k=i && k old(zi_done); + if (debug_infolevel) + *logptr(contextptr) << "aberth single cluster=" << i << "," << cend << "\n"; + // recursive call of aberth + bool b=aberth_singleprec(Pcluster,N,eps,Rcluster,i,cend,zi_done, 2/* afteriter*/,false,contextptr); + for (int k=i;k1 && !zi_done[i]) + *logptr(contextptr) << "New root found " << zi-d << "\n"; +#endif + zi_done[i]=1; + } + delta += absdz; + newR[i]=zi-d; + R[i]=newR[i]; // comment to avoid immediate update + } + newR.swap(R); + int count=0; + for (int k=0;k0){ + *logptr(contextptr) << "Aberth single prec iter " << k << " found=" << count << " cluster_search_start=" << cluster_start << ".." << cluster_afterend << " delta=" << delta << " time " << clock()*1e-6 << "\n"; + if (debug_infolevel>2){ + *logptr(contextptr) << "Current approx roots " << R << "\n"; + } + } +#endif + if (doing_cluster){ + if (ok>=afteriter) + return true; + continue; + } + if (//count==deg + delta<=eps*(ok?deg:deg-count) || count==deg + ) + ++ok; + else + ok=0; + if (ok>=afteriter){ + translate_shift(R,l,dr); + sort(R.begin(),R.end(),fdbl_less); + return true; + } + } + if (debug_infolevel) + *logptr(contextptr) << "Aberth single precision: too many iterations " << N << " delta " << delta << "\n"; + return false; +} + + +// check that roots are isolated or have precision eps, set zi_done[i] to 2 or 0 +bool chk_isol(vdbl & z,bool realpoly,int isolate,const vdbl & rz,double eps,vector & zi_done,GIAC_CONTEXT){ + int deg=z.size(); + if (debug_infolevel && isolate) + *logptr(contextptr) << "Certifying roots begin " << CLOCK()*1e-6 << "\n"; + dbl big(1LL<<62); // take care of almost complete cancellation in - + for (int i=0;i & zi_done,bool clearall){ + if (clearall){ + for (int i=0;i(a._REALptr)) + return ptr->maybe_zero(); + } + return is_exactly_zero(a); +} +void add(mpfi_t & rr,mpfi_t & ri,const gen & Pi){ + if (Pi.type==_CPLX){ + mpfi_add(rr,rr,dynamic_cast(Pi._CPLXptr->_REALptr)->infsup); + mpfi_add(ri,ri,dynamic_cast((Pi._CPLXptr+1)->_REALptr)->infsup); + } + else if (Pi.type==_REAL) + mpfi_add(rr,rr,dynamic_cast(Pi._REALptr)->infsup); + else if (Pi.type==_INT_) + mpfi_add_si(rr,rr,Pi.val); + else exit(1); +} + +void mult(mpfi_t & rr,mpfi_t & ri,const gen & x,mpfi_t & tmp,mpfi_t & tmp1, mpfi_t & tmp2){ + if (x.type==_CPLX){ + mpfi_mul(tmp1,rr,dynamic_cast(x._CPLXptr->_REALptr)->infsup); + mpfi_mul(tmp2,ri,dynamic_cast((x._CPLXptr+1)->_REALptr)->infsup); + mpfi_sub(tmp,tmp1,tmp2); + mpfi_mul(tmp1,rr,dynamic_cast((x._CPLXptr+1)->_REALptr)->infsup); + mpfi_mul(tmp2,ri,dynamic_cast(x._CPLXptr->_REALptr)->infsup); + mpfi_swap(tmp,rr); + mpfi_add(ri,tmp1,tmp2); + } + else if (x.type==_REAL){ + mpfi_mul(rr,rr,dynamic_cast(x._REALptr)->infsup); + mpfi_mul(ri,ri,dynamic_cast(x._REALptr)->infsup); + } + else if (x.type==_INT_){ + mpfi_mul_si(rr,rr,x.val); + mpfi_mul_si(ri,ri,x.val); + } + else exit(1); +} + +// find r=P(x) and r1=diff(P)(x) +bool horner2_mpfi(const vdbl & P,dbl x,dbl & r,dbl & r1,int nbits,bool pdiff=true){ + if (P.empty()) + return false; + size_t s=P.size()-1; + mpfi_t rr,ri,r1r,r1i,tmp,tmp1,tmp2; + mpfi_init2(rr,nbits); mpfi_set_si(rr,0); + mpfi_init2(ri,nbits); mpfi_set_si(ri,0); + mpfi_init2(r1r,nbits); mpfi_set_si(r1r,0); + mpfi_init2(r1i,nbits); mpfi_set_si(r1i,0); + mpfi_init2(tmp,nbits); + mpfi_init2(tmp1,nbits); + mpfi_init2(tmp2,nbits); + for (size_t i=0;i & zi_done,bool certify_lastiter,int isolate,bool secular,GIAC_CONTEXT){ + int neps=std::ceil(-log2(eps)); + if (neps>nbits) + nbits=64*((neps+63)/64); + int afteriter=2; + int deg=P0.size()-1,prevcount=0; + bool doing_cluster=cluster_start>0 || cluster_afterend1e-14) + R[j]=evalf_double(R[j],1,contextptr); + } + return 2; + } + } + } + if (R.empty()) + init_R(P,R); + } + accurate_evalf(P,nbits); + clear_zi_done(zi_done,true); + vdbl P_cert; int nbitscert=nbits+64; + if (certify_lastiter){ +#if defined MPFI_CERT && defined HAVE_LIBMPFI && !defined NO_RTTI + P_cert=*convert_interval(P,nbitscert,contextptr)._VECTptr; +#else + P_cert=P; +#endif + } + accurate_evalf(R,nbits); + vdbl P2(P0); int nbitsP2=2*nbits+64; + accurate_evalf(P2,nbitsP2); + bool firstiterhorner=!secular; + if (secular){ + bool refresh_nodes=A.empty(); + if (!refresh_nodes){ + if (A[0].type==_CPLX && A[0]._CPLXptr->type==_REAL) + refresh_nodes=mpfr_get_prec(A[0]._CPLXptr->_REALptr->inf)inf)0) + *logptr(contextptr) << clock()*1e-6 << " Aberth bits=" << nbits << " iter="<< k << " "; + delta=0; isol=true; + long maxloss=0,minloss=0; + if (doing_cluster){ + int K=cluster_start; + for (;K=2 || + (!ok && zi_done[i]) + ){ + // if root is not isolated, do the last iteration + newR[i]=R[i]; + continue; + } + dbl zi=R[i]; + if (debug_infolevel>2) + *logptr(contextptr) << CLOCK()*1e-6 << " computing d\n"; + dbl d,d1; + long loss=0; + if (ok && certify_lastiter){ +#if defined MPFI_CERT && defined HAVE_LIBMPFI && !defined NO_RTTI + int loss2=RAND_MAX; + if (!isolate || secular) + loss2=horner2_mpfr(P2,accurate_evalf(zi,nbitsP2),d,d1,nbitsP2,size,true); + if (secular){ + B[i]=R[i]; + gen p; product(p,R,i,nbitsP2); + A[i]=-d/(p*P[0]); // update secular nodes for next iteration + } + if (!isolate && loss2>=nbitsP2-16){ + gen zicert=convert_interval(zi,nbitscert,contextptr),dd,dd1; + horner2_mpfi(P_cert,zicert,d,d1,nbitscert); + if (maybe_zero(d1)){ + if (debug_infolevel) + *logptr(contextptr) << "MPFI unable to certify radius, root " << i << zi << "\n"; + return -1; + } + } +#else + loss=horner2_mpfr(P_cert,accurate_evalf(zi,nbitscert),d,d1,nbitscert,size,true); + while (loss>nbitscert-16){ + nbitscert*=2; + P_cert=P0; + accurate_evalf(P_cert,nbitscert); + loss=horner2_mpfr(P_cert,accurate_evalf(zi,nbitscert),d,d1,nbitscert,size,true); + } + if (is_exactly_zero(d1)) + return -1; + if (secular){ + B[i]=R[i]; + gen p; product(p,R,i,nbitscert); + A[i]=-d/(p*P[0]); // update secular nodes for next iteration + } +#endif + } + else { + if (secular && !firstiterhorner && secular_mpfr(A,B,zi,d,nbits,contextptr)) + d1=1; + else + loss=horner2_mpfr(P,zi,d,d1,nbits,size,true); + if (is_exactly_zero(d1)) + return -1; + } + d=d/d1; + if (ok) + rayon[i]=deg*abs(d,contextptr); + if (ok && certify_lastiter && rayon[i].type==_REAL){ +#if defined MPFI_CERT && defined HAVE_LIBMPFI && !defined NO_RTTI + rayon[i]=_right(rayon[i],contextptr); + d=gen(_milieu(re(d,contextptr),contextptr),_milieu(im(d,contextptr),contextptr)); +#else + rayon[i]=accurate_evalf(rayon[i],nbits); +#endif + } + dbl p(0); + if (debug_infolevel>2) + *logptr(contextptr) << CLOCK()*1e-6 << " computing p\n"; + bool binv=mpfr_sum_inv_diff(zi,R,i,p,nbits,contextptr); + if (debug_infolevel>2) + *logptr(contextptr) << CLOCK()*1e-6 << " end computing p\n"; + if (!binv && doing_cluster){ + *logptr(contextptr) << "Root estimates collision \n"; return 0; } +#if 0 + dbl pc(0); sum_inv_diff(zi,R,i,pc); + if (p!=pc) + *logptr(contextptr) << "err\n"; +#endif + double dd=absdbl(d),pp=absdbl(p); + double abszi=absdbl(zi); + if (debug_infolevel>2) + *logptr(contextptr) << CLOCK()*1e-6 << " cluster? i=" << i << ", delta=" << dd << ", cluster_step=" << cluster_step << ", p=" << pp << ", d*p=" << dd*pp << " " << cluster_dp << "\n"; + if (!binv || + (!ok && k>N/2 && !doing_cluster && dd<=cluster_step*abszi && dd*pp>=cluster_dp)){ + isol=false; + // cluster of roots, find all roots in this cluster + int cend=i+1; + dbl sumR=zi; + for (int k=cend;k1){ + int nbits2=2*nbits,Nc=cend-i; + // cluster is from i to cend-1 included + dbl z=sumR/dbl(Nc); // center of gravity of cluster + // improve z with a Newton iteration on the derivative of order size of cluster -1 + vdbl Pdiff; + --Nc; + for (int l=0;l<=deg-Nc;++l){ + gen h=1; + for (int k=deg-l;k>deg-l-Nc;--k){ + h=k*h; + } + Pdiff.push_back(h*P[l]); + } + gen z1,z2; + horner2_mpfr(Pdiff,z,z1,z2,nbits,size,true); + if (!is_exactly_zero(z2)) + z=z-z1/z2; + // shift P and reverse (roots become inverse of roots) + vdbl Pcluster(P),Rcluster(deg),initR(deg),Acluster(deg),Bcluster(deg); + accurate_evalf(Pcluster,nbits2); + z=accurate_evalf(z,nbits2); + Pcluster=shift(Pcluster,z,false); + reverse(Pcluster.begin(),Pcluster.end()); + if (is_exactly_zero(Pcluster[0])){ + Pcluster[0]=z/pow(2,nbits2,contextptr); + } + init_R(Pcluster,initR); + // dbl D(dbl(cend-i)/d); + int count=deg-1; + for (int k=0;k=i && k old(zi_done); + // recursive call of aberth + if (debug_infolevel) + *logptr(contextptr) << "aberth mpfr cluster=" << i << "," << cend << "\n"; + int b=aberth_mpfr(Pcluster,false,nbits2,N,eps,Acluster,Bcluster,Rcluster,rayon,i,cend,zi_done,false,false,false,contextptr); + for (int k=i;k1) + *logptr(contextptr) << "New root found " << newR[i] << "\n"; + if (debug_infolevel) + *logptr(contextptr) << "[" << i << "] "; + } + zi_done[i]=1; + } + else { + if (lossloss) + minloss=loss; + } + } + newR.swap(R); + int count=0,skipped=0; + for (int k=0;k0) + ++count; + else if (zi_done[k]==-1) + ++skipped; + } + if (debug_infolevel>0){ + *logptr(contextptr) << " found=" << count << " skipped " << skipped << " delta=" << delta << " precision loss " << double(minloss)/nbits << " (" << minloss << "/" << nbits << "), cluster_search=" << cluster_start << ".." <2){ + vdbl RR(R); + accurate_evalf(RR,45); + *logptr(contextptr) << "Current approx roots " << RR << "\n"; + } + } + if (doing_cluster){ + if (ok) + return 1; + continue; + } + if ( + delta<=eps*(ok?deg:deg-count) || count==deg + ){ + if (debug_infolevel) + *logptr(contextptr) << CLOCK()*1e-6 << " Aberth all roots found " << delta << "\n"; + ++ok; + } + // else ok=0; + if (ok==afteriter){ + // rescale and translate + for (size_t j=0;jnbits && count==prevcount) + return -1; + prevcount=count; + } + if (debug_infolevel) + *logptr(contextptr) << "Aberth mpfr: too many iterations " << N << " delta " << delta << "\n"; + return -1; +} +#endif + +dbl round(const dbl & z,const gen & pow2,int nbits){ + dbl res(z); + round2(res,nbits); + return res; + gen n,d; + fxnd(z,n,d); + return iquo(n*pow2,d)/pow2; +} + +int aberth_z(const vdbl & P0,int nbits,int N,double eps,vdbl & R,int cluster_start,int cluster_afterend,vector & zi_done,GIAC_CONTEXT){ + int deg=P0.size()-1; + bool doing_cluster=cluster_start>0 || cluster_afterend zi_done(deg,false); + double eps2=1e-4; + bool ok; + if (1){ // secular algorithm + aberth_singleprec(fP,N,eps2,fR,0,deg,zi_done,1,false,contextptr); + ok=aberth_singleprec(fP,N,eps2/16,fR,0,deg,zi_done,4,true /* secular*/ ,contextptr); + } + else + ok=aberth_singleprec(fP,2*N,eps2,fR,0,deg,zi_done,4,false,contextptr); + Convert(fR,R); +#if 1 // exact computations are way too slow + for (size_t j=0;j=2 || (!ok && zi_done[i])){ + // do the last iteration if root is not already isolated + newR[i]=R[i]; + continue; + } + dbl & zi=R[i]; + dbl d,d1; + if (logabsdbl(zi)>0){ + dbl gamma(round(inv(zi),pow2,nbits)); + horner2(Prev,gamma,d,d1); + if (!is_exactly_zero(d)){ + d=gamma*(dbl(deg)-gamma*d1/d); + if (is_exactly_zero(d)) + return 0; + d=inv(d); + } + } + else { + horner2(P,zi,d,d1); + if (is_exactly_zero(d1)) + return 0; + d=d/d1; + } + d=round(d,pow2,nbits); + if (is_exactly_zero(d)){ + newR[i]=zi; + zi_done[i]=1; + continue; + } + dbl p(0); bool binv=true; + for (int j=0;j2) + *logptr(contextptr) << "cluster? i=" << i << ", delta=" << dd << ", cluster_step=" << cluster_step << ", p=" << pp << ", d*p=" << dd*pp << " " << cluster_dp << "\n"; + if (!binv || + (!ok && k>N/2 && !doing_cluster && dd<=cluster_step*abszi && dd*pp>=cluster_dp)){ + // cluster of roots, find all roots in this cluster + int cend=i+1; + dbl sumR=zi; + for (int k=cend;k1){ + // cluster is from i to cend-1 included + dbl z=sumR/dbl(cend-i); // center of gravity of cluster + // shift P and reverse (roots become inverse of roots) + vdbl Pcluster(shift(P,z,false)),Rcluster(deg),initR(deg);; + reverse(Pcluster.begin(),Pcluster.end()); + // dbl D(dbl(cend-i)/d); + int count=deg-1; + for (int k=0;k=i && k old(zi_done); + // recursive call of aberth + if (debug_infolevel) + *logptr(contextptr) << "aberth exact cluster=" << i << "," << cend << "\n"; + bool b=aberth_z(Pcluster,nbits,N,eps,Rcluster,i,cend,zi_done,contextptr); + for (int k=0;k1 && !zi_done[i]) + *logptr(contextptr) << "New root found " << newR[i] << "\n"; + zi_done[i]=1; + } + } + newR.swap(R); + int count=0; + for (int k=0;k0){ + *logptr(contextptr) << "Aberth exact bits="<< nbits << " iter="<< k << " found=" << count << " delta=" << delta << " cluster_search=" << cluster_start << ".." <2){ + vdbl RR(R); + accurate_evalf(RR,45); + *logptr(contextptr) << "Current approx roots " << RR << "\n"; + } + } + if (doing_cluster){ + if (ok) + return 1; + continue; + } + if (delta<=eps*(ok?deg:deg-count) || count==deg) + ++ok; + // else ok=0; + if (ok==2){ + // rescale and translate + for (size_t j=0;j zi_done(P.size()-1,0); + int bit2=0,N2=0,eps2=0; + double eps0=eps; + vdbl A,B; + while (bits<=giac::ABERTH_NBITSMAX){ + //zi_done=vector(deg,0); +#if defined HAVE_LIBMPFR && !defined BF2GMP_H + int b=do_exact?aberth_z(P,bits,Nmax,eps,R,0,deg,zi_done,contextptr):aberth_mpfr(P,realpoly,bits,Nmax,eps,A,B,R,rayon,0,P.size()-1,zi_done,true,isolate,true/* secular*/,contextptr); +#else + int b=aberth_z(P,bits,Nmax,eps,R,0,deg,zi_done,contextptr); +#endif + bool bisol=b==2; + if (!bisol && b!=-1) + bisol=chk_isol(R,realpoly,isolate,rayon,eps0,zi_done,contextptr); + if (b>0){ + // if isolate is true, chk_isol will set zi_done[i] to 2 (root i is isolated) or 0 + if (b==2 || bisol){ + for (size_t j=0;j1e-4) + eps=1e-8; + else if (eps>1e-40) + eps=eps*eps; + else if (eps<=1e-280) + return false; + else + eps=eps*1e-40; + *logptr(contextptr) << "Root isolation: setting epsilon to " << eps << "\n"; + if (eps2>bit2){ + ++bit2; + bits *=2; + clear_zi_done(zi_done,true); + } + continue; + } + } + ++bit2; + bits *= 2; + clear_zi_done(zi_done,false); + ++N2; Nmax*=1.2; + } + return false; +} + + bool read_poly(const string & s,vdbl & P,GIAC_CONTEXT){ +#ifndef NO_STDEXCEPT + try { +#endif + gen g(s,contextptr); + g=eval(g,1,contextptr); + if (g.type!=_IDNT){ + if (g.type==_SYMB) + g=_symb2poly(g,contextptr); + if (g.type==_VECT){ + P=*g._VECTptr; + return true; + } + } +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & e){ + } +#endif + P.clear(); + FILE * f=fopen(s.c_str(),"r"); + if (!f) + return false; + string S; + while (1){ + char ch=fgetc(f); + if (feof(f)) + break; + S += ch; + } + fclose(f); + gen g2(S,contextptr); + g2=eval(g2,1,contextptr); + if (g2.type==_SYMB) + g2=_symb2poly(g2,contextptr); + if (g2.type==_VECT){ + P=*g2._VECTptr; + } + return true; + } + +vdbl p_coeff(const vdbl & R){ + vdbl P; + P.reserve(R.size()+1); + P.push_back(dbl(1)); + for (size_t i=0;i=1;--j){ + P[j] -= z*P[j-1]; + } + } + return P; +} + +// max distance between 2 elements of R +double ecart(const vdbl & R){ + int n=R.size(); + double d=1e307; + for (int i=0;inum,den=R._FRACptr->den; + num.uncoerce(); den.uncoerce(); + mpq_set_num(rq,*num._ZINTptr); + mpq_set_den(rq,*den._ZINTptr); + return true; + } + return false; +} + + int mps_solve(const vdbl & P,vdbl & R,vdbl & rayon,double eps,int isolate,bool secular,GIAC_CONTEXT){ + int n=P.size()-1,nmps=53; R.clear(); rayon.clear(); + mps_context *s; + s = mps_context_new (); + mps_context_select_algorithm(s, secular?MPS_ALGORITHM_SECULAR_GA:MPS_ALGORITHM_STANDARD_MPSOLVE); + nmps=eps==0?giac::ABERTH_NBITSMAX:int(ceil(-log2(std::abs(eps))));; + if (isolate){ + mps_context_set_output_goal (s, MPS_OUTPUT_GOAL_ISOLATE); + *logptr(contextptr) << "MPS " << (secular?"secular":"Aberth") << " goal isolate, output bits=" << nmps << "\n"; + } + else { + mps_context_set_output_goal (s, MPS_OUTPUT_GOAL_APPROXIMATE); + *logptr(contextptr) << "MPS " << (secular?"secular":"Aberth") << " goal approximate, output bits=" << nmps << "\n"; + } + mps_context_set_output_prec (s, nmps); + //mps_context_set_input_prec(s,0); + int I; + /* + for (I=0;I<=n;++I){ + if (!is_cinteger(P[I])) + break; + } + */ + mps_monomial_poly *p=0; + if (0 && I<=n){ + string S=symb_horner(P,vx_var).print(contextptr); + p = MPS_MONOMIAL_POLY (mps_parse_inline_poly_from_string (s,S.c_str())); + } + else { + p = mps_monomial_poly_new (s, n); + mpq_t rq,iq; + mpq_init(rq); mpq_init(iq); + for (int i=0;i<=n;++i){ + dbl R,I; + reim( P[n-i],R,I,contextptr); + if (R.type==_DOUBLE_ || I.type==_DOUBLE_ || R.type==_REAL || I.type==_REAL){ + R=evalf_double(R,1,contextptr); + I=evalf_double(I,1,contextptr); + mps_monomial_poly_set_coefficient_d (s, p, i,R._DOUBLE_val,I._DOUBLE_val); + continue; + } + if (!gen2mpq(R,rq)) + return -1; + if (!gen2mpq(I,iq)) + return -1; + mps_monomial_poly_set_coefficient_q (s, p, i,rq,iq); + } + mpq_clear(rq); mpq_clear(iq); + /* + + mps_monomial_poly_set_coefficient_q (s, p, 0, m_one, zero); + mps_monomial_poly_set_coefficient_q (s, p, n, one, zero); + + for (int i=0;i<=n;++i){ + dbl R,I; + reim( evalf_double(P[n-i],1,contextptr),R,I,contextptr); + mps_monomial_poly_set_coefficient_d (s, p, i,R._DOUBLE_val, I._DOUBLE_val); + } + */ + } + /* Set the input polynomial */ + mps_context_set_input_poly (s, MPS_POLYNOMIAL (p)); + + /* Actually solve the polynomial */ + double t1=CLOCK()*1e-6; + mps_mpsolve (s); + double t2=CLOCK()*1e-6; + *logptr(contextptr) << "MPS solve time " << t2-t1 << "\n"; + + R.clear(); + rdpe_t * drad = rdpe_valloc (n); // disk radius + mpc_t * mroot = mpc_valloc (n); + mpc_vinit2 (mroot, n, nmps); + mps_context_get_roots_m (s, &mroot, &drad); + mpfr_t tmp; mpfr_init2(tmp,64); + for (int i=0;i. + */ +using namespace std; +#include +#include +#include "derive.h" +#include "usual.h" +#include "symbolic.h" +#include "unary.h" +#include "poly.h" +#include "sym2poly.h" // for equalposcomp +#include "tex.h" +#include "prog.h" +#include "intg.h" +#include "subst.h" +#include "plot.h" +#include "modpoly.h" +#include "moyal.h" +#include "alg_ext.h" +#include "giacintl.h" + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + gen eval_before_diff(const gen & expr,const gen & variable,GIAC_CONTEXT){ + identificateur tmp_x_id(" eval_before_diff_x"); + gen tmp_x(tmp_x_id); + gen res=subst(expr,variable,tmp_x,false,contextptr); // replace variable by a non affected identifier + gen save_vx_var=vx_var; + if (variable==vx_var) vx_var=tmp_x; + int m=calc_mode(contextptr); + calc_mode(0,contextptr); + res=eval(res,1,contextptr); // eval res (all identifiers except X will be replaced by their values) + res=eval(res,1,contextptr); // eval res (all identifiers except X will be replaced by their values) + calc_mode(m,contextptr); + vx_var=save_vx_var; + res=subst(res,tmp_x,variable,false,contextptr); + return res; + } + + bool depend(const gen & g,const identificateur & i){ + if (g.type==_IDNT) + return *g._IDNTptr==i; + if (g.type==_SYMB) + return depend(g._SYMBptr->feuille,i); + if (g.type!=_VECT) + return false; + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it){ + if (depend(*it,i)) + return true; + } + return false; + } + + static int count_noncst(const gen & g,const identificateur & i){ + if (g.type!=_VECT) + return depend(g,i)?1:0; + int res=0; + for (unsigned j=0;jsize();++j){ + if (depend((*g._VECTptr)[j],i)) + ++res; + } + return res; + } + + static gen derive_SYMB(const gen &g_orig,const identificateur & i,GIAC_CONTEXT){ + const symbolic & s = *g_orig._SYMBptr; + if (s.sommet==at_pnt){ + gen f=g_orig._SYMBptr->feuille; + if (f.type==_VECT && !f._VECTptr->empty()){ + vecteur v=*f._VECTptr; + v[0]=derive(v[0],i,contextptr); + f=gen(v,f.subtype); + return symbolic(at_pnt,f); + } + } + // if s does not depend on i return 0 + if (!depend(g_orig,i)) + return zero; + // rational operators are treated first for efficiency + if (s.sommet==at_plus){ + bool do_step=step_infolevel(contextptr)>1 && count_noncst(s.feuille,i)>1; + if (do_step) + gprintf(gettext("Derivative of %gen apply linearity: (u+v+...)'=u'+v'+..."),makevecteur(s),contextptr); + if (s.feuille.type!=_VECT) + return derive(s.feuille,i,contextptr); + vecteur::const_iterator iti=s.feuille._VECTptr->begin(),itend=s.feuille._VECTptr->end(); + int taille=int(itend-iti); + if (taille==2) + return derive(*iti,i,contextptr)+derive(*(iti+1),i,contextptr); + vecteur v; + v.reserve(taille); + gen e; + for (;iti!=itend;++iti){ + e=derive(*iti,i,contextptr); + if (is_undef(e)) + return e; + if (!is_zero(e)) + v.push_back(e); + } + if (v.size()==1) + return v.front(); + if (v.empty()) + return zero; + gen res=_plus(gen(v,_SEQ__VECT),contextptr); // symbolic(at_plus,v); + if (do_step) + gprintf(gettext("Hence derivative of %gen by linearity is %gen"),makevecteur(g_orig,res),contextptr); + return res; + } + if (s.sommet==at_prod){ + bool do_step=step_infolevel(contextptr)>1 && count_noncst(s.feuille,i)>1; + if (s.feuille.type==_VECT && s.feuille._VECTptr->size()==2 && s.feuille._VECTptr->back().is_symb_of_sommet(at_inv) && !is_constant_wrt(s.feuille._VECTptr->back()._SYMBptr->feuille,i,contextptr)){ + gen u=s.feuille._VECTptr->front(),v=s.feuille._VECTptr->back()._SYMBptr->feuille; + if (do_step) + gprintf(gettext("Derivative of %gen/%gen, a quotient: (u/v)'=(u'*v-u*v')/v^2"),makevecteur(u,v),contextptr); + return (derive(u,i,contextptr)*v-u*derive(v,i,contextptr))/pow(v,2,contextptr); + } + if (do_step) + gprintf(gettext("Derivative of %gen, apply product rule: (u*v*...)'=u'*v*...+u*v'*...+..."),makevecteur(s),contextptr); + if (s.feuille.type!=_VECT) + return derive(s.feuille,i,contextptr); + vecteur::const_iterator itbegin=s.feuille._VECTptr->begin(),itj,iti,itend=s.feuille._VECTptr->end(); + int taille=int(itend-itbegin); + // does not work because of is_linear_wrt e.g. for cos(3*pi/4) + // if (taille==2) return derive(*itbegin,i,contextptr)*(*(itbegin+1))+(*itbegin)*derive(*(itbegin+1),i,contextptr); + vecteur v,w; + v.reserve(taille); + w.reserve(taille); + gen e; + for (iti=itbegin;iti!=itend;++iti){ + w.clear(); + e=derive(*iti,i,contextptr); + if (is_undef(e)) + return e; + if (!is_zero(e)){ + for (itj=itbegin;itj!=iti;++itj) + w.push_back(*itj); + w.push_back(e); + ++itj; + for (;itj!=itend;++itj) + w.push_back(*itj); + v.push_back(_prod(w,contextptr)); + } + } + if (v.size()==1) + return v.front(); + if (v.empty()) + return zero; + gen res=symbolic(at_plus,gen(v,_SEQ__VECT)); + if (do_step) + gprintf(gettext("Hence derivative of %gen by product rule is %gen"),makevecteur(g_orig,res),contextptr); + return res; + } + if (s.sommet==at_neg) + return -derive(s.feuille,i,contextptr); + if (s.sommet==at_pow){ + if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=2) + return gensizeerr(contextptr); + gen base = s.feuille._VECTptr->front(),exponent=s.feuille._VECTptr->back(); + if (step_infolevel(contextptr)>1){ + if (is_constant_wrt(exponent,i,contextptr)) + gprintf(gettext("Derivative of a power: (%gen)'=(%gen)*(%gen)'*%gen"),makevecteur(symb_pow(base,exponent),exponent,base,symb_pow(base,exponent-1)),contextptr); + else + gprintf(gettext("Derivative of a power: (%gen)'=%gen*(%gen)'*ln(%gen)+(%gen)*(%gen)'*%gen"),makevecteur(symb_pow(base,exponent),symb_pow(base,exponent),exponent,base,exponent,base,symb_pow(base,exponent-1)),contextptr); + } + gen dbase=derive(base,i,contextptr),dexponent=derive(exponent,i,contextptr); + // diff(base^exponent)=diff(exp(exponent*ln(base))) + // =base^exponent*diff(exponent)*ln(base)+base^(exponent-1)*exponent*diff(base) + gen expm1=exponent+gen(-1); + if (is_zero(dexponent)) + return exponent*dbase*pow(base,expm1,contextptr); + // changed 2024/11/06 for later simplify, was + // return dexponent*ln(base,contextptr)*s+exponent*dbase*pow(base,expm1,contextptr); + return (dexponent*ln(base,contextptr)+exponent*dbase/base)*s; + } + if (s.sommet==at_inv){ + if (step_infolevel(contextptr)>1) + gprintf(gettext("Derivative of inv(u)=-u'/u^2 with u=%gen"),makevecteur(s.feuille),contextptr); + if (s.feuille.is_symb_of_sommet(at_pow)){ + gen & f = s.feuille._SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()==2) + return derive(symb_pow(f._VECTptr->front(),-f._VECTptr->back()),i,contextptr); + } + return rdiv(-derive(s.feuille,i,contextptr),pow(s.feuille,2),contextptr); + } + if (equalposcomp(inequality_tab,s.sommet)) + return 0; + if (s.sommet==at_fsolve && s.feuille.type==_VECT && s.feuille._VECTptr->size()>=2){ + vecteur v=*s.feuille._VECTptr; + if (v[1].is_symb_of_sommet(at_equal) && v[1]._SYMBptr->feuille.type==_VECT && !v[1]._SYMBptr->feuille._VECTptr->empty()) + v[1]=v[1]._SYMBptr->feuille._VECTptr->front(); + gen eq=remove_equal(v[0]),y=v[1],x=i; // fsolve(eq(x,y),y) -> y(x), dy/dx=-(deq/dx)/(deq/dy) + gen res=-derive(eq,x,contextptr)/derive(eq,y,contextptr); + res=subst(res,y,s,false,contextptr); + return res; + } + if (s.sommet==at_rootof){ + gen f=s.feuille; + if (f.type==_VECT && f._VECTptr->size()==2 && f._VECTptr->front().type==_VECT && f._VECTptr->back().type==_VECT){ + vecteur P=*f._VECTptr->front()._VECTptr; + vecteur Q=*f._VECTptr->back()._VECTptr; + // d/dx(P(y))=(dP/dx)(y) + (dP/dy) (dy/dx) + // =(dP/dx)(y) - (dP/dy) (dQ/dx)/(dQ/dy) + // where y dependency is in the list polynomial P/Q + gen Px=trim(*derive(P,i,contextptr)._VECTptr,0); + Px=symb_rootof(Px,Q,contextptr); + gen Qx=trim(*derive(Q,i,contextptr)._VECTptr,0); + Qx=symb_rootof(Qx,Q,contextptr); + gen Py=derivative(P); + Py=symb_rootof(Py,Q,contextptr); + gen Qy=derivative(Q); + Qy=symb_rootof(Qy,Q,contextptr); + gen res=Px-(Py*Qx)/Qy; + res=normal(res,contextptr); + return res; + } + return gensizeerr(gettext("Derivative of rootof currently not handled")); + } + if (step_infolevel(contextptr)>1 && s.feuille.type!=_VECT){ + if (s.feuille==i){ + int save_step=step_infolevel(contextptr); + step_infolevel(contextptr)=0; + gen der=derive_SYMB(g_orig,i,contextptr); + step_infolevel(contextptr)=save_step; + gprintf(gettext("Derivative of elementary function %gen is %gen"),makevecteur(g_orig,der),contextptr); + } + else + gprintf(gettext("Derivative of a composition: (%gen)'=(%gen)'*f'(%gen) where f=%gen"),makevecteur(g_orig,s.feuille,s.feuille,s.sommet),contextptr); + } + if (s.sommet==at_UTPT){ + if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=2) + return gensizeerr(contextptr); + gen & arg=s.feuille._VECTptr->back(); + return -derive(arg,i,contextptr)*_student(s.feuille,contextptr); + } + if (s.sommet==at_UTPC){ + if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=2) + return gensizeerr(contextptr); + gen & arg=s.feuille._VECTptr->back(); + return -derive(arg,i,contextptr)*_chisquare(s.feuille,contextptr); + } + if (s.sommet==at_UTPF){ + if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=3) + return gensizeerr(contextptr); + gen & arg=s.feuille._VECTptr->back(); + return -derive(arg,i,contextptr)*_snedecor(s.feuille,contextptr); + } + if (s.sommet==at_program){ + return gensizeerr(gettext("Expecting an expression, not a function")); + } + if (s.sommet==at_ln){ + if (s.feuille.is_symb_of_sommet(at_abs) ) + return rdiv(derive(s.feuille._SYMBptr->feuille,i,contextptr),s.feuille._SYMBptr->feuille,contextptr); + if (s.feuille.is_symb_of_sommet(at_inv)) + return -derive(symbolic(at_ln,s.feuille._SYMBptr->feuille),i,contextptr); + if (s.feuille.is_symb_of_sommet(at_prod)){ + gen res; + const gen &f=s.feuille._SYMBptr->feuille; + if (f.type==_VECT){ + const_iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end(); + for (;it!=itend;++it) + res=res+derive(symbolic(at_ln,*it),i,contextptr); + return res; + } + } + } + if (s.feuille.type==_VECT){ + vecteur v=*s.feuille._VECTptr; + int vs=int(v.size()); + if (vs>=3 && (s.sommet==at_ifte || s.sommet==at_when) ){ + for (int j=1;j=3 && s.sommet==at_Beta){ + gen v0=v[0],v1=v[1],v2=v[2]; + if (!is_zero(derive(v0,i,contextptr)) || !is_zero(derive(v1,i,contextptr)) ) + return gensizeerr("diff of incomplete beta with respect to non constant 1st or 2nd arg not implemented"); + // diff/v2 of int_0^v2 t^(v0-1)*(1-t)^(v1-1) dt + gen tmp=pow(v2,v0-1,contextptr)*pow(1-v2,v1-1,contextptr)*derive(v2,i,contextptr); + if (vs==4){ + gen v3=v[3]; + if (is_one(v3)) + return tmp/Beta(v0,v1,contextptr); + return gensizeerr(contextptr); + gen v3p=derive(v3,i,contextptr); + if (!is_zero(v3p)) + return tmp-pow(v3,v0-1,contextptr)*pow(1-v3,v1-1,contextptr)*v3p; + } + return tmp; + } + if (vs==4 && s.sommet==at_sum){ + gen v0=v[0],v1=v[1],v2=v[2],v3=v[3]; + if (!is_zero(derive(v1,i,contextptr)) || !is_zero(derive(v2,i,contextptr)) || ! is_zero(derive(v3,i,contextptr)) ) + return gensizeerr(gettext("diff of sum with boundaries or mute variable depending on differentiation variable")); + if (is_inf(v2) || is_inf(v3)) + *logptr(contextptr) << gettext("Warning, assuming derivative commutes with infinite sum") << '\n'; + return _sum(makesequence(derive(v0,i,contextptr),v1,v2,v3),contextptr); + } + if ( (vs==2 || (vs==3 && is_zero(v[2]))) && (s.sommet==at_upper_incomplete_gamma || s.sommet==at_lower_incomplete_gamma || s.sommet==at_Gamma)){ + gen v0=v[0],v1=v[1]; + if (!is_zero(derive(v0,i,contextptr))) + return gensizeerr(gettext("diff of incomplete gamma with respect to non constant 1st arg not implemented")); + // diff(int_v1^inf exp(-t)*t^(v0-1) dt) + gen tmp1=exp(-v1,contextptr)*pow(v1,v0-1,contextptr)*derive(v1,i,contextptr); + return (s.sommet==at_lower_incomplete_gamma)?tmp1:-tmp1; + } + if (vs==3 && (s.sommet==at_upper_incomplete_gamma || s.sommet==at_lower_incomplete_gamma || s.sommet==at_Gamma)){ + return derive(symbolic(s.sommet,makesequence(v[0],v[1]))/symbolic(at_Gamma,v[0]),i,contextptr); + } + } + // now look at other operators, first onearg operator + if (s.sommet.ptr()->D){ + if (s.feuille.type!=_VECT) + return derive(s.feuille,i,contextptr)*(*s.sommet.ptr()->D)(1)(s.feuille,contextptr); + // multiargs operators + int taille=int(s.feuille._VECTptr->size()); + vecteur v; + v.reserve(taille); + vecteur::const_iterator iti=s.feuille._VECTptr->begin(),itend=s.feuille._VECTptr->end(); + gen e; + for (int j=1;iti!=itend;++iti,++j){ + e=derive(*iti,i,contextptr); + if (is_undef(e)) + return e; + if (!is_zero(e)) + v.push_back(e*(*s.sommet.ptr()->D)(j)(s.feuille,contextptr)); + } + if (v.size()==1) + return v.front(); + if (v.empty()) + return zero; + return symbolic(at_plus,gen(v,_SEQ__VECT)); + } + // integrate + if (s.sommet==at_integrate || s.sommet==at_HPINT){ + if (s.feuille.type!=_VECT) + return s.feuille; + vecteur v=*s.feuille._VECTptr; + int nargs=int(v.size()); + if (nargs<=1) + return s.feuille; + if (nargs==2 && is_equal(v[1])){ + gen v1f=v[1]._SYMBptr->feuille; + if (v1f.type==_VECT && v1f._VECTptr->size()==2){ + gen v1f1=v1f._VECTptr->front(); + gen v1f2=v1f._VECTptr->back(); + v[1]=v1f1; + if (v1f2.is_symb_of_sommet(at_interval)){ + v.push_back(v1f2._SYMBptr->feuille._VECTptr->front()); + v.push_back(v1f2._SYMBptr->feuille._VECTptr->back()); + nargs=4; + } + } + } + gen res,newint; + if (v[1]==i) + res=v[0]; + else { + res=subst(v[0],v[1],i,false,contextptr); + newint=derive(v[0],i,contextptr); + if (nargs<4) + newint=integrate_gen(newint,v[1],contextptr); + } + if (nargs==2) + return res+newint; + if (nargs==3) + return derive(v[2],i,contextptr)*subst(res,i,v[2],false,contextptr); + if (nargs==4){ + gen a3=derive(v[3],i,contextptr); + gen b3=is_zero(a3)?zero:limit(res,i,v[3],-1,contextptr); + gen a2=derive(v[2],i,contextptr); + gen b2=is_zero(a2)?zero:limit(res,i,v[2],1,contextptr); + return a3*b3-a2*b2+_integrate(gen(makevecteur(newint,v[1],v[2],v[3]),_SEQ__VECT),contextptr); + } + return gensizeerr(contextptr); + } + if (s.sommet==at_of && s.feuille.type==_VECT && s.feuille._VECTptr->size()==2){ + // assuming we do not have an index in a list or matrix! + gen f=s.feuille._VECTptr->front(); + gen arg=s.feuille._VECTptr->back(); + gen darg=derive(arg,i,contextptr); + if (!is_one(darg)){ + if (darg.type==_VECT){ + gen res=0; + for (int i=0;isize());++i){ + gen fprime=symbolic(at_derive,makesequence(f,i)); + res += darg[i]*symbolic(at_of,makesequence(fprime,arg)); + } + return res; + } + // f(arg)'=arg'*f'(arg) + gen fprime=symbolic(at_derive,f); + return darg*symbolic(at_of,makesequence(fprime,arg)); + } + } + // multi derivative and multi-indice derivatives + if (s.sommet==at_derive){ + if (s.feuille.type!=_VECT) + return symbolic(at_derive,gen(makevecteur(s.feuille,vx_var,2),_SEQ__VECT)); + if (s.feuille._VECTptr->size()==2){ // derive(f,x) + gen othervar=(*s.feuille._VECTptr)[1]; + if (othervar.type!=_IDNT) return gensizeerr(gettext("derive.cc/derive_SYMB")); + if (*othervar._IDNTptr==i){ // _FUNCnd derivative + vecteur res(*s.feuille._VECTptr); + symbolic sprime(s); + res.push_back(2); + return symbolic(at_derive,gen(res,_SEQ__VECT)); + } + else { + vecteur var; + var.push_back(othervar); + var.push_back(i); + vecteur nderiv; + nderiv.push_back(1); + nderiv.push_back(1); + return symbolic(at_derive,gen(makevecteur((*s.feuille._VECTptr)[0],var,nderiv),_SEQ__VECT)); + } + } + else { // derive(f,x,n) + if (s.feuille._VECTptr->size()!=3) return gensizeerr(gettext("derive.cc/derive_SYMB")); + gen othervar=(*s.feuille._VECTptr)[1]; + if (othervar.type==_IDNT){ + if (*othervar._IDNTptr==i){ // n+1 derivative + vecteur vprime=(*s.feuille._VECTptr); + vprime[2] += 1; + return symbolic(s.sommet,gen(vprime,_SEQ__VECT)); + } + else { + vecteur var; + var.push_back(othervar); + var.push_back(i); + vecteur nderiv; + nderiv.push_back((*s.feuille._VECTptr)[2]); + nderiv.push_back(1); + return symbolic(at_derive,gen(makevecteur((*s.feuille._VECTptr)[0],var,nderiv),_SEQ__VECT)); + } + } // end if othervar.type==_IDNT + else { // othervar.type must be _VECT + if (othervar.type!=_VECT) return gensizeerr(gettext("derive.cc/derive_SYMB")); + gen nder((*s.feuille._VECTptr)[2]); + if (nder.type!=_VECT || + nder._VECTptr->size()!=othervar._VECTptr->size()) return gensizeerr(gettext("derive.cc/derive_SYMB")); + vecteur nderiv(*nder._VECTptr); + int pos=equalposcomp(*othervar._VECTptr,i); + if (pos){ + nderiv[pos-1]=nderiv[pos-1]+1; + } + else { + othervar._VECTptr->push_back(i); + nderiv.push_back(1); + } + return symbolic(at_derive,gen(makevecteur((*s.feuille._VECTptr)[0],othervar,nderiv),_SEQ__VECT)); + } + } + } + if (s.sommet==at_re || s.sommet==at_im || s.sommet==at_conj){ + return s.sommet(derive(s.feuille,i,contextptr),contextptr); + } + // no info about derivative + return symbolic(at_derive,gen(makevecteur(s,i),_SEQ__VECT)); + //i.dbgprint(); + //s.dbgprint(); + } + + static gen derive_VECT(const vecteur & v,const identificateur & i,GIAC_CONTEXT){ + vecteur w; + w.reserve(v.size()); + vecteur::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + gen tmp=derive(*it,i,contextptr); + if (is_undef(tmp)) + return tmp; + w.push_back(tmp); + } + return w; + } + + gen derive(const gen & e,const identificateur & i,GIAC_CONTEXT){ + if (is_undef(e) || is_inequation(e)) + return undef; + if (abs_calc_mode(contextptr)==38 && i.id_name[0]>='A' && i.id_name[0]<='Z'){ + identificateur tmp("xdiff"); + gen ee=subst(e,i,tmp,true,contextptr); + ee=eval(ee,1,contextptr); + ee=subst(ee,i,tmp,true,contextptr); + ee=derive(ee,tmp,contextptr); + ee=subst(ee,tmp,i,true,contextptr); + return ee; + } + switch (e.type){ + case _INT_: case _DOUBLE_: case _ZINT: case _CPLX: case _MOD: case _REAL: case _USER: case _FLOAT_: + return 0; + case _IDNT: + if (is_undef(e)) + return e; + if (*e._IDNTptr==i) + return 1; + else + return 0; + case _SYMB: + return derive_SYMB(e,i,contextptr); + case _VECT: { + gen res=derive_VECT(*e._VECTptr,i,contextptr); + if (res.type==_VECT) res.subtype=e.subtype; + return res; + } + case _FRAC: + return fraction(derive(e._FRACptr->num,i,contextptr)*e._FRACptr->den-(e._FRACptr->num)*derive(e._FRACptr->den,i,contextptr),pow(e._FRACptr->den,2,contextptr)); + case _EXT: + if (is_zero(derive(*(e._EXTptr+1),i,contextptr))) + return algebraic_EXTension(derive(*e._EXTptr,i,contextptr),*(e._EXTptr+1)); + default: + return gentypeerr(contextptr); + } + return 0; + } + + static gen _VECTderive(const gen & e,const vecteur & v,GIAC_CONTEXT){ + vecteur w; + w.reserve(v.size()); + vecteur::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + gen tmp=derive(e,*it,contextptr); + if (is_undef(tmp)) + return tmp; + w.push_back(tmp); + } + return w; + } + + static gen derivesymb(const gen& e,const gen & var,GIAC_CONTEXT){ + identificateur x(" x"); + gen xx(x); + gen f=subst(e,var,xx,false,contextptr); + f=derive(f,x,contextptr); + f=subst(f,xx,var,false,contextptr); + return f; + } + gen derive(const gen & e,const gen & vars,GIAC_CONTEXT){ + // cout << e << " " << vars << '\n'; + if (is_equal(e)) + return symb_equal(derive(e._SYMBptr->feuille[0],vars,contextptr), + derive(e._SYMBptr->feuille[1],vars,contextptr)); + switch (vars.type){ + case _INT_: { + if (vars.val>=0 && e.is_symb_of_sommet(at_program)){ + const gen & f =e._SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()==3){ + gen fvars=f[0]; + gen fexpr=f[2]; + if (fvars.type==_VECT && vars.valsize()){ + gen x=(*fvars._VECTptr)[vars.val]; + gen res=derive(fexpr,x,contextptr); + res=symb_program(makesequence(fvars,f[1],res)); + return res; + } + } + } + return symbolic(at_derive,makesequence(e,vars)); + } + case _IDNT: + return derive(e,*vars._IDNTptr,contextptr); + case _VECT: + return _VECTderive(e,*vars._VECTptr,contextptr); + case _SYMB: + return derivesymb(e,vars,contextptr); + default: + return gensizeerr(contextptr); + } + return 0; + } + + gen derive(const gen & e,const gen & vars,const gen & nderiv,GIAC_CONTEXT){ + if (is_equal(e)) + return symb_equal(derive(e._SYMBptr->feuille[0],vars,nderiv,contextptr), + derive(e._SYMBptr->feuille[1],vars,nderiv,contextptr)); + if (nderiv.type==_INT_){ + int n=nderiv.val; + gen ecopie(e),eprime(e); + int j=1; + for (;j<=n;++j){ + eprime=derive(ecopie,vars,contextptr); + // if (n>2) + eprime=ratnormal(eprime,contextptr); + if (is_undef(eprime)) + return eprime; + if ( (eprime.type==_SYMB) && (eprime._SYMBptr->sommet==at_derive)) + break; + ecopie=eprime; + } + if (j==n+1) + return eprime; + if (n+1-j==1) + return symbolic(at_derive,gen(makevecteur(ecopie,vars),_SEQ__VECT)); + return symbolic(at_derive,gen(makevecteur(ecopie,vars,n+1-j),_SEQ__VECT)); + } + // multi-index derivation + if (nderiv.type!=_VECT || + vars.type!=_VECT) return gensizeerr(gettext("derive.cc/derive")); + int s=int(nderiv._VECTptr->size()); + if (s!=signed(vars._VECTptr->size())) return gensizeerr(gettext("derive.cc/derive")); + int j=0; + gen ecopie(e); + for (;j1 && v[1].is_symb_of_sommet(at_unquote)) + v[1]=eval(v[1],1,contextptr); + if (is_undef(v)) + return v; + if (step_infolevel(contextptr) && v.size()==2 && v[0].type==_SYMB) + gprintf(step_derive_header,gettext("===== Derive %gen with respect to %gen ====="),makevecteur(v[0],v[1]),contextptr); + gen var,res; + if (args.type!=_VECT && is_algebraic_program(v[0],var,res)){ + if (var.type==_VECT && var.subtype==_SEQ__VECT && var._VECTptr->size()==1) + var=var._VECTptr->front(); + res=derive(res,var,contextptr); + return symbolic(at_program,makesequence(var,0,res)); + } + int s=int(v.size()); + if (s==2){ + if (v[1].type==_VECT && v[1].subtype==_SEQ__VECT){ + vecteur & w=*v[1]._VECTptr; + int ss=int(w.size()); + gen res=v[0]; + for (int i=0;iexponent; + it->coeff=it->coeff*e; + it->exponent=e-1; + } + return res; + } + if (args.type!=_VECT && v[0].type==_VECT && v[0].subtype==_POLY1__VECT) + return gen(derivative(*v[0]._VECTptr),_POLY1__VECT); + return derive(v[0],v[1],contextptr); + } + if (s==3 && (v[2].type==_INT_ || (v[2].type==_VECT && v[2].subtype!=_SEQ__VECT)) ) + return derive( v[0],v[1],v[2],contextptr); + if (s<3) + return gensizeerr(contextptr); + if (s>=3 && v.back().is_symb_of_sommet(at_equal)){ + gen v_=gen(vecteur(v.begin(),v.end()-1),_SEQ__VECT); + v_=_derive(v_,contextptr); + return _subst(makesequence(v_,v.back()),contextptr); + } + const_iterateur it=v.begin()+1,itend=v.end(); + res=v[0]; + for (;it!=itend;++it) + res=ratnormal(_derive(gen(makevecteur(res,*it),_SEQ__VECT),contextptr),contextptr); + return res; + } + // "unary" version + gen step_derive(const gen & args,GIAC_CONTEXT){ + if (step_infolevel(contextptr)) + ++step_infolevel(contextptr); + gen res; +#ifndef NO_STDEXCEPT + try { + res=_derive(args,contextptr); + } catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + res=string2gen(e.what(),false); + res.subtype=-1; + } +#else + res=_derive(args,contextptr); +#endif + if (step_infolevel(contextptr)) + --step_infolevel(contextptr); + return res; + } + gen _diff(const gen & g,GIAC_CONTEXT){ + return _derive(g,contextptr); + } + static const char _derive_s []="diff"; + static string printasderive(const gen & feuille,const char * sommetstr,GIAC_CONTEXT){ + if (feuille.type!=_VECT){ + if (feuille.type>=_POLY && feuille.type!=_IDNT) + return "("+feuille.print()+")'"; + return feuille.print()+"'"; + } + return sommetstr+("("+feuille.print(contextptr)+")"); + } + static string texprintasderive(const gen & feuille,const char * sommetstr,GIAC_CONTEXT){ + if (feuille.type!=_VECT) + return gen2tex(feuille,contextptr)+"'"; + return "\\frac{\\partial \\left("+gen2tex(feuille._VECTptr->front(),contextptr)+"\\right)}{\\partial "+gen2tex(feuille._VECTptr->back(),contextptr)+"}"; + } + static define_unary_function_eval4_quoted (__derive,&step_derive,_derive_s,printasderive,texprintasderive); + define_unary_function_ptr5( at_derive ,alias_at_derive,&__derive,_QUOTE_ARGUMENTS,true); + + gen _grad(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT) + return gensizeerr(contextptr); + if (args._VECTptr->size()==3){ + gen opt=args._VECTptr->back(); + if (opt.is_symb_of_sommet(at_equal) && (opt._SYMBptr->feuille[0]==at_coordonnees || (opt._SYMBptr->feuille[0].type==_INT_ && opt._SYMBptr->feuille[0].val==_COORDS))){ + gen coord=(*args._VECTptr)[1]; + gen res=_derive(makesequence(args._VECTptr->front(),coord),contextptr); + if (res.type==_VECT){ + vecteur resv=*res._VECTptr; + if (opt._SYMBptr->feuille[1]==at_sphere && resv.size()==3){ + resv[1]=resv[1]/coord[0]; + resv[2]=resv[2]/(coord[0]*sin(coord[1],contextptr)); + return resv; + } + if (opt._SYMBptr->feuille[1]==at_cylindre && resv.size()>=2){ + resv[1]=resv[1]/coord[0]; + return resv; + } + } + } + } + if (args._VECTptr->size()!=2) + return gensizeerr(contextptr); + return _derive(args,contextptr); + } + static const char _grad_s []="grad"; + static define_unary_function_eval_quoted (__grad,&_grad,_grad_s); + define_unary_function_ptr5( at_grad ,alias_at_grad,&__grad,_QUOTE_ARGUMENTS,true); + + gen critical(const gen & g,bool extrema_only,GIAC_CONTEXT){ + gen arg,var; + if (g.type!=_VECT){ + arg=g; + var=ggb_var(arg); + } + else { + if (g.subtype!=_SEQ__VECT || g._VECTptr->size()<2) + return gensizeerr(contextptr); + arg=g._VECTptr->front(); + var=(*g._VECTptr)[1]; + } + int savestep=step_infolevel(contextptr); + gprintf(gettext("===== Critical points for %gen ====="),makevecteur(arg),contextptr); + step_infolevel(contextptr)=0; + gen d=_derive(makesequence(arg,var),contextptr); + gen deq=_equal(makesequence(d,0*var),contextptr); + // *logptr(contextptr) << "Critical points for "<< arg <<": solving " << deq << " with respect to " << var << '\n'; + int c=calc_mode(contextptr); + calc_mode(0,contextptr); + gen s=_solve(makesequence(deq,var),contextptr); + step_infolevel(contextptr)=savestep; + gprintf(step_extrema1,gettext("Derivative of %gen with respect to %gen is %gen\nSolving %gen with respect to %gen answer %gen"),makevecteur(arg,var,d,deq,var,s.type==_VECT?change_subtype(s,_SEQ__VECT):s),contextptr); + calc_mode(c,contextptr); + if (c==1 && s.type==_VECT) + s.subtype=0; + vecteur ls=lidnt(s); + for (int i=0;ifeuille; + return symbolic(at_of,makesequence(gen(symbolic(at_composepow,makesequence(at_function_diff,2))),f)); + } + if (g.is_symb_of_sommet(at_of)){ + gen & f = g._SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()==2){ + gen & f1=f._VECTptr->front(); + gen & f2=f._VECTptr->back(); + if (f1.is_symb_of_sommet(at_composepow)){ + gen & f1f=f1._SYMBptr->feuille; + if (f1f.type==_VECT && f1f._VECTptr->size()==2 && f1f._VECTptr->front()==at_function_diff){ + return symbolic(at_of,makesequence(gen(symbolic(at_composepow,makesequence(at_function_diff,f1f._VECTptr->back()+1))),f2)); + } + } + } + } + identificateur _tmpi(" _x"); + gen _tmp(_tmpi); + gen dg(derive(g(_tmp,contextptr),_tmp,contextptr)); + if (lop(dg,at_derive).empty()){ + identificateur tmpi(" x"); + gen tmp(tmpi); + _tmp=quotesubst(dg,_tmp,tmp,contextptr); + if (dg.type==_VECT) + _tmp=makevecteur(_tmp); + gen res=symb_program(tmp,zero,_tmp,contextptr); + return res; + } + return symbolic(at_function_diff,g); + } + static const char _function_diff_s []="function_diff"; + static define_unary_function_eval (__function_diff,&_function_diff,_function_diff_s); + define_unary_function_ptr5( at_function_diff ,alias_at_function_diff,&__function_diff,0,true); + + static const char _fonction_derivee_s []="fonction_derivee"; + static define_unary_function_eval (__fonction_derivee,&_function_diff,_fonction_derivee_s); + define_unary_function_ptr5( at_fonction_derivee ,alias_at_fonction_derivee,&__fonction_derivee,0,true); + + gen _implicit_diff(const gen & args,GIAC_CONTEXT){ + if (is_undef(args)) return args; + if (args.type!=_VECT || (args._VECTptr->size()!=3 && args._VECTptr->size()!=4)) + return gensizeerr(contextptr); + int ndiff=1; + if (args._VECTptr->size()==4){ + gen g=args._VECTptr->back(); + if (!is_integral(g) || g.type!=_INT_ || g.val<1) + return gensizeerr(contextptr); + ndiff=g.val; + } + gen eq(remove_equal(args._VECTptr->front())),x((*args._VECTptr)[1]),y((*args._VECTptr)[2]); + gen dy=derive(eq,y,contextptr); + if (is_squarematrix(dy)) + dy=mtran(*dy._VECTptr); + gen yprime=-inv(dy,contextptr)*derive(eq,x,contextptr); + if (ndiff==1) + return yprime; + gen yn=yprime; + for (int n=2;n<=ndiff;++n){ + yn=ratnormal(derive(yn,x,contextptr)+derive(yn,y,contextptr)*yprime,contextptr); + } + return yn; + } + static const char _implicit_diff_s []="implicit_diff"; + static define_unary_function_eval (__implicit_diff,&_implicit_diff,_implicit_diff_s); + define_unary_function_ptr5( at_implicit_diff ,alias_at_implicit_diff,&__implicit_diff,0,true); + + // mode==0 for domain, ==1 for singular values + void domain(const gen & f,const gen & x,vecteur & eqs,vecteur &excluded,int mode,GIAC_CONTEXT){ + vecteur v=lvarxwithinv(f,x,contextptr); + lvar(f,v); + for (int i=0;ifeuille; + if (is_constant_wrt(g,x,contextptr)) + continue; + if (g.type!=_SYMB) + continue; + gen gf=g._SYMBptr->feuille; + domain(gf,x,eqs,excluded,mode,contextptr); + unary_function_ptr & u=g._SYMBptr->sommet; + if (u==at_inv || u==at_Ei || (mode==1 && (u==at_ln || u==at_log10 || u==at_Ci))){ + excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(gf,0),x),contextptr))); + continue; + } + if (u==at_pow){ + if (mode==1){ + excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(gf[0],0),x),contextptr))); + continue; + } + if (is_constant_wrt(gf[1],x,contextptr) && is_greater(gf[1],0,contextptr)) + eqs.push_back(symb_superieur_egal(gf[0],0)); + else + eqs.push_back(symb_superieur_strict(gf[0],0)); + continue; + } + if (u==at_ln || u==at_log10 || u==at_Ci){ + eqs.push_back(symb_superieur_strict(gf,0)); + continue; + } + if (u==at_acosh){ + if (mode==1) + excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(gf,0),x),contextptr))); + else + eqs.push_back(symb_superieur_egal(gf,1)); + continue; + } + if (u==at_asin || u==at_acos || u==at_atanh){ + if (mode==1) + excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(pow(gf,2,contextptr),1),x),contextptr))); + else + eqs.push_back(symb_inferieur_egal(pow(gf,2,contextptr),1)); + continue; + } + if (u==at_tan){ + excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(symb_cos(gf),0),x),contextptr))); + continue; + } + if (u==at_sin || u==at_cos || u==at_exp || u==at_atan) + continue; + if (u==at_sinh || u==at_cosh || u==at_tanh) + continue; + if (u==at_floor || u==at_ceil || u==at_round || u==at_abs || u==at_sign || u==at_max || u==at_min) + continue; + *logptr(contextptr) << g << gettext(" function not supported, doing like if it was defined") << '\n'; + } + } + gen domain(const gen & f,const gen & x,int mode,GIAC_CONTEXT){ + // domain of expression f with respect to variable x + if (x.type!=_IDNT){ + gen domainx(identificateur("domainx")); + return domain(subst(f,x,domainx,false,contextptr),domainx,mode,contextptr); + } + vecteur eqs,excluded,res; + bool b=complex_mode(contextptr); + complex_mode(false,contextptr); +#ifndef NO_STDEXCEPT + try { +#endif + domain(f,x,eqs,excluded,mode,contextptr); + res=gen2vecteur(_solve(makesequence(eqs,x),contextptr)); +#ifndef NO_STDEXCEPT + } catch (std::runtime_error & e ) { + last_evaled_argptr(contextptr)=NULL; + *logptr(contextptr) << e.what() << '\n'; + } +#endif + complex_mode(b,contextptr); + comprim(excluded); + if (mode==1) + return excluded; + if (excluded.empty()) + return res.size()==1?res.front():res; + vecteur tmp; + for (int i=0;ifeuille); + v.push_back(tmp[j]); + res[i]=symbolic(at_and,gen(v,_SEQ__VECT)); + } + } + return res; + } + // not reached + if (res.size()==1){ + tmp.insert(tmp.begin(),res.front()); + return symbolic(at_and,gen(tmp,_SEQ__VECT)); + } + tmp.insert(tmp.begin(),symbolic(at_ou,gen(res,_SEQ__VECT))); + return symbolic(at_and,gen(tmp,_SEQ__VECT)); + } + void domain_auto_assume(const gen & f,const gen & x,GIAC_CONTEXT){ + vecteur range; + find_range(x,range,contextptr); + if (range.size()>=1 && range.front().type==_VECT){ + range=*range.front()._VECTptr; + if (range.size()==2 && range[0]==minus_inf && range[1]==plus_inf){ + gen periode; + if (is_periodic(f,x,periode,contextptr)){ + gen hyp=symb_and(symbolic(at_superieur_egal,makesequence(x,0)),symbolic(at_inferieur_egal,makesequence(x,periode))); + *logptr(contextptr) << "Periodic function. Auto assume" << hyp << "\n"; + giac_assume(hyp,contextptr); + } + } + } + } + gen _domain(const gen & args,GIAC_CONTEXT){ + if (is_undef(args)) return args; + if (args.type!=_VECT || args.subtype!=_SEQ__VECT){ + gen xval=assumeeval(vx_var,contextptr); + domain_auto_assume(args,vx_var,contextptr); + gen res=domain(args,vx_var,0,contextptr); + restorepurge(xval,vx_var,contextptr); + return res; + } + vecteur v=*args._VECTptr; + if (v.size()<2) + return gensizeerr(contextptr); + if (is_integral(v[1])) + v.insert(v.begin()+1,vx_var); + if (v.size()==2) + v.push_back(0); + if (v[2].type!=_INT_) + return gensizeerr(contextptr); + gen xval=assumeeval(vx_var,contextptr); + domain_auto_assume(v[0],v[1],contextptr); + gen res=domain(v[0],v[1],v[2].val,contextptr); + restorepurge(xval,vx_var,contextptr); + return res; + } + static const char _domain_s []="domain"; + static define_unary_function_eval (__domain,&_domain,_domain_s); + define_unary_function_ptr5( at_domain ,alias_at_domain,&__domain,0,true); + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/desolve.cc b/android/app/src/main/cpp/giac/src/giac/cpp/desolve.cc new file mode 100644 index 0000000..83e28d0 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/desolve.cc @@ -0,0 +1,2542 @@ +/* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c desolve.cc -DHAVE_CONFIG_H -DIN_GIAC" -*- */ +#include "giacPCH.h" +/* + * Copyright (C) 2000, 2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using namespace std; +#include +#include +#include "desolve.h" +#include "derive.h" +#include "intg.h" +#include "subst.h" +#include "usual.h" +#include "symbolic.h" +#include "unary.h" +#include "poly.h" +#include "sym2poly.h" // for equalposcomp +#include "tex.h" +#include "modpoly.h" +#include "series.h" +#include "solve.h" +#include "ifactor.h" +#include "prog.h" +#include "rpn.h" +#include "lin.h" +#include "intgab.h" +#include "giacintl.h" +#if defined GIAC_HAS_STO_38 || defined NSPIRE || defined NSPIRE_NEWLIB || defined FXCG || defined GIAC_GGB || defined USE_GMP_REPLACEMENTS || defined KHICAS +#else +#include "signalprocessing.h" +#endif + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + gen integrate_without_lnabs(const gen & e,const gen & x,GIAC_CONTEXT){ + // workaround for desolve(diff(y)*sin(x)=y*ln(y),x,y); + // otherwise it returns ln(-1-cos(x)) + bool save_cv=complex_variables(contextptr); + complex_variables(false,contextptr); + gen res=integrate_gen(e,x,contextptr); + if (lop(res,at_abs).empty() && lop(res,at_floor).empty()){ + complex_variables(save_cv,contextptr); + return res; + } + bool save_do_lnabs=do_lnabs(contextptr); + do_lnabs(false,contextptr); + res=integrate_gen(e,x,contextptr); + do_lnabs(save_do_lnabs,contextptr); + complex_variables(save_cv,contextptr); + return res; + } + + gen gen_t(const vecteur & v,GIAC_CONTEXT){ +#ifdef GIAC_HAS_STO_38 + identificateur id_t("t38_"); +#else + identificateur id_t(" t"); +#endif + gen tmp_t,t=t__IDNT; + t=t._IDNTptr->eval(1,tmp_t,contextptr); + if (t!=t__IDNT || equalposcomp(lidnt(v),t__IDNT)) + t=id_t; + return t; + } + + gen laplace(const gen & f0,const gen & x,const gen & s,GIAC_CONTEXT){ + if (x.type!=_IDNT) + return gensizeerr(contextptr); + if (f0.type==_VECT){ + vecteur v=*f0._VECTptr; + for (int i=0;ishift(idxt)); + f=r2sym(ff,v,contextptr); + if (n%2) + f=-f; + } + } + if (!assume_t_in_ab(t,plus_inf,plus_inf,true,true,contextptr)) + return gensizeerr(contextptr); + int c=calc_mode(contextptr); + calc_mode(0,contextptr); + gen res=_integrate(makesequence(f*exp(-t*x,contextptr),x),contextptr); + calc_mode(c,contextptr); + if (lop(res,at_integrate).empty() && lop(res,at_piecewise).empty() && lop(res,at_sign).empty()){ + gen res0(res); + res=-_limit(makesequence(res0,x,0,1),contextptr); + if (!lop(res0,at_lower_incomplete_gamma).empty()) + res += _limit(makesequence(res0,x,plus_inf),contextptr); + } + else + res=undef; + if (is_undef(res)) + res=_integrate(makesequence(f*exp(-t*x,contextptr),x,0,plus_inf),contextptr); + for (int i=1;i<=n;++i){ + if (is_undef(res)) + return res; + res = _integrate(gen(makevecteur(res,t,0,t),_SEQ__VECT),contextptr); + res += _integrate(gen(makevecteur(f/pow(-x,i),x,0,plus_inf),_SEQ__VECT),contextptr); + } + purgenoassume(t,contextptr); + if (s==x) + res=subst(res,t,x,false,contextptr); + return ratnormal(res,contextptr); + /* + gen remains,res=integrate(f*exp(-t*x,contextptr),*x._IDNTptr,remains,contextptr); + res=subst(-res,x,zero,false,contextptr); + if (s==x) + res=subst(res,t,x,false,contextptr); + if (!is_zero(remains)) + res = res +symbolic(at_integrate,gen(makevecteur(remains,x,0,plus_inf),_SEQ__VECT)); + return res; + */ + } + + static gen _laplace_(const gen & args,GIAC_CONTEXT){ + if (args.type!=_VECT) + return laplace(args,vx_var,vx_var,contextptr); + vecteur & v=*args._VECTptr; + int s=int(v.size()); + if (s==2) + return laplace( v[0],v[1],v[1],contextptr); + if (s!=3) + return gensizeerr(contextptr); + return laplace( v[0],v[1],v[2],contextptr); + } + // "unary" version + gen _laplace(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + bool b=approx_mode(contextptr); + approx_mode(false,contextptr); +#if !defined NSPIRE && !defined FXCG + my_ostream * ptr=logptr(contextptr); + logptr(0,contextptr); + gen res=_laplace_(args,contextptr); + logptr(ptr,contextptr); +#else + gen res=_laplace_(exact(args,contextptr),contextptr); +#endif + approx_mode(b,contextptr); + if (b || has_num_coeff(args)) + res=simplifier(evalf(res,1,contextptr),contextptr); + return res; + } + static const char _laplace_s []="laplace"; + static define_unary_function_eval (__laplace,&_laplace,_laplace_s); + define_unary_function_ptr5( at_laplace ,alias_at_laplace,&__laplace,0,true); + + polynome cstcoeff(const polynome & p){ + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (it->index.front()==0) + break; + } + return polynome(p.dim,vector< monomial >(it,itend)); + } + + // reduction of a fraction with multiple poles to single poles by integration + // by part, use the relation + // ilaplace(P'/P^(k+1))=laplacevar/k*ilaplace(1/P^k) + pf laplace_reduce_pf(const pf & p_cst, tensor & laplacevar ){ + pf p(p_cst); + assert(p.mult>0); + if (p.mult==1) + return p_cst; + tensor fprime=p.fact.derivative(); + tensor d(fprime.dim),C(fprime.dim),u(fprime.dim),v(fprime.dim); + egcdpsr(p.fact,fprime,u,v,d); // f*u+f'*v=d + tensor usave(u),vsave(v); + // int initial_mult=p.mult-1; + while (p.mult>1){ + egcdtoabcuv(p.fact,fprime,p.num,u,v,d,C); + p.mult--; + p.den=(p.den/p.fact)*C*gen(p.mult); + p.num=u*gen(p.mult)+v.derivative()+v*laplacevar; + if ( (p.mult % 5)==1) // simplify from time to time + TsimplifybyTlgcd(p.num,p.den); + if (p.mult==1) + break; + u=usave; + v=vsave; + } + return pf(p); + } + + static gen pf_ilaplace(const gen & e0,const gen & x, gen & remains,int,GIAC_CONTEXT){ + vecteur vexp; + gen res; + lin(e0,vexp,contextptr); // vexp = coeff, arg of exponential + const_iterateur it=vexp.begin(),itend=vexp.end(); + remains=0; + for (;it!=itend;){ + gen coeff=*it; + ++it; + gen axb=*it,expa,expb; + ++it; + gen e=coeff*exp(axb,contextptr); + if (!is_linear_wrt(axb,x,expa,expb,contextptr)){ + remains += e; + continue; + } + if (is_strictly_positive(expa,contextptr)) + *logptr(contextptr) << gettext("Warning, exponential x coeff is positive ") << expa << '\n'; + vecteur varx(lvarx(coeff,x)); + int varxs=int(varx.size()); + if (!varxs){ // Dirac function + res += coeff*exp(expb,contextptr)*symbolic(at_Dirac,laplace_var+expa); + continue; + } + if ( (varxs>1) || (varx.front()!=x) ) { + remains += e; + continue; + } + vecteur l; + l.push_back(x); // insure x is the main var + l.push_back(laplace_var); // s var as second var + l=vecteur(1,l); + alg_lvar(makevecteur(coeff,axb),l); + gen glap=e2r(laplace_var,l,contextptr); + if (glap.type!=_POLY) return gensizeerr(gettext("desolve.cc/pf_ilaplace")); + int s=int(l.front()._VECTptr->size()); + if (!s){ + l.erase(l.begin()); + s=int(l.front()._VECTptr->size()); + } + gen r=e2r(coeff,l,contextptr); + gen r_num,r_den; + fxnd(r,r_num,r_den); + if (r_num.type==_EXT){ + remains += e; + continue; + } + if (r_den.type!=_POLY){ + remains += e; + continue; + } + polynome den(*r_den._POLYptr),num(s); + if (r_num.type==_POLY) + num=*r_num._POLYptr; + else + num=polynome(r_num,s); + polynome p_content(lgcd(den)); + factorization vden(sqff(den/p_content)); // first square-free factorization + vector< pf > pfde_VECT; + polynome ipnum(s),ipden(s),temp(s),tmp(s); + partfrac(num,den,vden,pfde_VECT,ipnum,ipden); + vector< pf >::iterator it=pfde_VECT.begin(); + vector< pf >::const_iterator itend=pfde_VECT.end(); + vector< pf > rest,finalde_VECT; + for (;it!=itend;++it){ + pf single(laplace_reduce_pf(*it,*glap._POLYptr)); + gen extra_div=1; + factor(single.den,p_content,vden,false,withsqrt(contextptr),complex_mode(contextptr),1,extra_div); + partfrac(single.num,single.den,vden,finalde_VECT,temp,tmp); + } + it=finalde_VECT.begin(); + itend=finalde_VECT.end(); + gen lnpart(0),deuxaxplusb,sqrtdelta,exppart; + polynome a(s),b(s),c(s); + polynome d(s),E(s),lnpartden(s); + polynome delta(s),atannum(s),alpha(s); + vecteur lprime(l); + if (lprime.front().type!=_VECT) return gensizeerr(gettext("desolve.cc/pf_ilaplace")); + lprime.front()=cdr_VECT(*(lprime.front()._VECTptr)); + bool uselog; + for (;it!=itend;++it){ + int deg=it->fact.lexsorted_degree(); + switch (deg) { + case 1: // 1st order + findde(it->den,a,b); + lnpart=lnpart+rdiv(r2e(it->num,l,contextptr),r2e(firstcoeff(a),lprime,contextptr),contextptr)*exp(r2e(rdiv(-b,a,contextptr),lprime,contextptr)*laplace_var,contextptr); + break; + case 2: // 2nd order + findabcdelta(it->fact,a,b,c,delta); + exppart=exp(r2e(rdiv(-b,gen(2)*a,contextptr),lprime,contextptr)*laplace_var,contextptr); + uselog=is_positive(delta); + alpha=(it->den/it->fact).trunc1()*a; + findde(it->num,d,E); + atannum=a*E*gen(2)-b*d; + // cos part d/alpha*ln(fact) + lnpartden=alpha; + simplify(d,lnpartden); + if (uselog){ + sqrtdelta=normal(sqrt(r2e(delta,lprime,contextptr),contextptr),contextptr); + gen racine=ratnormal(sqrtdelta/gen(2)/r2e(a,lprime,contextptr),contextptr); + lnpart=lnpart+rdiv(r2e(d,lprime,contextptr),r2e(lnpartden,lprime,contextptr),contextptr)*cosh(racine*laplace_var,contextptr)*exppart; + gen aa=ratnormal(r2e(atannum,lprime,contextptr)/r2e(alpha,lprime,contextptr)/sqrtdelta,contextptr); + lnpart=lnpart+aa*sinh(racine*laplace_var,contextptr)*exppart; + } + else { + sqrtdelta=normal(sqrt(r2e(-delta,lprime,contextptr),contextptr),contextptr); + gen racine=ratnormal(sqrtdelta/gen(2)/r2e(a,lprime,contextptr),contextptr); + lnpart=lnpart+rdiv(r2e(d,lprime,contextptr),r2e(lnpartden,lprime,contextptr),contextptr)*cos(racine*laplace_var,contextptr)*exppart; + gen aa=ratnormal(r2e(atannum,lprime,contextptr)/r2e(alpha,lprime,contextptr)/sqrtdelta,contextptr); + lnpart=lnpart+aa*sin(racine*laplace_var,contextptr)*exppart; + } + break; + default: + rest.push_back(pf(it->num,it->den,it->fact,1)); + break ; + } + } + vecteur ipnumv=polynome2poly1(ipnum,1); + gen deno=r2e(ipden,l,contextptr); + int nums=int(ipnumv.size()); + for (int i=0;itype==_SYMB) && (it->_SYMBptr->sommet==at_derive) ){ + gen & g=it->_SYMBptr->feuille; + int m=-1,nder=1; + if ( (g.type==_VECT) && (!g._VECTptr->empty()) ){ + m=diffeq_order(g._VECTptr->front(),y); + if (g._VECTptr->size()==3){ + gen & gg=g._VECTptr->back(); + if (gg.type==_INT_) + nder=gg.val; + } + } + else + m=diffeq_order(g,y); + if (m>=0) + n=giacmax(n,m+nder); + } + } + return n; + } + + // true if f is a linear differential equation + // & returns the coefficient in v in descending order + // v has size order+2 with last term=cst coeff of the diff equation + static bool is_linear_diffeq(const gen & f_orig,const gen & x,const gen & y,int order,vecteur & v,int step_info,GIAC_CONTEXT){ + v.clear(); + gen f(f_orig),a,b,cur_y(y); + gen t=gen_t(makevecteur(x,y,f_orig),contextptr); + for (int i=0;i<=order;++i){ + gen ftmp(quotesubst(f,cur_y,t,contextptr)); + if (!is_linear_wrt(eval(ftmp,eval_level(contextptr),contextptr),t,a,b,contextptr)) + return false; + if (!rlvarx(a,y).empty()) + return false; + if (!i) + v.push_back(b); + v.push_back(a); + cur_y=symb_derive(y,x,i+1); + } + reverse(v.begin(),v.end()); + if (step_info && v.size()>3) + gprintf("Linear differential equation of coefficients %gen\nsecond member %gen",makevecteur(vecteur(v.begin(),v.end()-1),-v.back()),step_info,contextptr); + return true; + } + + static bool find_n_derivatives_function(const gen & f,const gen & x,int & nder,gen & fonction){ + if ( (f.type!=_SYMB) || (f._SYMBptr->sommet!=at_derive) ){ + nder=0; + fonction=f; + return true; + } + if (f._SYMBptr->feuille.type!=_VECT){ + if (!find_n_derivatives_function(f._SYMBptr->feuille,x,nder,fonction)) + return false; + ++nder; + return true; + } + vecteur & v=*f._SYMBptr->feuille._VECTptr; + if ( (v.size()>1) && (v[1]!=x) ) + return false; // setsizeerr(contextptr); + if (!find_n_derivatives_function(v[0],x,nder,fonction)) + return false; + if ( (v.size()==3) && (v[2].type==_INT_) ) + nder += v[2].val; + else + nder += 1; + return true; + } + + static gen function_of(const gen & y_orig,const gen & x_orig){ + if ( (y_orig.type!=_SYMB) || (y_orig._SYMBptr->sommet!=at_of) ) + return gensizeerr(gettext("function_of")); + vecteur & v =*y_orig._SYMBptr->feuille._VECTptr; + if ( (v[1]!=x_orig) || (v[0].type!=_IDNT) ) + return gensizeerr(gettext("function_of")); + return v[0]; + } + + static gen in_desolve_with_conditions(const vecteur & v_,const gen & x,const gen & y,const gen & solution_generale,const vecteur & parameters,const gen & f,int step_info,GIAC_CONTEXT){ + gen yy(y); + vecteur v(v_); + if (yy.type!=_IDNT) + yy=function_of(y,x); + if (is_undef(yy)) + return yy; + // special handling for systems + if (solution_generale.type==_VECT && v.size()==2){ + gen init=v[1],point=0; + if (init.is_symb_of_sommet(at_equal) && init._SYMBptr->feuille.type==_VECT&& init._SYMBptr->feuille._VECTptr->size()>=2){ + point=(*init._SYMBptr->feuille._VECTptr)[0]; + init=(*init._SYMBptr->feuille._VECTptr)[1]; + if (!point.is_symb_of_sommet(at_of) || point._SYMBptr->feuille.type!=_VECT || point._SYMBptr->feuille._VECTptr->size()<2 || point._SYMBptr->feuille._VECTptr->front()!=y) + return gensizeerr("Bad initial condition"); + point=(*point._SYMBptr->feuille._VECTptr)[1]; + } + gen systeme=subst(solution_generale,x,point,false,contextptr)-init; + gen s=_solve(makesequence(systeme,parameters),contextptr); + if (s.type!=_VECT) + return gensizeerr("Bad initial condition"); + vecteur res; + for (unsigned i=0;isize();++i){ + gen tmp=subst(solution_generale,parameters,s[i],false,contextptr); + tmp=ratnormal(tmp,contextptr); + res.push_back(tmp); + } + return res; + } + if (solution_generale.type==_VECT) + *logptr(contextptr) << gettext("Boundary conditions for parametric curve not implemented") << '\n'; + // solve boundary conditions + iterateur jt=v.begin()+1,jtend=v.end(); + for (unsigned ndiff=0;jt!=jtend;++ndiff,++jt){ + if (jt->type==_VECT && jt->_VECTptr->size()==2){ + if (ndiff) + *jt=symbolic(at_of,makesequence(symbolic(at_derive,makesequence(y,x,int(ndiff))),jt->_VECTptr->front()))-jt->_VECTptr->back(); + else + *jt=symbolic(at_of,makesequence(y,jt->_VECTptr->front()))-jt->_VECTptr->back(); + } + } + const_iterateur it=v.begin()+1,itend=v.end(); + vecteur conditions(remove_equal(it,itend)); + if (conditions.empty()) + return solution_generale; + // conditions must be in terms of y(value) or derivatives + vecteur condvar(rlvarx(conditions,yy)); + vecteur yvar; // will contain triplet (var,n,x) n=nth derivative, x point + it=condvar.begin(),itend=condvar.end(); + int maxnder=0; + for (;it!=itend;++it){ + if ( (it->type!=_SYMB) || (it->_SYMBptr->sommet!=at_of) ) + continue; + vecteur & w=*it->_SYMBptr->feuille._VECTptr; + int nder; + gen fonction; + if (!find_n_derivatives_function(w[0],x,nder,fonction)) + return gensizeerr(contextptr); + if (fonction==y){ + if ( (w[1].type==_VECT) && (!w[1]._VECTptr->empty())) + yvar.push_back(makevecteur(*it,nder,w[1]._VECTptr->front())); + else + yvar.push_back(makevecteur(*it,nder,w[1])); + } + if (nder>maxnder) + maxnder=nder; + } + // compute all derivatives of the general solution + vecteur derivatives(1,solution_generale); + gen current=solution_generale; + for (int i=1;i<=maxnder;++i){ + current=derive(current,x,contextptr); + derivatives.push_back(current); + } + // evaluate at points of yvar making substition vectors + it=yvar.begin(),itend=yvar.end(); + vecteur substin,substout; + for (;it!=itend;++it){ + vecteur & w=*it->_VECTptr; + substin.push_back(w[0]); + substout.push_back(subst(derivatives[w[1].val],x,w[2],false,contextptr)); + } + // replace in conditions + conditions=*eval(subst(conditions,substin,substout,false,contextptr),eval_level(contextptr),contextptr)._VECTptr; + // solve system over _c0..._cn-1 + int save_xcas_mode=xcas_mode(contextptr); + xcas_mode(contextptr)=0; + int save_calc_mode=calc_mode(contextptr); + calc_mode(contextptr)=0; + vecteur parameters_solutions=*_solve(gen(makevecteur(conditions,parameters),_SEQ__VECT),contextptr)._VECTptr; + if (step_info) + gprintf("General solution %gen\nSolving initial conditions\n%gen\nunknowns %gen\nSolutions %gen",makevecteur(solution_generale,conditions,parameters,parameters_solutions),step_info,contextptr); + xcas_mode(contextptr)=save_xcas_mode; + calc_mode(contextptr)=save_calc_mode; + // replace _c0..._cn-1 in solution_generale + it=parameters_solutions.begin(),itend=parameters_solutions.end(); + vecteur res; + for (;it!=itend;++it){ + gen solgen=eval(subst(solution_generale,parameters,*it,false,contextptr),eval_level(contextptr),contextptr); + // check if f is valid at points where conditions hold (3rd column of yvar) + gen solgenchk=eval(subst(f,y,solgen,false,contextptr),1,contextptr); + bool ok=true; + for (unsigned i=0;ibegin(),itend=solution_generale._VECTptr->end(); + vecteur res; + res.reserve(itend-it); + for (;it!=itend;++it){ + if (it->type==_VECT) it->subtype=0; + gen tmp=in_desolve_with_conditions(v,x,y,*it,parameters,f,step_info,contextptr); + if (is_undef(tmp)) + return tmp; + if (tmp.type==_VECT) + res=mergevecteur(res,*tmp._VECTptr); + else + res.push_back(tmp); + } + return num?evalf(res,1,contextptr):res; + } + + static gen desolve_with_conditions(const vecteur & v,const gen & x,const gen & y,gen & f,GIAC_CONTEXT){ + int st=step_infolevel(contextptr); + step_infolevel(0,contextptr); + gen res=desolve_with_conditions(v,x,y,f,st,contextptr); + step_infolevel(st,contextptr); + return res; + } + + // f must be a vector obtained using factors + // x, y are 2 idnt + // xfact and yfact should be initialized to 1 + // return true if f=xfact*yfact where xfact depends on x and yfact on y only + bool separate_variables(const gen & f,const gen & x,const gen & y,gen & xfact,gen & yfact,int step_info,GIAC_CONTEXT){ + const_iterateur jt=f._VECTptr->begin(),jtend=f._VECTptr->end(); + for (;jt!=jtend;jt+=2){ + vecteur tmp(*_lname(*jt,contextptr)._VECTptr); + if (equalposcomp(tmp,y)){ + if (equalposcomp(tmp,x)) + return false; + yfact=yfact*pow(*jt,*(jt+1),contextptr); + } + else + xfact=xfact*pow(*jt,*(jt+1),contextptr); + } + if (step_info) + gprintf("Separable variables d%gen/%gen=%gen*d%gen",makevecteur(y,yfact,xfact,x),step_info,contextptr); + return true; + } + + bool separate_variables(const gen & f,const gen & x,const gen & y,gen & xfact,gen & yfact,GIAC_CONTEXT){ + return separate_variables(f,x,y,xfact,yfact,step_infolevel(contextptr),contextptr); + } + + void ggb_varxy(const gen & f_orig,gen & vx,gen & vy,GIAC_CONTEXT){ + vecteur lv=lidnt(f_orig); + vx=vx_var; + vy=y__IDNT_e; +#if 0 + if (calc_mode(contextptr)==1){ + vx=gen("ggbtmpvarx",contextptr); + vy=gen("ggbtmpvary",contextptr); + } +#endif + for (unsigned i=0;ifeuille; + if (f.type==_VECT){ + vecteur w; + for (int j=0;jsize();++j){ + gen tmp=desolve_cleanup((*f._VECTptr)[j],x,contextptr); + if (!is_one(tmp)) + w.push_back(tmp); + } + return _prod(w,contextptr); + } + } + if (i.is_symb_of_sommet(at_abs) || i.is_symb_of_sommet(at_neg)) + return desolve_cleanup(i._SYMBptr->feuille,x,contextptr); + if (is_zero(derive(i,x,contextptr))) + return 1; + return i; + } + + // solve linear diff eq of order 1 a*y'+b*y+c=0 + static gen desolve_lin1(const gen &a,const gen &b,const gen & c,const gen & x,vecteur & parameters,int step_info,GIAC_CONTEXT){ + if (step_info) + gprintf("Linear differential equation of order 1 a*y'+b*y+c=0\na=%gen, b=%gen, c=%gen",makevecteur(a,b,c),step_info,contextptr); + if (a.type==_VECT){ + // y'+inv(a)*b(x)*y+inv(a)*c(x)=0 + // take laplace transform + // p*Y-Y(0)+bsura*Y+csura=0 + // (p+bsura)*Y=Y(0)-csura + int n=int(a._VECTptr->size()); + if (!ckmatrix(a) || !ckmatrix(b)) + return gensizeerr(contextptr); + gen inva=inv(a,contextptr); + gen bsura=inva*b,csura,cl; + if (!is_zero(derive(bsura,x,contextptr))) + return gensizeerr("Non constant linear differential system"); + if (c.type==_VECT){ + vecteur & cv=*c._VECTptr; + for (unsigned i=0;isize()==1) + cv[i]=cv[i]._VECTptr->front(); + } + csura=inva*c; + cl=_laplace(makesequence(csura,x,x),contextptr); + } + else { + if (!is_zero(c)) + return gensizeerr("Invalid second member"); + cl=vecteur(n); + } + if (cl.type!=_VECT || int(cl._VECTptr->size())!=n) + return gensizeerr("Invalid second member"); + for (int i=0;i y=C(x)exp(-int(b/a)) and a(x)*C'*exp()+c(x)=0 + gen & a=v[0]; + gen & b=v[1]; + gen & c=v[2]; + if (ckmatrix(a)){ + if (c.type!=_VECT && is_zero(c)) + c=c*a; + c=_tran(c,contextptr)[int(a._VECTptr->size())-1]; + } + result=desolve_lin1(a,b,c,x,parameters,step_info,contextptr); + return true; + } + // cst coeff? + gen cst=v.back(); + v.pop_back(); + if (derive(v,x,contextptr)==vecteur(n+1,zero)){ + if (step_info) + gprintf("Linear differential equation with constant coefficients\nOrder %gen, coefficients %gen",makevecteur(n,v),step_info,contextptr); + // Yes! + // simpler general solution for small order generic lin diffeq with cst coeff/squarefree case + if (n<=3){ + vecteur rac=solve(horner(v,x,contextptr),x,1,contextptr); + comprim(rac); + if (n==2 && rac.size()==1){ + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + gen sol = exp(rac.front()*x,contextptr)*(parameters[parameters.size()-2]*x+parameters.back()); + if (step_info) + gprintf("Homogeneous solution %gen",makevecteur(sol),step_info,contextptr); + bool b=calc_mode(contextptr)==1; + if (b) + calc_mode(0,contextptr); + gen part=_integrate(makesequence(-cst/v.front()*exp(-rac.front()*x,contextptr),x),contextptr)*x+_integrate(makesequence(cst/v.front()*x*exp(-rac.front()*x,contextptr),x),contextptr); + if (step_info) + gprintf("Particuliar solution %gen",makevecteur(part),step_info,contextptr); + if (b) + calc_mode(1,contextptr); + part=simplify(part*exp(rac.front()*x,contextptr),contextptr); + result=sol+part; + if (step_info) + gprintf("General solution %gen",makevecteur(result),step_info,contextptr); + return true; + } + if (int(rac.size())==n){ + gen sol; bool reel=true; + for (int j=0;j=0;--i){ + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + tmp=tmp*t+parameters.back(); + arbitrary=arbitrary+v[i]*tmp; + } + arbitrary=(laplace_cst+arbitrary)/symb_horner(v,t); + arbitrary=ilaplace(arbitrary,t,x,contextptr); + result=arbitrary; + return true; + } + } + } + if (n==2){ // a(x)*y''+b(x)*y'+c(x)*y+d(x)=0 + gen & a=v[0]; + gen & b=v[1]; + gen & c=v[2]; + gen & d=cst; +#if 0 + if (is_exactly_zero(c)){ + vecteur v1(makevecteur(a,b,d)); + if (desolve_linn(x,y,t,1,v1,parameters,result,step_info,contextptr)){ + result=_integrate(makesequence(result,x),contextptr); + return true; + } + } +#endif + gen u=-b/a,V=-c/a,w=-d/a, + k=simplify(u*u/4-derive(u,x,contextptr)/2+V,contextptr); + // y''=u*y'+V*y+w (with u,V,w functions of x) + // Pseudo-code from fhub on HP Museum Forum + /* + k:=u^2/4-u'/2+V + if k==const or k*x^2=const then + if k=const + then s:=x; t:=e^(int(u,x)/2); + else u:=u*x+1; k:=u^2/4+V*x^2; s:=ln(x); t:=x^(u/2); + endif; + if k=0 then u:=t*s; V:=t; + elseif k>0 then u:=t*e^(sqrt(k)*s); V:=t*e^(-sqrt(k)*s); + else u:=t*cos(sqrt(-k)*s); V:=t*sin(sqrt(-k)*s); + endif; + w:=w/(u*V'-V*u'); w:=V*int(u*w,x)-u*int(V*w,x); + solution: y=c1*u+c2*V+w + endif + */ + bool cst=is_zero(derive(k,x,contextptr)); + bool x2=is_zero(derive(ratnormal(u*x,contextptr),x,contextptr)) && is_zero(derive(ratnormal(v*x*x,contextptr),x,contextptr)); + if (cst || x2){ + gen s,t; + if (cst){ + s=x; + t=simplify(exp(integrate_without_lnabs(u,x,contextptr)/2,contextptr),contextptr); + } + else { + u=u*x+1; + u=simplify(u,contextptr); + k=simplify(u*u/4+V*x*x,contextptr); + s=ln(x,contextptr); t=pow(x,u/2,contextptr); + } + if (is_zero(k)){ + u=t*s; V=t; + } + else { + if (is_strictly_positive(-k,contextptr)){ + gen tmp=sqrt(-k,contextptr)*s; + u=t*cos(tmp,contextptr); + V=t*sin(tmp,contextptr); + } + else { + if (s.is_symb_of_sommet(at_ln)){ + gen tmp=pow(s._SYMBptr->feuille,sqrt(k,contextptr),contextptr); + u=t*tmp; + V=t/tmp; + } + else { + gen tmp=sqrt(k,contextptr)*s; + u=t*exp(tmp,contextptr); + V=t*exp(-tmp,contextptr); + } + } + } + w=simplify(w/(u*derive(V,x,contextptr)-V*derive(u,x,contextptr)),contextptr); + w=V*integrate_without_lnabs(u*w,x,contextptr)- + u*integrate_without_lnabs(V*w,x,contextptr); + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + result=w+parameters[parameters.size()-2]*u+parameters[parameters.size()-1]*V; + return true; + } + // IMPROVE: if a, b, c are polynomials, search for a polynomial solution + // of the homogeneous equation, if found we can solve the diffeq + gen aa(a),bb(b),cc(c); + if (lvarxwithinv(makevecteur(a,b,c),x,contextptr)==vecteur(1,x)){ + vecteur l=vecteur(1,x); + gen a0(a),b0(b); + a=_coeff(makesequence(a,x),contextptr); + b=_coeff(makesequence(b,x),contextptr); + c=_coeff(makesequence(c,x),contextptr); + if (a.type==_VECT && b.type==_VECT && c.type==_VECT){ + int A=int(a._VECTptr->size())-1,B=int(b._VECTptr->size())-1,C=int(c._VECTptr->size())-1,N=-1; + if (C==B-1){ + gen n=-c._VECTptr->front()/b._VECTptr->front(); + if (n.type==_INT_ && n.val>N){ + if (A-2front(),bb=b._VECTptr->front()-1,cc=c._VECTptr->front(); + gen delta=(sqrt(bb*bb-4*aa*cc,contextptr)+bb)/2; + if (delta.type==_INT_ && delta.val>N) + N=delta.val; + } + } + if (A-2==B-1 && Cfront()/a._VECTptr->front()+1; + if (n.type==_INT_ && n.val>N) + N=n.val; + } + if (C==A-2 && B-1front()/a._VECTptr->front(),contextptr))/2; + if (delta.type==_INT_ && delta.val>N) + N=delta.val; + } + if (N>=0){ + int nrows=giacmax(giacmax(B,C+1),N==1?0:A)+N; + // search a solution sum(y_k*x*k,k,0,N) + matrice m(nrows); + for (int i=0;isize();++i){ + int j=int(a._VECTptr->size())-i-1; + for (int k=2;k<=N;++k){ + (*m[j+k-2]._VECTptr)[k] += k*(k-1)*a[i]; + } + } + // b*y' + for (int i=0;isize();++i){ + int j=int(b._VECTptr->size())-i-1; + for (int k=1;k<=N;++k){ + (*m[j+k-1]._VECTptr)[k] += k*b[i]; + } + } + // c*y + for (int i=0;isize();++i){ + int j=int(c._VECTptr->size())-i-1; + for (int k=0;k<=N;++k){ + (*m[j+k]._VECTptr)[k] += c[i]; + } + } + m=mker(m,contextptr); + if (!m.empty()){ + gen sol=m.front(); + if (sol.type==_VECT){ + vecteur v=*sol._VECTptr; + reverse(v.begin(),v.end()); + sol=symb_horner(-v,x); + *logptr(contextptr) << "Polynomial solution found " << sol << '\n'; + // now solve equation a*y''+b*y'+c*y+d=0 with y=sol*z + // a*sol*z''+(2*a*sol'+b*sol)*z'=d + gen res=desolve_lin1(a0*sol,2*a0*derive(sol,x,contextptr)+b0*sol,d,x,parameters,step_info,contextptr); + res=_integrate(makesequence(res,x),contextptr); + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + res += parameters.back(); + res=res*sol; + result=res; + return true; + } + } + } + } + } // end polynomial a,b,c +#ifndef USE_GMP_REPLACEMENTS + a=aa; b=bb; c=cc; + if (d==0 && lvarx(makevecteur(a,b,c),x,contextptr)==vecteur(1,x)){ + // if a,b,c are rationals and d==0, Kovacic + gen k=_kovacicsols(makesequence(makevecteur(a,b,c),x),contextptr); + if (k.type==_VECT && !k._VECTptr->empty()){ + if (k._VECTptr->size()==2){ + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + result=parameters[parameters.size()-2]*k._VECTptr->front()+parameters[parameters.size()-1]*k._VECTptr->back(); + return true; + } + if (k._VECTptr->size()==1){ + // we have one solution Y, find an independent one as z*Y + gen Y=k._VECTptr->front(); + // a*(zY)''+b*(zY)'+c*(zY)=0 + // a*(z''Y+2z'Y')+b*(z'Y)=0 + // z''*(aY)+z'*(2aY'+bY)=0 + result=desolve_lin1(a*Y,2*a*derive(Y,x,contextptr)+b*Y,0,x,parameters,step_info,contextptr); + result=_integrate(makesequence(result,x),contextptr); + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + result += parameters.back(); + result = result*Y; + return true; + } + } + } +#endif + } // end 2nd order eqdiff + return false; + } + + gen desolve_f(const gen & f_orig,const gen & x_orig,const gen & y_orig,int & ordre,vecteur & parameters,gen & fres,int step_info,bool & num,GIAC_CONTEXT){ + num=false; + // if x_orig.type==_VECT || y_orig.type==_VECT, they should be evaled + if (x_orig.type!=_VECT && eval(x_orig,1,contextptr)!=x_orig) + return gensizeerr("Independent variable assigned. Run purge("+x_orig.print(contextptr)+")\n"); + if (y_orig.type!=_VECT && eval(y_orig,1,contextptr)!=y_orig) + return gensizeerr("Dependent variable assigned. Run purge("+y_orig.print(contextptr)+")\n"); + gen x(x_orig); + if ( (x_orig.type==_VECT) && (x_orig._VECTptr->size()==1) ) + x=x_orig._VECTptr->front(); + if (x.type!=_IDNT){ + gen vx,vy; + ggb_varxy(f_orig,vx,vy,contextptr); + if (x_orig.type==_VECT) + return desolve_with_conditions(makevecteur(f_orig,x_orig,y_orig),vx,vy,fres,step_info,contextptr); + else + return desolve_with_conditions(makevecteur(f_orig,makevecteur(x_orig,y_orig)),vx,vy,fres,step_info,contextptr); + } + if (y_orig.type==_VECT) // FIXME: differential system + return gensizeerr(contextptr); + gen f=remove_and(f_orig,at_and); + if (f.type==_VECT){ + vecteur fv=*f._VECTptr; + return desolve_with_conditions(fv,x,y_orig,fres,step_info,contextptr); + } + gen y(y_orig),yof(y_orig),partic(undef); + if (y_orig.is_symb_of_sommet(at_equal)){ + // particular solution provided + y=y_orig._SYMBptr->feuille[0]; + partic=eval(y_orig._SYMBptr->feuille[1],1,contextptr); + } + if (y.type==_IDNT){ + yof=symb_of(y,gen(vecteur(1,x),_SEQ__VECT)); + f=quotesubst(f,yof,y,contextptr); + f=quotesubst(f,y,yof,contextptr); + } + else + y=function_of(y_orig,x); + if (is_undef(y)) + return y; + gen save_vx=vx_var; + vx_var=x; + int save=calc_mode(contextptr); + calc_mode(0,contextptr); +#ifdef GIAC_HAS_STO_38 + // HP Prime: if there is a M0-M9 identifier, this will not work + vecteur fid(lidnt(f)); + for (unsigned i=0;iid_name; + if (strlen(ch)==2 && ch[0]=='M' && ch[1]>='0' && ch[1]<='9') + return gensizeerr("Home matrix variable "+ string(ch)+" not allowed. Store your matrix in a CAS variable first"); + } + } +#endif + f=remove_equal(eval(f,eval_level(contextptr),contextptr)); + num=has_num_coeff(f); + if (num) + f=exact(f,contextptr); + if (ckmatrix(f)){ + vecteur v = *f._VECTptr; + for (int i=0;i1 && !is_undef(partic)){ + // reduce order by one + vecteur s(n,partic); + for (int i=1;isize(),p); + sol=integrate_without_lnabs(sol,x,contextptr)+p; + return sol; + } + if (n==1) { // 1st order + vecteur sol; + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + f=quotesubst(f,symb_derive(y,x),t,contextptr); + // f is an expression of x,y,t where t stands for y' + gen fa,fb,fc,fd,faa,fab; + // Test for Lagrange/Clairault-like eqdiff, + if (x.type==_IDNT && y.type==_IDNT && is_linear_wrt(f,y,fc,fd,contextptr) && is_linear_wrt(fd,x,fa,fb,contextptr)){ + // Clairault: fa must be cst*t and fc must be cst (must simplify fa and fc) + // f=y*fc+(fa*x+fb) + fd=gcd(fc,fa); + fa=normal(fa/fd,contextptr); fb=normal(fb/fd,contextptr); fc=normal(fc/fd,contextptr); + if (is_linear_wrt(fa,t,faa,fab,contextptr) && is_zero(fab) && derive(faa,makevecteur(x,y,t),contextptr)==vecteur(3,0) && derive(fc,makevecteur(x,y,t),contextptr)==vecteur(3,0) && derive(fb,makevecteur(x,y),contextptr)==vecteur(2,0)){ + // 0=f=fc*y+fd = fc*y+fa*x+fb = fc*y+faa*x*y'+fb + // -> y=-faa/fc*x*y' -fb/fc + if (is_one(ratnormal(-faa/fc,contextptr))){ + if (step_info) + gprintf("Order 1 Clairault differential equation",vecteur(0),step_info,contextptr); + // y=x*y'-fb/fc + gen fm=ratnormal(-fb/fc,contextptr); + gen fmp=derive(fm,t,contextptr); + sol.push_back(parameters.back()*x+subst(fm,t,parameters.back(),false,contextptr)); + sol.push_back(makevecteur(-fmp,-t*fmp+fm)); + return sol; + } + } + // Lagrange-> fa/fb/fc dependent de t uniquement, if fb==0 -> separate var or homogeneous + if (is_zero(derive(makevecteur(fa,fb,fc),x,contextptr)) && !is_zero(fb)){ + if (step_info) + gprintf("Order 1 Lagrange differential equation",vecteur(0),step_info,contextptr); + // y+fa/fc*x+fb/fc=0 + fa=fa/fc; fb=fb/fc; + // y+fa*x+fb=0 + // t=dy/dx, dy/dt=t*dx/dt => t*dx/dt+fa'*x+fb'+fa*dx/dt + // linear equation 1st order (fa+t)*dx/dt+fa'*x+fb'=0 + gen res=desolve_lin1(fa+t,derive(fa,t,contextptr),derive(fb,t,contextptr),t,parameters,step_info,contextptr); + vecteur sing(solve(t+fa,t,3,contextptr)); + for (int i=0;ifeuille))+prb; + pr=_lncollect(factorcollect(pr,false,contextptr),contextptr); + } + else + pr=parameters.back()+pr; +#else + if (has_op(pr,*at_ln)) + pr=_lncollect(pr,contextptr); // hack to solve y'=y*(1-y) + if (pr.is_symb_of_sommet(at_ln)) + pr=symbolic(at_ln,parameters.back()*pr._SYMBptr->feuille); + else + pr=parameters.back()+pr; +#endif + gen implicitsol=pr-integrate_without_lnabs(xfact,x,contextptr); +#ifdef NO_STDEXCEPT + vecteur newsol=solve(implicitsol,*y._IDNTptr,3,contextptr); + if (is_undef(newsol)){ + newsol.clear(); + *logptr(contextptr) << "Unable to solve implicit equation "<< implicitsol << "=0 in " << y << '\n'; + } +#else + vecteur newsol; + int cm=calc_mode(contextptr); + calc_mode(0,contextptr); + try { + newsol=solve(implicitsol,*y._IDNTptr,3,contextptr); + } catch(std::runtime_error & err){ + last_evaled_argptr(contextptr)=NULL; + newsol.clear(); + *logptr(contextptr) << "Unable to solve implicit equation "<< implicitsol << "=0 in " << y << '\n'; + } + calc_mode(cm,contextptr); +#endif + sol=mergevecteur(sol,newsol); + continue; + } // end separate variables + if (is_zero(derive(*it,x,contextptr))){ // x incomplete + if (step_info) + gprintf("Order 1 x-incomplete differential equation",vecteur(0),step_info,contextptr); + if (debug_infolevel) + *logptr(contextptr) << gettext("Incomplete") << '\n'; + gen pr=integrate_without_lnabs(inv(*it,contextptr),y,contextptr)+parameters.back(); + sol=mergevecteur(sol,solve(pr-x,*y._IDNTptr,3,contextptr)); + continue; + } + // check for a linear substitution -> like an x incomplete + fa=derive(*it,x,contextptr); fb=derive(*it,y,contextptr); + fc=simplify(fa/fb,contextptr); + if (is_zero(derive(fc,x,contextptr)) && is_zero(derive(fc,y,contextptr))){ + gen eff=subst(*it,y,y-fc*x,false,contextptr); // does not depend on x + gen pr=integrate_without_lnabs(inv(eff+fc,contextptr),y,contextptr)+parameters.back(); + pr=subst(pr,y,y+fc*x,false,contextptr); + vecteur l1=lop(lvarx(pr,y),at_floor); + if (!l1.empty()){ + vecteur l2(l1.size()); + pr=subst(pr,l1,l2,false,contextptr); + } + vecteur sol1=solve(pr-x,*y._IDNTptr,3,contextptr); + sol=mergevecteur(sol,sol1); + continue; + } + // homogeneous? + gen tplus(t); + gen tmpsto=sto(doubleassume_and(vecteur(2,0),0,1,false,contextptr),tplus,contextptr); + if (is_undef(tmpsto)) + return tmpsto; + f=quotesubst(*it,makevecteur(x,y),makevecteur(tplus*x,tplus*y),contextptr); + f=recursive_normal(f-*it,contextptr); + purgenoassume(tplus,contextptr); + if (is_zero(f)){ + if (step_info) + gprintf("Order 1 Homogeneous differential equation",vecteur(0),step_info,contextptr); + if (debug_infolevel) + *logptr(contextptr) << gettext("Homogeneous differential equation") << '\n'; + tmpsto=sto(doubleassume_and(vecteur(2,0),0,1,false,contextptr),x,contextptr); + if (is_undef(tmpsto)) + return tmpsto; + f=recursive_normal(quotesubst(*it,y,tplus*x,contextptr)-tplus,contextptr); + purgenoassume(x,contextptr); + // y=tx -> t'x=f + // Singular solutions f(t)=0 + vecteur singuliere(multvecteur(x,solve(f,t,complex_mode(contextptr) + 2,contextptr))); + sol=mergevecteur(sol,singuliere); + // Non singular: t'/f(t)=1/x + gen pr=parameters.back()*_simplify(exp(integrate_without_lnabs(inv(f,contextptr),t,contextptr),contextptr),contextptr); + // Try to find t in x=pr + vecteur v=protect_solve(x-pr,*t._IDNTptr,1,contextptr); + if (!v.empty() && !is_undef(v)){ + *logptr(contextptr) << "solve(" << pr << "=" << x << "," << t << ") returned " << v << ".\nIf solutions were missed consider paramplot(" << makevecteur(pr,t*pr) << "," << t << ")" << '\n'; + for (unsigned j=0;j N dy + M dx=0 where -M/N=y' + gen M,N; + f=_fxnd(*it,contextptr); + M=-f[0]; + N=f[1]; + // find an integrating factor P such that d_x(P*N)=d_y(P*M) + // If P depends on x then N*d_x(P)+Pd_x(N)=Pd_y(M) -> + // d_x(P)/P=(d_y(M)-d_x(N))/N should depend on x only + // If P depends on y then P d_x(N)=Pd_y(M)+Md_y(P) + // d_y(P)/P=(d_x(N)-d_y(M))/M + // Then solve P*Ndy+P*Mdx=dF + f=normal((derive(M,y,contextptr)-derive(N,x,contextptr))/N,contextptr); + if (is_zero(derive(f,y,contextptr))){ + gen P=simplify(exp(integrate_without_lnabs(f,x,contextptr),contextptr),contextptr); + // D_y(F)=P*N + gen F=P*integrate_without_lnabs(N,y,contextptr); + if (step_info) + gprintf("Order 1 Integrating factor %gen",makevecteur(P),step_info,contextptr); + // D_x(F)=P*M + parameters.push_back(diffeq_constante(int(parameters.size()),contextptr)); + F=F+integrate_without_lnabs(normal(P*M-derive(F,x,contextptr),contextptr),x,contextptr)+parameters.back(); + sol=mergevecteur(sol,solve(F,*y._IDNTptr,3,contextptr)); + continue; + } + f=normal((derive(N,x,contextptr)-derive(M,y,contextptr))/M,contextptr); + if (is_zero(derive(f,x,contextptr))){ + gen P=simplify(exp(integrate_without_lnabs(f,y,contextptr),contextptr),contextptr); + gen F=P*integrate_without_lnabs(M,x,contextptr); + // D_y(F)=P*N + if (step_info) + gprintf("Order 1 Integrating factor %gen",makevecteur(P),step_info,contextptr); + F=F+integrate_without_lnabs(normal(P*N-derive(F,y,contextptr),contextptr),y,contextptr)+diffeq_constante(int(parameters.size()),contextptr); + sol=mergevecteur(sol,solve(F,*y._IDNTptr,3,contextptr)); + continue; + } + // Bernoulli? + // y'=a(x)*y+b(x)*y^k + // Let z=y^(1-k) + // z'=(1-k)*y^(-k)*y'=(1-k)*[a(x)*z+b(x)] + // Solve for z then for y + f=subst(*it,y,2*y,false,contextptr); + f=factors(f-2*(*it),vx_var,contextptr); // should be (2^k-2)*b(x)*y^k + xfact=plus_one; + yfact=plus_one; + if (separate_variables(f,x,y,xfact,yfact,step_info,contextptr)){ + // xfact should be (2^k-2)*b(x) and yfact=y^k + if ( (yfact.type==_SYMB) && (yfact._SYMBptr->sommet==at_pow) && + (yfact._SYMBptr->feuille._VECTptr->front()==y) ){ + if (step_info) + gprintf("Order 1 Bernoulli differential equation",vecteur(0),step_info,contextptr); + gen k=yfact._SYMBptr->feuille._VECTptr->back(); + gen B=normal(xfact/(pow(plus_two,k,contextptr)-plus_two),contextptr); + gen A=normal((*it-B*pow(y,k,contextptr))/y,contextptr); + gen b=(k-1)*A; + gen c=(k-1)*B; + gen i=simplify(integrate_without_lnabs(b,x,contextptr),contextptr); + gen C=integrate_without_lnabs(-c*exp(i,contextptr),x,contextptr); + f= (C+parameters.back())*exp(-i,contextptr); + gen sol1=pow(f,inv(1-k,contextptr),contextptr); + sol.push_back(sol1); + // FIXME: we should add other roots of unity in complex mode + if (k.type==_INT_ && k.val %2) + sol.push_back(-sol1); + } + } + // Ricatti f=*it quadratic in y + gen P,Q,R; + if (is_quadratic_wrt(*it,y,R,Q,P,contextptr)){ + if (step_info) + gprintf("Order 1 Riccati differential equation",vecteur(0),step_info,contextptr); + gen result; + // y'=P+Q*y+R*y^2=q0+q1*y+q2*y^2 + if (!is_undef(partic)){ + // z'+(q1+2*q2*partic)*z+q2=0 + result=desolve_lin1(1,Q+2*R*partic,R,x,parameters,step_info,contextptr); + return makevecteur(partic,partic+inv(result,contextptr)); + } + // let y=-1/(R*F)*dF/dx, then F''-(1/R*R'+Q)*F'+R*P*F=0 + vecteur v(makevecteur(1,-normal(Q+derive(R,x,contextptr)/R,contextptr),normal(R*P,contextptr),0)); + if (desolve_linn(x,y,t,2,v,parameters,result,step_info,contextptr)){ + result=lnexpand(ln(result,contextptr),contextptr); + result=-derive(result,x,contextptr)/R; + result=ratnormal(result,contextptr); + gen lastp=parameters.back(); + parameters.pop_back(); + gen partic=subst(result,lastp,0,false,contextptr); + partic=ratnormal(partic,contextptr); + result=subst(result,lastp,1,false,contextptr); + result=ratnormal(result,contextptr); + //result=-derive(result,x,contextptr)/(R*result); + return makevecteur(partic,result); + } + } + } // end for (;it!=itend;) + return sol; + } // end if n==1 + if (n==2){ + // y''=f(y,y'), set u=y' -> u'=f(y,u)/u + gen der1=substout[0],der2=substout[1]; + gen soly2=_cSolve(makesequence(symb_equal(ff,0),der2),contextptr); + vecteur paramsave=parameters; + if (soly2.type==_VECT && !is_undef(soly2)){ + vecteur sol; + const vecteur & soly2v = *soly2._VECTptr; + for (unsigned i=0;isize();++j){ + parameters=paramsavein; + gen usolj=(*usol._VECTptr)[j]; + gen ysol=desolve(symb_equal(symbolic(at_derive,makesequence(y,x)),usolj),x,y,ordre,parameters,contextptr); + if (is_undef(ysol)) + return unable_to_solve_diffeq(); + sol=mergevecteur(sol,gen2vecteur(ysol)); + } + continue; + } // end x-incomplete + gen res(string2gen(gettext("Unable to solve differential equation"),false)); + res.subtype=-1; + sol.push_back(res); + } + ordre=2; + return sol; + } + } + return unable_to_solve_diffeq(); + } + gen ggbputinlist(const gen & g,GIAC_CONTEXT){ + if (g.type==_VECT || calc_mode(contextptr)!=1) + return g; + return makevecteur(g); + } + static gen point2vecteur(const gen & g_,GIAC_CONTEXT){ + if (!g_.is_symb_of_sommet(at_point)) + return g_; + gen g=eval(g_._SYMBptr->feuille,1,contextptr); + gen x,y; + if (g.type==_VECT){ + if (g._VECTptr->size()!=2) + return gensizeerr(contextptr); + x=g._VECTptr->front(); + y=g._VECTptr->back(); + } + else + reim(g,x,y,contextptr); + g=makevecteur(x,y); + return g; + } + // "unary" version + gen _desolve(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + //if (has_num_coeff(args)) return evalf(_desolve(exact(args,contextptr),contextptr),1,contextptr); + int ordre; + vecteur parameters; + if (args.type!=_VECT || args.subtype!=_SEQ__VECT || (!args._VECTptr->empty() && is_equal(args._VECTptr->back()) && args._VECTptr->back()._SYMBptr->feuille[0].type!=_IDNT)){ + // guess x and y + vecteur lv(lop(args,at_of)); + vecteur f; + if (lv.size()>=1 && lv[0]._SYMBptr->feuille.type==_VECT && (f=*lv[0]._SYMBptr->feuille._VECTptr).size()==2){ + if (f[1].type==_IDNT || f[1].is_symb_of_sommet(at_at)){ + return desolve(args,f[1],f[0],ordre,parameters,contextptr); + } + } + gen vx,vy; + lv=lidnt(evalf(args,1,contextptr)); + if (lv.size()==2){ + vx=lv[0]; + vy=lv[1]; + lv=lvar(apply(args,equal2diff)); + lv=lop(lv,at_derive); + lv=lidnt(lv); + if (lv.size()==1 && vx==lv.front()) + swapgen(vx,vy); + return _desolve(makesequence(args,vx,vy),contextptr); + } + ggb_varxy(args,vx,vy,contextptr); + return _desolve(makesequence(args,vx,vy),contextptr); + } + vecteur v=*args._VECTptr; + int s=int(v.size()); + for (int i=0;isize()==2){ + gen a=eval(v[1]._VECTptr->front(),1,contextptr); + gen b=eval(v[1]._VECTptr->back(),1,contextptr); + v[1]=a; + v.insert(v.begin()+2,b); + ++s; + } + if (s==2){ + if ( (v[1].type==_SYMB && v[1]._SYMBptr->sommet==at_of && v[1]._SYMBptr->feuille.type==_VECT &&v [1]._SYMBptr->feuille._VECTptr->size()==2 ) ) + return desolve(v[0],(*v[1]._SYMBptr->feuille._VECTptr)[1],(*v[1]._SYMBptr->feuille._VECTptr)[0],ordre,parameters,contextptr); + if (v[1]==vx_var) + return _desolve(v[0],contextptr); + return ggbputinlist(desolve( v[0],vx_var,v[1],ordre,parameters,contextptr),contextptr); + } + gen f; + if (s==4) + return ggbputinlist(desolve_with_conditions(makevecteur(v[0],v[3]),v[1],v[2],f,contextptr),contextptr); + if (s==5) + return ggbputinlist(desolve_with_conditions(makevecteur(v[0],v[3],v[4]),v[1],v[2],f,contextptr),contextptr); + if (s!=3) + return gensizeerr(contextptr); + return ggbputinlist(desolve( v[0],v[1],v[2],ordre,parameters,contextptr),contextptr); + } + static const char _desolve_s []="desolve"; + static define_unary_function_eval_quoted (__desolve,&_desolve,_desolve_s); + define_unary_function_ptr5( at_desolve ,alias_at_desolve,&__desolve,1,true); + + static const char _dsolve_s []="dsolve"; + static define_unary_function_eval_quoted (__dsolve,&_desolve,_dsolve_s); + define_unary_function_ptr5( at_dsolve ,alias_at_dsolve,&__dsolve,_QUOTE_ARGUMENTS,true); + + gen ztrans(const gen & f,const gen & x,const gen & s,GIAC_CONTEXT){ + if (x.type!=_IDNT) + return gensizeerr(contextptr); + gen t(s); + if (s==x){ +#ifdef GIAC_HAS_STO_38 + t=identificateur("z38_"); +#else + t=identificateur(" tztrans"); +#endif + } + if (!assume_t_in_ab(t,plus_inf,plus_inf,true,true,contextptr)) + return gensizeerr(contextptr); + gen tmp=expand(f*pow(t,-x,contextptr),contextptr); + gen res=_sum(gen(makevecteur(tmp,x,0,plus_inf),_SEQ__VECT),contextptr); + purgenoassume(t,contextptr); + if (s==x) + res=subst(res,t,x,false,contextptr); + return ratnormal(res,contextptr); + } + + gen desolve(const gen & f_orig,const gen & x_orig,const gen & y_orig,int & ordre,vecteur & parameters,GIAC_CONTEXT){ + gen f; + gen x(x_orig),y(y_orig); + if (x.is_symb_of_sommet(at_unquote)) + x=eval(x,1,contextptr); + if (y.is_symb_of_sommet(at_unquote)) + y=eval(y,1,contextptr); + int st=step_infolevel(contextptr); + step_infolevel(0,contextptr); + bool num=false; + gen res=desolve_f(f_orig,x,y,ordre,parameters,f,st,num,contextptr); + if (num) + res=evalf(res,1,contextptr); + step_infolevel(st,contextptr); + return res; + } + + // "unary" version + gen _ztrans(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT) + return ztrans(args,vx_var,vx_var,contextptr); + vecteur & v=*args._VECTptr; + int s=int(v.size()); + if (s==2) + return ztrans( v[0],v[1],v[1],contextptr); + if (s!=3) + return gensizeerr(contextptr); + return ztrans( v[0],v[1],v[2],contextptr); + } + static const char _ztrans_s []="ztrans"; + static define_unary_function_eval (__ztrans,&_ztrans,_ztrans_s); + define_unary_function_ptr5( at_ztrans ,alias_at_ztrans,&__ztrans,0,true); + + static gen invztranserr(GIAC_CONTEXT){ + return gensizeerr(gettext("Inverse z-transform of non rational functions not implemented or unable to fully factor rational function")); + } + + // limited to rational fractions + gen invztrans(const gen & f,const gen & x,const gen & s,GIAC_CONTEXT){ + if (x.type!=_IDNT) + return gensizeerr(contextptr); + gen t(s); + if (s==x){ +#ifdef GIAC_HAS_STO_38 + t=identificateur("s38_"); +#else + t=identificateur(" tinvztrans"); +#endif + } + vecteur varx(lvarx(f,x)); + int varxs=int(varx.size()); + gen res; + if (varxs==0) + res=f*_Kronecker(t,contextptr); + else { + if (varxs>1) + return invztranserr(contextptr); + res=f/x; + vecteur l; + l.push_back(x); // insure x is the main var + l.push_back(t); // s var as second var + l=vecteur(1,l); + alg_lvar(res,l); + vecteur lprime(l); + if (lprime.front().type!=_VECT) return gensizeerr(gettext("desolve.cc/invztrans")); + lprime.front()=cdr_VECT(*(lprime.front()._VECTptr)); + gen glap=e2r(s,l,contextptr); + if (glap.type!=_POLY) return gensizeerr(gettext("desolve.cc/invztrans")); + int dim=int(l.front()._VECTptr->size()); + if (!dim){ + l.erase(l.begin()); + dim=int(l.front()._VECTptr->size()); + } + gen r=e2r(res,l,contextptr); + res=0; + gen r_num,r_den; + fxnd(r,r_num,r_den); + if (r_num.type==_EXT) + return invztranserr(contextptr); + if (r_den.type!=_POLY) + return invztranserr(contextptr); + polynome den(*r_den._POLYptr),num(dim); + if (r_num.type==_POLY) + num=*r_num._POLYptr; + else + num=polynome(r_num,dim); + polynome p_content(lgcd(den)); + den=den/p_content; + factorization vden; gen an; + gen extra_div; + if (!cfactor(den,an,vden,true,extra_div)) + return invztranserr(contextptr); + vector< pf > pfde_VECT; + polynome ipnum(dim),ipden(dim); + partfrac(num,den,vden,pfde_VECT,ipnum,ipden); + if (!is_zero(ipnum)) + *logptr(contextptr) << gettext("Warning, z*argument has a non-zero integral part") << '\n'; + vector< pf >::iterator it=pfde_VECT.begin(); + vector< pf >::const_iterator itend=pfde_VECT.end(); + gen a,A,B; + polynome b,c; + for (;it!=itend;++it){ + if (it->fact.lexsorted_degree()>1) + return invztranserr(contextptr); + findde(it->fact,b,c); + a=-gen(c)/gen(b); // pole + B=r2e(Tfirstcoeff(it->den),l,contextptr); + if (is_zero(a)){ + int mult=it->mult; + gen res0; + vecteur vnum; + polynome2poly1(it->num,1,vnum); + vnum=mergevecteur(vecteur(mult-vnum.size(),0),vnum); + for (int i=0;inum/it->den in terms of 1/(z-a), a/(z-a)^2, a^2/(z-a)^3, etc. + gen cur=r2e(it->num,l,contextptr); + A=r2e(a,lprime,contextptr); + gen z_minus_a=x-A,res0; + for (int i=it->mult-1;i>=0;--i){ + gen tmp=_quorem(makesequence(cur,z_minus_a,x),contextptr); + if (is_undef(tmp)) return tmp; + gen rem=tmp[1]; + cur=tmp[0]; + rem=rem/pow(A,i,contextptr)/factorial(i); + for (int j=0;jfeuille,s,a,b,contextptr)){ + // res==A*Kronecker(a*x+b)+B + if (is_one(a) && is_zero(b)){ + gen B0=subst(B,s,0,false,contextptr); + if (is_zero(ratnormal(B0+A,contextptr))) + res=B*symbolic(at_Heaviside,s-1); + } + } + return res; + } + + gen _invztrans(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT) + return invztrans(args,vx_var,vx_var,contextptr); + vecteur & v=*args._VECTptr; + int s=int(v.size()); + if (s==2) + return invztrans( v[0],v[1],v[1],contextptr); + if (s!=3) + return gensizeerr(contextptr); + return invztrans( v[0],v[1],v[2],contextptr); + } + static const char _invztrans_s []="invztrans"; + static define_unary_function_eval (__invztrans,&_invztrans,_invztrans_s); + define_unary_function_ptr5( at_invztrans ,alias_at_invztrans,&__invztrans,0,true); + + gen _Kronecker(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type==_VECT) + return apply(args,_Kronecker,contextptr); + if (!is_integer(args)) + return symbolic(at_Kronecker,args); + if (is_zero(args)) + return 1; + else + return 0; + } + static const char _Kronecker_s []="Kronecker"; + static define_unary_function_eval (__Kronecker,&_Kronecker,_Kronecker_s); + define_unary_function_ptr5( at_Kronecker ,alias_at_Kronecker,&__Kronecker,0,true); + +#ifndef USE_GMP_REPLACEMENTS + // this code slice (c) 2018 Luka Marohniฤ‡ + /* returns the coefficient of t in (fraction, Taylor or Laurent) expansion e */ + gen expansion_coeff(const gen &e,const gen &t,GIAC_CONTEXT) { + gen ret(0),g; + if (e.is_symb_of_sommet(at_plus) && e._SYMBptr->feuille.type==_VECT) { + const vecteur &feu=*e._SYMBptr->feuille._VECTptr; + for (const_iterateur it=feu.begin();it!=feu.end();++it) { + g=_ratnormal(*it/t,contextptr); + if (_evalf(g,contextptr).type==_DOUBLE_) { + ret=g; + break; + } + } + } else { + g=_ratnormal(e/t,contextptr); + if (_evalf(g,contextptr).type==_DOUBLE_) + ret=g; + } + return ret; + } + + bool kovacic_iscase1(const vecteur &poles,int dinf) { + if (dinf%2!=0 && dinf<=2) + return false; + for (const_iterateur it=poles.begin();it!=poles.end();++it) { + int order=it->_VECTptr->back().val; + if (order%2!=0 && order!=1) + return false; + } + return true; + } + + bool kovacic_iscase2(const vecteur &poles) { + for (const_iterateur it=poles.begin();it!=poles.end();++it) { + int order=it->_VECTptr->back().val; + if (order==2 || (order>2 && order%2!=0)) + return true; + } + return false; + } + + bool kovacic_iscase3(const gen &cpfr,const gen &x,const vecteur &poles,int dinf,GIAC_CONTEXT) { + if (dinf<2) + return false; + vecteur alpha,beta; + gen a,b,g(0),p; + int d; + for (const_iterateur it=poles.begin();it!=poles.end();++it) { + p=it->_VECTptr->front(); + d=it->_VECTptr->back().val; + if (d>2) + return false; + if (d>1) { + alpha.push_back(a=expansion_coeff(cpfr,pow(x-p,-2),contextptr)); + g+=a; + a=_eval(sqrt(1+4*a,contextptr),contextptr); + if (!_numer(a,contextptr).is_integer() || !_denom(a,contextptr).is_integer()) + return false; + } + beta.push_back(b=expansion_coeff(cpfr,_inv(x-p,contextptr),contextptr)); + g+=b*p; + } + g=_eval(sqrt(1+4*g,contextptr),contextptr); + return is_zero(_ratnormal(_sum(beta,contextptr),contextptr)) && + _numer(g,contextptr).is_integer() && _denom(g,contextptr).is_integer(); + } + + void build_E_families(const gen_map &E,const vecteur &cv,vecteur &family,matrice &families) { + int i=family.size(); + if (i>=int(cv.size())) + return; + const vecteur ev=*E.find(cv[i])->second._VECTptr; + for (const_iterateur it=ev.begin();it!=ev.end();++it) { + family.push_back(*it); + if (family.size()==cv.size()) + families.push_back(family); + else build_E_families(E,cv,family,families); + family.pop_back(); + } + } + + void create_identifiers(vecteur &vars,int n) { + vars.reserve(n); + stringstream ss; + for (int i=0;ifeuille; + if (g.type==_SYMB) { + gen args; + if (g._SYMBptr->feuille.type==_VECT) { + args=vecteur(0); + const vecteur &feu=*g._SYMBptr->feuille._VECTptr; + for (const_iterateur it=feu.begin();it!=feu.end();++it) { + args._VECTptr->push_back(strip_abs(*it)); + } + } else args=strip_abs(g._SYMBptr->feuille); + return symbolic(g._SYMBptr->sommet,args); + } + return g; + } + + gen explnsimp(const gen &g,GIAC_CONTEXT) { + gen e=expand(strip_abs(g),contextptr); + e=symbolic(at_exp2pow,symbolic(at_expexpand,symbolic(at_lncollect,e))); + return ratnormal(_lin(_eval(e,contextptr),contextptr),contextptr); + } + + bool isroot(const gen &g,gen °,GIAC_CONTEXT) { + if (!g.is_symb_of_sommet(at_pow)) + return false; + const gen &pw=g._SYMBptr->feuille._VECTptr->at(1); + return (deg=_inv(pw,contextptr)).is_integer() && !is_minus_one(deg); + } + + void partialrad(const gen &g,const gen °,gen &outside,gen &inside,bool isdenom,GIAC_CONTEXT) { + gen s; + if (g.is_integer() && (s=_pow(makesequence(g,_inv(deg,contextptr)),contextptr)).is_integer()) { + outside=outside*(isdenom?_inv(s,contextptr):s); + } else if (g.is_symb_of_sommet(at_prod) && g._SYMBptr->feuille.type==_VECT) { + vecteur &fv=*g._SYMBptr->feuille._VECTptr,qr; + for (const_iterateur it=fv.begin();it!=fv.end();++it) { + if (it->is_integer()) { + s=_pow(makesequence(*it,_inv(deg,contextptr)),contextptr); + outside=outside*(isdenom?_inv(s,contextptr):s); + continue; + } else if (it->is_symb_of_sommet(at_pow)) { + const gen &pw=it->_SYMBptr->feuille._VECTptr->at(1); + const gen &b=it->_SYMBptr->feuille._VECTptr->front(); + if (pw.is_integer()) { + qr=*_iquorem(makesequence(pw,deg),contextptr)._VECTptr; + if (isdenom) { + outside=outside/_pow(makesequence(b,qr.front()),contextptr); + inside=inside/_pow(makesequence(b,qr.back()),contextptr); + } else { + outside=outside*_pow(makesequence(b,qr.front()),contextptr); + inside=inside*_pow(makesequence(b,qr.back()),contextptr); + } + continue; + } + } else if (it->is_symb_of_sommet(at_inv)) { + partialrad(it->_SYMBptr->feuille,deg,outside,inside,!isdenom,contextptr); + continue; + } + inside=inside*(isdenom?_inv(*it,contextptr):*it); + } + } else if (g.is_symb_of_sommet(at_inv)) + partialrad(g._SYMBptr->feuille,deg,outside,inside,!isdenom,contextptr); + else inside=inside*(isdenom?_inv(g,contextptr):g); + } + + gen radsimp(const gen &g,GIAC_CONTEXT) { + gen deg; + if (g.type==_VECT) { + vecteur ret; + for (const_iterateur it=g._VECTptr->begin();it!=g._VECTptr->end();++it) { + ret.push_back(radsimp(*it,contextptr)); + } + return change_subtype(ret,g.subtype); + } + if (isroot(g,deg,contextptr)) { + gen radic=_collect(radsimp(g._SYMBptr->feuille._VECTptr->front(),contextptr),contextptr); + gen inside(1),outside(1),inum; + partialrad(radic,deg,outside,inside,false,contextptr); + gen ideg=_inv(deg,contextptr); + inside=_eval(symb_normal(inside),contextptr); + if (!(inum=_eval(_pow(makesequence(_numer(inside,contextptr),ideg),contextptr),contextptr)).is_symb_of_sommet(at_pow) || + inum._SYMBptr->feuille._VECTptr->at(1).is_integer()) + return _collect(outside,contextptr)*inum/_pow(makesequence(_collect(_denom(inside,contextptr),contextptr),ideg),contextptr); + return _collect(outside,contextptr)*_pow(makesequence(_collect(inside,contextptr),ideg),contextptr); + } + if (g.is_symb_of_sommet(at_prod) && g._SYMBptr->feuille.type==_VECT) { + vecteur &feu=*g._SYMBptr->feuille._VECTptr,degv; + gen den(1); + for (const_iterateur it=feu.begin();it!=feu.end();++it) { + if (it->is_symb_of_sommet(at_pow)) { + gen dg=_inv(it->_SYMBptr->feuille._VECTptr->at(1),contextptr); + if (is_greater(dg,2,contextptr)) + degv.push_back(dg); + } else if (it->is_symb_of_sommet(at_inv)) + den=den*it->_SYMBptr->feuille; + } + if (den.is_symb_of_sommet(at_prod) && den._SYMBptr->feuille.type==_VECT) { + vecteur &dfeu=*den._SYMBptr->feuille._VECTptr; + for (const_iterateur it=dfeu.begin();it!=dfeu.end();++it) { + if (it->is_symb_of_sommet(at_pow)) { + gen dg=_inv(it->_SYMBptr->feuille._VECTptr->at(1),contextptr); + if (is_greater(dg,2,contextptr)) + degv.push_back(dg); + } + } + } + gen gd=_lcm(degv,contextptr); + gen p=_collect(ratnormal(pow(g,gd.val),contextptr),contextptr); + if (p.is_symb_of_sommet(at_pow)) { + gen ppw=p._SYMBptr->feuille._VECTptr->at(1); + if (ppw.is_integer()) + gd=_eval(gd/ppw,contextptr); + } + gen ret=_pow(makesequence(p,_inv(gd,contextptr)),contextptr); + return isroot(ret,deg,contextptr)?radsimp(ret,contextptr):ratnormal(ret,contextptr); + } + if (g.type==_SYMB) { + gen &feu=g._SYMBptr->feuille; + if (feu.type==_VECT) { + vecteur res; + for (const_iterateur it=feu._VECTptr->begin();it!=feu._VECTptr->end();++it) { + res.push_back(radsimp(*it,contextptr)); + } + return symbolic(g._SYMBptr->sommet,change_subtype(res,feu.subtype)); + } + return symbolic(g._SYMBptr->sommet,radsimp(feu,contextptr)); + } + return g; + } + + vecteur strip_gcd(const vecteur &v,GIAC_CONTEXT) { + gen g1=_gcd(_apply(makesequence(at_numer,v),contextptr),contextptr); + gen g2=_gcd(_apply(makesequence(at_denom,v),contextptr),contextptr); + return *_collect(_ratnormal(multvecteur(g2/g1,v),contextptr),contextptr)._VECTptr; + } + + gen ratsimp_nonexp(const gen &g,GIAC_CONTEXT) { + if (g.type==_VECT) { + vecteur res; + for (const_iterateur it=g._VECTptr->begin();it!=g._VECTptr->end();++it) { + res.push_back(ratsimp_nonexp(*it,contextptr)); + } + return change_subtype(res,g.subtype); + } + if (g.is_symb_of_sommet(at_plus) && g._SYMBptr->feuille==_VECT) { + vecteur &terms=*g._SYMBptr->feuille._VECTptr; + gen res(0); + for (const_iterateur it=terms.begin();it!=terms.end();++it) { + res+=ratsimp_nonexp(*it,contextptr); + } + return res; + } + if (g.is_symb_of_sommet(at_prod) && g._SYMBptr->feuille.type==_VECT) { + vecteur &facs=*g._SYMBptr->feuille._VECTptr; + gen e(1),ne(1); + for (const_iterateur it=facs.begin();it!=facs.end();++it) { + if (it->is_symb_of_sommet(at_exp)) + e=*it*e; + else ne=*it*ne; + } + return _ratnormal(ne,contextptr)*e; + } + return g; + } + + gen fullsimp(const gen &g,GIAC_CONTEXT) { + return ratsimp_nonexp(_collect(radsimp(explnsimp(exp(_ratnormal(g,contextptr),contextptr), + contextptr),contextptr),contextptr),contextptr); + } + + /* + * This routine solves the general homogeneous linear second-order ODE + * y''=r(t)*y, where r is a non-constant rational function, using Kovacic's + * algorithm (https://core.ac.uk/download/pdf/82509765.pdf). A list of + * solutions is returned (possibly empty). + */ + gen kovacicsols(const gen &r_orig,const gen &x,const gen &dy_coeff,GIAC_CONTEXT) { + gen r=_ratnormal(r_orig,contextptr),inf=symbolic(at_plus,_IDNT_infinity()); + gen s=_numer(r,contextptr),t=_denom(r,contextptr),a,b,c,e,w=identificateur("omega_"); + int ds=_degree(makesequence(s,x),contextptr).val; + int dt=_degree(makesequence(t,x),contextptr).val,dinf=dt-ds,order,nu; + vecteur poles=*_roots(makesequence(t,x),contextptr)._VECTptr,solutions(0); + gen cpfr=_cpartfrac(makesequence(r,x),contextptr); + gen laur=_series(makesequence(r,x,inf,1,_POLY1__VECT),contextptr); + bool success=false; + if (kovacic_iscase1(poles,dinf)) { + //cerr << "Case 1 of Kovacic algorithm" << '\n'; + /* step 1 */ + gen_map alpha_plus,alpha_minus,sqrt_r; + gen alpha_inf_plus,alpha_inf_minus; + for (const_iterateur it=poles.begin();it!=poles.end();++it) { + c=it->_VECTptr->front(); + order=it->_VECTptr->back().val; + if (order==1) { + sqrt_r[c]=0; + alpha_plus[c]=alpha_minus[c]=1; + } else if (order==2) { + sqrt_r[c]=0; + b=expansion_coeff(cpfr,pow(x-c,-2),contextptr); + alpha_plus[c]=(1+sqrt(1+4*b,contextptr))/2; + alpha_minus[c]=(1-sqrt(1+4*b,contextptr))/2; + } else if (order%2==0 && order>=4) { + nu=order/2; + e=_series(makesequence(sqrt(r,contextptr),x,c,1,_POLY1__VECT),contextptr); + for (int i=2;i<=nu;++i) { + gen cf=expansion_coeff(e,pow(x-c,-i),contextptr); + if (i==nu) + a=cf; + sqrt_r[c]+=cf/pow(x-c,i); + } + if (is_zero(a)) + return false; + b=expansion_coeff(cpfr,pow(x-c,-nu-1),contextptr); + b-=expansion_coeff(_cpartfrac(makesequence(sq(sqrt_r[c]),x),contextptr),pow(x-c,-nu-1),contextptr); + alpha_plus[c]=(nu+b/a)/2; + alpha_minus[c]=(nu-b/a)/2; + } else assert(false); + } + if (dinf>2) { + sqrt_r[inf]=0; + alpha_inf_plus=0; + alpha_inf_minus=1; + } else if (dinf==2) { + sqrt_r[inf]=0; + b=_lcoeff(makesequence(s,x),contextptr)/_lcoeff(makesequence(t,x),contextptr); + alpha_inf_plus=(1+sqrt(1+4*b,contextptr))/2; + alpha_inf_minus=(1-sqrt(1+4*b,contextptr))/2; + } else if (dinf%2==0 && dinf<=0) { + nu=-dinf/2; + e=_series(makesequence(sqrt(r,contextptr),x,inf,1,_POLY1__VECT),contextptr); + for (int i=0;i<=nu;++i) { + gen cf=expansion_coeff(e,pow(x,i),contextptr); + if (i==nu) + a=cf; + sqrt_r[inf]+=cf*pow(x,i); + } + if (is_zero(a)) + return false; + b=expansion_coeff(_propfrac(makesequence(r,x),contextptr),pow(x,nu-1),contextptr); + b-=expansion_coeff(expand(sq(sqrt_r[inf]),contextptr),pow(x,nu-1),contextptr); + alpha_inf_plus=(b/a-nu)/2; + alpha_inf_minus=(-b/a-nu)/2; + } else assert(false); + /* step 2 */ + int np=poles.size()+1,N=(1<first); + } + for (int i=0;i_VECTptr->front().val; fw=it->_VECTptr->back(); + v=vecteur(vars.begin(),vars.begin()+d); + P=0; + for (int i=0;iempty()) { + lsol=_subst(makesequence(lsol._VECTptr->front(),v,vecteur(d,0)),contextptr); + solutions.push_back(_subst(makesequence(P,v,lsol),contextptr)* + fullsimp(_int(makesequence(fw-dy_coeff/2,x),contextptr),contextptr)); + success=true; + } + } + } + if (!success && kovacic_iscase2(poles)) { + //cerr << "Case 2 of Kovacic algorithm" << '\n'; + /* step 1 */ + gen_map E; + for (const_iterateur it=poles.begin();it!=poles.end();++it) { + c=it->_VECTptr->front(); + order=it->_VECTptr->back().val; + if (order==1) + E[c]=vecteur(1,4); + else if (order==2) { + b=expansion_coeff(cpfr,pow(x-c,-2),contextptr); + E[c]=vecteur(0); + for (int k=-1;k<=1;++k) { + gen tmp=_eval(2+2*k*sqrt(1+4*b,contextptr),contextptr); + if (tmp.is_integer()) + E[c]._VECTptr->push_back(tmp); + } + } else if (order>2) + E[c]=vecteur(1,order); + } + vecteur Einf(0); + if (dinf>2) + Einf=makevecteur(0,2,4); + else if (dinf==2) { + b=expansion_coeff(laur,pow(x,-2),contextptr); + for (int k=-1;k<=1;++k) { + gen tmp=_eval(2+2*k*sqrt(1+4*b,contextptr),contextptr); + if (tmp.is_integer()) + Einf.push_back(tmp); + } + } else if (dinf<2) + Einf.push_back(dinf); + /* step 2 */ + vecteur family,families,fam,cv,vars,v; + for (gen_map::const_iterator it=E.begin();it!=E.end();++it) { + cv.push_back(it->first); + } + build_E_families(E,cv,family,families); + int maxdeg=0,deg; + for (const_iterateur it=Einf.begin();it!=Einf.end();++it) { + if (families.empty()) { + e=*it/2; + if (e.is_integer() && is_positive(e,contextptr)) { + fam.push_back(makevecteur(e,0)); + maxdeg=std::max(maxdeg,e.val); + } + } + for (const_iterateur jt=families.begin();jt!=families.end();++jt) { + gen th(0); + bool discard=is_one(_even(*it,contextptr)); + const vecteur &fm=*(jt->_VECTptr); + for (const_iterateur kt=fm.begin();kt!=fm.end();++kt) { + th+=(*kt)/(x-cv[kt-fm.begin()]); + if (is_zero(_even(*kt,contextptr))) + discard=false; + } + //if (discard) continue; + e=_eval(*it-_sum(fm,contextptr),contextptr)/2; + if (e.is_integer() && is_positive(e,contextptr)) { + fam.push_back(makevecteur(e,th/2)); + maxdeg=std::max(maxdeg,e.val); + } + } + } + /* step 3 */ + create_identifiers(vars,maxdeg); + gen P,th,dth; + for (const_iterateur it=fam.begin();it!=fam.end() && !success;++it) { + deg=it->_VECTptr->front().val; th=it->_VECTptr->back(); + v=vecteur(vars.begin(),vars.begin()+deg); + P=0; + for (int i=0;iempty())) { + if (deg>0) { + cfs=_subst(makesequence(cfs._VECTptr->front(),v,vecteur(deg,0)),contextptr); + P=_subst(makesequence(P,v,cfs),contextptr); + } + gen ph=th+_derive(makesequence(P,x),contextptr)/P; + gen qsol=_solve(makesequence(symb_equal(sq(w)-w*ph+(_derive(makesequence(ph,x),contextptr)/2+sq(ph)/2-r),0),w),contextptr); + if (qsol.type==_VECT) for (const_iterateur jt=qsol._VECTptr->begin();jt!=qsol._VECTptr->end();++jt) { + solutions.push_back(fullsimp(_int(makesequence(*jt-dy_coeff/2,x),contextptr),contextptr)); + success=true; + } + } + } + } + if (!success && kovacic_iscase3(cpfr,x,poles,dinf,contextptr)) { + //cerr << "Case 3 of Kovacic algorithm" << '\n'; + vector nv=vecteur_2_vector_int(makevecteur(4,6,12)); + for (vector::const_iterator nt=nv.begin();nt!=nv.end();++nt) { + int n=*nt; + /* step 1 */ + gen_map E; + for (const_iterateur it=poles.begin();it!=poles.end();++it) { + c=it->_VECTptr->front(); + order=it->_VECTptr->back().val; + if (order==1) + E[c]=vecteur(1,12); + else if (order==2) { + a=expansion_coeff(cpfr,pow(x-c,-2),contextptr); + E[c]=vecteur(0); + for (int k=-n/2;k<=n/2;++k) { + gen tmp=_eval(6+k*(12/n)*sqrt(1+4*a,contextptr),contextptr); + if (tmp.is_integer()) + E[c]._VECTptr->push_back(tmp); + } + } + } + vecteur Einf(0); + b=dinf>2?gen(0):expansion_coeff(laur,pow(x,-2),contextptr); + for (int k=-n/2;k<=n/2;++k) { + gen tmp=_eval(6+k*(12/n)*sqrt(1+4*b,contextptr),contextptr); + if (tmp.is_integer()) + Einf.push_back(tmp); + } + /* step 2 */ + vecteur family,families,fam,cv,vars,v; + for (gen_map::const_iterator it=E.begin();it!=E.end();++it) { + cv.push_back(it->first); + } + build_E_families(E,cv,family,families); + int maxdeg=0,deg; + for (const_iterateur it=Einf.begin();it!=Einf.end();++it) { + if (families.empty()) { + e=*it*gen(n)/12; + if (e.is_integer() && is_positive(e,contextptr)) { + fam.push_back(makevecteur(e,0)); + maxdeg=std::max(maxdeg,e.val); + } + } + for (const_iterateur jt=families.begin();jt!=families.end();++jt) { + gen th(0); + const vecteur &fm=*(jt->_VECTptr); + for (const_iterateur kt=fm.begin();kt!=fm.end();++kt) { + th+=(*kt)/(x-cv[kt-fm.begin()]); + } + e=gen(n)*_eval(*it-_sum(*jt,contextptr),contextptr)/12; + if (e.is_integer() && is_positive(e,contextptr)) { + fam.push_back(makevecteur(e,gen(n)*th/12)); + maxdeg=std::max(maxdeg,e.val); + } + } + } + /* step 3 */ + gen S(1); + for (const_iterateur it=cv.begin();it!=cv.end();++it) { + S=S*(x-*it); + } + gen dS=_derive(makesequence(S,x),contextptr),th; + vecteur P(n+2,0); + create_identifiers(vars,maxdeg); + for (const_iterateur it=fam.begin();it!=fam.end();++it) { + deg=it->_VECTptr->front().val; th=it->_VECTptr->back(); + v=vecteur(vars.begin(),vars.begin()+deg); + for (int i=0;i0;) { + P[i]=-S*_derive(makesequence(P[i+1],x),contextptr)+((n-i)*dS-S*th)*P[i+1]-(n-i)*(i+1)*sq(S)*r*P[i+2]; + if (P[i].type==_SYMB) P[i]=_collect(P[i],contextptr); + } + gen cfs; + if ((deg==0 && is_zero(P[0])) || + (deg>0 && (cfs=_solve(makesequence(_coeff(makesequence(P[0],x),contextptr),v),contextptr)).type==_VECT && + !cfs._VECTptr->empty())) { + if (deg>0) { + cfs=_subst(makesequence(cfs._VECTptr->front(),v,vecteur(deg,0)),contextptr); + P=*_subst(makesequence(P,v,cfs),contextptr)._VECTptr; + } + vecteur ac(n+1); + for (int i=0;i<=n;++i) { + ac[i]=_collect(pow(S,i)*P[i+1]/_factorial(n-i,contextptr),contextptr); + } + //*logptr(contextptr) << "Warning: outputting the algebraic expression for ฯ‰" << '\n'; + ac=strip_gcd(ac,contextptr); + gen omg=pow(w,4)*ac[4]+pow(w,3)*ac[3]+pow(w,2)*ac[2]+w*ac[1]+ac[0]; + if (!is_zero(dy_coeff)) { + vecteur C=*_coeff(makesequence(_subst(makesequence(omg,w,w+dy_coeff/2),contextptr),w),contextptr)._VECTptr; + for (int i=0;i<=n;++i) { + ac[i]=_collect(_ratnormal(C[i],contextptr),contextptr); + } + ac=strip_gcd(ac,contextptr); + omg=pow(w,4)*ac[4]+pow(w,3)*ac[3]+pow(w,2)*ac[2]+w*ac[1]+ac[0]; + } + return omg; + } + } + } + } + return solutions; + } + + /* + * Return the solution(s) of a second-order linear homogeneous ODE using + * Kovacic's algorithm. The first argument is the ODE a(x)*y''+b(x)*y'+c(x)*y=0 + * itself, which may be given as an expression (left-hand side), an equation or + * a list [a,b,c]. The functions a, b and c must be rational in x. The second + * and third (both optional) arguments are the independent variable x and the + * dependent variable y, respectively. By default, the symbols "x" and "y" are + * used. + */ + gen _kovacicsols(const gen &g,GIAC_CONTEXT) { + if (g.type==_STRNG && g.subtype==-1) return g; + gen x=identificateur("x"),y=identificateur("y"),eq,p(0),q(0),r(0); + if (g.type!=_VECT || g.subtype!=_SEQ__VECT) { + eq=g; + } else if (g.subtype==_SEQ__VECT) { + vecteur &gv=*g._VECTptr; + if (gv.size()<2) return gensizeerr(contextptr); + eq=gv.front(); + if (gv.size()==2) { + if (eq.type==_VECT && gv.back().type==_IDNT) + x=gv.back(); + else if (gv.back().is_symb_of_sommet(at_of)) { + y=gv.back()._SYMBptr->feuille._VECTptr->front(); + x=gv.back()._SYMBptr->feuille._VECTptr->back(); + } else return gensizeerr(contextptr); + } else { + if (eq.type==_VECT) + return gensizeerr(contextptr); + x=gv[1]; + y=gv[2]; + } + if (y.type!=_IDNT || x.type!=_IDNT) + return gensizeerr(contextptr); + } + eq=idnteval(eq,contextptr); + if (eq.type==_VECT) { + vecteur &cfs=*eq._VECTptr; + if (cfs.size()!=3) + return gensizeerr(contextptr); + p=cfs[1]; q=cfs[2]; r=cfs[0]; + } else if (eq.type==_SYMB) { + gen dy=identificateur(" dy"),d2y=identificateur(" d2y"),yx=symb_of(y,x); + gen diffy=symbolic(at_derive,y),diff2y=symbolic(at_derive,diffy); + eq=_subst(makesequence(eq,makevecteur(_derive(makesequence(yx,x),contextptr),_derive(makesequence(yx,x,2),contextptr)), + makevecteur(dy,d2y)),contextptr); + eq=_subst(makesequence(_subst(makesequence(_subst(makesequence(eq,diff2y,d2y),contextptr),diffy,dy),contextptr),yx,y),contextptr); + if (eq.is_symb_of_sommet(at_equal)) + eq=equal2diff(eq); + eq=expand(eq,contextptr); + vecteur terms=eq.is_symb_of_sommet(at_plus) && eq._SYMBptr->feuille.type==_VECT? + *eq._SYMBptr->feuille._VECTptr:vecteur(1,eq); + gen tmp; + vecteur yvars=makevecteur(y,dy,d2y); + for (const_iterateur it=terms.begin();it!=terms.end();++it) { + if (is_constant_wrt_vars(tmp=_ratnormal(*it/y,contextptr),yvars,contextptr)) + q+=tmp; + else if (is_constant_wrt_vars(tmp=_ratnormal(*it/dy,contextptr),yvars,contextptr)) + p+=tmp; + else if (is_constant_wrt_vars(tmp=_ratnormal(*it/d2y,contextptr),yvars,contextptr)) + r+=tmp; + else return gensizeerr(contextptr); + } + } else return gensizeerr(contextptr); + if (is_zero(r)) // not a second order ODE + return gensizeerr(contextptr); + p=_ratnormal(p/r,contextptr); + q=_ratnormal(q/r,contextptr); + if (rlvarx(p,x).size()+rlvarx(q,x).size()>2) // p or q is not rational in x + return gensizeerr(contextptr); + /* solve the equation y''+p(x)*y'+q(x)*y=0, transform it first to z''=r(x)*z */ + r=sq(p)/4+_derive(makesequence(p,x),contextptr)/2-q; + return kovacicsols(r,x,p,contextptr); + } + static const char _kovacicsols_s []="kovacicsols"; + static define_unary_function_eval_quoted (__kovacicsols,&_kovacicsols,_kovacicsols_s); + define_unary_function_ptr5(at_kovacicsols,alias_at_kovacicsols,&__kovacicsols,_QUOTE_ARGUMENTS,true) + + /* + * Return true iff the expression 'e' is constant with respect to + * variables in 'vars'. + */ + bool is_constant_wrt_vars(const gen &e,const vecteur &vars,GIAC_CONTEXT) { + for (const_iterateur it=vars.begin();it!=vars.end();++it) { + if (!is_constant_wrt(e,*it,contextptr)) + return false; + } + return true; + } + + gen idnteval(const gen &g,GIAC_CONTEXT) { + if (g.type==_IDNT) + return _eval(g,contextptr); + if (g.type==_SYMB) { + gen &feu=g._SYMBptr->feuille; + if (feu.type==_VECT) { + vecteur v; + for (const_iterateur it=feu._VECTptr->begin();it!=feu._VECTptr->end();++it) { + v.push_back(idnteval(*it,contextptr)); + } + return symbolic(g._SYMBptr->sommet,change_subtype(v,feu.subtype)); + } + return symbolic(g._SYMBptr->sommet,idnteval(feu,contextptr)); + } + return g; + } + +#endif + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/ezgcd.cc b/android/app/src/main/cpp/giac/src/giac/cpp/ezgcd.cc new file mode 100644 index 0000000..2ecc571 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/ezgcd.cc @@ -0,0 +1,1655 @@ +/* -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -I../include -g -c ezgcd.cc -DHAVE_CONFIG_H -DIN_GIAC" -*- */ + +#include "giacPCH.h" +/* Multivariate GCD for large data not covered by the heuristic GCD algo + * Copyright (C) 2000,7 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using namespace std; +#include "threaded.h" +#include "ezgcd.h" +#include "sym2poly.h" +#include "gausspol.h" +#include "modpoly.h" +#include "monomial.h" +#include "derive.h" +#include "subst.h" +#include "solve.h" +#include "giacintl.h" + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + static void add_dim(monomial & m,int d){ + index_t i(m.index.iref()); + for (int j=0;j >::iterator it=p.coord.begin(),itend=p.coord.end(); + if (p.dim>=dim){ + p.dim=dim; + for (;it!=itend;++it){ + it->index=index_t(it->index.begin(),it->index.begin()+dim); + } + return; + } + int delta_dim=dim-p.dim; + p.dim=dim; + for (;it!=itend;++it) + add_dim(*it,delta_dim); + } + + // returns q such that p=q [degree] and q has only terms of degree= degree + polynome res(p.dim); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (total_degree(it->index)(res,0,p.dim)); + } + polynome pcur(p); + polynome y(monomial(plus_one,1,1,p.dim)); + if (!is_zero(v.front())) + y.coord.push_back(monomial(-v.front(),0,1,p.dim)); + polynome quo(y.dim),rem(y.dim); + pcur.TDivRem1(y,quo,rem); + rem=reduce(rem.trunc1(),vecteur(v.begin()+1,v.end()),degree); + quo=reduce(quo,v,degree-1); + return quo*y+rem.untrunc1(); + } + + static void reduce_poly(const polynome & p,const vecteur & v,int degree,polynome & res){ + res.coord.clear(); + res.dim=p.dim; + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + if (is_zero(v)){ + index_t::const_iterator jt,jtend; + int otherdeg; + for (;it!=itend;++it){ + jt=it->index.begin()+1; + jtend=it->index.end(); + for (otherdeg=0;jt!=jtend;++jt){ + otherdeg += *jt; + } + if (otherdegindex.front(); + polynome tmp(Tnextcoeff(it,itend)); + res=res+reduce(tmp,v,degree).untrunc1(d); + } + } + } + + // Same as reduce but do it for every coefficient of p with + // respect to the main variable + polynome reduce_poly(const polynome & p,const vecteur & v,int degree){ + polynome res(p.dim); + reduce_poly(p,v,degree,res); + return res; + } + + // reduce_divrem does a mixed division: euclidean w.r.t. the first var + // and ascending power of X-v for the other vars + // FIXME: this implementation does not work currently, except if other + // depends only on the first var + static bool reduce_divrem2(const polynome & a,const polynome & other,const vecteur & v,int n,polynome & quo,polynome & rem,bool allowrational=false) { + int asize=int(a.coord.size()); + if (!asize){ + quo=a; + rem=a; + return true; + } + int bsize=int(other.coord.size()); + if (bsize==0) { +#ifdef NO_STDEXCEPT + return false; +#else + setsizeerr(gettext("ezgcd.cc/reduce_divrem2")); +#endif + } + index_m a_max = a.coord.front().index; + index_m b_max = other.coord.front().index; + quo.coord.clear(); + quo.dim=a.dim; + rem.dim=a.dim; + if ( (bsize==1) && (b_max==b_max*0) ){ + rem.coord.clear(); + gen b=other.coord.front().value; + if (is_one(b)) + quo = a ; + else { + std::vector< monomial >::const_iterator itend=a.coord.end(); + for (std::vector< monomial >::const_iterator it=a.coord.begin();it!=itend;++it) + quo.coord.push_back(monomial(rdiv(it->value,b,context0),it->index)); + } + return true; + } + rem=a; + if ( ! (a_max>=b_max) ){ + // test that the first power of a_max is < to that of b_max + return (a_max.front()= b_max){ + // errors should be trapped here and false returned if error occured + gen q(rdiv(rem.coord.front().value,b,context0)); + if (!allowrational){ + if ( has_denominator(q) || + (!is_zero(q*b - rem.coord.front().value)) ) + return false; + } + // end error trapping + quo.coord.push_back(monomial(q,a_max-b_max)); + tensor temp; + reduce_poly(other.shift(a_max-b_max,q),v,n,temp); + rem = rem-temp; + if (rem.coord.size()) + a_max=rem.coord.front().index; + else + break; + } + return(true); + } + + bool reduce_divrem(const polynome & a,const polynome & other,const vecteur & v,int n,polynome & quo,polynome & rem) { + quo.coord.clear(); + quo.dim=a.dim; + rem.dim=a.dim; + // if ( (a.dim<=1) || (a.coord.empty()) ) + return reduce_divrem2(a,other,v,n,quo,rem); +#if 0 + std::vector< monomial >::const_iterator it=other.coord.begin(); + int bdeg=it->index.front(),rdeg; + tensor b0(Tnextcoeff(it,other.coord.end())); + tensor r(a),q(b0.dim); + while ( (rdeg=r.lexsorted_degree()) >=bdeg){ + it=r.coord.begin(); + tensor a0(Tnextcoeff(it,r.coord.end())),tmp(a0.dim); + // FIXME: should make ascending power division + if (!reduce_divrem(a0,b0,v,n,q,tmp) || !tmp.coord.empty()) + return false; + q=q.untrunc1(rdeg-bdeg); + quo=quo+q; + r=r-reduce_poly(q*other,v,n); + if (r.coord.empty()) + return true; + } + return true; +#endif + } + + // increment last index in v up to k, + // if last index is k-1 + // while index[size-pos] is k-pos increment pos + // if pos reaches size return false (not possible anymore) + // else increment index[size-pos] and set following ones to prev+1 + static bool next(vector & v,int dim,int k){ + ++v.back(); + if (v.back()!=k) + return true; + int pos=2; + for (;pos<=dim;++pos){ + if (v[dim-pos]!=k-pos) + break; + } + if (pos>dim) + return false; + ++v[dim-pos]; + for (--pos;pos>0;--pos){ + v[dim-pos]=v[dim-pos-1]+1; + } + return true; + } + + // pcur(x1,...,xk,0,...,0) + static void peval_xk_xn_zero(const polynome & pcur,int k,polynome & pcurx1x2){ + pcurx1x2.coord.clear(); + int dim=pcur.dim; + pcurx1x2.dim=dim; + vector< monomial >::const_iterator it=pcur.coord.begin(),itend=pcur.coord.end(); + for (;it!=itend;++it){ + int j=k; + index_t::const_iterator i = it->index.begin()+j; + for (;j >::iterator it=pcur.coord.begin(),itend=pcur.coord.end(); + for (;it!=itend;++it){ + it->index=index_t(it->index.begin(),it->index.begin()+k); + } + pcur.dim=k; + } + + static void untruncate_xk_xn(polynome & pcur,int dim){ + vector< monomial >::iterator it=pcur.coord.begin(),itend=pcur.coord.end(); + for (;it!=itend;++it){ + index_t i (dim); + i=it->index.iref(); + for (int j=int(i.size());jindex = i; + } + pcur.dim=dim; + } + + gen _coeff(const gen &,GIAC_CONTEXT); + + polynome divbylgcd(const polynome &p){ + polynome other(lgcd(p)),rem(p.dim),quo(p.dim); + if (!divrem1(p,other,quo,rem)){ + if (!divrem1(p,other,quo,rem,false,true)){ + CERR << "try_hensel_lift_factor bug \n"; + return p; + } + else { + gen den=1; lcmdeno(quo,den); + quo=den*quo; + return quo; + } + } + else + return quo; + } + + bool try_sparse_factor(const polynome & pcur,const factorization & v,int mult,factorization & f){ + /* Try sparse factorization + lcoeff(pcur,x1)^#factors-1 * pcur = product_#factors P_i + where P_i has lcoeff(pcur,x1) as leading coeff in x1 + and same non zeros coeffs pattern as the factors of Fb + */ + // count number of unknowns + factorization::const_iterator vit=v.begin(),vitend=v.end(); + int unknowns=0; + for (;vit!=vitend;++vit){ + if (vit->mult>1) + break; // return false might be more appropriate here + unknowns += int(vit->fact.coord.size())-1; // lcoeff is known + } + if (unknowns>=giacmax(5,pcur.lexsorted_degree()/2) || unknowns==0) + return false; + polynome lcp(Tfirstcoeff(pcur)); + int dim=pcur.dim; + vecteur lv(dim); + for (int i=0;ifact; + vector< monomial >::const_iterator it=fact.coord.begin(),itend=fact.coord.end(); + gen Pi=lc*pow(mainvar,it->index.front()); + for (++it;it!=itend;++it){ + if (pos>=la.size()) + return false; + Pi += la[pos]*pow(mainvar,it->index.front()); + ++pos; + } + Pis.push_back(Pi); + product = product * Pi; + } + product=product-r2sym(pcur,lv,context0)*pow(lc,int(Pis.size())-1,context0); + // solve equation wrt la + gen systemeg=_coeff(gen(makevecteur(product,mainvar),_SEQ__VECT),context0); + if (systemeg.type!=_VECT || systemeg._VECTptr->empty()) + return false; + vecteur syst; + const_iterateur it=systemeg._VECTptr->begin(),itend=systemeg._VECTptr->end(); + for (++it;it!=itend;++it){ + if (!is_zero(*it)) + syst.push_back(*it); + } + gen first=systemeg._VECTptr->front(); + // to solve syst wrt la, we search all linear equations + // if none return false, otherwise solve system, subst + while (!syst.empty()){ + int N=int(syst.size()); + vecteur linear; + for (int i=0;ibegin(),itend=tmp._VECTptr->end(); + for (;it!=itend;++it){ + if (!is_zero(*it)) + syst.push_back(*it); + } + } + first=recursive_normal(first,context0); + if (!is_zero(first)) + return false; + // subst la values + Pis=subst(Pis,la,la_val,false,context0); + for (unsigned int i=0;i6) then print(j); fi; od; fails at j:14342 + + return false; + const polynome & N=*num._POLYptr; + f.push_back(facteur(divbylgcd(N),mult)); + } + return true; + } + + // pcur(x,x1,x2,...) with [x1,x2,...]=[t^n1,t^n2,...] + void eval_tn(const polynome & pcur,const index_t & n,polynome & pt){ + pt.dim=2; + pt.coord.clear(); + pt.coord.reserve(pcur.coord.size()); + vector< monomial >::const_iterator it=pcur.coord.begin(),itend=pcur.coord.end(); + index_t cur(2); + for (;it!=itend;++it){ + const index_t & i=it->index.iref(); + index_t::const_iterator jt=i.begin(),jtend=i.end(); + index_t::const_iterator nt=n.begin(); + cur[0]=*jt; + int curn=0; + for (++jt;jt!=jtend;++jt,++nt) + curn += (*jt)*(*nt); + cur[1]=curn; + pt.coord.push_back(monomial(it->value,cur)); + } + pt.tsort(); + // Fix 2020 dec 4 for E:=c1^6*x2^5-c2^5*x1^6-c2^5*x2^6+c2^6*x2^5-4*b*c1^5*x2^5+2*b*c2^5*x1^5+7*b^2*c1^4*x2^5+b^2*c1^6*x2^3-2*b^2*c2^3*x1^6-2*b^2*c2^3*x2^6+3*b^2*c2^4*x2^5-2*b^2*c2^5*x2^4+b^2*c2^6*x2^3-6*b^3*c1^3*x2^5-2*b^3*c1^5*x2^3+2*b^3*c2^3*x1^5-2*b^3*c2^5*x1^3+2*b^4*c1^2*x2^5+b^4*c1^4*x2^3-2*b^4*c2^2*x2^5+2*b^4*c2^3*x1^4+4*b^4*c2^3*x2^4-3*b^4*c2^4*x2^3+b^4*c2^5*x1^2+b^4*c2^5*x2^2-2*b^5*c2^3*x1^3-2*c1^2*c2^3*x1^6-2*c1^2*c2^3*x2^6+3*c1^2*c2^4*x2^5-c1^4*c2*x1^6-c1^4*c2*x2^6+3*c1^4*c2^2*x2^5+2*c1^6*x1^2*x2^3+c1^6*x1^4*x2-3*c2^5*x1^2*x2^4-3*c2^5*x1^4*x2^2+2*c2^6*x1^2*x2^3+c2^6*x1^4*x2+4*b*c1*c2^3*x1^6+4*b*c1*c2^3*x2^6-4*b*c1*c2^4*x2^5+4*b*c1^2*c2^3*x1^5+4*b*c1^3*c2*x1^6+4*b*c1^3*c2*x2^6-8*b*c1^3*c2^2*x2^5+2*b*c1^4*c2*x1^5-8*b*c1^5*x1^2*x2^3-4*b*c1^5*x1^4*x2-2*b*c1^6*x1*x2^3-2*b*c1^6*x1^3*x2+2*b*c2^5*x1*x2^4+4*b*c2^5*x1^3*x2^2-2*b*c2^6*x1*x2^3-2*b*c2^6*x1^3*x2-8*b^2*c1*c2^3*x1^5-6*b^2*c1^2*c2*x1^6-6*b^2*c1^2*c2*x2^6+10*b^2*c1^2*c2^2*x2^5-4*b^2*c1^2*c2^3*x2^4+3*b^2*c1^2*c2^4*x2^3-8*b^2*c1^3*c2*x1^5-2*b^2*c1^4*c2*x2^4+3*b^2*c1^4*c2^2*x2^3+14*b^2*c1^4*x1^2*x2^3+7*b^2*c1^4*x1^4*x2+6*b^2*c1^5*x1*x2^3+6*b^2*c1^5*x1^3*x2+b^2*c1^6*x1^2*x2-6*b^2*c2^3*x1^2*x2^4-6*b^2*c2^3*x1^4*x2^2+6*b^2*c2^4*x1^2*x2^3+3*b^2*c2^4*x1^4*x2-2*b^2*c2^5*x1^2*x2^2+b^2*c2^6*x1^2*x2+4*b^3*c1*c2*x1^6+4*b^3*c1*c2*x2^6-6*b^3*c1*c2^2*x2^5+4*b^3*c1*c2^3*x1^4+4*b^3*c1*c2^3*x2^4-2*b^3*c1*c2^4*x2^3+10*b^3*c1^2*c2*x1^5-4*b^3*c1^2*c2^3*x1^3+4*b^3*c1^3*c2*x1^4+4*b^3*c1^3*c2*x2^4-4*b^3*c1^3*c2^2*x2^3-12*b^3*c1^3*x1^2*x2^3-6*b^3*c1^3*x1^4*x2-2*b^3*c1^4*c2*x1^3-8*b^3*c1^4*x1*x2^3-8*b^3*c1^4*x1^3*x2-2*b^3*c1^5*x1^2*x2+2*b^3*c2^3*x1*x2^4+4*b^3*c2^3*x1^3*x2^2-2*b^3*c2^5*x1*x2^2-8*b^4*c1*c2*x1^5-2*b^4*c1^2*c2*x1^4-2*b^4*c1^2*c2^2*x2^3+2*b^4*c1^2*c2^3*x1^2+2*b^4*c1^2*c2^3*x2^2+4*b^4*c1^2*x1^2*x2^3+2*b^4*c1^2*x1^4*x2+6*b^4*c1^3*x1*x2^3+6*b^4*c1^3*x1^3*x2+b^4*c1^4*c2*x1^2+b^4*c1^4*c2*x2^2+b^4*c1^4*x1^2*x2-4*b^4*c2^2*x1^2*x2^3-2*b^4*c2^2*x1^4*x2+6*b^4*c2^3*x1^2*x2^2-3*b^4*c2^4*x1^2*x2+4*b^5*c1*c2*x1^4-2*b^5*c1^2*c2*x1^3-2*b^5*c1^2*x1*x2^3-2*b^5*c1^2*x1^3*x2+2*b^5*c2^2*x1*x2^3+2*b^5*c2^2*x1^3*x2-2*b^5*c2^3*x1*x2^2-6*c1^2*c2^3*x1^2*x2^4-6*c1^2*c2^3*x1^4*x2^2+6*c1^2*c2^4*x1^2*x2^3+3*c1^2*c2^4*x1^4*x2-3*c1^4*c2*x1^2*x2^4-3*c1^4*c2*x1^4*x2^2+6*c1^4*c2^2*x1^2*x2^3+3*c1^4*c2^2*x1^4*x2+12*b*c1*c2^3*x1^2*x2^4+12*b*c1*c2^3*x1^4*x2^2-8*b*c1*c2^4*x1^2*x2^3-4*b*c1*c2^4*x1^4*x2+4*b*c1^2*c2^3*x1*x2^4+8*b*c1^2*c2^3*x1^3*x2^2-6*b*c1^2*c2^4*x1*x2^3-6*b*c1^2*c2^4*x1^3*x2+12*b*c1^3*c2*x1^2*x2^4+12*b*c1^3*c2*x1^4*x2^2-16*b*c1^3*c2^2*x1^2*x2^3-8*b*c1^3*c2^2*x1^4*x2+2*b*c1^4*c2*x1*x2^4+4*b*c1^4*c2*x1^3*x2^2-6*b*c1^4*c2^2*x1*x2^3-6*b*c1^4*c2^2*x1^3*x2-8*b^2*c1*c2^3*x1*x2^4-16*b^2*c1*c2^3*x1^3*x2^2+6*b^2*c1*c2^4*x1*x2^3+6*b^2*c1*c2^4*x1^3*x2-18*b^2*c1^2*c2*x1^2*x2^4-18*b^2*c1^2*c2*x1^4*x2^2+20*b^2*c1^2*c2^2*x1^2*x2^3+10*b^2*c1^2*c2^2*x1^4*x2-4*b^2*c1^2*c2^3*x1^2*x2^2+3*b^2*c1^2*c2^4*x1^2*x2-8*b^2*c1^3*c2*x1*x2^4-16*b^2*c1^3*c2*x1^3*x2^2+12*b^2*c1^3*c2^2*x1*x2^3+12*b^2*c1^3*c2^2*x1^3*x2-2*b^2*c1^4*c2*x1^2*x2^2+3*b^2*c1^4*c2^2*x1^2*x2+12*b^3*c1*c2*x1^2*x2^4+12*b^3*c1*c2*x1^4*x2^2-12*b^3*c1*c2^2*x1^2*x2^3-6*b^3*c1*c2^2*x1^4*x2+8*b^3*c1*c2^3*x1^2*x2^2-2*b^3*c1*c2^4*x1^2*x2+10*b^3*c1^2*c2*x1*x2^4+20*b^3*c1^2*c2*x1^3*x2^2-8*b^3*c1^2*c2^2*x1*x2^3-8*b^3*c1^2*c2^2*x1^3*x2-4*b^3*c1^2*c2^3*x1*x2^2+8*b^3*c1^3*c2*x1^2*x2^2-4*b^3*c1^3*c2^2*x1^2*x2-2*b^3*c1^4*c2*x1*x2^2-8*b^4*c1*c2*x1*x2^4-16*b^4*c1*c2*x1^3*x2^2+6*b^4*c1*c2^2*x1*x2^3+6*b^4*c1*c2^2*x1^3*x2-2*b^4*c1^2*c2*x1^2*x2^2-2*b^4*c1^2*c2^2*x1^2*x2+4*b^5*c1*c2*x1^2*x2^2-2*b^5*c1^2*c2*x1*x2^2; factor(E); + polynome pt1; + pt1.coord.reserve(pt.coord.size()); + it=pt.coord.begin();itend=pt.coord.end(); + cur[0]=(1<<15)-1; + for (;it!=itend;++it){ + if (it->index==cur){ + pt1.coord.back().value += it->value; + } + else { + if (!pt1.coord.empty() && is_zero(pt1.coord.back().value)) + pt1.coord.pop_back(); + cur=it->index.iref(); + pt1.coord.push_back(*it); + } + } + if (!pt1.coord.empty() && is_zero(pt1.coord.back().value)) + pt1.coord.pop_back(); + pt.coord.swap(pt1.coord); + } + + // return true if none of the coefficients of p with same 1st degree are the same + bool x_degrees(const polynome & p,vector & d){ + d.clear(); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + int prev=-1; + vecteur v; + for (;it!=itend;++it){ + int cur=it->index.iref().front(); + if (cur!=prev){ + v=vecteur(1,it->value); + d.push_back(cur); + prev=cur; + } + else { + if (equalposcomp(v,it->value)) + return false; + v.push_back(it->value); + } + } + return true; + } + + bool lex_or_coeff_sort(const monomial & a,const monomial & b){ + if (a.index.front()!=b.index.front()) + return a.index.front()>b.index.front(); + return is_strictly_greater(a.value,b.value,context0); + } + + bool try_sparse_factor_bi(polynome & pcur,int mult,factorization & f){ + int dim=pcur.dim; + if (dim<=2) + return false; + /* Try sparse factorization using bivariate images of a factor of + pcur(x,x1,x2,...) with [x1,x2,...]=[t^n1,t^n2,...] + where n1,n2,...=1,1,... then 2,1,... then 1,2,... + */ + polynome lcp(Tfirstcoeff(pcur)),lcpt; + polynome pt,ptcont; + index_t n(dim-1,1); + for (;;){ + eval_tn(pcur,n,pt); + ptcont=Tlgcd(pt); + pt=pt/ptcont; + eval_tn(lcp,n,lcpt); +#if POLY_SPARSE_BI + factorization ft; + gen extra_div_t; + factor(pt,ptcont,ft,false,false,false,1,extra_div_t); + if (ft.size()==1){ + f.push_back(facteur(pcur,mult)); + return true; + } + factorization::const_iterator vit=ft.begin(),vitend=ft.end(); +#else + vecteur lv(makevecteur(vx_var,gen("t",context0))); + gen dbg=_poly2symb(makesequence(pt,lv),context0); + dbg=_factors(dbg,context0) ; + if (dbg.type!=_VECT) return false; + vecteur v=*dbg._VECTptr; + if (v.size()==2 && v.back()==1){ + f.push_back(facteur(pcur,mult)); + return true; + } + iterateur vit=v.begin(),vitend=v.end(); +#endif + // factor must be distinct from other factors + // by one of the degrees in x + // select which factor will be reconstructed: + // multby=lcpt/lcoeff(factor of ft) must be as simple as possible + // Once selected, the factor will be normalized by * by multby + vector seldegs; + polynome multby,selp; + for (;vit!=vitend;++vit){ +#if POLY_SPARSE_BI + if (vit->mult>1) break; + const polynome & p=vit->fact; +#else + ++vit; + if (*vit!=1) break; + gen pg=_symb2poly(makesequence(*(vit-1),lv),context0); + if (pg.type!=_POLY) break; + const polynome & p = *pg._POLYptr; +#endif + index_t D=p.degree(); + double ratio=p.coord.size()/(double(D[0])*D[1]); + if (ratio>0.2) + return false; + vector degs; + bool b=x_degrees(p,degs); + if (degs==seldegs) break; + polynome multbynew=lcpt/Tfirstcoeff(p); + if (seldegs.empty() || (b && multbynew.coord.size()fact,lv),context0); + for (int k=1;k(*pcurg._POLYptr,fit->mult)); + } + return true; + } + seldegs=degs; + multby=multbynew; + selp=multby*p; + } + } + if (vit!=vitend){ + ++n[0]; + if (n[0]>=4) + return false; + continue; + } + // we will deduce x1^ in monomials by comparing with the same factor + // of the bivariate factorization with n1=2 instead of n1=1 + // then x2^ with n1=1 and n2=2 + // If one bivariate image has less monomials than another one it is an unlucky n, use another one + // If one bivariate image has more monomials, then we must throw everything and restart with this bivariate image + // Once all monomials are done we should get a factor of pcur + // by extracting the primitive part of this factor + sort(selp.coord.begin(),selp.coord.end(),lex_or_coeff_sort); + polynome curp,recon(selp); recon.dim=pcur.dim; + int increment=1,i=0; + for (;imult>1){vit=vitend;} break; + const polynome & p=vit->fact; +#else + ++vit; + if (*vit!=1) break; + gen pg=_symb2poly(makesequence(*(vit-1),lv),context0); + if (pg.type!=_POLY) break; + const polynome & p = *pg._POLYptr; +#endif + vector degs; + if (!x_degrees(p,degs)) break; + if (degs==seldegs){ + curp=lcpt/Tfirstcoeff(p)*p; + break; + } + } + if (vit==vitend || curp.coord.empty()) break; // not found or not sqrfree + // compare with selp + if (curp.coord.size()3) + break; + continue; + } + sort(curp.coord.begin(),curp.coord.end(),lex_or_coeff_sort); + if (curp.coord.size()>selp.coord.size()){ + // selp was unlucky, restart + recon=selp=curp; + n=n1; + break; + } + // selp and curp size match, now compare monomial by monomial + // and extract x[i] exponent in recon + vector< monomial >::iterator rt=recon.coord.begin(),rtend=recon.coord.end(),st=selp.coord.begin(),ct=curp.coord.begin(); + for (;rt!=rtend;++rt,++st,++ct){ + if (st->index[0]!=ct->index[0]) + break; + int idx0=st->index[1]; + int idx1=ct->index[1]; + index_t I=rt->index.iref(); + int delta=(idx1-idx0)/(n1i-ni); + if (i==0) + I[1]=delta; + else + I.push_back(delta); + if (i==n.size()-2){ + for (int j=0;j<=i;++j){ + idx1 -= I[j+1]*n1[j]; + } + I.push_back(idx1/n1[i+1]); + } + rt->index=I; + } + if (rt!=rtend) + break; + increment=1; + if (i==n.size()-2) ++i; + ++i; + } + if (i=4) + return false; + continue; + } + recon.tsort(); + // divide by reconstructed factor and restart factorization + recon=recon/Tlgcd(recon); + polynome quo,rem; + if (!pcur.TDivRem(recon,quo,rem,false) || !is_zero(rem)) + return false; + f.push_back(facteur(recon,mult)); + pcur=quo; + return try_sparse_factor_bi(pcur,mult,f); + } // end endless for + } + + void poly_truncate(const polynome & q,polynome & q1,int j){ + q1.coord.clear(); + vector< monomial >::const_iterator jt=q.coord.begin(),jtend=q.coord.end(); + for (;jt!=jtend;++jt){ + if (jt->index.total_degree() >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (it->index.total_degree()==i) + p1.coord.push_back(*it); + } + poly_truncate(q,q1,j); + // multiply, + mulpoly(p1,q1,tmp,0); + // add to res + p1.coord.clear(); + tmp.TAdd(res,p1); + p1.coord.swap(res.coord); + } + } + + // keep only monomials of total_degree==j without first degree + void poly_truncate1(const polynome & q,polynome & q1,int j){ + q1.coord.clear(); + vector< monomial >::const_iterator it=q.coord.begin(),itend=q.coord.end(); + index_t::const_iterator jt,jtend; + for (;it!=itend;++it){ + jt=it->index.begin()+1; + jtend=it->index.end(); + int otherdeg; + for (otherdeg=*jt,++jt;jt!=jtend;++jt){ + otherdeg += *jt; + } + if (otherdeg==j) + q1.coord.push_back(*it); + } + } + + void other_deg(const polynome & p,vector & pdeg){ + pdeg.reserve(p.coord.size()); pdeg.clear(); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + index_t::const_iterator jt,jtend; + jt=it->index.begin()+1; + //jtend=jt+dim-1; + jtend=it->index.end(); + int otherdeg; + for (otherdeg=*jt,++jt;jt & pdeg,vector & qdeg){ + bool eq=deg>=0; + int maxdeg=eq?deg:-deg; + res.coord.clear(); + int dim=p.dim; + int ps=int(p.coord.size()),qs=int(q.coord.size()); + p1.coord.reserve(ps); + other_deg(p,pdeg); + other_deg(q,qdeg); + const vector< monomial > & pcoord=p.coord; + const vector< monomial > & qcoord=q.coord; + for (int i=0;i<=maxdeg;++i){ + // p1 total degree <=i of p or ==i if deg>0, + // q1 total degree==maxdeg-i of q + int j=maxdeg-i; + // create p1 and q1 + p1.coord.clear(); + for (int k=0;k lcoeffs(s,lcp); + bool lcoeff_known=false; + factorization::const_iterator F0it=v0.begin(),F0itend=v0.end(); + vector F0fact; + for (;F0it!=F0itend;++F0it){ + if (F0it->mult>1) + break; + F0fact.push_back(modularize(F0it->fact,0,0)); + if (is_undef(F0fact.back())) + return false; + } + if (pcur.dim>2 && lcp.coord.size()>1){ + // try bivariate factorization to compute a priori the leadings coefficients + // that is factor pcur(x1,x2,0,...,0) = product p_i(x1,x2) + // then factor lcoeff(pcur)(x2,x3,..,xn) = product q_j(x2,..,xn) + // the lcoeff(pcur) corresponding to lcoeff(p_i)(x2) divides + // the product of the q_j such that either q_j(x2,0,...,0) is constant + // or gcd(q_j(x2,0,...,0),lcoeff(p_i)(x2)) is not constant + // then we know multiples of the lcoeffs, we can therefore replace s, F0it, F0itend, lcoeffs + polynome pcurx1x2; + peval_xk_xn_zero(pcur,2,pcurx1x2); + factorization fx1x2,flcoeff; + vector flcoeff0; + polynome pcurx1x2cont=lgcd(pcurx1x2); + gen extra_div=1; + // if pcurx1x2cont is not 1, the following code may fail + // example f:=3/5*a^2*b^2*c^2+129/20*a^2*b*c^3+18/5*a^2*b*c^2*d-1443/40*a^2*b*c^2+387/10*a^2*c^3*d-387*a^2*c^3-9/20*a^2*c^2*d+9/2*a^2*c^2-273/5*a*b^2*c^2*d+3/5*a*b^2*c^2-11739/20*a*b*c^3*d+129/20*a*b*c^3-18/5*a*b*c^2*d^2+1857/40*a*b*c^2*d-1443/40*a*b*c^2-387/10*a*c^3*d^2+4257/10*a*c^3*d-387*a*c^3+9/20*a*c^2*d^2-99/20*a*c^2*d+9/2*a*c^2+54*b^2*c^2*d^2-54*b^2*c^2*d+1161/2*b*c^3*d^2-1161/2*b*c^3*d-27/4*b*c^2*d^2+27/4*b*c^2*d; factor(f); + if ( + // is_one(pcurx1x2cont) + is_zero(pcurx1x2cont.lexsorted_degree()) + ){ + truncate_xk_xn(pcurx1x2,2); + if (lgcd(pcurx1x2).coord.size()>1) + return false; + if (!factor(pcurx1x2,pcurx1x2cont,fx1x2,true,false,false,1,extra_div) || extra_div!=1) + return false; + // fx1x2 contains factorization of pcur(x1,x2,0,...0) + // now find factorization of lcoeff(pcur)(x2,...,xn) + polynome pcur_lcoeff(Tfirstcoeff(pcur)),pcur_lcoeffcont,pcur_lcoeff_sqfftest; + peval_xk_xn_zero(pcur_lcoeff,2,pcur_lcoeff_sqfftest); + pcur_lcoeff_sqfftest=pcur_lcoeff_sqfftest.trunc1(); + // if (gcd(pcur_lcoeff_sqfftest,pcur_lcoeff_sqfftest.derivative()).lexsorted_degree()) return false; + if (!factor(pcur_lcoeff.trunc1(),pcur_lcoeffcont,flcoeff,false,false,false,1,extra_div) || extra_div!=1) + return false; + factorization::iterator jt=flcoeff.begin(),jtend=flcoeff.end(); + polynome constante(pcur_lcoeffcont.untrunc1()*pcurx1x2cont),tmp; + for (;jt!=jtend;++jt){ + jt->fact=jt->fact.untrunc1(); + peval_xk_xn_zero(jt->fact,2,tmp); // should only depend on x2 + if (Tis_constant(tmp)) + constante=constante*pow(jt->fact,jt->mult); + //else + flcoeff0.push_back(tmp); + } // flcoeff0 contains the list of factors of lcoeff(pcur) evaled at 0 + F0it=fx1x2.begin(); + F0itend=fx1x2.end(); + s=int(F0itend-F0it); + F0fact.clear(); + lcoeffs.clear(); + modpoly piF(1,1); + for (;F0it!=F0itend;++F0it){ + if (F0it->mult>1) + break; + polynome p (F0it->fact); // depends on x1 and x2 + untruncate_xk_xn(p,dim); + peval_xk_xn_zero(p,1,tmp); // make x2=0 + truncate_xk_xn(tmp,1); + modpoly Fi(modularize(tmp,0,0)); + if (is_undef(Fi)) + return false; + if (gcd(piF,Fi,0).size()>1) + return false; + piF=piF*Fi; + F0fact.push_back(Fi); + // corresponding lcoeff + p=Tfirstcoeff(p); + polynome tmp2=constante; + for (jt=flcoeff.begin(),jtend=flcoeff.end();jt!=jtend;++jt){ + for (int m=jt->mult;m>0;--m){ + polynome G(flcoeff0[jt-flcoeff.begin()]); + if (Tis_constant(simplify(p,G))) + break; + else { + tmp2 = tmp2 * jt->fact; + // mark jt->fact as used + --jt->mult; + } + } + } + lcoeffs.push_back(tmp2); + } + lcoeff_known=true; + } // if is_one(pcurx1x2cont) + } + if (F0it!=F0itend) + return false; + // ok each factor of F0=pcur|0 is square free, they are prime together + // if lcp has too much terms it will take too long, because + // we must multiply by product(lcoeffs)/lcp + // next check was >100 but then heuristic factorization fails + // (should also depends on the size of the coeffs and number of variables...) + if (!lcoeff_known && pow(lcp,s-1).coord.size()>1000) + return false; + // we will lift pcur*product(lcoeffs)/lcp = product_i F0fact[i]*lcoeffs[i](b)/lcoeff(F0fact[i]) + for (int i=0;i u; + if (!egcd(F0fact,0,u)) + return false;// sum_j U_j * product_{i \neq j} F0fact_i = 1 + // factor out common deno + // sum_j U_j * product_{i \neq j} F0fact_i = D + vecteur den(s); + gen D(1); + for (int i=0;i P(s),P0(s),U(s); + vecteur b(pcur_adjusted.dim-1); + for (int i=0;i(*it,deg-n,1,pcur_adjusted.dim)); + P0[i].coord.push_back(monomial(*it,deg-n,1,pcur_adjusted.dim)); + } + } + U[i].dim=pcur_adjusted.dim; + it=u[i].begin(); itend=u[i].end(); + deg=int(itend-it)-1; + for (int n=0;it!=itend;++it,++n){ + if (!is_zero(*it)) + U[i].coord.push_back(monomial(*it,deg-n,1,pcur_adjusted.dim)); + } + // CERR << Tcontent(U[i]) << '\n'; + } + polynome quo(dim),rem(dim),tmp(dim); + // we have now pcur_adjusted = product P_i + O(total_degree>=1) + int Total=pcur_adjusted.total_degree(); + // lift to pcur_adjusted = product P_i + O(total_degree>=k+1) + // for deg from 1 to total_degree(pcur_adjusted) + // P_i += (pcur_adjusted-product P_i) * U_j mod total_degree(k+1) +#if 1 // def EZGCD_DEGONLY + if (is_zero(b)){ + polynome tmp4(dim),tmp5(dim),tmp6(dim),prod(dim); + vector tmpi1,tmpi2; + for (int deg=1;deg<=Total;++deg){ + prod=P[s-2]; + for (int i=s-3;i>=0;--i){ + // reduce_poly(prod * P[i],b,deg+1,prod); // keep up to deg + tmp.coord.clear(); + mulpoly_truncate1(prod,P[i],tmp,-deg,tmp4,tmp5,tmp6,tmpi1,tmpi2); + prod.coord.swap(tmp.coord); + //if (prod!=prod1) CERR << "err " << deg << '\n'; + } // end loop on i + mulpoly_truncate1(prod,P[s-1],tmp,deg,tmp4,tmp5,tmp6,tmpi1,tmpi2); + prod.coord.swap(tmp.coord); + poly_truncate1(pcur_adjusted,tmp,deg); + prod = tmp - prod; + if (prod.coord.empty()){ + // check total degrees + int tdeg=0; + for (int i=0;i=0;--i){ + // prod = prod * P[i]; + tmp.coord.clear(); + mulpoly(prod,P[i],tmp,0); + prod.coord.swap(tmp.coord); + } + // N.B. prod==pcur_adjusted does not always work! + if ((prod-pcur_adjusted).coord.empty()) + deg=Total; + } + if (deg==Total){ + for (int i=0;i(divbylgcd(P[i]),mult)); + } + return true; + } + } + continue; + } + //CERR << Tcontent(prod) << '\n'; + for (int i=0;i >::const_iterator r1=rem.coord.begin(),r2=rem.coord.end(); + Div(r1,r2,D,rem.coord); + P[i] = P[i] + rem; + } + } + } // end if (is_zero(b)) + else +#endif + for (int deg=1;deg<=Total;++deg){ + polynome prod(P[s-1]); + for (int i=s-2;i>=0;--i){ + // reduce_poly(prod * P[i],b,deg+1,prod); // keep up to deg + tmp.coord.clear(); + mulpoly(prod,P[i],tmp,0); + reduce_poly(tmp,b,deg+1,prod); + } + prod = reduce_poly(pcur_adjusted,b,deg+1) - prod; + if (prod.coord.empty()){ + // check total degrees + int tdeg=0; + for (int i=0;i(divbylgcd(P[i]),mult)); + } + return true; + } + } + continue; + } + //CERR << Tcontent(prod) << '\n'; + for (int i=0;i >::const_iterator r1=rem.coord.begin(),r2=rem.coord.end(); + Div(r1,r2,D,rem.coord); + P[i] = P[i] + rem; + } + } // end for + // FIXME combine factors + if (s==2){ + f.push_back(facteur(pcur,mult)); + return true; + } + int nfact=s; + index_t pcur_deg(pcur_adjusted.degree()); + vector test(1); + for (int k=1;k<=nfact/2;){ + if (debug_infolevel) + COUT << CLOCK() << "Testing combination of " << k << " factors" << '\n'; + // FIXME check on cst coeff + if (1){ + polynome prodP(P[test[0]]); + for (int i=1;i(divbylgcd(prodP),mult)); + for (int i=k-1;i>=0;--i){ + P.erase(P.begin()+test[i]); + } + nfact -= k; + for (int i=0;i(k); + for (int i=0;i(pcur_adjusted/lgcd(pcur_adjusted),mult)); + return true; + } + + // find u,v,d s.t. u*p+v*q=d by Hensel lift + bool try_hensel_egcd(const polynome & p,const polynome & q,polynome &u,polynome &v,polynome & d){ + // check # of variables + //if (p.dim<=1 || p.dim!=q.dim) + return false; + // check that 0 is a good evaluation point (same degree, gcd==1) + vecteur b(1,0); + polynome p0(1),q0(1); + find_good_eval(p,q,p0,q0,b,(debug_infolevel>=2)); + if (!is_zero(b)) + return false; + int pdeg=p.lexsorted_degree(),qdeg=q.lexsorted_degree(); + if (p0.lexsorted_degree()!=pdeg || q0.lexsorted_degree()!=qdeg) + return false; + gen g=gcd(pdeg,qdeg); + if (g.type==_POLY && g._POLYptr->lexsorted_degree()) + return false; + // Bezout at other variables==0 + polynome u0(1),v0(1),d0(1); + egcd(p0,q0,u0,v0,d0); // d0 must be constant + // now p*u0+q*v0-d0=O(1) where O(k) means of order >= k wrt other variables + // p*uk+q*vk-d0=O(k) -> p*(uk+uk1)+q*(v+vk1)-d0=O(k+1) + // with uk1 and vk1=O(k+1) + // we have p0*uk1+q0*vk1=d0-p*uk-q*vk=yk + // hence uk1=yk*u0/d0 % q0, vk1=yk*v0/d0 % p0 + // rational (Pade-like) reconstruction uk=fraction of polynomials + // with max degree wrt other variables <=k/2 + // once both fractions corresp. to uk and vk stabilizes, check identity + } + + // Hensel linear or quadratic lift + // FIXME Quadratic lift currently works only if lcp is constant + // Lift the equality p(b)=qb*rb [where b is a vecteur like for peval + // assumed to have p.dim-1 coordinates] to p=q*r mod (X-b)^deg + // Assuming that lcoeff(q)=lcp, lcoeff(r)=lcp, lcoeff(p)=lcp^2 + // If you want to find factors of a poly P such that P(b)=Qb*Rb, + // if lcp is the leading coeff of P + // then p=P*lcp, qb=Qb*lcp(b)/lcoeff(Qb), rb=Rb*lcp(b)/lcoeff(Rb) + bool hensel_lift(const polynome & p, const polynome & lcp, const polynome & qb, const polynome & rb, const vecteur & b,polynome & q, polynome & r,bool linear_lift,double maxop){ + if (maxop) + linear_lift=true; // otherwise please adjust number of operations to do! + double nop=0; + int dim=p.dim; + int deg=total_degree(p); + if ( (qb.dim!=1) || (rb.dim!=1) || (dim==1) ){ +#ifdef NO_STDEXCEPT + return false; +#else + setsizeerr(gettext("Bad dimension for qb or rb or b or degrees")); +#endif + } + polynome qu(1),ru(1),qbd(1); + egcd(qb,rb,qu,ru,qbd); + if (!Tis_constant(qbd)){ +#ifdef NO_STDEXCEPT + return false; +#else + setsizeerr(gettext("qb and rb not prime together!")); +#endif + } + gen qrd(qbd.coord.front().value); + // now we have qu*qb+ru*rb=qrd with 1-d polynomials + change_dim(qu,dim); + change_dim(ru,dim); + // adjust dim & leading coeff of q and r by removing current leading coeff + // and replace by lcp + q=qb; + r=rb; + change_dim(q,dim); + change_dim(r,dim); + polynome q0(q),r0(r); + index_t qshift(q.dim); + qshift[0]=q.lexsorted_degree(); + q=q+(lcp-Tfirstcoeff(q)).shift(qshift); + qshift[0]=r.lexsorted_degree(); + r=r+(lcp-Tfirstcoeff(r)).shift(qshift); + polynome p_qr(dim); + for (int n=1;;){ + // qu*q+ru*r=qrd [n] (it's exact at the loop begin) + // p=q*r [n] where [n] means of total valuation >= n + // at the beginning n=1 + // enhanced at order 2*n by adding q',r' of valuation >=n + // p-(q+q')*(r+r')=p-q*r - (r'q+q'r)-q'*r' + // hence if we put r', q' such that p-q*r=(r'q+q'r) [2n] + // we are done. Since p-q*r is of order [n], we get the solution + // r'=qu*(p-qr)/qrd and q'=ru*(p-qr)/qrd + if (debug_infolevel) + CERR << "// Hensel " << n << " -> " << deg << '\n'; + if (n>deg) + return false; + if (linear_lift) + ++n; + else + n=2*n; + if (maxop>0){ + nop += double(q.coord.size())*r.coord.size(); + if (debug_infolevel) + CERR << "EZGCD " << nop << ":" << maxop << '\n'; + if (nop>maxop) + return false; + } + p_qr=reduce_poly(p-q*r,b,deg); + if (is_zero(p_qr)) + return true; + if (n>deg) + n=deg; + p_qr=reduce_poly(p_qr,b,n); + polynome qprime(reduce_poly(ru*p_qr,b,n)),qquo(qprime.dim),qrem(qprime.dim); + polynome rprime(reduce_poly(qu*p_qr,b,n)),rquo(rprime.dim),rrem(qprime.dim); + // reduction of qprime and rprime with respect to the main variable + // we know that + // (*) degree(p_qr) < degree(qr) + // where degree is the degree wrt the main variable + // since the leading coeffs of q and r are still adjusted + // Then there is a unique solution to (*) with + // degree(qprime)(qrd,0,dim))-reduce_poly(qu*q+ru*r,b,n); + qprime=reduce_poly(qu*p_qr,b,n); + rprime=reduce_poly(ru*p_qr,b,n); + reduce_divrem(qprime,r,b,n,qquo,qrem); + reduce_divrem(rprime,q,b,n,rquo,rrem); + qu=qu+inv(qrd,context0)*qrem; // should check that qu and ru have integer coeff + ru=ru+inv(qrd,context0)*rrem; + } + } + } + + // Replace the last coordinates of p with b instead of the first + gen peval_back(const polynome & p,const vecteur & b){ + int pdim=p.dim,bdim=int(b.size()); + vector cycle(pdim); + int deltad=pdim-bdim; + for (int i=0;i >::const_iterator it=p.coord.begin(); + std::vector< monomial >::const_iterator itend=p.coord.end(); + for (;it!=itend;){ + i[0]=it->index.front(); + polynome pactuel(Tnextcoeff(it,itend)); + gen g(peval(pactuel,v,mod)); + if ( (g.type==_POLY) && (g._POLYptr->dim==0) ) + g=g._POLYptr->coord.empty()?0:g._POLYptr->coord.front().value; + if (!is_zero(g)) + res.coord.push_back(monomial(g,i)); + } + return res; + } + + polynome unmodularize(const vector & a){ + if (a.empty()) + return polynome(1); + polynome res(1); + vector< monomial > & v=res.coord; + index_t i; + int deg=int(a.size())-1; + i.push_back(deg); + vector::const_iterator it=a.begin(); + vector::const_iterator itend=a.end(); + for (;it!=itend;++it,--i[0]){ + if (*it) + v.push_back(monomial(*it,i)); + } + return res; + } + + static bool convert_from_truncate(const vector< T_unsigned > & p,hashgcd_U var,polynome & P){ + P.dim=1; + P.coord.clear(); + vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end(); + P.coord.reserve(itend-it); + index_t i(1); + for (;it!=itend;++it){ + i.front()=it->u/var; + P.coord.push_back(monomial(gen(it->g),i)); + } + return true; + } + + // return true if a good eval point has been found + bool find_good_eval(const polynome & F,const polynome & G,polynome & Fb,polynome & Gb,vecteur & b,bool debuglog,const gen & mod){ + int Fdeg=int(F.lexsorted_degree()),Gdeg=int(G.lexsorted_degree()),nvars=int(b.size()); + gen Fg,Gg; + int essai=0; + int dim=F.dim; + if ( //false && + mod.type==_INT_ && mod.val){ + int modulo=mod.val; + std::vector vars(dim); + vector< T_unsigned > f,g,fb,gb; + index_t d(dim); + if (convert(F,G,d,vars,f,g,modulo)){ + vector bi(dim-1); + vecteur2vector_int(b,modulo,bi); + for (;;++essai){ + if (modulo && essai>modulo) + return false; + peval_x2_xn(f,bi,vars,fb,modulo); + if (&F==&G) + gb=fb; + else + peval_x2_xn(g,bi,vars,gb,modulo); + if (!fb.empty() && !gb.empty() && int(fb.front().u/vars.front())==Fdeg && int(gb.front().u/vars.front())==Gdeg){ + // convert back fb and gb and return true + convert_from_truncate(fb,vars.front(),Fb); + convert_from_truncate(gb,vars.front(),Gb); + return true; + } + for (int i=0;imod.val) + return false; + if (debuglog) + CERR << "Find_good_eval " << CLOCK() << " " << b << '\n'; + Fb=peval_1(F,b,mod); + if (debuglog) + CERR << "Fb= " << CLOCK() << " " << gen(Fb) << '\n'; + if (&F==&G) + Gb=Fb; + else { + Gb=peval_1(G,b,mod); + } + if (debuglog) + CERR << "Gb= " << CLOCK() << " " << gen(Gb) << '\n'; + if ( (Fb.lexsorted_degree()==Fdeg) && (Gb.lexsorted_degree()==Gdeg) ){ + if (debuglog) + CERR << "FOUND good eval" << CLOCK() << " " << b << '\n'; + return true; + } + b=vranm(nvars,0,0); // find another random point + } + } + + // It is probably required that 0 is a good evaluation point to + // have an efficient algorithm + // max_gcddeg is used when ezgcd was not successful to find + // the gcd even with 2 evaluations leading to the same gcd degree + // in this case ezgcd calls itself with a bound on the gcd degree + // is_sqff is true if we know that F_orig or G_orig is squarefree + // is_primitive is true if F_orig and G_orig is primitive + bool ezgcd(const polynome & F_orig,const polynome & G_orig,polynome & GCD,bool is_sqff,bool is_primitive,int max_gcddeg,double maxop){ + if (debug_infolevel) + CERR << "// Starting EZGCD dimension " << F_orig.dim << '\n'; + if (F_orig.dim<2){ +#ifdef NO_STDEXCEPT + return false; +#else + setsizeerr(gettext("Args must be multivariate polynomials")); +#endif + } + int Fdeg=F_orig.lexsorted_degree(),Gdeg=G_orig.lexsorted_degree(); + polynome F(F_orig.dim),G(F_orig.dim),cF(F_orig.dim),cG(F_orig.dim),cFG(F_orig.dim); + if (is_primitive){ + cFG=polynome(monomial(plus_one,0,F_orig.dim)); + cF=cFG; + cG=cFG; + F=F_orig; + G=G_orig; + } + else { + cF=Tlgcd(F_orig); + cG=Tlgcd(G_orig); + cFG=gcd(cF.trunc1(),cG.trunc1()).untrunc1(); + F=F_orig/cF; + G=G_orig/cG; + } + if (Tis_constant(F) || Tis_constant(G) ){ + GCD=cFG; + return true; + } + polynome lcF(Tfirstcoeff(F)),lcG(Tfirstcoeff(G)); + double nop=double(lcF.coord.size())*double(F.coord.size())+double(lcG.coord.size())*double(G.coord.size()); + if (maxop>0){ + if (maxopold_gcddeg) // bad evaluation point + continue; + if (new_gcddeg==old_gcddeg) // might be a good guess! + break; + old_gcddeg=new_gcddeg; + Db=new_Db; + Fb=new_Fb; + Gb=new_Gb; + b=new_b; + } + // Found two times the same degree, try to lift! + if ( (Fdeg<=Gdeg) && (old_gcddeg==Fdeg) ){ + if (G.TDivRem1(F,quo,rem) && rem.coord.empty()){ + GCD= F*cFG; + return true; + } + } + if ( (Gdeg4) && (old_gcddeg>Fdeg/4) && (old_gcddeg>Gdeg/4) ) + // return false; + polynome cofacteur(Fb/Db); + if (Tis_constant(gcd(cofacteur,Db))){ + // lift Fb/Db *Db, more precisely insure that lc of each factor + // is lcF(b) + gen lcFb(peval_back(lcF,b)); + if (lcFb.type==_POLY) + lcFb=lcFb._POLYptr->coord.front().value; + Db=(lcFb*Db)/Db.coord.front().value; + cofacteur=(lcFb*cofacteur)/cofacteur.coord.front().value; + polynome liftF(F*lcF); + polynome D(F_orig.dim),cofacteur_F(F_orig.dim),quo,rem; + if (hensel_lift(liftF,lcF,cofacteur,Db,b,cofacteur_F,D,!Tis_constant(lcF),maxop) ){ + D=D/Tlgcd(D); + if (F.TDivRem1(D,quo,rem) && is_zero(rem) && G.TDivRem1(D,quo,rem) && is_zero(rem)){ + GCD=D*cFG; + return true; + } + } + return false; + } + cofacteur=Gb/Db; + if (Tis_constant(gcd(cofacteur,Db))){ + // lift Gb/Db *Db, more precisely insure that lc of each factor + // is lcG(b) + gen lcGb(peval_back(lcG,b)); + if (lcGb.type==_POLY) + lcGb=lcGb._POLYptr->coord.front().value; + Db=(lcGb*Db)/Db.coord.front().value; + cofacteur=(lcGb*cofacteur)/cofacteur.coord.front().value; + polynome liftG(G*lcG); + polynome D(G_orig.dim),cofacteur_G(G_orig.dim),quo,rem; + if (hensel_lift(liftG,lcG,cofacteur,Db,b,cofacteur_G,D,!Tis_constant(lcG),maxop) ){ + D=D/Tlgcd(D); + if (F.TDivRem1(D,quo,rem) && is_zero(rem) && G.TDivRem1(D,quo,rem) && is_zero(rem)){ + GCD=D*cFG; + return true; + } + } + return false; + } + // FIXME find an integer j such that (F+jG)/D_b is coprime with D_b + return false; + } + + // algorithm=0 for HEUGCD, 1 for PRS, 2 for EZGCD, 3 for MODGCD + static gen heugcd_psrgcd_ezgcd_modgcd(const gen & args,int algorithm,GIAC_CONTEXT){ + vecteur & v=*args._VECTptr; + gen p1(v[0]),p2(v[1]),n1,n2,d1,d2; + vecteur lv; + if ( (v.size()==3) && (v[2].type==_VECT) ) + lv=*v[2]._VECTptr; + lvar(p1,lv); + lvar(p2,lv); + p1=e2r(p1,lv,contextptr); + fxnd(p1,n1,d1); + p2=e2r(p2,lv,contextptr); + fxnd(p2,n2,d2); + gen res,np_simp,nq_simp,d_content; + polynome p,q,p_gcd; + if ( (n1.type!=_POLY) || (n2.type!=_POLY) ) + res=gcd(n1,n2,contextptr); + else { + polynome pres; + bool result=false; + switch(algorithm){ + case 0: + p_gcd.dim=n1._POLYptr->dim; + result=gcdheu(*n1._POLYptr,*n2._POLYptr,p,np_simp,q,nq_simp,p_gcd,d_content,true); + pres=p_gcd*d_content; + break; + case 1: + pres=gcdpsr(*n1._POLYptr,*n2._POLYptr); + result=true; + break; + case 2: + result=ezgcd(*n1._POLYptr,*n2._POLYptr,pres); + break; + case 3: + result=gcd_modular_algo(*n1._POLYptr,*n2._POLYptr,pres,false); + break; + } + if (result) + res=pres; + else + return gensizeerr(gettext("GCD not successful")); + } + return r2e(res,lv,contextptr); + } + + gen _ezgcd(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) + return symbolic(at_ezgcd,args); + return heugcd_psrgcd_ezgcd_modgcd(args,2,contextptr); + } + static const char _ezgcd_s []="ezgcd"; + static define_unary_function_eval (__ezgcd,&_ezgcd,_ezgcd_s); + define_unary_function_ptr5( at_ezgcd ,alias_at_ezgcd,&__ezgcd,0,true); + + gen _modgcd(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) + return symbolic(at_modgcd,args); + return heugcd_psrgcd_ezgcd_modgcd(args,3,contextptr); + } + static const char _modgcd_s []="modgcd"; + static define_unary_function_eval (__modgcd,&_modgcd,_modgcd_s); + define_unary_function_ptr5( at_modgcd ,alias_at_modgcd,&__modgcd,0,true); + + gen _heugcd(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) + return symbolic(at_heugcd,args); + return heugcd_psrgcd_ezgcd_modgcd(args,0,contextptr); + } + static const char _heugcd_s []="heugcd"; + static define_unary_function_eval (__heugcd,&_heugcd,_heugcd_s); + define_unary_function_ptr5( at_heugcd ,alias_at_heugcd,&__heugcd,0,true); + + gen _psrgcd(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) + return symbolic(at_psrgcd,args); + return heugcd_psrgcd_ezgcd_modgcd(args,1,contextptr); + } + static const char _psrgcd_s []="psrgcd"; + static define_unary_function_eval (__psrgcd,&_psrgcd,_psrgcd_s); + define_unary_function_ptr5( at_psrgcd ,alias_at_psrgcd,&__psrgcd,0,true); + + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/first.cc b/android/app/src/main/cpp/giac/src/giac/cpp/first.cc new file mode 100644 index 0000000..3fd155b --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/first.cc @@ -0,0 +1,185 @@ +/* -*- compile-command: "g++ -g -c -I.. first.cc -DHAVE_CONFIG_H -DIN_GIAC -DGIAC_CHECK_NEW" -*- + * Copyright (C) 2000,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "first.h" +#ifndef USE_GMP_REPLACEMENTS +int init_gmp_memory::refcount = 0; +init_gmp_memory init_gmp_memory_instance; +#endif + +#ifdef HAVE_LIBGC +#include +#define GC_DEBUG +#include +void* operator new(std::size_t size) +{ + return GC_MALLOC_UNCOLLECTABLE( size ); +} + +void operator delete(void* obj) +{ + GC_FREE(obj); +} + +void* operator new[](std::size_t size) +{ + return GC_MALLOC_UNCOLLECTABLE(size); +} + +void operator delete[](void* obj) +{ + GC_FREE(obj); +} + +static void* RS_gmpalloc(size_t a) +{ + return GC_malloc_atomic(a); +} + +static void* RS_gmprealloc(void* old_p, size_t old_size, size_t new_size) +{ + void* tmp = GC_realloc(old_p, new_size); + return tmp; +} + +static void RS_gmpfree(void * old_p,size_t old_size) +{ + +} + +init_gmp_memory::init_gmp_memory() +{ + if (refcount++ == 0) + mp_set_memory_functions(RS_gmpalloc, RS_gmprealloc, RS_gmpfree); +} + +init_gmp_memory::~init_gmp_memory() +{ + if (--refcount == 0) { + // XXX: do I need to clean up something here? + } +} + +#else +init_gmp_memory::init_gmp_memory() { } +init_gmp_memory::~init_gmp_memory() { } + +#ifdef NSPIRE +#include +#else +#include +#include +#include +#endif + + +#ifdef GIAC_CHECK_NEW + +#include + +size_t giac_allocated = 0; +void* operator new(std::size_t size) +{ + std::cerr << giac_allocated << " + " << size << '\n'; + giac_allocated += size; + void * p = std::malloc(size); + if(!p) { + std::bad_alloc ba; + throw ba; + } + return p; +} + +void* operator new[](std::size_t size) +{ + std::cerr << giac_allocated << " + [] " << size << '\n'; + giac_allocated += size; + void * p = std::malloc(size); + if(!p) { + std::bad_alloc ba; + throw ba; + } + return p; +} + +void operator delete[](void* obj) +{ + free(obj); +} +#else + +#if 0 // defined KHICAS && defined DEVICE +// #include +extern const void * _stack_end; + +namespace giac { + extern volatile bool ctrl_c,interrupted; +} + +void* operator new(std::size_t size){ + void * p = std::malloc(size); + if ((size_t) p > (size_t) _stack_end) + giac::ctrl_c=giac::interrupted=true; + return p; +} + +void* operator new[](std::size_t size){ + // if ( (0x20038000-(size_t)sbrk(0))<2*size) giac::ctrl_c=giac::interrupted=true; + void * p = std::malloc(size); + if ((size_t) p > (size_t) _stack_end) + giac::ctrl_c=giac::interrupted=true; + return p; +} + +void operator delete(void* obj){ + free(obj); +} + +void operator delete[](void* obj){ + free(obj); +} +#endif // KHICAS +#endif // GIAC_CHECK_NEW + +#if defined NUMWORKS || defined KHICAS +void* operator new(std::size_t size){ + void * p = std::malloc(size); + if (!p) + exit(0); + return p; +} + +void* operator new[](std::size_t size){ + void * p = std::malloc(size); + if (!p) + exit(0); + return p; +} + +void operator delete(void* obj){ + free(obj); +} + +void operator delete[](void* obj){ + free(obj); +} +#endif + +#endif + diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/freeglut_stroke_roman.c b/android/app/src/main/cpp/giac/src/giac/cpp/freeglut_stroke_roman.c new file mode 100644 index 0000000..b4481e5 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/freeglut_stroke_roman.c @@ -0,0 +1,2820 @@ +#ifndef GIAC_GGB + +/* char: 0x20 */ + +static const SFG_StrokeStrip ch32st[] = +{ + { 0, NULL } +}; + +static const SFG_StrokeChar ch32 = {104.762f,0,ch32st}; + +/* char: 0x21 */ + +static const SFG_StrokeVertex ch33st0[] = +{ + {13.3819f,100.0f}, + {13.3819f,33.3333f} +}; + +static const SFG_StrokeVertex ch33st1[] = +{ + {13.3819f,9.5238f}, + {8.62f,4.7619f}, + {13.3819f,0.0f}, + {18.1438f,4.7619f}, + {13.3819f,9.5238f} +}; + +static const SFG_StrokeStrip ch33st[] = +{ + {2,ch33st0}, + {5,ch33st1} +}; + +static const SFG_StrokeChar ch33 = {26.6238f,2,ch33st}; + +/* char: 0x22 */ + +static const SFG_StrokeVertex ch34st0[] = +{ + {4.02f,100.0f}, + {4.02f,66.6667f} +}; + +static const SFG_StrokeVertex ch34st1[] = +{ + {42.1152f,100.0f}, + {42.1152f,66.6667f} +}; + +static const SFG_StrokeStrip ch34st[] = +{ + {2,ch34st0}, + {2,ch34st1} +}; + +static const SFG_StrokeChar ch34 = {51.4352f,2,ch34st}; + +/* char: 0x23 */ + +static const SFG_StrokeVertex ch35st0[] = +{ + {41.2952f,119.048f}, + {7.9619f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st1[] = +{ + {69.8667f,119.048f}, + {36.5333f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st2[] = +{ + {7.9619f,57.1429f}, + {74.6286f,57.1429f} +}; + +static const SFG_StrokeVertex ch35st3[] = +{ + {3.2f,28.5714f}, + {69.8667f,28.5714f} +}; + +static const SFG_StrokeStrip ch35st[] = +{ + {2,ch35st0}, + {2,ch35st1}, + {2,ch35st2}, + {2,ch35st3} +}; + +static const SFG_StrokeChar ch35 = {79.4886f,4,ch35st}; + +/* char: 0x24 */ + +static const SFG_StrokeVertex ch36st0[] = +{ + {28.6295f,119.048f}, + {28.6295f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st1[] = +{ + {47.6771f,119.048f}, + {47.6771f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st2[] = +{ + {71.4867f,85.7143f}, + {61.9629f,95.2381f}, + {47.6771f,100.0f}, + {28.6295f,100.0f}, + {14.3438f,95.2381f}, + {4.82f,85.7143f}, + {4.82f,76.1905f}, + {9.5819f,66.6667f}, + {14.3438f,61.9048f}, + {23.8676f,57.1429f}, + {52.439f,47.619f}, + {61.9629f,42.8571f}, + {66.7248f,38.0952f}, + {71.4867f,28.5714f}, + {71.4867f,14.2857f}, + {61.9629f,4.7619f}, + {47.6771f,0.0f}, + {28.6295f,0.0f}, + {14.3438f,4.7619f}, + {4.82f,14.2857f} +}; + +static const SFG_StrokeStrip ch36st[] = +{ + {2,ch36st0}, + {2,ch36st1}, + {20,ch36st2} +}; + +static const SFG_StrokeChar ch36 = {76.2067f,3,ch36st}; + +/* char: 0x25 */ + +static const SFG_StrokeVertex ch37st0[] = +{ + {92.0743f,100.0f}, + {6.36f,0.0f} +}; + +static const SFG_StrokeVertex ch37st1[] = +{ + {30.1695f,100.0f}, + {39.6933f,90.4762f}, + {39.6933f,80.9524f}, + {34.9314f,71.4286f}, + {25.4076f,66.6667f}, + {15.8838f,66.6667f}, + {6.36f,76.1905f}, + {6.36f,85.7143f}, + {11.1219f,95.2381f}, + {20.6457f,100.0f}, + {30.1695f,100.0f}, + {39.6933f,95.2381f}, + {53.979f,90.4762f}, + {68.2648f,90.4762f}, + {82.5505f,95.2381f}, + {92.0743f,100.0f} +}; + +static const SFG_StrokeVertex ch37st2[] = +{ + {73.0267f,33.3333f}, + {63.5029f,28.5714f}, + {58.741f,19.0476f}, + {58.741f,9.5238f}, + {68.2648f,0.0f}, + {77.7886f,0.0f}, + {87.3124f,4.7619f}, + {92.0743f,14.2857f}, + {92.0743f,23.8095f}, + {82.5505f,33.3333f}, + {73.0267f,33.3333f} +}; + +static const SFG_StrokeStrip ch37st[] = +{ + {2,ch37st0}, + {16,ch37st1}, + {11,ch37st2} +}; + +static const SFG_StrokeChar ch37 = {96.5743f,3,ch37st}; + +/* char: 0x26 */ + +static const SFG_StrokeVertex ch38st0[] = +{ + {101.218f,57.1429f}, + {101.218f,61.9048f}, + {96.4562f,66.6667f}, + {91.6943f,66.6667f}, + {86.9324f,61.9048f}, + {82.1705f,52.381f}, + {72.6467f,28.5714f}, + {63.1229f,14.2857f}, + {53.599f,4.7619f}, + {44.0752f,0.0f}, + {25.0276f,0.0f}, + {15.5038f,4.7619f}, + {10.7419f,9.5238f}, + {5.98f,19.0476f}, + {5.98f,28.5714f}, + {10.7419f,38.0952f}, + {15.5038f,42.8571f}, + {48.8371f,61.9048f}, + {53.599f,66.6667f}, + {58.361f,76.1905f}, + {58.361f,85.7143f}, + {53.599f,95.2381f}, + {44.0752f,100.0f}, + {34.5514f,95.2381f}, + {29.7895f,85.7143f}, + {29.7895f,76.1905f}, + {34.5514f,61.9048f}, + {44.0752f,47.619f}, + {67.8848f,14.2857f}, + {77.4086f,4.7619f}, + {86.9324f,0.0f}, + {96.4562f,0.0f}, + {101.218f,4.7619f}, + {101.218f,9.5238f} +}; + +static const SFG_StrokeStrip ch38st[] = +{ + {34,ch38st0} +}; + +static const SFG_StrokeChar ch38 = {101.758f,1,ch38st}; + +/* char: 0x27 */ + +static const SFG_StrokeVertex ch39st0[] = +{ + {4.44f,100.0f}, + {4.44f,66.6667f} +}; + +static const SFG_StrokeStrip ch39st[] = +{ + {2,ch39st0} +}; + +static const SFG_StrokeChar ch39 = {13.62f,1,ch39st}; + +/* char: 0x28 */ + +static const SFG_StrokeVertex ch40st0[] = +{ + {40.9133f,119.048f}, + {31.3895f,109.524f}, + {21.8657f,95.2381f}, + {12.3419f,76.1905f}, + {7.58f,52.381f}, + {7.58f,33.3333f}, + {12.3419f,9.5238f}, + {21.8657f,-9.5238f}, + {31.3895f,-23.8095f}, + {40.9133f,-33.3333f} +}; + +static const SFG_StrokeStrip ch40st[] = +{ + {10,ch40st0} +}; + +static const SFG_StrokeChar ch40 = {47.1733f,1,ch40st}; + +/* char: 0x29 */ + +static const SFG_StrokeVertex ch41st0[] = +{ + {5.28f,119.048f}, + {14.8038f,109.524f}, + {24.3276f,95.2381f}, + {33.8514f,76.1905f}, + {38.6133f,52.381f}, + {38.6133f,33.3333f}, + {33.8514f,9.5238f}, + {24.3276f,-9.5238f}, + {14.8038f,-23.8095f}, + {5.28f,-33.3333f} +}; + +static const SFG_StrokeStrip ch41st[] = +{ + {10,ch41st0} +}; + +static const SFG_StrokeChar ch41 = {47.5333f,1,ch41st}; + +/* char: 0x2a */ + +static const SFG_StrokeVertex ch42st0[] = +{ + {30.7695f,71.4286f}, + {30.7695f,14.2857f} +}; + +static const SFG_StrokeVertex ch42st1[] = +{ + {6.96f,57.1429f}, + {54.579f,28.5714f} +}; + +static const SFG_StrokeVertex ch42st2[] = +{ + {54.579f,57.1429f}, + {6.96f,28.5714f} +}; + +static const SFG_StrokeStrip ch42st[] = +{ + {2,ch42st0}, + {2,ch42st1}, + {2,ch42st2} +}; + +static const SFG_StrokeChar ch42 = {59.439f,3,ch42st}; + +/* char: 0x2b */ + +static const SFG_StrokeVertex ch43st0[] = +{ + {48.8371f,85.7143f}, + {48.8371f,0.0f} +}; + +static const SFG_StrokeVertex ch43st1[] = +{ + {5.98f,42.8571f}, + {91.6943f,42.8571f} +}; + +static const SFG_StrokeStrip ch43st[] = +{ + {2,ch43st0}, + {2,ch43st1} +}; + +static const SFG_StrokeChar ch43 = {97.2543f,2,ch43st}; + +/* char: 0x2c */ + +static const SFG_StrokeVertex ch44st0[] = +{ + {18.2838f,4.7619f}, + {13.5219f,0.0f}, + {8.76f,4.7619f}, + {13.5219f,9.5238f}, + {18.2838f,4.7619f}, + {18.2838f,-4.7619f}, + {13.5219f,-14.2857f}, + {8.76f,-19.0476f} +}; + +static const SFG_StrokeStrip ch44st[] = +{ + {8,ch44st0} +}; + +static const SFG_StrokeChar ch44 = {26.0638f,1,ch44st}; + +/* char: 0x2d */ + +static const SFG_StrokeVertex ch45st0[] = +{ + {7.38f,42.8571f}, + {93.0943f,42.8571f} +}; + +static const SFG_StrokeStrip ch45st[] = +{ + {2,ch45st0} +}; + +static const SFG_StrokeChar ch45 = {100.754f,1,ch45st}; + +/* char: 0x2e */ + +static const SFG_StrokeVertex ch46st0[] = +{ + {13.1019f,9.5238f}, + {8.34f,4.7619f}, + {13.1019f,0.0f}, + {17.8638f,4.7619f}, + {13.1019f,9.5238f} +}; + +static const SFG_StrokeStrip ch46st[] = +{ + {5,ch46st0} +}; + +static const SFG_StrokeChar ch46 = {26.4838f,1,ch46st}; + +/* char: 0x2f */ + +static const SFG_StrokeVertex ch47st0[] = +{ + {7.24f,-14.2857f}, + {73.9067f,100.0f} +}; + +static const SFG_StrokeStrip ch47st[] = +{ + {2,ch47st0} +}; + +static const SFG_StrokeChar ch47 = {82.1067f,1,ch47st}; + +/* char: 0x30 */ + +static const SFG_StrokeVertex ch48st0[] = +{ + {33.5514f,100.0f}, + {19.2657f,95.2381f}, + {9.7419f,80.9524f}, + {4.98f,57.1429f}, + {4.98f,42.8571f}, + {9.7419f,19.0476f}, + {19.2657f,4.7619f}, + {33.5514f,0.0f}, + {43.0752f,0.0f}, + {57.361f,4.7619f}, + {66.8848f,19.0476f}, + {71.6467f,42.8571f}, + {71.6467f,57.1429f}, + {66.8848f,80.9524f}, + {57.361f,95.2381f}, + {43.0752f,100.0f}, + {33.5514f,100.0f} +}; + +static const SFG_StrokeStrip ch48st[] = +{ + {17,ch48st0} +}; + +static const SFG_StrokeChar ch48 = {77.0667f,1,ch48st}; + +/* char: 0x31 */ + +static const SFG_StrokeVertex ch49st0[] = +{ + {11.82f,80.9524f}, + {21.3438f,85.7143f}, + {35.6295f,100.0f}, + {35.6295f,0.0f} +}; + +static const SFG_StrokeStrip ch49st[] = +{ + {4,ch49st0} +}; + +static const SFG_StrokeChar ch49 = {66.5295f,1,ch49st}; + +/* char: 0x32 */ + +static const SFG_StrokeVertex ch50st0[] = +{ + {10.1819f,76.1905f}, + {10.1819f,80.9524f}, + {14.9438f,90.4762f}, + {19.7057f,95.2381f}, + {29.2295f,100.0f}, + {48.2771f,100.0f}, + {57.801f,95.2381f}, + {62.5629f,90.4762f}, + {67.3248f,80.9524f}, + {67.3248f,71.4286f}, + {62.5629f,61.9048f}, + {53.039f,47.619f}, + {5.42f,0.0f}, + {72.0867f,0.0f} +}; + +static const SFG_StrokeStrip ch50st[] = +{ + {14,ch50st0} +}; + +static const SFG_StrokeChar ch50 = {77.6467f,1,ch50st}; + +/* char: 0x33 */ + +static const SFG_StrokeVertex ch51st0[] = +{ + {14.5238f,100.0f}, + {66.9048f,100.0f}, + {38.3333f,61.9048f}, + {52.619f,61.9048f}, + {62.1429f,57.1429f}, + {66.9048f,52.381f}, + {71.6667f,38.0952f}, + {71.6667f,28.5714f}, + {66.9048f,14.2857f}, + {57.381f,4.7619f}, + {43.0952f,0.0f}, + {28.8095f,0.0f}, + {14.5238f,4.7619f}, + {9.7619f,9.5238f}, + {5.0f,19.0476f} +}; + +static const SFG_StrokeStrip ch51st[] = +{ + {15,ch51st0} +}; + +static const SFG_StrokeChar ch51 = {77.0467f,1,ch51st}; + +/* char: 0x34 */ + +static const SFG_StrokeVertex ch52st0[] = +{ + {51.499f,100.0f}, + {3.88f,33.3333f}, + {75.3086f,33.3333f} +}; + +static const SFG_StrokeVertex ch52st1[] = +{ + {51.499f,100.0f}, + {51.499f,0.0f} +}; + +static const SFG_StrokeStrip ch52st[] = +{ + {3,ch52st0}, + {2,ch52st1} +}; + +static const SFG_StrokeChar ch52 = {80.1686f,2,ch52st}; + +/* char: 0x35 */ + +static const SFG_StrokeVertex ch53st0[] = +{ + {62.0029f,100.0f}, + {14.3838f,100.0f}, + {9.6219f,57.1429f}, + {14.3838f,61.9048f}, + {28.6695f,66.6667f}, + {42.9552f,66.6667f}, + {57.241f,61.9048f}, + {66.7648f,52.381f}, + {71.5267f,38.0952f}, + {71.5267f,28.5714f}, + {66.7648f,14.2857f}, + {57.241f,4.7619f}, + {42.9552f,0.0f}, + {28.6695f,0.0f}, + {14.3838f,4.7619f}, + {9.6219f,9.5238f}, + {4.86f,19.0476f} +}; + +static const SFG_StrokeStrip ch53st[] = +{ + {17,ch53st0} +}; + +static const SFG_StrokeChar ch53 = {77.6867f,1,ch53st}; + +/* char: 0x36 */ + +static const SFG_StrokeVertex ch54st0[] = +{ + {62.7229f,85.7143f}, + {57.961f,95.2381f}, + {43.6752f,100.0f}, + {34.1514f,100.0f}, + {19.8657f,95.2381f}, + {10.3419f,80.9524f}, + {5.58f,57.1429f}, + {5.58f,33.3333f}, + {10.3419f,14.2857f}, + {19.8657f,4.7619f}, + {34.1514f,0.0f}, + {38.9133f,0.0f}, + {53.199f,4.7619f}, + {62.7229f,14.2857f}, + {67.4848f,28.5714f}, + {67.4848f,33.3333f}, + {62.7229f,47.619f}, + {53.199f,57.1429f}, + {38.9133f,61.9048f}, + {34.1514f,61.9048f}, + {19.8657f,57.1429f}, + {10.3419f,47.619f}, + {5.58f,33.3333f} +}; + +static const SFG_StrokeStrip ch54st[] = +{ + {23,ch54st0} +}; + +static const SFG_StrokeChar ch54 = {73.8048f,1,ch54st}; + +/* char: 0x37 */ + +static const SFG_StrokeVertex ch55st0[] = +{ + {72.2267f,100.0f}, + {24.6076f,0.0f} +}; + +static const SFG_StrokeVertex ch55st1[] = +{ + {5.56f,100.0f}, + {72.2267f,100.0f} +}; + +static const SFG_StrokeStrip ch55st[] = +{ + {2,ch55st0}, + {2,ch55st1} +}; + +static const SFG_StrokeChar ch55 = {77.2267f,2,ch55st}; + +/* char: 0x38 */ + +static const SFG_StrokeVertex ch56st0[] = +{ + {29.4095f,100.0f}, + {15.1238f,95.2381f}, + {10.3619f,85.7143f}, + {10.3619f,76.1905f}, + {15.1238f,66.6667f}, + {24.6476f,61.9048f}, + {43.6952f,57.1429f}, + {57.981f,52.381f}, + {67.5048f,42.8571f}, + {72.2667f,33.3333f}, + {72.2667f,19.0476f}, + {67.5048f,9.5238f}, + {62.7429f,4.7619f}, + {48.4571f,0.0f}, + {29.4095f,0.0f}, + {15.1238f,4.7619f}, + {10.3619f,9.5238f}, + {5.6f,19.0476f}, + {5.6f,33.3333f}, + {10.3619f,42.8571f}, + {19.8857f,52.381f}, + {34.1714f,57.1429f}, + {53.219f,61.9048f}, + {62.7429f,66.6667f}, + {67.5048f,76.1905f}, + {67.5048f,85.7143f}, + {62.7429f,95.2381f}, + {48.4571f,100.0f}, + {29.4095f,100.0f} +}; + +static const SFG_StrokeStrip ch56st[] = +{ + {29,ch56st0} +}; + +static const SFG_StrokeChar ch56 = {77.6667f,1,ch56st}; + +/* char: 0x39 */ + +static const SFG_StrokeVertex ch57st0[] = +{ + {68.5048f,66.6667f}, + {63.7429f,52.381f}, + {54.219f,42.8571f}, + {39.9333f,38.0952f}, + {35.1714f,38.0952f}, + {20.8857f,42.8571f}, + {11.3619f,52.381f}, + {6.6f,66.6667f}, + {6.6f,71.4286f}, + {11.3619f,85.7143f}, + {20.8857f,95.2381f}, + {35.1714f,100.0f}, + {39.9333f,100.0f}, + {54.219f,95.2381f}, + {63.7429f,85.7143f}, + {68.5048f,66.6667f}, + {68.5048f,42.8571f}, + {63.7429f,19.0476f}, + {54.219f,4.7619f}, + {39.9333f,0.0f}, + {30.4095f,0.0f}, + {16.1238f,4.7619f}, + {11.3619f,14.2857f} +}; + +static const SFG_StrokeStrip ch57st[] = +{ + {23,ch57st0} +}; + +static const SFG_StrokeChar ch57 = {74.0648f,1,ch57st}; + +/* char: 0x3a */ + +static const SFG_StrokeVertex ch58st0[] = +{ + {14.0819f,66.6667f}, + {9.32f,61.9048f}, + {14.0819f,57.1429f}, + {18.8438f,61.9048f}, + {14.0819f,66.6667f} +}; + +static const SFG_StrokeVertex ch58st1[] = +{ + {14.0819f,9.5238f}, + {9.32f,4.7619f}, + {14.0819f,0.0f}, + {18.8438f,4.7619f}, + {14.0819f,9.5238f} +}; + +static const SFG_StrokeStrip ch58st[] = +{ + {5,ch58st0}, + {5,ch58st1} +}; + +static const SFG_StrokeChar ch58 = {26.2238f,2,ch58st}; + +/* char: 0x3b */ + +static const SFG_StrokeVertex ch59st0[] = +{ + {12.9619f,66.6667f}, + {8.2f,61.9048f}, + {12.9619f,57.1429f}, + {17.7238f,61.9048f}, + {12.9619f,66.6667f} +}; + +static const SFG_StrokeVertex ch59st1[] = +{ + {17.7238f,4.7619f}, + {12.9619f,0.0f}, + {8.2f,4.7619f}, + {12.9619f,9.5238f}, + {17.7238f,4.7619f}, + {17.7238f,-4.7619f}, + {12.9619f,-14.2857f}, + {8.2f,-19.0476f} +}; + +static const SFG_StrokeStrip ch59st[] = +{ + {5,ch59st0}, + {8,ch59st1} +}; + +static const SFG_StrokeChar ch59 = {26.3038f,2,ch59st}; + +/* char: 0x3c */ + +static const SFG_StrokeVertex ch60st0[] = +{ + {79.2505f,85.7143f}, + {3.06f,42.8571f}, + {79.2505f,0.0f} +}; + +static const SFG_StrokeStrip ch60st[] = +{ + {3,ch60st0} +}; + +static const SFG_StrokeChar ch60 = {81.6105f,1,ch60st}; + +/* char: 0x3d */ + +static const SFG_StrokeVertex ch61st0[] = +{ + {5.7f,57.1429f}, + {91.4143f,57.1429f} +}; + +static const SFG_StrokeVertex ch61st1[] = +{ + {5.7f,28.5714f}, + {91.4143f,28.5714f} +}; + +static const SFG_StrokeStrip ch61st[] = +{ + {2,ch61st0}, + {2,ch61st1} +}; + +static const SFG_StrokeChar ch61 = {97.2543f,2,ch61st}; + +/* char: 0x3e */ + +static const SFG_StrokeVertex ch62st0[] = +{ + {2.78f,85.7143f}, + {78.9705f,42.8571f}, + {2.78f,0.0f} +}; + +static const SFG_StrokeStrip ch62st[] = +{ + {3,ch62st0} +}; + +static const SFG_StrokeChar ch62 = {81.6105f,1,ch62st}; + +/* char: 0x3f */ + +static const SFG_StrokeVertex ch63st0[] = +{ + {8.42f,76.1905f}, + {8.42f,80.9524f}, + {13.1819f,90.4762f}, + {17.9438f,95.2381f}, + {27.4676f,100.0f}, + {46.5152f,100.0f}, + {56.039f,95.2381f}, + {60.801f,90.4762f}, + {65.5629f,80.9524f}, + {65.5629f,71.4286f}, + {60.801f,61.9048f}, + {56.039f,57.1429f}, + {36.9914f,47.619f}, + {36.9914f,33.3333f} +}; + +static const SFG_StrokeVertex ch63st1[] = +{ + {36.9914f,9.5238f}, + {32.2295f,4.7619f}, + {36.9914f,0.0f}, + {41.7533f,4.7619f}, + {36.9914f,9.5238f} +}; + +static const SFG_StrokeStrip ch63st[] = +{ + {14,ch63st0}, + {5,ch63st1} +}; + +static const SFG_StrokeChar ch63 = {73.9029f,2,ch63st}; + +/* char: 0x40 */ + +static const SFG_StrokeVertex ch64st0[] = +{ + {49.2171f,52.381f}, + {39.6933f,57.1429f}, + {30.1695f,57.1429f}, + {25.4076f,47.619f}, + {25.4076f,42.8571f}, + {30.1695f,33.3333f}, + {39.6933f,33.3333f}, + {49.2171f,38.0952f} +}; + +static const SFG_StrokeVertex ch64st1[] = +{ + {49.2171f,57.1429f}, + {49.2171f,38.0952f}, + {53.979f,33.3333f}, + {63.5029f,33.3333f}, + {68.2648f,42.8571f}, + {68.2648f,47.619f}, + {63.5029f,61.9048f}, + {53.979f,71.4286f}, + {39.6933f,76.1905f}, + {34.9314f,76.1905f}, + {20.6457f,71.4286f}, + {11.1219f,61.9048f}, + {6.36f,47.619f}, + {6.36f,42.8571f}, + {11.1219f,28.5714f}, + {20.6457f,19.0476f}, + {34.9314f,14.2857f}, + {39.6933f,14.2857f}, + {53.979f,19.0476f} +}; + +static const SFG_StrokeStrip ch64st[] = +{ + {8,ch64st0}, + {19,ch64st1} +}; + +static const SFG_StrokeChar ch64 = {74.3648f,2,ch64st}; + +/* char: 0x41 */ + +static const SFG_StrokeVertex ch65st0[] = +{ + {40.5952f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeVertex ch65st1[] = +{ + {40.5952f,100.0f}, + {78.6905f,0.0f} +}; + +static const SFG_StrokeVertex ch65st2[] = +{ + {16.7857f,33.3333f}, + {64.4048f,33.3333f} +}; + +static const SFG_StrokeStrip ch65st[] = +{ + {2,ch65st0}, + {2,ch65st1}, + {2,ch65st2} +}; + +static const SFG_StrokeChar ch65 = {80.4905f,3,ch65st}; + +/* char: 0x42 */ + +static const SFG_StrokeVertex ch66st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch66st1[] = +{ + {11.42f,100.0f}, + {54.2771f,100.0f}, + {68.5629f,95.2381f}, + {73.3248f,90.4762f}, + {78.0867f,80.9524f}, + {78.0867f,71.4286f}, + {73.3248f,61.9048f}, + {68.5629f,57.1429f}, + {54.2771f,52.381f} +}; + +static const SFG_StrokeVertex ch66st2[] = +{ + {11.42f,52.381f}, + {54.2771f,52.381f}, + {68.5629f,47.619f}, + {73.3248f,42.8571f}, + {78.0867f,33.3333f}, + {78.0867f,19.0476f}, + {73.3248f,9.5238f}, + {68.5629f,4.7619f}, + {54.2771f,0.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeStrip ch66st[] = +{ + {2,ch66st0}, + {9,ch66st1}, + {10,ch66st2} +}; + +static const SFG_StrokeChar ch66 = {83.6267f,3,ch66st}; + +/* char: 0x43 */ + +static const SFG_StrokeVertex ch67st0[] = +{ + {78.0886f,76.1905f}, + {73.3267f,85.7143f}, + {63.8029f,95.2381f}, + {54.279f,100.0f}, + {35.2314f,100.0f}, + {25.7076f,95.2381f}, + {16.1838f,85.7143f}, + {11.4219f,76.1905f}, + {6.66f,61.9048f}, + {6.66f,38.0952f}, + {11.4219f,23.8095f}, + {16.1838f,14.2857f}, + {25.7076f,4.7619f}, + {35.2314f,0.0f}, + {54.279f,0.0f}, + {63.8029f,4.7619f}, + {73.3267f,14.2857f}, + {78.0886f,23.8095f} +}; + +static const SFG_StrokeStrip ch67st[] = +{ + {18,ch67st0} +}; + +static const SFG_StrokeChar ch67 = {84.4886f,1,ch67st}; + +/* char: 0x44 */ + +static const SFG_StrokeVertex ch68st0[] = +{ + {11.96f,100.0f}, + {11.96f,0.0f} +}; + +static const SFG_StrokeVertex ch68st1[] = +{ + {11.96f,100.0f}, + {45.2933f,100.0f}, + {59.579f,95.2381f}, + {69.1029f,85.7143f}, + {73.8648f,76.1905f}, + {78.6267f,61.9048f}, + {78.6267f,38.0952f}, + {73.8648f,23.8095f}, + {69.1029f,14.2857f}, + {59.579f,4.7619f}, + {45.2933f,0.0f}, + {11.96f,0.0f} +}; + +static const SFG_StrokeStrip ch68st[] = +{ + {2,ch68st0}, + {12,ch68st1} +}; + +static const SFG_StrokeChar ch68 = {85.2867f,2,ch68st}; + +/* char: 0x45 */ + +static const SFG_StrokeVertex ch69st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch69st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const SFG_StrokeVertex ch69st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const SFG_StrokeVertex ch69st3[] = +{ + {11.42f,0.0f}, + {73.3248f,0.0f} +}; + +static const SFG_StrokeStrip ch69st[] = +{ + {2,ch69st0}, + {2,ch69st1}, + {2,ch69st2}, + {2,ch69st3} +}; + +static const SFG_StrokeChar ch69 = {78.1848f,4,ch69st}; + +/* char: 0x46 */ + +static const SFG_StrokeVertex ch70st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch70st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const SFG_StrokeVertex ch70st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const SFG_StrokeStrip ch70st[] = +{ + {2,ch70st0}, + {2,ch70st1}, + {2,ch70st2} +}; + +static const SFG_StrokeChar ch70 = {78.7448f,3,ch70st}; + +/* char: 0x47 */ + +static const SFG_StrokeVertex ch71st0[] = +{ + {78.4886f,76.1905f}, + {73.7267f,85.7143f}, + {64.2029f,95.2381f}, + {54.679f,100.0f}, + {35.6314f,100.0f}, + {26.1076f,95.2381f}, + {16.5838f,85.7143f}, + {11.8219f,76.1905f}, + {7.06f,61.9048f}, + {7.06f,38.0952f}, + {11.8219f,23.8095f}, + {16.5838f,14.2857f}, + {26.1076f,4.7619f}, + {35.6314f,0.0f}, + {54.679f,0.0f}, + {64.2029f,4.7619f}, + {73.7267f,14.2857f}, + {78.4886f,23.8095f}, + {78.4886f,38.0952f} +}; + +static const SFG_StrokeVertex ch71st1[] = +{ + {54.679f,38.0952f}, + {78.4886f,38.0952f} +}; + +static const SFG_StrokeStrip ch71st[] = +{ + {19,ch71st0}, + {2,ch71st1} +}; + +static const SFG_StrokeChar ch71 = {89.7686f,2,ch71st}; + +/* char: 0x48 */ + +static const SFG_StrokeVertex ch72st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch72st1[] = +{ + {78.0867f,100.0f}, + {78.0867f,0.0f} +}; + +static const SFG_StrokeVertex ch72st2[] = +{ + {11.42f,52.381f}, + {78.0867f,52.381f} +}; + +static const SFG_StrokeStrip ch72st[] = +{ + {2,ch72st0}, + {2,ch72st1}, + {2,ch72st2} +}; + +static const SFG_StrokeChar ch72 = {89.0867f,3,ch72st}; + +/* char: 0x49 */ + +static const SFG_StrokeVertex ch73st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const SFG_StrokeStrip ch73st[] = +{ + {2,ch73st0} +}; + +static const SFG_StrokeChar ch73 = {21.3f,1,ch73st}; + +/* char: 0x4a */ + +static const SFG_StrokeVertex ch74st0[] = +{ + {50.119f,100.0f}, + {50.119f,23.8095f}, + {45.3571f,9.5238f}, + {40.5952f,4.7619f}, + {31.0714f,0.0f}, + {21.5476f,0.0f}, + {12.0238f,4.7619f}, + {7.2619f,9.5238f}, + {2.5f,23.8095f}, + {2.5f,33.3333f} +}; + +static const SFG_StrokeStrip ch74st[] = +{ + {10,ch74st0} +}; + +static const SFG_StrokeChar ch74 = {59.999f,1,ch74st}; + +/* char: 0x4b */ + +static const SFG_StrokeVertex ch75st0[] = +{ + {11.28f,100.0f}, + {11.28f,0.0f} +}; + +static const SFG_StrokeVertex ch75st1[] = +{ + {77.9467f,100.0f}, + {11.28f,33.3333f} +}; + +static const SFG_StrokeVertex ch75st2[] = +{ + {35.0895f,57.1429f}, + {77.9467f,0.0f} +}; + +static const SFG_StrokeStrip ch75st[] = +{ + {2,ch75st0}, + {2,ch75st1}, + {2,ch75st2} +}; + +static const SFG_StrokeChar ch75 = {79.3267f,3,ch75st}; + +/* char: 0x4c */ + +static const SFG_StrokeVertex ch76st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const SFG_StrokeVertex ch76st1[] = +{ + {11.68f,0.0f}, + {68.8229f,0.0f} +}; + +static const SFG_StrokeStrip ch76st[] = +{ + {2,ch76st0}, + {2,ch76st1} +}; + +static const SFG_StrokeChar ch76 = {71.3229f,2,ch76st}; + +/* char: 0x4d */ + +static const SFG_StrokeVertex ch77st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const SFG_StrokeVertex ch77st1[] = +{ + {10.86f,100.0f}, + {48.9552f,0.0f} +}; + +static const SFG_StrokeVertex ch77st2[] = +{ + {87.0505f,100.0f}, + {48.9552f,0.0f} +}; + +static const SFG_StrokeVertex ch77st3[] = +{ + {87.0505f,100.0f}, + {87.0505f,0.0f} +}; + +static const SFG_StrokeStrip ch77st[] = +{ + {2,ch77st0}, + {2,ch77st1}, + {2,ch77st2}, + {2,ch77st3} +}; + +static const SFG_StrokeChar ch77 = {97.2105f,4,ch77st}; + +/* char: 0x4e */ + +static const SFG_StrokeVertex ch78st0[] = +{ + {11.14f,100.0f}, + {11.14f,0.0f} +}; + +static const SFG_StrokeVertex ch78st1[] = +{ + {11.14f,100.0f}, + {77.8067f,0.0f} +}; + +static const SFG_StrokeVertex ch78st2[] = +{ + {77.8067f,100.0f}, + {77.8067f,0.0f} +}; + +static const SFG_StrokeStrip ch78st[] = +{ + {2,ch78st0}, + {2,ch78st1}, + {2,ch78st2} +}; + +static const SFG_StrokeChar ch78 = {88.8067f,3,ch78st}; + +/* char: 0x4f */ + +static const SFG_StrokeVertex ch79st0[] = +{ + {34.8114f,100.0f}, + {25.2876f,95.2381f}, + {15.7638f,85.7143f}, + {11.0019f,76.1905f}, + {6.24f,61.9048f}, + {6.24f,38.0952f}, + {11.0019f,23.8095f}, + {15.7638f,14.2857f}, + {25.2876f,4.7619f}, + {34.8114f,0.0f}, + {53.859f,0.0f}, + {63.3829f,4.7619f}, + {72.9067f,14.2857f}, + {77.6686f,23.8095f}, + {82.4305f,38.0952f}, + {82.4305f,61.9048f}, + {77.6686f,76.1905f}, + {72.9067f,85.7143f}, + {63.3829f,95.2381f}, + {53.859f,100.0f}, + {34.8114f,100.0f} +}; + +static const SFG_StrokeStrip ch79st[] = +{ + {21,ch79st0} +}; + +static const SFG_StrokeChar ch79 = {88.8305f,1,ch79st}; + +/* char: 0x50 */ + +static const SFG_StrokeVertex ch80st0[] = +{ + {12.1f,100.0f}, + {12.1f,0.0f} +}; + +static const SFG_StrokeVertex ch80st1[] = +{ + {12.1f,100.0f}, + {54.9571f,100.0f}, + {69.2429f,95.2381f}, + {74.0048f,90.4762f}, + {78.7667f,80.9524f}, + {78.7667f,66.6667f}, + {74.0048f,57.1429f}, + {69.2429f,52.381f}, + {54.9571f,47.619f}, + {12.1f,47.619f} +}; + +static const SFG_StrokeStrip ch80st[] = +{ + {2,ch80st0}, + {10,ch80st1} +}; + +static const SFG_StrokeChar ch80 = {85.6667f,2,ch80st}; + +/* char: 0x51 */ + +static const SFG_StrokeVertex ch81st0[] = +{ + {33.8714f,100.0f}, + {24.3476f,95.2381f}, + {14.8238f,85.7143f}, + {10.0619f,76.1905f}, + {5.3f,61.9048f}, + {5.3f,38.0952f}, + {10.0619f,23.8095f}, + {14.8238f,14.2857f}, + {24.3476f,4.7619f}, + {33.8714f,0.0f}, + {52.919f,0.0f}, + {62.4429f,4.7619f}, + {71.9667f,14.2857f}, + {76.7286f,23.8095f}, + {81.4905f,38.0952f}, + {81.4905f,61.9048f}, + {76.7286f,76.1905f}, + {71.9667f,85.7143f}, + {62.4429f,95.2381f}, + {52.919f,100.0f}, + {33.8714f,100.0f} +}; + +static const SFG_StrokeVertex ch81st1[] = +{ + {48.1571f,19.0476f}, + {76.7286f,-9.5238f} +}; + +static const SFG_StrokeStrip ch81st[] = +{ + {21,ch81st0}, + {2,ch81st1} +}; + +static const SFG_StrokeChar ch81 = {88.0905f,2,ch81st}; + +/* char: 0x52 */ + +static const SFG_StrokeVertex ch82st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const SFG_StrokeVertex ch82st1[] = +{ + {11.68f,100.0f}, + {54.5371f,100.0f}, + {68.8229f,95.2381f}, + {73.5848f,90.4762f}, + {78.3467f,80.9524f}, + {78.3467f,71.4286f}, + {73.5848f,61.9048f}, + {68.8229f,57.1429f}, + {54.5371f,52.381f}, + {11.68f,52.381f} +}; + +static const SFG_StrokeVertex ch82st2[] = +{ + {45.0133f,52.381f}, + {78.3467f,0.0f} +}; + +static const SFG_StrokeStrip ch82st[] = +{ + {2,ch82st0}, + {10,ch82st1}, + {2,ch82st2} +}; + +static const SFG_StrokeChar ch82 = {82.3667f,3,ch82st}; + +/* char: 0x53 */ + +static const SFG_StrokeVertex ch83st0[] = +{ + {74.6667f,85.7143f}, + {65.1429f,95.2381f}, + {50.8571f,100.0f}, + {31.8095f,100.0f}, + {17.5238f,95.2381f}, + {8.0f,85.7143f}, + {8.0f,76.1905f}, + {12.7619f,66.6667f}, + {17.5238f,61.9048f}, + {27.0476f,57.1429f}, + {55.619f,47.619f}, + {65.1429f,42.8571f}, + {69.9048f,38.0952f}, + {74.6667f,28.5714f}, + {74.6667f,14.2857f}, + {65.1429f,4.7619f}, + {50.8571f,0.0f}, + {31.8095f,0.0f}, + {17.5238f,4.7619f}, + {8.0f,14.2857f} +}; + +static const SFG_StrokeStrip ch83st[] = +{ + {20,ch83st0} +}; + +static const SFG_StrokeChar ch83 = {80.8267f,1,ch83st}; + +/* char: 0x54 */ + +static const SFG_StrokeVertex ch84st0[] = +{ + {35.6933f,100.0f}, + {35.6933f,0.0f} +}; + +static const SFG_StrokeVertex ch84st1[] = +{ + {2.36f,100.0f}, + {69.0267f,100.0f} +}; + +static const SFG_StrokeStrip ch84st[] = +{ + {2,ch84st0}, + {2,ch84st1} +}; + +static const SFG_StrokeChar ch84 = {71.9467f,2,ch84st}; + +/* char: 0x55 */ + +static const SFG_StrokeVertex ch85st0[] = +{ + {11.54f,100.0f}, + {11.54f,28.5714f}, + {16.3019f,14.2857f}, + {25.8257f,4.7619f}, + {40.1114f,0.0f}, + {49.6352f,0.0f}, + {63.921f,4.7619f}, + {73.4448f,14.2857f}, + {78.2067f,28.5714f}, + {78.2067f,100.0f} +}; + +static const SFG_StrokeStrip ch85st[] = +{ + {10,ch85st0} +}; + +static const SFG_StrokeChar ch85 = {89.4867f,1,ch85st}; + +/* char: 0x56 */ + +static const SFG_StrokeVertex ch86st0[] = +{ + {2.36f,100.0f}, + {40.4552f,0.0f} +}; + +static const SFG_StrokeVertex ch86st1[] = +{ + {78.5505f,100.0f}, + {40.4552f,0.0f} +}; + +static const SFG_StrokeStrip ch86st[] = +{ + {2,ch86st0}, + {2,ch86st1} +}; + +static const SFG_StrokeChar ch86 = {81.6105f,2,ch86st}; + +/* char: 0x57 */ + +static const SFG_StrokeVertex ch87st0[] = +{ + {2.22f,100.0f}, + {26.0295f,0.0f} +}; + +static const SFG_StrokeVertex ch87st1[] = +{ + {49.839f,100.0f}, + {26.0295f,0.0f} +}; + +static const SFG_StrokeVertex ch87st2[] = +{ + {49.839f,100.0f}, + {73.6486f,0.0f} +}; + +static const SFG_StrokeVertex ch87st3[] = +{ + {97.4581f,100.0f}, + {73.6486f,0.0f} +}; + +static const SFG_StrokeStrip ch87st[] = +{ + {2,ch87st0}, + {2,ch87st1}, + {2,ch87st2}, + {2,ch87st3} +}; + +static const SFG_StrokeChar ch87 = {100.518f,4,ch87st}; + +/* char: 0x58 */ + +static const SFG_StrokeVertex ch88st0[] = +{ + {2.5f,100.0f}, + {69.1667f,0.0f} +}; + +static const SFG_StrokeVertex ch88st1[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeStrip ch88st[] = +{ + {2,ch88st0}, + {2,ch88st1} +}; + +static const SFG_StrokeChar ch88 = {72.3667f,2,ch88st}; + +/* char: 0x59 */ + +static const SFG_StrokeVertex ch89st0[] = +{ + {1.52f,100.0f}, + {39.6152f,52.381f}, + {39.6152f,0.0f} +}; + +static const SFG_StrokeVertex ch89st1[] = +{ + {77.7105f,100.0f}, + {39.6152f,52.381f} +}; + +static const SFG_StrokeStrip ch89st[] = +{ + {3,ch89st0}, + {2,ch89st1} +}; + +static const SFG_StrokeChar ch89 = {79.6505f,2,ch89st}; + +/* char: 0x5a */ + +static const SFG_StrokeVertex ch90st0[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeVertex ch90st1[] = +{ + {2.5f,100.0f}, + {69.1667f,100.0f} +}; + +static const SFG_StrokeVertex ch90st2[] = +{ + {2.5f,0.0f}, + {69.1667f,0.0f} +}; + +static const SFG_StrokeStrip ch90st[] = +{ + {2,ch90st0}, + {2,ch90st1}, + {2,ch90st2} +}; + +static const SFG_StrokeChar ch90 = {73.7467f,3,ch90st}; + +/* char: 0x5b */ + +static const SFG_StrokeVertex ch91st0[] = +{ + {7.78f,119.048f}, + {7.78f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st1[] = +{ + {12.5419f,119.048f}, + {12.5419f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st2[] = +{ + {7.78f,119.048f}, + {41.1133f,119.048f} +}; + +static const SFG_StrokeVertex ch91st3[] = +{ + {7.78f,-33.3333f}, + {41.1133f,-33.3333f} +}; + +static const SFG_StrokeStrip ch91st[] = +{ + {2,ch91st0}, + {2,ch91st1}, + {2,ch91st2}, + {2,ch91st3} +}; + +static const SFG_StrokeChar ch91 = {46.1133f,4,ch91st}; + +/* char: 0x5c */ + +static const SFG_StrokeVertex ch92st0[] = +{ + {5.84f,100.0f}, + {72.5067f,-14.2857f} +}; + +static const SFG_StrokeStrip ch92st[] = +{ + {2,ch92st0} +}; + +static const SFG_StrokeChar ch92 = {78.2067f,1,ch92st}; + +/* char: 0x5d */ + +static const SFG_StrokeVertex ch93st0[] = +{ + {33.0114f,119.048f}, + {33.0114f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st1[] = +{ + {37.7733f,119.048f}, + {37.7733f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st2[] = +{ + {4.44f,119.048f}, + {37.7733f,119.048f} +}; + +static const SFG_StrokeVertex ch93st3[] = +{ + {4.44f,-33.3333f}, + {37.7733f,-33.3333f} +}; + +static const SFG_StrokeStrip ch93st[] = +{ + {2,ch93st0}, + {2,ch93st1}, + {2,ch93st2}, + {2,ch93st3} +}; + +static const SFG_StrokeChar ch93 = {46.3933f,4,ch93st}; + +/* char: 0x5e */ + +static const SFG_StrokeVertex ch94st0[] = +{ + {44.0752f,109.524f}, + {5.98f,42.8571f} +}; + +static const SFG_StrokeVertex ch94st1[] = +{ + {44.0752f,109.524f}, + {82.1705f,42.8571f} +}; + +static const SFG_StrokeStrip ch94st[] = +{ + {2,ch94st0}, + {2,ch94st1} +}; + +static const SFG_StrokeChar ch94 = {90.2305f,2,ch94st}; + +/* char: 0x5f */ + +static const SFG_StrokeVertex ch95st0[] = +{ + {-1.1f,-33.3333f}, + {103.662f,-33.3333f}, + {103.662f,-28.5714f}, + {-1.1f,-28.5714f}, + {-1.1f,-33.3333f} +}; + +static const SFG_StrokeStrip ch95st[] = +{ + {5,ch95st0} +}; + +static const SFG_StrokeChar ch95 = {104.062f,1,ch95st}; + +/* char: 0x60 */ + +static const SFG_StrokeVertex ch96st0[] = +{ + {33.0219f,100.0f}, + {56.8314f,71.4286f} +}; + +static const SFG_StrokeVertex ch96st1[] = +{ + {33.0219f,100.0f}, + {28.26f,95.2381f}, + {56.8314f,71.4286f} +}; + +static const SFG_StrokeStrip ch96st[] = +{ + {2,ch96st0}, + {3,ch96st1} +}; + +static const SFG_StrokeChar ch96 = {83.5714f,2,ch96st}; + +/* char: 0x61 */ + +static const SFG_StrokeVertex ch97st0[] = +{ + {63.8229f,66.6667f}, + {63.8229f,0.0f} +}; + +static const SFG_StrokeVertex ch97st1[] = +{ + {63.8229f,52.381f}, + {54.299f,61.9048f}, + {44.7752f,66.6667f}, + {30.4895f,66.6667f}, + {20.9657f,61.9048f}, + {11.4419f,52.381f}, + {6.68f,38.0952f}, + {6.68f,28.5714f}, + {11.4419f,14.2857f}, + {20.9657f,4.7619f}, + {30.4895f,0.0f}, + {44.7752f,0.0f}, + {54.299f,4.7619f}, + {63.8229f,14.2857f} +}; + +static const SFG_StrokeStrip ch97st[] = +{ + {2,ch97st0}, + {14,ch97st1} +}; + +static const SFG_StrokeChar ch97 = {66.6029f,2,ch97st}; + +/* char: 0x62 */ + +static const SFG_StrokeVertex ch98st0[] = +{ + {8.76f,100.0f}, + {8.76f,0.0f} +}; + +static const SFG_StrokeVertex ch98st1[] = +{ + {8.76f,52.381f}, + {18.2838f,61.9048f}, + {27.8076f,66.6667f}, + {42.0933f,66.6667f}, + {51.6171f,61.9048f}, + {61.141f,52.381f}, + {65.9029f,38.0952f}, + {65.9029f,28.5714f}, + {61.141f,14.2857f}, + {51.6171f,4.7619f}, + {42.0933f,0.0f}, + {27.8076f,0.0f}, + {18.2838f,4.7619f}, + {8.76f,14.2857f} +}; + +static const SFG_StrokeStrip ch98st[] = +{ + {2,ch98st0}, + {14,ch98st1} +}; + +static const SFG_StrokeChar ch98 = {70.4629f,2,ch98st}; + +/* char: 0x63 */ + +static const SFG_StrokeVertex ch99st0[] = +{ + {62.6629f,52.381f}, + {53.139f,61.9048f}, + {43.6152f,66.6667f}, + {29.3295f,66.6667f}, + {19.8057f,61.9048f}, + {10.2819f,52.381f}, + {5.52f,38.0952f}, + {5.52f,28.5714f}, + {10.2819f,14.2857f}, + {19.8057f,4.7619f}, + {29.3295f,0.0f}, + {43.6152f,0.0f}, + {53.139f,4.7619f}, + {62.6629f,14.2857f} +}; + +static const SFG_StrokeStrip ch99st[] = +{ + {14,ch99st0} +}; + +static const SFG_StrokeChar ch99 = {68.9229f,1,ch99st}; + +/* char: 0x64 */ + +static const SFG_StrokeVertex ch100st0[] = +{ + {61.7829f,100.0f}, + {61.7829f,0.0f} +}; + +static const SFG_StrokeVertex ch100st1[] = +{ + {61.7829f,52.381f}, + {52.259f,61.9048f}, + {42.7352f,66.6667f}, + {28.4495f,66.6667f}, + {18.9257f,61.9048f}, + {9.4019f,52.381f}, + {4.64f,38.0952f}, + {4.64f,28.5714f}, + {9.4019f,14.2857f}, + {18.9257f,4.7619f}, + {28.4495f,0.0f}, + {42.7352f,0.0f}, + {52.259f,4.7619f}, + {61.7829f,14.2857f} +}; + +static const SFG_StrokeStrip ch100st[] = +{ + {2,ch100st0}, + {14,ch100st1} +}; + +static const SFG_StrokeChar ch100 = {70.2629f,2,ch100st}; + +/* char: 0x65 */ + +static const SFG_StrokeVertex ch101st0[] = +{ + {5.72f,38.0952f}, + {62.8629f,38.0952f}, + {62.8629f,47.619f}, + {58.101f,57.1429f}, + {53.339f,61.9048f}, + {43.8152f,66.6667f}, + {29.5295f,66.6667f}, + {20.0057f,61.9048f}, + {10.4819f,52.381f}, + {5.72f,38.0952f}, + {5.72f,28.5714f}, + {10.4819f,14.2857f}, + {20.0057f,4.7619f}, + {29.5295f,0.0f}, + {43.8152f,0.0f}, + {53.339f,4.7619f}, + {62.8629f,14.2857f} +}; + +static const SFG_StrokeStrip ch101st[] = +{ + {17,ch101st0} +}; + +static const SFG_StrokeChar ch101 = {68.5229f,1,ch101st}; + +/* char: 0x66 */ + +static const SFG_StrokeVertex ch102st0[] = +{ + {38.7752f,100.0f}, + {29.2514f,100.0f}, + {19.7276f,95.2381f}, + {14.9657f,80.9524f}, + {14.9657f,0.0f} +}; + +static const SFG_StrokeVertex ch102st1[] = +{ + {0.68f,66.6667f}, + {34.0133f,66.6667f} +}; + +static const SFG_StrokeStrip ch102st[] = +{ + {5,ch102st0}, + {2,ch102st1} +}; + +static const SFG_StrokeChar ch102 = {38.6552f,2,ch102st}; + +/* char: 0x67 */ + +static const SFG_StrokeVertex ch103st0[] = +{ + {62.5029f,66.6667f}, + {62.5029f,-9.5238f}, + {57.741f,-23.8095f}, + {52.979f,-28.5714f}, + {43.4552f,-33.3333f}, + {29.1695f,-33.3333f}, + {19.6457f,-28.5714f} +}; + +static const SFG_StrokeVertex ch103st1[] = +{ + {62.5029f,52.381f}, + {52.979f,61.9048f}, + {43.4552f,66.6667f}, + {29.1695f,66.6667f}, + {19.6457f,61.9048f}, + {10.1219f,52.381f}, + {5.36f,38.0952f}, + {5.36f,28.5714f}, + {10.1219f,14.2857f}, + {19.6457f,4.7619f}, + {29.1695f,0.0f}, + {43.4552f,0.0f}, + {52.979f,4.7619f}, + {62.5029f,14.2857f} +}; + +static const SFG_StrokeStrip ch103st[] = +{ + {7,ch103st0}, + {14,ch103st1} +}; + +static const SFG_StrokeChar ch103 = {70.9829f,2,ch103st}; + +/* char: 0x68 */ + +static const SFG_StrokeVertex ch104st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch104st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeStrip ch104st[] = +{ + {2,ch104st0}, + {7,ch104st1} +}; + +static const SFG_StrokeChar ch104 = {71.021f,2,ch104st}; + +/* char: 0x69 */ + +static const SFG_StrokeVertex ch105st0[] = +{ + {10.02f,100.0f}, + {14.7819f,95.2381f}, + {19.5438f,100.0f}, + {14.7819f,104.762f}, + {10.02f,100.0f} +}; + +static const SFG_StrokeVertex ch105st1[] = +{ + {14.7819f,66.6667f}, + {14.7819f,0.0f} +}; + +static const SFG_StrokeStrip ch105st[] = +{ + {5,ch105st0}, + {2,ch105st1} +}; + +static const SFG_StrokeChar ch105 = {28.8638f,2,ch105st}; + +/* char: 0x6a */ + +static const SFG_StrokeVertex ch106st0[] = +{ + {17.3876f,100.0f}, + {22.1495f,95.2381f}, + {26.9114f,100.0f}, + {22.1495f,104.762f}, + {17.3876f,100.0f} +}; + +static const SFG_StrokeVertex ch106st1[] = +{ + {22.1495f,66.6667f}, + {22.1495f,-14.2857f}, + {17.3876f,-28.5714f}, + {7.8638f,-33.3333f}, + {-1.66f,-33.3333f} +}; + +static const SFG_StrokeStrip ch106st[] = +{ + {5,ch106st0}, + {5,ch106st1} +}; + +static const SFG_StrokeChar ch106 = {36.2314f,2,ch106st}; + +/* char: 0x6b */ + +static const SFG_StrokeVertex ch107st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch107st1[] = +{ + {57.219f,66.6667f}, + {9.6f,19.0476f} +}; + +static const SFG_StrokeVertex ch107st2[] = +{ + {28.6476f,38.0952f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeStrip ch107st[] = +{ + {2,ch107st0}, + {2,ch107st1}, + {2,ch107st2} +}; + +static const SFG_StrokeChar ch107 = {62.521f,3,ch107st}; + +/* char: 0x6c */ + +static const SFG_StrokeVertex ch108st0[] = +{ + {10.02f,100.0f}, + {10.02f,0.0f} +}; + +static const SFG_StrokeStrip ch108st[] = +{ + {2,ch108st0} +}; + +static const SFG_StrokeChar ch108 = {19.34f,1,ch108st}; + +/* char: 0x6d */ + +static const SFG_StrokeVertex ch109st0[] = +{ + {9.6f,66.6667f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch109st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeVertex ch109st2[] = +{ + {61.981f,47.619f}, + {76.2667f,61.9048f}, + {85.7905f,66.6667f}, + {100.076f,66.6667f}, + {109.6f,61.9048f}, + {114.362f,47.619f}, + {114.362f,0.0f} +}; + +static const SFG_StrokeStrip ch109st[] = +{ + {2,ch109st0}, + {7,ch109st1}, + {7,ch109st2} +}; + +static const SFG_StrokeChar ch109 = {123.962f,3,ch109st}; + +/* char: 0x6e */ + +static const SFG_StrokeVertex ch110st0[] = +{ + {9.18f,66.6667f}, + {9.18f,0.0f} +}; + +static const SFG_StrokeVertex ch110st1[] = +{ + {9.18f,47.619f}, + {23.4657f,61.9048f}, + {32.9895f,66.6667f}, + {47.2752f,66.6667f}, + {56.799f,61.9048f}, + {61.561f,47.619f}, + {61.561f,0.0f} +}; + +static const SFG_StrokeStrip ch110st[] = +{ + {2,ch110st0}, + {7,ch110st1} +}; + +static const SFG_StrokeChar ch110 = {70.881f,2,ch110st}; + +/* char: 0x6f */ + +static const SFG_StrokeVertex ch111st0[] = +{ + {28.7895f,66.6667f}, + {19.2657f,61.9048f}, + {9.7419f,52.381f}, + {4.98f,38.0952f}, + {4.98f,28.5714f}, + {9.7419f,14.2857f}, + {19.2657f,4.7619f}, + {28.7895f,0.0f}, + {43.0752f,0.0f}, + {52.599f,4.7619f}, + {62.1229f,14.2857f}, + {66.8848f,28.5714f}, + {66.8848f,38.0952f}, + {62.1229f,52.381f}, + {52.599f,61.9048f}, + {43.0752f,66.6667f}, + {28.7895f,66.6667f} +}; + +static const SFG_StrokeStrip ch111st[] = +{ + {17,ch111st0} +}; + +static const SFG_StrokeChar ch111 = {71.7448f,1,ch111st}; + +/* char: 0x70 */ + +static const SFG_StrokeVertex ch112st0[] = +{ + {9.46f,66.6667f}, + {9.46f,-33.3333f} +}; + +static const SFG_StrokeVertex ch112st1[] = +{ + {9.46f,52.381f}, + {18.9838f,61.9048f}, + {28.5076f,66.6667f}, + {42.7933f,66.6667f}, + {52.3171f,61.9048f}, + {61.841f,52.381f}, + {66.6029f,38.0952f}, + {66.6029f,28.5714f}, + {61.841f,14.2857f}, + {52.3171f,4.7619f}, + {42.7933f,0.0f}, + {28.5076f,0.0f}, + {18.9838f,4.7619f}, + {9.46f,14.2857f} +}; + +static const SFG_StrokeStrip ch112st[] = +{ + {2,ch112st0}, + {14,ch112st1} +}; + +static const SFG_StrokeChar ch112 = {70.8029f,2,ch112st}; + +/* char: 0x71 */ + +static const SFG_StrokeVertex ch113st0[] = +{ + {61.9829f,66.6667f}, + {61.9829f,-33.3333f} +}; + +static const SFG_StrokeVertex ch113st1[] = +{ + {61.9829f,52.381f}, + {52.459f,61.9048f}, + {42.9352f,66.6667f}, + {28.6495f,66.6667f}, + {19.1257f,61.9048f}, + {9.6019f,52.381f}, + {4.84f,38.0952f}, + {4.84f,28.5714f}, + {9.6019f,14.2857f}, + {19.1257f,4.7619f}, + {28.6495f,0.0f}, + {42.9352f,0.0f}, + {52.459f,4.7619f}, + {61.9829f,14.2857f} +}; + +static const SFG_StrokeStrip ch113st[] = +{ + {2,ch113st0}, + {14,ch113st1} +}; + +static const SFG_StrokeChar ch113 = {70.7429f,2,ch113st}; + +/* char: 0x72 */ + +static const SFG_StrokeVertex ch114st0[] = +{ + {9.46f,66.6667f}, + {9.46f,0.0f} +}; + +static const SFG_StrokeVertex ch114st1[] = +{ + {9.46f,38.0952f}, + {14.2219f,52.381f}, + {23.7457f,61.9048f}, + {33.2695f,66.6667f}, + {47.5552f,66.6667f} +}; + +static const SFG_StrokeStrip ch114st[] = +{ + {2,ch114st0}, + {5,ch114st1} +}; + +static const SFG_StrokeChar ch114 = {49.4952f,2,ch114st}; + +/* char: 0x73 */ + +static const SFG_StrokeVertex ch115st0[] = +{ + {57.081f,52.381f}, + {52.319f,61.9048f}, + {38.0333f,66.6667f}, + {23.7476f,66.6667f}, + {9.4619f,61.9048f}, + {4.7f,52.381f}, + {9.4619f,42.8571f}, + {18.9857f,38.0952f}, + {42.7952f,33.3333f}, + {52.319f,28.5714f}, + {57.081f,19.0476f}, + {57.081f,14.2857f}, + {52.319f,4.7619f}, + {38.0333f,0.0f}, + {23.7476f,0.0f}, + {9.4619f,4.7619f}, + {4.7f,14.2857f} +}; + +static const SFG_StrokeStrip ch115st[] = +{ + {17,ch115st0} +}; + +static const SFG_StrokeChar ch115 = {62.321f,1,ch115st}; + +/* char: 0x74 */ + +static const SFG_StrokeVertex ch116st0[] = +{ + {14.8257f,100.0f}, + {14.8257f,19.0476f}, + {19.5876f,4.7619f}, + {29.1114f,0.0f}, + {38.6352f,0.0f} +}; + +static const SFG_StrokeVertex ch116st1[] = +{ + {0.54f,66.6667f}, + {33.8733f,66.6667f} +}; + +static const SFG_StrokeStrip ch116st[] = +{ + {5,ch116st0}, + {2,ch116st1} +}; + +static const SFG_StrokeChar ch116 = {39.3152f,2,ch116st}; + +/* char: 0x75 */ + +static const SFG_StrokeVertex ch117st0[] = +{ + {9.46f,66.6667f}, + {9.46f,19.0476f}, + {14.2219f,4.7619f}, + {23.7457f,0.0f}, + {38.0314f,0.0f}, + {47.5552f,4.7619f}, + {61.841f,19.0476f} +}; + +static const SFG_StrokeVertex ch117st1[] = +{ + {61.841f,66.6667f}, + {61.841f,0.0f} +}; + +static const SFG_StrokeStrip ch117st[] = +{ + {7,ch117st0}, + {2,ch117st1} +}; + +static const SFG_StrokeChar ch117 = {71.161f,2,ch117st}; + +/* char: 0x76 */ + +static const SFG_StrokeVertex ch118st0[] = +{ + {1.8f,66.6667f}, + {30.3714f,0.0f} +}; + +static const SFG_StrokeVertex ch118st1[] = +{ + {58.9429f,66.6667f}, + {30.3714f,0.0f} +}; + +static const SFG_StrokeStrip ch118st[] = +{ + {2,ch118st0}, + {2,ch118st1} +}; + +static const SFG_StrokeChar ch118 = {60.6029f,2,ch118st}; + +/* char: 0x77 */ + +static const SFG_StrokeVertex ch119st0[] = +{ + {2.5f,66.6667f}, + {21.5476f,0.0f} +}; + +static const SFG_StrokeVertex ch119st1[] = +{ + {40.5952f,66.6667f}, + {21.5476f,0.0f} +}; + +static const SFG_StrokeVertex ch119st2[] = +{ + {40.5952f,66.6667f}, + {59.6429f,0.0f} +}; + +static const SFG_StrokeVertex ch119st3[] = +{ + {78.6905f,66.6667f}, + {59.6429f,0.0f} +}; + +static const SFG_StrokeStrip ch119st[] = +{ + {2,ch119st0}, + {2,ch119st1}, + {2,ch119st2}, + {2,ch119st3} +}; + +static const SFG_StrokeChar ch119 = {80.4905f,4,ch119st}; + +/* char: 0x78 */ + +static const SFG_StrokeVertex ch120st0[] = +{ + {1.66f,66.6667f}, + {54.041f,0.0f} +}; + +static const SFG_StrokeVertex ch120st1[] = +{ + {54.041f,66.6667f}, + {1.66f,0.0f} +}; + +static const SFG_StrokeStrip ch120st[] = +{ + {2,ch120st0}, + {2,ch120st1} +}; + +static const SFG_StrokeChar ch120 = {56.401f,2,ch120st}; + +/* char: 0x79 */ + +static const SFG_StrokeVertex ch121st0[] = +{ + {6.5619f,66.6667f}, + {35.1333f,0.0f} +}; + +static const SFG_StrokeVertex ch121st1[] = +{ + {63.7048f,66.6667f}, + {35.1333f,0.0f}, + {25.6095f,-19.0476f}, + {16.0857f,-28.5714f}, + {6.5619f,-33.3333f}, + {1.8f,-33.3333f} +}; + +static const SFG_StrokeStrip ch121st[] = +{ + {2,ch121st0}, + {6,ch121st1} +}; + +static const SFG_StrokeChar ch121 = {66.0648f,2,ch121st}; + +/* char: 0x7a */ + +static const SFG_StrokeVertex ch122st0[] = +{ + {56.821f,66.6667f}, + {4.44f,0.0f} +}; + +static const SFG_StrokeVertex ch122st1[] = +{ + {4.44f,66.6667f}, + {56.821f,66.6667f} +}; + +static const SFG_StrokeVertex ch122st2[] = +{ + {4.44f,0.0f}, + {56.821f,0.0f} +}; + +static const SFG_StrokeStrip ch122st[] = +{ + {2,ch122st0}, + {2,ch122st1}, + {2,ch122st2} +}; + +static const SFG_StrokeChar ch122 = {61.821f,3,ch122st}; + +/* char: 0x7b */ + +static const SFG_StrokeVertex ch123st0[] = +{ + {31.1895f,119.048f}, + {21.6657f,114.286f}, + {16.9038f,109.524f}, + {12.1419f,100.0f}, + {12.1419f,90.4762f}, + {16.9038f,80.9524f}, + {21.6657f,76.1905f}, + {26.4276f,66.6667f}, + {26.4276f,57.1429f}, + {16.9038f,47.619f} +}; + +static const SFG_StrokeVertex ch123st1[] = +{ + {21.6657f,114.286f}, + {16.9038f,104.762f}, + {16.9038f,95.2381f}, + {21.6657f,85.7143f}, + {26.4276f,80.9524f}, + {31.1895f,71.4286f}, + {31.1895f,61.9048f}, + {26.4276f,52.381f}, + {7.38f,42.8571f}, + {26.4276f,33.3333f}, + {31.1895f,23.8095f}, + {31.1895f,14.2857f}, + {26.4276f,4.7619f}, + {21.6657f,0.0f}, + {16.9038f,-9.5238f}, + {16.9038f,-19.0476f}, + {21.6657f,-28.5714f} +}; + +static const SFG_StrokeVertex ch123st2[] = +{ + {16.9038f,38.0952f}, + {26.4276f,28.5714f}, + {26.4276f,19.0476f}, + {21.6657f,9.5238f}, + {16.9038f,4.7619f}, + {12.1419f,-4.7619f}, + {12.1419f,-14.2857f}, + {16.9038f,-23.8095f}, + {21.6657f,-28.5714f}, + {31.1895f,-33.3333f} +}; + +static const SFG_StrokeStrip ch123st[] = +{ + {10,ch123st0}, + {17,ch123st1}, + {10,ch123st2} +}; + +static const SFG_StrokeChar ch123 = {41.6295f,3,ch123st}; + +/* char: 0x7c */ + +static const SFG_StrokeVertex ch124st0[] = +{ + {11.54f,119.048f}, + {11.54f,-33.3333f} +}; + +static const SFG_StrokeStrip ch124st[] = +{ + {2,ch124st0} +}; + +static const SFG_StrokeChar ch124 = {23.78f,1,ch124st}; + +/* char: 0x7d */ + +static const SFG_StrokeVertex ch125st0[] = +{ + {9.18f,119.048f}, + {18.7038f,114.286f}, + {23.4657f,109.524f}, + {28.2276f,100.0f}, + {28.2276f,90.4762f}, + {23.4657f,80.9524f}, + {18.7038f,76.1905f}, + {13.9419f,66.6667f}, + {13.9419f,57.1429f}, + {23.4657f,47.619f} +}; + +static const SFG_StrokeVertex ch125st1[] = +{ + {18.7038f,114.286f}, + {23.4657f,104.762f}, + {23.4657f,95.2381f}, + {18.7038f,85.7143f}, + {13.9419f,80.9524f}, + {9.18f,71.4286f}, + {9.18f,61.9048f}, + {13.9419f,52.381f}, + {32.9895f,42.8571f}, + {13.9419f,33.3333f}, + {9.18f,23.8095f}, + {9.18f,14.2857f}, + {13.9419f,4.7619f}, + {18.7038f,0.0f}, + {23.4657f,-9.5238f}, + {23.4657f,-19.0476f}, + {18.7038f,-28.5714f} +}; + +static const SFG_StrokeVertex ch125st2[] = +{ + {23.4657f,38.0952f}, + {13.9419f,28.5714f}, + {13.9419f,19.0476f}, + {18.7038f,9.5238f}, + {23.4657f,4.7619f}, + {28.2276f,-4.7619f}, + {28.2276f,-14.2857f}, + {23.4657f,-23.8095f}, + {18.7038f,-28.5714f}, + {9.18f,-33.3333f} +}; + +static const SFG_StrokeStrip ch125st[] = +{ + {10,ch125st0}, + {17,ch125st1}, + {10,ch125st2} +}; + +static const SFG_StrokeChar ch125 = {41.4695f,3,ch125st}; + +/* char: 0x7e */ + +static const SFG_StrokeVertex ch126st0[] = +{ + {2.92f,28.5714f}, + {2.92f,38.0952f}, + {7.6819f,52.381f}, + {17.2057f,57.1429f}, + {26.7295f,57.1429f}, + {36.2533f,52.381f}, + {55.301f,38.0952f}, + {64.8248f,33.3333f}, + {74.3486f,33.3333f}, + {83.8724f,38.0952f}, + {88.6343f,47.619f} +}; + +static const SFG_StrokeVertex ch126st1[] = +{ + {2.92f,38.0952f}, + {7.6819f,47.619f}, + {17.2057f,52.381f}, + {26.7295f,52.381f}, + {36.2533f,47.619f}, + {55.301f,33.3333f}, + {64.8248f,28.5714f}, + {74.3486f,28.5714f}, + {83.8724f,33.3333f}, + {88.6343f,47.619f}, + {88.6343f,57.1429f} +}; + +static const SFG_StrokeStrip ch126st[] = +{ + {11,ch126st0}, + {11,ch126st1} +}; + +static const SFG_StrokeChar ch126 = {91.2743f,2,ch126st}; + +/* char: 0x7f */ + +static const SFG_StrokeVertex ch127st0[] = +{ + {52.381f,100.0f}, + {14.2857f,-33.3333f} +}; + +static const SFG_StrokeVertex ch127st1[] = +{ + {28.5714f,66.6667f}, + {14.2857f,61.9048f}, + {4.7619f,52.381f}, + {0.0f,38.0952f}, + {0.0f,23.8095f}, + {4.7619f,14.2857f}, + {14.2857f,4.7619f}, + {28.5714f,0.0f}, + {38.0952f,0.0f}, + {52.381f,4.7619f}, + {61.9048f,14.2857f}, + {66.6667f,28.5714f}, + {66.6667f,42.8571f}, + {61.9048f,52.381f}, + {52.381f,61.9048f}, + {38.0952f,66.6667f}, + {28.5714f,66.6667f} +}; + +static const SFG_StrokeStrip ch127st[] = +{ + {2,ch127st0}, + {17,ch127st1} +}; + +static const SFG_StrokeChar ch127 = {66.6667f,2,ch127st}; + +static const SFG_StrokeChar *chars[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &ch32, &ch33, &ch34, &ch35, &ch36, &ch37, &ch38, &ch39, + &ch40, &ch41, &ch42, &ch43, &ch44, &ch45, &ch46, &ch47, + &ch48, &ch49, &ch50, &ch51, &ch52, &ch53, &ch54, &ch55, + &ch56, &ch57, &ch58, &ch59, &ch60, &ch61, &ch62, &ch63, + &ch64, &ch65, &ch66, &ch67, &ch68, &ch69, &ch70, &ch71, + &ch72, &ch73, &ch74, &ch75, &ch76, &ch77, &ch78, &ch79, + &ch80, &ch81, &ch82, &ch83, &ch84, &ch85, &ch86, &ch87, + &ch88, &ch89, &ch90, &ch91, &ch92, &ch93, &ch94, &ch95, + &ch96, &ch97, &ch98, &ch99, &ch100, &ch101, &ch102, &ch103, + &ch104, &ch105, &ch106, &ch107, &ch108, &ch109, &ch110, &ch111, + &ch112, &ch113, &ch114, &ch115, &ch116, &ch117, &ch118, &ch119, + &ch120, &ch121, &ch122, &ch123, &ch124, &ch125, &ch126, &ch127 +}; + +const SFG_StrokeFont fgStrokeRoman = {"Roman",128,152.381f,chars}; + +#endif // ndef GIAC_GGB diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/gauss.cc b/android/app/src/main/cpp/giac/src/giac/cpp/gauss.cc new file mode 100644 index 0000000..07ca8cb --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/gauss.cc @@ -0,0 +1,1095 @@ +// -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c gauss.cc -Wall" -*- +#include "giacPCH.h" + +/* + * Copyright (C) 2001,14 R. De Graeve, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using namespace std; +//#include +#include "gauss.h" +#include "vecteur.h" +#include "derive.h" +#include "subst.h" +#include "usual.h" +#include "sym2poly.h" +#include "solve.h" +#include "ti89.h" +#include "plot.h" +#include "misc.h" +#include "ifactor.h" +#include "prog.h" +#include "giacintl.h" + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + vecteur quad(int &b,const gen & q, const vecteur & x,GIAC_CONTEXT){ + //x=vecteur des variables, q=la fonction a tester,n=la dimension de x + //b=2 si q est quadratique,=0,1 ou 3 si il y des termes d'ordre 0,1 ou 3 + //renvoie (la jacobienne de q)/2 + gen qs; + gen dq; + gen dqs; + gen qdd; + int n=int(x.size()); + + vecteur A; + //creation d'une matrice carree A d'ordre n + for (int i=0;isize()); + if (s!=2) + return gendimerr(contextptr); + if (args._VECTptr->back().type==_VECT) + return qxa(args._VECTptr->front(),*args._VECTptr->back()._VECTptr,contextptr); + return symb_q2a(args); + } + static const char _q2a_s []="q2a"; + static define_unary_function_eval (__q2a,&_q2a,_q2a_s); + define_unary_function_ptr5( at_q2a ,alias_at_q2a,&__q2a,0,true); + + vecteur gauss(const gen & q, const vecteur & x, vecteur & D, vecteur & U, vecteur & P,GIAC_CONTEXT){ + int n=int(x.size()),b; + gen u1,u2,q1,l1,l2; + vecteur R(1); + vecteur PR; + for (int i=0;i2 et on retourne q + vecteur A(quad(b,q,x,contextptr)); + if (b!=2){ + R[0]=q; + D.clear(); + U.clear(); + return R; + } + //la forme q est quadratique de matrice A + if (q==0) { + //R[0]=q; + vecteur vide(n); + D=vide; + U=vide; + P=I; + return vide; + } + if (n==1){ + gen q0=_factor(q,contextptr); + R[0]=q0; + vecteur un(1); + un[0]=A[0][0]; + D=un; + U=x; + P=I; + return(R); + } + int r; + r=n; + for (int i=n-1 ;i>=0;i--){ + if (A[i][i]!=0) { + r=i; + } + } + if (r!=n) { + //il y a des termes carres + u1=recursive_normal(rdiv(derive(q,x[r],contextptr),plus_two,contextptr),contextptr); + q1=recursive_normal(q-rdiv(u1*u1,A[r][r],contextptr),contextptr); + vecteur y; + //y contient les variables qui restent (on enleve x[r]) + for (int j=0;j=0;i--){ + for (int j=i+1;j>=1;j--){ + if (A[i][j]!=0) { + r1=i; + r2=j; + } + } + } + l1=rdiv(derive(q,x[r1],contextptr),2,contextptr); + l2=rdiv(derive(q,x[r2],contextptr),2,contextptr); + u1=recursive_normal(l1+l2,contextptr); + u2=recursive_normal(l1-l2,contextptr); + q1=recursive_normal(q-rdiv(plus_two*l1*l2,A[r1][r2],contextptr),contextptr); + vecteur y; + for (int j=0;jsize()); + if (s<2) + return gendimerr(contextptr); + const gen & arg1=(*args._VECTptr)[1]; + if (arg1.type==_VECT){ + const vecteur & v=*arg1._VECTptr; + vecteur D,U,P; + gen w=gauss(args._VECTptr->front(),v.empty()?lidnt(args):v,D,U,P,contextptr); + w=_plus(w,contextptr); + if (s>2|| v.empty()) + return makesequence(w,D,P); + return w; + } + return _randNorm(args,contextptr); + } + static const char _gauss_s []="gauss"; + static define_unary_function_eval (__gauss,&_gauss,_gauss_s); + define_unary_function_ptr5( at_gauss ,alias_at_gauss,&__gauss,0,true); + + gen axq(const vecteur &A,const vecteur & x,GIAC_CONTEXT){ + //transforme une matrice carree (symetrique) en la forme quadratique q + //(les variables sont dans x) + //d nbre de variables + //il faut verifier que A est carree + //A n'est pas forcement symetrique + int d=int(x.size()); + int da=int(A.size()); + if (!(is_squarematrix(A)) || (da!=d) ) + return gensizeerr(gettext("Invalid dimension")); + vecteur Ax; + multmatvecteur(A,x,Ax); + return normal(dotvecteur(x,Ax),contextptr); + } + + static gen symb_a2q(const gen & args){ + return symbolic(at_a2q,args); + } + gen _a2q(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT || args._VECTptr->empty()) + return gensizeerr(contextptr); + int s=int(args._VECTptr->size()); + if (args.subtype!=_SEQ__VECT && s<=6){ + vecteur vars(makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e,t__IDNT_e,u__IDNT_e,v__IDNT_e)); + vars.erase(vars.begin()+s,vars.end()); + return _a2q(makesequence(args,vars),contextptr); + } + if (s!=2) + return gendimerr(contextptr); + const vecteur & v = *args._VECTptr; + if (ckmatrix(v.front()) && v.back().type==_VECT) + return axq(*v.front()._VECTptr,*v.back()._VECTptr,contextptr); + return symb_a2q(args); + } + static const char _a2q_s []="a2q"; + static define_unary_function_eval (__a2q,&_a2q,_a2q_s); + define_unary_function_ptr5( at_a2q ,alias_at_a2q,&__a2q,0,true); + + vecteur qxac(const gen &q,const vecteur & x,GIAC_CONTEXT){ + //transforme une forme quadratique en une matrice symetrique A + //(les variables sont dans x) + int d; + //d nbre de variables + d=int(x.size()); + // int da; + //il faut verifier que q est quadratique + vecteur A; + int b; + A=quad(b,q,x,contextptr); + if (b==2) { + return(A); + } + else { + return vecteur(1,gensizeerr(gettext("q is not quadratic"))); + } + } + + // rational parametrization of a conic, given cartesian equation and point over + gen conique_ratparam(const gen & eq,const gen & M,GIAC_CONTEXT){ + if (is_undef(M)) + return undef; + gen Mx,My,x(x__IDNT_e),y(y__IDNT_e),t(t__IDNT_e); + if (!contains(eq,x)) + ck_parameter_x(contextptr); + if (!contains(eq,y)) + ck_parameter_y(contextptr); + ck_parameter_t(contextptr); + reim(M,Mx,My,contextptr); + gen eqM=_quo(makesequence(subst(eq,makevecteur(x,y),makevecteur(Mx+x,My+t*x),false,contextptr),x),contextptr); + gen a,b; + if (!is_linear_wrt(eqM,x,a,b,contextptr)) + return undef; + return M+(-b/a)*(1+cst_i*t); + vecteur res=solve(eqM,x,0,contextptr); // x in terms of t + if (res.size()!=1) + return undef; + return M+res[0]*(1+cst_i*t); + } + + // return M,a,b,c,d,e such that the parametric equation of the conic + // is M+(1+i*t)*(d*t+e)/(a*t^2+b*t+c) + vecteur conique_ratparams(const gen & eq,const gen & M,GIAC_CONTEXT){ + if (is_undef(M)) + return vecteur(1,undef); + gen Mx,My,x(x__IDNT_e),y(y__IDNT_e),t(t__IDNT_e); + if (!contains(eq,x)) + ck_parameter_x(contextptr); + if (!contains(eq,y)) + ck_parameter_y(contextptr); + ck_parameter_t(contextptr); + reim(M,Mx,My,contextptr); + gen eqM=_quo(makesequence(subst(eq,makevecteur(x,y),makevecteur(Mx+x,My+t*x),false,contextptr),x),contextptr); + gen num,deno,a,b,c,d,e; + if (!is_linear_wrt(eqM,x,deno,num,contextptr) || !is_linear_wrt(num,t,d,e,contextptr) || !is_quadratic_wrt(deno,t,a,b,c,contextptr)) + return vecteur(1,undef); + return makevecteur(at_ellipse,M,a,b,c,-d,-e); + } + + int conique_reduite(const gen & equation_conique,const gen & pointsurconique,const vecteur & nom_des_variables,gen & x0, gen & y0, vecteur & V0, vecteur &V1, gen & propre,gen & equation_reduite, vecteur & param_curves,gen & ratparam,bool numeric,GIAC_CONTEXT,gen *aptr,gen * bptr){ + ratparam=conique_ratparam(equation_conique,pointsurconique,contextptr); + gen q(remove_equal(equation_conique)); + vecteur x(nom_des_variables); + if (x.size()!=2) + return 0; // setsizeerr(contextptr); + identificateur iT(" T"); + x.push_back(iT); + //n est le nombre de variables en geo. projective + int n=3; + //nom des nouvelles variables + vecteur A; + gen qp; + qp=q; + for (int i=0;i X=-coeffy2/coeffx*Y^2 + // X+i*Y=-coeffy2/coeffx*Y^2+i*Y + gen coeff=-coeffy2/coeffx; + if (aptr) *aptr=coeffx; + if (bptr) *bptr=coeffy2; +#ifdef GIAC_HAS_STO_38 + gen t(vx_var); +#else + gen t(t__IDNT_e); +#endif + ck_parameter_t(contextptr); + gen Z=coeff*t*t+cst_i*t; + Z=z0+zV0*Z; + if (is_undef(ratparam)) + ratparam=Z; +#if defined POCKETCAS + param_curves.push_back(makevecteur(Z,t,-10,10,0.1,q,ratparam)); +#else + param_curves.push_back(makevecteur(Z,t,-4,4,0.1,q,ratparam)); +#endif + } + } + else { + // a*c-b*b!=0 => on a une conique a centre ou 2 dr concourantes + // ellipse/hyperbole + if (b==0){ + vp0=a; + vp1=c; + V0[0]=1; V0[1]=0; + V1[0]=0; V1[1]=1; + } else { + //si b!=0 + gen delta; + delta=(a-c)*(a-c)+4*b*b; + delta=normalize_sqrt(sqrt(delta,contextptr),contextptr); + vp0=ratnormal((a+c+delta)/2,contextptr); + vp1=ratnormal((a+c-delta)/2,contextptr); + gen normv1(normalize_sqrt(sqrt(b*b+(vp0-a)*(vp0-a),contextptr),contextptr)); + V0[0]=normal(b/normv1,contextptr); + V0[1]=normal((vp0-a)/normv1,contextptr); + V1[0]=-V0[1]; V1[1]=V0[0]; + } + if (is_greater(vp0,vp1,contextptr)){ + swapgen(vp0,vp1); + std::swap(V0,V1); + } + if (aptr) *aptr=-vp0/f; + if (bptr) *bptr=-vp1/f; + //coord du centre + x0=(-d*c+b*e)/(a*c-b*b); + y0=(-a*e+d*b)/(a*c-b*b); + gen z0=x0+cst_i*y0; + gen zV0=V0[0]+cst_i*V0[1]; + gen coeffcst=normal(d*x0+e*y0+f,contextptr); + equation_reduite=vp0*pow(x[0],2)+vp1*pow(x[1],2)+ coeffcst; + // parametric equations + gen svp0(exact(sign(vp0,contextptr),contextptr)), + svp1(exact(sign(vp1,contextptr),contextptr)), + scoeffcst(exact(sign(coeffcst,contextptr),contextptr)); + if (svp0.type==_INT_ && svp1.type==_INT_ && scoeffcst.type==_INT_){ +#ifdef GIAC_HAS_STO_38 + gen t(vx_var); +#else + gen t(t__IDNT_e); +#endif + ck_parameter_t(contextptr); + int sprodvp = svp0.val * svp1.val; + int sprodcoeff = svp0.val*scoeffcst.val; + if (sprodvp>0){ + restype=3; // ellipse + if (is_zero(coeffcst)){ +#ifndef GIAC_HAS_STO_38 + *logptr(contextptr) << gettext("Ellipsis reduced to (") << x0 << "," << y0 << ")" << '\n'; +#endif + param_curves.push_back(z0); + return -2; + } + if (sprodcoeff>0){ +#ifndef GIAC_HAS_STO_38 + *logptr(contextptr) << gettext("Empty ellipsis") << '\n'; +#endif + return -3; + } +#ifndef GIAC_HAS_STO_38 + *logptr(contextptr) << gettext("Ellipsis of center (") << x0 << "," << y0 << ")" << '\n'; +#endif + vp0=normalize_sqrt(sqrt(-coeffcst/vp0,contextptr),contextptr); + vp1=normalize_sqrt(sqrt(-coeffcst/vp1,contextptr),contextptr); + // (x[0]/vp0)^2 + (x[1]/vp1)^2 = 1 + // => x[0]+i*x[1]=vp0*cos(t)+i*vp1*sin(t) + // => x+i*y = x0+i*y0 + V0*(x[0]+i*y[0]) + gen tmp; + if (numeric){ + if (!is_undef(ratparam)) + tmp=subst(evalf(ratparam,1,contextptr),t,symbolic(at_tan,t/2),false,contextptr); + else { + tmp=evalf(vp0,1,contextptr)*symb_cos(t)+cst_i*evalf(vp1,1,contextptr)*symb_sin(t); + tmp=evalf(z0,1,contextptr)+evalf(zV0,1,contextptr)*tmp; + } + } + else { + tmp=vp0*symb_cos(t)+cst_i*vp1*symb_sin(t); + tmp=z0+zV0*tmp; + } + if (is_undef(ratparam)) + ratparam=z0+zV0*(vp0*(1-pow(t,2))+cst_i*vp1*plus_two*t)/(1+pow(t,2)); + + bool rad = angle_radian(contextptr), deg = angle_degree(contextptr); + param_curves.push_back(makevecteur(tmp,t,0, rad?cst_two_pi:(deg ? 360 : 400), rad?cst_two_pi/60:(deg?6:rdiv(20,3)),q,ratparam)); //grad + + } else { + if (is_zero(coeffcst)){ + // 2 secant lines at (x0,y0) +#ifndef GIAC_HAS_STO_38 + *logptr(contextptr) << gettext("2 secant lines at (") << x0 << "," << y0 << ")" << '\n'; +#endif + // vp0*X^2+vp1*Y^2=0 => Y=+/-sqrt(-vp0/vp1)*X + gen directeur=normalize_sqrt(sqrt(-vp0/vp1,contextptr),contextptr); + if (is_undef(ratparam)) + ratparam=makevecteur(z0+zV0*(1+cst_i*directeur)*t,z0+zV0*(1-cst_i*directeur)*t); + param_curves.push_back(gen(makevecteur(z0,z0+zV0*(1+cst_i*directeur)),_LINE__VECT)); + param_curves.push_back(gen(makevecteur(z0,z0+zV0*(1-cst_i*directeur)),_LINE__VECT)); + return -4; + } + restype=4; // hyperbola +#ifndef GIAC_HAS_STO_38 + *logptr(contextptr) << gettext("Hyperbola of center (") << x0 << "," << y0 << ")" << '\n'; +#endif + if (sprodcoeff<0) + vp0=-vp0; + else + vp1=-vp1; + vp0=normalize_sqrt(sqrt(coeffcst/vp0,contextptr),contextptr); + vp1=normalize_sqrt(sqrt(coeffcst/vp1,contextptr),contextptr); + gen tmp; + if (numeric){ + if (!is_undef(ratparam)) + tmp=subst(evalf(ratparam,1,contextptr),t,symbolic(at_tan,t/2),false,contextptr); + else { + tmp=evalf(vp0,1,contextptr)*symbolic(sprodcoeff<0?at_cosh:at_sinh,t)+cst_i*evalf(vp1,1,contextptr)*symbolic(sprodcoeff<0?at_sinh:at_cosh,t); + tmp=evalf(z0,1,contextptr)+evalf(zV0,1,contextptr)*tmp; + } + } + else { + tmp=vp0*symbolic(sprodcoeff<0?at_cosh:at_sinh,t)+cst_i*vp1*symbolic(sprodcoeff<0?at_sinh:at_cosh,t); + tmp=z0+zV0*tmp; + } + bool noratparam=is_undef(ratparam); + if (noratparam){ + ratparam=vp0*gen((sprodcoeff<0)?(t+plus_one/t)/2:(t-plus_one/t)/2)+cst_i*vp1*((sprodcoeff<0)?(t-plus_one/t)/2:(t+plus_one/t)/2); + ratparam=z0+zV0*ratparam; + } +#if defined POCKETCAS + param_curves.push_back(makevecteur(tmp,t,-10,10,0.1,q,ratparam)); +#else + double tt=lop(tmp,at_cosh).empty()?3.14:2.8; + param_curves.push_back(makevecteur(tmp,t,-tt,tt,tt/100,q,ratparam)); +#endif + if (noratparam){ + if (numeric){ + tmp=(sprodcoeff<0?-1:1)*evalf(vp0,1,contextptr)*symbolic(sprodcoeff<0?at_cosh:at_sinh,t)+(sprodcoeff<0?1:-1)*cst_i*evalf(vp1,1,contextptr)*symbolic(sprodcoeff<0?at_sinh:at_cosh,t); + tmp=evalf(z0,1,contextptr)+evalf(zV0,1,contextptr)*tmp; + } + else { + tmp=(sprodcoeff<0?-1:1)*vp0*symbolic(sprodcoeff<0?at_cosh:at_sinh,t)+(sprodcoeff<0?1:-1)*cst_i*vp1*symbolic(sprodcoeff<0?at_sinh:at_cosh,t); + tmp=z0+zV0*tmp; + } +#if defined POCKETCAS + param_curves.push_back(makevecteur(tmp,t,-10,10,0.1,q,ratparam)); +#else + param_curves.push_back(makevecteur(tmp,t,-tt,tt,tt/100,q,ratparam)); +#endif + } + } + } + } + return restype; + } + +#ifdef RTOS_THREADX + bool quadrique_reduite(const gen & q,const gen & M,const vecteur & vxyz,gen & x,gen & y,gen & z,vecteur & u,vecteur & v,vecteur & w,vecteur & propre,gen & equation_reduite,vecteur & param_surface,vecteur & centre,bool numeric,GIAC_CONTEXT){ + return false; + } +#else + bool quadrique_reduite(const gen & q,const gen & M,const vecteur & vxyz,gen & x,gen & y,gen & z,vecteur & u,vecteur & v,vecteur & w,vecteur & propre,gen & equation_reduite,vecteur & param_surface,vecteur & centre,bool numeric,GIAC_CONTEXT){ + if (vxyz.size()!=3) + return false; // setdimerr(contextptr); + x=vxyz[0]; y=vxyz[1]; z=vxyz[2]; + identificateur idt("t"); + gen t(idt),upar("u",contextptr),vpar("v",contextptr); + ck_parameter_u(contextptr); + ck_parameter_v(contextptr); + gen Q=normal(t*t*(subst(q,vxyz,makevecteur(x/t,y/t,z/t),false,contextptr)),contextptr); // homogeneize + matrice A=qxa(Q,makevecteur(x,y,z,t),contextptr); + if (is_undef(A)) + return false; + if (numeric) + A=*evalf_double(A,1,contextptr)._VECTptr; + // unsigned r=_rank(A).val; + matrice B=matrice_extract(A,0,0,3,3); + if (is_undef(B)) return false; + matrice C=makevecteur(A[0][3],A[1][3],A[2][3]); + matrice P; + egv(B,P,propre,contextptr,false,false,false); + gen s1,s2,s3; + if (ckmatrix(propre)){ + s1=propre[0][0];s2=propre[1][1];s3=propre[2][2]; + } + else { + s1=propre[0];s2=propre[1];s3=propre[2]; + } + if (is_zero(s1)) s1=0; + if (is_zero(s2)) s2=0; + if (is_zero(s3)) s3=0; + P=mtran(P); + P[0]=normal(_normalize(P[0],contextptr),contextptr); + P[1]=normal(_normalize(P[1],contextptr),contextptr); + P[2]=normal(_normalize(P[2],contextptr),contextptr); + u=*P[0]._VECTptr; + v=*P[1]._VECTptr; + w=*P[2]._VECTptr; + if ( s1==0 && s2!=0 ){ + vecteur b(u); + u=v; v=w; w=b; + gen a(s1); + s1=s2; s2=s3; s3=a; + } + if ( s2==0 && s3!=0 ){ + vecteur b=w; + w=v; v=u; u=b; + gen a=s3; + s3=s2; s2=s1; s1=a; + } + gen s1g=evalf_double(sign(s1,contextptr),1,contextptr); + gen s2g=evalf_double(sign(s2,contextptr),1,contextptr); + gen s3g=evalf_double(sign(s3,contextptr),1,contextptr); + if (s1g.type!=_DOUBLE_ || s2g.type!=_DOUBLE_ || s3g.type!=_DOUBLE_){ + *logptr(contextptr) << (gettext("Can't check sign ")+s1g.print(contextptr)+gettext(" or ")+s2g.print(contextptr)+gettext(" or ")+s3g.print(contextptr)) << '\n'; + return false; + } + int s1s=int(s1g._DOUBLE_val), s2s=int(s2g._DOUBLE_val), s3s=int(s3g._DOUBLE_val); + if (s3!=0){ // hence s1!=0 && s2!=0 + if (s1s*s2s<0){ + if (s1s*s3s>0){ // exchange s2 and s3 + swap(v,w); + swap(s2,s3); + swap(s2s,s3s); + } + else { // s1s and s2s not same sign, s1s and s3s not same sign + // therefore s2s and s3s have the same sign + vecteur b(u); + u=v; v=w; w=b; + gen a(s1); + s1=s2; s2=s3; s3=a; + int as(s1s); + s1s=s2s; s2s=s3s; s3s=as; + } + } + // now s1 and s2 have the same sign + } + P=mtran(makevecteur(u,v,w)); + vecteur CP=multvecteurmat(C,P); + /* gen CPxyz=dotvecteur(CP,vxyz); + gen c=normal(derive(CPxyz,vxyz),contextptr); + if (c.type!=_VECT || c._VECTptr->size()!=3) + return false; + */ + gen c=normal(CP,contextptr),d; + gen c1(c._VECTptr->front()),c2((*c._VECTptr)[1]),c3(c._VECTptr->back()); + gen ustep=_USTEP; + ustep.subtype=_INT_PLOT; + gen vstep=_VSTEP; + vstep.subtype=_INT_PLOT; + if (!is_zero(s1)){ + if (!is_zero(s2)){ + if (!is_zero(s3)){ + gen tmp=normal(-c1/s1*u-c2/s2*v-c3/s3*w,contextptr); + if (tmp.type!=_VECT) + return false; + while (tmp._VECTptr->size()<3) + tmp._VECTptr->insert(tmp._VECTptr->begin(),0); + centre=*tmp._VECTptr; + d=normal(subst(q,vxyz,centre,false,contextptr),contextptr); + equation_reduite=s1*pow(x,2)+s2*pow(y,2)+s3*pow(z,2)+d; + gen dg=evalf_double(sign(d,contextptr),1,contextptr); + if (dg.type!=_DOUBLE_) + return false; // cksignerr(d); + int ds=int(dg._DOUBLE_val); + if (ds==0){ + // if s3s*s1s>0 solution=1 point, else cone + if (s3s*s1s>0) + param_surface.push_back(centre); + else { // s1*x^2+s2*y^2=-s3*z^2 -> x^2/a^2+y^2/b^2=z^2 + gen a(sqrt(-s3/s1,contextptr)),b(sqrt(-s3/s2,contextptr)); + gen eq=makevecteur(a*upar*symb_cos(vpar),b*upar*symb_sin(vpar),upar); + *logptr(contextptr) << gettext("Cone of center ") << centre << '\n'; + eq=centre+multmatvecteur(P,*eq._VECTptr); + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(-5,5))); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(0,cst_two_pi))); + ustep=symb_equal(ustep,1./2); + vstep=symb_equal(vstep,cst_two_pi/20); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + } + } // end if ds==0 + else { + if (s1s*s3s>0){ + if (s1s*ds>0) + *logptr(contextptr) << gettext("Empty ellipsoid") << '\n'; + else { + gen a=sqrt(-d/s1,contextptr),b=sqrt(-d/s2,contextptr),c=sqrt(-d/s3,contextptr); + // x^2/a^2+y^2/b^2+z^2/c^2=1 + gen eq=makevecteur(a*symb_sin(upar)*symb_cos(vpar),b*symb_sin(upar)*symb_sin(vpar),c*symb_cos(upar)); + *logptr(contextptr) << gettext("Ellipsoid of center ") << centre << '\n'; + eq=centre+multmatvecteur(P,*eq._VECTptr); + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(0,cst_pi))); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(0,cst_two_pi))); + ustep=symb_equal(ustep,cst_pi/20); + vstep=symb_equal(vstep,cst_two_pi/20); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + } + } // end s1 and s3 of same sign + else { // s1 and s2 have same sign, opposite to s3 + if (s1s*ds>0){ + gen a=sqrt(d/s1,contextptr),b=sqrt(d/s2,contextptr),c=sqrt(-d/s3,contextptr); + // x^2/a^2+y^2/b^2+1=z^2/c^2, hyperboloide, 2 nappes + gen eq=makevecteur(a*symb_sinh(upar)*symb_cos(vpar),b*symb_sinh(upar)*symb_sin(vpar),c*symb_cosh(upar)); + eq=centre+multmatvecteur(P,*eq._VECTptr); + *logptr(contextptr) << gettext("2-fold hyperboloid of center ") << centre << '\n'; + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(0,3))); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(0,cst_two_pi))); + ustep=symb_equal(ustep,3./20); + vstep=symb_equal(vstep,cst_two_pi/20); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + eq=makevecteur(a*symb_sinh(upar)*symb_cos(vpar),b*symb_sinh(upar)*symb_sin(vpar),-c*symb_cosh(upar)); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + } + else { // s1, s2 opposite sign to s3,d + gen a=sqrt(-d/s1,contextptr),b=sqrt(-d/s2,contextptr),c=sqrt(d/s3,contextptr); + // x^2/a^2+y^2/b^2=z^2/c^2+1, hyperboloide, 2 nappes + gen eq=makevecteur(a*symb_cosh(upar)*symb_cos(vpar),b*symb_cosh(upar)*symb_sin(vpar),c*symb_sinh(upar)); + *logptr(contextptr) << gettext("2-fold hyperboloid of center ") << centre << '\n'; + eq=centre+multmatvecteur(P,*eq._VECTptr); + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(-3,3))); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(0,cst_two_pi))); + ustep=symb_equal(ustep,3./20); + vstep=symb_equal(vstep,cst_two_pi/20); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + } + } + } + return true; + } // end if (s3!=0) + // s3==0, s1!=0, s2!=0 + if (is_zero(c3)){ + gen tmp=normal(multmatvecteur(P,makevecteur(-c1/s1,-c2/s2,0)),contextptr); + if (tmp.type!=_VECT || tmp._VECTptr->size()!=3) return false; + centre=*tmp._VECTptr; + gen d(normal(subst(q,vxyz,centre,false,contextptr),contextptr)); + gen dg=evalf_double(sign(d,contextptr),1,contextptr); + if (dg.type!=_DOUBLE_) + return false; // cksignerr(d); + int ds=int(dg._DOUBLE_val); + equation_reduite=s1*pow(x,2)+s2*pow(y,2)+d; + if (s1s*s2s>0){ + *logptr(contextptr) << gettext("Elliptic cylinder around ") << centre << '\n'; + + if (is_zero(d)) // line (cylinder of radius 0) + param_surface.push_back(makevecteur(centre,centre+w)); + else { + // elliptic cylinder (maybe empty) + if (s1s*ds<0){ // s1*x^2+s2*y^2=-d + gen a(sqrt(-d/s1,contextptr)),b(sqrt(-d/s2,contextptr)); + gen eq=makevecteur(a*symb_cos(vpar),b*symb_sin(vpar),upar); + eq=centre+multmatvecteur(P,*eq._VECTptr); + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(-5,5))); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(0,cst_two_pi))); + ustep=symb_equal(ustep,1./2); + vstep=symb_equal(vstep,cst_two_pi/20); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + } + } + return true; + } // end s1 and s2 of same sign + else { // s1 and s2 have opposite signs, s1*x^2+s2*y^2+d=0 + if (is_zero(d)){ // 2 plans + *logptr(contextptr) << gettext("2 plans intersecting at ") << centre << '\n'; + gen n=u+sqrt(-s2/s1,contextptr)*v; + param_surface.push_back(symbolic(at_hyperplan,gen(makevecteur(n,centre),_SEQ__VECT))); + n=u-sqrt(-s2/s1,contextptr)*v; + param_surface.push_back(symbolic(at_hyperplan,gen(makevecteur(n,centre),_SEQ__VECT))); + return true; + } + else { // hyperbolic cylinder + *logptr(contextptr) << gettext("Hyperbolic cylinder around ") << centre << '\n'; + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(-5,5))); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(-3,3))); + ustep=symb_equal(ustep,1./2); + vstep=symb_equal(vstep,0.3); + if (s1s*ds<0){ // x^2/(-d/s1) - y^2/(d/s2)=1 + gen a(sqrt(-d/s1,contextptr)),b(sqrt(d/s2,contextptr)); + gen eq=makevecteur(a*symb_cosh(vpar),b*symb_sinh(vpar),upar); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + eq=makevecteur(-a*symb_cosh(vpar),b*symb_sinh(vpar),upar); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + return true; + } + else { // x^2/(d/s1) - y^2/(-d/s2)=-1 + gen a(sqrt(d/s1,contextptr)),b(sqrt(-d/s2,contextptr)); + gen eq=makevecteur(a*symb_sinh(vpar),b*symb_cosh(vpar),upar); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + eq=makevecteur(a*symb_sinh(vpar),-b*symb_cosh(vpar),upar); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + return true; + } + } + } + } // end c3==0 + else { + // s3==0, s1!=0, s2!=0, c3!=0 + gen tmp=normal(subvecteur(multvecteur(-c1/s1,u),multvecteur(c2/s2,v)),contextptr); + if (tmp.type!=_VECT) return false; + gen dred=subst(q,vxyz,*tmp._VECTptr,false,contextptr); + tmp=normal(tmp-dred/(2*c3)*w,contextptr); + if (tmp.type!=_VECT || tmp._VECTptr->size()!=3) return false; + centre=*tmp._VECTptr; + equation_reduite=s1*pow(x,2)+s2*pow(y,2)+2*c3*z; + // parametrization of s1*x^2+s2*y^2+2*c3*z=0 + if (s1s*s2s>0){ + *logptr(contextptr) << gettext("Elliptic paraboloid of center ") << centre << '\n'; + // if (s1s*s2s>0) x^2+y^2/(s1/s2)=-2*c3*z/s1 + // x=u*cos(t), y=u*sqrt(s1/s2)*sin(t), z=-u^2*s1/2/c3 + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(0,5))); + ustep=symb_equal(ustep,1./2); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(0,cst_two_pi))); + vstep=symb_equal(vstep,cst_two_pi/20); + gen a(sqrt(s1/s2,contextptr)),b(-s1/2/c3); + gen eq=makevecteur(upar*symb_cos(vpar),a*upar*symb_sin(vpar),b*pow(upar,2)); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + return true; + } + else { + // if (s1s*s2s<0) x^2-y^2/(-s1/s2)=-2*c3*z/s1 + *logptr(contextptr) << gettext("Hyperbolic paraboloid of center ") << centre << '\n'; + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(-3,3))); + ustep=symb_equal(ustep,0.3); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(-3,3))); + vstep=symb_equal(vstep,0.3); + gen a(-s1/s2),b(s1/2/c3); + gen eq=makevecteur(upar,sqrt(a,contextptr)*vpar,b*(pow(vpar,2)-pow(upar,2))); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + return true; + } + } + } // end if (!is_zero(s2)) + // here s3==0, s2==0, s1!=0 + gen tmp=normal(-c1/s1*u,contextptr); + // gen tmp=normal(multmatvecteur(P,makevecteur(-c1/s1,0,0)),contextptr); + if (tmp.type!=_VECT || tmp._VECTptr->size()!=3) return false; + // gen tmp=normal(multmatvecteur(P,makevecteur(-c1/s1,0,0)),contextptr); + if (!is_zero(c2) || !is_zero(c3)){ + gen c4=normalize_sqrt(sqrt(c2*c2+c3*c3,contextptr),contextptr); + gen v1=normal(multmatvecteur(P,makevecteur(0,c3/c4,-c2/c4)),contextptr); + gen w1=normal(multmatvecteur(P,makevecteur(0,c2/c4,c3/c4)),contextptr); + gen dred=subst(q,vxyz,*tmp._VECTptr,false,contextptr); + P=mtran(makevecteur(u,v1,w1)); + v=*v1._VECTptr; w=*w1._VECTptr; + tmp=tmp+normal(-dred/(2*c4)*w1,contextptr); + // tmp=tmp+normal(multmatvecteur(P,makevecteur(0,0,-d/(2*c4))),contextptr); + if (tmp.type!=_VECT || tmp._VECTptr->size()!=3) return false; + centre=*tmp._VECTptr; + // ??? dred=normal(subst(q,vxyz,centre),contextptr); + equation_reduite=s1*pow(x,2)+2*c4*z; // ???+dred; + gen ueq=symbolic(at_equal,makesequence(upar,symb_interval(-5,5))); + gen veq=symbolic(at_equal,makesequence(vpar,symb_interval(-5,5))); + ustep=symb_equal(ustep,1./2); + vstep=symb_equal(vstep,1./2); + *logptr(contextptr) << gettext("Paraboloid cylinder") << '\n'; + gen eq=makevecteur(upar,vpar,-s1*pow(upar,2)/2/c4); + eq=centre+multmatvecteur(P,*eq._VECTptr); + param_surface.push_back(makevecteur(eq,ueq,veq,ustep,vstep)); + return true; + } + else { // c2==0 and c3==0 + *logptr(contextptr) << gettext("2 parallel plans") << '\n'; + centre=*tmp._VECTptr; + gen dred=normal(subst(q,vxyz,centre,false,contextptr),contextptr); + equation_reduite=s1*pow(x,2)+dred; + if (is_zero(dred)){ // a single plan multiplicity 2 + param_surface.push_back(symbolic(at_hyperplan,gen(makevecteur(u,centre),_SEQ__VECT))); + } + gen dg=evalf_double(sign(dred,contextptr),1,contextptr); + if (dg.type!=_DOUBLE_) + return false; // cksignerr(d); + int ds=int(dg._DOUBLE_val); + if (s1s*ds<0){ // 2 plans x = +/- sqrt(-dred/s1) + gen a(sqrt(-dred/s1,contextptr)); + param_surface.push_back(symbolic(at_hyperplan,gen(makevecteur(u,centre+a*u),_SEQ__VECT))); + param_surface.push_back(symbolic(at_hyperplan,gen(makevecteur(u,centre-a*u),_SEQ__VECT))); + } + return true; + } + } // end if !is_zero(s1) + return false; + } +#endif // RTOS_THREADX + + gen conique_quadrique_reduite(const gen & args,GIAC_CONTEXT,bool conique){ + vecteur v(gen2vecteur(args)); + int s=int(v.size()); + if (!s || s>4) + return gendimerr(contextptr); + if (s==4) + v=makevecteur(v[0],makevecteur(v[1],v[2],v[3])); + if (s==3) + v=makevecteur(v[0],makevecteur(v[1],v[2])); + if (s==1){ + v.push_back(conique?makevecteur(x__IDNT_e,y__IDNT_e):makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e)); + } + if (v[0].type==_SYMB && v[1].type==_VECT){ + gen x0,y0,z0,eq_reduite,propre,ratparam; + vecteur V0,V1,V2,param_curves,centre,proprev; + if (v[1]._VECTptr->size()==3){ + quadrique_reduite(v[0],undef,*v[1]._VECTptr,x0,y0,z0,V0,V1,V2,proprev,eq_reduite,param_curves,centre,false,contextptr); + return makevecteur(centre,mtran(makevecteur(V0,V1,V2)),proprev,eq_reduite,param_curves); + } + else { + if (!conique_reduite(v[0],undef,*v[1]._VECTptr,x0,y0,V0,V1,propre,eq_reduite,param_curves,ratparam,false,contextptr)) + return gensizeerr(contextptr); + return makevecteur(makevecteur(x0,y0),mtran(makevecteur(V0,V1)),propre,eq_reduite,param_curves); + } + } + return gentypeerr(contextptr); + } + gen _conique_reduite(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + return conique_quadrique_reduite(args,contextptr,true); + } + static const char _conique_reduite_s []="reduced_conic"; + static define_unary_function_eval (__conique_reduite,&_conique_reduite,_conique_reduite_s); + define_unary_function_ptr5( at_conique_reduite ,alias_at_conique_reduite,&__conique_reduite,0,true); + + gen _quadrique_reduite(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + return conique_quadrique_reduite(args,contextptr,false); + } + static const char _quadrique_reduite_s []="reduced_quadric"; + static define_unary_function_eval (__quadrique_reduite,&_quadrique_reduite,_quadrique_reduite_s); + define_unary_function_ptr5( at_quadrique_reduite ,alias_at_quadrique_reduite,&__quadrique_reduite,0,true); + + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/gausspol.cc b/android/app/src/main/cpp/giac/src/giac/cpp/gausspol.cc new file mode 100644 index 0000000..1a7ac9c --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/gausspol.cc @@ -0,0 +1,8137 @@ +/* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -I../include -g -c gausspol.cc -D_I386_ -DHAVE_CONFIG_H -DIN_GIAC" -*- */ +#include "giacPCH.h" +/* + * This file implements several functions that work on univariate and + * multivariate polynomials and rational functions. + * These functions include polynomial quotient and remainder, GCD and LCM + * computation, factorization and rational function normalization. */ + +/* + * Copyright (C) 2000,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using namespace std; +#include "gausspol.h" +#include "modpoly.h" +#include "modfactor.h" +#include "solve.h" // for has_num_coeff +#include "alg_ext.h" +#include "sym2poly.h" +#include "prog.h" +#include "plot.h" +#include "modpoly.h" +#include "threaded.h" +#include "usual.h" +#include "ezgcd.h" +#include "giacintl.h" +#include +#include + +#ifdef USE_GMP_REPLACEMENTS +#undef HAVE_GMPXX_H +#undef HAVE_LIBMPFR +#endif + +#ifdef HAVE_GMPXX_H +#define myint mpz_class +#else +#define myint my_mpz +#endif + +// #undef HAVE_LIBNTL + +#ifdef USTL +namespace ustl { + inline bool operator > (const giac::index_t & a,const giac::index_t & b){ + if (a.size()!=b.size()) + return a.size()>b.size(); + return !giac::all_inf_equal(a,b); + } + inline bool operator < (const giac::index_t & a,const giac::index_t & b){ + if (a.size()!=b.size()) + return a.size() trivial_n_factor(gen &n){ + vector v; + if (is_zero(n)) + return v; + for (int i=0;i nv(trivial_n_factor(ntemp)); + int k=nv.size(); + vecteur v; + v.push_back(gen(1)); + for (int j=0;j v(trivial_n_factor(ncopy)); + vecteur res; + res.push_back(1); + res.push_back(-1); // res=x-1 + int pi=1; + vector::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (it->fact.type!=_INT_) + return vecteur(1,gensizeerr(gettext("gausspol.cc/cyclotomic"))); + int p=it->fact.val; + pi *= p; + vecteur res_x_to_xp(x_to_xp(res,p)); + res=res_x_to_xp/res; + } + return x_to_xp(res,n/pi); + } + + //********************************** + // functions relative to polynomials + //********************************** + polynome gen2polynome(const gen & e,int dim){ + if (e.type==_POLY) + return *e._POLYptr; + return polynome(e,dim); + } + + // instantiation of dbgprint for poly + void dbg(const polynome & p){ + p.dbgprint(); + } + + bool is_one(const polynome & p){ + return Tis_one(p); + } + + polynome firstcoeff(const polynome & p){ + return Tfirstcoeff(p); + } + + void Add_gen ( std::vector< monomial >::const_iterator & a, + std::vector< monomial >::const_iterator & a_end, + std::vector< monomial >::const_iterator & b, + std::vector< monomial >::const_iterator & b_end, + std::vector< monomial > & new_coord, + bool (* is_strictly_greater)( const index_m &, const index_m &)) { + if ( (a!=a_end && new_coord.begin()==a) || (b!=b_end && new_coord.begin()==b)){ + std::vector< monomial > tmp; + Add_gen(a,a_end,b,b_end,tmp,is_strictly_greater); + std::swap(new_coord,tmp); + return; + } + new_coord.clear(); + new_coord.reserve( (a_end - a) + (b_end - b)); + gen sum; + for (;;) { + if (a == a_end) { + while (b != b_end) { + new_coord.push_back(*b); + ++b; + } + break; + } + const index_m & pow_a = a->index; + // If b is empty, fill up with elements from a and stop + if (b == b_end) { + while (a != a_end) { + new_coord.push_back(*a); + ++a; + } + break; + } + const index_m & pow_b = b->index; + // a and b are non-empty, compare powers + if (pow_a!=pow_b){ + if (is_strictly_greater(pow_a, pow_b)) { + // a has lesser power, get coefficient from a + new_coord.push_back(*a); + ++a; + } + else { + // b has lesser power, get coefficient from b + new_coord.push_back(*b); + ++b; + } + } + else { + sum = (*a).value + (*b).value; + if (!is_zero(sum)) + new_coord.push_back(monomial(sum,pow_a)); + ++a; + ++b; + } + } + } + + polynome operator + (const polynome & th,const polynome & other) { +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return monomial(gensizeerr(gettext("Stopped by user interruption.")),th.dim); + } + // Tensor addition + vector< monomial >::const_iterator a=th.coord.begin(); + vector< monomial >::const_iterator a_end=th.coord.end(); + if (a == a_end) { + return other; + } + vector< monomial >::const_iterator b=other.coord.begin(); + vector< monomial >::const_iterator b_end=other.coord.end(); + if (b==b_end){ + return th; + } + polynome res(th.dim,th); + Add_gen(a,a_end,b,b_end,res.coord,th.is_strictly_greater); + return res; + } + + void Sub_gen ( std::vector< monomial >::const_iterator & a, + std::vector< monomial >::const_iterator & a_end, + std::vector< monomial >::const_iterator & b, + std::vector< monomial >::const_iterator & b_end, + std::vector< monomial > & new_coord, + bool (* is_strictly_greater)( const index_m &, const index_m &)) { + if ( (a!=a_end && new_coord.begin()==a) || (b!=b_end && new_coord.begin()==b)){ + std::vector< monomial > tmp; + Sub_gen(a,a_end,b,b_end,tmp,is_strictly_greater); + std::swap(new_coord,tmp); + return; + } + new_coord.clear(); + new_coord.reserve( (a_end - a) + (b_end - b)); + gen diff; + for (;;) { + if (a == a_end) { + while (b != b_end) { + new_coord.push_back(-(*b)); + ++b; + } + break; + } + const index_m & pow_a = a->index; + // If b is empty, fill up with elements from a and stop + if (b == b_end) { + while (a != a_end) { + new_coord.push_back(*a); + ++a; + } + break; + } + const index_m & pow_b = b->index; + // a and b are non-empty, compare powers + if (pow_a!=pow_b){ + if (is_strictly_greater(pow_a, pow_b)) { + // a has lesser power, get coefficient from a + new_coord.push_back(*a); + ++a; + } + else { + // b has lesser power, get coefficient from b + new_coord.push_back(-(*b)); + ++b; + } + } + else { + diff = (*a).value - (*b).value; + if (!is_zero(diff)) + new_coord.push_back(monomial(diff,pow_a)); + ++a; + ++b; + } + } + } + + polynome operator - (const polynome & th,const polynome & other) { +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return monomial(gensizeerr(gettext("Stopped by user interruption.")),th.dim); + } + // Tensor addition + vector< monomial >::const_iterator a=th.coord.begin(); + vector< monomial >::const_iterator a_end=th.coord.end(); + vector< monomial >::const_iterator b=other.coord.begin(); + vector< monomial >::const_iterator b_end=other.coord.end(); + if (b == b_end) { + return th; + } + polynome res(th.dim,th); + Sub(a,a_end,b,b_end,res.coord,th.is_strictly_greater); + return res; + } + + void mulpoly(const polynome & th,const gen & fact0,polynome & res){ + if (&th!=&res) + res.coord.clear(); + gen fact=fact0; + if (fact.type!=_MOD && fact.type!=_USER && !th.coord.empty() && th.coord.front().value.type==_MOD){ + fact = makemod(fact,*(th.coord.front().value._MODptr+1)); + } + if (!is_exactly_zero(fact)){ + vector< monomial >::const_iterator a = th.coord.begin(); + vector< monomial >::const_iterator a_end = th.coord.end(); + Mul(a,a_end,fact,res.coord); + } + } + + polynome operator * (const polynome & th, const gen & fact){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return monomial(gensizeerr(gettext("Stopped by user interruption.")),th.dim); + } + // Tensor constant multiplication + if (fact.type!=_MOD && fact==gen(1)) + return th; + polynome res(th.dim,th); + mulpoly(th,fact,res); + return res; + } + +#ifdef NSPIRE + template nio::ios_base & operator << (nio::ios_base & os,const int_unsigned & i){ + return os << i.g << ":" << i.u ; + } +#else + ostream & operator << (ostream & os,const int_unsigned & i){ + return os << i.g << ":" << i.u ; + } +#endif + + inline bool operator < (const int_unsigned & gu1,const int_unsigned & gu2){ + return gu1.u > gu2.u; + } + + template + static bool convert(const polynome & p,const index_t & deg,std::vector< T_unsigned > & v,int reduce){ + std::vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + v.clear(); + v.reserve(itend-it); + T_unsigned gu; + U u; + index_t::const_iterator itit,ditbeg=deg.begin(),ditend=deg.end(),dit; + if (reduce==0){ + for (;it!=itend;++it){ + itit=it->index.begin(); + u=U(*itit); + for (dit=ditbeg+1,++itit;dit!=ditend;++itit,++dit) + u=u*U(*dit)+U(*itit); + gu.u=u; + if (it->value.type!=_INT_) + return false; + gu.g=it->value.val; + v.push_back(gu); + } + return true; + } + for (;it!=itend;++it){ + itit=it->index.begin(); + u=U(*itit); + for (dit=ditbeg+1,++itit;dit!=ditend;++itit,++dit) + u=u*U(*dit)+U(*itit); + gu.u=u; + int tmp=it->value.val; + if (it->value.type==_INT_ && 2*tmp<=reduce && -2*tmpvalue,reduce)); + if (tmp.type!=_INT_) + return false; + gu.g=tmp.val; + } + v.push_back(gu); + } + return true; + } + + template + static void convert(const std::vector< T_unsigned > & v,const index_t & deg,polynome & p){ + typename std::vector< T_unsigned >::const_iterator it=v.begin(),itend=v.end(); + index_t::const_reverse_iterator ditbeg=deg.rbegin(),ditend=deg.rend(),dit; + p.dim=ditend-ditbeg; + p.coord.clear(); + p.coord.reserve(itend-it); + U u; + index_t i(p.dim); + int k; + for (;it!=itend;++it){ + u=it->u; + for (k=p.dim-1,dit=ditbeg;dit!=ditend;++dit,--k){ + i[k]=u % unsigned(*dit); + u = u/unsigned(*dit); + } + p.coord.push_back(monomial(it->g,i)); + } + } + + + template + static void convert(const vector< T_unsigned > & source,vector< T_unsigned > & target){ + target.clear(); + typename vector< T_unsigned >::const_iterator it=source.begin(),itend=source.end(); + target.reserve(itend-it); + for (;it!=itend;++it) + target.push_back(T_unsigned(it->g,it->u)); + } + + static gen ichrem_smod(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,const gen & i,const gen & j){ + if (i.type==_ZINT) + mpz_set(*iz,*i._ZINTptr); + else + mpz_set_si(*iz,i.val); + // i-j + if (j.type==_INT_){ + if (j.val>0) + mpz_sub_ui(*tmpz,*iz,j.val); + else + mpz_add_ui(*tmpz,*iz,-j.val); + } + else + mpz_sub(*tmpz,*iz,*j._ZINTptr); + // times B +i + mpz_addmul(*iz,*tmpz,*Bz); + // mod A + mpz_mod(*tmpz,*iz,*Az); + // compare with *tmpz-Az + mpz_sub(*iz,*tmpz,*Az); + mpz_neg(*iz,*iz); + ref_mpz_t *res = new ref_mpz_t(GIAC_MPZ_INIT_SIZE); + if (mpz_cmp(*iz,*tmpz)>=0) // use *tmpz + mpz_set(res->z,*tmpz); + else { + mpz_set(res->z,*iz); + mpz_neg(res->z,res->z); + } + return res; + } + + static gen ichrem_smod(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,longlong i,longlong j){ + if (i==j) + return i; + longlong2mpz(i,iz); + // longlong2mpz(i-j,tmpz); does not work since i-j might overflow + longlong2mpz(j,tmpz); + mpz_sub(*tmpz,*iz,*tmpz); + // i+=B*(i-j) + mpz_addmul(*iz,*tmpz,*Bz); + // mod A + mpz_mod(*tmpz,*iz,*Az); + // compare with *tmpz-Az + mpz_sub(*iz,*tmpz,*Az); + mpz_neg(*iz,*iz); + ref_mpz_t *res = new ref_mpz_t(GIAC_MPZ_INIT_SIZE); + int test=mpz_cmp(*iz,*tmpz); + if (test>=0) // use *tmpz + mpz_set(res->z,*tmpz); + else { + mpz_set(res->z,*iz); + mpz_neg(res->z,res->z); + } + return res; + } + +#if 0 + // set i to i+((((j-i)* mod addprime)*u) mod addprime)*targetprime, inplace operation + // (where u*targetprime+unknow_integer*addprime=1) + static void ichrem_smod_inplace(int addprime,int u,const gen &targetprime,gen & i,const gen & j){ + longlong tmp=longlong(j.val)-((i.type==_ZINT)?modulo(*i._ZINTptr,addprime):i.val); + tmp=(tmp*u)%addprime; + if (targetprime.type==_ZINT && i.type==_ZINT){ + if (tmp>0) + mpz_addmul_ui(*i._ZINTptr,*targetprime._ZINTptr,int(tmp)); + else + mpz_submul_ui(*i._ZINTptr,*targetprime._ZINTptr,-int(tmp)); + } + else + i += int(tmp)*targetprime; + } + + static gen ichrem_smod(int addprime,int u,const gen &targetprime,longlong i,int j,mpz_t * tmpz){ + longlong tmp=longlong(j)-i%addprime; + tmp=(tmp*u)%addprime; + gen I(i); + I.uncoerce(); + // now return I+tmp*targetprime + if (targetprime.type==_INT_){ + tmp *= targetprime.val; // no overflow since tmp<2^31 and targetprime.val also + longlong2mpz(tmp,tmpz); + mpz_add(*I._ZINTptr,*I._ZINTptr,*tmpz); + } + else { + if (tmp>=0) + mpz_addmul_ui(*I._ZINTptr,*targetprime._ZINTptr,tmp); + else + mpz_submul_ui(*I._ZINTptr,*targetprime._ZINTptr,-tmp); + } + return I; + } +#endif + + // set i to i+(i-j)*B mod A, inplace operation + void ichrem_smod_inplace(mpz_t * Az,mpz_t * Bz,mpz_t * iz,mpz_t * tmpz,gen & i,const gen & j){ + if (i==j) + return; + if (i.type==_ZINT) + mpz_set(*iz,*i._ZINTptr); + else + mpz_set_si(*iz,i.val); + // i-j + if (j.type==_INT_){ + if (j.val>0) + mpz_sub_ui(*tmpz,*iz,j.val); + else + mpz_add_ui(*tmpz,*iz,-j.val); + } + else + mpz_sub(*tmpz,*iz,*j._ZINTptr); + // times B +i + mpz_addmul(*iz,*tmpz,*Bz); + // mod A + mpz_mod(*tmpz,*iz,*Az); + // compare with *tmpz-Az + mpz_sub(*iz,*tmpz,*Az); + mpz_neg(*iz,*iz); + if (i.type==_ZINT){ + if (mpz_cmp(*iz,*tmpz)>=0) // use *tmpz + mpz_set(*i._ZINTptr,*tmpz); + else { + mpz_set(*i._ZINTptr,*iz); + mpz_neg(*i._ZINTptr,*i._ZINTptr); + } + } + else { + ref_mpz_t *res = new ref_mpz_t(GIAC_MPZ_INIT_SIZE); + if (mpz_cmp(*iz,*tmpz)>=0) // use *tmpz + mpz_set(res->z,*tmpz); + else { + mpz_set(res->z,*iz); + mpz_neg(res->z,res->z); + } + i=res; + } + } + +#if 0 + // smod(B*(i-j)+i,A); + static gen ichrem_smod(const gen & A,const gen & B,const gen & i,const gen & j){ + if (i==j) + return i; + if (A.type!=_ZINT || B.type!=_ZINT) + return smod(B*(i-j)+i,A); + mpz_t * Az=A._ZINTptr,*Bz=B._ZINTptr,iz,tmpz; + ref_mpz_t *res = new ref_mpz_t(GIAC_MPZ_INIT_SIZE); + mpz_init(tmpz); + if (i.type==_ZINT) + mpz_init_set(iz,*i._ZINTptr); + else + mpz_init_set_si(iz,i.val); + // i-j + if (j.type==_INT_){ + if (j.val>0) + mpz_sub_ui(tmpz,iz,j.val); + else + mpz_add_ui(tmpz,iz,-j.val); + } + else + mpz_sub(tmpz,iz,*j._ZINTptr); + // times B +i + mpz_addmul(iz,tmpz,*Bz); + // mod A + mpz_mod(tmpz,iz,*Az); + // compare with tmpz-Az + mpz_sub(iz,tmpz,*Az); + mpz_neg(iz,iz); + if (mpz_cmp(iz,tmpz)>0) // use tmpz + mpz_set(res->z,tmpz); + else { + mpz_set(res->z,iz); + mpz_neg(res->z,res->z); + } + mpz_clear(iz); + mpz_clear(tmpz); + return res; + } + + static gen ichrem_smod(const gen & A,const gen & B,longlong i,longlong j){ + // return smod((i-j)*B+i,A); + if (i==j) + return i; + return ichrem_smod(A,B,gen(i),gen(j)); + } +#endif + + template + static void ichrem(const vector< T_unsigned > & add,int addprime,const vector< T_unsigned > & init,vector< T_unsigned > & target,gen & targetprime){ + gen A,B,d; + egcd(addprime,targetprime,A,B,d); +#ifndef NO_STDEXCEPT + if (!is_one(d)) // should not happen + setsizeerr(); +#endif + // addprime*A+targetprime*B=1 + // find c such that c=it->g mod targetprime and c=jt->g mod addprime + // it->g + v*targetprime = jt->g + u*addprime + // it->g - jt->g = u*addprime - v*targetprime + // v=(jt->g-it->g)*B + // hence c=it->g+(jt->g-it->g)*B*targetprime mod addprime*targetprime + // IMPROVE c=it->g+(((jt->g-it->g) mod addprime)*B mod addprime)*targetprime + // int b=B.type==_ZINT?mpz_get_si(*B._ZINTptr):B.val; + A=addprime*targetprime; + B=-targetprime*B; + mpz_t z1,z2; + mpz_init(z1); + mpz_init(z2); + if (A.type!=_ZINT) + A.uncoerce(); + if (B.type!=_ZINT) + B.uncoerce(); + typename vector< T_unsigned >::const_iterator jt=add.begin(),jtend=add.end(); + typename vector< T_unsigned >::const_iterator kt=init.begin(),ktend=init.end(); + typename vector< T_unsigned >::iterator it=target.begin(),itend=target.end(); + if (it==itend){ + target.reserve(ktend-kt); + for (;kt!=ktend && jt!=jtend;){ + if (kt->u==jt->u){ + // it->g=smod(B*(it->g-jt->g)+it->g,A); + // target.push_back(T_unsigned(ichrem_smod(addprime,b,targetprime,kt->g,jt->g,&z1),jt->u)); + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,kt->g,jt->g),jt->u)); + ++kt; ++jt; + } + else { + if (kt->u>jt->u){ + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,kt->g,0),kt->u)); + ++kt; + } + else { + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u)); + ++jt; + } + } + } + for (;jt!=jtend;++jt) + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u)); + for (;kt!=ktend;++jt) + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,kt->g,0),kt->u)); + } + else { + for (;it!=itend && jt!=jtend;){ + if (it->u==jt->u){ + // it->g=smod(B*(it->g-jt->g)+it->g,A); + ichrem_smod_inplace(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,jt->g); + // ichrem_smod_inplace(addprime,b,targetprime,it->g,jt->g); + // it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,jt->g); + ++it; ++jt; + } + else { + if (it->u>jt->u){ + ichrem_smod_inplace(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0); + // ichrem_smod_inplace(addprime,b,targetprime,it->g,0); + // it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0); + ++it; + } + else { + vector< T_unsigned > copie(it,itend); + target.erase(it,itend); + it=copie.begin(); itend=copie.end(); + for (;it!=itend;){ + if (jt==jtend || it->u>jt->u){ + it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0); + target.push_back(*it); + ++it; + } + else { + ++jt; + if (it->u==jt->u){ + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,jt->g),it->u)); + ++it; + } + else + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u)); + } + } + break; + } + } + } + for (;jt!=jtend;++jt) + target.push_back(T_unsigned(ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,0,jt->g),jt->u)); + for (;it!=itend;++it){ + // it->g=ichrem_smod(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0); + ichrem_smod_inplace(A._ZINTptr,B._ZINTptr,&z1,&z2,it->g,0); + // ichrem_smod_inplace(addprime,b,targetprime,it->g,0); + } + } // end target empty at beginning + targetprime = addprime*targetprime; + mpz_clear(z1); + mpz_clear(z2); + } + +#ifdef INT128 + template + static void smod(vector< T_unsigned > & target,int prime){ + typename vector< T_unsigned >::iterator it=target.begin(),itend=target.end(); + for (;it!=itend;++it){ + it->g %= prime; + } + } +#endif + + template + static void smod(const vector< T_unsigned > & source,vector< T_unsigned > & target,int prime){ + if (&target==&source){ + typename vector< T_unsigned >::iterator it=target.begin(),itend=target.end(); + for (;it!=itend;++it){ + it->g %= prime; + if (!it->g){ + vector< T_unsigned > copie(target); + +#ifndef BESTA_OS + smod(copie,target,prime); +#else + + // &copie != &target (by definition) so the following is + // substituted from below as the Kiel ARM compiler does + // not support this sort of recursive template expansion. + + copie.clear(); + typename vector< T_unsigned >::const_iterator it=source.begin(),itend=source.end(); + copie.reserve(itend-it); + longlong res; + for (;it!=itend;++it){ + res=it->g % prime; + if (res) + copie.push_back(T_unsigned(res,it->u)); + } + target=copie; +#endif + + break; + } + } + return; + } + target.clear(); + typename vector< T_unsigned >::const_iterator it=source.begin(),itend=source.end(); + target.reserve(itend-it); + longlong res; + for (;it!=itend;++it){ + res=it->g % prime; + if (res) + target.push_back(T_unsigned(res,it->u)); + } + } + +#ifdef INT128 + template + static void convert_int128(const vector< T_unsigned > & p1d,vector< T_unsigned > & p1D){ + typename vector< T_unsigned >::const_iterator it=p1d.begin(),itend=p1d.end(); + p1D.clear(); + p1D.reserve(itend-it); + for (;it!=itend;++it) + p1D.push_back(T_unsigned(it->g,it->u)); + } +#endif + + void addsamepower_gen(std::vector< monomial >::const_iterator & it, + std::vector< monomial >::const_iterator & itend, + std::vector< monomial > & new_coord){ + gen res; + while (it!=itend){ + res=(*it).value; + index_m pow=(*it).index; + ++it; + while ( (it!=itend) && ((*it).index==pow)){ + res=res+(*it).value; + ++it; + } + if (!is_zero(res)) + new_coord.push_back(monomial(res, pow)); + } + } + + void Mul_gen ( std::vector< monomial >::const_iterator & ita, + std::vector< monomial >::const_iterator & ita_end, + std::vector< monomial >::const_iterator & itb, + std::vector< monomial >::const_iterator & itb_end, + std::vector< monomial > & new_coord, + bool (* is_strictly_greater)( const index_m &, const index_m &), +#ifdef CPP11 + const std::function &, const monomial &)> m_is_strictly_greater +#else + const std::pointer_to_binary_function < const monomial &, const monomial &, bool> m_is_strictly_greater +#endif + ) { + if (ita==ita_end || itb==itb_end){ + new_coord.clear(); + return; + } + int asize=int(ita_end-ita),bsize=int(itb_end-itb); + int d=int(ita->index.size()); + std::vector< monomial > multcoord; + multcoord.reserve(asize*bsize); // correct for sparse polynomial + std::vector< monomial >::const_iterator ita_begin = ita,itb_begin=itb ; + index_m old_pow=(*ita).index+(*itb).index; + gen res( 0); + for ( ; ita!=ita_end; ++ita ){ + std::vector< monomial >::const_iterator ita_cur=ita; + std::vector< monomial >::const_iterator itb_cur=itb; + for (;itb_cur!=itb_end;--ita_cur,++itb_cur) { + index_m cur_pow=(*ita_cur).index+(*itb_cur).index; + if (cur_pow!=old_pow){ + if (!is_zero(res)) + multcoord.push_back( monomial(res ,old_pow )); + res=((*ita_cur).value) * ((*itb_cur).value); + old_pow=cur_pow; + } + else + res=res+((*ita_cur).value) * ((*itb_cur).value); + if (ita_cur==ita_begin) + break; + } + } + --ita; + ++itb; + for ( ; itb!=itb_end;++itb){ + std::vector< monomial >::const_iterator ita_cur=ita; + std::vector< monomial >::const_iterator itb_cur=itb; + for (;itb_cur!=itb_end;--ita_cur,++itb_cur) { + index_m cur_pow=(*ita_cur).index+(*itb_cur).index; + if (cur_pow!=old_pow){ + if (!is_zero(res)) + multcoord.push_back( monomial(res ,old_pow )); + res=((*ita_cur).value) * ((*itb_cur).value); + old_pow=cur_pow; + } + else + res=res+((*ita_cur).value) * ((*itb_cur).value); + + if (ita_cur==ita_begin) + break; + } + } + // push last monomial + if (!is_zero(res)) + multcoord.push_back( monomial(res ,old_pow )); + // sort by asc. power +#if 1 // def NSPIRE + sort( multcoord.begin(),multcoord.end(),sort_helper(m_is_strictly_greater)); +#else + sort( multcoord.begin(),multcoord.end(),m_is_strictly_greater); +#endif + std::vector< monomial >::const_iterator it=multcoord.begin(); + std::vector< monomial >::const_iterator itend=multcoord.end(); + // adjust result size + // statistics about polynomial density + // a dense poly of deg. aa and d variables has binomial(aa+d,d) monomials + // we need to reserve at most asize*bsize + // but less for dense polynomials since + //ย binomial(aa+d,d)*binomial(bb+d,d) > binomial(aa+bb+d,d) + int aa=total_degree(ita_begin->index),bb=total_degree(itb_begin->index); + double r; + double factoriald=std::log(evalf_double(factorial(d+1),1,context0)._DOUBLE_val); + // double factorialaa=std::lgamma(aa+1),factorialbb=std::lgamma(bb+1); + // double factorialaad=std::lgamma(aa+d+1),factorialbbd=std::lgamma(bb+d+1); + double factorialaabbd=std::log(evalf_double(factorial(aa+bb+d+1),1,context0)._DOUBLE_val), + factorialaabb=std::log(evalf_double(factorial(aa+bb+1),1,context0)._DOUBLE_val); + r=std::exp(factorialaabbd-(factorialaabb+factoriald)); + if (debug_infolevel>1) + CERR << "// " << CLOCK() << " Mul degree " << aa << "+" << bb << " size " << asize << "*" << bsize << "=" << asize*bsize << " max " << r << '\n'; + new_coord.clear(); + if (my_isinf(r) || my_isnan(r) || r>1e9) + new_coord.reserve(itend-it); + else + new_coord.reserve(giacmin(int(r),int(itend-it))); + // add terms with same power + addsamepower_gen(it,itend,new_coord); + if (debug_infolevel>1) + CERR << "// Actual mul size " << new_coord.size() << '\n'; + } + + bool is_integer_poly(const polynome & p,bool intonly){ + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (it->value.type==_INT_) continue; + if (intonly) return false; + if (it->value.type==_ZINT) continue; + // if (it->type==_CPLX && is_exactly_zero(*(it->_CPLXptr+1))) continue; + return false; + // if (!is_integer(*it)) return false; + } + return true; + } + + bool polynome2poly1(const polynome & p,const index_t & pdeg,const index_t °,vecteur & v){ + v.clear(); + int tot=0; + for (size_t i=0;i >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + int u; + index_t::const_iterator itit,ditbeg=deg.begin(),ditend=deg.end(),dit; + gen tmp; + for (;it!=itend;++it){ + u=0; + itit=it->index.begin(); + for (dit=ditbeg;dit!=ditend;++itit,++dit) + u=u*(*dit)+(*itit); + if (!is_integer(it->value.type)) + return false; + v[u]=it->value; + } + return true; + } + + bool poly12polynome(const vecteur & v,const index_t & deg,polynome & p){ + const_iterateur it=v.begin(),itend=v.end(); + index_t::const_reverse_iterator ditbeg=deg.rbegin(),ditend=deg.rend(),dit; + p.dim=ditend-ditbeg; + p.coord.clear(); + p.coord.reserve(itend-it); + int u,U=int(v.size()); + index_t i(p.dim); + int k; + for (--itend;itend>=it;--itend){ + gen g=*itend; + if (is_zero(g)) + continue; + u=int(itend-it); + for (k=p.dim-1,dit=ditbeg;dit!=ditend;++dit,--k){ + i[k]=u % unsigned(*dit); + u = u/unsigned(*dit); + } + p.coord.push_back(monomial(g,i)); + } + return true; + } + + void int32_modularize(polynome & res,const gen &m){ + vector< monomial >::iterator it=res.coord.begin(),itend=res.coord.end(); + for (;it!=itend;++it){ + if (it->value.type==_INT_){ + int r=it->value.val; + r += (unsigned(r)>>31)*m.val; // make positive + r -= (unsigned((m.val>>1)-r)>>31)*m.val; + it->value=makemodquoted(r,m); + } + } + } + + // Fast multiplication using hash maps, might also use an int for reduction + // but there is no garantee that res is smod-ed modulo reduce + void mulpoly(const polynome & th, const polynome & other,polynome & res,const gen & reduce){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + res=monomial(gensizeerr(gettext("Stopped by user interruption.")),th.dim); + return; + } + /* + if (th.dim==12) + CERR << "* begin " << CLOCK() << " " << th.coord.size() << "*" << other.coord.size() << '\n'; + */ + // Multiplication + vector< monomial >::const_iterator ita = th.coord.begin(); + vector< monomial >::const_iterator ita_end = th.coord.end(); + vector< monomial >::const_iterator itb = other.coord.begin(); + vector< monomial >::const_iterator itb_end = other.coord.end(); + // COUT << coord.size() << " " << (int) ita_end - (int) ita << " " << sizeof(monomial) << '\n' ; + // first some trivial cases + if (ita==ita_end || is_one(other)){ + res=th; + return; + } + if (itb==itb_end || is_one(th)){ + res=other; + return ; + } + index_t d1=th.degree(),d2=other.degree(),d(th.dim); + double d10,d20; + if ( 0 && + th.dim==1 + && (d10=d1[0])>=FFTMUL_SIZE && (d20=d2[0])>=FFTMUL_SIZE && (ita_end-ita)*double(itb_end-itb)>(d10+d20)*std::log(double(d10+d20)) + && is_integer_poly(th,false) && is_integer_poly(other,false) + ){ + modpoly A=polynome2poly1(th,1); + modpoly B=polynome2poly1(other,1); + modpoly C; + mulmodpoly(A,B,0,C); + poly12polynome(C,1,res,1); + return; + } + double lagrtime=1.,sumdeg=0.; + for (int i=0;i=(1<<15)){ + res=monomial(gensizeerr(gettext("Polynomial exponent overflow.")),th.dim); + return; + } + sumdeg += tmp; + lagrtime *= tmp; + } + d10=lagrtime; + lagrtime *= sumdeg; + // Now look if length a=1 or length b=1, happens frequently + // think of x^3*y^2*z translated to internal form + int c1=int(th.coord.size()); + if (c1==1){ + res=other.shift(th.coord.front().index,th.coord.front().value); + return ; + } + int c2=int(other.coord.size()); + if (c2==1){ + res=th.shift(other.coord.front().index,other.coord.front().value); + return; + } + //int t1=th.coord.front().value.type,t2=other.coord.front().value.type; + gen T1=th.coord.front().value,T2=other.coord.front().value; + // gen T1=th.coord[c1/2].value,T2=other.coord[c2/2].value; + int t1=T1.type,t2=T2.type; +#if 1 // does not work if _ext are embedded inside fractions (check done in unext) + if (t1==_EXT || t2==_EXT){ + gen minp; + if (t1==_EXT) + minp=*(T1._EXTptr+1); + else + minp=*(T2._EXTptr+1); + polynome p1m,p2m,pm(th.dim); + if (minp.type==_VECT && unext(th,minp,p1m) && unext(other,minp,p2m)){ + mulpoly(p1m,p2m,pm,0); + ext(pm,minp,res); + //Mul(ita,ita_end,itb,itb_end,pm.coord,th.is_strictly_greater,th.m_is_strictly_greater); + //if (!(pm-res).coord.empty()) + //CERR << "err" << th << '\n' << other << '\n' << pm-res << '\n'; + return; + } + } // end EXT + if (1 && (t1==_MOD || t2==_MOD)){ + gen m=t1==_MOD?*(T1._MODptr+1):*(T2._MODptr+1); + if (m.type==_INT_){ + polynome thm,otherm; + unmodularize(th,thm); + unmodularize(other,otherm); + mulpoly(thm,otherm,res,m); + int32_modularize(res,m); + return; + } + } +#endif +#ifdef NO_TEMPLATE_MULTGCD +#ifdef FXCG + Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater); +#else + Mul(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater); + // Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater); +#endif + return; +#else + if ( + //true || // used for debugging with small poly + c1>50 || c2 >50 || (c1>7 && c2>7) + ){ + // Degree info, try to multiply the polys using integer for the exponents + ulonglong ans=1,pid1=1,pid2=1; + for (int i=0;iRAND_MAX) + break; + } + // ans/d[th.dim-1] == degree 1 with respect to main var and 0 for other + // guess size of result + // compare product of d1[i] with c1 and product of d2[i] with c2 + // for sparness factor + double d1sparness=double(c1)/pid1; + double d2sparness=double(c2)/pid2; + ulonglong c1c2= ulonglong(c1)*c2; + if (ans (1<<24) ) + c1c2 = 1 << 24; + // Possible improvement for modular product mod p in an array + // make one of the argument with negative coeffs, the other with positive + // init array with p^2, then type_operator_plus_times_reduce + // could do += p1[]*p2[] and if result <0 add p^2 + // ?encode reduce as -p^2, and check sign in do_threadmult in threaded.h + // OR use int128 + if (ans<=RAND_MAX) { + if (reduce.type==_INT_){ + if (//reduce.val<46340 && + reduce.val>0 + ){ +#if 1 + longlong maxp1,maxp2; + vector< T_unsigned > p1d,p2d,pd; + if (convert_int(th,d,p1d,maxp1) && convert_int(other,d,p2d,maxp2) ){ + double maxp1p2=double(maxp1)*maxp2; + unsigned minc1c2=giacmin(c1,c2); + double un63=double(ulonglong (1) << 63); + double res_size=double(minc1c2)*maxp1p2; + // Check if mod may be done only at the end + res_size /= un63; + if (res_size<1){ + if (th.dim==1 || !threadmult(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2))) + smallmult(p1d,p2d,pd,0,size_t(c1c2)); + smod(pd,pd,reduce.val); + convert_from(pd,d,res,false); + } + else { +#ifdef INT128 + if (res_size > p1D,p2D,pD; + convert_int128(p1d,p1D); + convert_int128(p2d,p2D); + if (th.dim==1 || !threadmult(p1D,p2D,pD,ans/d[0],0,c1c2)) + smallmult(p1D,p2D,pD,0,c1c2); + smod(pD,reduce.val); + convert_from(pD,d,res,false); + } + else +#endif // INT128 + { + if (th.dim==1 || !threadmult(p1d,p2d,pd,unsigned(ans/d[0]),reduce.val,size_t(c1c2))) + smallmult(p1d,p2d,pd,reduce.val,size_t(c1c2)); + convert_from(pd,d,res,false); + } + } + return; + } // if convert_int ... +#else + // Modular multiplication, convert everything to integers + vector< int_unsigned > p1,p2,p; + if (convert(th,d,p1,reduce.val) && convert(other,d,p2,reduce.val)){ + if (reduce.val<46340 && 10*lagrtime(p1,p2,p,ans/d[0],reduce.val,int(c1c2))) + smallmult(p1,p2,p,reduce.val,int(c1c2)); // 46340 bound not required? + } + convert(p,d,res); + return ; + } +#endif + } // end reduce.val>0 + } // end reduce.val==_INT_ + if ( //false + (t1==_INT_ || t1==_ZINT) && (t2==_INT_ || t2==_ZINT) + ){ + if (//1|| + 0 && + c1>=FFTMUL_SIZE && c2>=FFTMUL_SIZE && th.dim>1 && d10*std::log(d10)(ita,ita_end,itb,itb_end,res1.coord,th.is_strictly_greater,th.m_is_strictly_greater); + if (res1!=res) + CERR << "fftmult * error " << res-res1 << '\n'; +#endif + return; +#endif + } + longlong maxp1,maxp2; + // should be T_unsigned + // instead tmp_operator_times converts longlong args of * to long + vector< T_unsigned > p1d,p2d,pd; + if (convert_int(th,d,p1d,maxp1) && convert_int(other,d,p2d,maxp2) ) { + double maxp1p2=double(maxp1)*maxp2; + unsigned minc1c2=giacmin(c1,c2); + double un63=double(ulonglong (1) << 63); + double res_size=double(minc1c2)*maxp1p2; + // Check number of required primes: + res_size /= un63; + double nprimes=std::ceil(std::log(res_size)/std::log(2147483647.)); + if (debug_infolevel>5) CERR << CLOCK() << " primes required " << nprimes << '\n'; +#ifdef INT128 + if (nprimes>0 && nprimes<10){ + // using multiplications with int128 + vector< T_unsigned > p1D,p2D,pD; + convert_int128(p1d,p1D); + convert_int128(p2d,p2D); + if (th.dim==1 || !threadmult(p1D,p2D,pD,ans/d[0],0,c1c2)) + smallmult(p1D,p2D,pD,0,c1c2); + if (debug_infolevel>5) CERR << CLOCK() << " end int128 mult " << '\n'; + unsigned pds=pD.size(); + res_size=double(minc1c2)*maxp1p2/std::pow(2.0,127); + if (res_size<1){ + if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion int128_t unsigned" << '\n'; + convert_from(pD,d,res,true,threads>1); + if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n'; + return; + } + vector< T_unsigned > target; + convert(pD,target); + double primed=3037000499.; // floor(2^31.5) + primed /= std::sqrt(double(giacmax(minc1c2,4))); + gen targetprime = pow(plus_two,128); + int prime2=prevprime(int(std::floor(primed))).val; + for (;res_size>=1;){ + if (debug_infolevel>5) + CERR << "prime used " << prime2 << '\n'; + // the product of the two poly mod prime2 can be computed + // without mod computation + vector< T_unsigned > p1add,p2add,add; + smod(p1d,p1add,prime2); + smod(p2d,p2add,prime2); + if (th.dim==1 || !threadmult(p1add,p2add,add,ans/d[0],0,pds)) + smallmult(p1add,p2add,add,0,pds); + smod(add,add,prime2); + if (debug_infolevel>5) CERR << CLOCK() << " ichrem longlong" << '\n'; + ichrem(add,prime2,pd,target,targetprime); // pd is not used at all here + res_size /= prime2; + prime2=prevprime(prime2-2).val; + } + if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion gen unsigned" << '\n'; + convert_from(target,d,res,true); + if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n'; + return; + } +#endif // INT128 + if ( +#ifdef HAVE_GMPXX_H + mpzclass_allowed?nprimes<3.5:nprimes<4.5 +#else + nprimes<4.5 +#endif + ){ + if(debug_infolevel>5) CERR << "Begin smallmult " << CLOCK() << '\n'; + if (th.dim==1 || !threadmult(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2))) + smallmult(p1d,p2d,pd,0,size_t(c1c2)); + if(debug_infolevel>5) CERR << "End smallmult " << CLOCK() << '\n'; + unsigned pds=unsigned(pd.size()); + if ( res_size< 1 ){ + convert_from(pd,d,res,false); + return; + } + // /* + else { + if (debug_infolevel) + CERR << nprimes << " primes required" << '\n'; + vector< T_unsigned > target; + // convert(pd,target); + int prime1=2147483647; + double primed=3037000499.; // floor(2^31.5) + primed /= std::sqrt(double(giacmax(minc1c2,4))); + // the product of the two poly mod prime2 can be computed + // without mod computation + int prime2=prevprime(int(std::floor(primed))).val; + gen targetprime = pow(plus_two,64); + for(;res_size>=1;--nprimes){ + bool withsmod + =false; + //=true; + //=(res_size>std::pow(prime1-1000,nprimes-1)*prime2); + if (debug_infolevel>5) CERR << CLOCK() << " prime " << (withsmod?prime1:prime2) << '\n'; + if (withsmod){ + vector< int_unsigned > p1,p2,padd; + if (!convert(th,d,p1,prime1) || !convert(other,d,p2,prime1)){ +#ifndef NO_STDEXCEPT + setsizeerr(); // should not happen +#endif + } + if (th.dim==1 || !threadmult(p1,p2,padd,unsigned(ans/d[0]),prime1,pds)) + smallmult(p1,p2,padd,prime1,pds); + if (debug_infolevel>5) CERR << CLOCK() << " ichrem int mod" << '\n'; + ichrem(padd,prime1,pd,target,targetprime); + res_size /= prime1; + prime1=prevprime(prime1-2).val; + } + else { + vector< T_unsigned > p1add,p2add,add; + smod(p1d,p1add,prime2); + smod(p2d,p2add,prime2); + if (th.dim==1 || !threadmult(p1add,p2add,add,unsigned(ans/d[0]),0,pds)) + smallmult(p1add,p2add,add,0,pds); + smod(add,add,prime2); + if (debug_infolevel>5) CERR << CLOCK() << " ichrem longlong" << '\n'; + ichrem(add,prime2,pd,target,targetprime); + res_size /= prime2; + prime2=prevprime(prime2-2).val; + } + if (debug_infolevel>5) CERR << CLOCK() << " ichrem end" << '\n'; + } + if (debug_infolevel>5) CERR << CLOCK() << '\n'; + convert_from(target,d,res,true); + if (debug_infolevel>5) CERR << CLOCK() << '\n'; + return; + } // end else (some primes are required) + // */ + } // end nprimes > p1d,p2d,pd; + if (convert_int(p1m,d,p1d,maxp1) && convert_int(p2m,d,p2d,maxp2) ){ + double maxp1p2=double(maxp1)*maxp2; + unsigned minc1c2=giacmin(c1,c2); + double un63=double(ulonglong (1) << 63); + double res_size=double(minc1c2)*maxp1p2; + // Check if mod may be done only at the end + res_size /= un63; + if (res_size<1){ + if (th.dim==1 || !threadmult(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2))) + smallmult(p1d,p2d,pd,0,size_t(c1c2)); + smod(pd,pd,modulo.val); + convert_from(pd,d,res,false); + } + else { +#ifdef INT128 + if (res_size > p1D,p2D,pD; + convert_int128(p1d,p1D); + convert_int128(p2d,p2D); + if (th.dim==1 || !threadmult(p1D,p2D,pD,ans/d[0],0,c1c2)) + smallmult(p1D,p2D,pD,0,c1c2); + smod(pD,modulo.val); + convert_from(pD,d,res,false); + } + else +#endif + { + if (th.dim==1 || !threadmult(p1d,p2d,pd,unsigned(ans/d[0]),modulo.val,size_t(c1c2))) + smallmult(p1d,p2d,pd,modulo.val,size_t(c1c2)); + convert_from(pd,d,res,false); + } + } + // modularize + gen g=makemod(res,modulo); + if (g.type==_POLY) + res=*g._POLYptr; + else + res.coord.clear(); + return; + } + } // end modulo.type==_INT_ + } // end _MOD types +#endif + if (t1==_DOUBLE_ && t2==_DOUBLE_){ + vector< T_unsigned > p1d,p2d,pd; + if (convert_double(th,d,p1d) && convert_double(other,d,p2d) ){ + if (th.dim==1 || !threadmult(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2))) + smallmult(p1d,p2d,pd,0,size_t(c1c2)); + convert_from(pd,d,res,true); + return; + } + } + // FIXME : the comparison 10*lagr_time is not good at all for e.g int/double args + if (is_zero(reduce) && 100*lagrtime > p1,p2,p; + convert(th,d,p1); + convert(other,d,p2); + smallmulpoly_interpolate(p1,p2,p,d); + convert(p,d,res); + return; + } +#ifdef HAVE_GMPXX_H + if (t1<=_ZINT && t2<=_ZINT && mpzclass_allowed){ + if (debug_infolevel>1) + CERR << "mpz mult convert begin " << CLOCK() << '\n'; + vector< T_unsigned > p1d,p2d,pd; + if (convert_myint(th,d,p1d) && convert_myint(other,d,p2d) ){ + if (debug_infolevel>1) + CERR << "mpz mult begin " << CLOCK() << '\n'; + // threadmult is slow for heap allocated data because of malloc lock + // if (th.dim==1 || !threadmult(p1d,p2d,pd,ans/d[0],0,c1c2)) + smallmult(p1d,p2d,pd,0,c1c2); + if (debug_infolevel>1) + CERR << "mpz mult end " << CLOCK() << '\n'; + convert_from(pd,d,res,false); + return; + } + } +#endif + vector< T_unsigned > p1,p2,p; + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult convert begin " << CLOCK() << '\n'; + convert(th,d,p1); + convert(other,d,p2); + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult begin " << CLOCK() << '\n'; + // threadmult does not work on multi-CPU (malloc error with GMP data structures) and it would be slow anyway because of malloc locks + // if (th.dim==1 || !threadmult(p1,p2,p,ans/d[0],0,c1c2)) + smallmult(p1,p2,p,0,size_t(c1c2)); + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult end " << CLOCK() << '\n'; + convert(p,d,res); + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult convert end " << CLOCK() << '\n'; + return ; + // CERR << "Copy " << CLOCK() << " " << copy_number << '\n'; + // if (th.dim==12) + // CERR << "sort *unsigned end " << CLOCK() << " " << res.coord.size() << '\n'; + /* + polynome save(res); + sort(res.coord.begin(),res.coord.end(),th.m_is_strictly_greater); // still done + if (res!=save) + CERR << "unsorted" << '\n'; + */ + // if (res.coord.size()==1357366) + // CERR << "coucou" << '\n'; + // if (th.dim==12){ + // CERR << "*unsigned end " << CLOCK() << '\n'; + } + if (ans/RAND_MAX0){ + // Modular multiplication, convert everything to integers + vector< T_unsigned > p1,p2,p; + if (convert(th,d,p1,reduce.val) && convert(other,d,p2,reduce.val)){ + if (reduce.val<46340 && 10*lagrtime + // instead tmp_operator_times converts longlong args of * to long + vector< T_unsigned > p1d,p2d,pd; + if (debug_infolevel>1) + CERR << CLOCK() << "longlong mult ulonglong convert begin " << CLOCK() << '\n'; + if (convert_int(th,d,p1d,maxp1) && convert_int(other,d,p2d,maxp2) ){ + double maxp1p2=double(maxp1)*maxp2; + unsigned minc1c2=giacmin(c1,c2); + double un63=double(ulonglong (1) << 63); + double res_size=double(minc1c2)*maxp1p2; + // Check number of required primes: + res_size /= un63; + double nprimes=std::ceil(std::log(res_size)/std::log(2147483647.)); + if (debug_infolevel>5) CERR << CLOCK() << " primes required " << nprimes << '\n'; +#ifdef INT128 + if (nprimes>0 && nprimes<10){ + // using multiplications with int128 + vector< T_unsigned > p1D,p2D,pD; + convert_int128(p1d,p1D); + convert_int128(p2d,p2D); + if (th.dim==1 || !threadmult(p1D,p2D,pD,ans/d[0],0,c1c2)) + smallmult(p1D,p2D,pD,0,c1c2); + if (debug_infolevel>5) CERR << CLOCK() << " end int128 mult " << '\n'; + unsigned pds=pD.size(); + res_size=double(minc1c2)*maxp1p2/std::pow(2.0,127); + if (res_size<1){ + if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion int 128_t ulonglong" << '\n'; + convert_from(pD,d,res,true,threads>1); + if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n'; + return; + } + vector< T_unsigned > target; + convert(pD,target); + double primed=3037000499.; // floor(2^31.5) + primed /= std::sqrt(double(giacmax(minc1c2,4))); + gen targetprime = pow(plus_two,128); + int prime2=prevprime(int(std::floor(primed))).val; + for (;res_size>=1;){ + if (debug_infolevel>5) + CERR << "prime used " << prime2 << '\n'; + // the product of the two poly mod prime2 can be computed + // without mod computation + vector< T_unsigned > p1add,p2add,add; + smod(p1d,p1add,prime2); + smod(p2d,p2add,prime2); + if (th.dim==1 || !threadmult(p1add,p2add,add,ans/d[0],0,pds)) + smallmult(p1add,p2add,add,0,pds); + smod(add,add,prime2); + if (debug_infolevel>5) CERR << CLOCK() << " ichrem longlong" << '\n'; + ichrem(add,prime2,pd,target,targetprime); // pd is not used at all here + res_size /= prime2; + prime2=prevprime(prime2-2).val; + } + if (debug_infolevel>5) CERR << CLOCK() << " begin result conversion gen ulonglong" << '\n'; + convert_from(target,d,res,true); + if (debug_infolevel>5) CERR << CLOCK() << " end result conversion" << '\n'; + return; + } +#endif + if ( res_size< 1 ){ + if (debug_infolevel>1) + CERR << CLOCK() << "longlong mult ulonglong begin " << CLOCK() << '\n'; + if (th.dim==1 || !threadmult(p1d,p2d,pd,ans/d[0],0,size_t(c1c2))) + smallmult(p1d,p2d,pd,0,size_t(c1c2)); + if (debug_infolevel>1) + CERR << CLOCK() << "longlong mult ulonglong end " << CLOCK() << '\n'; + convert_from(pd,d,res,false); + if (debug_infolevel>1) + CERR << CLOCK() << "longlong mult ulonglong convert end " << CLOCK() << '\n'; + return; + } + } + } + if (t1==_DOUBLE_ && t2==_DOUBLE_){ + vector< T_unsigned > p1d,p2d,pd; + if (convert_double(th,d,p1d) && convert_double(other,d,p2d) ){ + if (th.dim==1 || !threadmult(p1d,p2d,pd,unsigned(ans/d[0]),0,size_t(c1c2))) + smallmult(p1d,p2d,pd,0,size_t(c1c2)); + convert_from(pd,d,res,true); + return; + } + } + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult ulonglong convert begin " << CLOCK() << '\n'; + vector< T_unsigned > p1,p2,p; + convert(th,d,p1); + convert(other,d,p2); + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult ulonglong mult begin " << CLOCK() << '\n'; + smallmult(p1,p2,p,0,size_t(c1c2)); + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult ulonglong mult end " << CLOCK() << '\n'; + convert(p,d,res); + if (debug_infolevel>1) + CERR << CLOCK() << "gen mult ulonglong convert end " << CLOCK() << '\n'; + // if (th.dim==12) + // CERR << "sort*longlong end " << CLOCK() << " " << res.coord.size() << '\n'; + // sort(res.coord.begin(),res.coord.end(),th.m_is_strictly_greater); // still done + // if (th.dim==12) + // CERR << "*longlong end " << CLOCK() << '\n'; + return ; + } + } // end if c1>7 && c2>7 + if (debug_infolevel>1) + CERR << CLOCK() << "Mul begin " << CLOCK() << '\n'; +#ifdef FXCG + Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater); +#else + if (c1*c2<100) + Mul_gen(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater); + else + Mul(ita,ita_end,itb,itb_end,res.coord,th.is_strictly_greater,th.m_is_strictly_greater); +#endif + if (debug_infolevel>1) + CERR << CLOCK() << "Mul end " << CLOCK() << '\n'; + // if (th.dim==12) + // CERR << "* end " << CLOCK() << " " << res.coord.size() << '\n'; + return ; +#endif // NO_TEMPLATE_MULTGCD besta_os + } + + polynome operator * (const polynome & th, const polynome & other) { + polynome res(th.dim,th); // reserve() is done by Mul + mulpoly(th,other,res,0); + return res; + } + + polynome & operator *= (polynome & th, const polynome & other) { +#ifdef NSPIRE + th=th*other; +#else + mulpoly(th,other,th,0); +#endif + return th; + } + + /* + Note about Miller Pure Recurrence, see Knuth, TAOC v.2 + If P(x) = sum_{i=0}^n p_i x^k + Then P(x)^m = sum_{k=0}^{m*n} a(m,k) x^k + Where + a(m,0) = p_0^m, + a(m,k) = 1/(k p_0) sum_{i=1}^min(n,k) p_i ((m+1)i-k) a(m,k-i), + For k<=m we have a division free implementation, let + a(m,k)=b(m,k) p_0^(m-k) + b(m,0)=1, b(m,k)=1/k sum_{i=1}^min(n,k) p_i ((m+1)i-k) b(m,k-i) p_0^(i-1) + But for k>m, the division by p0 must be done at each step + which might be too costly + Example: P(x)=3x^2+2x+5, n=2 + m=2: P^2=9*x^4+12*x^3+34*x^2+20*x+25 + b(m,0)=1, a(m,0)=25 + b(m,1)= p_1*(3*1-1)*b(m,0)=4, a(m,1)=20 + b(m,2)=1/2*(p_1*(3*1-2)*b(m,1)+p_2*(3*2-2)*p_0*b(m,0)) + =1/2*(2*4+3*4*5)=34, a(m,2)=34 + a(m,3)=1/3/5*(p_1*(3*1-3)*a(m,2)+p_2*(3*2-3)*a(m,1))=12 + a(m,4)=1/4/5*(p_1*(3*1-4)*a(m,3)+p_2*(3*2-4)*a(m,2))=1/20*(-2*12+3*2*34)=9 + There is a case where no bad division occurs: if p_0 is a constant + (no other variable occur) or if n==1 (binomial formula) + */ + bool powpoly(const polynome & th, int u,polynome & res){ + if (u<0){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Negative polynome power")); +#endif + return false; + } + if (!u){ + res= tensor(gen(1),th.dim); + return true; + } + if (u==1){ + res=th; + return true; + } + if (u==2){ + res=th*th; + return true; + } +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + res.coord.clear(); + res.coord.push_back(monomial(gensizeerr(gettext("Stopped by user interruption.")),res.dim)); + return false; + } + if (th.dim==1 && u>10){ + modpoly a; + polynome2poly1(th,1,a); + gen b=pow(gen(a,_POLY1__VECT),u); + if (b.type==_VECT){ + poly12polynome(*b._VECTptr,1,res,1); + return true; + } + } + vector< monomial >::const_iterator ita = th.coord.begin(); + vector< monomial >::const_iterator ita_end = th.coord.end(); + int c1=int(ita_end-ita); + if (c1==0){ + res=th; + return true; + } + if (c1==1){ + res=th; + res.coord.front().value=pow(res.coord.front().value,u); + res.coord.front().index = res.coord.front().index*u ; + return true; + } + ulonglong ans=1,pid1=1; + index_t d1=th.degree(),d(th.dim); + for (int i=0;iRAND_MAX) + break; + } + if (ans<=RAND_MAX){ + // int t1=th.coord.front().value.type; + /* +#ifdef HAVE_GMPXX_H + if (t1<=_ZINT && mpzclass_allowed){ + vector< T_unsigned > p1,p2,p; + if (convert_myint(th,d,p1) ){ + p2=p1; + for (int i=1;i20) + CERR << "power mpz " << i << " " << CLOCK() << '\n'; + unsigned c1c2 = p1.size()*p2.size(); + if (th.dim==1 || !threadmult(p1,p2,p,ans/d[0],0,c1c2)) + smallmult(p1,p2,p,0,c1c2); + p1=p; + } + convert_from(p,d,res,false); + return; + } + } +#endif + */ + vector< T_unsigned > p1,p2,p; + convert(th,d,p1); + p2=p1; + for (int i=1;i20) + CERR << "power gen " << i << " " << CLOCK() << '\n'; + unsigned c1c2 = unsigned(p1.size()*p2.size()); + // threadmult does not work on multi-CPU (malloc error with GMP data structures) + // if (th.dim==1 || !threadmult(p1,p2,p,ans/d[0],0,c1c2)) + smallmult(p1,p2,p,0,c1c2); + p1=p; + } + convert(p,d,res); + } + else // ans>RAND_MAX +#endif // NO_TEMPLATE_MULTGCD + res=Tpow(th,u); + return true; + } + + polynome operator - (const polynome & th) { + // Tensor addition + polynome res(th.dim,th); + vector< monomial >::const_iterator a = th.coord.begin(); + vector< monomial >::const_iterator a_end = th.coord.end(); + res.coord.reserve(a_end - a ); + for (;a!=a_end;++a){ + res.coord.push_back(monomial(-(*a).value,(*a).index)); + } + return res; + } + + void submulpoly(const polynome & a,const polynome & b,const polynome & q,polynome & r){ +#if 0 + r=a-b*q; +#else + polynome tmp(a.dim); + mulpoly(b,q,tmp,0); + vector< monomial >::const_iterator a_beg=a.coord.begin(); + vector< monomial >::const_iterator a_end=a.coord.end(); + vector< monomial >::const_iterator b_beg=tmp.coord.begin(); + vector< monomial >::const_iterator b_end=tmp.coord.end(); + vector< monomial > & new_coord=r.coord; + new_coord.clear(); + for (;;) { + // If a is empty, fill up with elements from b and stop + if (a_beg == a_end) { + while (b_beg != b_end) { + new_coord.push_back(-(*b_beg)); + ++b_beg; + } + break; + } + const index_m & pow_a = a_beg->index; + // If b is empty, fill up with elements from a and stop + if (b_beg == b_end) { + while (a_beg != a_end) { + new_coord.push_back(*a_beg); + ++a_beg; + } + break; + } + const index_m & pow_b = b_beg->index; + // a and b are non-empty, compare powers + if (pow_a!=pow_b){ + if (a.is_strictly_greater(pow_a, pow_b)) { + // a has lesser power, get coefficient from a + new_coord.push_back(*a_beg); + ++a_beg; + } + else { + // b has lesser power, get coefficient from b + new_coord.push_back(-(*b_beg)); + ++b_beg; + } + } + else { + gen diff = (*a_beg).value - (*b_beg).value; + if (!is_zero(diff)) + new_coord.push_back(monomial(diff,pow_a)); + ++a_beg; + ++b_beg; + } + } +#endif + } + + // exactquo==2 means we know that b divides a and we search the cofactor + // exactquo==1 means we want to check that b divides a + // exactquo==-1 means compute quotient first using heap div then r=a-b*quo + // exactquo==-2 means compute quotient only using heap div + bool divrem1(const polynome & a,const polynome & b,polynome & quo,polynome & r,int exactquo,bool allowrational) { + quo.coord.clear(); + quo.dim=a.dim; + r.dim=a.dim; + r.coord.clear(); + int bs=int(b.coord.size()); + if ( b.dim<=1 || bs==1 || a.coord.empty() ){ + return a.TDivRem(b,quo,r,allowrational) && (exactquo>0?r.coord.empty():true) ; + } + int bdeg=b.coord.front().index.front(),rdeg=a.lexsorted_degree(),ddeg=rdeg-bdeg; +#ifndef NO_TEMPLATE_MULTGCD + int hashdivremres=0; + if (ddeg>3 && !allowrational){ + index_t d1=a.degree(),d2=b.degree(),d3=b.coord.front().index.iref(),d(a.dim); + // i-th degrees of th / other in quotient and remainder + // are <= i-th degree of th + ddeg*(i-th degree of other - i-th degree of lcoeff of other) + double ans=1; + for (int i=0;i>= 1)) + break; + } + d[i] = 1 << j; + ans = ans*unsigned(d[i]); + if (ans/RAND_MAX>RAND_MAX) + break; + } + bool doit=true; + if (ans vars(a.dim); + vars[a.dim-1]=1; + for (int i=a.dim-2;i>=0;--i){ + vars[i]=d[i+1]*vars[i+1]; + } + if (debug_infolevel>1) + CERR << "divrem1 convert " << CLOCK() << '\n'; + if (a.coord.front().value.type==_MOD || b.coord.front().value.type==_MOD){ + gen reduce=a.coord.front().value.type==_MOD?*(a.coord.front().value._MODptr+1):*(b.coord.front().value._MODptr+1); + if (reduce.type==_INT_){ + polynome thm,otherm; + unmodularize(a,thm); + unmodularize(b,otherm); + vector< T_unsigned > p1,p2,p,quot32,remain32; + if (convert(thm,d,p1,reduce.val) && convert(otherm,d,p2,reduce.val)){ + if (hashdivrem(p1,p2,quot32,remain32,vars,reduce.val,0,false,exactquo)>=1){ + convert_from(quot32,d,quo,true); + if (exactquo==-1 && hashdivremres==2) + submulpoly(a,b,quo,r); + else + convert_from(remain32,d,r,true); + int32_modularize(quo,reduce); + int32_modularize(r,reduce); + return true; + } + } + } + } + else { + std::vector< T_unsigned > p1,p2,quot,remain; + longlong maxp1,maxp2; + doit=convert_int(a,d,p1,maxp1) && convert_int(b,d,p2,maxp2) && maxp1/RAND_MAX < RAND_MAX; + if (doit){ + if (maxp11) + CERR << "hashdivrem1 int32 begin " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n'; + // try with int instead of longlong + std::vector< T_unsigned > p132,p232,quot32,remain32; + if (convert_int32(a,d,p132) && convert_int32(b,d,p232) && + (hashdivremres=hashdivrem(p132,p232,quot32,remain32,vars,0,RAND_MAX/double(maxp2)/p2.size(),false,exactquo))>=1){ + if (debug_infolevel>1) + CERR << "hashdivrem1 int32 success " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n'; + convert_from(quot32,d,quo,true); + if (exactquo==-1 && hashdivremres==2) submulpoly(a,b,quo,r); else + convert_from(remain32,d,r,true); + return true; + } + else { + if (debug_infolevel>1) + CERR << "hashdivrem1 int32 failure " << CLOCK() << '\n'; + } + } + if (debug_infolevel>1) + CERR << "hashdivrem1 longlong begin " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n'; + if ((hashdivremres=hashdivrem(p1,p2,quot,remain,vars,/* reduce*/0,RAND_MAX/double(maxp2)/p2.size()*RAND_MAX,false,exactquo))>=1){ + if (debug_infolevel>1) + CERR << "hashdivrem1 longlong end " << CLOCK() << '\n'; + convert_from(quot,d,quo,false); + if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else + convert_from(remain,d,r,false); + return true; + } + else { + if (debug_infolevel>1) + CERR << "hashdivrem1 longlong failure " << CLOCK() << '\n'; + } + } +#ifdef INT128 + { + int128_t maxp1,maxp2; + vector< T_unsigned > aD,bD,qD,rD; + if (debug_infolevel>1) + CERR << "hashdivrem1 int128 int begin " << CLOCK() << " ddeg=" << ddeg << '\n'; + if (convert_int(a,d,aD,maxp1) && convert_int(b,d,bD,maxp2) && (hashdivremres=hashdivrem(aD,bD,qD,rD,vars,0,1.7e38/double(maxp2)/p2.size(),false,exactquo))>=1){ + if (debug_infolevel>1) + CERR << "hashdivrem1 int128 int success " << CLOCK() << " maxp1=" << double(maxp1) << " maxp2=" << double(maxp2) << " ddeg=" << ddeg << '\n'; + convert_from(qD,d,quo,true); + if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else + convert_from(rD,d,r,true); + return true; + } + } +#endif + doit=false; + } +#ifdef HAVE_GMPXX_H + if (mpzclass_allowed) + { + std::vector< T_unsigned > p1,p2,quot,remain; + if (debug_infolevel>1) + CERR << "divrem1mpz int convert " << CLOCK() << '\n'; + doit=convert_myint(a,d,p1) && convert_myint(b,d,p2); + if (doit){ + if (debug_infolevel>1) + CERR << "hashdivrem1mpz int begin " << CLOCK() << " ddeg=" << ddeg << '\n'; + if ((hashdivremres=hashdivrem(p1,p2,quot,remain,vars,/* reduce */ 0,/* no size check */0.0,false,exactquo))>=1){ + if (debug_infolevel>1) + CERR << "hashdivrem1mpz int end " << CLOCK() << '\n'; + convert_from(quot,d,quo,false); + if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else + convert_from(remain,d,r,false); + return true; + } + else { + if (debug_infolevel>1) + CERR << "hashdivrem1mpz int failure " << CLOCK() << '\n'; + } + } + } +#endif + } + if (doit && ans/RAND_MAX vars(a.dim); + vars[a.dim-1]=1; + for (int i=a.dim-2;i>=0;--i){ + vars[i]=d[i+1]*vars[i+1]; + } + if (debug_infolevel>1) + CERR << "divrem1 convert " << CLOCK() << '\n'; + if (a.coord.front().value.type==_MOD || b.coord.front().value.type==_MOD){ + gen reduce=a.coord.front().value.type==_MOD?*(a.coord.front().value._MODptr+1):*(b.coord.front().value._MODptr+1); + if (reduce.type==_INT_){ + polynome thm,otherm; + unmodularize(a,thm); + unmodularize(b,otherm); + vector< T_unsigned > p1,p2,p,quot32,remain32; + if (convert(thm,d,p1,reduce.val) && convert(otherm,d,p2,reduce.val)){ + if (hashdivrem(p1,p2,quot32,remain32,vars,reduce.val,0,false,exactquo)>=1){ + convert_from(quot32,d,quo,true); + if (exactquo==-1 && hashdivremres==2) + submulpoly(a,b,quo,r); + else + convert_from(remain32,d,r,true); + int32_modularize(quo,reduce); + int32_modularize(r,reduce); + return true; + } + } + } + } + else { + std::vector< T_unsigned > p1,p2,quot,remain; + longlong maxp1,maxp2; + doit=convert_int(a,d,p1,maxp1) && convert_int(b,d,p2,maxp2) && maxp1/RAND_MAX < RAND_MAX; + // doit=false; + if (doit){ + if (debug_infolevel>1) + CERR << "hashdivrem1 longlong ulonglong begin " << CLOCK() << " maxp1=" << maxp1 << " maxp2=" << maxp2 << " ddeg=" << ddeg << '\n'; + if ((hashdivremres=hashdivrem(p1,p2,quot,remain,vars,/* reduce */0,RAND_MAX/double(maxp2)/p2.size()*RAND_MAX,false,exactquo))>=1){ + if (debug_infolevel>1) + CERR << "hashdivrem1 longlong ulonglong end " << CLOCK() << '\n'; + convert_from(quot,d,quo,false); + if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else + convert_from(remain,d,r,false); + return true; + } + else { + if (debug_infolevel>1) + CERR << "hashdivrem1 longlong ulonglong failure " << CLOCK() << '\n'; + } + } +#ifdef INT128 + { + int128_t maxp1,maxp2; + vector< T_unsigned > aD,bD,qD,rD; + if (debug_infolevel>1) + CERR << "hashdivrem1 int128 ulonglong begin " << CLOCK() << " ddeg=" << ddeg << '\n'; + if (convert_int(a,d,aD,maxp1) && convert_int(b,d,bD,maxp2) && (hashdivremres=hashdivrem(aD,bD,qD,rD,vars,0,1.7e38/double(maxp2)/p2.size(),false,exactquo))>=1){ + if (debug_infolevel>1) + CERR << "hashdivrem1 int128 ulonglong success " << CLOCK() << " maxp1=" << double(maxp1) << " maxp2=" << double(maxp2) << " ddeg=" << ddeg << '\n'; + convert_from(qD,d,quo,true); + if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else + convert_from(rD,d,r,true); + return true; + } + } +#endif + } +#ifdef HAVE_GMPXX_H + if (mpzclass_allowed) + { + std::vector< T_unsigned > p1,p2,quot,remain; + // longlong maxp1,maxp2; + if (debug_infolevel>1) + CERR << "divrem1mpz ulonglong convert " << CLOCK() << '\n'; + doit=convert_myint(a,d,p1) && convert_myint(b,d,p2); + if (doit){ + if (debug_infolevel>1) + CERR << "hashdivrem1z ulonglong begin " << CLOCK() << " ddeg=" << ddeg << '\n'; + if ((hashdivremres=hashdivrem(p1,p2,quot,remain,vars,/* reduce */ 0,/* no size check */0.0,false,exactquo))>=1){ + if (debug_infolevel>1) + CERR << "hashdivrem1 ulonglong end " << CLOCK() << '\n'; + convert_from(quot,d,quo,false); + if (hashdivremres==2 && exactquo==-1) submulpoly(a,b,quo,r); else + convert_from(remain,d,r,false); + return true; + } + else { + if (debug_infolevel>1) + CERR << "hashdivrem1 ulonglong failure " << CLOCK() << '\n'; + } + } + } +#endif + } + } // end if (ddeg>3) +#endif // NO_TEMPLATE_MULTGCD + return a.TDivRem1(b,quo,r,allowrational,exactquo>0); + } + + polynome operator / (const polynome & th,const polynome & other) { + if (Tis_one(other)) return th; + polynome rem(th.dim,th),quo(th.dim,th); + // if ( !(th).TDivRem1(other,quo,rem) ) + if ( !divrem1(th,other,quo,rem) ){ +#ifdef NO_STDEXCEPT + quo.coord.clear(); + quo.coord.push_back(monomial(gensizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print()),quo.dim)); +#else + setsizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print()); +#endif + } + return(quo); + } + + polynome operator / (const polynome & th,const gen & fact ) { + if (fact==gen(1)) + return th; + polynome res(th.dim,th); + vector< monomial >::const_iterator a = th.coord.begin(); + vector< monomial >::const_iterator a_end = th.coord.end(); + Div(a,a_end,fact,res.coord); + return res; + } + + polynome operator % (const polynome & th,const polynome & other) { + polynome rem(th.dim,th),quo(th.dim,th); + if ( !(th).TDivRem1(other,quo,rem) ){ +#ifdef NO_STDEXCEPT + rem.coord.clear(); + rem.coord.push_back(monomial(gensizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print()),quo.dim)); +#else + setsizeerr(gettext("Unable to divide, perhaps due to rounding error")+th.print()+" / "+other.print()); +#endif + } + return(rem); + } + + polynome operator % (const polynome & th, const gen & modulo) { + polynome res(th.dim,th); + vector< monomial >::const_iterator a = th.coord.begin(); + vector< monomial >::const_iterator a_end = th.coord.end(); + res.coord.reserve(a_end - a ); + for (;a!=a_end;++a){ + gen tmp((*a).value % modulo); + if (!is_zero(tmp)) + res.coord.push_back(monomial(tmp,a->index)); + } + return res; + } + + polynome re(const polynome & th){ + return Tapply(th,no_context_re); + } + + polynome im(const polynome & th){ + return Tapply(th,no_context_im); + } + + polynome conj(const polynome & th){ + return Tapply(th,no_context_conj); + } + + void smod(const polynome & th, const gen & modulo,polynome & res){ + vector< monomial >::const_iterator a = th.coord.begin(); + vector< monomial >::const_iterator a_end = th.coord.end(); + res.coord.clear(); + res.coord.reserve(a_end - a ); + for (;a!=a_end;++a){ + const gen & tmp=smod(a->value, modulo); + if (!is_zero(tmp)) + res.coord.push_back(monomial(tmp,a->index)); + } + } + + polynome smod(const polynome & th, const gen & modulo) { + polynome res(th.dim,th); + smod(th,modulo,res); + return res; + } + + // var is the variable number to extract, from 1 to p.dim + void polynome2poly1(const polynome & pp,int var,vecteur & v){ + if (pp.dim==0){ + gensizeerr("polynome2poly1"); + v.clear(); + if (!pp.coord.empty()) + v.push_back(pp.coord.front().value); + } + if (var!=1){ + polynome p(pp); + p.reorder(transposition(0,var-1,p.dim)); + polynome2poly1(p,1,v); + return; + } + v.clear(); + int current_deg=pp.lexsorted_degree(); + v.reserve(current_deg+1); + vector< monomial >::const_iterator it=pp.coord.begin(),itend=pp.coord.end(); + for (;it!=itend;--current_deg){ + if (it->index.front()==current_deg){ + if (pp.dim==1){ + v.push_back(it->value); + ++it; + } + else + v.push_back(Tnextcoeff(it,itend)); + } + else { +#if 0 + if (pp.dim==1) + v.push_back(0); + else + v.push_back(polynome(pp.dim-1)); +#else + v.push_back(0); +#endif + } + } + for (;current_deg>=0;--current_deg) + v.push_back(zero); + } + + vecteur polynome2poly1(const polynome & p,int var){ + vecteur v; + polynome2poly1(p,var,v); + return v; + } + + // like polynome2poly1 for univariate p + vecteur polynome12poly1(const polynome & p){ + if (p.dim>1) + return polynome2poly1(p,1); + int current_deg=p.lexsorted_degree(); + vecteur v; + v.reserve(current_deg+1); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;--current_deg){ + if (it->index.front()==current_deg){ + v.push_back(it->value); + ++it; + } + else + v.push_back(zero); + } + for (;current_deg>=0;--current_deg) + v.push_back(zero); + return v; + } + + vecteur polynome2poly1(const polynome & p){ + if (p.dim>1) + return polynome2poly1(p,1); + vecteur v; + int current_deg=p.lexsorted_degree(); + v.reserve(current_deg+1); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;--current_deg){ + if (it->index.front()==current_deg){ + v.push_back(it->value); + ++it; + } + else + v.push_back(zero); + } + for (;current_deg>=0;--current_deg) + v.push_back(zero); + return v; + } + + gen polynome2poly1(const gen & e,int var){ + if (e.type==_POLY) + return polynome2poly1(*e._POLYptr,var); + if (e.type!=_FRAC) + return e; + return fraction(polynome2poly1(e._FRACptr->num,var),polynome2poly1(e._FRACptr->den,var)); + } + + int inner_POLYdim(const vecteur & v){ + const_iterateur it=v.begin(),itend=v.end(); + int dim=1; + for (;it!=itend;++it){ + if (it->type==_POLY){ + dim=it->_POLYptr->dim+1; + break; + } + } + return dim; + } + + gen untrunc(const gen & e,int degree,int dimension){ + if (e.type==_POLY) + return e._POLYptr->untrunc(degree,dimension); + if (e.type==_EXT) + return algebraic_EXTension(untrunc(*e._EXTptr,degree,dimension),untrunc(*(e._EXTptr+1),degree,dimension)); + if (e.type==_VECT){ + const_iterateur it=e._VECTptr->begin(),itend=e._VECTptr->end(); + vecteur res; + res.reserve(itend-it); + for (;it!=itend;++it) + res.push_back(untrunc(*it,degree,dimension)); + return res; + } + if (e.type==_FRAC) + return fraction(untrunc(e._FRACptr->num,degree,dimension),untrunc(e._FRACptr->den,0,dimension)); + return tensor(monomial(e,degree,1,dimension)); + } + + gen vecteur2polynome(const vecteur & v,int dimension){ + const_iterateur it=v.begin(),itend=v.end(); + gen e; + for (int d=int(itend-it)-1;it!=itend;++it,--d){ + if (!is_zero(*it)) + e = e+untrunc(*it,d,dimension); + } + return e; + } + + polynome poly12polynome(const vecteur & v){ + const_iterateur it=v.begin(),itend=v.end(); + polynome p(1); + for (int d=int(itend-it)-1;it!=itend;++it,--d){ + if (!is_zero(*it)) + p.coord.push_back(monomial(*it,d,1,1)); + } + return p; + } + + // WARNING: var begins at 1 and ends at dimension + void poly12polynome(const vecteur & v, int var,polynome & p,int dimension){ + if (dimension) + p.dim=dimension; + else + p.dim=inner_POLYdim(v); + p.coord.clear(); + const_iterateur it=v.begin(),itend=v.end(); + for (int d=int(itend-it)-1;it!=itend;++it,--d){ + if (is_zero(*it)) + continue; + if (it->type!=_POLY || (it->_POLYptr->dim+1)!=p.dim) + p.coord.push_back(monomial(*it,d,1,p.dim)); + else { + vector< monomial >::const_iterator p_it=it->_POLYptr->coord.begin(),p_itend=it->_POLYptr->coord.end(); + for (;p_it!=p_itend;++p_it) + p.coord.push_back(p_it->untrunc(d,p.dim)); + } + } + if (var!=1){ + p.reorder(transposition(0,var-1,p.dim)); + } + } + + polynome poly1_2_polynome(const vecteur & v, int dimension){ + polynome p(dimension); + const_iterateur it=v.begin(),itend=v.end(); + for (int d=int(itend-it)-1;it!=itend;++it,--d){ + if (is_zero(*it)) + continue; + p.coord.push_back(monomial(*it,d,1,p.dim)); + } + return p; + } + + polynome poly12polynome(const vecteur & v,int var,int dimension){ + polynome p(0); + poly12polynome(v,var,p,dimension); + return p; + } + + // assuming pmod and qmod are prime together, find r such that + // r = p mod pmod and r = q mod qmod + // hence r = p + A*pmod = q + B*qmod + // or A*pmod -B*qmod = q - p + // assuming u*pmod+v*pmod=d we get + // A=u*(q-p)/d + polynome ichinrem(const polynome &p,const polynome & q,const gen & pmod,const gen & qmod){ + gen u,v,d,tmp,pqmod(pmod*qmod); + egcd(pmod,qmod,u,v,d); + // COUT << u << "*" << pmod << "+" << v << "*" << qmod << "=" << d << " " << u*pmod+v*qmod << '\n'; + vector< monomial >::const_iterator a = p.coord.begin(); + vector< monomial >::const_iterator a_end = p.coord.end(); + vector< monomial >::const_iterator b = q.coord.begin(); + vector< monomial >::const_iterator b_end = q.coord.end(); + polynome res(p.dim); + res.coord.reserve(a_end - a ); + for (;(a!=a_end)&&(b!=b_end);){ + if (a->index != b->index){ + if (a->index>=b->index){ + tmp=a->value-rdiv(u*a->value,d,context0); + res.coord.push_back(monomial(smod(tmp,pqmod),a->index)); + ++a; + } + else { + tmp=rdiv(u*b->value,d,context0); + res.coord.push_back(monomial(smod(tmp,pqmod),b->index)); + ++b; + } + } + else { + tmp=a->value+rdiv(u*(b->value-a->value),d,context0) *pmod ; + // COUT << a->value << " " << b->value << "->" << tmp << " " << pqmod << '\n'; + res.coord.push_back(monomial(smod(tmp,pqmod),b->index)); + ++b; + ++a; + } + } + for (;a!=a_end;++a) + res.coord.push_back(monomial(smod(a->value-rdiv(u*(a->value),d,context0),pqmod),a->index)); + for (;b!=b_end;++b) + res.coord.push_back(monomial(smod(rdiv(u*b->value,d,context0),pqmod),b->index)); + return res; + } + + bool divrem (const polynome & th, const polynome & other, polynome & quo, polynome & rem, bool allowrational ){ + return th.TDivRem(other,quo,rem,allowrational); + } + + bool exactquotient(const polynome & a,const polynome & b,polynome & quo,bool allowrational){ + CLOCK_T beg=CLOCK(),delta; + if (debug_infolevel>1) + CERR << beg*1e-6 << " exactquo begin" << '\n'; + bool res= a.Texactquotient(b,quo,allowrational); + delta=CLOCK()-beg; + if (delta && debug_infolevel>1) // a.dim>=inspectdim + CERR << "exactquo end " << delta*1e-6 << " " << res << '\n'; + return res; + } + + static bool divremmod2 (const polynome & th,const polynome & other, const gen & modulo,polynome & quo, polynome & rem) { + int asize=int(th.coord.size()); + if (!asize){ + quo=th; + rem=th; + return true; + } + int bsize=int(other.coord.size()); + if (bsize==0){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("gausspol.cc/divremmod2")); +#endif + return false; + } + index_m a_max = th.coord.front().index; + index_m b_max = other.coord.front().index; + quo.coord.clear(); + quo.dim=th.dim; + rem.dim=th.dim; + if ( (bsize==1) && (b_max==b_max*0) ){ + rem.coord.clear(); + gen b=other.coord.front().value; + if (b==gen(1)) + quo = th ; + else { + b=invmod(b,modulo); + vector< monomial >::const_iterator itend=th.coord.end(); + for (vector< monomial >::const_iterator it=th.coord.begin();it!=itend;++it) + quo.coord.push_back(monomial( smod(it->value*b,modulo),it->index)); + } + return true; + } + rem=th; + if ( ! (a_max>=b_max) ){ + // test that the first power of a_max is < to that of b_max + return (a_max.front()= b_max){ + gen q=smod(rem.coord.front().value*b, modulo); + quo.coord.push_back(monomial(q,a_max-b_max)); + polynome temp=other.shift(a_max-b_max,q); + rem = smod(rem-temp, modulo); + if (rem.coord.size()) + a_max=rem.coord.front().index; + else + break; + } + return(true); + } + + bool divremmod (const polynome & th,const polynome & other, const gen & modulo,polynome & quo, polynome & r) { + quo.coord.clear(); + quo.dim=th.dim; + r.dim=th.dim; + if ( (th.dim<=1) || (th.coord.empty()) ) + return divremmod2(th,other,modulo,quo,r); + int os=int(other.coord.size()); + if (!os){ + r=th; + return true; + } + if (os==1){ + // Check for a division by 1 + if (is_one(other.coord.front().value) && other.coord.front().index.is_zero()){ + quo=th; + r.coord.clear(); + return true; + } + // IMPROVE Invert other.coord.front() and shift/multiply + + } + std::vector< monomial >::const_iterator it=other.coord.begin(); + int bdeg=it->index.front(),rdeg=th.lexsorted_degree(),ddeg=rdeg-bdeg; +#ifndef NO_TEMPLATE_MULTGCD + // FIXME hashdivrem may fail if not divisible if false is commented below + // search new quotient term in threaded.h if heap multiplication is used + if (//false && + ddeg>2 && os>10 + ){ + index_t d1=th.degree(),d2=other.degree(),d3=other.coord.front().index.iref(),d(th.dim); + // i-th degrees of th / other in quotient and remainder + // are <= i-th degree of th + ddeg*(i-th degree of other - i-th degree of lcoeff of other) + double ans=1; + for (int i=0;i>= 1)) + break; + } + d[i] = 1 << j; + ans = ans*unsigned(d[i]); + if (ans/RAND_MAX>RAND_MAX) + break; + } + if (ans0){ + // convert everything to integers + vector< T_unsigned > p1,p2,quot,remain; + vector vars(th.dim); + vars[th.dim-1]=1; + for (int i=th.dim-2;i>=0;--i){ + vars[i]=d[i+1]*vars[i+1]; + } + if (debug_infolevel>1) + CERR << "divrem convert " << CLOCK() << '\n'; + if (convert(th,d,p1,modulo.val) && convert(other,d,p2,modulo.val)){ + if (debug_infolevel>1) + CERR << "hashdivrem begin " << CLOCK() << '\n'; + if (hashdivrem(p1,p2,quot,remain,vars,modulo.val,0.0,false)==1){ + if (debug_infolevel>1) + CERR << "hashdivrem end " << CLOCK() << '\n'; + convert(quot,d,quo); + convert(remain,d,r); + return true; + } + else + return false; + } + } // end modulo.type==_INT + } // end ans < RAND_MAX + if (ans/RAND_MAX0){ + // convert everything to integers + vector< T_unsigned > p1,p2,quot,remain; + vector vars(th.dim); + vars[th.dim-1]=1; + for (int i=th.dim-2;i>=0;--i){ + vars[i]=d[i+1]*vars[i+1]; + } + if (convert(th,d,p1,modulo.val) && convert(other,d,p2,modulo.val)){ + if (hashdivrem(p1,p2,quot,remain,vars,modulo.val,0.0,false)==1){ + convert(quot,d,quo); + convert(remain,d,r); + return true; + } + else + return false; + } + } // end modulo.type==_INT + } // end ans/RAND_MAX < RAND_MAX + } // end if ddeg>2 && os>10 +#endif //NO_TEMPLATE_MULTGCD + tensor b0(Tnextcoeff(it,other.coord.end())); + r=th; + tensor q(b0.dim),q_other(th.dim); + while ( (rdeg=r.lexsorted_degree()) >=bdeg){ + it=r.coord.begin(); + tensor a0(Tnextcoeff(it,r.coord.end())),tmp(a0.dim); + if (!divremmod(a0,b0,modulo,q,tmp) || !tmp.coord.empty()) + return false; + q=q.untrunc1(rdeg-bdeg); + quo=quo+q; + mulpoly(q,other,q_other,modulo); + r=smod(r-q_other,modulo); + if (r.coord.empty()) + return true; + } + return true; + } + + + polynome pow(const polynome & p,const gen & n){ + polynome res(p.dim); + if (!n.is_integer()){ +#ifdef NO_STDEXCEPT + res.coord.push_back(monomial(gensizeerr(gettext("gausspol.cc/pow")),p.dim)); + return res; +#else + setsizeerr(gettext("gausspol.cc/pow")); +#endif + } + int i=n.to_int(); + if (!powpoly(p,i,res)){ +#ifdef NO_STDEXCEPT + res.coord.clear(); + res.coord.push_back(monomial(gensizeerr(gettext("gausspol.cc/pow")),p.dim)); +#else + setsizeerr(gettext("gausspol.cc/pow")); +#endif + } + return res; + } + + polynome pow(const polynome & p, int n){ + polynome res(p.dim); + powpoly(p,n,res); + return res; + } + + static polynome powmod1(const polynome &p,int n,const gen & modulo){ + switch (n) { + case 0: + return polynome(gen(1),p.dim); + case 1: + return p; + default: + polynome temp(powmod(p,n/2,modulo)); + if (n%2) + return (temp * temp * p) % modulo; + else + return (temp*temp) % modulo; + } + } + + polynome powmod(const polynome &p,int n,const gen & modulo){ + if (p.dim<2) + return powmod1(p,n,modulo); + polynome res(gen(1),p.dim); + for (int i=0;i >::iterator it=P.coord.begin(),itend=P.coord.end(); + for (;it!=itend;++it) + it->value=exact(it->value,context0); + } + + void evalf_inplace(polynome & P){ + vector< monomial >::iterator it=P.coord.begin(),itend=P.coord.end(); + for (;it!=itend;++it) + it->value=evalf(it->value,1,context0); + } + + // Ducos: optimizations of the subresultant algorithm + + // n=d-1-e, d=degree(Sd), e=degree(Sd1), Se=(lc(Sd1)^n*Sd1)/lc(Sd)^n + void ducos_e(const polynome & Sd,const polynome & sd,const polynome & Sd1,polynome & Se){ + int n=Sd.lexsorted_degree()-Sd1.lexsorted_degree()-1; + if (!n){ + Se=Sd1; + return; + } + if (n==1){ + Se=(Tfirstcoeff(Sd1)*Sd1)/sd; + return; + } + // n>=2 + polynome sd1(Tfirstcoeff(Sd1)),s((sd1*sd1)/sd); + for (int j=2;j1) + CERR << CLOCK()*1e-6 << "cducos_e1 begin d=" << d << '\n'; + polynome cd1(Tfirstcoeff(Sd1)),se(Tfirstcoeff(Se)); + index_t sh(dim); +#if 0 + vector Hv; + for (int j=0;j Hv(e); + Hv.reserve(d); +#endif + sh[0]=e; + Hv.push_back(se.shift(sh)-Se); + for (int j=e+1;j=0) + piXHj1=XHj1.Tcoeffs() [XHj1.lexsorted_degree()-e].untrunc1(); + XHj1=XHj1-(piXHj1*Sd1)/cd1; + Hv.push_back(XHj1); + } + polynome D(A.dim),DA(A.dim); // sum_{j Av(A.Tcoeffs()); +#else + vector Av; A.Tcoeffs(Av); +#endif + // split next loop in 2 parts, because Hv indexes lower than e are straightforward + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " ducos_e1 D begin" << '\n'; + for (int j=e-1;j>=0;--j){ + sh[0]=j; +#if 0 + D.append((Av[Av.size()-1-j]*se.trunc1()).untrunc1().shift(sh)); +#else + D.append(Av[Av.size()-1-j].untrunc1()*se.shift(sh)); +#endif + } + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " ducos_e1 D j=e " << e << "<" << d << '\n'; + for (int j=e;j1) + CERR << CLOCK()*1e-6 << " ducos_e1 D end, start division" << '\n'; +#if 1 + D = D/Av.front().untrunc1(); +#else + if (!is_one(Av.front())){ + polynome quo(dim),rem(dim); + divrem1(D,Av.front().untrunc1(),quo,rem,3,false); + D.coord.swap(quo.coord); + } +#endif + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " ducos_e1 D ready" << '\n'; + polynome Hd1(Hv.back()); + sh[0]=1; + Hd1=Hd1.shift(sh); // X*Hd1 +#if 1 + res=(cd1*(Hd1+D)-(Hd1.coeff(e).untrunc1()*Sd1)); +#else + res=(cd1*(Hd1+D)-(Hd1.Tcoeffs()[Hd1.lexsorted_degree()-1-e]).untrunc1()*Sd1); +#endif + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " ducos_e1 D final division" << '\n'; +#if 1 + res=res/sd; +#else + if (!is_one(sd)){ + polynome quo(dim),rem(dim); + divrem1(res,sd,quo,rem,3,false); + res.coord.swap(quo.coord); + } +#endif + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " ducos_e1 end" << '\n'; + if ( (d-e+1)%2) + res=-res; + } + + void subresultant(const polynome & P,const polynome & Q,polynome & C,bool ducos){ + int dim=P.dim; + if (dim==1){ + gen c; + vecteur p,q; + polynome2poly1(P,1,p); + polynome2poly1(Q,1,q); + subresultant(p,q,c); + C=polynome(monomial(c,1)); + return; + } + int a=P.partial_degree(2); + int b=Q.partial_degree(2); + int m=P.lexsorted_degree(); + int n=Q.lexsorted_degree(); + // first estimate n*(a-m)+m*b + int d1=n*(a-m)+m*b; + gen coeffP; + if (!ducos && !interpolable_resultant(P,d1,coeffP,false,context0)) ducos=true; + if (!ducos && !interpolable_resultant(Q,d1,coeffP,false,context0)) ducos=true; + //gen Pg=a*gen(m)*comb(m+dim-2,dim-2); + //gen Qg=b*gen(n)*comb(n+dim-2,dim-2); + if (//1 || + !ducos && giacmin(m,n)>2 && dim<4 && P.coord.size()>=m && Q.coord.size() >= n + // && Pg.type==_INT_ && P.coord.size()>=Pg.val/2 && Qg.type==_INT_ && Q.coord.size()>=Qg.val/2 + ){ + double iclock=CLOCK()*1e-6; + // for dense inputs, interpolate + polynome pp0(P); + pp0.reorder(transposition(0,1,dim)); + polynome qp0(Q); + qp0.reorder(transposition(0,1,dim)); + // second estimate + a=pp0.lexsorted_degree(); + b=qp0.lexsorted_degree(); + // a*n+b*m + int d2=a*n+b*m; + int d=giacmin(d1,d2); + // interpolation + vecteur vp,vq,vp0,vq0,X(d+1),Y(d+1); + polynome2poly1(pp0,1,vp); + pp0=firstcoeff(P).trunc1(); + polynome2poly1(pp0,1,vp0); + polynome2poly1(qp0,1,vq); + qp0=firstcoeff(Q).trunc1(); + polynome2poly1(qp0,1,vq0); + int j=-d/2; + if (coeffP.type==_USER) + j=0; + for (int i=0;i<=d;++i,++j){ + if (!debug_infolevel){ + double cclock=CLOCK()*1e-6; + if (cclock-iclock>15) + debug_infolevel=1; + } + if (debug_infolevel && (i%16==0)) + CERR << CLOCK()*1e-6 << " interp horner, loop index " << i << '\n'; + gen xi; + for (;;++j){ + // find evaluation preserving degree in x + if (0 && j==0) + CERR << "j" << '\n'; + xi=interpolate_xi(j,coeffP); + gen hp=horner(vp0,xi); + gen hq=horner(vq0,xi); + if (!is_zero(hp) && !is_zero(hq)) + break; + } + X[i]=xi; + gen gp=horner(vp,xi); + gen gq=horner(vq,xi); + if (debug_infolevel && (i%16==0)) + CERR << CLOCK()*1e-6 << " interp resultant evaled at " << j << ", " << 100*double(i)/(d+1) << "% done" << '\n'; + if (gp.type==_POLY && gq.type==_POLY){ + Y[i]=resultant(*gp._POLYptr,*gq._POLYptr); + continue; + } + if (gp.type==_POLY){ + Y[i]=pow(gq,gp._POLYptr->lexsorted_degree(),context0); + continue; + } + if (gq.type==_POLY){ + Y[i]=pow(gp,gq._POLYptr->lexsorted_degree(),context0); + continue; + } + Y[i]=1; + } + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " interp dd " << '\n'; + vecteur R=divided_differences(X,Y); + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " interp build " << '\n'; + modpoly resp(1,R[d]),tmp; // cst in y + for (int i=d-1;i>=0;--i){ + operator_times(resp,makevecteur(1,-X[i]),0,tmp); + if (tmp.empty()) + tmp=vecteur(1,R[i]); + else + tmp.back() += R[i]; + tmp.swap(resp); + } + poly12polynome(resp,2,C,dim); + return; + } + int d=P.lexsorted_degree(),e=Q.lexsorted_degree(); + if (d1){ + polynome sd(Tfirstcoeff(A)); + if (step==0) + sd=pow(sd,P.lexsorted_degree()-Q.lexsorted_degree()); + ducos_e(A,sd,B,C); + } + else + C=B; + if (e==0){ + // adjust sign: already done by doing pseudodivrem(-Q,...) + //if ((P.lexsorted_degree()*Q.lexsorted_degree())%2) C=-C; + return; + } + ducos_e1(A,B,C,sd,B); + A.coord.swap(C.coord); // A=C; + sd=Tfirstcoeff(A); + } + } + + void subresultant(const polynome & P,const polynome & Q,gen & c,polynome & C,bool ducos){ + polynome p(P),q(Q); + gen pz=ppz(p),qz=ppz(q); + gen coefft,coeffqt; + int pt=coefftype(p,coefft),qt=coefftype(q,coeffqt); + polynome g; + c=pow(pz,q.lexsorted_degree())*pow(qz,p.lexsorted_degree()); + if (pt==0 && qt==0){ + if (P.dim==1 && p.lexsorted_degree()>MODRESULTANT && q.lexsorted_degree()>MODRESULTANT){ + gen r=mod_resultant(polynome2poly1(p,1),polynome2poly1(q,1),0.0); + c=c*r; + if (is_zero(r)) + C.coord.clear(); + else + poly12polynome(vecteur(1,1),1,C); + return; + } + // try gcd only if it is fast (integer coefficients for example) + g=gcd(p,q); + if (g.lexsorted_degree()){ + C.coord.clear(); + return; + } + } + else { + g=Tlgcd(p); + Tlgcd(q,g); + } + if (!is_one(g)){ + p=p/g; + q=q/g; + } + subresultant(p,q,C,ducos); + if (!is_one(g)){ + int expo=p.lexsorted_degree()+q.lexsorted_degree(); + for (int i=0;iuntrunc1(); + else + res=polynome(monomial(determinant,p.dim)); + return true; + } + + polynome resultant(const polynome & p,const polynome & q){ + // polynomial subresultant does not work if p and q have approx coeff + if (p.coord.empty()) + return p; + if (q.coord.empty()) + return q; + bool approx=has_num_coeff(p) || has_num_coeff(q); + if (p.dim==1){ + if (approx + // || (p.lexsorted_degree()>=GIAC_PADIC/2 && q.lexsorted_degree()>=GIAC_PADIC/2) + ){ + matrice S; polynome res(p.dim); + if (resultant_sylvester(p,q,S,res)) + return res; + } + } + if (approx){ + polynome P(p),Q(q); + exact_inplace(P); exact_inplace(Q); + polynome res=Tresultant(P,Q); + evalf_inplace(res); + return res; + } + double pq=double(p.coord.size())*q.coord.size(); + unsigned dim=p.dim; +#if 0 // def HAVE_LIBPARI // : PARI is faster but has problems with some large inputs + // we must keep the same variable ordering than in PARI + if (dim>=2 && dim<=4 && pq>256 && p.coord.size()>4 && q.coord.size()>4){ + gen coefft,coeffqt; + int pt=coefftype(p,coefft),qt=coefftype(q,coeffqt); + if (pt==0 && qt==0){ + // PARI call + vecteur lv; + if (dim==2) lv=makevecteur(x__IDNT_e,y__IDNT_e); + if (dim==3) lv=makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e); + if (dim==4) lv=makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e,t__IDNT_e); + gen P=r2sym(p,lv,context0),Q=r2sym(q,lv,context0),res; + if (pari_polresultant(P,Q,lv,res,context0)){ + res=sym2r(res,lv,context0); + if (res.type==_POLY){ +#if 0 + polynome res1; subresultant(p,q,res1,true); + if (res!=res1){ + cerr << res._POLYptr->coord.size() << '\n'; + return res1; + } +#endif + return *res._POLYptr; + } + } + } + } +#endif // HAVE_LIBPARI + polynome R(p.dim); gen r; + subresultant(p,q,r,R,false); + return r*R; +#if 0 + polynome R1(Tresultant(p,q)); + // COUT << R << "," << R1 << '\n'; + if (R!=R1) + COUT << "error " << '\n'; + return R1; +#endif + } + + polynome lgcd(const polynome & p){ + return Tlgcd(p); + } + + gen ppz(polynome & p,bool divide){ +#ifdef USE_GMP_REPLACEMENTS + return Tppz(p,divide); +#else + vector< monomial >::iterator it=p.coord.begin(),itend=p.coord.end(); + if (it==itend) + return 1; + gen res=(itend-1)->value; + for (it=p.coord.begin();it!=itend-1;++it){ + res=gcd(res,it->value,context0); + if (is_one(res)) + return 1; + } + if (!divide) + return res; + if (res.type==_INT_ && res.val>0){ + for (it=p.coord.begin();it!=itend;++it){ + if (it->value.type!=_ZINT || it->value.ref_count()>1) + it->value=it->value/res; + else + mpz_divexact_ui(*it->value._ZINTptr,*it->value._ZINTptr,res.val); + } + return res; + } + if (res.type==_ZINT){ + for (it=p.coord.begin();it!=itend;++it){ + if (it->value.type!=_ZINT || it->value.ref_count()>1) + it->value=it->value/res; + else + mpz_divexact(*it->value._ZINTptr,*it->value._ZINTptr,*res._ZINTptr); + } + return res; + } + for (it=p.coord.begin();it!=itend;++it){ + it->value=it->value/res; + } + return res; +#endif + } + + // Find the content of p with respect to the 1st variable + // p=p(x1,...,xn)=poly in x1 with coeff depending on x2,..,xn + // content wrt x1 depends on x2,...,xn + void lgcdmod(const polynome & p,const gen & modulo,polynome & pgcd){ + if (!p.dim){ + pgcd=p; + return ; + } + pgcd=pgcd.trunc1(); + vector< monomial >::const_iterator it=p.coord.begin(); + vector< monomial >::const_iterator itend=p.coord.end(); + // vector< monomial >::const_iterator itbegin=it; + for (;it!=itend;){ + if (is_one(pgcd)) + break; + pgcd=gcdmod(pgcd,Tnextcoeff(it,itend),modulo); + } + if (pgcd.coord.empty()){ + index_m i; + for (int j=0;j(gen(1),i)); + } + else + pgcd=pgcd.untrunc1(); + } + + // Split a multivariate poly X_1...X_n as multivar X_dim+1...X_n + // with coeff multivar poly of X_1..X_dim + polynome split(const polynome & p,int inner_dim){ + int outer_dim=p.dim-inner_dim; + polynome cur_inner(inner_dim); + polynome res(outer_dim); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (; it!=itend;++it){ + index_t outer_index(it->index.begin()+inner_dim,it->index.end()); + index_t inner_index(it->index.begin(),it->index.begin()+inner_dim); + cur_inner=polynome(monomial(it->value,inner_index)); + res=res+polynome(monomial(cur_inner,outer_index)); + } + return res; + } + + /* +#ifdef HASH_MAP_NAMESPACE + class hash_function_index_t { + public: + inline size_t operator () (const index_t & a) const { + size_t r=0; + index_t::const_iterator ita=a.begin(),itaend=a.end(); + for (;ita!=itaend;++ita){ + r <<= 4; + r += (*ita) & 0xf; + } + return r; + } + hash_function_index_t() {}; + }; + + typedef HASH_MAP_NAMESPACE::hash_map map_index_t_polynome; +#else + typedef std::map map_index_t_polynome; +#endif + */ + + typedef std::map map_index_t_polynome; + + // return true if content=1 is detected + static bool split(const polynome & p,int inner_dim,map_index_t_polynome & res){ + // int outer_dim=p.dim-inner_dim; + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (; it!=itend;++it){ + index_t cur_index= it->index.iref(); + index_t outer_index(it->index.begin()+inner_dim,it->index.end()); + index_t inner_index(it->index.begin(),it->index.begin()+inner_dim); + map_index_t_polynome::iterator jt=res.find(outer_index),jtend=res.end(); + if (jt==jtend){ + if (is_zero(inner_index)) + return true; + res[outer_index]=polynome(monomial(it->value,inner_index)); + } + else + jt->second.coord.push_back(monomial(it->value,inner_index)); + } + return false; + } + + gen lcoeffn(const polynome & p){ + int dim=p.dim; + polynome res(dim); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + if (it==itend) + return 0; + index_t i= it->index.iref(); + for (;it!=itend;++it){ + const index_t & j= it->index.iref(); + i[dim-1]=j[dim-1]; + if (i!=j) + break; + res.coord.push_back(*it); + } + return res; + } + + gen lcoeff1(const polynome & p){ + if (p.coord.empty()) + return zero; + int inner_dim=1; + // int outer_dim=p.dim-inner_dim; + polynome cur_inner(inner_dim); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + index_t::const_iterator jt0 = it->index.begin(),jtend=it->index.end(),jt,kt0,kt; + for (; it!=itend;++it){ + kt0 = it->index.begin(); + for (jt=jt0+inner_dim,kt=kt0+inner_dim;jt!=jtend;++kt,++jt){ + if (*kt<*jt) + break; + if (*kt>*jt){ + jt0=kt0; + jtend=kt0+p.dim; + cur_inner.coord.clear(); + jt=jtend; + break; + } + } + if (jt==jtend) + cur_inner.coord.push_back(monomial(it->value,index_t(kt0,kt0+inner_dim))); + } + return cur_inner; + } + + polynome content1mod(const polynome & p,const gen & modulo,bool setdim){ + if (p.coord.empty()){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("content1mod")); +#endif + return polynome(monomial(1,p.dim)); + } + if (p.coord.size()==1){ + int n=p.coord.front().index.front(); + polynome c(monomial(p.coord.front().value,index_t(1,n))); + if (setdim) + change_dim(c,p.dim); + return c; + } + // New code + map_index_t_polynome m; + polynome c(1); + if (!split(p,1,m)){ + int c0=RAND_MAX,i0; + map_index_t_polynome::iterator it=m.begin(),itend=m.end(); + if (m.size()==1) + c=it->second; + else { + for (;c0 && it!=itend;++it){ + if (!it->second.coord.empty() && (i0=it->second.coord.front().index.front())second; + c0=i0; + } + } + it=m.begin(); + for (;it!=itend;++it){ + if (!c.coord.empty() &&c.coord.front().index.front()==0 ){ + c=polynome(plus_one,1); + break; + } + c=gcdmod(c,it->second,modulo); + } + /* Old code + polynome lp(split(p,1)),c(1); + vector< monomial >::const_iterator it=lp.coord.begin(),itend=lp.coord.end(); + for (;it!=itend;++it){ + if (it->value.type==_POLY) + c=gcdmod(c,*it->value._POLYptr,modulo); + else { + c=polynome(plus_one,1); // was c=polynome(plus_one,p.dim-1); + break; + } + } + */ + } // end if itend==it+1 + } // end if (!split()) : i.e. if the content is not trivially 1 + else + c=polynome(plus_one,1); + if (setdim) + change_dim(c,p.dim); + return c; + } + + polynome pp1mod(const polynome & p,const gen & modulo){ + polynome q(p.dim),r(p.dim); + polynome tmp(content1mod(p,modulo)); + // CERR << "pp1mod " << tmp << '\n'; + divremmod(p,tmp,modulo,q,r); + return q; + } + + // Find non zeros coeffs of p + int find_nonzero(const polynome & p,index_t & res){ + res.clear(); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + if (it==itend) + return 0; + int old_deg=it->index.front(),cur_deg=0; + int nzeros=0; + res.push_back(1); + for (;it!=itend;++it){ + cur_deg=it->index.front(); + if (cur_deg!=old_deg){ + nzeros += old_deg - cur_deg -1 ; + for (int i=old_deg-cur_deg;i>1;--i) + res.push_back(0); + res.push_back(1); + old_deg=cur_deg; + } + } + if (cur_deg){ + nzeros += cur_deg; + for (int i=cur_deg;i>0;--i) + res.push_back(0); + } + return nzeros; + } + + static bool degree2unsigned(index_t & deg,unsigned & u){ + u=1; + index_t::iterator it=deg.begin(),itend=deg.end(); + for (;it!=itend;++it){ + ++(*it); + u = u*unsigned(*it); + if (u>RAND_MAX) + return false; + } + return true; + } + + vecteur vranmnot0(int dim){ + for (;;){ + vecteur r=vranm(dim,0,0); + if (!is_zero(r)) + return r; + } + } + + // p_orig and q_orig are primitive with respect to the main variable + // p(x1,...,xn) q(x1,...,xn) viewed as p(x1) and q(x1) + // d must be the same + static void mod_gcdmod(const polynome &p_orig, const polynome & q_orig, const gen & modulo, polynome & d,int gcddeg=0){ + if (p_orig.coord.empty() || is_one(q_orig)){ + d=q_orig; + return; + } + if (q_orig.coord.empty() || is_one(p_orig)){ + d=p_orig; + return; + } + if (debug_infolevel) + CERR << "gcdmod content dim " << d.dim << " " << CLOCK() << '\n'; + polynome p(p_orig.dim),q(q_orig.dim),r; + vector pint,qint; + index_t pintd=p_orig.degree(),qintd=q_orig.degree(); + unsigned pu,qu; + // Make p and q primitive with respect to x2,...,xn + // i.e. the coeff of p and q which are polynomials in x1 + // are relative prime + // r is the gcd of the content in this sense + bool docontent1mod=true; + // bug there, if false is removed lwN and lwN1 do not work + if (false && + modulo.type==_INT_ && degree2unsigned(pintd,pu) && degree2unsigned(qintd,qu)){ + convert(p_orig,pintd,pint,modulo.val); + convert(q_orig,qintd,qint,modulo.val); + if (is_content_trivially_1(pint,pu/pintd.front()) && is_content_trivially_1(qint,qu/qintd.front())) + docontent1mod=false; + } + if (docontent1mod) { + polynome pc(content1mod(p_orig,modulo)),qc(content1mod(q_orig,modulo)); + divremmod(p_orig,pc,modulo,p,r); + divremmod(q_orig,qc,modulo,q,r); + // CERR << "content end " << CLOCK() << '\n'; + change_dim(pc,1); change_dim(qc,1); + r=gcdmod(pc,qc,modulo); + change_dim(r,p.dim); + } + else { + p=p_orig; + q=q_orig; + r=polynome(plus_one,p.dim); + } + // Find degree of gcd with respect to x1, more precisely gcddeg>=degree/x1 + // and compute data for the sparse modular algorithm + index_t vzero; // coeff of vzero correspond to zero or non zero + int nzero=1; // Number of zero coeffs + vecteur alphav,gcdv; // Corresponding values of alpha and gcd at alpha + if (!gcddeg){ + vecteur b(p.dim-1); + for (int essai=0;essai<2;++essai){ + if (essai) + b=vranmnot0(p.dim-1); // find another random point + polynome Fb(1),Gb(1); + // Fb and Gb are p and q where x2,...,xn are evaluated at b + if (!find_good_eval(p,q,Fb,Gb,b,(debug_infolevel>=2),modulo)) + break; + polynome Db(gcdmod(Fb,Gb,modulo)); // 1-d gcd wrt x1 + int Dbdeg=Db.lexsorted_degree(); + if (!Dbdeg){ + gcddeg=0; + break; + } + if (!gcddeg){ // 1st gcd test + gcddeg=Dbdeg; + nzero=find_nonzero(Db,vzero); + } + else { // 2nd try + if (Dbdeggcddeg) // 2nd try unlucky, restart 2nd try + --essai; + else { // Same gcd degree for 1st and 2nd try, keep this degree + index_t tmp; + nzero=find_nonzero(Db,tmp); + if (nzero){ + vzero = vzero | tmp; + // Recompute nzero, it is the number of 0 coeff of vzero + index_t::const_iterator it=vzero.begin(),itend=vzero.end(); + for (nzero=0;it!=itend;++it){ + if (!*it) ++nzero; + } + } + } + } + } + } + } + else { + gcddeg -= r.lexsorted_degree() ; + nzero = 0; // No info available + } + if (!gcddeg){ + d=r; + return; + } + d=polynome(p.dim); + polynome interp(plus_one,p.dim); + // gcd of leading coefficients of p and q viewed as poly in X_2...X_n + // with coeff in Z[X_1] + if (debug_infolevel) + CERR << "gcdmod lcoeff1 dim " << d.dim << " " << CLOCK() << '\n'; + gen lp(lcoeff1(p)),lq(lcoeff1(q)); + polynome Delta(plus_one,p.dim); + if ((lp.type==_POLY) && (lq.type==_POLY) ) + Delta=gcdmod(*lp._POLYptr,*lq._POLYptr,modulo); + // we are now interpolating G=gcd(p,q)*a poly/x1 + // such that the leading coeff of G is Delta + index_t pdeg(p.degree()),qdeg(q.degree()); + int spdeg=0,sqdeg=0; + for (int i=1;i1) + CERR << "gcdmod find alpha dim " << d.dim << " " << CLOCK() << '\n'; + for (;;++alpha){ + vecteur valpha; + polynome palpha(p.dim-1),qalpha(q.dim-1); + for (;alpha1) + CERR << "gcdmod eval " << alpha << " dim " << d.dim << " " << CLOCK() << '\n'; + if (alpha==modulo){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Modgcd: no suitable evaluation point")); +#endif + return ; + } + polynome g(gcdmod(palpha,qalpha,modulo)); + index_t gdeg(g.degree()); + // int gcd_plus_delta_deg=gcddeg+Delta.lexsorted_degree(); + if (gdeg==delta){ + // Try spmod first + if (nzero){ + // Add alpha,g + alphav.push_back(alpha); + gcdv.push_back(g); + if (gcddeg-nzero==e){ + // We have enough evaluations, let's try SPMOD + // Build the matrix, each line has coeffs / vzero + matrice m; + for (int j=0;j<=e;++j){ + index_t::reverse_iterator it=vzero.rbegin(),itend=vzero.rend(); + vecteur line; + for (gen p=alphav[j],pp=plus_one;it!=itend;++it,pp=smod(p*pp,modulo)){ + if (*it) + line.push_back( pp); + } + reverse(line.begin(),line.end()); + line.push_back(gcdv[j]); + m.push_back(line); + } + // Reduce linear system modulo modulo + gen det; vecteur pivots; matrice mred; + // CERR << "SPMOD " << CLOCK() << '\n'; + modrref(m,mred,pivots,det,0,int(m.size()),0,int(m.front()._VECTptr->size())-1,true,false,modulo,false,0); + // CERR << "SPMODend " << CLOCK() << '\n'; + if (!is_zero(det)){ + // Last column is the solution, it should be polynomials + // that must be untrunced with index = to non-0 coeff of vzero + polynome trygcd(p.dim); + index_t::const_iterator it=vzero.begin(),itend=vzero.end(); + int deg=int(itend-it)-1; + for (int pos=0;it!=itend;++it,--deg){ + if (!*it) + continue; + gen tmp=mred[pos][e+1]; // e+1=#of points -> last col + if (tmp.type==_POLY) + trygcd=trygcd+tmp._POLYptr->untrunc1(deg); + else + if (!is_zero(tmp)) + trygcd=trygcd+polynome(monomial(tmp,deg,1,p.dim)); + ++pos; + } + // Check if trygcd is the gcd! + polynome pD(pp1mod(trygcd,modulo)),Q(p.dim),R(d.dim); + divremmod(p,pD,modulo,Q,R); + if (R.coord.empty()){ + divremmod(q,pD,modulo,Q,R); + if (R.coord.empty()){ + pD=pD*r; + d=smod(pD*invmod(pD.coord.front().value,modulo),modulo); + return; + } + } + } + // SPMOD not successful :-( + nzero=0; + } // end if gcddeg-nzero==e + } // end if (nzero) + if (debug_infolevel>1) + CERR << "gcdmod interp dim " << d.dim << " " << CLOCK() << '\n'; + polynome g1=(g*smod(peval(Delta,valpha,modulo),modulo))*invmod(g.coord.front().value,modulo); + gen tmp(g1-peval(d,valpha,modulo)); + if (tmp.type==_POLY){ + g1=smod(*tmp._POLYptr,modulo); + g1=g1.untrunc1(); + } + else + g1=polynome(tmp,p.dim); + d=d+g1*interp*invmod(peval(interp,valpha,modulo),modulo); + d=smod(d,modulo); + interp=interp*(polynome(monomial(plus_one,1,1,p.dim))-polynome(gen(alpha),p.dim)); + ++e; + if (e>gcddeg + || is_zero(tmp) + ){ + if (debug_infolevel) + CERR << "gcdmod pp1mod dim " << d.dim << " " << CLOCK() << '\n'; + polynome pD(pp1mod(d,modulo)),Q(p.dim),R(d.dim); + // This removes the polynomial in x1 that we multiplied by + // (it was necessary to know the lcoeff of the interpolated poly) + if (debug_infolevel) + CERR << "gcdmod check dim " << d.dim << " " << CLOCK() << '\n'; + // Now, gcd divides pD for gcddeg+1 values of x1 + // degree(pD)<=degree(gcd) + divremmod(p,pD,modulo,Q,R); + if (debug_infolevel){ + CERR << "test * " << CLOCK() << '\n'; + polynome R2; + mulpoly(pD,Q,R2,modulo); + CERR << "test * end " << CLOCK() << '\n'; + } + if (R.coord.empty()){ + divremmod(q,pD,modulo,Q,R); + // If pD divides both P and Q, then the degree wrt variables + // x2,...,xn is the right one (because it is <= since pD + // divides the gcd and >= since pD(x1=one of the try) was a gcd + // The degree in x is the right one because of the condition + // on the lcoeff + // Note that the division test might be much longer than the + // interpolation itself (e.g. if the degree of the gcd is small) + // but it seems unavoidable, for example if + // P=Y-X+X(X-1)(X-2)(X-3) + // Q=Y-X+X(X-1)(X-2)(X-4) + // then gcd(P,Q)=1, but if we take Y=0, Y=1 or Y=2 + // we get gcddeg=1 (probably degree 1 for the gcd) + // interpolation at X=0 and X=1 will lead to Y-X as candidate gcd + // and even adding X=2 will not change it + // We might remove division if we compute the cofactors of P and Q + // if P=pD*cofactor is true for degree(P) values of x1 + // and same for Q, and the degrees wrt x1 of pD and cofactors + // have sum equal to degree of P or Q then pD is the gcd + if (R.coord.empty()){ + pD=pD*r; + d=smod(pD*invmod(pD.coord.front().value,modulo),modulo); + if (debug_infolevel) + CERR << "gcdmod found dim " << d.dim << " " << CLOCK() << '\n'; + return; + } + } + if (debug_infolevel) + CERR << "Gcdmod bad guess " << '\n'; + continue; + } + else + continue; + } + if (gdeg[0]>delta[0]) // branch if all degree are >= + continue; + if (delta[0]>=gdeg[0]){ // restart with g + gcdv=vecteur(1,g); + alphav=vecteur(1,alpha); + delta=gdeg; + g=(g*smod(peval(Delta,valpha,modulo),modulo))*invmod(g.coord.front().value,modulo); + d=g.untrunc1(); + e=1; + interp=polynome(monomial(plus_one,1,1,p.dim))-polynome(gen(alpha),p.dim); + continue; + } + } + } + + void psrgcdmod(polynome & a,polynome & b,const gen & modulo,polynome & prim){ + // set auxiliary polynomials g and h to 1 + polynome g(gen(1),a.dim); + polynome h(g),quo(g),r(g); + while (!a.coord.empty()){ + int n=b.lexsorted_degree(); + int m=a.lexsorted_degree(); + if (!n) {// if b is constant (then b!=0), gcd=original lgcdmod + prim=polynome(gen(1),a.dim); + return ; + } + int ddeg=m-n; + if (ddeg<0) + swap(a,b); // exchange a<->b may occur only at the beginning + else { + polynome b0(firstcoeff(b)); + divremmod(a*pow(b0,ddeg+1),b,modulo,quo,r); // division works always + if (r.coord.empty()) + break; + // remainder is non 0, loop continue: a <- b + a=b; + polynome temp(powmod(h,ddeg,modulo)); + // now divides r by g*h^(m-n), result is the new b + divremmod(r,g*temp,modulo,b,quo); // quo is the remainder here, not used + // new g=b0 and new h=b0^(m-n)*h/temp + if (ddeg==1) // the normal case, remainder deg. decreases by 1 each time + h=b0; + else // not sure if it's better to keep temp or divide by h^(m-n+1) + divremmod(pow(b0,ddeg)*h,temp,modulo,h,quo); + g=b0; + } + } + // COUT << "Prim" << b << '\n'; + quo.coord.clear(); + lgcdmod(b,modulo,quo); + divremmod(b,quo,modulo,prim,r); + prim=smod(prim*invmod(prim.coord.front().value,modulo),modulo); + } + + void contentgcdmod(const polynome &p, const polynome & q, const gen & modulo, polynome & cont,polynome & prim){ + if (p.coord.empty()){ + cont.coord.clear(); + lgcdmod(q,modulo,cont); + polynome temp(cont.dim); + divremmod(q,cont,modulo,prim,temp); + return ; + } + if (q.coord.empty()){ + contentgcdmod(q,p,modulo,cont,prim); + return; + } + if (p.dim!=q.dim){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("gausspol.cc/contentgcdmod")); +#endif + return ; + } + // dp and dq are the "content" of p and q w.r.t. other variables + polynome dp(p.dim), dq(p.dim); + // CERR << p.dim << " " << CLOCK() << '\n'; + lgcdmod(p,modulo,dp); + lgcdmod(q,modulo,dq); + // CERR << "End " << p.dim << " " << CLOCK() << '\n'; + cont=gcdmod(dp.trunc1(),dq.trunc1(),modulo).untrunc1(); + if (!p.dim){ + prim=polynome(gen(1),0); + return ; + } + // COUT << "Cont" << cont << '\n'; + polynome a(p.dim),b(p.dim),quo(p.dim),r(p.dim); + // a and b are the primitive part of p and q + divremmod(p,dp,modulo,a,r); + divremmod(q,dq,modulo,b,r); + if (modulo.val>=4*giacmin(p.lexsorted_degree(),q.lexsorted_degree())){ + mod_gcdmod(a,b,modulo,prim); + return ; + } + psrgcdmod(a,b,modulo,prim); + } + + bool gcdmod_dim1(const polynome &p,const polynome & q,const gen & modulo,polynome & d,polynome & pcof,polynome & qcof,bool compute_cof,bool & real){ + real= poly_is_real(p) && poly_is_real(q); + if (p.dim!=1) + return false; + if (q.dim!=1) + return false; + d.dim=pcof.dim=qcof.dim=1; + if (real && modulo.type==_INT_ && gcdsmallmodpoly(p,q,modulo.val,d,pcof,qcof,compute_cof)){ + return true; + } + modpoly P(polynome2poly1(p,1)); + modpoly Q(polynome2poly1(q,1)); + environment envi; + environment * env=&envi; + env->modulo=modulo; + env->pn=env->modulo; + env->moduloon=true; + env->complexe=true; + modpoly R,PQ,PR; + gcdmodpoly(P,Q,env,R); + if (is_undef(R)) + return false; + d=poly12polynome(R); + if (compute_cof){ + DivRem(P,R,env,PQ,PR); + pcof=poly12polynome(PQ); + DivRem(Q,R,env,PQ,PR); + qcof=poly12polynome(PQ); + } + return true; + } + + polynome gcdmod(const polynome &p,const polynome & q,const gen & modulo){ +#ifndef NO_STDEXCEPT + if (p.dim!=q.dim) + setsizeerr(gettext("Bug!")); +#endif + if (p==q) + return p; + if (p.coord.empty()) + return q; + if (q.coord.empty()) + return p; + if (p.dim==1){ + polynome d(1),pd(1),qd(1); + bool estreel; + gcdmod_dim1(p,q,modulo,d,pd,qd,false,estreel); + return d; + } + // Check that there are enough points for interpolation + // Otherwise PSR + if (modulo.val>=4*giacmin(p.lexsorted_degree(),q.lexsorted_degree())){ + polynome d(p.dim),pcof(p.dim),qcof(p.dim); + if (modgcd(p,q,modulo,d,pcof,qcof,false)) + return d; +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted){ + ctrl_c=false; interrupted=true; + d.coord.push_back(monomial(gensizeerr(gettext("Stopped by user interruption.")),d.dim)); + return d; + } + } + polynome a(smod(p*invmod(p.coord.front().value,modulo),modulo)); + polynome b(smod(q*invmod(q.coord.front().value,modulo),modulo)); + // Use evaluation points if enough available or modular psrh + polynome prim(p.dim),cont(p.dim); + contentgcdmod(a,b,modulo,prim,cont); + if (debug_infolevel>10) + COUT << "Prim" << prim << "Cont" << cont << '\n'; + return smod(prim*cont, modulo); + } + + /* + p and q are assumed to have integer content=1 + the leading coeff of d=gcd(p,q) divides the leading coeff of p and q + we will therefore normalize modular gcds to have the gcd of the + leading coeffs as leading coeff, and will try divisibility + of it's smodular representant after division by the content + */ + bool gcd_modular_algo(polynome &p,polynome &q, polynome &d,bool compute_cof){ + if (p.dim==1) + return gcd_modular_algo1(p,q,d,compute_cof); + polynome plgcd(p.dim), qlgcd(q.dim), pp(p.dim), qq(p.dim),gcdlgcd(p.dim); + plgcd=lgcd(p); + qlgcd=lgcd(q); + pp=p/plgcd; + qq=q/qlgcd; + gcdlgcd=gcd(plgcd,qlgcd); + gen gcdfirstcoeff(gcd(pp.coord.front().value, qq.coord.front().value,context0)); + int gcddeg= giacmin(pp.lexsorted_degree(),qq.lexsorted_degree()); + gen bound(pow(gen(2),gcddeg+1)* abs(gcdfirstcoeff,context0) * min(pp.norm(), qq.norm(),context0)); + gen modulo(nextprime(max(gcdfirstcoeff+1,gen(30000),context0))); + gen productmodulo(1); + polynome currentgcd(p.dim),p_simp(p.dim),q_simp(p.dim),rem(p.dim); + // 30000 leaves many primes below the 2^15 bound + for (;;modulo = nextprime(modulo+2)){ + // increment modulo to avoid modulo = 1 [4] so that it works in Z[i] + while ( is_one(modulo % 4) || is_zero(gcdfirstcoeff % modulo)) + modulo=nextprime(modulo+2); + polynome _gcdmod(gcdmod(smod(pp,modulo),smod(qq,modulo),modulo)); + gen adjustcoeff=gcdfirstcoeff*invmod(_gcdmod.coord.front().value,modulo); + _gcdmod=smod((_gcdmod * adjustcoeff), modulo) ; + int m=_gcdmod.lexsorted_degree(); + if (!m){ + p=pp*(plgcd/gcdlgcd); + q=qq*(qlgcd/gcdlgcd); + d=gcdlgcd; + return true; + } + // combine step + if (mgcddeg this prime is bad, just ignore + } + // if (productmodulo>bound){ + d=smod(currentgcd,productmodulo); + ppz(d); + //if ( pp.TDivRem1(d,p_simp,rem) && rem.coord.empty() && qq.TDivRem1(d,q_simp,rem) && rem.coord.empty() ){ + if ( divrem1(pp,d,p_simp,rem) && rem.coord.empty() && divrem1(qq,d,q_simp,rem) && rem.coord.empty() ){ + p=p_simp*(plgcd/gcdlgcd); + q=q_simp*(qlgcd/gcdlgcd); + d=d*gcdlgcd; + return true; + } + // } + } + return false; + } + + polynome pzadic(const polynome &p,const gen & n){ + monomial_v v; + index_t i; + for (monomial_v::const_iterator it=p.coord.begin();it!=p.coord.end();++it){ + i.clear(); + i.push_back(0); + for (index_t::const_iterator iti=it->index.begin();iti!=it->index.end();++iti) + i.push_back(*iti); + gen k=it->value; + for (int j=0;!is_zero(k);j++){ + gen r=smod(k,n.re(0)); + if (!is_zero(r)){ + i[0]=j; + v.push_back(monomial(r,i)); + } + k=iquo( (k-r),n.re(context0)); + } + } + // sort v + polynome res(p.dim+1,v); + res.tsort(); + return res; + } + + bool listmax(const polynome &p,gen & n ){ + return Tlistmax(p,n); + } + + bool unext(const polynome & p,const gen & pmin,polynome & res){ + res.dim=p.dim; res.coord.clear(); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + res.coord.reserve(itend-it); + for (;it!=itend;++it){ + gen g=it->value; + if (g.type==_FRAC) + return false; + if (g.type==_EXT){ + if (*(g._EXTptr+1)!=pmin) + return false; + g=*g._EXTptr; + if (g.type==_VECT) + g.subtype=_POLY1__VECT; + res.coord.push_back(monomial(g,it->index)); + } + else + res.coord.push_back(*it); + } + return true; + } + + bool ext(polynome & res,const gen & pmin){ + vector< monomial >::iterator it=res.coord.begin(),itend=res.coord.end(); + for (;it!=itend;++it){ + gen g=ext_reduce(it->value,pmin); + if (is_zero(g)) return false; + it->value=g; + } + return true; + } + + void ext(const polynome & p,const gen & pmin,polynome & res){ + res.dim=p.dim; + res.coord.clear(); + res.coord.reserve(p.coord.size()); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + gen g=ext_reduce(it->value,pmin); + if (is_zero(g)) + continue; + res.coord.push_back(monomial(g,it->index)); + } + } + + void unmodularize(const polynome & p,polynome & res){ + res.dim=p.dim; + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + res.coord.reserve(itend-it); + for (;it!=itend;++it){ + if (it->value.type==_MOD) + res.coord.push_back(monomial(*it->value._MODptr,it->index)); + else + res.coord.push_back(monomial(it->value,it->index)); + } + } + + polynome unmodularize(const polynome & p){ + polynome res(p.dim); + unmodularize(p,res); + return res; + } + + void modularize(polynome & d,const gen & m){ + vector< monomial >::iterator it=d.coord.begin(),itend=d.coord.end(); + for (;it!=itend;++it){ + if (it->value.type!=_USER) + it->value=makemod(it->value,m); + } + } + + // Find indexes of p such that p is constant, answer is in i + static void has_constant_variables(const polynome & p,index_t & i){ + i=index_t(p.dim,0); + for (int j=0;j >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + index_t::iterator iit,iitend; + for (;it!=itend && !i.empty();++it){ + index_t::const_iterator j=it->index.begin(); + iit=i.begin(); iitend=i.end(); + for (;iit!=iitend;){ + if (*(j+*iit)){ // non-0 power in monomial + i.erase(iit); + iit=i.begin(); + iitend=i.end(); + } + else + ++iit; + } + } + } + + // p assumed to be constant wrt variables in pi + // vi is a vector of degree + static int extract_monomials(const polynome &p,const index_t & pi,vectpoly & vp){ + index_t pdeg=p.degree(); + // find largest degree of p with respect to these variables + int s=int(pi.size()),ans=1; + index_t v(s+1); + int i=0; + for (;i1000) // FIXME what's the right size?? + return i; + v[i]=pdeg[pi[i]]+1; + ans=ans*v[i]; + } + if (ans>10000) + return -1; + vp=vectpoly(ans,polynome(p.dim-s)); + if (ans==1) + vp[0].coord.reserve(p.coord.size()); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + index_t::const_iterator piitbeg=pi.begin(),piit,piitend=pi.end(),vitbeg=v.begin(),vit,iti; + index_t::iterator iit; + int vp_pos; + for (;it!=itend;++it){ + index_m i(p.dim-s); + piit=piitbeg; + vit=vitbeg; + iit=i.begin(); + iti=it->index.begin(); + vp_pos=0; + // construct new index without constant variables + // and find value of index inside vp + // iti index in current monomial of p, piit index in list of variables (p or q cst), vit index in v + for (int j=0;j!=p.dim;++iti,++j){ + if (piit!=piitend && j==*piit){ + ++piit; + vp_pos=vp_pos*(*vit)+(*iti); + ++vit; + } + else { + *iit=*iti; + ++iit; + } + } + vp[vp_pos].coord.push_back(monomial(it->value,i)); + } + return 0; + } + + static bool has_constant_variables_gcd(const polynome & p,const polynome & q,polynome & d){ + if (q.coord.empty()){ + d=p; + return true; + } + if (p.coord.empty()){ + d=q; + return true; + } + index_t pi,qi; + has_constant_variables(p,pi); + has_constant_variables(q,qi); + // merge pi and qi + index_t::iterator qit=qi.begin(),qitend=qi.end(); + for (;qit!=qitend;++qit){ + if (!equalposcomp(pi,*qit)) + pi.push_back(*qit); + } + if (pi.empty()) + return false; + int s=int(pi.size()); + if (s==p.dim){ + gen n=gcd(Tcontent(p),Tcontent(q),context0); + d=polynome(monomial(n,p.dim)); + return true; + } + sort(pi.begin(),pi.end()); + // p or q is constant with respect to at least one variable + // make a vector of polynomial from p and q + vectpoly vp,vq; + int i; + if ( (i=extract_monomials(p,pi,vp)) ){ + if (i<0) + return false; + pi=index_t(pi.begin(),pi.begin()+i); + i=extract_monomials(p,pi,vp); + if (i<0) + return false; + } + if ( (i=extract_monomials(q,pi,vq)) ){ + if (i<0) + return false; + pi=index_t(pi.begin(),pi.begin()+i); + extract_monomials(p,pi,vp); + i=extract_monomials(q,pi,vq); + if (i<0) + return false; + } + // find gcd of polys in vp and vq + vectpoly::const_iterator it=vp.begin(),itend=vp.end(),jt=vq.begin(),jtend=vq.end(); + d=*jt; + for (++jt;!is_one(d) && it!=itend;++it) + d=gcd(d,*it); + for (;!is_one(d) && jt!=jtend;++jt) + d=gcd(d,*jt); + // reconstruct gcd of p and q + vector< monomial >::iterator dt=d.coord.begin(),dtend=d.coord.end(); + index_t::const_iterator piitbeg=pi.begin(),piit,piitend=pi.end(),dtit; + int j; + for (;dt!=dtend;++dt){ + index_m newi; + newi.reserve(p.dim); + piit=piitbeg; + dtit=dt->index.begin(); + for (j=0;jindex=newi; + } + d.dim=p.dim; + return true; + } + + int coefftype(const polynome & p,gen & coefft){ + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + int t=0; + for (;it!=itend;++it){ + const unsigned char tmp=it->value.type; + if (tmp==_INT_ || tmp==_ZINT) + continue; + t=tmp; + coefft=it->value; + if (t==_USER) + return t; + if (t==_MOD) + return t; + if (t==_EXT) + return t; + } + return t; + } + + void trim(polynome & pmod,const gen & m){ + while (!pmod.coord.empty()){ + if (!is_zero(smod(pmod.coord.front().value,m))) + break; + pmod.coord.erase(pmod.coord.begin()); + } + } + + static bool gcdheu(const polynome &p_orig,const index_t & p_deg,const polynome &q_orig, const index_t & q_deg,polynome & p_simp, gen & np_simp, polynome & q_simp, gen & nq_simp, polynome & d, gen & d_content,bool skip_test,bool compute_cofactors){ + // COUT << "Entering gcdheu " << p.dim << '\n'; + if (debug_infolevel>=123456-p_orig.dim) + CERR << "Gcdheu begin " << p_orig.dim << " " << CLOCK() << " " << p_deg << " " << p_orig.coord.size() << " " << q_deg << " " << q_orig.coord.size() << '\n'; + if (&p_orig!=&p_simp) + p_simp=p_orig; + if (&q_orig!=&q_simp) + q_simp=q_orig; + if (debug_infolevel>=123456-p_simp.dim) + CERR << "Gcdheu end copy" << CLOCK() << '\n'; + // check if one coeff is a _MOD or _USER + gen coefft,coeffqt; + int pt=coefftype(p_simp,coefft),qt=coefftype(q_simp,coeffqt); + if (pt>=_EXT && qt>=_EXT && pt!=qt){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Incompatible coeff type")); +#endif + return false; + } + if (pt<_EXT && qt>=_EXT){ + pt=qt; + coefft=coeffqt; + } + // If p, q have modular coeff, use modular algo + if (!pt){ + pt=qt; + coefft=coeffqt; + } + d_content=1; + if (pt==_MOD){ + gen m=*(coefft._MODptr+1); + if (debug_infolevel) + CERR << "gcdmod begin " << CLOCK() << '\n'; + polynome pmod,qmod; + unmodularize(p_simp,pmod); + unmodularize(q_simp,qmod); + trim(pmod,m); + trim(qmod,m); + d=gcdmod(pmod,qmod,m); + if (debug_infolevel) + CERR << "gcdmod end " << CLOCK() << '\n'; + if (compute_cofactors){ + polynome pmodd,qmodd,tmp; + divremmod(pmod,d,m,pmodd,tmp); + divremmod(qmod,d,m,qmodd,tmp); + // CERR << dmod << ":;\n" << pmodd << ":;\n" << qmodd << '\n'; + p_simp=pmodd; + modularize(p_simp,m); + q_simp=qmodd; + modularize(q_simp,m); + } + modularize(d,m); + return true; + } + if (pt==_USER){ + coefft._USERptr->polygcd(p_simp,q_simp,d); + if (compute_cofactors){ + p_simp=p_simp/d; + q_simp=q_simp/d; + } + return true; + } + // does not work for collect(( -az^2-3*az*cos(kt)^2+az-cos(kt)^2)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ax*ksx*sin(kt)+(az^2*cos(kt)^2+az*cos(kt)^2+az+2*cos(kt)^2-1)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ax*ktx*sin(kt)+(az^2+3*az*cos(kt)^2-az+cos(kt)^2)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ay*ksy*sin(kt)+(az^2+3*az*cos(kt)^2-az+cos(kt)^2)*sqrt(2*cos(kt)^2+az^2+2*az*cos(kt)^2-1)*ay*kty*sin(kt)) + // np_simp=(pt!=_EXT)?ppz(p_simp):1; + // nq_simp=(qt!=_EXT)?ppz(q_simp):1; + np_simp=ppz(p_simp); + nq_simp=ppz(q_simp); + if (debug_infolevel>=123456-p_simp.dim) + CERR << "Gcdheu end ppz" << CLOCK() << " " << np_simp << " " << nq_simp << '\n'; + d_content=gcd(np_simp,nq_simp,context0); + // type may have changed by ppz simplification, recheck + if (!is_integer(np_simp)) + pt=coefftype(p_simp,coefft); + if (!is_integer(nq_simp)) + qt=coefftype(q_simp,coeffqt); + if (pt>=_EXT && qt>=_EXT && pt!=qt){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Incompatible coeff type")); +#endif + return false; + } + if (pt<_EXT && qt>=_EXT){ + pt=qt; + coefft=coeffqt; + } + if (!pt){ + pt=qt; + coefft=coeffqt; + } + if (qt==_POLY && pt<_POLY){ + pt=qt; + coefft=coeffqt; + } + if (pt==_POLY){ + if (coefft.type!=_POLY){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + int innerdim=coefft._POLYptr->dim; + polynome pmulti=unsplitmultivarpoly(p_simp,innerdim); + polynome qmulti=unsplitmultivarpoly(q_simp,innerdim); + d=gcd(pmulti,qmulti); + d=splitmultivarpoly(d,innerdim); + if (compute_cofactors){ + p_simp=p_simp/d; + q_simp=q_simp/d; + } + return true; + } + if (Tis_constant(p_simp) || Tis_constant(q_simp)){ + if (debug_infolevel>=2) + CERR << "//Gcdheu p constant!" << '\n'; + d=polynome(plus_one,p_simp.dim); + return true; + } + if (p_simp.dim==1 && !pt){ + // gcd in Z[X] + return gcd_modular(p_simp,q_simp,d,p_simp,q_simp,compute_cofactors); + } + bool allowrational = (pt>=_POLY || qt>=_POLY) && (pt!=_EXT && qt!=_EXT); + if ( + !all_inf_equal(q_deg,p_deg) + // !(p_deg>q_deg) + ){ + polynome quo(p_simp.dim); + if (exactquotient(q_simp,p_simp,quo,allowrational)){ + d=p_simp; + q_simp=quo; + p_simp=polynome(monomial(plus_one,0,p_simp.dim)); + if (is_positive(-d.coord.front())){ + d=-d; p_simp=-p_simp; q_simp=-q_simp; + } + if ( debug_infolevel>=123456-p_simp.dim ) + CERR << "// End exact " << p_simp.dim << " " << CLOCK() << " " <=123456-p_simp.dim ) + CERR << "//Gcdheu exact division failed! " << CLOCK() << '\n'; + if (p_simp.coord.size()==1){ + index_t i=index_gcd(p_simp.coord.front().index.iref(),q_simp.gcddeg()); + d=polynome(monomial(plus_one,i)); + if (i!=index_t(i.size())){ + i=-i; + p_simp=p_simp.shift(i); + q_simp=q_simp.shift(i); + } + return true; + } + } + if ( + !all_inf_equal(p_deg,q_deg) + //!(q_deg>p_deg) + ) { + polynome quo(p_simp.dim); + if (exactquotient(p_simp,q_simp,quo,allowrational)){ + d=q_simp; + p_simp=quo; + q_simp=polynome(monomial(plus_one,0,p_simp.dim)); + if (is_positive(-d.coord.front())){ + d=-d; p_simp=-p_simp; q_simp=-q_simp; + } + if ( debug_infolevel>=123456-p_simp.dim ) + CERR << "//End exact " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n'; + return true; + } + if ( debug_infolevel>=123456-p_simp.dim ) + CERR << "//Gcdheu exact division failed! " << CLOCK() << '\n'; + if (q_simp.coord.size()==1){ + index_t i=index_gcd(q_simp.coord.front().index.iref(),p_simp.gcddeg()); + d=polynome(monomial(plus_one,i)); + if (i!=index_t(i.size())){ + i=-i; + p_simp=p_simp.shift(i); + q_simp=q_simp.shift(i); + } + return true; + } + } + if (p_simp.lexsorted_degree()==0){ + if (debug_infolevel >= 20-p_simp.dim) + CERR << "Begin cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n'; + if (q_simp.lexsorted_degree()==0){ + d=gcd(p_simp.trunc1(),q_simp.trunc1()).untrunc1(); + } + else { + d=p_simp; + Tlgcd(q_simp,d); + } + if (!is_one(d) && compute_cofactors){ + p_simp=p_simp/d; + q_simp=q_simp/d; + } + if (debug_infolevel >= 20-p_simp.dim) + CERR << "End cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n'; + return true; + } + if (q_simp.lexsorted_degree()==0){ + if (debug_infolevel >= 20-p_simp.dim) + CERR << "Begin cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n'; + d=q_simp; + Tlgcd(p_simp,d); + if (!is_one(d) && compute_cofactors){ + q_simp=q_simp/d; + p_simp=p_simp/d; + } + if (debug_infolevel >= 20-p_simp.dim) + CERR << "End cst " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n'; + return true; + } + if (pt==_EXT){ + // FIXME then test for + // m:=matrix(2,2,[1,1,i*(sqrt(a^2*b^2-4*a*b)+a*b)/(2*a),i*(-sqrt(a^2*b^2-4*a*b)+a*b)/(2*a)]); M:=simplify(trn(m)*m); egvl(M); + int dim=p_simp.dim; + vector< T_unsigned > p,q,g,pcof,qcof; + index_t di(dim); + std::vector vars(dim); + if (!convert(p_simp,q_simp,di,vars,p,q)) + return false; + if (!gcd_ext(p,q,g,pcof,qcof,vars,compute_cofactors,threads)) + return false; + if (debug_infolevel>1) + CERR << CLOCK()*1e-6 << " success gcd_ext" << '\n'; + convert_from(g,di,d); + if (compute_cofactors){ + convert_from(pcof,di,p_simp); + convert_from(qcof,di,q_simp); + } + // normalize gcd and cofactors + gen firstd=evalf_double(d.coord.front().value,1,context0); + if (firstd.type==_DOUBLE_ && is_positive(-firstd,context0)){ + d *= -1; + if (compute_cofactors){ + p_simp *= -1; + q_simp *= -1; + } + } + if (firstd.type==_CPLX && firstd._CPLXptr->type==_DOUBLE_ && (firstd._CPLXptr+1)->type==_DOUBLE_){ + int arg=int(std::floor(std::atan2((firstd._CPLXptr+1)->_DOUBLE_val,firstd._CPLXptr->_DOUBLE_val)/(3.14159265358979323846/2))); + if (arg!=0){ + gen mult=arg>0?(-cst_i):(arg==-1?cst_i:-1); + d *= mult; + if (mult.type==_CPLX) mult=-mult; + if (compute_cofactors){ + p_simp *= mult; + q_simp *= mult; + } + } + } + return true; + } + int Dbdeg=giacmin(p_simp.lexsorted_degree(),q_simp.lexsorted_degree()); + bool est_reel=poly_is_real(p_simp) && poly_is_real(q_simp); // FIXME: should check for extensions! + if (debug_infolevel>=2) + CERR << "//Gcdheu " << p_deg << " " << p_simp.coord.size() << " " << q_deg << " " << q_simp.coord.size() << '\n'; + // first try evaluation for quick trivial gcd + if (!skip_test ){ + if (p_simp.dim>1) { + vecteur b(p_simp.dim-1); + polynome Fb(1),Gb(1),Db(1); + if (debug_infolevel >= 20-p_simp.dim) + CERR << "// GCD eval dimension " << p_simp.dim << " " << CLOCK() << " " << p_deg << " " << p_simp.coord.size() << " " << q_deg << q_simp.coord.size() << " " << '\n'; + gen essaimod=30013; // 30011; // mod 4 = 3 + for (int essai=0;essai<2;++essai){ + if (essai) + b=vranmnot0(p_simp.dim-1); // find another random point + // essaimod was est_reel?essaimod:0 + for (;!find_good_eval(p_simp,q_simp,Fb,Gb,b,debug_infolevel >= 20-p_simp.dim,essaimod);){ + for (;;){ + essaimod=nextprime(essaimod+1); + if (is_one(smod(essaimod,4))) + break; + } + } +#ifndef NO_STDEXCEPT + try { +#endif + Db=gcdmod(Fb,Gb,essaimod); +#ifndef NO_STDEXCEPT + } catch (std::runtime_error & ){ + Db=gcd(Fb,Gb); + } +#endif + Dbdeg=Db.lexsorted_degree(); + if (debug_infolevel >= 20-p_simp.dim) + CERR << "// evaled GCD deg " << Dbdeg << '\n'; + if (!Dbdeg){ + d.coord.clear(); + Tcommonlgcd(p_simp,q_simp,d); + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "end eval " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n'; + if (compute_cofactors){ + p_simp=p_simp/d; + q_simp=q_simp/d; + } + return true; + } + if (Dbdeg==p_simp.lexsorted_degree()){ // try p_simp/lgcd as gcd + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "Trying p/lgcd(p) as gcd " << p_simp.dim << " " << CLOCK() << '\n'; + polynome p_simp_lgcd(Tlgcd(p_simp)); + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "lgcd(p) ok " << p_simp.dim << " " << CLOCK() << '\n'; + polynome p_simp_simp(p_simp.dim); + if (!exactquotient(p_simp,p_simp_lgcd,p_simp_simp)) { +#ifndef NO_STDEXCEPT + setsizeerr(gettext("gausspol.cc/gcdheu")); +#endif + return false; + } + polynome quo(q_simp.dim); + if (exactquotient(q_simp,p_simp_simp,quo)){ + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "Success p/lgcd(p) as gcd " << p_simp.dim << " " << CLOCK() << '\n'; + polynome quo_lgcd(p_simp_lgcd); + Tlgcd(quo,quo_lgcd); + d=p_simp_simp*quo_lgcd; + if (compute_cofactors){ + p_simp=p_simp_lgcd/quo_lgcd; + q_simp=quo/quo_lgcd; + } + return true; + } + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "Failed p/lgcd(p) as gcd " << p_simp.dim << " " << CLOCK() << '\n'; + } + if (Dbdeg==q_simp.lexsorted_degree()){ // try p_simp/lgcd as gcd + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "Trying q/lgcd(q) as gcd " << p_simp.dim << " " << CLOCK() << '\n'; + polynome q_simp_lgcd(Tlgcd(q_simp)); + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "lgcd(q) ok " << p_simp.dim << " " << CLOCK() << '\n'; + polynome q_simp_simp(q_simp.dim); + if (!exactquotient(q_simp,q_simp_lgcd,q_simp_simp)){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("gausspol.cc/gcdheu")); +#endif + return false; + } + polynome quo(p_simp.dim); + if (exactquotient(p_simp,q_simp_simp,quo)){ + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "Success q/lgcd(q) as gcd " << p_simp.dim << " " << CLOCK() << '\n'; + polynome quo_lgcd(q_simp_lgcd); + Tlgcd(quo,quo_lgcd); + d=q_simp_simp*quo_lgcd; + if (compute_cofactors){ + q_simp=q_simp_lgcd/quo_lgcd; + p_simp=quo/quo_lgcd; + } + return true; + } + if ( debug_infolevel >= 20-p_simp.dim ) + CERR << "Failed q/lgcd(q) as gcd " << p_simp.dim << " " << CLOCK() << '\n'; + } + } + } + } + // now work on p_simp and q_simp + if (!p_simp.dim){ + d=polynome(gen(1),0); + return true; + } + gen np,nq,n; + if (!listmax(p_simp,np)){ + return false; + } + if (!listmax(q_simp,nq)){ + return false; + } + if (p_simp.dim==1){ // integer modular try, was p_simp.dim==1 && est_reel + environment * env= new environment; + bool avoid_it=false; + dense_POLY1 pp,qq; +#ifndef NO_STDEXCEPT + try { +#endif + pp=modularize(p_simp,0,env); + qq=modularize(q_simp,0,env); + if (is_undef(pp) || is_undef(qq)) + avoid_it=true; +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & ){ + avoid_it=true; + } +#endif + env->moduloon = true; + env->modulo=1001; + env->pn=env->modulo; + env->complexe=!est_reel; + for (int essai=0;essai<2 && !avoid_it;++essai){ + env->modulo=nextprime(env->modulo+2); + while ( !is_one(smod(env->modulo,4)) || !is_one(gcd(gcd(env->modulo,pp.front(),context0),qq.front(),context0)) ) + env->modulo=nextprime(env->modulo+2); + modpoly _gcdmod; + gcdmodpoly(pp,qq,env,_gcdmod); + if (is_undef(_gcdmod)) + return false; + Dbdeg=giacmin(Dbdeg,int(_gcdmod.size())-1); + if (!Dbdeg) + break; + } + delete env; + if (!Dbdeg){ + d=polynome(gen(1),p_simp.dim); + return true; + } + } + polynome p1(p_simp.dim),q1(p_simp.dim),r1(p_simp.dim),r2(p_simp.dim); + gen n_2(2),n_73794(73794),n_27011(27011); + if (is_greater(nq,np,context0)) + n=n_2*nq+n_2; + else + n=n_2*np+n_2; + // PSR if gcd has a large degree, modular if low degree, else try heugcd + // PSR complexity is proportionnal to + // #iteration*deg_var_n*(total_deg_other_vars*#iteration)^(2*#other_var) + // MODGCD to product of all (part_deg_of_gcd+1+part_deg_of_gcd_lcoeff) + int maxpqdeg0=giacmax(p_simp.lexsorted_degree(),q_simp.lexsorted_degree()); + int minpqdeg0=giacmin(p_simp.lexsorted_degree(),q_simp.lexsorted_degree()); + index_t maxpqdeg(p_simp.dim); + double sparsenessp=double(p_simp.coord.size()),sparsenessq=double(q_simp.coord.size()); + for (int i=0;iheuop) minop=heuop; if (minop>modop) minop=modop; + if (debug_infolevel) + CERR << "Psr " << psrgcdop << ", Mod " << modop << ", Heu " << heuop << ", Min" << minop << '\n'; + if (modop modop && + (p_simp.dim>3) // && (Dbdeg<=maxpqdeg0/4+1) + && ezgcd(p_simp,q_simp,d,true,true,0,minop)){ + if (debug_infolevel) + COUT << "// Used EZ gcd " << '\n'; + if (compute_cofactors){ + q_simp=q_simp/d; + p_simp=p_simp/d; + } + return true; + } + if (//false && + p_simp.dim>1 && psrgcdop< modop && psrgcdop < heuop ){ + d=gcdpsr(p_simp,q_simp,Dbdeg); + if (compute_cofactors){ + q_simp=q_simp/d; + p_simp=p_simp/d; + } + return true; + } +#ifndef NSPIRE + if (//true || + modop < heuop + ){ // was if ( modop < heuop && est_reel) + if (debug_infolevel) + COUT << "// " << CLOCK() << " Using modular gcd " << '\n'; + bool res=gcd_modular(p_simp,q_simp,d,p_simp,q_simp,compute_cofactors); + if (debug_infolevel) + COUT << "// " << CLOCK() << " End modular gcd " << '\n'; + return res; + } +#endif + } + if (debug_infolevel) + COUT << "// Using Heu gcd " << '\n'; + int max_try=0; + for (; max_try= 20-p_simp.dim) + CERR << "end gcdheu " << p_simp.dim << " " << CLOCK() << " " << d.coord.size() << '\n'; + return true; + } + n=iquo(n*n_73794,n_27011); + } + // COUT << "gcdheu failure" << '\n'; + return false; + } + + bool gcdheu(const polynome &p_orig,const polynome &q_orig, polynome & p_simp, gen & np_simp, polynome & q_simp, gen & nq_simp, polynome & d, gen & d_content,bool skip_test,bool compute_cofactors){ + index_t pdeg=p_orig.degree(),qdeg=q_orig.degree(); + return gcdheu(p_orig,pdeg,q_orig,qdeg,p_simp,np_simp,q_simp,nq_simp,d,d_content,skip_test,compute_cofactors); + } + + polynome gcdpsr(const polynome &p,const polynome &q,int gcddeg){ + if (is_undef(p) || is_undef(q)) + return polynome( monomial(1,p.dim)); + if (has_num_coeff(p) || has_num_coeff(q)) + return polynome( monomial(1,p.dim)); + if (debug_infolevel) + COUT << "// Using PSR gcd " << '\n'; + if (!gcddeg && p.dim>1){ // find probable degree + vecteur b(p.dim-1); + polynome Fb(1),Gb(1),Db(1); + for (int essai=0;essai<2;++essai){ + if (essai) + b=vranmnot0(p.dim-1); // find another random point + find_good_eval(p,q,Fb,Gb,b,debug_infolevel >= 20-p.dim); + Db=gcd(Fb,Gb); + int Dbdeg=Db.lexsorted_degree(); + if (!Dbdeg) + return gcd(Tlgcd(p),Tlgcd(q)); + if (!gcddeg) + gcddeg=Dbdeg; + else + gcddeg=giacmin(Dbdeg,gcddeg); + } + } + return Tgcdpsr(p,q,gcddeg); + } + + bool findabcdelta(const polynome & p,polynome & a,polynome &b,polynome & c,polynome & delta){ + if (p.lexsorted_degree()!=2) + return false; + monomial_v::const_iterator it=p.coord.begin(),itend=p.coord.end(); + a=Tnextcoeff(it,itend); + if (it==itend){ + b=polynome(a.dim); + c=polynome(a.dim); + delta=polynome(a.dim); + return true; + } + if (it->index.front()==1) + b=Tnextcoeff(it,itend); + else + b=polynome(a.dim); + if (it==itend) + c=polynome(a.dim); + else + c=Tnextcoeff(it,itend); + delta=b*b-a*c*gen(4); + return (it==itend); + } + + bool findde(const polynome & p,polynome & d,polynome &e){ + if (p.coord.empty()){ + d=p; + e=p; + return true; + } + int n=p.lexsorted_degree(); + if (n>1) + return false; + monomial_v::const_iterator it=p.coord.begin(),itend=p.coord.end(); + if (!n){ + e=Tnextcoeff(it,itend); + d=polynome(e.dim); + return(it==itend); + } + d=Tnextcoeff(it,itend); + if (it==itend) + e=polynome(d.dim); + else + e=Tnextcoeff(it,itend); + return (it==itend); + } + + int total_degree(const polynome & p){ + int res=0,deg; + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + deg=int(it->index.total_degree()); + if (deg>res) + res=deg; + } + return res; + } + + // evaluate all vars but the j-th to 0 + static gen peval0(const polynome & p,int j,int & total_deg){ + if (!j){ + vecteur v(p.dim-1); + total_deg=total_degree(Tfirstcoeff(p).degree()); + return peval(p,v,0); + } + vecteur res; + total_deg=0; + int s=0,smax=0,n=p.dim,total; + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + int i,k=0; + index_t::const_iterator itit; + bool add; + for (;it!=itend;++it){ + itit=it->index.begin(); + add=true; + for (i=0,total=0;ivalue; + else { + for (;svalue); + ++s; + } + } + if (k>smax){ + total_deg=total-k; + smax=k; + } + if (k==smax) + total_deg=giacmax(total_deg,total-k); + } + reverse(res.begin(),res.end()); + return trim(res,0); + } + + static void dividedegrees(polynome & p,int var,int d) { + if (d==1) return; + std::vector< monomial >::iterator it=p.coord.begin(),it_end=p.coord.end(); + for (;it!=it_end;++it){ + index_t i=it->index.iref(); + i[var] /= d; + it->index=i; + } + } + + // return gcd of exponents in p and q for variable number var + static int xn2x(const polynome & p,const polynome & q,int var){ + vector< monomial >::const_iterator It=p.coord.begin(),Itend=p.coord.end(); + int l=0; + for (;It!=Itend;++It){ + const index_t &i=It->index.iref(); + l=gcd(l,i[var]); + if (l==1) + return 1; + } + It=q.coord.begin();Itend=q.coord.end(); + for (;It!=Itend;++It){ + const index_t &i=It->index.iref(); + l=gcd(l,i[var]); + if (l==1) + return 1; + } + return l; + } + + static bool xn2x(polynome &p,polynome & q,vector & gcd_index){ + gcd_index=vector(p.dim,1); + bool ans=false; + for (int i=0;i1); + gcd_index[i] = res; + if (res){ + dividedegrees(p,i,res); + dividedegrees(q,i,res); + } + } + return ans; + } + + static bool xn2x(const polynome &p,const polynome & q){ + for (int i=0;i1) + return true; + } + return false; + } + + static void multiplydegrees(polynome & p,int var,int d) { + if (d==1) return; + std::vector< monomial >::iterator it=p.coord.begin(),it_end=p.coord.end(); + for (;it!=it_end;++it){ + index_t i=it->index.iref(); + i[var] *= d; + it->index=i; + } + } + + static void x2xn(polynome &p,vector & gcd_index){ + for (int i=0;i & permutation){ + if (p.dim<2) + return false; + int pd=pdeg.front(),qd=qdeg.front(),res=giacmin(pd,qd),pos=0,tmp; + // Find first lowest degree position + vector vpos(1,0); + for (int j=1;j(1,j); + } + if (tmp==res) + vpos.push_back(j); + } + int s=int(vpos.size()); + // Same lowest degree, eval p at 0...0 and compare + // (for ezgcd to find good eval: peval at zero must be non 0 + // and the lcoeff must be as small as possible) + pos=vpos[0]; + if (s>1){ + int plcoeff,qlcoeff; + gen p0=peval0(p,pos,plcoeff); + gen q0=peval0(q,pos,qlcoeff); + for (int j=1;j= 20-p.dim) + CERR << "Exchange " << CLOCK() << " " << p.dim << " " << p.degree() << " " << p.coord.size() << " " << q.degree() << " " << q.coord.size() << '\n'; + permutation=transposition(0,pos,p.dim); + p.reorder(permutation); + q.reorder(permutation); + return true; + } + + void lcmdeno(const polynome & p, gen & res){ + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + gen tmp=it->value; + if (tmp.type!=_FRAC && tmp.type!=_EXT) + continue; + gen tmpden=1; + while (tmp.type==_FRAC || tmp.type==_EXT){ + if (tmp.type==_EXT){ + if (tmp._EXTptr->type==_VECT){ + vecteur v=*tmp._EXTptr->_VECTptr; + gen eden; + lcmdeno(v,eden,context0); + tmpden=tmpden*eden; + } + break; + } + tmpden=tmpden*tmp._FRACptr->den; + tmp=tmp._FRACptr->num; + } + res=lcm(tmpden,res); + } + } + + void lcmmult(polynome & p, const gen & res){ + vector< monomial >::iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + gen tmp=it->value; + if (tmp.type!=_FRAC && tmp.type!=_EXT){ + it->value=tmp*res; + continue; + } + gen tmpden=1; + while (tmp.type==_FRAC || tmp.type==_EXT){ + if (tmp.type==_EXT){ + if (tmp._EXTptr->type==_VECT){ + vecteur v=*tmp._EXTptr->_VECTptr; + gen eden; + lcmdeno(v,eden,context0); + tmp=algebraic_EXTension(v,*(tmp._EXTptr+1)); + tmpden=tmpden*eden; + } + break; + } + tmpden=tmpden*tmp._FRACptr->den; + tmp=tmp._FRACptr->num; + } + it->value=(res/tmpden)*tmp; + } + } + + void simplify_gcdpart(polynome & p,polynome & q,polynome & p_gcd,bool ckxn2x){ + vector gcd_index; + if (ckxn2x && xn2x(p,q,gcd_index)){ + simplify_gcdpart(p,q,p_gcd,false); + x2xn(p_gcd,gcd_index); + x2xn(p,gcd_index); + x2xn(q,gcd_index); + return; + } + polynome p_orig(p); + polynome q_orig(q); + p_gcd.coord.clear(); + std::vector permutation; + index_t pdeg=p.degree(),qdeg=q.degree(); + bool exchanged=exchange_variables(p_orig,pdeg,q_orig,qdeg,permutation); + gen d_content=1,np_simp=1,nq_simp=1; + if (gcdheu(p_orig,pdeg,q_orig,qdeg,p,np_simp,q,nq_simp,p_gcd,d_content,false,true)){ + p=p*rdiv(np_simp,d_content,context0); + q=q*rdiv(nq_simp,d_content,context0); + if (exchanged){ + p.reorder(permutation); + q.reorder(permutation); + p_gcd.reorder(permutation); + if (!p_gcd.coord.empty() && is_strictly_positive(-p_gcd.coord.front().value,context0)){ + p_gcd=-p_gcd; + p=-p; + q=-q; + } + } + p_gcd=p_gcd*d_content; + gen pz=ppz(p,true),qz=ppz(q,true); + gen g=simplify(pz,qz); + mulpoly(p_gcd,g,p_gcd); + mulpoly(p,pz,p); + mulpoly(q,qz,q); + return ; + } + p_gcd=gcdpsr(p_orig,q_orig); + polynome tmprem(p_gcd.dim); + p_orig.TDivRem1(p_gcd,p,tmprem,true); + q_orig.TDivRem1(p_gcd,q,tmprem,true); + // If alg. extensions are involved, p and q may now contain fractions + gen tmpmult(plus_one); + lcmdeno(p,tmpmult); + lcmdeno(q,tmpmult); + p=p*tmpmult; + q=q*tmpmult; + if (exchanged){ + p.reorder(permutation); + q.reorder(permutation); + p_gcd.reorder(permutation); + } + p_gcd=inv(tmpmult,context0)*p_gcd; + return ; + } + + void simplify(polynome & p,polynome & q,polynome & p_gcd){ + if (is_one(q)){ + p_gcd=q; + return; + } + if (is_one(p)){ + p_gcd=p; + return ; + } + if (q.coord.empty()){ + p_gcd=polynome(gen(1),p.dim); + swap(p_gcd.coord,p.coord); + return ; + } + if (p.coord.empty()){ + p_gcd=polynome(gen(1),p.dim); + swap(p_gcd.coord,q.coord); + return ; + } + if (!p.dim){ + gen p0=p.coord.front().value,q0=q.coord.front().value; + gen tmp=simplify(p0,q0); + p=polynome(p0,0); + q=polynome(q0,0); + p_gcd=polynome(tmp,0); + return; + } + if (p==q){ + p_gcd=polynome(gen(1),p.dim); + swap(p.coord,p_gcd.coord); + q=p; + return; + } + if (has_constant_variables_gcd(p,q,p_gcd)){ + polynome temp(p.dim); + exactquotient(p,p_gcd,temp); + swap(p.coord,temp.coord); + exactquotient(q,p_gcd,temp); + swap(q.coord,temp.coord); + return ; + } + index_t pback=p.coord.back().index.iref(),qback=q.coord.back().index.iref(); + if (!is_zero(pback)) + pback=p.gcddeg(); + if (!is_zero(qback)) + qback=q.gcddeg(); + if (!is_zero(pback) || !is_zero(qback)){ + index_t dback=index_gcd(pback,qback); + if (!is_zero(pback)) + p=p.shift(-pback); + if (!is_zero(qback)) + q=q.shift(-qback); + simplify_gcdpart(p,q,p_gcd,true); + if (!is_zero(dback)){ + p_gcd=p_gcd.shift(dback); + pback = pback-dback; + qback = qback-dback; + } + if (!is_zero(pback)) + p=p.shift(pback); + if (!is_zero(qback)) + q=q.shift(qback); + return; + } + simplify_gcdpart(p,q,p_gcd,true /* ckxn2x */); + } + + polynome simplify(polynome &p,polynome &q){ + polynome p_gcd(p.dim); + simplify(p,q,p_gcd); + return p_gcd; + } + + void gcd_gcdpart(const polynome & p,const polynome & q,polynome & d,bool ckxn2x){ + if (ckxn2x && xn2x(p,q)){ + polynome p_(p),q_(q); + vector gcd_index; + xn2x(p_,q_,gcd_index); + gcd_gcdpart(p_,q_,d,false); + x2xn(d,gcd_index); + return; + } + polynome p_simp(p.dim),q_simp(p.dim); + index_t pdeg=p.degree(),qdeg=q.degree(); + gen d_content,np_simp,nq_simp; + if (p.coord.front().value.type==_MOD && gcdheu(p,pdeg,q,qdeg,p_simp,np_simp,q_simp,nq_simp,d,d_content,false,false) ){ + d *= d_content; + return ; + } + if (has_constant_variables_gcd(p,q,d)) + return ; + d.coord.clear(); + std::vector permutation; + polynome p_orig(p),q_orig(q); + bool exchanged=exchange_variables(p_orig,pdeg,q_orig,qdeg,permutation); + if (gcdheu(p_orig,pdeg,q_orig,qdeg,p_orig,np_simp,q_orig,nq_simp,d,d_content,false,false)){ + if (exchanged) + d.reorder(permutation); + d *= d_content; + return ; + } + d=gcdpsr(p_orig,q_orig); + if (exchanged) + d.reorder(permutation); + // if integers only, should add here gcd using modgcd + d *= d_content; + if (!d.coord.empty() && d.coord.front().value.type==_MOD) + d *= inv(d.coord.front().value,context0); + return ; + } + + void gcd(const polynome & p,const polynome & q,polynome & d){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + d=monomial(gensizeerr(gettext("Stopped by user interruption.")),p.dim); + return ; + } + if (p.coord.empty()){ + d=q; + return; + } + if (q.coord.empty()){ + d=p; + return ; + } + if (p.coord.front().value.type==_MOD && q.coord.front().value.type!=_MOD){ + polynome qq=p.coord.front().value*q; + gcd(p,qq,d); + return; + } + if (p.coord.front().value.type!=_MOD && q.coord.front().value.type==_MOD){ + polynome pp=q.coord.front().value*p; + gcd(pp,q,d); + return; + } + /* if (p==q) + return p; */ + if (p.dim==0){ + index_t i; + d=polynome( monomial(gcd(p.constant_term(),q.constant_term(),context0),i)); + return ; + } + d.dim=p.dim; + d.coord.clear(); + index_t pback=p.coord.back().index.iref(),qback=q.coord.back().index.iref(); + if (!is_zero(pback)) + pback=p.gcddeg(); + if (!is_zero(qback)) + qback=q.gcddeg(); + if (!is_zero(pback) || !is_zero(qback)){ + index_t dback=index_gcd(pback,qback); + polynome pshift=p.shift(-pback), qshift=q.shift(-qback); + gcd(pshift,qshift,d); + if (!is_zero(dback)) + d=d.shift(dback); + return; + } + gcd_gcdpart(p,q,d,true); + } + + polynome gcd(const polynome & p,const polynome & q){ + polynome d(p.dim); + gcd(p,q,d); + return d; + } + + void egcdlgcd(const polynome &p1, const polynome & p2, polynome & u,polynome & v,polynome & d){ + TegcdTlgcd(p1,p2,u,v,d); + } + + void egcd(const polynome &p1, const polynome & p2, polynome & u,polynome & v,polynome & d){ + if (p1.lexsorted_degree()==0){ + d=p1; + u.coord.clear(); + u.dim=p1.dim; + u.coord.push_back(monomial(1,index_t(u.dim))); + v.dim=p1.dim; + v.coord.clear(); + return; + } + if (p2.lexsorted_degree()==0){ + d=p2; + u.coord.clear(); + u.dim=p2.dim; + v.dim=p2.dim; + v.coord.clear(); + v.coord.push_back(monomial(1,index_t(u.dim))); + return; + } + if (try_hensel_egcd(p1,p2,u,v,d)) + return; + polynome g=gcd(p1,p2); + if (g.lexsorted_degree()){ + // if p1 and p2 do not have alg. extensions inside we can divide by g + int pt1=p1.coord.front().value.type,pt2=p2.coord.front().value.type; + if (pt1<_EXT && pt2<_EXT){ + egcd(p1/g,p2/g,u,v,d); + d=g*d; + return; + } + // in general, let a and A such that a*p1=g*A and b and B / b*p2=g*B + // solve bezout for A and B: A*U+B*V=D + // multiply by g + // p1*(a*U)+p2*(b*V)=d*g + polynome a(g.dim),A(g.dim),b(g.dim),B(g.dim),rem(g.dim); + if (!p1.TPseudoDivRem(g,A,rem,a) || !rem.coord.empty() || + !p2.TPseudoDivRem(g,B,rem,b) || !rem.coord.empty()){ + // should not happen + gensizeerr("gausspol/egcd error"); + } + egcd(A,B,u,v,d); + u=a*u; + v=b*v; + d=g*d; + return; + } + gen p1g,p2g; + int p1t=coefftype(p1,p1g); + int p2t=coefftype(p2,p2g); + if (p1.dim!=1 + //&& (p1t!=0 || p2t!=0) + ){ + egcdpsr(p1,p2,u,v,d); + return; + } + if (p1t==0 && p2t==0 + && (p1.dim!=1 || (p1.lexsorted_degree()>=giacmax(MAX_COMMON_ALG_EXT_ORDER_SIZE+1,GIAC_PADIC/2) && p2.lexsorted_degree()>=giacmax(MAX_COMMON_ALG_EXT_ORDER_SIZE+1,GIAC_PADIC/2))) + ){ + if (debug_infolevel>2) + CERR << CLOCK()*1e-6 << "starting extended gcd degrees " << p1.lexsorted_degree() << " " << p2.lexsorted_degree() << '\n'; + vecteur G,p1v,p2v; + polynome2poly1(g,1,G); + polynome2poly1(p1,1,p1v); + polynome2poly1(p2,1,p2v); + // solve sylvester matrix * []=d + matrice S=sylvester(p1v,p2v); + S=mtran(S); + int add=int(p1v.size()+p2v.size()-G.size()-2); + vecteur V=mergevecteur(vecteur(add,0),G),U; + if (p1.dim>1){ + // make the system symbolic so that Lagrange interpolation may happen + vecteur varv; + for (int i=1;itype==_VECT){ + vecteur G; + polynome2poly1(g,1,G); + polynome pmini(2),P1,P2; + algext_vmin2pmin(*(p1g._EXTptr+1)->_VECTptr,pmini); + polynome P1n(1),P2n(1); + if (algext_convert(p1,p1g,P1) && algext_convert(p2,p1g,P2)){ + if (algnorme(P1,pmini,P1n) && algnorme(P2,pmini,P2n)){ + // first solve norme(p1)*un+norme(p2)*vn=d + // then norme(p1)/p1*un*p1+norme(p2)/p2*vn*p2=d + // hence u=norme(p1)/p1*un and v=norme(p2)/p2*vn + int p1t=coefftype(P1n,p1g); + int p2t=coefftype(P2n,p2g); + polynome P12g=gcd(P1n,P2n); + if (p1t==0 && p2t==0 && P12g.lexsorted_degree()==0){ + //CERR << P1n % pp1 << '\n'; + //CERR << P2n % pp2 << '\n'; + P1=P1n/p1; + P2=P2n/p2; + // solve sylvester matrix * []=d + matrice S=sylvester(polynome2poly1(P1n,1),polynome2poly1(P2n,1)); + S=mtran(S); + vecteur V(S.size()); + V[S.size()-1]=G[0]; + vecteur U(linsolve(S,V,context0)); + gen D; + lcmdeno(U,D,context0); + G=multvecteur(D,G); + poly12polynome(G,1,d); + int p2s=P2n.lexsorted_degree(); + V=vecteur(U.begin()+p2s,U.end()); + poly12polynome(V,1,v); + //v=(v*P2) % p1; + polynome prod(v*P2),quo(p1.dim),rem(p1.dim); + if (prod.TDivRem1(p1,quo,rem,true)){ + v=rem; + U=vecteur(U.begin(),U.begin()+p2s); + poly12polynome(U,1,u); + // u=(u*P1) % p2; + prod=u*P1; + if (prod.TDivRem1(p2,quo,rem,true)){ + u=rem; + //CERR << (operator_times(u,p1,0)+operator_times(v,p2,0))/D << '\n'; + return; + } + } + } + } + } + } + if (p1t==_EXT && p2t==0 && p1g.type==_EXT && (p1g._EXTptr+1)->type==_VECT){ + vecteur G,p2v,p1v; + polynome2poly1(g,1,G); + polynome2poly1(p2,1,p2v); + polynome2poly1(p1,1,p1v); + polynome pmini(2),P1; + algext_vmin2pmin(*(p1g._EXTptr+1)->_VECTptr,pmini); + polynome P1n(1); + if (algext_convert(p1,p1g,P1)){ + if (algnorme(P1,pmini,P1n)){ + // first solve norme(p1)*un+p2*v=d + // then norme(p1)/p1*un*p1+v*p2=d + // hence u=norme(p1)/p1*un + int p1t=coefftype(P1n,p1g); + if (p1t==0){ + P1=P1n/p1; + // solve sylvester matrix * []=d + matrice S=sylvester(polynome2poly1(P1n,1),p2v); + S=mtran(S); + vecteur V(vecteur(S.size())); + V[S.size()-1]=G[0]; + vecteur U(linsolve(S,V,context0)); + gen D; + lcmdeno(U,D,context0); + int p2s=int(p2v.size())-1; + V=vecteur(U.begin()+p2s,U.end()); +#if 1 + // uv*p1v+V*p2v=D + // find remainder(V,p1v) -> V then uv=(D-V*p2v)/p1v + V=V % p1v; + gen DV; lcmdeno(V,DV,context0); + poly12polynome(V,1,v); + D=D*DV; + vecteur tmpv; mulmodpoly(V,p2v,0,tmpv); + submodpoly(vecteur(1,D),tmpv,U); + U=U/p1v; + poly12polynome(U,1,u); +#else // does not always work, must take remainder + poly12polynome(V,1,v); + U=vecteur(U.begin(),U.begin()+p2s); + poly12polynome(U,1,u); + u=u*P1; +#endif + G=multvecteur(D,G); + poly12polynome(G,1,d); + //CERR << (operator_times(u,p1,0)+operator_times(v,p2,0))/D << '\n'; + return; + } + } + } + } + if (p2t==_EXT && p1t==0 && p2g.type==_EXT && (p2g._EXTptr+1)->type==_VECT){ + egcd(p2,p1,v,u,d); + return; + } + egcdlgcd(p1,p2,u,v,d); + if (is_positive(-d.coord.front().value,context0)){ + d=-d; u=-u; v=-v; + } + if (d.coord.front().value.type==_USER){ + gen dinv=inv(d.coord.front().value,context0); + if (dinv.type==_USER){ + d=dinv*d; + u=dinv*u; + v=dinv*v; + } + } + } + + /* Factorization */ + + // build a multivariate poly + // with normal coeff from a multivariate poly with multivariate poly coeffs + polynome unsplitmultivarpoly(const polynome & p,int inner_dim){ + polynome res(p.dim+inner_dim); + index_t inner_index,outer_index; + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + outer_index=it->index.iref(); + if (it->value.type!=_POLY){ + for (int j=0;j(it->value,outer_index)); + } + else { + vector< monomial >::const_iterator jt=it->value._POLYptr->coord.begin(),jtend=it->value._POLYptr->coord.end(); + for (;jt!=jtend;++jt){ + inner_index= jt->index.iref(); + res.coord.push_back(monomial(jt->value,mergeindex(outer_index,inner_index))); + } + } + } + return res; + } + + // build from a multivariate poly with normal coeff + // a multivariate poly with multivariate poly coeffs + polynome splitmultivarpoly(const polynome & p,int inner_dim){ + int outer_dim=p.dim-inner_dim; + index_t cur_outer(outer_dim); + polynome cur_inner(inner_dim); + polynome res(outer_dim); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (; it!=itend;++it){ + index_t outer_index(it->index.begin(),it->index.begin()+outer_dim); + index_t inner_index(it->index.begin()+outer_dim,it->index.end()); + if (outer_index!=cur_outer){ + if (!is_zero(cur_inner)) + res.coord.push_back(monomial(cur_inner,cur_outer)); + cur_inner.coord.clear(); + cur_outer=outer_index; + } + cur_inner.coord.push_back(monomial(it->value,inner_index)); + } + if (!is_zero(cur_inner)) + res.coord.push_back(monomial(cur_inner,cur_outer)); + return res; + } + + // if one coeff of p is a polynomial, we must build a multivariate poly + // with normal coeff from a multivariate poly with multivariate poly coeffs + static bool poly_factor(const polynome & p, int inner_dim,polynome & p_content,factorization & f,bool with_sqrt,bool complexmode,gen & extra_div){ + // convert p -> pp + polynome pp(unsplitmultivarpoly(p,inner_dim)),pp_content(p.dim+inner_dim); + // factorize pp + // setting with_sqrt to false otherwise problems with mixed num/exact + // e.g. EIGENVAL([[4,x],[r,p]]) + if (!factor(pp,pp_content,f,false,false,complexmode,1,extra_div)) + return false; + // convert back pp_content -> p_content and each term of f + p_content=splitmultivarpoly(pp_content,inner_dim); + factorization::iterator f_it=f.begin(),f_itend=f.end(); + for (;f_it!=f_itend;++f_it) + f_it->fact=splitmultivarpoly(f_it->fact,inner_dim); + return true; + } + + void Tpown_ff(polynome & g,int n){ + vector< monomial > ::iterator it=g.coord.begin(),itend=g.coord.end(); + for (;it!=itend;++it){ + it->value=pow(it->value,n); + it->index=it->index*n; + } + } + static void push_factor(factorization & v,polynome & g,polynome & q,int k,int n){ + q=q/Tpow(g,k); + for (int l=0;;++l){ + polynome d(gcd(q,g)); + if (d!=g){ + v.push_back(facteur< polynome >(g/d,k+l*n)); + if (Tis_one(d)) + break; + g=d; + } + polynome gn(g); + Tpown_ff(gn,n); + q=q/gn; + // instead of q=q/Tpow(g,n); + } + } + // Yun algorithm in finite field of characteristic n + // Must be called recursively since it will not detect powers multiple of n + static void partialsquarefree_fp(const polynome & p,unsigned n,polynome & c,factorization & v){ + v.clear(); + c=p; + polynome y(p.derivative()),w(p); + y=smod(y,gen(int(n))); + simplify(w,y); + // If p=p_1*p_2^2*...*p_n^n, + // then c=gcd(p,p')=Pi_{i s.t. i%n!=0} p_i^{i-1} Pi_{i s.t. i%n==0} p_i^i + // w=p/c=Pi_{i%n>=1} p_i, + // y=p'/c=Sum_{i%n>=1} ip_i'*pi_{j!=i, j%n>=1} p_j + y=y-w.derivative(); + y=smod(y,gen(int(n))); + // y=Sum_{i%n>=2} (i-1)p_i'*pi_{j!=i,j%n!=0} p_j + int k=1; + while(!y.coord.empty()){ + // y=sum_{i%n >= k+1} (i-k) p_i' * pi_{j!=i, j>=k} p_j + polynome g=simplify(w,y); + if (!Tis_one(g)) + push_factor(v,g,c,k,n); + // this push p_k, now w=pi_{i%n>=k+1} p_i and + // y=sum_{i%n>=k+1} (i-k)%n p_i' * pi_{j!=i, j%n>=k+1} p_j + y=y-w.derivative(); + y=smod(y,gen(int(n))); + // y=sum_{i%n>=k+1} (i-(k+1)) p_i' * pi_{j!=i, j%n>=k+1} p_j + k++; + } + if (!Tis_one(w)) + push_factor(v,w,c,k,n);//v.push_back(facteur< polynome >(w,k)); + // at the end c contains Pi_{i mod p=0} p_i^i} + } + + // Yun algorithm in finite field of characteristic n + // Requires factorization_compress after + static factorization uncompressed_squarefree_fp(const polynome & p,unsigned n,unsigned exposant){ + factorization res; + if (Tis_one(p)) + return res; + polynome c(p.dim); + partialsquarefree_fp(p,n,c,res); + if (Tis_one(c)) + return res; + if (Tis_constant(c)){ + // res.push_back(facteur(c,1)); + return res; + } + // Check that all first degrees are divisible by n + // and search for a variable such that one degree is not divisible by n + vector< monomial >::const_iterator It=c.coord.begin(),Itend=c.coord.end(); + for (;It!=Itend;++It){ + const index_t &i=It->index.iref(); + for (int j=0;jfact.reorder(transposition(0,j,c.dim)); + res.push_back(*jt); + } + return res; + } + } + } + polynome b(c.dividealldegrees(n)); + if (exposant!=1){ + // replace all coeffs of b by coeff^(p^(n-1)) + // since in F_{p^n} we have a=(a^(p^(n-1)))^p which is not a^p + std::vector< monomial > ::iterator it=b.coord.begin(),itend=b.coord.end(); + int ntoexposant=pow(n,exposant-1).val; + for (;it!=itend;++it){ + it->value=pow(it->value,ntoexposant); + } + } + // Note that this is not correct, we must compute gcd of res and resn + // that have the same residue modulo n + // Example factor( (x+1)^3*(x-1)^4 %3 ) + // puts x-1 in res and (x^2-1)^3 in c + // Hence we must call factorization_compress at the end + factorization resn(uncompressed_squarefree_fp(b,n,exposant)); + factorization::const_iterator it=resn.begin(),itend=resn.end(); + for (;it!=itend;++it){ + res.push_back(facteur(it->fact,it->mult*n)); + } + return res; + } + + // Compress factorization, required for sqff on finite field + static void factorization_compress(factorization & sqff_f){ + factorization sqfftmp(sqff_f); + sqff_f.clear(); + vecteur vtmp; + int pos; + factorization::const_iterator it=sqfftmp.begin(),itend=sqfftmp.end(); + for (;it!=itend;++it){ + if ( (pos=equalposcomp(vtmp,it->fact)) ){ + sqff_f[pos-1].mult += it->mult; + } + else { + vtmp.push_back(it->fact); + sqff_f.push_back(*it); + } + } + } + + bool sqff_ffield_factor(const factorization & sqff_f,int n,environment * env,factorization & f){ + // Now factorize each factor + factorization::const_iterator it=sqff_f.begin(),itend=sqff_f.end(); + for (;it!=itend;++it){ + // const facteur & fp=*it; + const polynome & itfact = it->fact; + if (itfact.lexsorted_degree()<=1){ + f.push_back(*it); + continue; + } + if (itfact.dim>1){ + vecteur b(itfact.dim-1); + polynome Fb,Gb; + if (find_good_eval(itfact,itfact,Fb,Gb,b,(debug_infolevel>=2))){ + if (is_zero(b)){ + factorization sqff_F0(squarefree_fp(Fb,n,1)),v0; + if (!sqff_ffield_factor(sqff_F0,n,env,v0)) + return false; + if (try_hensel_lift_factor(itfact,Fb,v0,it->mult,f)) + continue; + } + int essaimax=10; + for (int essai=0;essaimodulo.val); + int hasard=0; + vb0[0]=sym2r(lv[0]+hasard,lv,context0); + vb1[0]=sym2r(lv[0]-hasard,lv,context0); + for (int i=1;imodulo.val); + int hasard2=std_rand()/(RAND_MAX/env->modulo.val); + lv[i]=gen("x"+print_INT_(i),context0); + vb0[i]=sym2r(lv[i]+hasard1*lv[0]+hasard2,lv,context0); + vb1[i]=sym2r(lv[i]-hasard1*lv[0]-hasard2,lv,context0); + } + gen pb=peval(unmodularize(itfact),vb0,env->modulo,false),num,den; + fxnd(pb,num,den); + if (num.type!=_POLY){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + polynome ptrans=*num._POLYptr; + modularize(ptrans,env->modulo); + factorization ftrans,v0; + b=vecteur(ptrans.dim-1); + find_good_eval(ptrans,ptrans,Fb,Gb,b,(debug_infolevel>=2)); + if (is_zero(b)){ + gen extra_div=1; + factor(Fb,Gb,v0,false,false,false,1,extra_div); + if (is_one(v0.front().fact)) + v0.erase(v0.begin()); + if (try_hensel_lift_factor(ptrans,Fb,v0,it->mult,ftrans)){ + factorization::const_iterator it=ftrans.begin(),itend=ftrans.end(); + for (;it!=itend;++it){ + pb=peval(unmodularize(it->fact),vb1,env->modulo,false); + fxnd(pb,num,den); + if (num.type!=_POLY){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + polynome tmp(*num._POLYptr); + modularize(tmp,env->modulo); + f.push_back(facteur(tmp,it->mult)); + } + essaimax=0; + } + } + } // end for essaimoduloon?unmodularize(itfact):it->fact + ,n,env)); + if (is_undef(Qtry)){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + // and call sqff mod factor + vector< facteur > wf; + vector qmat; + // qmatrix(Qtry,env,qmat,0); + if (!ddf(Qtry,qmat,env,wf)){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + vector w; + if (!cantor_zassenhaus(wf,qmat,env,w)){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + // put result in f + vector::const_iterator jt=w.begin(),jtend=w.end(); + gen gtmp; + for ( ;jt!=jtend;++jt){ + polynome tmp(unmodularize(*jt)); + gtmp=env->moduloon?makemod(tmp,n):tmp; + if (gtmp.type==_POLY) + f.push_back(facteur(*gtmp._POLYptr,it->mult)); + } + } + // cleanup, set first coeff to 1 + factorization::iterator jt=f.begin(),jtend=f.end(); + for (;jt!=jtend;++jt){ + gen coeff=jt->fact.coord.front().value; + if (coeff.type==_MOD) + coeff = inv(coeff,context0); + jt->fact = coeff * jt->fact; + } + return true; + } + + factorization squarefree_fp(const polynome & p,unsigned n,unsigned exposant){ + factorization res(uncompressed_squarefree_fp(p,n,exposant)); + factorization_compress(res); + return res; + } + + // p is primitive wrt the main var + bool mod_factor(const polynome & p_orig,polynome & p_content,int n,factorization & f){ + if (!is_probab_prime_p(n)) + return false; + environment env; + env.moduloon = true; + env.modulo=n; + env.pn=n; + // Check that all coeff are mod + polynome p(p_orig.dim); + vector< monomial >::const_iterator pit=p_orig.coord.begin(),pitend=p_orig.coord.end(); + for (;pit!=pitend;++pit){ + gen val0=pit->value; + if (val0.type!=_MOD) + val0=makemod(val0,n); + gen & tmp = *(val0._MODptr+1); + if (tmp.type!=_INT_ || tmp.val!=n){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + gen & val = *(val0._MODptr); + if (val.type==_CPLX) + env.complexe=true; + if (!is_zero(val)) + p.coord.push_back(monomial(val0,pit->index)); + } +#ifdef HAVE_LIBNTL +#ifdef HAVE_LIBPTHREAD + int locked=pthread_mutex_trylock(&ntl_mutex); +#endif // HAVE_LIBPTHREAD + if (p.dim==1 && !locked){ + bool res=true; +#ifndef NO_STDEXCEPT + try { +#endif + vecteur v; + if (p.dim!=1){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("gausspol.cc/mod_factor")); +#endif + return false; + } + if (p.coord.empty()){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + int deg=p.lexsorted_degree(); + int curpow=deg; + v.reserve(deg+1); + vector< monomial >::const_iterator ppit=p.coord.begin(); + vector< monomial >::const_iterator ppitend=p.coord.end(); + for (;ppit!=ppitend;++ppit){ + int newpow=ppit->index.front(); + for (;curpow>newpow;--curpow) + v.push_back(0); + if (ppit->value.type==_INT_) + v.push_back(ppit->value); + if (ppit->value.type==_MOD) + v.push_back(*ppit->value._MODptr); + --curpow; + } + for (;curpow>-1;--curpow) + v.push_back(0); + // FIXME NTL works on monic polynomials only!! + gen v0=v.front(); + if (!is_one(v0)){ + p_content = p_content*v0; + v0=invmod(v0,gen(n)); + v = operator_times(v,v0,&env); + } + if (n==2){ + NTL::GF2X ntlf(modpoly2GF2X(v)); + NTL::vec_pair_GF2X_long fres(NTL::CanZass(ntlf,0)); + int s=fres.length(); + for (int i=0;i(*makemod(unmodularize(res),2)._POLYptr,fres[i].b)); + } + } + else { + NTL::ZZ_p::init(inttype2ZZ(n)); + NTL::ZZ_pX ntlf(modpoly2ZZ_pX(v)); + NTL::vec_pair_ZZ_pX_long fres(NTL::CanZass(ntlf,0)); + int s=fres.length(); + for (int i=0;i(*makemod(unmodularize(res),n)._POLYptr,fres[i].b)); + } + } +#ifndef NO_STDEXCEPT + } catch (std::runtime_error & e){ + res=false; + } +#endif +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&ntl_mutex); +#endif + return res; + } // end !locked +#endif + // sqff + factorization sqff_f(squarefree_fp(p,n,1)); + if (!sqff_ffield_factor(sqff_f,n,&env,f)) + return false; + factorization_compress(f); + // cleanup cst coeff + gen coeff(1); + factorization::iterator it=f.begin(),itend=f.end(); + for (;it!=itend;++it){ + coeff=coeff*pow(it->fact.coord.front().value,it->mult,context0); + } + coeff=p.coord.front().value/coeff; + p_content=coeff*p_content; + return true; + } + + // factorization over an algebraic extension + // the main variable of G is the algebraic extension variable + // the minimal polynomial of this variable is p_mini + // G is assumed to be square-free + // See algorithm 3.6.4 in Henri Cohen book starting at step 3 + // Gtry is non 0 if algfactor has detected a possible factor + bool algfactor(const polynome & G,const polynome & p_mini,int & k,factorization & f,bool complexmode,gen & extra_div,polynome & Gtry){ + // search sqff norm + polynome norme(G.dim),temp(G.dim),p_mini1(p_mini); + p_mini1.reorder(transposition(0,1,G.dim)); + p_mini1=p_mini1.trunc1(); + k=-1; + for (;;) { + ++k; + // replace X by X-k*Y in G and _compute resultant + if (k){ + vecteur v; + polynome2poly1(G,2,v); // X is the second var + polynome decal(G.dim-1); + decal.coord.push_back(monomial(gen(-k),1,G.dim-1)); // -k*main_var + v=taylor(v,decal); + poly12polynome(v,2,temp,G.dim); + // take remainder otherwise algnorme is too slow + temp = temp % p_mini; + if (!algnorme(temp,p_mini,norme)) + norme=resultant(temp,p_mini).trunc1(); + } + else { +#if 0 // IMPROVE: find a good criterion to enable! + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " sylvester resultant begin" << '\n'; + vecteur Gv(polynome2poly1(G,1)),p_miniv(polynome2poly1(p_mini,1)); + matrice S=sylvester(p_miniv,Gv); + S=mtran(S); + gen g=det_minor(S,vecteur(0),false,context0); + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " sylvester resultant end" << '\n'; + if (g.type==_POLY) + norme=*g._POLYptr; + else +#endif + norme=resultant(G,p_mini).trunc1(); + } + if (gcd(norme,p_mini1).lexsorted_degree()) + continue; + // check that norme is squarefree, first find inner dimension + polynome dnorme=norme.derivative(); + int innerdim=0; + vector< monomial >::const_iterator ckalg_it=norme.coord.begin(),ckalg_itend=norme.coord.end(); + for (; ckalg_it!=ckalg_itend;++ckalg_it){ + if (ckalg_it->value.type==_POLY){ + innerdim=ckalg_it->value._POLYptr->dim; + break; + } + } + // convert to usual multivariate polynomials + polynome N(unsplitmultivarpoly(norme,innerdim)),Np(unsplitmultivarpoly(norme.derivative(),innerdim)); + polynome GG=gcd(N,Np); + if (!GG.lexsorted_degree()){ + break; + } + else { + if (k==0 && innerdim==0 && !Gtry.coord.empty()){ + factorization ftry=sqff(GG); + int extdeg=p_mini.lexsorted_degree(); + GG=polynome(monomial(plus_one,0,Gtry.dim)); + for (int i=0;i(*tmp_it,d,1,p_mini.dim)); + } + } + + // add a dimension in front of pcur for algebraic extension variable + bool algext_convert(const polynome & pcur,const gen & e,polynome & p_y){ + p_y.dim=pcur.dim+1; + vector< monomial >::const_iterator p_it=pcur.coord.begin(),p_itend=pcur.coord.end(); + for (;p_it!=p_itend;++p_it){ + if (p_it->value.type!=_EXT){ + p_y.coord.push_back(p_it->untrunc1()); + continue; + } + if (*(p_it->value._EXTptr+1)!=*(e._EXTptr+1)){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Factor: Only one algebraic extension allowed")); +#endif + return false; + } + // convert the polynomial of the algebraic extension generator + index_t ii=p_it->index.iref(); + ii.insert(ii.begin(),0); + p_y=p_y+poly1_2_polynome(*(p_it->value._EXTptr->_VECTptr),p_y.dim).shift(ii); + } + // p_y=p_y/Tcontent(p_y); + return true; + } + + static bool do_factor(const polynome &p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div); + + bool has_embedded_poly(const polynome & p){ + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (it->value.type==_POLY) + return true; + } + return false; + } + + bool ext_factor_nodegck(const polynome &p,const gen & e,gen & an,polynome & p_content,factorization & f,bool complexmode,gen & extra_div){ + if (e._EXTptr->type!=_VECT){ +#ifndef NO_STDEXCEPT + settypeerr(gettext("Modular factorization not yet accessible")); +#endif + return false; + } + gen ip=im(p,context0); + bool ip0=is_zero(ip); + if (!ip0 || complexmode){ + gen anreal(an),extra_divreal(extra_div); factorization freal; polynome p_contentreal(p_content); + if (ip0 && !ext_factor(p,e,anreal,p_contentreal,freal,false,extra_divreal)) + return false; + // replace i by [1,0]:[1,0,1] + gen bn=1,the_ext=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,1)); + gen newp=re(p,context0)+the_ext*ip; + if (newp.type!=_POLY) + return false; + vector< monomial >::iterator it=newp._POLYptr->coord.begin(),itend=newp._POLYptr->coord.end(); + for (;it!=itend;++it){ + if (it->value.type==_EXT) + it->value=ext_reduce(it->value); + if (it->value.type==_FRAC && it->value._FRACptr->num.type==_EXT) + it->value=ext_reduce(it->value._FRACptr->num)/it->value._FRACptr->den; + } + lcmdeno(*newp._POLYptr,bn); + newp=bn*newp; + for (it=newp._POLYptr->coord.begin(),itend=newp._POLYptr->coord.end();it!=itend;++it){ + if (it->value.type==_EXT){ + if (the_ext.type==_EXT){ + common_EXT(*(it->value._EXTptr+1),*(the_ext._EXTptr+1),0,context0); + the_ext=ext_reduce(the_ext); + if (the_ext.type==_FRAC) + the_ext=the_ext._FRACptr->num; + } + else + the_ext=it->value; + } + } + if (e.type==_EXT){ + gen ee=*(e._EXTptr+1); + common_EXT(ee,*(the_ext._EXTptr+1),0,context0); + the_ext=ext_reduce(the_ext); + if (the_ext.type==_FRAC) + the_ext=the_ext._FRACptr->num; + } + for (it=newp._POLYptr->coord.begin();it!=itend;++it){ + if (it->value.type==_EXT) + it->value=ext_reduce(it->value); +#if 1 // added for f:=(-40*a_t^4*6*sqrt(6)+100*a_t^4*6+230*a_t^4*sqrt(6)-576*a_t^4-20*i*a_t^3*sqrt(-(2*sqrt(6))^2+25)*6-(-100*i)*a_t^3*sqrt(-(2*sqrt(6))^2+25)*sqrt(6)-120*i*a_t^3*sqrt(-(2*sqrt(6))^2+25)-20*i*a_t*sqrt(-(2*sqrt(6))^2+25)*6-(-100*i)*a_t*sqrt(-(2*sqrt(6))^2+25)*sqrt(6)-120*i*a_t*sqrt(-(2*sqrt(6))^2+25)+40*6*sqrt(6)-100*6-230*sqrt(6)+576)/(198*sqrt(6)-485);g:=factor(f);normal(f-g); + if (it->value.type==_EXT){ + if (the_ext.type==_EXT) + common_EXT(*(it->value._EXTptr+1),*(the_ext._EXTptr+1),0,context0); + it->value=ext_reduce(it->value); + the_ext=ext_reduce(the_ext); + if (the_ext.type==_FRAC) + the_ext=the_ext._FRACptr->num; + } +#endif + } + gen bn2=1; + lcmdeno(*newp._POLYptr,bn2); + mulpoly(*newp._POLYptr,bn2,*newp._POLYptr); // newp=bn2*newp; + if (the_ext.type!=_EXT) + return false; + bool res=ext_factor(*newp._POLYptr,the_ext,an,p_content,f,false,extra_div); + if (f.size()==freal.size()){ + an=anreal; + p_content=p_contentreal; + f=freal; + extra_div=extra_divreal; + return true; + } + an=an/(bn*bn2); + return res; + } + an=p.coord.front().value; + factorization fsqff=sqff(p); + // factorization of each factor of fsqff + factorization fz; + factorization::const_iterator it=fsqff.begin(),itend=fsqff.end(); + for (;it!=itend;++it){ + polynome pcur=it->fact; + gen tmp1(1); lcmdeno(pcur,tmp1); + pcur=tmp1*pcur; + // normalize leading term + if (pcur.coord.front().value.type==_EXT){ + gen pcur0=inv_EXT(pcur.coord.front().value),num,den; + fxnd(pcur0,num,den); + pcur=num*pcur; + } + int mult=it->mult; + int d=pcur.lexsorted_degree(); + if (!d) + continue; + if (d==1){ + an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0); + f.push_back(facteur(pcur,mult)); + continue; + } + // make a polynomial with 1 more variable: the extension + vecteur v_mini; + if ((e._EXTptr+1)->type==_VECT) + v_mini=*((e._EXTptr+1)->_VECTptr); + else { +#ifndef NO_STDEXCEPT + settypeerr(gettext("To be implemented")); +#endif + return false; + } + // const_iterateur v_it,v_itend=v_mini.end(); + polynome p_y(p.dim+1); + // polynome p_mini(poly12polynome(v_mini)); + // p_mini=p_mini.untrunc(0,2); + // p_mini.reorder(transposition(0,1,2)); + // polynome p_mini(poly12polynome(v_mini,1,p.dim+1)); + polynome p_mini(p.dim+1); + algext_vmin2pmin(v_mini,p_mini); + if (!algext_convert(pcur,e,p_y)) + return false; +#if defined HAVE_LIBPARI && !defined(WIN32) // otherwise factor(x^4-4,sqrt(2)) segfault on cygwin32 + gen coefft; + if (p_y.dim==2 && p_y.degree(1)>=4 && !complexmode && coefftype(p_y,coefft)<_POLY && coefftype(p_mini,coefft)<_POLY){ + int dim=p_y.dim; + vecteur lv=makevecteur(y__IDNT_e,x__IDNT_e); + gen P=r2sym(p_y,lv,context0),Pmini=r2sym(p_mini,lv,context0),res; + swapgen(lv[0],lv[1]); + // call changed in pari.cc to nffactor() without nfinit() + // y^16-2204*y^15+3708732*y^14-2224018932*y^13+7601236038322*y^12-16871353226971624*y^11+11785784895214530912*y^10+14512858706664248868684*y^9-28159800647990521512088725*y^8+22629180037206015783743082216*y^7-4503073664215964343024123764736*y^6-18033250417520024351996412301581172*y^5+36809629124123557233363574360979382082*y^4-26522074490260067527688235446457244110348*y^3+5261395505608051233271161218542638549351612*y^2+1568113413809748536593336025794328431775552560*y+284494252767223281126819740714222484913944245281 + // generated by normal(rootof([[468,-1072,3680,-5865,9664,-7886,2040,1515],[1,-2,7,-10,16,-10,-2,4,1]])+sqrt(rootof([[555066,-1338975,4229538,-7124970,10786458,-9150474,798516,2168328],[1,-2,7,-10,16,-10,-2,4,1]]))) + // or A:=[[1,0,0],[rootof([[1,0,0],[1,-1,1,-1,1]]),rootof([[-1,1,-1,1],[1,-1,1,-1,1]]),rootof([[1,0,0],[1,-1,1,-1,1]])],[rootof([[1,0,1,-1],[1,-1,1,-1,1]]),rootof([[1,0],[1,-1,1,-1,1]]),0]];jordan(A); + // takes forever for pari nfinit0 + if (pari_nffactor(P,Pmini,lv,res,context0) && res.type==_VECT){ + vecteur v=*res._VECTptr; + unsigned j=0; + lv=vecteur(1,vecteur(1,lv[0])); + int fpos=f.size(); + for (;jsize()!=2) + break; + int mult=res._VECTptr->back().val; + res=res._VECTptr->front(); + if (res.is_symb_of_sommet(at_plus) && res._SYMBptr->feuille.type==_VECT && res._SYMBptr->feuille._VECTptr->size()==2 && res._SYMBptr->feuille._VECTptr->front()==x__IDNT_e + ){ + res=res._SYMBptr->feuille._VECTptr->back(); + gen den=1; + if (res.is_symb_of_sommet(at_prod) && res._SYMBptr->feuille.type==_VECT && res._SYMBptr->feuille._VECTptr->size()==2){ + den=res._SYMBptr->feuille._VECTptr->back(); + if (den.is_symb_of_sommet(at_inv)) + den=den._SYMBptr->feuille; + else + den=undef; + res=res._SYMBptr->feuille._VECTptr->front(); + } + if (!is_integer(den) || !res.is_symb_of_sommet(at_rootof)) + break; + res=res._SYMBptr->feuille; + res=algebraic_EXTension(res[0],change_subtype(res[1],0))/den; + polynome p(1); + p.coord.push_back(monomial(1,1,1,1)); + p.coord.push_back(monomial(res,0,1,1)); + f.push_back(facteur(p,mult)); + continue; + } else + break; // res=sym2r(res,lv,context0); // FIXME, might recurse + if (res.type==_FRAC) + res=res._FRACptr->num; + if (res.type!=_POLY) + continue; + // ? unitarize res + *res._POLYptr=*res._POLYptr/res._POLYptr->coord.front().value; + f.push_back(facteur(*res._POLYptr,mult)); + } + if (j==v.size()){ //adjust an + factorization::const_iterator f_it=f.begin(),f_itend=f.end(); + for (;f_it!=f_itend;++f_it){ + an=rdiv(an,pow(f_it->fact.coord.front().value,gen(f_it->mult),context0),context0); + } + continue;// return true; + } + else + f.erase(f.begin()+fpos,f.end()); + } + } +#endif + int k; + polynome Gtry; + // polynome Gtry(pcur); + // does not work if trying to factor a rational poly over an extension + if (!algfactor(p_y,p_mini,k,fz,false,extra_div,Gtry)) + return false; + if (!Gtry.coord.empty()){ + // pcur is square free, multiplicities in ftry and fz should be 1 + polynome ptmp(pcur/Gtry); + gen antmp; + if (!ext_factor(ptmp,e,antmp,p_content,fz,false,extra_div)) + return false; + factorization ftry; + polynome Gcontent(pcur.dim); + if (!do_factor(Gtry,Gcontent,ftry,true,false,false,1,extra_div)) + return false; + for (int i=0;ifact; + // unitarize pcur + pcur=pcur/pcur.coord.front().value; + f.push_back(facteur(pcur,mult)); + } + continue; + } + factorization::const_iterator f_it=fz.begin(),f_itend=fz.end(); + if (f_itend-f_it==1){ // irreducible (after sqff) + an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0); + f.push_back(facteur(pcur,mult)); + } + else { + gen bn(1); + polynome pcopy(pcur); + bool embedded_poly=has_embedded_poly(p_mini); + for (;f_it!=f_itend;++f_it){ + if (k){ // shift f_it->fact + //vecteur v=polynome2poly1(f_it->fact); + vecteur v; polynome2poly1(f_it->fact,1,v); + vecteur decalv(2,zero); + decalv[0]=k; + gen decal=algebraic_EXTension(decalv,v_mini); + v=taylor(v,decal); + // pcur=poly12polynome(v); + poly12polynome(v,1,pcur,f_it->fact.dim); + if (embedded_poly) + pcur=gcd(pcur,pcopy); + else { + // fix it for normal(sqrt(a*pi)/(2*sqrt(a)*sqrt(pi))); + // dcur might have denominators inside + if (f_it+1==f_itend){ + pcur=pcopy; + } + else { + polynome dcur=simplify(pcur,pcopy); + dcur.coord.swap(pcur.coord); + gen t; + lcmdeno(pcopy,t); + } + } + } + else { + if (embedded_poly) + pcur=gcd(f_it->fact,p); + else { + if (f_it+1==f_itend){ + pcur=pcopy; + } + else { + polynome fcopy(f_it->fact); + polynome dcur=simplify(fcopy,pcopy); + dcur.coord.swap(pcur.coord); + gen t; + lcmdeno(pcopy,t); + } + } + } + // unitarize pcur instead of computing bn + pcur=pcur/pcur.coord.front().value; + // bn=bn*pow(pcur.coord.front().value,gen(mult)); + f.push_back(facteur(pcur,mult)); + } + an=rdiv(an,bn,context0); + } + } // end for (;it!=itend;) + return true; + } + + bool ext_factor(const polynome &p,const gen & e,gen & an,polynome & p_content,factorization & f,bool complexmode,gen & extra_div){ + if (e.type==_EXT && (e._EXTptr+1)->type==_EXT){ + gen E=ext_reduce(e); + polynome P(p); + vector< monomial >::iterator it=P.coord.begin(),itend=P.coord.end(); + for (;it!=itend;++it){ + if (it->value.type==_EXT) it->value=ext_reduce(it->value); + } + return ext_factor(P,E,an,p_content,f,complexmode,extra_div); + } + if (!ext_factor_nodegck(p,e,an,p_content,f,complexmode,extra_div)) + return false; + // additional check that degrees match + int pdeg=p.lexsorted_degree(),sumdeg=0; + for (size_t i=0;i1) + v.push_back(tmp); + else { + vecteur w=polynome2poly1(tmp,1); + gen a=w.front(),b=w[1],c=w[2]; + gen delta=4*a*c-b*b,deltaf; + if ( !complexmode && has_evalf(delta,deltaf,1,context0) && is_positive(deltaf,context0)){ + v.push_back(tmp); + return; + } + gen b_over_2=rdiv(b,plus_two,context0); + if (b_over_2.type!=_FRAC){ + delta=a*c-b_over_2*b_over_2; + gen un=plus_one; + if (is_positive(delta,context0)){ + un=cst_i; + delta=-delta; + } + vecteur vv(makevecteur(plus_one,rdiv(algebraic_EXTension(makevecteur(un,b_over_2),makevecteur(plus_one,zero,delta)),a,context0))); + v.push_back(poly12polynome(vv,1)); + vv=makevecteur(1,algebraic_EXTension(makevecteur(-un,b_over_2),makevecteur(plus_one,zero,delta))/a); + v.push_back(a*poly12polynome(vv,1)); + } + else { + gen un=plus_one; + if (is_positive(delta,context0)){ + un=cst_i; + delta=-delta; + } + vecteur vv(makevecteur(plus_one,rdiv(algebraic_EXTension(makevecteur(un,b),makevecteur(plus_one,zero,delta)),2*a,context0))); + v.push_back(poly12polynome(vv,1)); + vv=makevecteur(1,rdiv(algebraic_EXTension(makevecteur(-un,b),makevecteur(plus_one,zero,delta)),2*a,context0)); + v.push_back(a*poly12polynome(vv,1)); + } + } + } + + bool cfactor(const polynome & p, gen & an,factorization & f,bool with_sqrt,gen &extra_div){ + an=p.coord.front().value; + if (has_num_coeff(p) && p.dim==1){ + vectpoly w; + if (!sqfffactor(p,w,false,false,true)) + return false; + vectpoly::const_iterator itw=w.begin(),itwend=w.end(); + for (;itw!=itwend;++itw) + f.push_back(facteur(*itw,1)); + return true; + } + factorization fsqff=sqff(p); + // factorization of each factor of fsqff + factorization fz; + factorization::const_iterator it=fsqff.begin(),itend=fsqff.end(); + for (;it!=itend;++it){ + polynome pcur=it->fact; + int mult=it->mult; + int d=pcur.lexsorted_degree(); + if (!d) + continue; + if (d==1){ + an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0); + f.push_back(facteur(pcur,mult)); + continue; + } + // make a polynomial with 1 more variable (i) + polynome p_y(im(pcur).untrunc1(1)+re(pcur).untrunc1()); + polynome p_mini(p_y.dim); + p_mini.coord.push_back(monomial(1,1,p_y.dim)); + p_mini=p_mini.multiplydegrees(2); + p_mini.coord.push_back(monomial(1,0,p_y.dim)); + int k; + polynome Gtry; + if (!algfactor(p_y,p_mini,k,fz,false,extra_div,Gtry)) + return false; + factorization::const_iterator f_it=fz.begin(),f_itend=fz.end(); + for (;f_it!=f_itend;++f_it){ + if (k){ // shift f_it->fact + vecteur v; + polynome2poly1(f_it->fact,1,v); + gen decal=polynome(gen(0,k),f_it->fact.dim-1); + v=taylor(v,decal); + poly12polynome(v,1,pcur,f_it->fact.dim); + pcur=gcd(pcur,p); + } + else + pcur=gcd(f_it->fact,p); + an=rdiv(an,pow(pcur.coord.front().value,gen(mult),context0),context0); + vectpoly tmpv; + addtov(pcur,tmpv,with_sqrt,true); + f.push_back(facteur(tmpv[0],mult)); + if (tmpv.size()==2) + f.push_back(facteur(tmpv[1],mult)); + } + } + return true; + } + + // factorize a square-free univariate polynomial + bool sqfffactor(const polynome &p, vectpoly & v,bool with_sqrt,bool test_composite,bool complexmode){ + if (debug_infolevel>5) + CERR << "Begin sqfffactor" << p << '\n'; + // test if p has a numeric coeff + if (has_num_coeff(p)){ + vecteur w=polynome2poly1(p,1); + w=proot(w,context0); + if (is_undef(w)) + return false; + const_iterateur it=w.begin(),itend=w.end(); + polynome res(1),res2(1); + res.coord.push_back(monomial(1,index_t(1,1))); + res2.coord.push_back(monomial(1,index_t(1,2))); + for (;it!=itend;++it){ + polynome copie(1); + gen impart=im(*it,context0); + if (!complexmode && !is_zero(impart) && (it+1)!=itend ){ + copie = res2; + gen repart=re(*it,context0); + copie.coord.push_back(monomial(-2*repart,index_t(1,1))); + copie.coord.push_back(monomial(repart*repart+impart*impart,index_t(1,0))); + ++it; + } + else { + copie = res; + if (!is_zero(*it)) + copie.coord.push_back(monomial(-(complexmode?*it:re(*it,context0)),index_t(1,0))); + } + v.push_back(copie); + } + return true; + } + int d; + // special speedup for x^n +/- 1 + if (p.coord.size()==2 && p.coord.front().value==1 && is_zero(p.coord.back().index.iref())){ + d=p.lexsorted_degree(); + if (p.coord.back().value==-1){ + // product of cyclotomic(n) where n divides d + gen dd=idivis(d,context0); + if (dd.type==_VECT){ + const_iterateur it=dd._VECTptr->begin(),itend=dd._VECTptr->end(); + for (;it!=itend;++it){ + if (with_sqrt){ + if (it->val==5 || it->val==10){ + gen e=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,-5)); + gen f=it->val==5?1:-1; + addtov(poly12polynome(makevecteur(1,(f-e)/2,1),1),v,false,false); + addtov(poly12polynome(makevecteur(1,(f+e)/2,1),1),v,false,false); + continue; + } + if (it->val==8){ + gen e=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,-2)); + addtov(poly12polynome(makevecteur(1,e,1),1),v,false,false); + addtov(poly12polynome(makevecteur(1,-e,1),1),v,false,false); + continue; + } + } + polynome tmp=poly12polynome(cyclotomic(it->val),1); + addtov(tmp,v,with_sqrt,complexmode); + } + return true; + } + } +#ifndef EMCC + if (d%4==0 && with_sqrt){ + gen e=algebraic_EXTension(makevecteur(1,0),makevecteur(1,0,-2)); + gen an=1,extra_div=1; + factorization f; + polynome p_content(p.dim); + if (ext_factor(p,e,an,p_content,f,complexmode,extra_div) && an==1 && extra_div==1){ + for (size_t i=0;ibegin(),itend=dd._VECTptr->end(); + for (;it!=itend;++it){ + polynome tmp=poly12polynome(cyclotomic(it->val),1); + addtov(tmp,v,with_sqrt,complexmode); + } + return true; + } + } + } + // find the gcd of the degrees of *it + if (test_composite) + d=p.gcddeg(0); + else + d=1; + if (debug_infolevel>5) + CERR << "sqfffactor gcddeg " << d << '\n'; + if (d<=1){ + // find linear factors now! + environment * env=new environment; + polynome temp(1); + int ithprime=1; + int bound=linearfind(p,env,temp,v,ithprime); + if (bound==0){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + // if degree of temp<=3, we are finished since not irred -> one fact + // has degree 1 (hence found previously) + int tempdeg=temp.lexsorted_degree(); + if (debug_infolevel>5) + CERR << "sqfffactor after linearfind " << temp << '\n'; + if (tempdeg1?debug_infolevel:0),MODFACTOR_PRIMES)){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + vectpoly::const_iterator itw=w.begin(),itwend=w.end(); + for (;itw!=itwend;++itw){ + addtov(*itw,v,with_sqrt,complexmode); + } + if (signe==-1) + v.back()=-v.back(); + } + delete env; + } + else { // gcddeg!=1, take the largest divisor of d + //if (p.coord.size()==2){ + gen dd(d); + vector nv(trivial_n_factor(dd)); + if (dd==gen(1)) + d=nv[nv.size()-1].fact.to_int(); + else + d=dd.to_int(); + //} + // use x^d as new variable, divide every degree by d + if (d==p.lexsorted_degree()) + return sqfffactor(p,v,with_sqrt,false,complexmode); + polynome q(p.dividedegrees(d)); + vectpoly w; + // IMPROVE: if we factor allowing 2nd order poly roots + // we could factor bisquare poly + // BUT that requires converting the roots to internal form + if (!sqfffactor(q,w,false,true,complexmode)) + return false; + vectpoly::const_iterator itw=w.begin(),itwend=w.end(); + for (;itw!=itwend;++itw){ + if (!sqfffactor(itw->multiplydegrees(d),v,with_sqrt,false,complexmode)) + return false; + } + } + return true; + } + + bool has_gf_coeff(const polynome & p,gen & modulo){ +#ifdef RTTI + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (it->type==_USER){ + if (galois_field * ptr=dynamic_cast(it->_USERptr)){ + modulo=ptr->p; + return true; + } + } + } +#endif + return false; + } + + factorization sqff(const polynome &p ){ + factorization f; gen m; + if ( (has_mod_coeff(p,m) || has_gf_coeff(p,m)) && m.type==_INT_){ + // otherwise it's like if char is 0 + f=squarefree_fp(p,m.val,1); + } + else + f=Tsqff_char0(p); + // take care of cst coefficients + if (!p.coord.empty()){ + gen p0=p.coord.front().value,p1(1); + for (unsigned i=0;i(polynome(p0,p.dim),1)); + else + f[0].fact = p0*f[0].fact; + } + } + return f; + } + + static bool sqff_evident_primitive(const polynome & pp,factorization & f,bool with_sqrt,bool complexmode){ + // first square-free factorization + +#if 0 // Cette version ne marche pas it->fact plus bas renvoie un vecteur vide.. ou quelquechose comme ca.. + const factorization & sqff_f = has_num_coeff(pp)?factorization(1,facteur< polynome >(pp,1)):sqff(pp); +#else // celle la, plus ancienne, marche... + factorization sqff_f; + if (has_num_coeff(pp)) + sqff_f.push_back(facteur< polynome >(pp,1)); + else + sqff_f=sqff(pp); +#endif + f.clear(); + if (pp.dim!=1){ + f=sqff_f; + return true; + } + factorization::const_iterator it=sqff_f.begin(); + factorization::const_iterator itend=sqff_f.end(); + vectpoly v; + for (;it!=itend;++it){ + v.clear(); + if (!sqfffactor(it->fact,v,with_sqrt,true,complexmode)) + return false; + f.reserve(f.size()+v.size()); + vectpoly::const_iterator itv=v.begin(),itvend=v.end(); + for (;itv!=itvend;++itv) + f.push_back(facteur(*itv,it->mult)); + } + return true; + } + + bool sqff_evident(const polynome & p,factorization & f,bool with_sqrt,bool complexmode){ + // first make p primitive + polynome pp=p/lgcd(p); + return sqff_evident_primitive(pp,f,with_sqrt,complexmode); + } + + /* Factorization of sqff unitary polynomial with variables in reverse order + Return number of factors, -1 if not successful + Might be called if polynomial is not unitary, but there is no + proof that unlimited tries succeed in this case */ + static int unitaryfactor(polynome & unitaryp, vectpoly & f,bool with_sqrt,bool complexmode){ + int dd=unitaryp.degree(unitaryp.dim-1); + if (!dd) + return 0; // unitaryp is cst w.r.t. x + if (dd==1){ + f.push_back(unitaryp); + unitaryp=unitaryp/unitaryp; + return 1; + } + if (unitaryp.dim==1){ + factorization ff; + if (!sqff_evident(unitaryp,ff,with_sqrt,complexmode)) + return -1; + if (f.empty()) + f.reserve(ff.size()); + factorization::const_iterator ff_it=ff.begin(),ff_end=ff.end(); + for (;ff_it!=ff_end;++ff_it) + f.push_back(ff_it->fact); + return int(ff.size()); + } + ppz(unitaryp); // remove content + gen n_2(2),np,n_73794(73794),n_27011(27011); + polynome quo(unitaryp.dim),rem(unitaryp.dim); + if (!listmax(unitaryp,np)) + return 0; + gen x0(n_2*np+n_2); + int ntry=0; + while (unitaryp.lexsorted_degree()){ + ntry++; + if (ntry>GCDHEU_MAXTRY) + return 0; + // find evaluation point such that evaluated poly is sqff + // pz is unitary w.r.t. last var hence has same degree and is primitive + polynome pz(unitaryp(x0)); + while (gcd(pz.derivative(),pz).lexsorted_degree()){ + x0=x0+gen(1); + pz=unitaryp(x0); + } + // factorization of pz + vectpoly fz; + int nf=unitaryfactor(pz,fz,with_sqrt,complexmode); + if (nf==-1) + return nf; + if (!nf) + return int(f.size()); + if (nf==1) { + f.push_back(unitaryp); + unitaryp=polynome(monomial(gen(1),0,unitaryp.dim)); + return int(f.size()); + } + // factorization fz into factorization f + vectpoly::iterator f_it=fz.begin(),f_itend=fz.end(); + for (;f_it!=f_itend;++f_it){ + *f_it=pzadic(*f_it,x0); + // try division, each factor found is necessarily irreducible + if ( (unitaryp.TDivRem1(*f_it,quo,rem)) && (rem.coord.empty())){ + unitaryp=quo; + f.push_back(*f_it); + } + } + x0=iquo(x0*n_73794,n_27011); // for the next try, if necessary + } + // factorize the cst term + vectpoly fz; + polynome tmp(unitaryp.trunc1()); + int nf=unitaryfactor(tmp,fz,with_sqrt,complexmode); + if (nf==-1) + return nf; + if (!nf) + return int(f.size()); + if (nf==1){ + f.push_back(unitaryp); + unitaryp=polynome(monomial(gen(1),0,unitaryp.dim)); + return int(f.size()); + } + vectpoly::iterator f_it=fz.begin(),f_itend=fz.end(); + for (;f_it!=f_itend;++f_it) + f.push_back(f_it->untrunc1()); + unitaryp=polynome(monomial(gen(1),0,unitaryp.dim)); + return int(f.size()); + } + + void unitarize(const polynome &pcur, polynome &unitaryp, polynome & an){ + an=firstcoeff(pcur).trunc1(); + if (is_one(an)){ + unitaryp=pcur; + return; + } + monomial_v::const_iterator it=pcur.coord.begin(); + monomial_v::const_iterator itend=pcur.coord.end(); + polynome curanpow(pow(an,0)); + int savpow=it->index.front(); + unitaryp=pow(polynome(monomial(gen(1),1,pcur.dim)),savpow); + savpow--; + int newpow; + Tnextcoeff(it,itend); // ++it; + for (;it!=itend;){ + newpow=it->index.front(); + polynome an_1=Tnextcoeff(it,itend); + curanpow=curanpow*pow(an,savpow-newpow); + unitaryp=unitaryp+(an_1*curanpow).untrunc1(newpow); + savpow=newpow; + } + } + + polynome ununitarize(const polynome & unitaryp, const polynome & an){ + if (is_one(an)) + return unitaryp; + monomial_v::const_iterator it=unitaryp.coord.begin(); + monomial_v::const_iterator itend=unitaryp.coord.end(); + int curpow; + polynome ppush(unitaryp.dim); + for (;it!=itend;){ + curpow=it->index.front(); + polynome an_1=Tnextcoeff(it,itend); + ppush=ppush+(an_1*pow(an,curpow)).untrunc1(curpow); + } + return ppush/lgcd(ppush); + } + + static bool do_factor_hensel(const polynome &p,polynome& p_primit,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div,bool hensel_only){ + if (p.dim==1){ + // FIXME: if p_primit has num coeffs, we must check the leading coeff + // and adjust p_content + if (has_num_coeff(p_primit)){ + gen an=p_primit.coord.front().value; + p_content=an*p_content; + vector< monomial >::iterator it=p_primit.coord.begin(),itend=p_primit.coord.end(); + for (;it!=itend;++it) + it->value=evalf(it->value/an,1,context0); + } + return sqff_evident_primitive(p_primit,f,with_sqrt,complexmode); + } + // extract powers of indeterminates + index_t mindeg=p_primit.coord.back().index.iref(); + vector< monomial >::const_iterator pt=p_primit.coord.begin(),ptend=p_primit.coord.end(); + for (;pt!=ptend;++pt){ + mindeg=index_min(mindeg,pt->index.iref()); + if (is_zero(mindeg)) + break; + } + // square-free factorization + factorization fsqff; + if (!is_zero(mindeg)){ + p_primit=p_primit.shift(-mindeg); + fsqff=sqff(p_primit); + for (int i=0;i(monomial(1,i+1,p.dim),mindeg[i])); + } + } + else + fsqff=sqff(p_primit); + // factorization of each factor of fsqff + /* + First of course square free factorization, then try a few (2) random values for all indeterminates except the first one, for a fast check of irreducibility. If not, lift the equality in one variable + P(x,0,...0)=product P_i(x,0,...,0) + more precisely, one must take care of the leading coefficient, hence lift + P*lcoeff(P)^(#nfactors-1)=product P_i + where in P_i the leading coefficient is replaced by lcoeff(P). + In order to avoid densification (if lcoeff(P) has many coefficients), I make a bivariate factorization, this way instead of using lcoeff(P) for every P_i, I'm using a divisor of lcoeff(P). It's a little different from what is describe in the thesis of Bernardin (I don't make polynomial rational reconstructions for example). + There is also a try to do sparse factorization before. + If Hensel lift does not work (for example P(x,0...0) loose degree or has non square-free factors), I'm using "heuristic factorization", i.e. evaluate P at x>=2 linfnorm(P)+2, factor this polynomial, reconstruct factors (using x as basis and symmetric remainder) and check division, if remainder is 0 an irreducible factor has been found, otherwise try with a larger value of x. + The corresponding code slices are in ezgcd.cc try_sparse_factor and try_hensel_lift_factor, and do_factor in gausspol.cc. + */ + factorization::const_iterator it=fsqff.begin(),itend=fsqff.end(); + for (;it!=itend;++it){ + polynome pcur=it->fact; + int mult=it->mult; + if (has_num_coeff(pcur)){ + f.push_back(facteur(pcur,mult)); + continue; + } + // try first 2 good evaluations in case pcur is irreducible + vecteur b(pcur.dim-1),b0; + factorization v,v0; + polynome Fb(1),Gb(1),F0; + int essai,nfactbound=RAND_MAX; + for (essai=0;essai<2;++essai){ + if (essai) + b=vranmnot0(pcur.dim-1); // find another random point + find_good_eval(pcur,pcur,Fb,Gb,b,(debug_infolevel>=2)); + factor(Fb,Gb,v,false,false,false,1,extra_div); + if (!essai){ + F0=Fb; + v0=v; + b0=b; + } + if ( (v.size()==1) && (v.front().mult==1) ) + break; + factorization::const_iterator it=v.begin(),itend=v.end(); + int nfact=0; + for (;it!=itend;++it) + nfact += it->mult; + if (0 && essai && nfactbound>nfact){ + nfactbound=nfact; + F0=Fb; + v0=v; + b0=b; + } + nfactbound=giacmin(nfactbound,nfact); + } + if (essai<2){ + f.push_back(facteur(pcur,mult)); + continue; + } + // check if pcur is a homogeneous polynomial + if (sum_degree(pcur.coord.back().index)){ + int xdeg=sum_degree(pcur.coord.back().index); + vector< monomial >::iterator it=pcur.coord.begin(),itend=pcur.coord.end(); + for (;it!=itend;++it){ + if (sum_degree(it->index)!=xdeg){ + break; + } + } + if (it==itend){ + // set x[j]=x[0]*x[j] for all vars, divide by x[0]^xdeg, + // remove old x[0] variable + polynome pcurh(pcur.trunc1()); + pcurh.tsort(); + // factor it + polynome pcur_cont; + factorization pcur_f,ppcur_f; + do_factor(pcurh,pcur_cont,pcur_f,false,with_sqrt,complexmode,1,extra_div); + // factorize (recursivly) pcur_cont + for (int innerdim=1;innerdim(tmp,ppcur_f[i].mult)); + } + } + if (pcur_f.size()==1){ + f.push_back(facteur(pcur,mult)); + continue; + } + // for each factor multiply by x[0]^degree in x[j] of factor, + // and set x[j]=x[j]/x[0], and put in v + for (unsigned i=0;iindex)); + it=P.coord.begin(); + for (;it!=itend;++it){ + index_t idx=it->index.iref(); + idx.insert(idx.begin(),jdeg-sum_degree(idx)); + it->index=idx; + } + P.tsort(); + P.dim=pcur.dim; + // adjust sign + if (is_strictly_positive(-P.coord.front().value,context0)) + P=-P; + f.push_back(facteur(P,mult)); + } + continue; + } // end homogeneous poly + } // end if (sum_degrees(...) + if (try_sparse_factor(pcur,v,mult,f)) + continue; + if (try_sparse_factor_bi(pcur,mult,f)) + continue; + /* Try Hensel lift factorization */ + bool hensel_factored=false; + for (unsigned hensel_try=0;hensel_try<5;++hensel_try){ + gen lm; + if (!listmax(p,lm)) + lm=100; + if (p.dim>2 && !is_zero(b0) && is_greater(lm,10,context0)){ + int b0d=int(b0.size()); + // search a smaller b + for (int essai=0;essai<3;++essai){ + for (int i=0;i=2))){ + b0=b; + break; + } + } + // translate + vecteur vb0(b0d+1),vb1(b0d+1),lv(b0d+1); + lv[0]=gen("x0",context0); + vb0[0]=sym2r(lv[0],lv,context0); + vb1[0]=vb0[0]; + for (int i=1;i<=b0d;i++){ + lv[i]=gen("x"+print_INT_(i),context0); + vb0[i]=sym2r(lv[i]+b0[i-1],lv,context0); + vb1[i]=sym2r(lv[i]-b0[i-1],lv,context0); + } + gen pb=peval(pcur,vb0,0,false),num,den; + fxnd(pb,num,den); + if (num.type!=_POLY){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + polynome ptrans=*num._POLYptr; + factorization ftrans; + b=vecteur(b.size()); + find_good_eval(ptrans,ptrans,Fb,Gb,b,(debug_infolevel>=2)); + if (is_zero(b)){ + factor(Fb,Gb,v0,false,false,false,1,extra_div); + if (int(v0.size())<2*nfactbound && try_hensel_lift_factor(ptrans,Fb,v0,mult,ftrans)){ + factorization::const_iterator it=ftrans.begin(),itend=ftrans.end(); + for (;it!=itend;++it){ + pb=peval(it->fact,vb1,0,false); + fxnd(pb,num,den); + if (num.type!=_POLY){ +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; + } + f.push_back(facteur(*num._POLYptr,it->mult)); + } + hensel_factored=true; + break; // break loop on hensel_try + } + } + } + } // end loop on hensel_try + if (hensel_factored) + continue; + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " hensel lift factor begin" << '\n'; + if (is_zero(b0) && int(v0.size())<2*nfactbound && try_hensel_lift_factor(pcur,F0,v0,mult,f)){ + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " hensel lift factor success" << '\n'; + continue; + } + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " hensel lift factor failure" << '\n'; + if (hensel_only) + return false; + /* Now try heuristic factorization then call unitaryfactor + on each found factor */ + vectpoly fz; + pcur.reverse(); + unitaryfactor(pcur,fz,false,false); + pcur.reverse(); + vectpoly::iterator f_it=fz.begin(),f_itend=fz.end(); + for (;f_it!=f_itend;++f_it){ + f_it->reverse(); + // if an!=1, P(Y)=P(a_n*X) and divide by content + f.push_back(facteur(*f_it,mult)); + } + if (!is_one(pcur)){ + /* now make polynomial unitary with respect to last var + P(x)=a_n*x^n+...+a_0, x=X/a_n, + P(x)=Q(X)=1/a_n^(n-1) * [ X^n+ a_{n-1}*a_n X^(n-1)+...+ a_0*a_n^{n-1}] + */ + fz.clear(); + polynome unitaryp(p.dim),an(p.dim-1); + unitarize(pcur,unitaryp,an); + // rewrite variables in inverted order + unitaryp.reverse(); + // and call unitaryfactor + if (unitaryfactor(unitaryp,fz,false,false)==-1) + return false; + // rewrite back variables in initial order for each polynomial + // and push back factorization + f_it=fz.begin(),f_itend=fz.end(); + for (;f_it!=f_itend;++f_it){ + f_it->reverse(); + // if an!=1, P(Y)=P(a_n*X) and divide by content + f.push_back(facteur(ununitarize(*f_it,an),mult)); + } + } + } + // adjust lcoeff + if (!p_content.coord.empty()){ + gen lc(1); + for (it=f.begin(),itend=f.end();it!=itend;++it){ + lc=lc*pow(it->fact.coord.front().value,it->mult,context0); + } + p_content = p.coord.front().value/(p_content.coord.front().value*lc)*p_content; + } + return true; + } + + int is_homogeneous(const polynome & p){ + std::vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + if (p.dim<2 || it==itend) + return 0; + int d=sum_degree(it->index); + for (++it;it!=itend;++it){ + if (sum_degree(it->index)!=d) + return 0; + } + return d; + } + + bool homogeneize(polynome & p,int dhom){ + ++p.dim; + std::vector< monomial >::iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + int d=sum_degree(it->index); + if (d>dhom) + return false; + index_t i(it->index.begin(),it->index.end()); + i.push_back(dhom-d); + it->index=i; + } + return true; + } + + static bool do_factor(const polynome &p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div){ + // check for homogeneous polynomial -> 1 var less + if (int dhom=is_homogeneous(p)){ + polynome phom(p); + // remove last degree + std::vector< monomial >::iterator it=phom.coord.begin(),itend=phom.coord.end(); + for (;it!=itend;++it){ + it->index=index_t(it->index.begin(),it->index.end()-1); + } + phom.dim--; + bool res=do_factor(phom,p_content,f,false,with_sqrt,complexmode,divide_an_by,extra_div); + // rehomogeneize f + factorization::iterator f_it=f.begin(),f_itend=f.end(); + for (;f_it!=f_itend;++f_it){ + int d=f_it->fact.total_degree(); + homogeneize(f_it->fact,d); + dhom -= d*f_it->mult; + } + homogeneize(p_content,dhom); + return res; + } + f.clear(); + if (p.coord.empty()){ + p_content=p; + return true; + } + polynome p_primit(p.dim); + if (!isprimitive){ + p_content=lgcd(p); + if (is_strictly_positive(-p.coord.front().value,context0) && is_strictly_positive(p_content.coord.front().value,context0)) + p_content=-p_content; + // p_primit=p/p_content; + polynome unused; + if (!divrem1(p,p_content,p_primit,unused,0,false)){ + divrem1(p,p_content,p_primit,unused,0,true); + gen tmp(1); + lcmdeno(p_primit,tmp); + p_primit = tmp*p_primit; + extra_div=extra_div*tmp; + } + } + else + p_primit=p; +#if 1 + // adjust for i + if (!isprimitive && p_primit.coord.front().value.type==_CPLX){ + const gen & g=p_primit.coord.front().value; + if (is_exactly_zero(*g._CPLXptr)){ + if (is_strictly_positive(*(g._CPLXptr+1),context0)){ + p_primit=-cst_i*p_primit; + p_content=cst_i*p_content; + //extra_div=cst_i*extra_div; + } + else { + p_primit=cst_i*p_primit; + p_content=-cst_i*p_content; + //extra_div=-cst_i*extra_div; + } + } + } +#endif + p_content /= divide_an_by; + if (is_one(p_primit)) + return true; + if (p_primit.lexsorted_degree()==1){ + f.push_back(facteur(p_primit,1)); + return true; + } + if (!is_zero(im(divide_an_by,0))) // || !is_zero(im(p_primit,context0))) + complexmode=true; + if (!p_content.coord.empty()){ + if (!complexmode && !is_zero(im(p_content.coord.front().value,0))) + complexmode=true; + // check if one coeff is an alg. extension (only one is allowed) + if (p_content.coord.front().value.type==_EXT){ + gen an; + if (!ext_factor(p_primit,p_content.coord.front().value,an,p_content,f,complexmode,extra_div)) + return false; + p_content=an*p_content; + return true; + } + } + if (divide_an_by.type==_EXT){ + gen an; + if (!ext_factor(p_primit,divide_an_by,an,p_content,f,complexmode,extra_div)) + return false; + p_content=an*p_content; + return true; + } + vector< monomial >::const_iterator ckalg_it=p.coord.begin(),ckalg_itend=p.coord.end(); + for (; ckalg_it!=ckalg_itend;++ckalg_it){ + if (p.dim>1 && (ckalg_it->value.type==_DOUBLE_ || + ckalg_it->value.type==_REAL || + ckalg_it->value.type==_FLOAT_ || + (ckalg_it->value.type==_CPLX && (ckalg_it->value._CPLXptr->type==_DOUBLE_ || (ckalg_it->value._CPLXptr+1)->type==_DOUBLE_)) + ) ){ + // FIXME Prime terminal output + // CERR << "Factorization of multivariate polynomial with approx. coeffs not implemented. Please try with exact coefficients" << '\n'; +#if 1 // otherwise integrate(cos(x/2)**2/(x+sin(x)),x); failure + return false; +#endif + } + if (ckalg_it->value.type==_USER){ + ckalg_it->value._USERptr->polyfactor(p_primit,f); + return true; + } + if (ckalg_it->value.type==_EXT){ + // Try Hensel lift for multivariate factorization if extension of degree>=3 + if (p_primit.dim>1 && (ckalg_it->value._EXTptr+1)->type==_VECT + //&& (ckalg_it->value._EXTptr+1)->_VECTptr->size()>3 + ){ + if (do_factor_hensel(p,p_primit,p_content,f,isprimitive,with_sqrt,complexmode,divide_an_by,extra_div,true)) + return true; + } + gen an; + if (!ext_factor(p_primit,ckalg_it->value,an,p_content,f,complexmode,extra_div)) + return false; + if (with_sqrt){ + factorization fz(f); + f.clear(); + factorization::const_iterator f_it=fz.begin(),f_itend=fz.end(); + for (;f_it!=f_itend;++f_it){ + vectpoly tmpv; + addtov(f_it->fact,tmpv,with_sqrt,complexmode); + f.push_back(facteur(tmpv[0],f_it->mult)); + if (tmpv.size()==2) + f.push_back(facteur(tmpv[1],f_it->mult)); + } + } + p_content=an*p_content; + return true; + } + } + // check if polynomial coeff are embedded inside p + for (ckalg_it=p.coord.begin(); ckalg_it!=ckalg_itend;++ckalg_it){ + if (ckalg_it->value.type==_POLY) + return poly_factor(p,ckalg_it->value._POLYptr->dim,p_content,f,with_sqrt,complexmode,extra_div); + } + // check if p has modular coeff + for (ckalg_it=p.coord.begin(); ckalg_it!=ckalg_itend;++ckalg_it){ + if (ckalg_it->value.type==_MOD){ + if ((ckalg_it->value._MODptr+1)->type!=_INT_) + return false; + return mod_factor(p_primit,p_content,(ckalg_it->value._MODptr+1)->val,f); + } + } + // check if one coefficient is complex + if (complexmode || !is_zero(im(p))){ + gen an; + bool res=cfactor(p_primit,an,f,with_sqrt,extra_div); + if (!res) + return false; + p_content=an*p_content; + return true; + } + return do_factor_hensel(p,p_primit,p_content,f,isprimitive,with_sqrt,complexmode,divide_an_by,extra_div,false); + } + + bool polynome_less(const polynome & f,const polynome & g){ + unsigned fs=unsigned(f.coord.size()),gs=unsigned(g.coord.size()); + if (fs!=gs) + return fs > ::const_iterator it=f.coord.begin(),jt=g.coord.begin(),itend=f.coord.end(); + for (;it!=itend;++it,++jt){ + if (it->index!=jt->index) + return !lex_is_greater(it->index.iref(),jt->index.iref()); // (jt->index <= it->index); + if (it->value!=jt->value){ + gen a=evalf_double(it->value,1,context0),b=evalf_double(jt->value,1,context0); + if (a.type==_DOUBLE_ && b.type==_DOUBLE_) + return a._DOUBLE_valvalue.islesscomplexthan(jt->value); + } + } + return false; + } + + struct facteur_polynome_sort_t { + facteur_polynome_sort_t(){} + bool operator ()(const facteur & f,const facteur & g){ + return polynome_less(f.fact,g.fact); + } + }; + + bool factor(const polynome &p,polynome & p_content,factorization & f,bool isprimitive,bool with_sqrt,bool complexmode,const gen & divide_an_by,gen & extra_div){ + bool res=do_factor(p,p_content,f,isprimitive,with_sqrt,complexmode,divide_an_by,extra_div); +#if 1 // ndef EMCC // does not work for emscripten, don't know why... + // sort f + sort(f.begin(),f.end(),facteur_polynome_sort_t()); +#endif + return res; + } + + bool operator < (const polynome & f,const polynome & g){ + return polynome_less(f,g); + } + + bool operator < (const facteur & f,const facteur & g){ + const polynome & fp=f.fact; + const polynome & gp=g.fact; + return fp > & v_ , vector < pf > & pfdecomp, polynome & ipnum, polynome & ipden,bool rational ){ + polynome num(num_),den(den_); + vector< facteur< polynome > > v(v_); + vector< facteur< polynome > >::iterator jt=v.begin(),jtend=v.end(); + if (jt==jtend){ + ipnum=num_; + ipden=den_; + return; + } + for (;jt!=jtend;++jt){ + gen tmp(1); + lcmdeno(jt->fact,tmp); + if (!is_one(tmp)){ + lcmmult(jt->fact,tmp); // jt->fact=tmp*jt->fact; + tmp=pow(tmp,jt->mult,context0); + num=tmp*num; + den=tmp*den; + } + } + // check that all mult == 1 and deg<=2 + // later will split in 2 parts, 1st having this property + vector< facteur< polynome > >::const_iterator it=v.begin(),itend=v.end(); + pfdecomp.reserve(itend-it); + for (;it!=itend;++it){ + if (it->mult!=1 || it->fact.lexsorted_degree()>2) + break; + } + if (!rational || it!=itend){ + Tpartfrac(num,den,v,pfdecomp,ipnum,ipden); + return; + } + // conditions met + // compute integral part + int dim=num.dim; + polynome rem(dim); + num.TPseudoDivRem(den,ipnum,rem,ipden); + // for degree==1 : N/(P*Q)= (N mod P)/(Q mod P) / P + ... + // for P of degree==2, P=a*x^2+b*x+c, D=P*Q, N mod P = n1*x+n2 + // Q mod P = q1*x+q2, then N/(D*P)=v/P+... + // where v=1/(q2*(a*q2-b*q1)+c*q1^2)*(n2*(a*q2-q1*b)+q1*n1*c+(-q1*n2+q2*n1)*a*x) + it = v.begin(); + if (itend-it==1){ + polynome nums(rem), dens(den*ipden); + TsimplifybyTlgcd(nums,dens); + pfdecomp.push_back(pf(nums,dens,it->fact,it->mult)); + return; + } + polynome nmodp(dim),nmodpden(dim),q(dim),qmodp(dim),qmodpden(dim),quo(dim),tmp; + for (;it!=itend;++it){ + const polynome & P =it->fact; + if (P.lexsorted_degree()==0) continue; + rem.TPseudoDivRem(P,quo,nmodp,nmodpden); // nmodpden*num=P*quo+nmodp -> num mod P = nmodp/nmodpden + nmodpden=nmodpden*ipden; + den.TDivRem(P,q,tmp,false); + q.TPseudoDivRem(P,quo,qmodp,qmodpden); // qmodpden*q=P*quo+qmodp -> q mod P = qmodp/qmodpden + if (P.lexsorted_degree()==1){ + simplify(qmodpden,nmodpden); + simplify(nmodp,qmodp); + pfdecomp.push_back(pf(nmodp*qmodpden,qmodp*nmodpden*P,P,1)); + continue; + } + vecteur P1,N1,Q1,Vnum(2),Vden(1); + polynome2poly1(P,1,P1); + polynome2poly1(qmodp,1,Q1); + polynome2poly1(nmodp,1,N1); + gen a=P1.front(),b=P1[1],c=P1.back(); + gen q1,q2,n1,n2,aq2bq1; + if (Q1.size()==2){ + q1=Q1.front(); q2=Q1.back(); + } + else + q2=Q1.front(); + aq2bq1=a*q2-b*q1; + if (N1.size()==2){ + n1=N1.front(); n2=N1.back(); + } + else + n2=N1.front(); + Vnum[0]=(-q1*n2+q2*n1)*a; + Vnum[1]=n2*aq2bq1+q1*n1*c; + Vden[0]=q2*aq2bq1+c*q1*q1; + polynome vnum(dim),vden(dim); + poly12polynome(Vnum,1,vnum,dim); + poly12polynome(Vden,1,vden,dim); + simplify(qmodpden,nmodpden); + simplify(vnum,vden); + pfdecomp.push_back(pf(vnum*qmodpden,vden*nmodpden*P,P,1)); + } + } + + // Input a,b,c,u,v,d such that a*u+b*v=d, + // Output u,v,C such that a*u+b*v=c*C + void egcdtoabcuv(const tensor & a,const tensor &b, const tensor &c, tensor &u,tensor &v, tensor & d, tensor & C){ + if (Tis_constant(c)){ + C=d; + u *= c.coord.front().value; + v *= c.coord.front().value; + return; + } + tensor d0(Tfirstcoeff(d)); + int m=c.lexsorted_degree(); + int n=d.lexsorted_degree(); + assert(m>=n); // degree of c must be greater than degree of d + C=Tpow(d0,m-n+1); + tensor coverd(a.dim),temp(a.dim); + (c*C).TDivRem1(d,coverd,temp); + assert(temp.coord.empty()); // division of c by d must be exact + // now multiply a*u+b*v=d by coverd -> a*u*coverd+b*v*coverd=c*d0pow + u *= coverd; // u=u*coverd; + v *= coverd; // v=v*coverd; + m=u.lexsorted_degree(); + n=b.lexsorted_degree(); + if (m temp*b+u + // a*b + b*(a*temp+v*d0) = c*C + v=a*temp+v*d0; + return ; + } + + // Bรฉzout identity + // given p and q, find u and v s.t. u*p+v*q=d where d=gcd(p,q) using PSR algo + // Iterative algorithm to find u and d, then q=(d-u*p)/v + void egcdpsr(const polynome &p1, const polynome & p2, polynome & u,polynome & v,polynome & d){ + assert(p1.dim==p2.dim); + // set auxiliary polynomials g and h to 1 + tensor g(gen(1),p1.dim); + tensor h(g); + tensor a(p1.dim),b(p1.dim),q(p1.dim),r(p1.dim); + const tensor cp1=Tlgcd(p1); + const tensor cp2=Tlgcd(p2); + bool genswapped=false; + if (p1.lexsorted_degree() pp1=Tis_one(cp1)?p1:p1/cp1; + const tensor pp2=Tis_one(cp2)?p2:p2/cp2; + if (genswapped){ + a=pp2; + b=pp1; + } + else { + a=pp1; + b=pp2; + } + // initializes ua to 1 and ub to 0, the coeff of u in ua*a+va*b=a + tensor ua(gen(1),p1.dim), ub(p1.dim),ur(p1.dim); + tensor b0pow(p1.dim); + // loop: ddeg <- deg(a)-deg(b), + // genDivRem: b0^(ddeg+1)*a = bq+r + // hence ur <- ua*b0^(ddeg+1)-q*ub verifies + // ur*a+vr*b=r + // a <- b, b <- r/(g*h^ddeg), ua <- ub and ub<- ur/(g*h^ddeg) + // g <- b0, h <- b0^(m-n) * h / h^ddeg + for (;;){ + int n=b.lexsorted_degree(); + int m=a.lexsorted_degree(); + if (!n){ // b is cst !=0 hence is the gcd, ub is valid + break; + } + int ddeg=m-n; + const tensor b0=Tfirstcoeff(b); + // b0pow=genpow(b0,ddeg+1); + // (a*b0pow).genDivRem1(b,q,r); // division works always + a.TPseudoDivRem(b,q,r,b0pow); + // if r is 0 then b is the gcd and ub the coeff + if (r.coord.empty()) + break; + // COUT << ua*b0pow << '\n' << q*ub << '\n' ; + (ua*b0pow).TSub(q*ub,ur); // ur=ua*b0pow-q*ub; + // COUT << ur << '\n'; + swap(a,b); // a=b + const tensor temp=Tpow(h,ddeg); + // now divides r by g*h^(m-n), result is the new b + r.TDivRem1(g*temp,b,q,true); // q is not used anymore + swap(ua,ub); // ua=ub + ur.TDivRem1(g*temp,ub,q,true); + // COUT << (b-ub*p1) << "/" << p2 << '\n'; + // new g=b0 and new h=b0^(m-n)*h/temp + if (ddeg==1) // the normal case, remainder deg. decreases by 1 each time + h=b0; + else // not sure if it's better to keep temp or divide by h^(m-n+1) + (Tpow(b0,ddeg)*h).TDivRem1(temp,h,q,true); + g=b0; + } + // ub is valid and b is the gcd, vb=(b-ub*p1)/p2 if not Tswapped + // vb is stored in ua + // COUT << ub << '\n'; + if (genswapped){ + (b-ub*pp2).TDivRem1(pp1,ua,r,true); // must allow rational for ext coeffs + ua *= cp2; // ua=ua*cp2; + ub *= cp1; // ub=ub*cp1; + b *= cp1; b *= cp2; // b=b*cp1*cp2; + } + else { + (b-ub*pp1).TDivRem1(pp2,ua,r,true); + ua *= cp1; // ua=ua*cp1; + ub *= cp2; // ub=ub*cp2; + b *= cp1; b *= cp2; // b=b*cp1*cp2; + } + // final simplifications + q.coord.clear(); + Tlgcd(b,q); // q=Tlgcd(b); + Tlgcd(ua,q); + Tlgcd(ub,q); + b.TDivRem1(q,d,r,true); // d=b/Tlgcd + if (genswapped){ + ub.TDivRem1(q,v,r,true); // v=ub/Tlgcd + ua.TDivRem1(q,u,r,true); // u=ua/Tlgcd + } + else { + ub.TDivRem1(q,u,r,true); // u=ub/Tlgcd + ua.TDivRem1(q,v,r,true); // v=ua/Tlgcd + } + } + + pf intreduce_pf(const pf & p_cst, vector< pf > & intdecomp ,bool residue){ + assert(p_cst.mult>0); + if (p_cst.mult==1) + return p_cst; + pf p(p_cst); + tensor fprime=p.fact.derivative(); + tensor d(fprime.dim),u(fprime.dim),v(fprime.dim),C(fprime.dim); + tensor resnum(fprime.dim); + gen resden(1),dengcd(1); + egcdpsr(p.fact,fprime,u,v,d); // f*u+f'*v=d + tensor usave(u),vsave(v); + int initial_mult=p.mult-1; + gen currentden=p.den/pow(p.fact,p.mult); // p.den.coord.front().value/pow(p.fact.coord.front().value,p.mult,context0); + p.den=tensor(monomial(1,p.fact.dim)); + while (p.mult>1){ + egcdtoabcuv(p.fact,fprime,p.num,u,v,d,C); + p.mult--; + if (currentden.type==_POLY) + currentden=gen(p.mult)*C*(*currentden._POLYptr); + else + currentden=gen(p.mult)*C*currentden; + p.num=u*gen(p.mult)+v.derivative(); + if (!residue){ // resnum/resden + (-v*p.den)/currentden -> resnum/resden + dengcd=simplify3(resden,currentden); + if (currentden.type==_POLY) + resnum=resnum*(*currentden._POLYptr); + else + resnum=resnum*currentden; + if (resden.type==_POLY) + resnum=resnum-(*resden._POLYptr)*v*p.den; + else + resnum=resnum-resden*v*p.den; + resden=dengcd*resden*currentden; + currentden = dengcd*currentden; // restore currentden + p.den=p.den*p.fact; + } + // simplify from time to time + if (p.mult%5 ==1){ + gen gn=lgcd(p.num); + gen gn1=simplify3(gn,currentden); + if (gn1.type==_POLY) + p.num = p.num / *gn1._POLYptr; + else + p.num/=gn1; + } + if (p.mult==1) + break; + u=usave; + v=vsave; + } + if (!residue){ + p.den=resden.type==_POLY?(*resden._POLYptr)*p.den:resden*p.den; + TsimplifybyTlgcd(resnum,p.den); + intdecomp.push_back(pf(resnum,p.den,p.fact,initial_mult)); + } + p.den=(currentden.type==_POLY)?(*currentden._POLYptr)*p.fact:currentden*p.fact; + return pf(p); + } + + vecteur vector_of_polynome2vecteur(const vectpoly & v){ + vecteur res; + vectpoly::const_iterator it=v.begin(),itend=v.end(); + res.reserve(itend-it); + for (;it!=itend;++it) + res.push_back(*it); + return res; + } + + vecteur sturm_seq(const polynome & p,polynome & cont){ + vectpoly v; + Tsturm_seq(p,cont,v); + return vector_of_polynome2vecteur(v); + } + + /* FAST PEVAL */ + /* + // accumulate partial evaluation in polynomial (it,itend) + // cur_index and nvar indicate the number of first identical eval.variables + // vsize is the total number of eval.variables + polynome peval(vector< monomial >::const_iterator & it,const vector< monomial >::const_iterator & itend,const vector< vecteur > & power_of_xi,index_t & cur_index,int nvar,int vsize,int var0){ + polynome res(var0); + for (;;){ + if (it==itend) + return res; + const index_t & it_t=it->index.iref(); + index_t::const_iterator it_tt=it_t.begin(); + index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin(); + for (;it_tt!=it_ttend;++cur_it,++it_tt){ + if (*it_tt!=*cur_it) + return res; + } + // same index beginning + if (nvar==vsize){ + res.coord.push_back(monomial(it->value,index_t(it_t.begin()+vsize,it_t.end()))); + ++it; + if (debug_infolevel) + CERR << "// " << itend-it << " monomials remain " << CLOCK() << '\n'; + } + else { // go one level deeper + cur_index.push_back(*(it->index.begin()+nvar)); + const gen & g=power_of_xi[nvar][cur_index.back()]; + if (debug_infolevel) + CERR << "// Enter level " << nvar+1 << " " << CLOCK() << '\n'; + if (g.type==_POLY) + res=res+(*g._POLYptr)*peval(it,itend,power_of_xi,cur_index,nvar+1,vsize,var0); + else + res=res+g*peval(it,itend,power_of_xi,cur_index,nvar+1,vsize,var0); + cur_index.pop_back(); + if (debug_infolevel) + CERR << "// Back to level " << nvar << " " << CLOCK() << '\n'; + } + } + } + + gen peval(const polynome & p,const vecteur & v){ + int pdim=p.dim,vsize=v.size(),var0=pdim-vsize; + if (var0<0) + setsizeerr(gettext("Too much substitution variables")); + polynome res(var0); + if (p.coord.empty()) + return res; + vecteur vnum,vden; + gen vn,vd; + vnum.reserve(vsize); + vden.reserve(vsize); + for (int i=0;i power_of_xi; + power_of_xi.reserve(pdim); + index_t pdeg(p.degree()); + index_t deg(pdeg.begin(),pdeg.begin()+vsize); + // compute thet table of powers + gen global_deno(plus_one); + for (int i=0;i >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + index_t cur_index; + return fraction(peval(it,itend,power_of_xi,cur_index,0,vsize,var0),global_deno); + } + */ + + // a*b+c*d + gen foisplus(const polynome & a,const polynome & b,const polynome & c,const polynome & d){ + if (debug_infolevel >= 20-a.dim) + CERR << "foisplus begin " << CLOCK() << '\n'; +#ifndef NO_TEMPLATE_MULTGCD + index_t da=a.degree(),db=b.degree(),dc=c.degree(),dd=d.degree(),de(a.dim); + double ans=1; + for (int i=0;iRAND_MAX) + break; + } + if (ans<=RAND_MAX){ + ref_polynome * res = new ref_polynome(a.dim); + vector< T_unsigned > pa,pb,p,pc,pd; + convert(a,de,pa); + convert(b,de,pb); + smallmult(pa,pb,p,0,100); + convert(c,de,pc); + convert(d,de,pd); + smallmult(pc,pd,pa,0,100); + smalladd(p,pa,pb); + convert(pb,de,res->t); + if (debug_infolevel >= 20-a.dim) + CERR << "foisplus end " << CLOCK() << '\n'; + // CERR << res->t-(a*b+c*d) << '\n'; + return res; + } + if (ans/RAND_MAX > pa,pb,p,pc,pd; + convert(a,de,pa); + convert(b,de,pb); + smallmult(pa,pb,p,0,100); + convert(c,de,pc); + convert(d,de,pd); + smallmult(pc,pd,pa,0,100); + smalladd(p,pa,pb); + convert(pb,de,res->t); + // CERR << res->t << '\n' << (a*b+c*d) << '\n'; + return res; + } +#endif + return a*b+c*d; + } + + gen foisplus(const gen & a,const gen & b,const gen & c,const gen & d){ + if (a.type==_POLY && b.type<_POLY &&c.type==_POLY && d.type<_POLY){ + polynome res(a._POLYptr->dim); + if (b==1){ + if (d==1) + a._POLYptr->TAdd(*c._POLYptr,res); + else { + if (0 && c.ref_count()==1){ + *c._POLYptr *= d; + a._POLYptr->TAdd(*c._POLYptr,res); + } else { + polynome cd(*c._POLYptr); + cd *= d; + a._POLYptr->TAdd(cd,res); + } + } + return res; + } + if (0 && a.ref_count()==1){ + *a._POLYptr *= b; + return foisplus(a,1,c,d); + } + polynome ab(*a._POLYptr); + ab *= b; + if (d==1) + ab.TAdd(*c._POLYptr,res); + else { + polynome cd(*c._POLYptr); + cd *= d; + ab.TAdd(cd,res); + } + return res; + } + return a*b+c*d; + } + + static gen pevaladd(const gen & aa,const gen & bb){ + if (debug_infolevel>40) + CERR << "pevaladd begin " << CLOCK() << '\n'; + gen res=aa+bb; + if (debug_infolevel>40) + CERR << "pevaladd end " << CLOCK() << '\n'; + return res; + } + + static gen pevalmul(const gen & aa,const gen & bb,const gen & m){ + if (debug_infolevel>40) + CERR << "pevalmul begin " << CLOCK() << '\n'; + gen res; + if (!is_zero(m)) + res=smod(aa,m)*bb; + else + res=aa*bb; + /* + if ( (aa.type!=_FRAC) || (bb.type!=_FRAC) ) + return aa*bb; + const Tfraction & a(*aa._FRACptr); + const Tfraction & b(*bb._FRACptr); + gen res(Tfraction(a.num*b.num,a.den*b.den)); + */ + if (debug_infolevel>40) + CERR << "pevalmul end " << CLOCK() << '\n'; + return res; + } + + // Horner like evaluation + // m != 0 for modular evaluation + static gen peval(vector< monomial >::const_iterator & it,const vector< monomial >::const_iterator & itend,const vecteur & nums,const vecteur & dens,const index_t & deg,index_t & cur_index,int nvar,int vsize,int var0,const gen & m){ + if (it==itend) + return zero; + if (nvar==vsize){ + polynome res(var0); + for (;;){ + if (it==itend) + return res; + index_t::const_iterator it_tt=it->index.begin(); + index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin(); + for (;it_tt!=it_ttend;++cur_it,++it_tt){ + if (*it_tt!=*cur_it){ + return res; + } + } + // same main variables powers, accumulate constants + res.coord.push_back(monomial(it->value,index_t(it->index.begin()+vsize,it->index.end()))); + ++it; + if (debug_infolevel>40) + CERR << "// " << itend-it << " monomials remain " << CLOCK() << '\n'; + } + } + // we are not at the deepest level + gen res,tmp1,tmp2; + int prev_power=0,cur_power=deg[nvar]; + const gen & gn=nums[nvar]; + const gen & gd=dens[nvar]; + gen cur_gd(plus_one); + if (is_zero(gn)){ // if gn=0 we just discard monomials + for (;;){ + if (it==itend) + return zero; + index_t::const_iterator it_tt=it->index.begin(); + index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin(); + for (;it_tt!=it_ttend;++cur_it,++it_tt){ + if (*it_tt!=*cur_it) + return zero; + } + if (!*it_tt) // break at first monomial with power = 0 at this index + break; + ++it; + } + cur_index.push_back(0); + gen res(pow(gd,prev_power)); + if (!is_zero(m)) + res=smod(res,m); + res=res*peval(it,itend,nums,dens,deg,cur_index,nvar+1,vsize,var0,m); + cur_index.pop_back(); + return res; + } // end gn==0 + for (;;){ + prev_power=cur_power; + if (it==itend){ + if (!prev_power) + return res; + else + return pevalmul(pow(gn,prev_power),res,m); + // return pow(gn,prev_power)*res; + } + cur_power=*(it->index.begin()+nvar); + // same powers for the beginning indices? (always true the first time) + index_t::const_iterator it_tt=it->index.begin(); + index_t::const_iterator it_ttend=it_tt+nvar,cur_it=cur_index.begin(); + for (;it_tt!=it_ttend;++cur_it,++it_tt){ + if (*it_tt!=*cur_it) + return pevalmul(pow(gn,prev_power),res,m); + // return pow(gn,prev_power)*res; + } + // Yes: go one level deeper + tmp1=pevalmul(pow(gn,prev_power-cur_power),res,m); + res=zero; + cur_index.push_back(cur_power); + if (debug_infolevel>40) + CERR << "// Enter level " << nvar+1 << " " << CLOCK() << " ^ " << prev_power-cur_power << '\n'; + tmp2=peval(it,itend,nums,dens,deg,cur_index,nvar+1,vsize,var0,m); + cur_index.pop_back(); + if (debug_infolevel>40) + CERR << "// Back to level " << nvar << " " << CLOCK() << '\n'; + cur_gd=cur_gd*pow(gd,prev_power-cur_power); + if (!is_zero(m)) + cur_gd=smod(cur_gd,m); + // res=pevalmul(pow(gn,prev_power-cur_power),res)+cur_gd*peval(it,itend,nums,dens,deg,cur_index,nvar+1,vsize,var0); + res=pevaladd(tmp1,cur_gd*tmp2); + if (!is_zero(m)) + res=smod(res,m); + tmp1=zero; + tmp2=zero; + } + } + + static void smallmult(const std::vector< int_unsigned > & v1,const std::vector< int_unsigned > & v2,std::vector< int_unsigned > & v,int reduce,int possible_size=100){ +#ifdef HASH_MAP_NAMESPACE + typedef HASH_MAP_NAMESPACE::hash_map hash_prod ; + hash_prod produit(possible_size); + // COUT << "hash " << CLOCK() << '\n'; +#else + typedef std::map hash_prod; + hash_prod produit; + // COUT << "small map" << '\n'; +#endif + hash_prod::iterator prod_it,prod_itend; + std::vector< int_unsigned >::const_iterator it1=v1.begin(),it1end=v1.end(),it2beg=v2.begin(),it2,it2end=v2.end(); + // FIXME if reduce is small use int for g1,g instead of longlong + longlong g1,g; + unsigned u1,u; + for (;it1!=it1end;++it1){ + g1=it1->g; + u1=it1->u; + for (it2=it2beg;it2!=it2end;++it2){ + u=u1+it2->u; + g=g1*it2->g ; // moved % reduce so that 1 % is done instead of 2 + prod_it=produit.find(u); + if (prod_it==produit.end()) + produit[u]=g % reduce; + else { + int & s=prod_it->second; + g += s; + s = g % reduce; + } + } + } + int_unsigned gu; + prod_it=produit.begin(),prod_itend=produit.end(); + v.clear(); + v.reserve(produit.size()); + for (;prod_it!=prod_itend;++prod_it){ + if (!is_zero(gu.g=prod_it->second)){ + gu.u=prod_it->first; + v.push_back(gu); + } + } + // COUT << "smallmult end " << CLOCK() << '\n'; + sort(v.begin(),v.end()); + } + + static void smallmult(int x,std::vector & v,int m){ + if (!x){ + v.clear(); + return; + } + std::vector::iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + it->g *= x; + it->g %= m; + } + } + + static void smalladd(const std::vector< int_unsigned > & v1,const std::vector< int_unsigned > & v2,int m,std::vector< int_unsigned > & v){ + std::vector< int_unsigned >::const_iterator it1=v1.begin(),it1end=v1.end(),it2=v2.begin(),it2end=v2.end(); + int g; + v.clear(); + v.reserve((it1end-it1)+(it2end-it2)); // worst case + for (;it1!=it1end && it2!=it2end;){ + if (it1->u==it2->u){ + g=(it1->g+it2->g)%m; + if (g) + v.push_back(int_unsigned(g,it1->u)); + ++it1; + ++it2; + } + else { + if (it1->u>it2->u){ + v.push_back(*it1); + ++it1; + } + else { + v.push_back(*it2); + ++it2; + } + } + } + for (;it1!=it1end;++it1) + v.push_back(*it1); + for (;it2!=it2end;++it2) + v.push_back(*it2); + } + + // Poly evaluation of p at x modulo m, d is the degree in int_unsigned.u + static void peval(const vector & p,int d,int x,int m,vector & res){ + res.clear(); + vector tmp1,tmp2; + if (p.empty()) + return; + // CERR << p << '\n'; + vector::const_iterator it=p.begin(),itend=p.end(); + int deg=d*(it->u / d),ddeg; + for (;deg>=0;deg -=d ){ // Horner like + // CERR << res << '\n'; + smallmult(x,res,m); + // CERR << res << '\n'; + tmp2.clear(); + // Find next coeff + for (;it!=itend;++it){ + ddeg=it->u-deg; + if (ddeg<0) + break; + tmp2.push_back(int_unsigned(it->g,ddeg)); + } + // CERR << tmp2 << '\n'; + tmp1=res; + smalladd(tmp1,tmp2,m,res); + // CERR << res << '\n'; + } + } + + static bool peval(const polynome & p,const gen & x0,int m,polynome & g,vector * P){ + gen x1=smod(x0,m); + if (x1.type!=_INT_) + return false; + int x=x1.val; + index_t d=p.degree(); + unsigned ans; + if (!degree2unsigned(d,ans)) + return false; + vector Q; + if (!P) + P=&Q; + if (P->empty() && !convert(p,d,*P,m)) + return false; + vector res; + peval(*P,ans/d.front(),x,m,res); + d.erase(d.begin()); + convert(res,d,g); + return true; + } + + gen peval(const polynome & p,const vecteur & v,const gen & m,bool simplify_at_end,vector * pptr){ + int pdim=int(p.dim),vsize=int(v.size()),var0=pdim-vsize; + if (v==vecteur(vsize)){ // fast evaluation at 0 + index_t i(pdim); + i[vsize-1]=1; + // i=(0,0,...,0,1) + // find the last position in p where a monomial with index i + // could be inserted, the remaining of p truncated is the answer + vector< monomial >::const_iterator it,itend=p.coord.end(); + it=upper_bound(p.coord.begin(),itend,monomial(plus_one,i),p.m_is_strictly_greater); + if ( (it!=itend) && it->index.iref()==i) + ++it; + polynome res(var0); + res.coord.reserve(itend-it); + for (;it!=itend;++it){ + res.coord.push_back(monomial(it->value,index_t(it->index.begin()+vsize,it->index.end()))); + } + return res; + } + if (vsize==1 && m.type==_INT_ && m.val>0 && m.val<46340){ + polynome res; + if (peval(p,v.front(),m.val,res,pptr)) + return res; + } + if (var0<0){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Too much substitution variables")); +#else + return gensizeerr(gettext("Too much substitution variables")); +#endif + } + polynome res(var0); + if (p.coord.empty()) + return res; + vecteur vnum,vden; + gen vn,vd; + vnum.reserve(vsize); + vden.reserve(vsize); + if (simplify_at_end){ + for (int i=0;i >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + index_t cur_index; + index_t pdeg(p.degree()); + index_t deg(pdeg.begin(),pdeg.begin()+vsize); + gen numer(peval(it,itend,vnum,vden,deg,cur_index,0,vsize,var0,m)); + if (!is_zero(m)) + numer=smod(numer,m); + if (debug_infolevel>40){ + CERR << "// Peval end " << CLOCK(); + if (numer.type==_POLY) + CERR << " poly " << numer._POLYptr->coord.size(); + CERR << '\n'; + } + if ( is_zero(numer)) + return numer; + // compute thet table of powers + gen global_deno(plus_one); + for (int i=0;i(*it)) + res.push_back(facteur(*it,i)); + } + return res; + } +#endif + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/gen.cc b/android/app/src/main/cpp/giac/src/giac/cpp/gen.cc new file mode 100644 index 0000000..62c850f --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/gen.cc @@ -0,0 +1,17414 @@ +// -*- mode:C++ ; compile-command: "g++ -I.. -I../include -DHAVE_CONFIG_H -DIN_GIAC -DGIAC_GENERIC_CONSTANTS -fno-strict-aliasing -g -c gen.cc -Wall" -*- +#include "giacPCH.h" +#if defined KHICAS || defined SDL_KHICAS +#include "kdisplay.h" +#if defined DEVICE && !defined NUMWORKS_SLOTAB && !defined NUMWORKS_SLOTB && !defined NSPIRE_NEWLIB +size_t stackptr=0x20036000; +#else +#if defined x86_64 +size_t stackptr=0xffffffffffffffff; +#else +size_t stackptr=0xffffffff; +#endif +#endif +#endif + +#ifdef NSPIRE_NEWLIB +#include +#endif + +/* + * Copyright (C) 2001,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using namespace std; +#if !defined NSPIRE && !defined FXCG && !defined KHICAS +#include +#include +#endif +#define __USE_ISOC9X 1 +#include +#include +#include +#include +#include +#include +// #include +#include "gen.h" +#include "gausspol.h" +#include "identificateur.h" +#include "poly.h" +#include "usual.h" +#include "input_lexer.h" +#include "sym2poly.h" +#include "vecteur.h" +#include "modpoly.h" +#include "alg_ext.h" +#include "prog.h" +#include "rpn.h" +#include "plot.h" +#include "intg.h" +#include "subst.h" +#include "derive.h" +#include "threaded.h" +#include "maple.h" +#include "solve.h" +#include "csturm.h" +#include "sparse.h" +#include "quater.h" +#if defined GIAC_HAS_STO_38 || defined NSPIRE || defined NSPIRE_NEWLIB || defined FXCG || defined GIAC_GGB || defined USE_GMP_REPLACEMENTS || defined KHICAS || defined SDL_KHICAS +inline bool is_graphe(const giac::gen &g){ return false; } +#else +#include "graphtheory.h" +#endif +#include "giacintl.h" +#ifdef RTOS_THREADX +extern "C" uint32_t mainThreadStack[]; +#endif +#ifdef HAVE_PTHREAD_H +#include +#endif + +#ifdef EMCC_BIND +#include +#endif + +#if (defined EMCC || defined EMCC2) && !defined GIAC_GGB +#include "kdisplay.h" + +#if 0 // def EMCC_GLUT +#include +#else +#include "SDL/SDL.h" +#include +#include +//#include "SDL/SDL_image.h" +#include "SDL/SDL_opengl.h" +#endif + +#include "opengl.h" +#endif + +#ifdef USE_GMP_REPLACEMENTS +#undef HAVE_GMPXX_H +#undef HAVE_LIBMPFR +#endif + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + +#if defined FXCG || defined HP39 //|| defined NUMWORKS_SLOTAB +#define ALLOCSMALL +#endif + +#ifdef ALLOCSMALL + + // 32 bytes structure: 4096/32=128 slots of memory + // ALLOCA constants must be multiples of 2*32 + const int ALLOC16=8*32; // symbolic +#ifdef NUMWORKS_SLOTAB + const int ALLOC24=8*32; // complex, identificateur, mpz_t + static unsigned int freeslot24[ALLOC24/32]={ + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }; +#else + const int ALLOC24=16*32; // complex, identificateur, mpz_t + // #define ALLOC32 3*32 // not used + // unsigned os_python_heap=0x88068000; // free memory area, used by Python heap + #define ALLOC48 8*32 // eqw, comment this line if memory crash in eqw + static unsigned int freeslot24[ALLOC24/32]={ + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff,0xffffffff, 0xffffffff, + }; +#endif + static unsigned int freeslot16[ALLOC16/32]={ + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + //0xffffffff, 0xffffffff + }; +#ifdef ALLOC32 + static unsigned int freeslot32[ALLOC32/32]={ + 0xffffffff, 0xffffffff, 0xffffffff, + //0xffffffff,0xffffffff, 0xffffffff,0xffffffff, 0xffffffff, + //0xffffffff, 0xffffffff + }; + eight_int * tab32; +#endif +#ifdef ALLOC48 + static unsigned int freeslot48[ALLOC48/32]={ + 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff,0xffffffff, 0xffffffff, + }; + // static twelve_int tab48[ALLOC48]; + twelve_int * tab48=0; +#endif + +#if 0 // alloc in static area + static six_int tab24[ALLOC24]; + static four_int tab16[ALLOC16]; +#else // alloc in main.cc + four_int * tab16=0; + six_int * tab24=0; +#endif + + + unsigned freeslotpos(unsigned n){ + unsigned r=1; + if ( (n<<16)==0 ){ + r+= 16; + n>>=16; + } + if ( (n<<24)==0 ) { + r+= 8; + n>>=8; + } + if ( (n<<28)==0 ) { + r+= 4; + n>>=4; + } + if ( (n<<30)==0 ) { + r+= 2; + n>>=2; + } + r -= n&1; + return r; + } + + static void* allocfast(size_t size){ + int i,pos; + if (tab24 && size==24){ + for (i=0;i= (size_t) &tab24[0]) && + ((size_t)obj < (size_t) &tab24[ALLOC24]) ){ + int pos= ((size_t)obj -((size_t) &tab24[0]))/sizeof(six_int); + freeslot24[pos/32] |= (1 << (pos%32)); + return; + } + if ( ((size_t)obj>=(size_t) &tab16[0] ) && + ((size_t)obj<(size_t) &tab16[ALLOC16] ) ){ + * (unsigned *) obj= 0; + int pos= ((size_t)obj -((size_t) &tab16[0]))/sizeof(four_int); + freeslot16[pos/32] |= (1 << (pos%32)); + return; + } +#ifdef ALLOC48 + if ( ((size_t)obj>=(size_t) &tab48[0] ) && + ((size_t)obj<(size_t) &tab48[ALLOC48] ) ){ + * (unsigned *) obj= 0; + int pos= ((size_t)obj -((size_t) &tab48[0]))/sizeof(twelve_int); + freeslot48[pos/32] |= (1 << (pos%32)); + return; + } +#endif +#ifdef ALLOC32 + if ( ((size_t)obj>=(size_t) &tab32[0]) && + ((size_t)obj<(size_t) &tab32[ALLOC32]) ){ + int pos= ((size_t)obj -((size_t) &tab32[0]))/sizeof(eight_int); + freeslot32[pos/32] |= (1 << (pos%32)); + return; + } +#endif + free(obj); + } + unsigned hamdist(unsigned val){ + size_t res=0; + if (!val) return res; + for (int i=0;i<32;++i){ + res += ((val >>i) & 1); + } + return res; + } + + size_t freeslotmem(){ + size_t res=0; + for (int i=0;ire=0; + ptr->im=0; + deletefast(ptr); + } +#endif + +#if defined(SMARTPTR64) || !defined(ALLOCSMALL) + inline void deletesymbolic(ref_symbolic * ptr){ + delete ptr ; + } +#else + static void deletesymbolic(ref_symbolic * ptr){ + ptr->s.feuille=0; + deletefast(ptr); + } +#endif + +#if defined(SMARTPTR64) || !defined(IMMEDIATE_VECTOR) || !defined(ALLOCSMALL) + void delete_ref_vecteur(ref_vecteur * ptr){ + delete ptr ; + } +#else + void delete_ref_vecteur(ref_vecteur * ptr){ + ptr->v.clear(); + deletefast(ptr); + } +#endif + + /* + unsigned control_c_counter=0; + unsigned control_c_counter_mask=0xff; + */ + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t mpfr_mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t locale_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + + void sprintfdouble(char * ch,const char * format,double d){ +#ifdef FXCG + sprint_double(ch,d); // no format +#else +#ifdef NSPIRE + dtostr(d,8,ch); // FIXME! +#else +#if defined(EMCC) || defined(EMCC2) + sprintf(ch,format,d); +#else + my_sprintf(ch,format,d); +#endif +#endif +#endif + } + + // bool is_inevalf=false; + + static string last_evaled_function(GIAC_CONTEXT){ + const char * last =last_evaled_function_name(contextptr); + if (!last) + return ""; + string res; + bool paren=true; + if (abs_calc_mode(contextptr)==38 && !strcmp(last,"sqrt")) + res="โˆš"; + else { + string tmp=unlocalize(autosimplify(contextptr)); + if (tmp!=last) + res=last; + else + paren=false; + } + if (paren) res +="("; + const gen * lastarg= last_evaled_argptr(contextptr); + if (lastarg){ + if (strcmp(last,"try_catch")==0 && lastarg->type==_VECT && !lastarg->_VECTptr->empty()){ // workaround for optimizations on some operations like * + res = lastarg->_VECTptr->front().print(contextptr); + paren = false; + } + else + res += lastarg->print(contextptr); + } + if (paren) res += ")"; + debug_struct * dbg = debug_ptr(contextptr); + if (!dbg->sst_at_stack.empty()){ + res += gettext(" in "); + gen pos=dbg->args_stack.back(); + string tmp; + if (pos.type==_VECT && pos._VECTptr->size()>=2){ + vecteur v(pos._VECTptr->begin()+1,pos._VECTptr->end()); + if (v.size()==1){ + if (v.front().type==_VECT && v.front()._VECTptr->empty()) + tmp=pos._VECTptr->front().print(contextptr)+"()"; + else + tmp=pos._VECTptr->front().print(contextptr)+"("+v.front().print(contextptr)+")"; + } + else + tmp = pos._VECTptr->front().print(contextptr)+"("+gen(v,_SEQ__VECT).print(contextptr)+")"; + } + else + tmp = pos.print(contextptr); + res += tmp; + res += gettext(" instruction #"); + res += print_INT_(dbg->current_instruction); + res += gettext(" error, try debug(")+tmp+")"; + } + else + res += ' '; + return res+"\n "; + } + +#ifdef NO_STDEXCEPT // FIXME + void settypeerr(GIAC_CONTEXT){ + gentypeerr(contextptr); + } + + void setsizeerr(GIAC_CONTEXT){ + gensizeerr(contextptr); + } + + void setdimerr(GIAC_CONTEXT){ + gendimerr(contextptr); + } + + void settypeerr(const string & s){ + gentypeerr(s); + } + + void setsizeerr(const string & s){ + gensizeerr(s); + } + + void setdimerr(const string & s){ + gendimerr(s); + } + + void divisionby0err(const gen & e,GIAC_CONTEXT){ + gendivisionby0err(e,contextptr); + } + + void cksignerr(const gen & e,GIAC_CONTEXT){ + gencksignerr(e,contextptr); + } + + void invalidserieserr(const string & s,GIAC_CONTEXT){ + geninvalidserieserr(s,contextptr); + } + + void toofewargs(const string & s,GIAC_CONTEXT){ + gentoofewargs(s,contextptr); + } + + void toomanyargs(const string & s,GIAC_CONTEXT){ + gentoomanyargs(s,contextptr); + } + + void maxordererr(GIAC_CONTEXT){ + genmaxordererr(contextptr); + } + + void setstabilityerr(GIAC_CONTEXT){ + genstabilityerr(contextptr); + } +#else + void settypeerr(GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Bad Argument Type"))); + } + + void setsizeerr(GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Bad Argument Value"))); + } + + void setdimerr(GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Invalid dimension"))); + } + + void settypeerr(const string & s){ + throw(std::runtime_error(s+gettext(" Error: Bad Argument Type"))); + } + + void setsizeerr(const string & s){ + throw(std::runtime_error(s+gettext(" Error: Bad Argument Value"))); + } + + void setdimerr(const string & s){ + throw(std::runtime_error(s+gettext(" Error: Invalid dimension"))); + } + + void divisionby0err(const gen & e,GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Division of ") + e.print(contextptr)+ gettext(" by 0"))); + } + + void cksignerr(const gen & e,GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Unable to check sign: ")+e.print(contextptr))); + } + + void invalidserieserr(const string & s,GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Invalid series expansion: ")+s)); + } + + void toofewargs(const string & s,GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Too few arguments: ")+s)); + } + + void toomanyargs(const string & s,GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Too many arguments: ")+s)); + } + + void maxordererr(GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("Max order (")+gen(max_series_expansion_order).print(contextptr)+gettext(") exceeded or non unidirectional series"))); + } + + void setstabilityerr(GIAC_CONTEXT){ + throw(std::runtime_error(last_evaled_function(contextptr)+gettext("calculation size limit exceeded"))); + } +#endif // NO_STDEXCEPT + + gen undeferr(const string & s){ +#if defined(EMCC) || defined(EMCC2) + CERR << s << '\n'; +#endif +#if defined NSPIRE || defined FXCG + wait_1ms(1); +#else +#ifdef GIAC_HAS_STO_38 + usleep(10); +#else +#ifndef __MINGW_H + usleep(1000); +#endif +#endif +#endif +#if !defined NO_STDEXCEPT && !defined EMCC + if (debug_infolevel!=-5) + throw(std::runtime_error(s)); +#endif + gen res(string2gen(s,false)); + res.subtype=-1; + return res; + } + + gen gentypeerr(GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Bad Argument Type")); + } + + void gentypeerr(gen & g,GIAC_CONTEXT){ + g=undeferr(last_evaled_function(contextptr)+gettext("Error: Bad Argument Type")); + } + + gen gensizeerr(GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Bad Argument Value")); + } + + void gensizeerr(gen & g,GIAC_CONTEXT){ + g=undeferr(last_evaled_function(contextptr)+gettext("Error: Bad Argument Value")); + } + + gen gendimerr(GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Invalid dimension")); + } + + void gendimerr(gen & g,GIAC_CONTEXT){ + g=undeferr(last_evaled_function(contextptr)+gettext("Error: Invalid dimension")); + } + + gen gentypeerr(const string & s){ + return undeferr(s+gettext(" Error: Bad Argument Type")); + } + + void gentypeerr(const char * ch,gen & g){ + g=undeferr(string(gettext(ch))+gettext(" Error: Bad Argument Type")); + } + + gen gensizeerr(const string & s){ + return undeferr(s+gettext(" Error: Bad Argument Value")); + } + + void gensizeerr(const char * ch,gen & g){ + g=undeferr(string(gettext(ch))+gettext(" Error: Bad Argument Value")); + } + + gen gendimerr(const string & s){ + return undeferr(s+gettext(" Error: Invalid dimension")); + } + + void gendimerr(const char * ch,gen & g){ + g=undeferr(string(gettext(ch))+gettext(" Error: Invalid dimension")); + } + + gen gendivisionby0err(const gen & e,GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Division of ") + e.print(contextptr)+ gettext(" by 0")); + } + + gen gencksignerr(const gen & e,GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Unable to check sign: ")+e.print(contextptr)); + } + + gen geninvalidserieserr(const string & s,GIAC_CONTEXT){ + *logptr(contextptr) << undeferr(last_evaled_function(contextptr)+gettext("Error: Invalid series expansion: ")+s) << '\n'; + return undef; + } + + gen gentoofewargs(const string & s,GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Too few arguments: ")+s); + } + + gen gentoomanyargs(const string & s,GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Too many arguments: ")+s); + } + + gen genmaxordererr(GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: Max order (")+gen(max_series_expansion_order).print(contextptr)+gettext(") exceeded or non unidirectional series")); + } + + gen genstabilityerr(GIAC_CONTEXT){ + return undeferr(last_evaled_function(contextptr)+gettext("Error: calculation size limit exceeded")); + } + + // void parseerror(){ + // throw(std::runtime_error("Parse error")); + // } + + enum { debugtype=_CPLX }; +#define debugtypeptr _CPLXptr + + /* Constructors, destructors, copy */ + gen vector2vecteur(const vecteur & v){ + gen g=v.back()-v.front(); + if (g.type!=_VECT) + return makenewvecteur(re(g,context0),im(g,context0)); + return g; + } + + gen gen::change_subtype(int newsubtype){ + subtype=newsubtype; + return *this; + } + + gen change_subtype(const gen & g,int newsubtype){ + gen g_(g); + g_.subtype=newsubtype; + return g_; + } + + int * complex_display_ptr(const gen & g) { + if (g.type!=_CPLX) + return 0; + return (int *)(g._CPLXptr)-1; + } + + gen::gen(long i) { +#ifdef COMPILE_FOR_STABILITY + control_c(); +#endif +#ifdef SMARTPTR64 + * ((ulonglong * ) this)=0; +#endif + val=(int)i; + // longlong temp=val; + if (val==i && val!=1<<31){ +#ifndef SMARTPTR64 + type=_INT_; + subtype=0; +#endif + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(64)) << 16; +#else + __ZINTptr = new ref_mpz_t(64); +#endif + type =_ZINT; + subtype=0; + // convert longlong to mpz_t + bool signe=(i<0); + if (signe) + i=-i; + unsigned int i1=sizeof(long)==4?0:i>>32; + unsigned int i2=(unsigned int)i; + mpz_set_ui(*_ZINTptr,i1); + mpz_mul_2exp(*_ZINTptr,*_ZINTptr,32); + mpz_add_ui(*_ZINTptr,*_ZINTptr,i2); + if (signe) + mpz_neg(*_ZINTptr,*_ZINTptr); + } + } + + gen::gen(longlong i) { +#ifdef COMPILE_FOR_STABILITY + control_c(); +#endif +#ifdef SMARTPTR64 + * ((ulonglong * ) this)=0; +#endif + val=(int)i; + // longlong temp=val; + if (val==i && val!=1<<31){ +#ifndef SMARTPTR64 + type=_INT_; + subtype=0; +#endif + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(64)) << 16; +#else + __ZINTptr = new ref_mpz_t(64); +#endif + type =_ZINT; + subtype=0; + // convert longlong to mpz_t + bool signe=(i<0); + if (signe) + i=-i; + unsigned int i1=i>>32; + unsigned int i2=(unsigned int)i; + mpz_set_ui(*_ZINTptr,i1); + mpz_mul_2exp(*_ZINTptr,*_ZINTptr,32); + mpz_add_ui(*_ZINTptr,*_ZINTptr,i2); + if (signe) + mpz_neg(*_ZINTptr,*_ZINTptr); + /* + longlong lbase=65536; + long base=65536; + longlong i1=i/lbase; + long i2=i1/lbase; // i2=i/2^32 + //COUT << "Initialization of " << _ZINTptr << '\n' ; + mpz_init_set_si(*_ZINTptr,i2); + mpz_mul_ui(*_ZINTptr,*_ZINTptr,base); // i/2^32 * 2^16 + long i2mod=i1 % lbase; + if (i2mod>0) + mpz_add_ui(*_ZINTptr,*_ZINTptr,i2mod); + else + mpz_sub_ui(*_ZINTptr,*_ZINTptr,-i2mod); // i/2^16 + mpz_mul_ui(*_ZINTptr,*_ZINTptr,base); // i/2^16 * 2^16 + long i1mod = i % lbase; + if (i1mod>0) + mpz_add_ui(*_ZINTptr,*_ZINTptr,i1mod); + else + mpz_sub_ui(*_ZINTptr,*_ZINTptr,-i1mod); // i + */ + } + } + + gen::gen(longlong i,int nbits) { +#ifdef COMPILE_FOR_STABILITY + control_c(); +#endif +#ifdef SMARTPTR64 + * ((ulonglong * ) this)=0; +#endif + val=(int)i; + // longlong temp=val; + if (val==i && val!=1<<31){ +#ifndef SMARTPTR64 + type=_INT_; + subtype=0; +#endif + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(nbits)) << 16; +#else + __ZINTptr = new ref_mpz_t(nbits); +#endif + type =_ZINT; + subtype=0; + // convert longlong to mpz_t + bool signe=(i<0); + if (signe) + i=-i; + unsigned int i1=i>>32; + unsigned int i2=(unsigned int)i; + mpz_set_ui(*_ZINTptr,i1); + mpz_mul_2exp(*_ZINTptr,*_ZINTptr,32); + mpz_add_ui(*_ZINTptr,*_ZINTptr,i2); + if (signe) + mpz_neg(*_ZINTptr,*_ZINTptr); + } + } + +#ifdef INT128 + gen::gen(int128_t i) { +#ifdef COMPILE_FOR_STABILITY + control_c(); +#endif +#ifdef SMARTPTR64 + * ((ulonglong * ) this)=0; +#endif + val=i; + // longlong temp=val; + if (val==i && val!=1<<31){ +#ifndef SMARTPTR64 + type=_INT_; + subtype=0; +#endif + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(128)) << 16; +#else + __ZINTptr = new ref_mpz_t(128); +#endif + type =_ZINT; + subtype=0; + bool signe=(i<0); + if (signe) + i=-i; +#if !defined(USE_GMP_REPLACEMENTS) && !defined BF2GMP_H + mpz_import(*_ZINTptr,4/* count*/,-1/*1 for least significant first*/,4/* sizeof unsigned*/,0,0,&i); + // CERR << gen(*_ZINTptr) ; +#else + unsigned int i3= i; + i = i>>32; + unsigned int i2= i; + i = i>>32; + unsigned int i1= i; + i = i>>32; + // convert to mpz_t + if (i1 || i){ + mpz_set_ui(*_ZINTptr,(unsigned int) i); + mpz_mul_2exp(*_ZINTptr,*_ZINTptr,32); + mpz_add_ui(*_ZINTptr,*_ZINTptr,i1); + mpz_mul_2exp(*_ZINTptr,*_ZINTptr,32); + mpz_add_ui(*_ZINTptr,*_ZINTptr,i2); + } + else + mpz_set_ui(*_ZINTptr,i2); + mpz_mul_2exp(*_ZINTptr,*_ZINTptr,32); + mpz_add_ui(*_ZINTptr,*_ZINTptr,i3); +#endif + if (signe) + mpz_neg(*_ZINTptr,*_ZINTptr); + // CERR << " " << gen(*_ZINTptr) << '\n' ; + } + } +#endif + + gen::gen(const mpz_t & m) { + if (int(mpz_sizeinbase(m,2))>MPZ_MAXLOG2){ + type=0; +#if 1 + *this=undef; +#else + *this=mpz_sgn(m)==-1?minus_inf:plus_inf; +#endif + return; + } +#ifdef COMPILE_FOR_STABILITY + control_c(); +#endif +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(m)) << 16; +#else + __ZINTptr= new ref_mpz_t(m); +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _ZINTptr > stackptr) + ctrl_c=interrupted=true; +#endif + type =_ZINT; + subtype=0; + } + +#if defined HAVE_GMPXX_H && !defined USE_GMP_REPLACEMENTS + gen::gen(const mpz_class & m){ + int l=mpz_sizeinbase(m.get_mpz_t(),2); + if (l<32){ + type = _INT_; + val = mpz_get_si(m.get_mpz_t()); + } + else { +#ifdef SMARTPTR64 + ref_mpz_t * ptr=new ref_mpz_t; + mpz_set(ptr->z,m.get_mpz_t()); + * ((ulonglong * ) this) = ulonglong(ptr) << 16; +#else + __ZINTptr= new ref_mpz_t(); +#if defined KHICAS && !defined SIMU + if ((size_t) _ZINTptr > stackptr) + ctrl_c=interrupted=true; +#endif + mpz_set(__ZINTptr->z,m.get_mpz_t()); +#endif + type =_ZINT; + } + subtype=0; + } +#endif + + gen::gen(const identificateur & s){ +#ifdef COMPILE_FOR_STABILITY + control_c(); +#endif +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_identificateur(s)) << 16; +#else + __IDNTptr= new ref_identificateur(s); +#endif + type=_IDNT; + subtype=0; + } + +#if defined(SMARTPTR64) || !defined(IMMEDIATE_VECTOR) || !defined(ALLOCSMALL) + ref_vecteur * new_ref_vecteur(const vecteur & v){ + return new ref_vecteur(v); + } +#else + ref_vecteur * new_ref_vecteur(const vecteur & v){ + ref_vecteur * ptr=(ref_vecteur *) allocfast(sizeof(ref_vecteur)); + ptr->ref_count=1; + *(unsigned *)&ptr->v=0; + *((unsigned *)&ptr->v+1)=0; + *((unsigned *)&ptr->v+2)=0; + *((unsigned *)&ptr->v+3)=0; + *((unsigned *)&ptr->v+4)=0; + *((unsigned *)&ptr->v+5)=0; + *((unsigned *)&ptr->v+6)=0; + ptr->v=v; + return ptr; + } +#endif + + gen::gen(const vecteur & v,short int s) + { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_vecteur(v)) << 16; +#else + __VECTptr= new_ref_vecteur(v); +#endif +#if defined KHICAS && !defined SIMU + if (v.size()>1 && + ( (size_t) _VECTptr > stackptr || + (size_t) _VECTptr->begin() > stackptr) + ) + ctrl_c=interrupted=true; +#endif + type=_VECT; + subtype=(signed char)s; + } + + gen::gen(ref_vecteur * vptr,short int s){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(vptr) << 16; +#else + __VECTptr= vptr; +#endif + type=_VECT; + subtype=(signed char)s; +#if defined KHICAS && !defined SIMU + if (_VECTptr->size()>1 && + ( (size_t) _VECTptr > stackptr || + (size_t) _VECTptr->begin() > stackptr) + ) + ctrl_c=interrupted=true; +#endif + } + +#if defined(SMARTPTR64) || !defined(ALLOCSMALL) + ref_symbolic * new_ref_symbolic(const symbolic & s){ + return new ref_symbolic(s); + } +#else + ref_symbolic * new_ref_symbolic(const symbolic & s){ + ref_symbolic * ptr=(ref_symbolic *) allocfast(sizeof(ref_symbolic)); + ptr->ref_count=1; + * (unsigned *) &ptr->s.sommet = 0; + ptr->s.feuille.type=0; + ptr->s=s; + return ptr; + } +#endif + + gen::gen(const symbolic & s){ +#ifdef COMPILE_FOR_STABILITY + control_c(); +#endif +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new_ref_symbolic(s)) << 16; +#else + __SYMBptr = new_ref_symbolic(s) ; +#endif + type = _SYMB; + subtype = 0; +#if defined KHICAS && !defined SIMU + if (_SYMBptr->sommet!=at_restart && _SYMBptr->sommet!=at_purge && (size_t) _SYMBptr > stackptr) + ctrl_c=interrupted=true; +#endif + } + + gen::gen(ref_symbolic * sptr){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(sptr) << 16; +#else + __SYMBptr = sptr; +#endif + type = _SYMB; + subtype = 0; +#if defined KHICAS && !defined SIMU + if (_SYMBptr->sommet!=at_restart && _SYMBptr->sommet!=at_purge && (size_t) _SYMBptr > stackptr) + ctrl_c=interrupted=true; +#endif + } + + gen::gen(ref_identificateur * sptr){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(sptr) << 16; +#else + __IDNTptr = sptr; +#endif + type = _IDNT; + subtype = 0; + } + + gen::gen(const gen_user & g){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_gen_user(g)) << 16; +#else + __USERptr = new ref_gen_user(g) ; +#endif + type = _USER; + subtype=0; + } + + gen::gen(ref_gen_user * sptr){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(sptr) << 16; +#else + __USERptr = sptr; +#endif + type = _USER; + subtype = 0; + } + +#ifdef ALLOC44 + ref_eqwdata * new_ref_eqwdata(const eqwdata & e){ + ref_eqwdata * ptr=(ref_eqwdata *) allocfast(sizeof(ref_eqwdata)); + ptr->ref_count=1; + *(unsigned *)&ptr->e=0; + *((unsigned *)&ptr->e+1)=0; + *((unsigned *)&ptr->e+2)=0; + *((unsigned *)&ptr->e+3)=0; + *((unsigned *)&ptr->e+4)=0; + *((unsigned *)&ptr->e+5)=0; + *((unsigned *)&ptr->e+6)=0; + *((unsigned *)&ptr->e+7)=0; + *((unsigned *)&ptr->e+8)=0; + *((unsigned *)&ptr->e+9)=0; + ptr->e=e; + return ptr; + } +#endif + + gen::gen(const eqwdata & g){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_eqwdata(g)) << 16; +#else +#ifdef ALLOC44 + __EQWptr = new_ref_eqwdata(g); +#else + __EQWptr = new ref_eqwdata(g); +#endif +#endif + type = _EQW; + subtype=0; + } + + gen::gen(const grob & g){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_grob(g)) << 16; +#else + __GROBptr = new ref_grob(g); +#endif + type = _GROB; + subtype=0; + } + + gen makemap(){ + gen g; +#ifdef SMARTPTR64 + * ((ulonglong * ) &g) = ulonglong(new ref_gen_map) << 16; +#else +#if 1 // def NSPIRE + g.__MAPptr = new ref_gen_map; +#else +#ifdef CPP11 + g.__MAPptr = new ref_gen_map(islesscomplexthanf); +#else + g.__MAPptr = new ref_gen_map(ptr_fun(islesscomplexthanf)); +#endif // CPP11 +#endif +#endif + g.type=_MAP; + g.subtype=0; + return g; + } + + gen::gen(const gen_map & s){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_gen_map(s)) << 16; +#else + __MAPptr = new ref_gen_map(s) ; +#endif + type = _MAP; + subtype = 0; + } + + gen::gen(const polynome & p){ + subtype=0; + if (p.coord.empty()){ + type = _INT_; + val = 0; + } + else { + if (Tis_constant(p) && is_atomic(p.coord.front().value) ){ + type = _INT_; + * this = p.coord.front().value; + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new Tref_tensor(p)) << 16; +#else + __POLYptr = new Tref_tensor(p) ; +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _POLYptr > stackptr) + ctrl_c=interrupted=true; +#endif + type = _POLY; + } + } + } + + gen::gen(const fraction & p){ + subtype=0; + if (is_undef(p.num) || is_undef(p.den)){ + type=_INT_; + *this=undef; + return; + } + if (is_inf(p.den)){ + type=_INT_; + val=0; + if (is_inf(p.num)) + *this=undef; + return; + } + if (is_exactly_zero(p.num)){ + type=_INT_; + val=0; + return; + } + if (is_one(p.den)){ + type=_INT_; + *this = p.num; + return; + } + if (is_minus_one(p.den)){ + type=_INT_; + *this = -p.num; + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new Tref_fraction(p)) << 16; +#else + __FRACptr = new Tref_fraction(p) ; +#endif + type = _FRAC; + } + } + + gen::gen(Tref_tensor * pptr){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(pptr) << 16; +#else + __POLYptr = pptr ; +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _POLYptr > stackptr) + ctrl_c=interrupted=true; +#endif + subtype=0; + type = _POLY; + } + + // WARNING coerce *mptr to an int if possible, in this case delete mptr + // Pls do not use this constructor unless you know exactly what you do!! + gen::gen(ref_mpz_t * mptr){ + int l=mpz_sizeinbase(mptr->z,2); + // if (l<17){ + if (l<32){ + type = _INT_; + val = mpz_get_si(mptr->z); + // COUT << "Destruction by mpz_t * " << *mptr << '\n'; + delete mptr; + } + else { + if (l>MPZ_MAXLOG2){ + type=0; +#if 1 + *this=undef; +#else + *this=(mpz_sgn(mptr->z)==-1)?minus_inf:plus_inf; +#endif + delete mptr; + return; + } +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(mptr) << 16; +#else + __ZINTptr = mptr; +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _ZINTptr > stackptr) + ctrl_c=interrupted=true; +#endif + type =_ZINT; + } + subtype=0; + // COUT << *this << '\n'; + } + + // WARNING coerce *mptr to an int if possible, in this case delete mptr + // Pls do not use this constructor unless you know exactly what you do!! + bool ref_mpz_t2gen(ref_mpz_t * mptr,gen & g){ + if (g.type>_DOUBLE_){ + g=mptr; + return true; + } + int l=mpz_sizeinbase(mptr->z,2); + // if (l<17){ + if (l<32){ + g.type=_INT_; + g.subtype=0; + g.val = mpz_get_si(mptr->z); + // COUT << "Destruction by mpz_t * " << *mptr << '\n'; + return false; + } + else { + if (l>MPZ_MAXLOG2){ + g.type=0; +#if 1 + g=undef; +#else + g=(mpz_sgn(mptr->z)==-1)?minus_inf:plus_inf; +#endif + return false; + } +#ifdef SMARTPTR64 + * ((ulonglong * ) &g) = ulonglong(mptr) << 16; +#else + g.__ZINTptr = mptr; +#endif + g.type =_ZINT; + g.subtype=0; + return true; + } + } + + gen::gen(const my_mpz& z){ + int l=mpz_sizeinbase(z.ptr,2); + if (l<32){ + type = _INT_; + val = mpz_get_si(z.ptr); + } + else { + if (l>MPZ_MAXLOG2){ + type=0; +#if 1 + *this=undef; +#else + *this=(mpz_sgn(z.ptr)==-1)?minus_inf:plus_inf; +#endif + return; + } +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(z.ptr)) << 16; +#else + __ZINTptr = new ref_mpz_t(z.ptr); +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _ZINTptr > stackptr) + ctrl_c=interrupted=true; +#endif + type =_ZINT; + } + subtype=0; + } + + gen::gen(const gen & e) { + if (e.type>_DOUBLE_ && e.type!=_FLOAT_ +#ifndef SMARTPTR64 + && e.type!=_FUNC +#endif + ) { + if ( +#ifdef SMARTPTR64 + (*((ulonglong *) &e) >> 16) +#else + e.__ZINTptr +#endif + ){ + ref_count_t * rc=(ref_count_t *)&e.ref_count(); + if (*rc!=-1) + ++(*rc); + } + } +#ifdef DOUBLEVAL + _DOUBLE_val = e._DOUBLE_val; +#else + * ((longlong *) this) = *((longlong * ) &e); +#endif +#ifndef SMARTPTR64 + __ZINTptr=e.__ZINTptr; +#endif + type=e.type; + subtype=e.subtype; + } + + inline ref_complex * new_ref_complex(gen a,gen b){ +#if defined(SMARTPTR64) || !defined(ALLOCSMALL) + return new ref_complex(a,b); +#else + ref_complex * ptr= (ref_complex *) allocfast(sizeof(ref_complex)); + ptr->ref_count=1; + ptr->display=0; + ptr->re.type=0; + ptr->re=a; + ptr->im.type=0; + ptr->im=b; + return ptr; +#endif + } + + gen::gen(int a,int b) { + subtype=0; + if (!b){ + type=_INT_; + val=a; + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_complex(a,b)) << 16; +#else + __CPLXptr = new_ref_complex(a,b); +#endif + type =_CPLX; + subtype=0; + } + } + +#ifndef DOUBLEVAL + gen::gen(double d){ + opaque_double_copy(&d,this); type=_DOUBLE_; + }; +#endif + + gen::gen(double a,double b){ + subtype=0; + // COUT << a << " " << b << " " << epsilon << '\n'; + if (fabs(b)<1e-12*fabs(a)){ +#ifdef DOUBLEVAL + _DOUBLE_val=a; +#else + *((double *) this) = a; +#endif + type=_DOUBLE_; + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_complex(a,b)) << 16; +#else +#if 0 //def FXCG + __CPLXptr = new ref_complex(a,b); +#else + __CPLXptr = new_ref_complex(a,b); +#endif +#endif + type =_CPLX; + subtype=3; + } + } + + gen::gen(const gen & a,const gen & b) { // a and b must be type <2! + if ( (a.type>=_CPLX && a.type!=_FLOAT_) || (b.type>=_CPLX && b.type!=_FLOAT_) ){ + type=0; + *this=a+cst_i*b; // gentypeerr(gettext("complex constructor")); + return; + } + if (is_exactly_zero(b)){ + if (a.type==_FLOAT_){ + type=0; + *this=a; + } + else { + type=a.type; + switch (type ) { + case _INT_: + val=a.val; + subtype=0; + break; + case _DOUBLE_: +#ifdef DOUBLEVAL + _DOUBLE_val = a._DOUBLE_val; +#else + *((double *) this) = a._DOUBLE_val; + type=_DOUBLE_; +#endif + break; + case _ZINT: +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(*a._ZINTptr)) << 16; +#else + __ZINTptr=new ref_mpz_t(a.__ZINTptr->z); // a is a _ZINT +#endif + type=_ZINT; + subtype=0; + break; + case _REAL: + subtype=0; +#ifdef SMARTPTR64 +#ifndef NO_RTTI + if (real_interval * ptr=dynamic_cast(a._REALptr)){ + * ((ulonglong * ) this) = ulonglong(new ref_real_interval(*ptr)) << 16; + subtype=1; + } + else +#endif + * ((ulonglong * ) this) = ulonglong(new ref_real_object(*a._REALptr)) << 16; +#else +#ifndef NO_RTTI + if (real_interval * ptr=dynamic_cast(a._REALptr)){ + __REALptr=(ref_real_object *) new ref_real_interval(*ptr); + subtype=1; + } + else +#endif + __REALptr=new ref_real_object(a.__REALptr->r); +#endif + type=_REAL; + break; + default: + type=0; + *this=gentypeerr(gettext("complex constructor")); + } + } + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_complex(a,b)) << 16; +#else + __CPLXptr = new_ref_complex(a,b); +#endif + type =_CPLX; + subtype= (a.type==_DOUBLE_) + (b.type==_DOUBLE_)*2; + } + } + gen::gen(const complex & c) { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_complex(c)) << 16; +#else + __CPLXptr = new ref_complex(c); +#endif + type=_CPLX; + subtype=3; + } + + double gen::DOUBLE_val() const { +#ifdef DOUBLEVAL + return _DOUBLE_val; +#else + return opaque_double_val(this); +#endif + } + + giac_float gen::FLOAT_val() const { +#ifdef DOUBLEVAL + return _FLOAT_val; +#else + longlong r = * (longlong *)(this) ; + // * (unsigned char *) (&r) = 0; +#ifdef BCD + return * (giac_float *)(&r); +#else + return giac_float(* (double *)(&r)); +#endif // BCD +#endif // DOUBLEVAL + } + + gen gen::makegen(int i) const { + switch (type){ + case _INT_: case _ZINT: case _CPLX: + return gen(i); + case _VECT: + return vecteur(1,i); + case _USER: + return _USERptr->makegen(i); + default: + return gensizeerr(gettext("makegen of type ")+print(context0)); + } + } + + complex gen2complex_d(const gen & e){ + if (e.type==_CPLX){ + if (e.subtype==3) + return complex((*e._CPLXptr)._DOUBLE_val,(*(e._CPLXptr+1))._DOUBLE_val); + gen ee=e.evalf_double(1,context0); // ok + if (ee.type==_DOUBLE_) return complex(ee._DOUBLE_val,0); + if (ee.type!=_CPLX){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("complex")); +#endif + return complex(nan(),nan()); + } + return complex((*ee._CPLXptr)._DOUBLE_val,(*(ee._CPLXptr+1))._DOUBLE_val); + } + if (e.type==_DOUBLE_) + return complex(e._DOUBLE_val,0); + if (e.type==_INT_) + return complex(e.val,0); + if (e.type==_ZINT) + return complex(e.evalf(1,context0)._DOUBLE_val,0); // ok +#ifndef NO_STDEXCEPT + setsizeerr(gettext("complex")); +#endif + return complex(nan(),nan()); + } + + gen::gen(const sparse_poly1 & p){ + if (p.empty()){ + type=0; + subtype=0; + val=0; + } + else { + if (is_undef(p.front().exponent)){ + type=0; + *this=undef; + } + else { +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_sparse_poly1(p)) << 16; +#else + __SPOL1ptr= new ref_sparse_poly1(p); +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _SPOL1ptr > stackptr) + ctrl_c=interrupted=true; +#endif + subtype=0; + type=_SPOL1; + } + } + } + + gen::gen(const unary_function_ptr * f,int nargs){ +#if defined SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_unary_function_ptr(*f)) << 16; +#else + _FUNC_ = (size_t) (* (size_t*) f); + // __FUNCptr= new ref_unary_function_ptr(f); +#endif + type=_FUNC; + subtype=nargs; + } + + gen::gen(const unary_function_ptr & f,int nargs){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_unary_function_ptr(f)) << 16; +#else + _FUNC_ = (size_t)(* (size_t *) &f); + // __FUNCptr= new ref_unary_function_ptr(f); +#endif + type=_FUNC; + subtype=nargs; + } + + gen::gen(const giac_float & f){ +#ifdef DOUBLEVAL + _FLOAT_val=f; +#else +#ifdef BCD + *((giac_float *) this) = f; +#else // BCD + *((double *) this) = f; +#endif // BCD +#endif // DOUBLEVAL + type=_FLOAT_; + } + +#ifdef BCD + gen::gen(accurate_bcd_float * b){ + giac_float f=fUnExpand(b); +#ifdef DOUBLEVAL + _FLOAT_val=f; +#else + *((giac_float *) this) = f; +#endif // DOUBLEVAL + type=_FLOAT_; + } +#endif // BCD + + void gen::delete_gen() { + switch (type) { +#ifdef SMARTPTR64 + case _ZINT: + delete (ref_mpz_t *) (* ((ulonglong * ) this) >> 16); + break; + case _REAL: { + ref_real_object * ptr=(ref_real_object *) (* ((ulonglong * ) this) >> 16); +#ifndef NO_RTTI + if (dynamic_cast(&ptr->r)) + delete (ref_real_interval *) ptr; + else +#endif + delete ptr; + break; + } + case _CPLX: + delete (ref_complex *) (* ((ulonglong * ) this) >> 16); + break; + case _IDNT: + delete (ref_identificateur *) (* ((ulonglong * ) this) >> 16); + break; + case _VECT: + delete (ref_vecteur *) (* ((ulonglong * ) this) >> 16); + break; + case _SYMB: + delete (ref_symbolic *) (* ((ulonglong * ) this) >> 16); + break; + case _USER: + delete (ref_gen_user *) (* ((ulonglong * ) this) >> 16); + break; + case _EXT: + delete (ref_algext *) (* ((ulonglong * ) this) >> 16); + break; + case _MOD: + delete (ref_modulo *) (* ((ulonglong * ) this) >> 16); + break; + case _POLY: + delete (ref_polynome *) (* ((ulonglong * ) this) >> 16); + break; + case _FRAC: + _FRACptr->den=_FRACptr->num=0; + delete (ref_fraction *) (* ((ulonglong * ) this) >> 16); + break; + case _SPOL1: + delete (ref_sparse_poly1 *) (* ((ulonglong * ) this) >> 16); + break; + case _STRNG: + delete (ref_string *) (* ((ulonglong * ) this) >> 16); + break; + case _FUNC: + delete (ref_unary_function_ptr *) (* ((ulonglong * ) this) >> 16); + break; + case _MAP: + delete (ref_gen_map *) (* ((ulonglong * ) this) >> 16); + break; + case _EQW: + delete (ref_eqwdata *) (* ((ulonglong * ) this) >> 16); + break; + case _GROB: + delete (ref_grob *) (* ((ulonglong * ) this) >> 16); + break; + case _POINTER_: + if (subtype==_FL_WIDGET_POINTER && fl_widget_delete_function) + fl_widget_delete_function(_POINTER_val); + if (subtype==_BUFFER_POINTER) + ; // free((ref_void_pointer *) (* ((ulonglong * ) this) >> 16)); + else + delete (ref_void_pointer *) (* ((ulonglong * ) this) >> 16); + break; +#else // SMARTPTR64 + case _ZINT: + delete __ZINTptr; + break; + case _REAL: { + ref_real_object * ptr=__REALptr; +#ifndef NO_RTTI + if (dynamic_cast(&ptr->r)) + delete (ref_real_interval *) __REALptr; + else +#endif + delete __REALptr; + break; + } + case _CPLX: + deletecomplex(__CPLXptr); // delete __CPLXptr; + break; + case _IDNT: + delete __IDNTptr; + break; + case _VECT: + delete_ref_vecteur(__VECTptr); // delete __VECTptr; + break; + case _SYMB: + deletesymbolic(__SYMBptr); // delete __SYMBptr; + break; + case _USER: + delete __USERptr; + break; + case _EXT: + delete __EXTptr; + break; + case _MOD: + delete __MODptr; + break; + case _POLY: + delete __POLYptr; + break; + case _FRAC: + delete __FRACptr; + break; + case _SPOL1: + delete __SPOL1ptr; + break; + case _STRNG: + delete __STRNGptr; + break; +#ifdef SMARTPTR64 + case _FUNC: + delete __FUNCptr; + break; +#endif + case _MAP: + delete __MAPptr; + break; + case _EQW: +#ifdef ALLOC44 + __EQWptr->e.g=0; + deletefast(__EQWptr); +#else + delete __EQWptr; +#endif + break; + case _GROB: + delete __GROBptr; + break; + case _POINTER_: + if (subtype==_FL_WIDGET_POINTER && fl_widget_delete_function) + fl_widget_delete_function(_POINTER_val); + delete __POINTERptr; + break; +#endif // SMARTPTR64 + default: +#ifndef NO_STDEXCEPT + settypeerr(gettext("Gen Destructor")); +#endif + ; + } + } + + void delete_ptr(signed char subtype,short int type_save,ref_mpz_t * ptr_save) { +#if 0 // def COMPILE_FOR_STABILITY // commented (D.Alm) The call to delete_ptr() would sometimes get cancelled if ctrl_c was being set, which could cause the "Stopped by user interruption." exception somehow to be fired twice, with the second time not being caught properly by my exception handling code. + control_c(); +#endif + if (ptr_save && type_save!=_FLOAT_&& ptr_save->ref_count!=-1 && !--(ptr_save->ref_count)){ + switch (type_save) { + case _ZINT: + delete ptr_save; + break; + case _REAL: { + ref_real_object * ptr=(ref_real_object *) ptr_save; +#ifndef NO_RTTI + if (dynamic_cast(&ptr->r)) + delete (ref_real_interval *) ptr; + else +#endif + delete ptr; + break; + } + case _CPLX: + deletecomplex((ref_complex *) ptr_save); + break; + case _IDNT: + delete (ref_identificateur *) ptr_save ; + break; + case _SYMB: + deletesymbolic( (ref_symbolic *) ptr_save); + break; + case _USER: + delete (ref_gen_user *) ptr_save; + break; + case _EXT: + delete (ref_algext * ) ptr_save; + break; + case _MOD: + delete (ref_modulo * ) ptr_save; + break; + case _VECT: + delete_ref_vecteur((ref_vecteur *) ptr_save); // delete (ref_vecteur *) ptr_save; + break; + case _POLY: + delete (ref_polynome *) ptr_save; + break; + case _FRAC: + delete (ref_fraction *) ptr_save; + break; + case _SPOL1: + delete (ref_sparse_poly1 *) ptr_save; + break; + case _STRNG: + delete (ref_string *) ptr_save; + break; +#ifdef SMARTPTR64 + case _FUNC: + delete (ref_unary_function_ptr *) ptr_save; + break; +#endif + case _MAP: + delete (ref_gen_map *) ptr_save; + break; + case _EQW: +#ifdef ALLOC44 + ((ref_eqwdata *) ptr_save)->e.g=0; + deletefast(ptr_save); +#else + delete (ref_eqwdata *) ptr_save; +#endif + break; + case _GROB: + delete (ref_grob *) ptr_save; + break; + case _POINTER_: + if (subtype==_FL_WIDGET_POINTER && fl_widget_delete_function) + fl_widget_delete_function( ((ref_void_pointer *)ptr_save)->p); + delete (ref_void_pointer *) ptr_save; + break; + case _FLOAT_: + break; + default: +#ifndef NO_STDEXCEPT + settypeerr(gettext("Gen Operator =")); +#endif + ; + } + } + } + + + double gen::to_double(GIAC_CONTEXT) const { + if (type==_DOUBLE_) + return _DOUBLE_val; + if (type==_INT_) + return double(val); + gen tmp=evalf_double(1,contextptr); + if (tmp.type==_DOUBLE_) + return tmp._DOUBLE_val; +#ifdef NAN + return NAN; +#else + double d=1.0; + d=d-d/double(1ULL<<53); + return d*2.0/d; +#endif + } + + bool gen::is_vector_of_size(size_t n) const { + return type==_VECT && _VECTptr->size()==n; + } + + bool gen::is_identificateur_with_name(const char * s) const { + return type==_IDNT && strcmp(_IDNTptr->id_name,s)==0; + } + + + int gen::to_int() const { + switch (type ) { + case _INT_: + return val; + case _ZINT: + return mpz_get_si(*_ZINTptr); + case _CPLX: + return _CPLXptr->to_int() ; + default: +#ifndef NO_STDEXCEPT + settypeerr(gettext("To_int")); +#endif + return 0; + } + return 0; + } + + void gen::uncoerce(size_t s) { + if (type==_INT_){ + int tmp =val; +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_mpz_t(s)) << 16; +#else + __ZINTptr = new ref_mpz_t(s); +#endif + type=_ZINT; + mpz_set_si(*_ZINTptr,tmp); + } + } + + gen _FRAC2_SYMB(const fraction & f){ + if (is_one(f.num)) + return symb_inv(f.den); + if (is_minus_one(f.num)) + return -symb_inv(f.den); + return symbolic(at_prod,makesequence(f.num,symb_inv(f.den))); + } + + gen _FRAC2_SYMB(const gen & e){ +#ifdef DEBUG_SUPPORT + if (e.type!=_FRAC) setsizeerr(gettext("gen.cc/_FRAC2_SYMB")); +#endif + return _FRAC2_SYMB(*e._FRACptr); + } + + gen _FRAC2_SYMB(const gen & n,const gen & d){ + return symbolic(at_prod,makesequence(n,symb_inv(d))); + } + + + /* Eval, evalf */ + gen evalf_VECT(const vecteur & v,int subtype,int level,const context * contextptr){ + // bool save_is_inevalf=is_inevalf; + // is_inevalf=true; + vecteur w; + vecteur::const_iterator it=v.begin(), itend=v.end(); + w.reserve(itend-it); + for (;it!=itend;++it){ + gen tmp=it->evalf(level,contextptr); + if (subtype){ + if ((subtype==_SEQ__VECT)&&(tmp.type==_VECT) && (tmp.subtype==_SEQ__VECT)){ + const_iterateur jt=tmp._VECTptr->begin(),jtend=tmp._VECTptr->end(); + for (;jt!=jtend;++jt) + w.push_back(*jt); + } + else { + if ((subtype!=_SET__VECT) || (!equalposcomp(w,tmp))) + w.push_back(tmp); + } + } + else + w.push_back(tmp); + } + // is_inevalf=save_is_inevalf; + return gen(w,subtype); + } + + + bool eval_VECT(const gen & g,gen & evaled,int subtype,int level,const context * contextptr){ + // const vecteur & v = *g._VECTptr; + gen tmp; + const gen * ansptr; + ref_vecteur * vptr; + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(),jt,jtend; + if (subtype!=_SET__VECT && subtype!=_SEQ__VECT){ + for (;it!=itend;++it){ + if (it->in_eval(level,evaled,contextptr)) + break; + } + if (it==itend) + return false; + } + vptr = new_ref_vecteur(0); + vptr->v.reserve(itend-g._VECTptr->begin()); + if (subtype!=_SET__VECT && subtype!=_SEQ__VECT){ + for (jt=g._VECTptr->begin();jt!=it;++jt) + vptr->v.push_back(*jt); + if (evaled.type==_VECT && evaled.subtype==_SEQ__VECT){ + jt=evaled._VECTptr->begin(); jtend=evaled._VECTptr->end(); + for (;jt!=jtend;++jt){ + //if ((subtype!=_SET__VECT) || (!equalposcomp(vptr->v,*jt))) + vptr->v.push_back(*jt); + } + } + else { + //if ( subtype!=_SET__VECT || (!equalposcomp(vptr->v,evaled))) + vptr->v.push_back(evaled); + } + ++it; + } + evaled=gen(vptr,subtype); + for (;it!=itend;++it){ + if (it->is_symb_of_sommet(at_comment)) + continue; + ansptr=(it->in_eval(level,tmp,contextptr))?&tmp:&*it; + if (ansptr->type==_VECT && ansptr->subtype==_SEQ__VECT){ + jt=ansptr->_VECTptr->begin(); jtend=ansptr->_VECTptr->end(); + for (;jt!=jtend;++jt){ + //if ((subtype!=_SET__VECT) || (!equalposcomp(vptr->v,*jt))) + vptr->v.push_back(*jt); + } + } + else { + //if ( subtype!=_SET__VECT || (!equalposcomp(vptr->v,*ansptr))) + vptr->v.push_back(*ansptr); + } + } + if (evaled.type==_VECT && subtype==_SET__VECT) + chk_set(*evaled._VECTptr); + // CERR << "End " << v << " " << w << '\n'; + return true; + } + + // evalf a real fraction + gen evalf_FRAC(const fraction & f,GIAC_CONTEXT){ + gen n(f.num),d(f.den); + if (n.type==_INT_ && d.type==_INT_) + return evalf(n,1,contextptr)/evalf(d,1,contextptr); + if (is_zero(n)) + return evalf(n,0,contextptr); + bool npos=is_positive(n,contextptr),dpos=is_positive(d,contextptr); + bool neg=npos?!dpos:dpos; + if (!npos) + n=-n; + if (!dpos) + d=-d; + bool inf1=is_greater(d,n,contextptr); +#ifdef FXCG + gen m=gen(longlong(1)<<61); + gen md=gen(1.0)/m; +#else +#ifdef BCD + static gen m=gen(longlong(100000000000000)); +#else + static gen m=gen(longlong(1)<<61); +#endif + static gen md=gen(1.0)/m; +#endif + if (absint(sizeinbase2(n)-sizeinbase2(d))>=53){ + gen a=inf1?iquo(d,n):iquo(n,d); + gen res=evalf(a,1,contextptr); + if (neg) res=-res; + return inf1?inv(res,contextptr):res; + } + gen a=inf1?iquo(d*m,n):iquo(n*m,d); + gen res=evalf(a,1,contextptr); + if (neg) res=-res; + res = md*res; + return inf1?inv(res,contextptr):res; + } + + // evaluate _FUNCndary in RPN mode, f must be of type _FUNC + static gen rpneval_FUNC(const gen & f,GIAC_CONTEXT){ + // int s=history_out(contextptr).size(); + int nargs=giacmax(f.subtype,0); + if (!nargs){ + gen res=(*f._FUNCptr)(gen(history_out(contextptr),_RPN_STACK__VECT),contextptr); + if ( (res.type!=_VECT) || (res.subtype!=_RPN_STACK__VECT)) + res=gen(makenewvecteur(res),_RPN_STACK__VECT); + history_out(contextptr)=*res._VECTptr; + history_in(contextptr)=history_out(contextptr); + return res; + } + vecteur v(nargs); + for (int i=nargs-1;i>=0;--i){ + v[i]=history_out(contextptr).back(); + history_out(contextptr).pop_back(); + history_in(contextptr).pop_back(); + } + if (nargs==1) + return (*f._FUNCptr)(v.front(),contextptr); + else + return (*f._FUNCptr)(v,contextptr); + } + + static bool evalcomment(const vecteur & v,gen &evaled,int level,const context * contextptr){ + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if ( (it->type!=_SYMB) || (it->_SYMBptr->sommet!=at_comment) ) + break; + } + if (it+1==itend){ + evaled=it->eval(level,contextptr); + return true; + } + if (it!=itend){ + gen partial=vecteur(it,itend); + if (eval_VECT(partial,evaled,_SEQ__VECT,level,contextptr)) + return true; + else { + evaled=partial; + return true; + } + } + evaled=zero; + return true; + } + + bool check_not_assume(const gen & not_evaled,gen & evaled, bool evalf_after,const context * contextptr){ + if ( evaled.type==_VECT && evaled.subtype==_ASSUME__VECT ){ + if ( evalf_after && evaled._VECTptr->size()==2 && (evaled._VECTptr->back().type<=_CPLX || evaled._VECTptr->back().type==_FRAC || evaled._VECTptr->back().type==_FLOAT_) ){ + evaled=evaled._VECTptr->back().evalf(1,contextptr); + return true; + } + if (not_evaled.type==_IDNT && evaled._VECTptr->size()==1 && evaled._VECTptr->front().type==_INT_){ + gen tmp=not_evaled; + tmp.subtype=evaled._VECTptr->front().val; + evaled=tmp; + return true; + } + return false; + } + else { + if (evalf_after && evaled.type!=_IDNT){ + gen res; + if (has_evalf(evaled,res,0,contextptr)){ + evaled=res; + return true; + } + } + return &evaled!=¬_evaled; + } + return false; + } + +#if 0 + gen gen::eval(int level,const context * contextptr) const{ + // CERR << "eval " << *this << " " << level << '\n'; + gen res; + // return in_eval(level,res,contextptr)?res:*this; + if (in_eval(level,res,contextptr)) + return res; + else + return *this; + } +#endif + + static bool in_eval_mod(const gen & g,gen & evaled,int level,GIAC_CONTEXT){ + evaled=makemod(g._MODptr->eval(level,contextptr),(g._MODptr+1)->eval(level,contextptr)); + return true; + } + + static bool in_eval_user(const gen & g,gen & evaled,int level,GIAC_CONTEXT){ + evaled=g._USERptr->eval(level,contextptr); + return true; + } + + static bool in_eval_func(const gen & g,gen * evaledptr,GIAC_CONTEXT){ + if (rpn_mode(contextptr) && (history_out(contextptr).size()>=unsigned(g.subtype))) + *evaledptr=rpneval_FUNC(g,contextptr); + else { + if (g.subtype) + return false; + else + *evaledptr=(*g._FUNCptr)(gen(vecteur(0),_SEQ__VECT),contextptr); + } + return true; + } + + static bool in_eval_idnt(const gen & g,gen & evaled,int level,GIAC_CONTEXT){ + identificateur * gptr=g._IDNTptr; + if (strcmp(gptr->id_name,string_pi)==0 || strcmp(gptr->id_name,string_euler_gamma)==0 ) + return false; + if (!contextptr && g.subtype==_GLOBAL__EVAL) + evaled=global_eval(*gptr,level); + else { + if (!gptr->in_eval(level-1,g,evaled,contextptr)) + return false; + } + if ( evaled.type!=_VECT || evaled.subtype!=_ASSUME__VECT ){ + if (evaled.is_symb_of_sommet(at_program)) + lastprog_name(gptr->id_name,contextptr); + return true; + } + return check_not_assume(g,evaled,false,contextptr); + } + + static bool in_eval_vect(const gen & g,gen & evaled,int level,GIAC_CONTEXT){ +#ifdef HAVE_LIBMPFI + if (g.subtype==_INTERVAL__VECT && g._VECTptr->size()==2){ + // convert to MPFI real_interval + gen l=eval(g._VECTptr->front(),level,contextptr),u=eval(g._VECTptr->back(),level,contextptr); + if (is_strictly_greater(l,u,contextptr)){ + swapgen(l,u); + } + bool lexact=is_integer(l),uexact=is_integer(u); + gen ul=u-l; + if (is_exactly_zero(ul)){ + if (u.type==_REAL) + ul=int(mpfr_get_prec(u._REALptr->inf)); + else + ul=int(3.2*decimal_digits(contextptr)); + } + else { + ul=u-l; + ul=2*ul/(abs(u,contextptr)+abs(l,contextptr)); + ul=ln(abs(evalf(ul,1,contextptr),contextptr),contextptr); + ul=-_ceil(ul/ln(evalf(2,1,contextptr),contextptr),contextptr); + } + int nbits=53; + if (ul.type==_INT_ && ul.val>48){ + nbits=ul.val+4; + l=accurate_evalf(l,nbits); + u=accurate_evalf(u,nbits); + } + else { + l=evalf(l,level,contextptr); u=evalf(u,level,contextptr); + } + if (l.type==_DOUBLE_ && u.type==_REAL) + u=evalf_double(u,1,contextptr); + if (u.type==_DOUBLE_ && l.type==_REAL) + l=evalf_double(l,1,contextptr); + if (l.type==_DOUBLE_){ + // adjust mantissa of l down and mantissa of u up + double epsilon=7e-15; // 2^(-47) + if (!lexact) + l=(1.+(l._DOUBLE_val>0?(-epsilon):(epsilon)))*l; + if (!uexact) + u=(1.+(u._DOUBLE_val>0?(epsilon):(-epsilon)))*u; + } + else { // do the same for MPFR + gen epsilon=pow(plus_two,nbits-2,contextptr); // nbits-3? + epsilon=fraction(1,epsilon); + if (!lexact){ + if (is_positive(l,contextptr)) + l=(1-epsilon)*l; + else + l=(1+epsilon)*l; + } + if (!uexact){ + if (is_positive(u,contextptr)) + u=(1+epsilon)*u; + else + u=(1-epsilon)*u; + } + } + if ( (l.type==_DOUBLE_ && u.type==_DOUBLE_) || + (l.type==_REAL && u.type==_REAL) ){ + mpfi_t interv; + mpfi_init(interv); + mpfi_set_prec(interv,nbits); + if (l.type==_DOUBLE_) + mpfi_interv_d(interv,l._DOUBLE_val,u._DOUBLE_val); + else + mpfi_interv_fr(interv,l._REALptr->inf,u._REALptr->inf); + evaled=gen(real_interval(interv)); + mpfi_clear(interv); + return true; + } + } +#endif + if (g.subtype==_SPREAD__VECT){ + makespreadsheetmatrice(*g._VECTptr,contextptr); + spread_eval(*g._VECTptr,contextptr); + return false; + } + if (g.subtype==_TABLE__VECT){ + eval_VECT(g,evaled,g.subtype,level,contextptr); + evaled=_table(evaled,contextptr); + return true; + } + if (g.subtype==_FOLDER__VECT || g.subtype==_RGBA__VECT) + return false; + if ( (g.subtype==_SEQ__VECT) && (!g._VECTptr->empty()) && (g._VECTptr->front().type==_SYMB) + && (g._VECTptr->front().is_symb_of_sommet(at_comment)) + && (g._VECTptr->back().type==_SYMB) + && (g._VECTptr->back().is_symb_of_sommet(at_return)) + ){ + return evalcomment(*g._VECTptr,evaled,level,contextptr); + } + if (g._VECTptr->size()==1 && g._VECTptr->front().is_symb_of_sommet(at_interval)) + return in_eval_vect(gen(makevecteur(g._VECTptr->front()[1],g._VECTptr->front()[2]),_INTERVAL__VECT),evaled,1,contextptr); + return eval_VECT(g,evaled,g.subtype,level,contextptr); + } + + bool gen::in_eval(int level,gen & evaled,const context * contextptr) const{ +#ifdef TIMEOUT + if (type!=_SYMB || _SYMBptr->sommet!=at_caseval) + control_c(); +#endif + if (ctrl_c || interrupted || !stack_check(contextptr)) { + interrupted = true; ctrl_c=false; + *logptr(contextptr) << "Stopped in in_eval" << '\n'; + gensizeerr(gettext("Stopped by user interruption or stack overflow."),evaled); + return true; + } + if (!level) + return false; + switch (type) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _ZINT: case _REAL: case _CPLX: case _POLY: case _FRAC: case _SPOL1: case _EXT: case _STRNG: case _MAP: case _EQW: case _GROB: case _POINTER_: + return false; + case _IDNT: + return in_eval_idnt(*this,evaled,level,contextptr); + case _VECT: + return in_eval_vect(*this,evaled,level,contextptr); + case _SYMB: + if (subtype==_SPREAD__SYMB) + return false; + { + symbolic * sptr=_SYMBptr; + unary_function_ptr & Sommet=sptr->sommet; + const gen & feuille=sptr->feuille; + bool is_ifte=false,is_of_local_ifte_bloc=false,is_plus=Sommet==at_plus,is_prod=false,is_pow=false; + if (is_plus || (is_prod=(Sommet==at_prod)) || (is_pow=(Sommet==at_pow)) || (is_of_local_ifte_bloc=(Sommet==at_of || Sommet==at_local || (is_ifte=Sommet==at_ifte) || Sommet==at_bloc)) ){ + int & elevel=eval_level(contextptr); + short int slevel=elevel; + // Check if we are not far from stack end +#ifdef RTOS_THREADX + if ((void *)&slevel<= (void *)&mainThreadStack[2048]){ + if ((void *)&slevel<= (void *)&mainThreadStack[1024]){ + gensizeerr(gettext("Too many recursion levels"),evaled); // two many recursion levels + return true; + } + evaled=nr_eval(*this,level,contextptr); + return true; + } +#else // rtos +#if !defined(WIN32) && defined(HAVE_PTHREAD_H) && defined HAVE_LIBPTHREAD + void * stackaddr; + if (contextptr && (stackaddr=thread_param_ptr(contextptr)->stackaddr)){ + // CERR << &slevel << " " << thread_param_ptr(contextptr)->stackaddr << '\n'; + if ( ((size_t) &slevel) < ((size_t) stackaddr)+65536){ + if ( ((size_t) &slevel) < ((size_t) stackaddr)+8192){ + gensizeerr(gettext("Too many recursion levels"),evaled); // two many recursion levels + return true; + } + *logptr(contextptr) << gettext("Running non recursive evaluator") << '\n'; + evaled=nr_eval(*this,level,contextptr); + return true; + } + } else +#endif // pthread + { + debug_struct * dbgptr=debug_ptr(contextptr); + if ( int(dbgptr->sst_at_stack.size()) >= MAX_RECURSION_LEVEL){ + if ( int(dbgptr->sst_at_stack.size()) >= MAX_RECURSION_LEVEL+10){ + gensizeerr(gettext("Too many recursions)"),evaled); + return true; + } +#ifdef KHICAS + if (warn_nr){ + *logptr(contextptr) << gettext("Running non recursive evaluator") << '\n'; + warn_nr=false; + } +#else + *logptr(contextptr) << gettext("Running non recursive evaluator") << '\n'; +#endif + evaled=nr_eval(*this,level,contextptr); + return true; + } + } +#endif // rtos + const vecteur * vptr; + if ( (is_plus ||is_prod || is_pow) && feuille.type==_VECT && (vptr=feuille._VECTptr)->size()==2){ + const gen & vptrfront=vptr->front(); + const gen & vptrback=vptr->back(); + gen a; + if (!vptrfront.in_eval(level,a,contextptr)) + a=vptrfront; + if (a.type!=_VECT || a.subtype!=_SEQ__VECT){ + if (!vptrback.in_eval(level,evaled,contextptr)) + evaled=vptrback; + if (evaled.type!=_VECT || evaled.subtype!=_SEQ__VECT){ + if (is_plus) evaled=operator_plus(a,evaled,contextptr); + else { + if (is_prod) evaled=operator_times(a,evaled,contextptr); + else evaled=pow(a,evaled,contextptr); + } + elevel=slevel; + return true; + } + } + } + if (is_of_local_ifte_bloc){ + elevel=level; + evaled=feuille; // FIXME must also set eval_level to level + } + else { + if (!feuille.in_eval(level,evaled,contextptr)) + evaled=feuille; + } + if (is_ifte) + evaled=ifte(evaled,true,contextptr); + else + evaled=(*Sommet.ptr())(evaled,contextptr); + elevel=slevel; + } + else + evaled=sptr->eval(level,contextptr); + return true; + } + case _USER: + return in_eval_user(*this,evaled,level,contextptr); + case _MOD: + return in_eval_mod(*this,evaled,level,contextptr); + case _FUNC: + return in_eval_func(*this,&evaled,contextptr); + default: + gentypeerr("Eval",evaled) ; + return false; + } + return false; + } + + polynome apply( const polynome & p, const gen_op & f){ + polynome res(p.dim); + std::vector< monomial > :: const_iterator it=p.coord.begin(),itend=p.coord.end(); + res.coord.reserve(itend-it); + for (;it!=itend;++it){ + gen tmp(f(it->value)); + if (!is_zero(tmp,context0)) + res.coord.push_back(monomial(tmp,it->index)); + } + return res; + } + + polynome apply( const polynome & p, const context * contextptr, gen (* f) (const gen &, const context *)){ + polynome res(p.dim); + std::vector< monomial > :: const_iterator it=p.coord.begin(),itend=p.coord.end(); + res.coord.reserve(itend-it); + for (;it!=itend;++it){ + gen tmp(f(it->value,contextptr)); + if (!is_zero(tmp,contextptr)) + res.coord.push_back(monomial(tmp,it->index)); + } + return res; + } + + static gen set_precision(const gen & g,int nbits){ + if (nbits<45) + return evalf_double(g,1,context0); +#ifdef HAVE_LIBMPFR + return real_object(g,nbits); +#else + gen tmp=evalf_double(g,1,context0); + gen G=g; + if (tmp.type==_DOUBLE_ && tmp._DOUBLE_val!=0) + round2(G,int(nbits-std::log(absdouble(tmp._DOUBLE_val))/std::log(2.0))); + return evalf_double(G,1,context0); +#endif + } + + gen accurate_evalf(const gen & g,int nbits){ + if (g.type==_FRAC && g._FRACptr->num.type==_VECT) + return inv(accurate_evalf(g._FRACptr->den,nbits),context0)*accurate_evalf(g._FRACptr->num,nbits); + if (g.type==_VECT) + return gen(accurate_evalf(*g._VECTptr,nbits),g.subtype); + if (g.type==_SYMB) + return symbolic(g._SYMBptr->sommet,accurate_evalf(g._SYMBptr->feuille,nbits)); + if (g.type==_IDNT){ + if (g==cst_pi) + return m_pi(nbits); + if (g==cst_euler_gamma) + return m_gamma(nbits); + return g; + } + gen r,i;reim(g,r,i,context0); // only called for numeric values + if (is_exactly_zero(i)) + return set_precision(r,nbits); + else + return gen(set_precision(r,nbits),set_precision(i,nbits)); + } + + vecteur accurate_evalf(const vecteur & v,int nbits){ + vecteur res(v); + iterateur it=res.begin(),itend=res.end(); + for (;it!=itend;++it) + *it = accurate_evalf(*it,nbits); + return res; + } + + gen evalf(const gen & e,int level,const context * contextptr){ + return e.evalf(level,contextptr); + } + + gen no_context_evalf(const gen & e){ + gen tmp; + if (has_evalf(e,tmp,1,context0)) + return tmp; + else + return e; + } + + static const double double0_15[]={0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0}; + static double _int2double(unsigned i){ + if (i<16) + return double0_15[i]; + else + return _int2double(i/16)*16.0+double0_15[i%16]; + } + // double(int) does not seem to work under GNUWINCE + double int2double(int i){ + if (i<0){ +#if defined WIN32 && !defined __CYGWIN__ // INT_MAX not defined with cygwin + if (i<-INT_MAX) return -1.0-INT_MAX; +#else + if (i<-RAND_MAX) return -1.0-RAND_MAX; +#endif + return -_int2double(-i); + } + else + return _int2double(i); + } + + + gen gen::evalf(int level,const context * contextptr) const{ + // CERR << "evalf " << *this << " " << level << '\n'; +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + if (level==0) + return *this; + gen evaled; + if (in_evalf(level,evaled,contextptr)) + return evaled; + else + return *this; + } + + gen m_pi(GIAC_CONTEXT){ + int nbits=digits2bits(decimal_digits(contextptr)); + return m_pi(nbits); + } + + gen m_pi(int nbits){ +#ifdef HAVE_LIBMPFR + if (nbits>48){ +#ifdef HAVE_LIBPTHREAD + int locked=pthread_mutex_lock(&mpfr_mutex); +#else // HAVE_LIBPTHREAD + int locked=0; +#endif + if (!locked) + mpfr_set_default_prec(nbits); + mpfr_t pi; + mpfr_init(pi); + mpfr_const_pi(pi,MPFR_RNDN); +#ifdef HAVE_LIBPTHREAD + if (!locked) + pthread_mutex_unlock(&mpfr_mutex); +#endif + gen res=real_object(pi); + mpfr_clear(pi); + return res; + } +#endif +#if 0 // def BCD + return fpi(); +#else + return M_PI; +#endif + } + + gen m_gamma(int nbits){ +#ifdef HAVE_LIBMPFR + if (nbits>15){ +#ifdef HAVE_LIBPTHREAD + int locked=pthread_mutex_lock(&mpfr_mutex); +#else // HAVE_LIBPTHREAD + int locked=0; +#endif + if (!locked) + mpfr_set_default_prec(nbits); + mpfr_t euler_gamma; + mpfr_init(euler_gamma); +#ifdef BF2GMP_H + mpfr_set_str(euler_gamma,"0.5772156649015328606065120900824024310421593359399235988057672348848677267776646709369470632917467495146314472498070824809605040144865428362241739976449235362535003337429373377376739427925952582470949160087352039481656708532331517766115286211995015079847937450857057400299213547861466940296043254215190587755352",nbits,MPFR_RNDN); +#else + mpfr_const_euler(euler_gamma,MPFR_RNDN); +#endif +#ifdef HAVE_LIBPTHREAD + if (!locked) + pthread_mutex_unlock(&mpfr_mutex); +#endif + gen res=real_object(euler_gamma); + mpfr_clear(euler_gamma); + return res; + } +#endif + return .577215664901533; + } + + gen m_gamma(GIAC_CONTEXT){ + int nbits=digits2bits(decimal_digits(contextptr)); + return m_gamma(nbits); + } + + static bool approx_pnt(int level,const gen & g,gen & evaled,const context * contextptr){ + vecteur v=*g._SYMBptr->feuille._VECTptr; + if (!v[0].in_evalf(level,evaled,contextptr)) + return false; + v[0]=evaled; + evaled=symbolic(at_pnt,gen(v,g._SYMBptr->feuille.subtype)); + return true; + } + + static bool has_evalf(const identificateur & g,int subtype,gen & res,int level,GIAC_CONTEXT){ + if (strcmp(g.id_name,string_pi)==0){ + res=m_pi(contextptr); + return true; + } + gen tmp=g; + tmp.subtype=subtype; + tmp=tmp.evalf(level,contextptr); + if (tmp.type==_IDNT || tmp.type==_SYMB) + return false; + return has_evalf(tmp,res,0,contextptr); + } + + bool has_evalf(const gen & g,gen & res,int level,GIAC_CONTEXT){ + switch (g.type){ + case _DOUBLE_: case _FLOAT_: case _REAL: + res=g; + return true; + case _INT_: case _ZINT: case _CPLX: + res=evalf(g,1,contextptr); + return true; + case _IDNT: + return has_evalf(*g._IDNTptr,g.subtype,res,level,contextptr); + case _SYMB: + if (has_evalf(g._SYMBptr->feuille,res,level,contextptr)){ + res=g._SYMBptr->sommet(res,contextptr); + if (res.type==_INT_ || res.type==_ZINT) + res=evalf(res,1,contextptr); + return res.type==_DOUBLE_ || res.type==_FLOAT_ || res.type==_CPLX || res.type==_REAL; + } + else + return false; + } + if (g.type==_EXT){ + gen a,b; + if (has_evalf(*g._EXTptr,a,level,contextptr) && has_evalf(*(g._EXTptr+1),b,level,contextptr)){ + a=alg_evalf(a,b,*(g._EXTptr+2),contextptr); + return a.type==_EXT?false:has_evalf(a,res,level,contextptr); + } + return false; + } + if (g.type==_FRAC){ + if (is_cinteger(g._FRACptr->num) && is_cinteger(g._FRACptr->den)){ + return g.in_evalf(1,res,contextptr); + } + gen num,den; + if (has_evalf(g._FRACptr->num,num,level,contextptr) && has_evalf(g._FRACptr->den,den,level,contextptr)){ + res=num/den; + return true; + } + else + return false; + } + if (g.type!=_VECT) + return false; + if (g.subtype==_ASSUME__VECT && !g._VECTptr->empty()){ + res=g._VECTptr->back(); + return true; + } + vecteur v; + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + v.reserve(itend-it); + for (;it!=itend;++it){ + if (!has_evalf(*it,res,level,contextptr)) + return false; + v.push_back(res); + } + res=gen(v,g.subtype); + return true; + } + + bool gen::in_evalf(int level,gen & evaled,const context * contextptr) const{ + if (!level) + return false; + switch (type) { + case _REAL: +#if 0 // ndef NO_RTTI // infinite recursion with has_evalf and real intervals + if (real_interval * ptr=dynamic_cast(_REALptr)){ + evaled=real_object(ptr->inf); + return true; + } +#endif + return false; + case _DOUBLE_: case _FLOAT_: case _STRNG: case _MAP: case _EQW: case _GROB: case _POINTER_: + return false; + case _INT_: + if (subtype) + return false; + if (decimal_digits(contextptr)>14){ + evaled=real_object(*this,digits2bits(decimal_digits(contextptr))); + return true; + } +#if 0 // def BCD + evaled=giac_float(val); +#else + evaled=int2double(val); +#endif + return true; + case _ZINT: +#if 0 // def BCD + evaled=giac_float(_ZINTptr); +#else + if (decimal_digits(contextptr)>14) + evaled=real_object(*this,digits2bits(decimal_digits(contextptr))); + else + evaled=mpz_get_d(*_ZINTptr); +#endif + return true; + case _CPLX: + evaled=gen(_CPLXptr->evalf(level,contextptr),(_CPLXptr+1)->evalf(level,contextptr)); + return true; + case _USER: + evaled=_USERptr->evalf(level,contextptr); + return true; + case _IDNT: + if (strcmp(_IDNTptr->id_name,string_pi)==0){ + evaled=m_pi(contextptr); + return true; + } + if (strcmp(_IDNTptr->id_name,string_euler_gamma)==0){ + evaled=m_gamma(contextptr); + return true; + } + if (!contextptr && subtype==_GLOBAL__EVAL) + evaled=global_evalf(*_IDNTptr,level-1); + else { + if (!_IDNTptr->in_eval(level-1,*this,evaled,contextptr)) + return false; + } + return check_not_assume(*this,evaled,true,contextptr); + case _VECT: + evaled=evalf_VECT(*_VECTptr,subtype,level,contextptr); + return true; + case _SYMB: + if (subtype==_SPREAD__SYMB) + return false; + if (_SYMBptr->sommet==at_pow && _SYMBptr->feuille._VECTptr->back().type==_INT_){ + evaled=pow(_SYMBptr->feuille._VECTptr->front().evalf(level,contextptr),_SYMBptr->feuille._VECTptr->back(),contextptr); + return true; + } + if (_SYMBptr->sommet==at_integrate || (_SYMBptr->sommet==at_int && xcas_mode(contextptr)!=3)){ + evaled=_gaussquad(_SYMBptr->feuille,contextptr); // FIXME: take care of precision (romberg if >14 digits?) + return true; + } + if (_SYMBptr->sommet==at_rootof){ + gen f=_SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()>2 && f[1].type!=_VECT) + f=makevecteur(makevecteur(1,0),f); + evaled=approx_rootof(f.evalf(level,contextptr),contextptr); + return true; + } + if (_SYMBptr->sommet==at_cell) + return false; + if (_SYMBptr->sommet==at_pnt && _SYMBptr->feuille.type==_VECT && !_SYMBptr->feuille._VECTptr->empty()) + return approx_pnt(level,*this,evaled,contextptr); + evaled=_SYMBptr->evalf(level,contextptr); + return true; + case _FRAC: +#ifdef HAVE_LIBMPFR + if (decimal_digits(contextptr)>14) + evaled=rdiv(_FRACptr->num.evalf(level,contextptr),_FRACptr->den.evalf(level,contextptr),contextptr); + else +#endif + { + if (is_zero(_FRACptr->num.im(contextptr)) && is_zero(_FRACptr->den.im(contextptr))) + evaled=evalf_FRAC(*_FRACptr,contextptr); + else + evaled=re(contextptr).evalf(1,contextptr)+cst_i*im(contextptr).evalf(1,contextptr); + } + return true; +#ifdef HAVE_LIBMPFR + if (decimal_digits(contextptr)<=14) + evaled=set_precision(re(contextptr),60).evalf_double(1,contextptr)+cst_i*set_precision(im(contextptr),60).evalf_double(1,contextptr); + else +#endif + evaled=rdiv(_FRACptr->num.evalf(level,contextptr),_FRACptr->den.evalf(level,contextptr),contextptr); + return true; + case _FUNC: + return in_eval_func(*this,&evaled,contextptr); + case _MOD: case _ROOT: + return false; // replace in RPN mode + case _EXT: + evaled=alg_evalf(_EXTptr->eval(level,contextptr),(_EXTptr+1)->eval(level,contextptr),*(_EXTptr+2),contextptr); + return true; + case _POLY: + evaled=apply(*_POLYptr,no_context_evalf); + return true; + default: + evaled=gentypeerr(gettext("Evalf")) ; + return false; + } + return false; + } + + gen real2int(const gen & g,GIAC_CONTEXT){ + if (g.type==_REAL){ + if (is_strictly_positive(-g,contextptr)) + return -real2int(-g,contextptr); + if (is_zero(g)) + return 0; +#ifdef BF2GMP_H + ref_mpz_t * m=new ref_mpz_t; + mpz_init(m->z); + mpz_set(m->z,g._REALptr->inf); + bf_rint(&m->z,BF_RNDD); + return gen(m); +#else +#ifdef HAVE_LIBMPFR + ref_mpz_t * m=new ref_mpz_t; + int n=int(mpfr_get_z_exp(m->z,g._REALptr->inf)); + gen res(m->z); + if (n>=0) + return res*pow(plus_two,gen(n),contextptr); + return _iquo(makesequence(res,pow(plus_two,gen(-n),contextptr)),contextptr); +#else + return g; +#endif // MPFR +#endif // BF2GMP_H + } + if (g.type!=_VECT) + return g; + return apply(g,real2int,contextptr); + } + + gen real2double(const gen & g){ + if (g.type==_REAL) + return g._REALptr->evalf_double(); + if (g.type==_FLOAT_) + return get_double(g._FLOAT_val); + if (g.type!=_VECT) + return g; + return apply(g,real2double); + } + + gen gen::evalf_double(int level,const context * contextptr) const{ + if (type==_DOUBLE_) + return *this; + if (type==_INT_ && subtype==_INT_BOOLEAN) + return double(val); + gen g; + if (has_evalf(*this,g,level,contextptr)){ + if (g.type==_CPLX) + return gen(real2double(*g._CPLXptr),real2double(*(g._CPLXptr+1))); + else + return real2double(g); + } + else + return *this; + } + + gen evalf2double_nock(const gen & g0,int level,const context * contextptr){ + if (g0.type==_INT_) + return double(g0.val); + if (g0.type==_DOUBLE_) + return g0; + if (g0.type==_IDNT && contextptr && level){ + sym_tab::const_iterator it=contextptr->tabptr->find(g0._IDNTptr->id_name); + if (it!=contextptr->tabptr->end()){ + return evalf2double_nock(it->second,level-1,contextptr); + } + } + if (g0.is_symb_of_sommet(at_program)) + return g0; + if (g0.type==_FLOAT_ || g0.type==_FRAC || g0.type==_ZINT || g0.type==_REAL) + return evalf_double(g0,1,contextptr); + if (storcl_38 && level && g0.type==_IDNT){ + if (!strcmp(g0._IDNTptr->id_name,"pi")) + return M_PI; + gen res; +// if (storcl_38(res,0,g0._IDNTptr->id_name,undef,false,contextptr)) return evalf2double_nock(res,level-1,contextptr); + } + if (g0.type==_VECT){ + ref_vecteur *vptr = new_ref_vecteur(*g0._VECTptr); + iterateur it=vptr->v.begin(),itend=vptr->v.end(); + for (;it!=itend;++it) + *it=evalf2double_nock(*it,level,contextptr); + return gen(vptr,g0.subtype); + } + if (is_inf(g0)||is_undef(g0)) + return g0; + if (g0.type==_SYMB){ + unary_function_ptr & s =g0._SYMBptr->sommet; + gen f =g0._SYMBptr->feuille; + if (s==at_integrate && f._VECTptr->size()==4) + return _gaussquad(f,contextptr); + if (f.type==_VECT && !s.quoted()){ + if (s==at_plus){ + double res(0); + gen tmp; + iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end(); + for (;it!=itend;++it){ + tmp=evalf2double_nock(*it,level,contextptr); + if (tmp.type!=_DOUBLE_) + break; + res=res+tmp._DOUBLE_val; + } + if (it==itend) + return res; + } + if (s==at_prod){ + double res(1); + gen tmp; + iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end(); + for (;it!=itend;++it){ + tmp=evalf2double_nock(*it,level,contextptr); + if (tmp.type!=_DOUBLE_) + break; + res=res*tmp._DOUBLE_val; + } + if (it==itend) + return res; + } + if (f._VECTptr->size()==2){ + gen tmp1=evalf2double_nock(f._VECTptr->front(),level,contextptr); + gen tmp2=f._VECTptr->back(); + if (tmp1.type==_DOUBLE_ && tmp2.type==_INT_ && s==at_pow) + return std::pow(tmp1._DOUBLE_val,double(tmp2.val)); + tmp2=evalf2double_nock(tmp2,level,contextptr); + if (s==at_pow) + return pow(tmp1,tmp2,contextptr); + if (s==at_division) + return rdiv(tmp1,tmp2,contextptr); + if (s==at_minus) + return operator_minus(tmp1,tmp2,contextptr); + tmp1=s(gen(makenewvecteur(tmp1,tmp2),f.subtype),contextptr); + if (tmp1.type<_IDNT || tmp1.type==_FRAC) + tmp1=evalf2double_nock(tmp1,1,contextptr); + return tmp1; + } + } + if (s.quoted()) { + if (s==at_quote) + return f; + if (f.type==_SYMB && contains(f,cst_pi)) + f=evalf2double_nock(f,1,contextptr); + f=s(f,contextptr); + if (f.type<_IDNT || f.type==_FRAC) + f=evalf2double_nock(f,1,contextptr); + return f; + } + f=s(evalf2double_nock(f,level,contextptr),contextptr); + if (f.type<_IDNT || f.type==_FRAC) + f=evalf2double_nock(f,1,contextptr); + return f; + } + if (g0.type==_CPLX){ + if (g0._CPLXptr->type==_DOUBLE_ && (g0._CPLXptr+1)->type==_DOUBLE_){ +#if 1 + // maybe we should round complex numbers that are close to reals? + if (fabs((g0._CPLXptr+1)->_DOUBLE_val)<1e-12*fabs(g0._CPLXptr->_DOUBLE_val)) + return g0._CPLXptr->_DOUBLE_val; +#endif + return g0; + } + return evalf2double_nock(*g0._CPLXptr,1,contextptr)+cst_i*evalf2double_nock(*(g0._CPLXptr+1),1,contextptr); + } + gen g=evalf(g0,level,contextptr); + if (g.type==_FLOAT_) + return evalf_double(g,1,contextptr); + if (g.type==_CPLX) + return evalf2double_nock(*g._CPLXptr,1,contextptr)+cst_i*evalf2double_nock(*(g._CPLXptr+1),1,contextptr); + return g; + } + + + gen gen::evalf2double(int level,const context * contextptr) const{ + /* + gen g=evalf(level,contextptr); + return g.evalf_double(level,contextptr); + */ + return evalf2double_nock(*this,level,contextptr); + } + + gen chk_inf_nan(const gen & g0){ + if (g0.type==_FLOAT_){ + if (fis_nan(g0._FLOAT_val)) + return undeferr(gettext("Undefined")); + if (fis_inf_notmax(g0._FLOAT_val)) + return undeferr(gettext("Infinity error")); + return g0; + } + if (is_undef(g0)){ + if (g0.type==_STRNG) + return g0; + if (g0.type==_VECT && !g0._VECTptr->empty()) + return g0._VECTptr->front(); + return undeferr(gettext("Undefined")); + } + if (is_inf(g0)) + return undeferr(gettext("Infinity error")); + return g0; + } + + gen evalf2bcd_nock(const gen & g0,int level,const context * contextptr){ + if (g0.type==_FLOAT_) + return g0; + if (g0.type==_FRAC) + return evalf_FRAC(*g0._FRACptr,contextptr); + if (g0.type==_INT_) + return giac_float(g0.val); + // FIXME _ZINT should be converted without being evalf-ed to double +#ifdef BCD + if (g0.type==_ZINT) + return giac_float(g0._ZINTptr); +#endif + if (storcl_38 && level && g0.type==_IDNT){ +#ifdef BCD + if (!strcmp(g0._IDNTptr->id_name,"pi")) + return fpi(); +#endif + gen res; + if (storcl_38(res,0,g0._IDNTptr->id_name,undef,false,contextptr,NULL,false)) + return evalf2bcd_nock(res,level-1,contextptr); + } + if (g0.type==_VECT){ + ref_vecteur *vptr = new_ref_vecteur(*g0._VECTptr); + iterateur it=vptr->v.begin(),itend=vptr->v.end(); + for (;it!=itend;++it) + *it=evalf2bcd_nock(*it,level,contextptr); + return gen(vptr,g0.subtype); + } + if (is_inf(g0)||is_undef(g0)) + return g0; + if (g0.type==_SYMB){ + /* + if (g0._SYMBptr->sommet==at_unit){ + gen f = g0._SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()==2){ + f=gen(makevecteur(evalf2bcd_nock(f._VECTptr->front(),level,contextptr),f._VECTptr->back()),f.subtype); + return symbolic(at_unit,f); + } + else + return g0; + } + */ + unary_function_ptr & s =g0._SYMBptr->sommet; + gen f =g0._SYMBptr->feuille; + if (s==at_integrate && f._VECTptr->size()==4) + return _gaussquad(f,contextptr); + if (f.type==_VECT && !s.quoted()){ + if (s==at_plus){ + giac_float res(0); + gen tmp; + iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end(); + for (;it!=itend;++it){ + tmp=evalf2bcd_nock(*it,level,contextptr); + if (tmp.type!=_FLOAT_) + break; + res=res+tmp._FLOAT_val; + } + if (it==itend) + return res; + } + if (s==at_prod){ + giac_float res(1); + gen tmp; + iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end(); + for (;it!=itend;++it){ + tmp=evalf2bcd_nock(*it,level,contextptr); + if (tmp.type!=_FLOAT_) + break; + res=res*tmp._FLOAT_val; + } + if (it==itend) + return res; + } + if (f._VECTptr->size()==2){ + gen tmp1=evalf2bcd_nock(f._VECTptr->front(),level,contextptr); + gen tmp2=f._VECTptr->back(); + if (tmp1.type==_FLOAT_ && tmp2.type==_INT_ && s==at_pow) + return fpow(tmp1._FLOAT_val,giac_float(tmp2.val)); + tmp2=evalf2bcd_nock(tmp2,level,contextptr); + if (s==at_pow) + return pow(tmp1,tmp2,contextptr); + if (s==at_division) + return rdiv(tmp1,tmp2,contextptr); + if (s==at_minus) + return operator_minus(tmp1,tmp2,contextptr); + tmp1=s(gen(makenewvecteur(tmp1,tmp2),f.subtype),contextptr); + if (tmp1.type<_IDNT || tmp1.type==_FRAC) + tmp1=evalf2bcd_nock(tmp1,1,contextptr); + return tmp1; + } + } + if (s.quoted()) { + if (s==at_quote) + return f; + f=s(f,contextptr); + if (f.type<_IDNT || f.type==_FRAC) + f=evalf2bcd_nock(f,1,contextptr); + return f; + } + f=s(evalf2bcd_nock(f,level,contextptr),contextptr); + if (f.type<_IDNT || f.type==_FRAC) + f=evalf2bcd_nock(f,1,contextptr); + return f; + } + if (g0.type==_CPLX){ + if (g0._CPLXptr->type==_FLOAT_ && (g0._CPLXptr+1)->type==_FLOAT_) + return g0; + return evalf2bcd_nock(*g0._CPLXptr,1,contextptr)+cst_i*evalf2bcd_nock(*(g0._CPLXptr+1),1,contextptr); + } + gen g=evalf(g0,level,contextptr); + if (g.type==_DOUBLE_) + return giac_float(g._DOUBLE_val); + if (g.type==_CPLX) + return evalf2bcd_nock(*g._CPLXptr,1,contextptr)+cst_i*evalf2bcd_nock(*(g._CPLXptr+1),1,contextptr); + return g; + } + + gen evalf2bcd(const gen & g0,int level,const context * contextptr){ + return chk_inf_nan(evalf2bcd_nock(g0,level,contextptr)); + } + + bool poly_is_real(const polynome & p){ + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (!it->value.is_real(0)) // context is 0 since coeff do not depend on + return false; + } + return true; + } + + bool vect_is_real(const vecteur & v,GIAC_CONTEXT){ + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (!it->is_real(contextptr)) + return false; + } + return true; + } + + /* Checking */ + bool gen::is_real(GIAC_CONTEXT) const { + switch (type) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _ZINT: case _REAL: + return true; + case _CPLX: + return (is_zero(*(_CPLXptr+1),contextptr)); + case _POLY: + return poly_is_real(*_POLYptr); + case _VECT: + return vect_is_real(*_VECTptr,contextptr); + default: + return is_zero(im(contextptr),contextptr); + } + } + + bool gen::is_approx() const { + switch(type){ + case _DOUBLE_: case _FLOAT_: case _REAL: + return true; + case _CPLX: + return subtype==3 || (_CPLXptr->is_approx() && (_CPLXptr+1)->is_approx()); + case _VECT: + return has_num_coeff(*this); + default: + return false; + } + } + + bool gen::is_cinteger() const { + switch (type ) { + case _INT_: case _ZINT: + return true; + case _CPLX: + return _CPLXptr->is_integer() && (_CPLXptr+1)->is_integer(); + default: + return false; + } + } + + bool gen::is_integer() const { + switch (type ) { + case _INT_: case _ZINT: + return true; + case _CPLX: + return is_exactly_zero(*(_CPLXptr+1)) && _CPLXptr->is_integer(); + default: + return false; + } + } + + bool _VECT_is_constant(const vecteur & v){ + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + if (!(it->is_constant())) + return false; + return true; + } + + bool gen::is_constant() const { + switch (type ) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _REAL: case _ZINT: case _CPLX: + return true; + case _VECT: + return _VECT_is_constant(*this->_VECTptr); + case _EXT: + return _EXTptr->is_constant() && (_EXTptr+1)->is_constant(); + case _POLY: + return Tis_constant(*_POLYptr) && _POLYptr->coord.front().value.is_constant(); + default: + return false; + } + } + + bool is_atomic(const gen & e){ + return e.type<_POLY || e.type==_FLOAT_ || e.type==_USER; + } + + static gen giac_conj(const gen & g,GIAC_CONTEXT){ + return conj(g,contextptr); + } + + static gen giac_re(const gen & g,GIAC_CONTEXT){ + return re(g,contextptr); + } + + static gen giac_im(const gen & g,GIAC_CONTEXT){ + return im(g,contextptr); + } + + static vecteur _VECTconj(const vecteur & a,GIAC_CONTEXT){ + vecteur res; + vecteur::const_iterator it=a.begin(),itend=a.end(); + for (;it!=itend;++it) + res.push_back(it->conj(contextptr)); + return res; + } + + // the complex pointed by res is modified despite being declared const + static gen adjust_complex_display(const gen & res,const gen & a,const gen & b){ + int * target = complex_display_ptr(res); + int * aptr = complex_display_ptr(a); + int * bptr = complex_display_ptr(b); + if (target && aptr && bptr) + *target = *aptr & *bptr; + return res; + } + + // the complex pointed by res is modified despite being declared const + static gen adjust_complex_display(const gen & res,const gen & a){ + int * target = complex_display_ptr(res); + int * aptr = complex_display_ptr(a); + if (target && aptr) + *target = *aptr ; + return res; + } + + // change complex display type (in-place, true if changed, false otherwise) + // modifies complex, vecteur and symbolics + int adjust_complex_display(gen & res,int value){ + if (res.type==_CPLX){ + if (value==3) + return 1; + res=gen(*res._CPLXptr,*(res._CPLXptr+1)); + int * target = complex_display_ptr(res); + if (value==2) + *target = 1 - (*target); + else + * target = value; + return 1; + } + if (res.type==_VECT){ + vecteur v(*res._VECTptr); + int n=int(v.size()); + int r=0; + for (int i=0;ifeuille; + int r=adjust_complex_display(f,value); + if (!r || value==3) + return r; + res=symbolic(res._SYMBptr->sommet,f); + return r; + } + + gen gen::conj(GIAC_CONTEXT) const { + switch (type ) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _ZINT: case _REAL: case _STRNG: + return *this; + case _CPLX: + return adjust_complex_display(gen(*_CPLXptr,-(*(_CPLXptr+1))),*this); + case _VECT: + return gen(_VECTconj(*_VECTptr,contextptr),subtype); + case _MAP: + return apply(*this,giac_conj,contextptr); + case _USER: + return _USERptr->conj(contextptr); + case _IDNT: + if (is_assumed_real(*this,contextptr)) + return *this; + /* if ( (_IDNTptr->value) && (is_zero(_IDNTptr->value->im(),contextptr)) ) + return *this; */ + return new_ref_symbolic(symbolic(at_conj,*this)); + case _SYMB: + if (_SYMBptr->sommet==at_conj) + return _SYMBptr->feuille; + if (_SYMBptr->sommet==at_re || _SYMBptr->sommet==at_im) + return *this; + if (_SYMBptr->sommet==at_polar_complex && _SYMBptr->feuille.type==_VECT && _SYMBptr->feuille._VECTptr->size()==2){ + vecteur v=*_SYMBptr->feuille._VECTptr; + v[1]=-v[1]; + return symbolic(at_polar_complex,gen(v,_SEQ__VECT)); + } + if (_SYMBptr->sommet==at_rootof){ + gen a; + if (has_evalf(*this,a,1,contextptr) && is_zero(a.im(contextptr),contextptr)) + return *this; + if (_SYMBptr->feuille.type==_VECT && _SYMBptr->feuille._VECTptr->size()==2){ + vecteur tmp=*_SYMBptr->feuille._VECTptr; + if (lidnt(tmp[1]).empty()){ + vecteur w=*tmp[1]._VECTptr; + gen P; + if (conj_in_nf(w,P,contextptr)){ + // P is a rootof such that conj(rootof(w))=P + gen c=horner(tmp[0].conj(contextptr),P); + c=normal(c,contextptr); + return c; + } + } + } + } + if (equalposcomp(plot_sommets,_SYMBptr->sommet) || equalposcomp(analytic_sommets,_SYMBptr->sommet) || _SYMBptr->sommet==at_surd || _SYMBptr->sommet==at_erf || _SYMBptr->sommet==at_division) + return new_ref_symbolic(symbolic(_SYMBptr->sommet,_SYMBptr->feuille.conj(contextptr))); + else + return new_ref_symbolic(symbolic(at_conj,*this)); + case _FRAC: + return fraction(_FRACptr->num.conj(contextptr),_FRACptr->den.conj(contextptr)); + case _MOD: + return makemod(_MODptr->conj(contextptr),*(_MODptr+1)); + case _EXT: + return algebraic_EXTension(_EXTptr->conj(contextptr),*(_EXTptr+1)); + case _POLY: + return apply(*_POLYptr,contextptr,giac_conj); + default: + return gentypeerr(gettext("Conj")); + } + return 0; + } + + static vecteur _VECTre(const vecteur & a,GIAC_CONTEXT){ + vecteur res; + vecteur::const_iterator it=a.begin(),itend=a.end(); + for (;it!=itend;++it) + res.push_back(it->re(contextptr)); + return res; + } + + vecteur pascal_next_line(const vecteur & v){ + if (v.empty()) + return vecteur(1,plus_one); + const_iterateur it=v.begin(),itend=v.end(); + gen current(*it); + vecteur w; + w.reserve(itend-it+1); + w.push_back(current); + for (++it;it!=itend;++it){ + w.push_back(*it+current); + current=*it; + } + w.push_back(plus_one); + return w; + } + + vecteur pascal_nth_line(int n){ + n=absint(n); + vecteur v(1,plus_one); + for (int i=0;isize()==2){ + i=f._VECTptr->back(); + f=f._VECTptr->front(); + r=f*cos(i,contextptr); + i=f*sin(i,contextptr); + return; + } + if (u==at_division){ + reim(f[0]*inv(f[1],contextptr),r,i,contextptr); + return ; + } + if (u==at_sqrt){ + reim(pow(f,plus_one_half,contextptr),r,i,contextptr); + return; + } + if (u==at_prod){ + if (f.type!=_VECT){ + reim(f,r,i,contextptr); + return; + } + vecteur v(*f._VECTptr); + if (v.empty()){ + r=plus_one; + i=0; + return; + } + if (v.size()==1){ + reim(v.front(),r,i,contextptr); + return; + } + // cut v in 2 parts and recursive call + // re(a*b)=re(a)*re(b)-im(a)*im(b) + const_iterateur it=v.begin(),itend=v.end(); + const_iterateur itm=it+(itend-it+1)/2; + gen a(new_ref_symbolic(symbolic(u,vecteur(it,itm)))); + gen b(new_ref_symbolic(symbolic(u,vecteur(itm,itend)))); + gen ra,rb,ia,ib; + reim(a,ra,ia,contextptr); + reim(b,rb,ib,contextptr); + r=ra*rb-ia*ib; + i=ra*ib+ia*rb; + return; + } + if (u==at_surd && is_integer(f._VECTptr->back())){ + reim(f._VECTptr->front(),r,i,contextptr); + if (is_zero(i,contextptr)){ + r=_surd(makesequence(r,f._VECTptr->back()),contextptr); + return; + } + } + if (u==at_derive && f.type==_VECT && !f._VECTptr->empty()){ + vecteur v=*f._VECTptr; + reim(v.front(),r,i,contextptr); + v.front()=r; + r=symbolic(at_derive,gen(v,f.subtype)); + if (is_zero(i)) + return; + v.front()=i; + i=symbolic(at_derive,gen(v,f.subtype)); + return; + } + if (u==at_pow){ + gen e=f._VECTptr->front(),expo=f._VECTptr->back(); + if (expo.type==_INT_){ + int n=expo.val; + if (n==0){ + r=1; + i=0; + return; + } + reim(e,r,i,contextptr); + if (n==1) + return ; + if (is_zero(i,contextptr)){ + r=pow(r,n); + return; + } + if (is_zero(r,contextptr)){ + if (n%2){ + r=zero; + i=pow(i,n); + if (n%4==3) + i=-i; + return; + } + r=pow(i,n); + i=0; + if (n%4==2) + r=-r; + return; + } + bool n_pos=(n>0); + if (!n_pos){ + reim(inv(pow(e,-n),contextptr),r,i,contextptr); + return; + } + vecteur v=pascal_nth_line(n); + vecteur sommer,sommei; + gen signer=1; + const_iterateur it=v.begin(); + for (int j=0;j<=n;j+=2){ + sommer.push_back(signer*(*it)*pow(r,n-j)*pow(i,j)); + ++it; + ++it; + signer=-signer; + } + it=v.begin(); + gen signei=1; + ++it; + for (int j=1;j<=n;j+=2){ + sommei.push_back(signei*(*it)*pow(r,n-j)*pow(i,j)); + ++it; + ++it; + signei=-signei; + } + r=new_ref_symbolic(symbolic(at_plus,sommer)); + i=new_ref_symbolic(symbolic(at_plus,sommei)); + return ; + } // end integer exponent + if ( is_zero(im(expo,contextptr),contextptr) && is_zero(im(e,contextptr),contextptr) ){ + if (!is_integer(expo) && is_positive(-e,contextptr)){ + r=pow(-e,expo,contextptr)*cos(cst_pi*expo,contextptr); + i=pow(-e,expo,contextptr)*sin(cst_pi*expo,contextptr); + } + else { + r=s; + i=0; + } + return; + } + if (is_zero(im(expo,contextptr),contextptr)){ + reim(e,r,i,contextptr); + gen abse=normal(pow(r,2,contextptr)+pow(i,2,contextptr),contextptr); + gen arge=arg(e,contextptr); + arge=expo*arge; + abse=sqrt(abse,contextptr); + abse=pow(abse,expo,contextptr); + r=abse*cos(arge,contextptr); + i=abse*sin(arge,contextptr); + return; + } + } + if (u==at_rootof && f.type==_VECT && f._VECTptr->size()==2){ + vecteur tmp=*f._VECTptr; + // check that the rootof is really real + if (tmp[1].type==_VECT){ + int nrealposroot=1; + if (lidnt(tmp[1]).empty()){ + vecteur w=*tmp[1]._VECTptr; + gen pol(symb_horner(w,vx_var)); + nrealposroot=sturmab(pol,vx_var,0,plus_inf,contextptr); + if (nrealposroot==0 && is_zero(im(tmp[1],contextptr))){ + // complex, perhaps the conjugate is in the same nf + gen P; + if (conj_in_nf(w,P,contextptr)){ + // P is a rootof such that conj(rootof(w))=P + gen c=horner(conj(tmp[0],contextptr),P); + r=normal((s+c)/2,contextptr); + i=normal((s-c)/2/cst_i,contextptr); + return; + } + } + } + if (nrealposroot>0){ + reim(tmp[0],r,i,contextptr); + r=algtrim(r); + if (r.type==_VECT){ + tmp[0]=r; + r=new_ref_symbolic(symbolic(u,gen(tmp,f.subtype))); + } + i=algtrim(i); + if (i.type==_VECT){ + tmp[0]=i; + i=new_ref_symbolic(symbolic(u,gen(tmp,f.subtype))); + } + return; + } + } + } + gen ref,imf; + if (u==at_integrate){ + if (f.type!=_VECT){ + reim(f,ref,imf,contextptr); + r=symbolic(at_integrate,ref); + i=is_exactly_zero(imf)?zero:symbolic(at_integrate,imf); + return; + } + vecteur v=*f._VECTptr; + if (v.size()<=2 || (v.size()>=4 && is_exactly_zero(im(v[2],contextptr)) && is_exactly_zero(im(v[3],contextptr)))){ + f=v[0]; + reim(f,ref,imf,contextptr); + v[0]=ref; + r=is_exactly_zero(ref)?zero:symbolic(at_integrate,gen(v,_SEQ__VECT)); + v[0]=imf; + i=is_exactly_zero(imf)?zero:symbolic(at_integrate,gen(v,_SEQ__VECT)); + return; + } + } + reim(f,ref,imf,contextptr); + if (is_zero(imf,contextptr) && equalposcomp(reim_op,u)){ + r=s; i=0; return; + } + if (u==at_ln){ // FIXME?? might recurse + if (do_lnabs(contextptr)){ + r=ln(abs(f,contextptr),contextptr); + i=arg(f,contextptr); + } + else { + r=s; i=0; + } + return ; + } + if (u==at_tan){ + reim(rdiv(sin(f,contextptr),cos(f,contextptr),contextptr),r,i,contextptr); + return; + } + if (u==at_tanh){ + reim(rdiv(sinh(f,contextptr),cosh(f,contextptr),contextptr),r,i,contextptr); + return; + } + if ((u==at_asin || u==at_acos) && is_zero(imf,contextptr) && is_greater(1,f,contextptr) && is_greater(f,-1,contextptr)){ + r=s; i=0; return; + } + if (u==at_inv){ + if (1){ // new version + gen g=gcd(ref,imf,contextptr); + if (!is_one(g)){ + ref=ratnormal(ref/g); + imf=ratnormal(imf/g); + } + gen tmp=inv(pow(ref,2)+pow(imf,2),contextptr); + r=ref*tmp/g; + i=-imf*tmp/g; + } else { // old version + gen tmp=inv(pow(ref,2)+pow(imf,2),contextptr); + r=ref*tmp; + i=-imf*tmp; + } + return; + } + if (u==at_exp) { + // FIXME?? exp might recurse + r=exp(ref,contextptr)*cos(imf,contextptr); + i=exp(ref,contextptr)*sin(imf,contextptr); + return; + } + if (u==at_cos){ + r=cosh(imf,contextptr)*cos(ref,contextptr); + i=-sinh(imf,contextptr)*sin(ref,contextptr); + return; + } + if (u==at_sin){ + r=cosh(imf,contextptr)*sin(ref,contextptr); + i=sinh(imf,contextptr)*cos(ref,contextptr); + return; + } + if (u==at_cosh){ + r=cos(imf,contextptr)*cosh(ref,contextptr); + i=sin(imf,contextptr)*sinh(ref,contextptr); + return; + } + if (u==at_sinh){ + r=cos(imf,contextptr)*sinh(ref,contextptr); + i=sin(imf,contextptr)*cosh(ref,contextptr); + return; + } + if (u==at_floor || u==at_ceil || u==at_round){ + r=u(ref,contextptr); + i=u(imf,contextptr); + return; + } + if (u==at_Si && is_zero(imf)){ + r=_Si(ref,contextptr); return; + } + if (u==at_Ei && is_zero(imf)){ + r=_Ei(ref,contextptr); return; + } + if (u==at_Ci && is_zero(imf) && is_greater(ref,0,contextptr)){ + r=_Ci(ref,contextptr); return; + } + if (u==at_erf){ // works for analytic functions + gen conjf=symbolic(u,ref-cst_i*imf); + r=(s+conjf)/2; + i=-cst_i*(s-conjf)/2; + return; + } + r=new_ref_symbolic(symbolic(at_re,gen(s))); + i=new_ref_symbolic(symbolic(at_im,gen(s))); + } + + static void reim_poly(const polynome & p,gen & r,gen & i,GIAC_CONTEXT){ + polynome R(p.dim),I(p.dim); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + reim(it->value,r,i,contextptr); + if (!is_zero(r,contextptr)) + R.coord.push_back(monomial(r,it->index)); + if (!is_zero(i,contextptr)) + I.coord.push_back(monomial(i,it->index)); + } + r=R; + i=I; + } + + static void reim_vect(const vecteur & v,gen & r,gen & i,int subtype,GIAC_CONTEXT){ + const_iterateur it=v.begin(),itend=v.end(); + vecteur R,I; + R.reserve(itend-it); + I.reserve(itend-it); + for (;it!=itend;++it){ + reim(*it,r,i,contextptr); + R.push_back(r); + I.push_back(i); + } + if (subtype==_POLY1__VECT){ + R=trim(R,0); + I=trim(I,0); + } + r=gen(R,subtype); + i=gen(I,subtype); + } + + static void reim_spol(const sparse_poly1 & p,gen & r,gen & i,GIAC_CONTEXT){ + sparse_poly1 R,I; + sparse_poly1::const_iterator it=p.begin(),itend=p.end(); + for (;it!=itend;++it){ + reim(it->coeff,r,i,contextptr); + if (!is_zero(r,contextptr)) + R.push_back(monome(r,it->exponent)); + if (!is_zero(i,contextptr)) + I.push_back(monome(i,it->exponent)); + } + r=R; + i=I; + } + + static gen frac_reim(const gen & n,const gen & d,bool findre,GIAC_CONTEXT){ + gen dbar(conj(d,contextptr)),tmp(n*dbar); + tmp=findre?re(tmp,contextptr):im(tmp,contextptr); + return tmp/(d*dbar); + } + + // compute simultaneously real and imaginary part + void reim(const gen & g,gen & r,gen & i,GIAC_CONTEXT){ + switch (g.type ) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _ZINT: case _REAL: case _STRNG: + r=g; + i=0; + break; + case _CPLX: + r=*g._CPLXptr; + i=*(g._CPLXptr+1); + break; + case _VECT: + reim_vect(*g._VECTptr,r,i,g.subtype,contextptr); + break; + case _IDNT: + if (is_assumed_real(g,contextptr)){ + r=g; + i=0; + } + else { + r=new_ref_symbolic(symbolic(at_re,g)); + i=new_ref_symbolic(symbolic(at_im,g)); + } + break; + case _SYMB: + if (equalposcomp(plot_sommets,g._SYMBptr->sommet)){ + reim(g._SYMBptr->feuille,r,i,contextptr); + r=new_ref_symbolic(symbolic(g._SYMBptr->sommet,r)); + i=new_ref_symbolic(symbolic(g._SYMBptr->sommet,i)); + } + else { + if (expand_re_im(contextptr)) + symb_reim(*g._SYMBptr,r,i,contextptr); + else { + r=new_ref_symbolic(symbolic(at_re,g)); + i=new_ref_symbolic(symbolic(at_im,g)); + } + } + break; + case _USER: + r=g._USERptr->re(contextptr); + i=g._USERptr->im(contextptr); + break; + case _FRAC: + r=frac_reim(g._FRACptr->num,g._FRACptr->den,true,contextptr); + i=frac_reim(g._FRACptr->num,g._FRACptr->den,false,contextptr); + break; + case _MOD: + reim(*g._MODptr,r,i,contextptr); + r=makemod(r,*(g._MODptr+1)); + i=makemod(i,*(g._MODptr+1)); + break; + case _EXT: + reim(*g._EXTptr,r,i,contextptr); + r=algebraic_EXTension(r,*(g._EXTptr+1)); + i=algebraic_EXTension(i,*(g._EXTptr+1)); + break; + case _POLY: + reim_poly(*g._POLYptr,r,i,contextptr); + break; + case _SPOL1: + reim_spol(*g._SPOL1ptr,r,i,contextptr); + break; + default: + r=gentypeerr(gettext("reim")); + i=r; + } + } + + static gen symb_re(const symbolic & s,GIAC_CONTEXT){ + unary_function_ptr u=s.sommet; + gen f=s.feuille; + if ( (u==at_re) || (u==at_im) || (u==at_abs) )// re(re), re(im), re(abs) + return s; + if (u==at_conj) + return re(f,contextptr); + if (u==at_plus) + return _plus(re(f,contextptr),contextptr); + if (u==at_neg) + return -re(f,contextptr); + if (u==at_pow){ + gen e=f._VECTptr->front(),expo=f._VECTptr->back(); + if (expo.type==_INT_){ + int n=expo.val; + if (n==0) + return plus_one; + // ? compute conj and use 1/2*(z+-zbar)? + gen r=re(e,contextptr); + if (n==1) + return r; + gen i=im(e,contextptr); + if (n==2) + return pow(r,2)-pow(i,2); + if (is_zero(i,contextptr)) + return pow(r,n); + if (is_zero(r,contextptr)){ + if (n%2) + return zero; + if (n%4==2) + return -pow(i,n); + else + return pow(i,n); + } + bool n_pos=(n>0); + if (!n_pos) + return re(inv(pow(e,-n),contextptr),contextptr); + vecteur v=pascal_nth_line(n); + vecteur somme; + gen signe=plus_one; + const_iterateur it=v.begin(); //,itend=v.end(); + for (int j=0;j<=n;j+=2){ + somme.push_back(signe*(*it)*pow(r,n-j)*pow(i,j)); + ++it; + ++it; + signe=-signe; + } + gen res=new_ref_symbolic(symbolic(at_plus,somme)); + return res; + } // end integer exponent + if ( is_zero(im(expo,contextptr),contextptr) && is_zero(im(e,contextptr),contextptr) ){ + gen sgn=atan_tan_no_floor(contextptr)?1:sign(e,contextptr); // workaround for int(sqrt(x+sqrt(x))) + if (!is_integer(expo)){ + if (sgn==-1) + return pow(-e,expo,contextptr)*cos(cst_pi*expo,contextptr); + if (sgn!=1) + return symbolic(at_re,s); + } + return s; + } + } + if (u==at_ln) // FIXME?? might recurse + return ln(abs(f,contextptr),contextptr); + gen r,i; + symb_reim(s,r,i,contextptr); + return r; + } + + gen no_context_re(const gen & a){ + return re(a,context0); + } + + gen no_context_im(const gen & a){ + return im(a,context0); + } + + gen no_context_conj(const gen & a){ + return conj(a,context0); + } + + gen gen::re(GIAC_CONTEXT) const { + switch (type ) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _ZINT: case _REAL: case _STRNG: + return *this; + case _CPLX: + return *_CPLXptr; + case _VECT: + return gen(subtype==_POLY1__VECT?trim(_VECTre(*_VECTptr,contextptr),0):_VECTre(*_VECTptr,contextptr),subtype); + case _MAP: + return apply(*this,giac_re,contextptr); + case _IDNT: + if (is_assumed_real(*this,contextptr)) + return *this; + if ( (_IDNTptr->value) && (is_zero(_IDNTptr->value->im(contextptr),contextptr)) ) + return *this; + return new_ref_symbolic(symbolic(at_re,*this)); + case _SYMB: + if (equalposcomp(plot_sommets,_SYMBptr->sommet)) + return new_ref_symbolic(symbolic(_SYMBptr->sommet,_SYMBptr->feuille.re(contextptr))); + if (expand_re_im(contextptr)) + return symb_re(*_SYMBptr,contextptr); + else + return new_ref_symbolic(symbolic(at_re,*this)); + case _USER: + return _USERptr->re(contextptr); + case _FRAC: + return frac_reim(_FRACptr->num,_FRACptr->den,true,contextptr); + case _MOD: + return makemod(_MODptr->re(contextptr),*(_MODptr+1)); + case _EXT: + return algebraic_EXTension(_EXTptr->re(contextptr),*(_EXTptr+1)); + case _POLY: + return apply(*_POLYptr,contextptr,giac_re); + default: + return gentypeerr(gettext("Re")); + } + return 0; + } + + static vecteur _VECTim(const vecteur & a,GIAC_CONTEXT){ + vecteur res; + vecteur::const_iterator it=a.begin(),itend=a.end(); + for (;it!=itend;++it) + res.push_back(it->im(contextptr)); + return res; + } + + static gen symb_im(const symbolic & s,GIAC_CONTEXT){ + unary_function_ptr u=s.sommet; + gen f=s.feuille; + if ( (u==at_re) || (u==at_im) || (u==at_abs) )// im of a real + return zero; + if (u==at_conj) + return -im(f,contextptr); + if (u==at_plus) + return _plus(im(f,contextptr),contextptr); + if (u==at_neg) + return -im(f,contextptr); + if (u==at_pow){ + gen e=f._VECTptr->front(),expo=f._VECTptr->back(); + if (expo.type==_INT_) { + // ? compute conj and use 1/2*(z+-zbar)? + gen r=re(e,contextptr); + gen i=im(e,contextptr); + int n=f._VECTptr->back().val; + if (n==0) + return zero; + if (is_zero(i,contextptr)) + return zero; + if (is_zero(r,contextptr)){ + if (n%2==0) + return zero; + if (n%4==1) + return pow(i,n); + else + return -pow(i,n); + } + bool n_pos=(n>0); + if (!n_pos) + return im(inv(pow(e,-n),contextptr),contextptr); + vecteur v=pascal_nth_line(n); + vecteur somme; + gen signe=plus_one; + const_iterateur it=v.begin(); // ,itend=v.end(); + ++it; + for (int j=1;j<=n;j+=2){ + somme.push_back(signe*(*it)*pow(r,n-j)*pow(i,j)); + ++it; + ++it; + signe=-signe; + } + gen res=new_ref_symbolic(symbolic(at_plus,somme)); + return res; + } // end integer exponent + if ( is_zero(im(expo,contextptr),contextptr) && is_zero(im(e,contextptr),contextptr) ){ + // e must also be positive for non-integral power + if (!is_integer(expo)){ + gen sgn=atan_tan_no_floor(contextptr)?1:sign(e,contextptr); // workaround for int(sqrt(x+sqrt(x))) + if (sgn==-1) + return pow(-e,expo,contextptr)*sin(cst_pi*expo,contextptr); + if (sgn!=1) + return symbolic(at_im,s); + } + return zero; + } + } + if (u==at_ln) + return arg(f,contextptr); + gen r,i; + symb_reim(s,r,i,contextptr); + return i; + } + + gen gen::im(GIAC_CONTEXT) const { + switch (type) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _ZINT: case _REAL: case _STRNG: + return 0; + case _CPLX: + return *(_CPLXptr+1); + case _VECT: + return gen(subtype==_POLY1__VECT?trim(_VECTim(*_VECTptr,contextptr),0):_VECTim(*_VECTptr,contextptr),subtype); + case _MAP: + return apply(*this,giac_im,contextptr); + case _IDNT: + if (is_inf(*this) || is_undef(*this)) + return undef; + if (is_assumed_real(*this,contextptr)) + return zero; + if ( (_IDNTptr->value) && (is_zero(_IDNTptr->value->im(contextptr),contextptr)) ) + return zero; + return new_ref_symbolic(symbolic(at_im,*this)); + case _SYMB: + if (equalposcomp(plot_sommets,_SYMBptr->sommet)) + return new_ref_symbolic(symbolic(_SYMBptr->sommet,_SYMBptr->feuille.im(contextptr))); + if (expand_re_im(contextptr)) + return symb_im(*_SYMBptr,contextptr); + else + return new_ref_symbolic(symbolic(at_im,*this)); + case _USER: + return _USERptr->im(contextptr); + case _FRAC: + return frac_reim(_FRACptr->num,_FRACptr->den,false,contextptr); + case _MOD: + return makemod(_MODptr->im(contextptr),*(_MODptr+1)); + case _EXT: + return algebraic_EXTension(_EXTptr->im(contextptr),*(_EXTptr+1)); + case _POLY: + return apply(*_POLYptr,contextptr,giac_im); + default: + return gentypeerr(gettext("Im")); + } + return 0; + } + + static gen _VECTabs(const vecteur & a,GIAC_CONTEXT){ + gen res(0); + vecteur::const_iterator it=a.begin(), itend=a.end(); + for (;it!=itend;++it){ + res=max(res,abs(*it,contextptr),contextptr); + } + return res; + } + + static gen linfnorm(const vecteur & a,GIAC_CONTEXT){ + gen res(0); + vecteur::const_iterator it=a.begin(), itend=a.end(); + for (;it!=itend;++it){ + res=max(res,linfnorm(*it,contextptr),contextptr); + } + return res; + } + + static gen real_abs(const gen & s,GIAC_CONTEXT){ + gen tmp=evalf_double(s,1,contextptr); + if (tmp.type==_DOUBLE_){ + if (tmp._DOUBLE_val>epsilon(contextptr)) + return s; + if (tmp._DOUBLE_val<-epsilon(contextptr)) + return -s; + if (has_num_coeff(s)) + return 0.0; + else { +#ifdef HAVE_LIBMPFR + tmp=accurate_evalf(s,ABS_NBITS_EVALF+10)*pow(2,ABS_NBITS_EVALF,contextptr); + if (!is_greater(1,abs(tmp,contextptr),contextptr)){ + if (is_positive(tmp,contextptr)) + return s; + return -s; + } +#else + return 0; +#endif + } + } + if (tmp.type==_FLOAT_){ + if (tmp._FLOAT_val>epsilon(contextptr)) + return s; + if (tmp._FLOAT_val<-epsilon(contextptr)) + return -s; + return 0.0; + } + int j=sturmsign(s,false,contextptr); + if (!j || j==-2) + return new_ref_symbolic(symbolic(at_abs,gen(s))); + return j*s; + } + + static gen idnt_abs(const gen & s,GIAC_CONTEXT){ + if (is_inf(s)) + return plus_inf; + if (is_undef(s)) + return s; + // if (contextptr && contextptr->assumedpositive && equalposcomp(*contextptr->assumedpositive,simplifier(s,contextptr))) return s; + if (!eval_abs(contextptr) || has_num_coeff(s)) + return new_ref_symbolic(symbolic(at_abs,s)); + gen r,i; + reim(s,r,i,contextptr); + if (is_zero(i,contextptr)) + return real_abs(s,contextptr); + else { + if (i.type==_SYMB + && !lop(i,at_im).empty() // was i._SYMBptr->sommet==at_im, changed 3 jan 2021 for abs(2*(sqrt(x+sqrt(x))-(sqrt(x)))-1); + && !lop(r,at_re).empty() + ) + return new_ref_symbolic(symbolic(at_abs,s)); + gen r2i2=pow(r,2)+pow(i,2); + if (has_op(r2i2,*at_cos) || has_op(r2i2,*at_sin)){ + r2i2=_tlin(r2i2,contextptr); // _tcollect? + vecteur l=lvar(r2i2); + unsigned count=0; + for (unsigned i=0;i=2) + r2i2=_tcollect(r2i2,contextptr); + } + return sqrt(r2i2,contextptr); + } + } + + static gen symb_abs(const symbolic & s,GIAC_CONTEXT){ + unary_function_ptr u=s.sommet; + gen f=s.feuille; + if (u==at_abs) // abs(abs) + return s; + if (u==at_neg) + return abs(f,contextptr); + if (!complex_mode(contextptr)){ + if (u==at_ln) + return real_abs(s,contextptr); + if (!has_i(s)){ + if (u==at_exp || ( (u==at_sqrt && is_positive(f,contextptr)) || (u==at_pow && f[1]==plus_one_half && is_positive(f[0],contextptr)) ) ) + return s; + // if (calc_mode(contextptr)==1 && u==at_pow && f.type==_VECT && f._VECTptr->size()==2 && f._VECTptr->back()==plus_one_half && is_positive(f[0],contextptr)) return s; + } + } + else { + if (do_lnabs(contextptr) && u==at_ln) + return new_ref_symbolic(symbolic(at_abs,s)); + if (u==at_exp) + return exp(re(f,contextptr),contextptr); + } + if ( (u==at_pow) && (is_zero(im(f._VECTptr->back(),contextptr),contextptr))){ + gen fback=f._VECTptr->back(); + if (fback.type==_INT_ && (fback.val % 2==0)) + return pow(abs(f._VECTptr->front(),contextptr),fback,contextptr); + return new_ref_symbolic(symbolic(u,makesequence(abs(f._VECTptr->front(),contextptr),f._VECTptr->back()))); + } + if (u==at_inv) + return inv(abs(f,contextptr),contextptr); + if (u==at_prod) + return new_ref_symbolic(symbolic(u,apply(f,contextptr,abs))); + return idnt_abs(s,contextptr); + } + + gen abs(const gen & a,GIAC_CONTEXT){ + switch (a.type ) { + case _INT_: + return(absint(a.val)); + case _ZINT: + if (mpz_sgn(*a._ZINTptr)<0) + return(-a); + else + return(a); + case _REAL: + return a._REALptr->abs(); + case _CPLX: +#ifdef GIAC_HAS_STO_38 + if (a._CPLXptr->type==_FLOAT_ && (a._CPLXptr+1)->type==_FLOAT_) + { + HP_gen r; + cAbs_g(gen2HP(*a._CPLXptr), gen2HP(*(a._CPLXptr+1)), &r); + return HP2gen(r); + } +#endif + if (a.subtype==3){ + gen * aptr=a._CPLXptr; + double ar=aptr->_DOUBLE_val,ai=(aptr+1)->_DOUBLE_val; + double z=std::abs(ar)+std::abs(ai); + if (z==0) return z; + ar/=z; ai/=z; + return z*std::sqrt(ar*ar+ai*ai); + // return gen(std::sqrt(ar*ar+ai*ai)); + } + return sqrt(sq(*a._CPLXptr)+sq(*(a._CPLXptr+1)),contextptr) ; + case _DOUBLE_: + return fabs(a._DOUBLE_val); + case _FLOAT_: + return fabs(a._FLOAT_val); + case _VECT: + if (a.subtype==_POINT__VECT || a.subtype==_GGBVECT) + return _l2norm(a,contextptr); + return _VECTabs(*a._VECTptr,contextptr); + case _IDNT: + return idnt_abs(a,contextptr); + case _SYMB: + //if (contextptr && contextptr->assumedpositive && equalposcomp(*contextptr->assumedpositive,simplifier(a,contextptr))) return a; + if (is_equal(a)) + return apply_to_equal(a,abs,contextptr); + if (a.is_symb_of_sommet(at_pnt)){ + if (is3d(a)) + return _l2norm(_coordonnees(a,contextptr),contextptr); + return abs(_affixe(a,contextptr),contextptr); + } + return symb_abs(*a._SYMBptr,contextptr); + case _USER: + return a._USERptr->abs(contextptr); + case _FRAC: + if (is_integer(a._FRACptr->num) && is_integer(a._FRACptr->den)) + return fraction(abs(a._FRACptr->num,contextptr),abs(a._FRACptr->den,contextptr)); + return rdiv(abs(a._FRACptr->num,contextptr),abs(a._FRACptr->den,contextptr),contextptr); + default: + return gentypeerr(gettext("Abs")); + } + return 0; + } + + gen linfnorm(const gen & a,GIAC_CONTEXT){ // L^inf norm is |re|+|im| for a complex + switch (a.type ) { + case _INT_: + return(absint(a.val)); + case _ZINT: + if (mpz_sgn(*a._ZINTptr)<0) + return(-a); + else + return(a); + case _CPLX: + return(abs(*a._CPLXptr,contextptr)+abs(*(a._CPLXptr+1),contextptr)) ; + case _DOUBLE_: + return fabs(a._DOUBLE_val); + case _FLOAT_: + return fabs(a._FLOAT_val); + case _FRAC: + return linfnorm(a._FRACptr->num)/linfnorm(a._FRACptr->den); + case _VECT: + return _VECTabs(*a._VECTptr,contextptr); + case _USER: + return a._USERptr->abs(contextptr); + case _IDNT: case _SYMB: + return new_ref_symbolic(symbolic(at_abs,a)); + default: + return gentypeerr(gettext("Linfnorm")); + } + return 0; + } + + // workaround for intervals + bool is_zero_or_contains(const gen & g,GIAC_CONTEXT){ +#ifdef NO_RTTI + return is_zero(g,contextptr); +#else + if (g.type==_CPLX) + return is_zero_or_contains(*g._CPLXptr,contextptr) && is_zero_or_contains(*(g._CPLXptr+1),contextptr); + if (is_zero(g,contextptr)) + return true; + if (g.type!=_REAL) + return false; + if (real_interval * ptr=dynamic_cast(g._REALptr)) + return ptr->maybe_zero(); + return false; +#endif + } + + gen arg_CPLX(const gen & a,GIAC_CONTEXT){ + gen realpart=normal(a.re(contextptr),contextptr), + imagpart=normal(a.im(contextptr),contextptr); + if (realpart.type==_FLOAT_ && imagpart.type==_FLOAT_){ +#ifdef GIAC_HAS_STO_38 + //grad + return atan2f(realpart._FLOAT_val,imagpart._FLOAT_val,angle_mode(contextptr)); +#else + return atan2f(realpart._FLOAT_val,imagpart._FLOAT_val,angle_radian(contextptr)); +#endif + } + if (is_zero_or_contains(realpart,contextptr)){ + if (is_zero_or_contains(imagpart,contextptr)) + return undef; + return operator_plus(cst_pi_over_2,-atan(realpart/imagpart,contextptr),contextptr)*sign(imagpart,contextptr); + } + if (is_zero_or_contains(imagpart,contextptr)) + return operator_plus((1-sign(realpart,contextptr))*cst_pi_over_2,atan(imagpart/realpart,contextptr),contextptr); + if ( (realpart.type==_DOUBLE_ || realpart.type==_FLOAT_) || (imagpart.type==_DOUBLE_ || imagpart.type==_FLOAT_) ) + return eval(atan(ratnormal(rdiv(imagpart,realpart,contextptr),contextptr),contextptr)+(1-sign(realpart,contextptr))*sign(imagpart,contextptr)*evalf_double(cst_pi_over_2,1,contextptr),1,contextptr); + else + return operator_plus(atan(ratnormal(rdiv(imagpart,realpart,contextptr),contextptr),contextptr),(1-sign(realpart,contextptr))*sign(imagpart,contextptr)*cst_pi_over_2,contextptr); + } + + static gen _VECTarg(const vecteur & a,GIAC_CONTEXT){ + vecteur res; + vecteur::const_iterator it=a.begin(), itend=a.end(); + for (;it!=itend;++it){ + res.push_back(arg(*it,contextptr)); + } + return res; + } + + gen arg(const gen & a,GIAC_CONTEXT){ + if (a.type==_CPLX && a._CPLXptr->type==_DOUBLE_ && (a._CPLXptr+1)->type==_DOUBLE_){ + double d=atan2((a._CPLXptr+1)->_DOUBLE_val,a._CPLXptr->_DOUBLE_val); + if (angle_radian(contextptr)) + return d; + int mode = angle_mode(contextptr); + if(mode == 1) //if was in degrees + return 180*d/M_PI; + else + return 200 * d / M_PI; + } + if (!angle_radian(contextptr)){ + //grad + int mode = get_mode_set_radian(contextptr); //get current mode + gen res=evalf(arg(a,contextptr),1,contextptr); + angle_mode(mode,contextptr); //set back to either degree or grads + if(mode == 1) //if was in degrees + return 180*res/cst_pi; + else + return 200 * res / cst_pi; + } + if (a.is_symb_of_sommet(at_pow)){ + gen af=a._SYMBptr->feuille; + if (af.type==_VECT && af._VECTptr->size()==2){ + gen res=im(ln(af._VECTptr->front(),contextptr)*af._VECTptr->back(),contextptr); + return _smod(makesequence(res,cst_two_pi),contextptr); + } + } + if (a.is_symb_of_sommet(at_exp)) + return _smod(makesequence(im(a._SYMBptr->feuille,contextptr),cst_two_pi),contextptr); + if (a.is_symb_of_sommet(at_prod)){ + const gen & af=a._SYMBptr->feuille; + if (af.type==_VECT){ + const_iterateur it=af._VECTptr->begin(),itend=af._VECTptr->end(); + gen res; + int nonzero=0; + for (;it!=itend;++it){ + gen tmp(arg(*it,contextptr)); + if (!is_zero(tmp,contextptr)){ + res += tmp; + ++nonzero; + } + } + if (nonzero>1) + return _smod(makesequence(res,cst_two_pi),contextptr); + return res; + } + } + if (is_equal(a)) + return apply_to_equal(a,arg,contextptr); + switch (a.type ) { + case _INT_: case _ZINT: case _FLOAT_: case _REAL: + if (is_positive(a,contextptr)) + return 0; + else + return cst_pi; + case _DOUBLE_: + return a._DOUBLE_val>=0?0.0:M_PI; + case _CPLX: + return arg_CPLX(a,contextptr); + case _VECT: + return _VECTarg(*a._VECTptr,contextptr); + case _IDNT: + case _SYMB: + // if ( is_zero(im(a,contextptr),contextptr) || (evalf(a,eval_level(contextptr),contextptr).type==_CPLX) ) + return arg_CPLX(a,contextptr); + // return new symbolic(at_arg,a); + case _USER: + return a._USERptr->arg(contextptr); + case _FRAC: + return arg(a._FRACptr->num*conj(a._FRACptr->den,contextptr),contextptr); + default: + return gentypeerr(gettext("Arg")); + } + return 0; + } + + gen gen::squarenorm(GIAC_CONTEXT) const { + switch (type ) { + case _INT_: case _DOUBLE_: case _FLOAT_: case _ZINT: + return (*this) * (*this); + case _REAL: + return sq(*this); + case _CPLX: + return sq(*_CPLXptr)+sq(*(_CPLXptr+1)); + case _FRAC: + return fraction(_FRACptr->num.squarenorm(contextptr),_FRACptr->den.squarenorm(contextptr)); + default: + { + gen a,b; + reim(*this,a,b,contextptr); + return a*a+b*b; + } + } + } + + gen sq(const gen & a){ +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (a.type==_REAL){ + if (real_interval * ptr=dynamic_cast(a._REALptr)){ + mpfi_t interv; + mpfi_init2(interv,mpfi_get_prec(ptr->infsup)); + mpfi_sqr(interv,ptr->infsup); + gen res=gen(real_interval(interv)); + mpfi_clear(interv); + return res; + } + } +#endif + return a*a; + } + + int gen::bindigits() const{ + int res,valeur; + switch (type ) { + case _INT_: + res=0; + valeur=val; + for (;valeur;res++) + valeur = valeur >> 1; + return res; + case _ZINT: + return mpz_sizeinbase(*_ZINTptr,2)+1; + case _CPLX: + return giacmax(_CPLXptr->bindigits(),(_CPLXptr+1)->bindigits() ) ; + default: +#ifndef NO_STDEXCEPT + settypeerr(gettext("Bindigits")); +#endif + return 0; + } + return 0; + } + + static gen addpoly(const gen & th, const gen & other){ + if ((th.type!=_POLY) || (other.type!=_POLY)){ +#ifndef NO_STDEXCEPT + settypeerr(gettext("addpoly")); +#endif + return gentypeerr(gettext("addpoly")); + } + // Tensor addition + vector< monomial >::const_iterator a=th._POLYptr->coord.begin(); + vector< monomial >::const_iterator a_end=th._POLYptr->coord.end(); + if (a == a_end) { + return other; + } + vector< monomial >::const_iterator b=other._POLYptr->coord.begin(); + vector< monomial >::const_iterator b_end=other._POLYptr->coord.end(); + if (b==b_end){ + return th; + } + ref_polynome * resptr=new ref_polynome(th._POLYptr->dim); + Add_gen(a,a_end,b,b_end,resptr->t.coord,th._POLYptr->is_strictly_greater); + return resptr; + } + + polynome addpoly(const polynome & p,const gen & c){ + if (is_exactly_zero(c)) + return p; + polynome pcopy(p); + if ( (!p.coord.empty()) && p.coord.back().index.is_zero() ) { + pcopy.coord.back().value = pcopy.coord.back().value + c; + if (is_exactly_zero(pcopy.coord.back().value)) + pcopy.coord.pop_back(); + } + else + pcopy.coord.push_back(monomial(c,pcopy.dim)); + return pcopy; + } + + gen chkmod(const gen& a,const gen & b){ +#ifndef NO_RTTI + if (is_integer(a) && b.type==_USER){ + if (galois_field * ptr=dynamic_cast(b._USERptr)){ + return makemodquoted(a,ptr->p); + } + } +#endif + if ( (b.type!=_MOD) || ((a.type==_MOD) && (*(a._MODptr+1)==*(b._MODptr+1)) )) + return a; + return makemodquoted(a,*(b._MODptr+1)); + } + gen makemod(const gen & a,const gen & b){ + if (a.type==_VECT) + return apply1st(a,b,makemod); + if (a.type==_POLY){ + polynome res(a._POLYptr->dim); + vector< monomial >::const_iterator it=a._POLYptr->coord.begin(),itend=a._POLYptr->coord.end(); + res.coord.reserve(itend-it); + for (;it!=itend;++it){ + gen tmp=makemod(it->value,b); + if (!is_exactly_zero(tmp)) + res.coord.push_back(monomial(tmp,it->index)); + } + return res; + } + if (a.type==_MOD){ + if (is_exactly_zero(b)) // unmodularize + return *a._MODptr; + if (*(a._MODptr+1)==b) // avoid e.g. 7 % 5 % 5 + return a; + } + if (a.type==_USER) + return a; + if (is_exactly_zero(b)) + return a; + if (a.type==_DOUBLE_ || a.type==_REAL || a.type==_FLOAT_) + return gensizeerr(gettext("Mod expects integers not floats. Hint: check that you are in exact mode.")); + gen res=makemodquoted(0,0); + if ( (b.type==_INT_) || (b.type==_ZINT) ) + *res._MODptr=smod(a,b); + else { + if (b.type!=_VECT){ + res=0; +#ifdef NO_STDEXCEPT + return gensizeerr(gettext("Bad mod:")+b.print(context0)); +#else + setsizeerr(gettext("Bad mod:")+b.print(context0)); +#endif + } + if (a.type==_VECT) + *res._MODptr=(*a._VECTptr)%(*b._VECTptr); + else + *res._MODptr=a; + } + *(res._MODptr+1)=b; + return res; + } + + gen makemodquoted(const gen & a,const gen & b){ + gen res; +#ifdef SMARTPTR64 + * ((ulonglong * ) &res) = ulonglong(new ref_modulo(a,b)) << 16; +#else + res.__MODptr=new ref_modulo(a,b); +#endif + res.type=_MOD; + return res; + } + + static gen modadd(const ref_modulo * a,const ref_modulo *b){ + if (a->modulo!=b->modulo){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Mod are different")); +#endif + } + return makemod(a->n+b->n,a->modulo); + } + + static gen modsub(const ref_modulo * a,const ref_modulo *b){ +#ifndef NO_STDEXCEPT + if (a->modulo!=b->modulo) + setsizeerr(gettext("Mod are different")); +#endif + return makemod(a->n-b->n,a->modulo); + } + + static gen modmul(const ref_modulo * a,const ref_modulo *b){ +#ifndef NO_STDEXCEPT + if (a->modulo!=b->modulo) + setsizeerr(gettext("Mod are different")); +#endif + return makemod(a->n*b->n,a->modulo); + } + + static gen modinv(const gen & a){ + gen modu=*(a._MODptr+1); + if ( ( (modu.type==_INT_) || (modu.type==_ZINT) ) && + a._MODptr->is_cinteger() ) + return makemod(invmod(*a._MODptr,modu),modu); + if (modu.type==_VECT){ + modpoly polya,u,v,d; + if (a._MODptr->type!=_VECT) + polya.push_back(*a._MODptr); + else + polya=*a._MODptr->_VECTptr; + egcd(polya,*modu._VECTptr,0,u,v,d); + if (d.size()!=1){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Not invertible")); +#endif + return 0; + } + return makemod(u/d.front(),modu); + } + return fraction(makemod(plus_one,*(a._MODptr+1)),a); + } + + // a and b must be dense univariate polynomials + // WARNING: may modify a in place (suitable inside a += operator) + static gen addgen_poly(const gen & a,const gen & b,bool inplace=false){ + vecteur & av=*a._VECTptr; + vecteur & bv=*b._VECTptr; + if (inplace){ + /* + int as=av.size(),bs=bv.size(); + if (asempty()?0:res; + } + + gen & operator_plus_eq(gen &a,const gen & b,GIAC_CONTEXT){ +#if defined(EMCC) || defined(EMCC2) + a=operator_plus(a,b,contextptr); + return a; +#endif + if (a.type==b.type){ + + if (a.type==_DOUBLE_){ +#ifdef DOUBLEVAL + a._DOUBLE_val += b._DOUBLE_val; return a; +#else + *((double *) &a) += *((double *) &b); + a.type = _DOUBLE_; + return a; +#endif + } + if (a.type==_FLOAT_){ +#ifdef DOUBLEVAL + a._FLOAT_val += b._FLOAT_val; return a; +#else + *((giac_float *) &a) += *((giac_float *) &b); + a.type = _FLOAT_; + return a; +#endif + } + if (a.type==_INT_){ + longlong tmp=((longlong) a.val+b.val); + a.val=(int)tmp; + if (a.val==tmp && tmp!=-2147483648) + return a; + return a=tmp; + } + if (a.type==_ZINT && a.ref_count()==1){ + mpz_t * ptr=a._ZINTptr; + mpz_add(*ptr,*ptr,*b._ZINTptr); + if (mpz_sizeinbase(*ptr,2)<32){ + return a=mpz_get_si(*ptr); + } + return a; + } + if (a.type==_VECT && a.subtype==_POLY1__VECT && a.ref_count()==1){ + if (addgen_poly(a,b,true)._VECTptr->empty()) + a=0; + return a; + } + } + if (a.type==_ZINT && b.type==_INT_ && a.ref_count()==1){ + mpz_t * ptr=a._ZINTptr; + if (b.val<0) + mpz_sub_ui(*ptr,*ptr,-b.val); + else + mpz_add_ui(*ptr,*ptr,b.val); + if (mpz_sizeinbase(*ptr,2)<32){ + return a=gen(*ptr); + } + return a; + } + // if (!( (++control_c_counter) & control_c_counter_mask)) +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return a=gensizeerr(gettext("Stopped by user interruption.")); + } + return a=operator_plus(a,b,contextptr); + } + + static gen ck_evalf_double(const gen & g,GIAC_CONTEXT){ + gen tmp=evalf_double(g,1,contextptr); + if (tmp.type<=_CPLX) + return tmp; + return gensizeerr(contextptr); + } + + gen operator_plus(const gen & a,const gen & b,unsigned t,GIAC_CONTEXT){ + static bool warnextend=true; + // if (!( (++control_c_counter) & control_c_counter_mask)) +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + register ref_mpz_t * e; + switch ( t ) { + case _ZINT__ZINT: + e =new ref_mpz_t; + mpz_add(e->z,*a._ZINTptr,*b._ZINTptr); + return e; + case _DOUBLE___DOUBLE_: + return a._DOUBLE_val+b._DOUBLE_val; + case _FLOAT___FLOAT_: + return a._FLOAT_val+b._FLOAT_val; + case _VECT__VECT: + if (// abs_calc_mode(contextptr)==38 && + (a.subtype==_MATRIX__VECT ||b.subtype==_MATRIX__VECT)){ + if (!ckmatrix(a) || !ckmatrix(b)) + return gensizeerr(contextptr); + if (a._VECTptr->size()!=b._VECTptr->size() || a._VECTptr->front()._VECTptr->size()!=b._VECTptr->front()._VECTptr->size()) + return gendimerr(contextptr); + } + if (a.subtype==_POLY1__VECT) + return addgen_poly(a,b); + if (a.subtype==_PNT__VECT) + return gen(makenewvecteur(a._VECTptr->front()+b,a._VECTptr->back()),a.subtype); + if (a.subtype!=_POINT__VECT && equalposcomp((int *) _GROUP__VECT_subtype,a.subtype)) + return sym_add(a,b,contextptr); + if (b.subtype!=_POINT__VECT && equalposcomp((int *)_GROUP__VECT_subtype,b.subtype)) + return sym_add(b,a,contextptr); + if (a.subtype==_POINT__VECT && b.subtype==_POINT__VECT) + return gen(addvecteur(*a._VECTptr,*b._VECTptr),0); + if (a.subtype==0 && b.subtype==0 && python_compat(contextptr)==2) + return mergevecteur(*a._VECTptr,*b._VECTptr); + if (warnextend && a.subtype==0 && b.subtype==0 && python_compat(contextptr)){ + warnextend=false; + alert(gettext("Warning + is vector addition, run list1.extend(list2) for list concatenation"),contextptr); + } + return gen(addvecteur(*a._VECTptr,*b._VECTptr),a.subtype?a.subtype:b.subtype); + case _MAP__MAP: + { + int arows,acols,an,brows,bcols,bn; + if ( (is_sparse_matrix(a,arows,acols,an) && is_sparse_matrix(b,brows,bcols,bn)) || (is_sparse_vector(a,arows,an) && is_sparse_vector(b,brows,bn)) ){ + gen_map res; + gen g(res); + sparse_add(*a._MAPptr,*b._MAPptr,*g._MAPptr); + return g; + } + } + case _INT___ZINT: + e = new ref_mpz_t; + if (a.val<0) + mpz_sub_ui(e->z,*b._ZINTptr,-a.val); + else + mpz_add_ui(e->z,*b._ZINTptr,a.val); + return e; + case _ZINT__INT_: + e = new ref_mpz_t; + if (b.val<0) + mpz_sub_ui(e->z,*a._ZINTptr,-b.val); + else + mpz_add_ui(e->z,*a._ZINTptr,b.val); + return e; + case _DOUBLE___INT_: + return a._DOUBLE_val+b.val; + case _INT___DOUBLE_: + return a.val+b._DOUBLE_val; + case _FLOAT___DOUBLE_: + return a._FLOAT_val+giac_float(b._DOUBLE_val); + case _FLOAT___INT_: + return a._FLOAT_val+giac_float(b.val); + case _FLOAT___FRAC: + return a+evalf2bcd(b,1,contextptr); + case _DOUBLE___FRAC: + return a+ck_evalf_double(b,contextptr); + case _INT___FLOAT_: + return b._FLOAT_val+giac_float(a.val); + case _DOUBLE___FLOAT_: + return b._FLOAT_val+giac_float(a._DOUBLE_val); + case _DOUBLE___ZINT: + return a._DOUBLE_val+mpz_get_d(*b._ZINTptr); + case _DOUBLE___REAL: + return a._DOUBLE_val+real2double(*b._REALptr); + case _REAL__DOUBLE_: + return b._DOUBLE_val+real2double(*a._REALptr); + case _ZINT__DOUBLE_: + return b._DOUBLE_val+mpz_get_d(*a._ZINTptr); + case _CPLX__INT_: + if (b.val==0) return a; + case _CPLX__ZINT: case _CPLX__DOUBLE_: case _CPLX__FLOAT_: case _CPLX__REAL: + return gen(*a._CPLXptr+b,*(a._CPLXptr+1)); + case _INT___CPLX: + if (a.val==0) return b; + case _ZINT__CPLX: case _FLOAT___CPLX: case _DOUBLE___CPLX: case _REAL__CPLX: + return gen(a+*b._CPLXptr,*(b._CPLXptr+1)); + case _CPLX__CPLX: { + gen * aptr=a._CPLXptr, *bptr=b._CPLXptr; + if (aptr->type==_DOUBLE_ && (aptr+1)->type==_DOUBLE_ && bptr->type ==_DOUBLE_ && (bptr+1)->type ==_DOUBLE_) + return adjust_complex_display(gen(aptr->_DOUBLE_val + bptr->_DOUBLE_val, (aptr+1)->_DOUBLE_val + (bptr+1)->_DOUBLE_val),a,b); + return adjust_complex_display(gen(*aptr + *bptr, *(aptr+1) + *(bptr+1)),a,b); + } + case _POLY__POLY: + return addpoly(a,b); + case _FRAC__FRAC: + return (*a._FRACptr)+(*b._FRACptr); + case _FRAC__FLOAT_: + return evalf2bcd(a,1,contextptr)+b; + case _INT___FRAC: case _ZINT__FRAC: + return a+(*b._FRACptr); + case _FRAC__INT_: case _FRAC_ZINT: + return (*a._FRACptr)+b; + case _FRAC__DOUBLE_: + return ck_evalf_double(a,contextptr)+b; + case _SPOL1__SPOL1: + return spadd(*a._SPOL1ptr,*b._SPOL1ptr,contextptr); + case _EXT__EXT: + return ext_add(a,b,contextptr); + case _STRNG__STRNG: + if (is_undef(a)) return a; + if (is_undef(b)) return b; + return string2gen('"'+(*a._STRNGptr)+(*b._STRNGptr)+'"'); + case _POLY__INT_: case _POLY__ZINT: case _POLY__DOUBLE_: case _POLY__FLOAT_: case _POLY__CPLX: case _POLY__MOD: case _POLY__USER: case _POLY__REAL: + return addpoly(*a._POLYptr,b); + case _INT___POLY: case _ZINT__POLY: case _DOUBLE___POLY: case _FLOAT___POLY: case _CPLX__POLY: case _MOD__POLY: case _USER__POLY: case _REAL__POLY: + return addpoly(*b._POLYptr,a); + case _MOD__MOD: +#ifdef SMARTPTR64 + return modadd( (ref_modulo *) (* ((ulonglong * ) &a) >> 16),(ref_modulo *) (* ((ulonglong * ) &b) >> 16)); +#else + return modadd(a.__MODptr,b.__MODptr); +#endif + case _REAL__REAL: + return (*a._REALptr)+(*b._REALptr); + case _IDNT__IDNT: + if (a==unsigned_inf && b==unsigned_inf) + return undef; + if (b==undef) + return b; + if (a==undef || a==unsigned_inf) + return a; + if (b==unsigned_inf) + return b; + return new_ref_symbolic(symbolic(at_plus,makesequence(a,b))); + case _VECT__MAP: + { + int brows,bcols,an; + if (is_sparse_matrix(b,brows,bcols,an)){ + matrice B; + if (!convert(*b._MAPptr,B)) + return gendimerr(contextptr); + return a+B; + } + } + case _MAP__VECT: + { + int arows,acols,an; + if (is_sparse_matrix(a,arows,acols,an)){ + matrice A; + if (!convert(*a._MAPptr,A)) + return gendimerr(contextptr); + return A+b; + } + } + default: + if (a.type==_INT_ && a.val==0 && b.type!=_STRNG) + return b; + if (b.type==_INT_ && b.val==0 && a.type!=_STRNG) + return a; + if (is_undef(a)) + return a; + if (is_undef(b)) + return b; + if (a.type==_FLOAT_){ + if (is_inf(a)) + return a; + if (b.type==_VECT) + return sym_add(b,a,contextptr); + gen b1; + if (has_evalf(b,b1,1,contextptr) && b.type!=b1.type) + return operator_plus(a,b1,contextptr); + return operator_plus(evalf_double(a,1,contextptr),b,contextptr); + } + if (b.type==_FLOAT_){ + if (is_inf(b)) + return b; + if (a.type==_VECT) + return sym_add(a,b,contextptr); + gen a1; + if (has_evalf(a,a1,1,contextptr) && a.type!=a1.type) + return operator_plus(a1,b,contextptr); + return operator_plus(a,evalf_double(b,1,contextptr),contextptr); + } + if (a.type==_STRNG) + return string2gen(*a._STRNGptr+b.print(contextptr),false); + if (b.type==_STRNG) + return string2gen(a.print(contextptr)+*b._STRNGptr,false); + if (a.type==_SPOL1) + return spadd(*a._SPOL1ptr,gen2spol1(b),contextptr); + if (b.type==_SPOL1) + return spadd(gen2spol1(a),*b._SPOL1ptr,contextptr); + if (a.type==_USER) + return (*a._USERptr)+b; + if (b.type==_USER) + return (*b._USERptr)+a; + if (a.type==_REAL) + return a._REALptr->addition(b,contextptr); + if (b.type==_REAL){ + return b._REALptr->addition(a,contextptr); + } + return sym_add(a,b,contextptr); + } + } + + gen operator_plus (const gen & a,const gen & b,GIAC_CONTEXT){ + register unsigned t=(a.type<< _DECALAGE) | b.type; + if (!t) + return((longlong) a.val+b.val); + return operator_plus(a,b,t,contextptr); + } + + gen operator + (const gen & a,const gen & b){ + register unsigned t=(a.type<< _DECALAGE) | b.type; + if (!t) + return ((longlong) a.val+b.val); + return operator_plus(a,b,t,context0); + } + + // specialization of Tfraction operator + + Tfraction operator + (const Tfraction & a,const Tfraction &b){ + if (is_one(a.den)) + return(Tfraction (a.num+b)); + if (is_one(b.den)) + return(Tfraction (b.num+a)); + gen da(a.den),db(b.den); + gen den=simplify3(da,db),num; + if (a.num.type==_POLY && b.num.type==_POLY && db.type==_POLY && da.type==_POLY) + num=foisplus(*a.num._POLYptr,*db._POLYptr,*b.num._POLYptr,*da._POLYptr); + else + num=foisplus(a.num,db,b.num,da) ; // (a.num*db+b.num*da); + if (den.type==_FRAC){ + num=num * den._FRACptr->den; + den=den._FRACptr->num; + } + if (is_exactly_zero(num)) + return Tfraction(num,1); + simplify3(num,den); + if (den.type==_CPLX){ // 3 jan 2020, avoid complex denominator + gen & a=*den._CPLXptr; + gen & b=*(den._CPLXptr+1); + num=num*gen(a,-b); + den=a*a+b*b; + } + den=den*da*db; + return Tfraction (num,den); + } + + + static gen symbolic_plot_makevecteur(const unary_function_ptr & u,const gen & e,bool project,GIAC_CONTEXT){ + if ( (u!=at_pnt) || (e.type!=_VECT) || (e.subtype!=_PNT__VECT) ) + return symbolic(u,e); + // e is a curve or a pnt + vecteur w(*e._VECTptr); + if ( (w.size()!=2) && (w.size()!=3)) + return symbolic(u,e); + gen a0(w[0]); + gen a1(w[1]); + if ( a1.type==_VECT && a1._VECTptr->size()==3 ) + return symbolic(u,gen(makenewvecteur(a0,a1,a1._VECTptr->back()),_PNT__VECT)); + if ( a1.type==_VECT && a1._VECTptr->size()==2 ){ + if (project){ + // we must project a0 + gen param=a1._VECTptr->back(); // v= [ pnt() t ] + if (param.type==_VECT){ + vecteur v=*param._VECTptr; + v[1]=projection(v[0],a0,contextptr); + if (is_undef(v[1])) + return v[1]; + a0=remove_at_pnt(parameter2point(v,contextptr)); // same + a1=makenewvecteur(a1._VECTptr->front(),v); + } + } + else + a1=a1._VECTptr->front(); + } + return symbolic(u,gen(makenewvecteur(a0,a1),_PNT__VECT)); + } + + gen sym_add(const gen & a,const gen & b,GIAC_CONTEXT){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + bool adeuxpoints=a.is_symb_of_sommet(at_deuxpoints); + if ( (a.is_symb_of_sommet(at_interval) || adeuxpoints)&& a._SYMBptr->feuille.type==_VECT && a._SYMBptr->feuille._VECTptr->size()==2) + return symbolic(a._SYMBptr->sommet,makesequence(a._SYMBptr->feuille._VECTptr->front()+b,a._SYMBptr->feuille._VECTptr->back()+b)); // removed +(adeuxpoints?minus_one:zero) otherwise slicing like v[1:4] does not work + if (a.is_symb_of_sommet(at_unit)){ + if (is_zero(b)) + return a; + if (equalposcomp(lidnt(b),cst_pi)!=0) + return sym_add(a,evalf(b,1,contextptr),contextptr); + if (b.is_symb_of_sommet(at_unit)){ + vecteur & va=*a._SYMBptr->feuille._VECTptr; + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + if (va[1]==vb[1]) + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(operator_plus(va[0],vb[0],contextptr),va[1]))); + gen g=mksa_reduce(vb[1]/va[1],contextptr); + gen tmp=chk_not_unit(g); + if (is_undef(tmp)) return tmp; + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(operator_plus(va[0],operator_times(g,vb[0],contextptr),contextptr),va[1]))); + } + if (lidnt(b).empty()){ + gen g=mksa_reduce(a,contextptr); + gen tmp=chk_not_unit(g); + if (is_undef(tmp)) return tmp; + return g+b; + } + } + if (b.is_symb_of_sommet(at_unit)){ + if (is_zero(a)) + return b; + if (equalposcomp(lidnt(a),cst_pi)!=0) + return sym_add(evalf(a,1,contextptr),b,contextptr); + if (lidnt(a).empty()){ + gen g=mksa_reduce(b,contextptr); + gen tmp=chk_not_unit(g); + if (is_undef(tmp)) return tmp; + return a+g; + } + } + if (a.is_approx()){ + gen b1; + if (has_evalf(b,b1,1,contextptr) && (b.type!=b1.type || b!=b1)){ +#ifdef HAVE_LIBMPFR + if (a.type==_REAL){ + gen b2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(a._REALptr)) + b2=convert_interval(b,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + b2=accurate_evalf(b,mpfr_get_prec(a._REALptr->inf)); + if (b2.is_approx()) + return a+b2; + } + if (a.type==_CPLX && a._CPLXptr->type==_REAL){ + gen b2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(a._CPLXptr->_REALptr)) + b2=convert_interval(b,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + b2=accurate_evalf(b,mpfr_get_prec(a._CPLXptr->_REALptr->inf)); + if (b2.is_approx()) + return a+b2; + } +#endif + return a+b1; + } + } + if (b.is_approx()){ + gen a1; + if (has_evalf(a,a1,1,contextptr) && (a.type!=a1.type || a!=a1)){ +#ifdef HAVE_LIBMPFR + if (b.type==_REAL){ + gen a2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(b._REALptr)) + a2=convert_interval(a,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + a2=accurate_evalf(a,mpfr_get_prec(b._REALptr->inf)); + if (a2.is_approx()) + return a2+b; + } + if (b.type==_CPLX && b._CPLXptr->type==_REAL){ + gen a2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(b._CPLXptr->_REALptr)) + a2=convert_interval(a,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + a2=accurate_evalf(a,mpfr_get_prec(b._CPLXptr->_REALptr->inf)); + if (a2.is_approx()) + return a2+b; + } +#endif + return a1+b; + } + } + if ( (a.type==_SYMB) && equalposcomp(plot_sommets,a._SYMBptr->sommet) ){ + if ( (b.type==_SYMB) && equalposcomp(plot_sommets,b._SYMBptr->sommet) ) + return a._SYMBptr->feuille._VECTptr->front()+b._SYMBptr->feuille._VECTptr->front(); + else { + if (b.type==_VECT) + return translation(b,a,contextptr); + gen a_(a); + if (a.is_symb_of_sommet(at_curve) && a._SYMBptr->feuille.type==_VECT && a._SYMBptr->feuille._VECTptr->size()==2 && a._SYMBptr->feuille._VECTptr->front().type==_VECT){ + // adjust param and cartesian eq + vecteur v=*a._SYMBptr->feuille._VECTptr->front()._VECTptr; + if (v.size()==7) + v[6] += b; + if (v.size()>=6){ + v[5]=subst(v[5],makevecteur(x__IDNT_e,y__IDNT_e),makevecteur(x__IDNT_e-re(b,contextptr),y__IDNT_e-im(b,contextptr)),false,contextptr); + a_=symbolic(at_curve,gen(makevecteur(gen(v,a._SYMBptr->feuille._VECTptr->front().subtype),a._SYMBptr->feuille._VECTptr->back()),a._SYMBptr->feuille.subtype)); + } + } + return symbolic_plot_makevecteur( a_._SYMBptr->sommet,a_._SYMBptr->feuille+b,true,contextptr); + } + } + if ( (b.type==_SYMB) && equalposcomp(plot_sommets,b._SYMBptr->sommet) ){ + if (a.type==_VECT) + return translation(a,b,contextptr); + return symbolic_plot_makevecteur(b._SYMBptr->sommet,b._SYMBptr->feuille+a,true,contextptr); + } + gen var1,var2,res1,res2; + if (is_algebraic_program(a,var1,res1)){ + if (is_algebraic_program(b,var2,res2)){ + if (var1!=var2 && is_constant_wrt(res2,var1,contextptr)){ + res2=subst(res2,var2,var1,false,contextptr); + var2=var1; + } + if (var1==var2) + return symbolic(at_program,gen(makevecteur(var1,0,operator_plus(res1,res2,contextptr)),_SEQ__VECT)); + } + if (!is_constant_wrt(b,var1,contextptr)) + *logptr(contextptr) << "Warning function+constant with constant dependent of mute variable" << '\n'; + return symbolic(at_program,gen(makevecteur(var1,0,operator_plus(res1,b,contextptr)),_SEQ__VECT)); + } + if (is_algebraic_program(b,var2,res2)){ + if (!is_constant_wrt(a,var2,contextptr)) + *logptr(contextptr) << "Warning constant+function with constant dependent of mute variable" << '\n'; + return symbolic(at_program,gen(makevecteur(var2,0,operator_plus(a,res2,contextptr)),_SEQ__VECT)); + } + if (a.type==_VECT){ + if (is_zero(b,contextptr)) + return a; + if (a.subtype==_LIST__VECT) + return apply1st(a,b,contextptr,operator_plus); + vecteur res=*a._VECTptr; + if (res.empty()) + return b; + if (a.subtype==_VECTOR__VECT && a._VECTptr->size()==2){ + if (b.type==_VECT && b._VECTptr->size()==2){ + vecteur & bv=*b._VECTptr; + if (b.subtype==_VECTOR__VECT && res.front()==bv.back()) + return _vector(gen(makenewvecteur(bv.front(),bv.back()+res.back()-res.front()),_SEQ__VECT),contextptr); + return _vector(gen(makenewvecteur(res.front(),res.back()+bv.back()-bv.front()),_SEQ__VECT),contextptr); + } + return _point(b+res.back()-res.front(),contextptr); + } + if (b.type==_VECT && b.subtype==_VECTOR__VECT && b._VECTptr->size()==2) + return a+vector2vecteur(*b._VECTptr); + if (a.subtype==_POINT__VECT && a._VECTptr->size()==3 && b.type!=_VECT){ + gen reb,imb; reim(b,reb,imb,contextptr); + res[0] += reb; + res[1] += imb; + return res; + } + if (equalposcomp((int *)_GROUP__VECT_subtype,a.subtype)){ // add to each element + iterateur it=res.begin(),itend=res.end(); + for (;it!=itend;++it) + *it=*it+b; + return gen(res,a.subtype); + } + if (a.subtype==_PNT__VECT){ + res.front()=res.front()+b; + return gen(res,_PNT__VECT); + } + if (a.subtype!=_POLY1__VECT && ckmatrix(a)){ // matrix+cst + int s=int(res.size()); + if (unsigned(s)==res.front()._VECTptr->size()){ + for (int i=0;ifeuille) + return chkmod(zero,a); + if (a.is_symb_of_sommet(at_neg) && b==a._SYMBptr->feuille) + return chkmod(zero,b); + if (is_exactly_zero(a) && !(a.type==_MOD && b.type==_INT_)) + return b; + if (is_exactly_zero(b) && !(b.type==_MOD && a.type==_INT_)) + return a; + if (a.type==_STRNG) + return string2gen(*a._STRNGptr+b.print(context0),false); + if (b.type==_STRNG) + return string2gen(a.print(context0)+*b._STRNGptr,false); + if (a.type==_FRAC){ + if ( (b.type!=_SYMB) && (b.type!=_IDNT) ) + return (*a._FRACptr)+b; + if (b.is_symb_of_sommet(at_neg)) + return a-b._SYMBptr->feuille; + if (b.is_symb_of_sommet(at_inv) && is_cinteger(b._SYMBptr->feuille)) + return (*a._FRACptr)+fraction(1,b._SYMBptr->feuille); + if (b.is_symb_of_sommet(at_prod) && b._SYMBptr->feuille.type==_VECT){ + const vecteur & bf=*b._SYMBptr->feuille._VECTptr; + if (bf.size()==2 && is_integer(bf[0]) && bf[1].is_symb_of_sommet(at_inv) && is_cinteger(bf[1]._SYMBptr->feuille)) + return (*a._FRACptr)+fraction(bf[0],bf[1]._SYMBptr->feuille); + } + return sym_add(_FRAC2_SYMB(a),b,contextptr); + } + if (b.type==_FRAC){ + if ( (a.type!=_SYMB) && (a.type!=_IDNT) ) + return a+(*b._FRACptr); + if (a.is_symb_of_sommet(at_neg)) + return b-a._SYMBptr->feuille; + if (a.is_symb_of_sommet(at_inv) && is_cinteger(a._SYMBptr->feuille)) + return fraction(1,a._SYMBptr->feuille)+(*b._FRACptr); + if (a.is_symb_of_sommet(at_prod) && a._SYMBptr->feuille.type==_VECT){ + const vecteur & af=*a._SYMBptr->feuille._VECTptr; + if (af.size()==2 && is_integer(af[0]) && af[1].is_symb_of_sommet(at_inv) && is_cinteger(af[1]._SYMBptr->feuille)) + return fraction(af[0],af[1]._SYMBptr->feuille)+(*b._FRACptr); + } + return sym_add(a,_FRAC2_SYMB(b),contextptr); + } + if (a.type==_EXT){ + if (a.is_constant() && (b.type==_POLY)) + return addpoly(*b._POLYptr,a); + /* + if (b.type==_POLY && b.is_constant()) + return a+b._POLYptr->coord.front().value; + */ + else + return algebraic_EXTension(*a._EXTptr+b,*(a._EXTptr+1)); + } + if (b.type==_EXT){ + if (b.is_constant() && (a.type==_POLY)) + return addpoly(*a._POLYptr,b); + /* + if (a.type==_POLY && a.is_constant()) + return a._POLYptr->coord.front().value+b; + */ + else + return algebraic_EXTension(a+*b._EXTptr,*(b._EXTptr+1)); + } + int ia=is_inequality(a),ib=is_inequality(b); + if (ia){ + vecteur & va=*a._SYMBptr->feuille._VECTptr; + if (ia==ib || (ia==1 && ib)){ + if (ia==4) // <> + <> + return undef; + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(b._SYMBptr->sommet,makesequence(va.front()+vb.front(),va.back()+vb.back()))); + } + if (ia==1 || !ib) // = + + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,makesequence(va.front()+b,va.back()+b))); + if ( (ia==5 && ib==6) || (ia==6 && ib==5)){ + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(at_superieur_strict,makesequence(va.front()+vb.front(),va.back()+vb.back()))); + } + } + if (ib) + return b+a; + if (a.is_symb_of_sommet(at_interval)){ + gen & f=a._SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()==2){ + vecteur & v=*f._VECTptr; + if (b.is_symb_of_sommet(at_interval)){ + gen & g=b._SYMBptr->feuille; + if (g.type==_VECT && g._VECTptr->size()==2){ + vecteur & w=*g._VECTptr; + return new_ref_symbolic(symbolic(at_interval,gen(makenewvecteur(w[0]+v[0],w[1]+v[1]),_SEQ__VECT))); + } + } + return new_ref_symbolic(symbolic(at_interval,gen(makenewvecteur(b+v[0],b+v[1]),_SEQ__VECT))); + } + } + if (b.is_symb_of_sommet(at_interval)) + return b+a; + /* if (xcas_mode(contextptr) && (a.type==_SYMB|| b.type==_SYMB) ) + return liste2symbolique(fusion2liste(symbolique2liste(a),symbolique2liste(b))); */ + if ((a.type==_SYMB) && (b.type==_SYMB)){ + if (a._SYMBptr->sommet==at_plus) { + if (b._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(at_plus,gen(mergevecteur(*(a._SYMBptr->feuille._VECTptr),*(b._SYMBptr->feuille._VECTptr)),_SEQ__VECT))); + else + return new_ref_symbolic(symbolic(*a._SYMBptr,b)); + } + else { + if (b._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(*(b._SYMBptr),a)); + else + return new_ref_symbolic(symbolic(at_plus,makesequence(a,b))); + } + } + if (b.type==_SYMB){ + if (b._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(a,b._SYMBptr->sommet,b._SYMBptr->feuille)); + else + return new_ref_symbolic(symbolic(at_plus,makesequence(a,b))); + } + if (a.type==_SYMB){ + if ( a._SYMBptr->sommet==at_plus && a._SYMBptr->feuille.type==_VECT && a._SYMBptr->feuille._VECTptr->size()>1 && + ( (b==plus_one && a._SYMBptr->feuille._VECTptr->back()==minus_one) || (b==minus_one && a._SYMBptr->feuille._VECTptr->back()==plus_one) ) + ) + { + vecteur v=*a._SYMBptr->feuille._VECTptr; + v.pop_back(); + if (v.size()==1) + return v.front(); + else + return new_ref_symbolic(symbolic(at_plus,gen(v,a._SYMBptr->feuille.subtype))); + } + if (a._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(*a._SYMBptr,b)); + else + return new_ref_symbolic(symbolic(at_plus,makesequence(a,b))); + } + if ( (a.type==_IDNT) || (b.type==_IDNT)) + return new_ref_symbolic(symbolic(at_plus,makesequence(a,b))); + if (a.type==_MOD) + return a+makemod(b,*(a._MODptr+1)); + if (b.type==_MOD) + return makemod(a,*(b._MODptr+1))+b; + return new_ref_symbolic(symbolic(at_plus,makesequence(a,b))); + // settypeerr(gettext("sym_add")); + } + + static gen subpoly(const gen & th, const gen & other){ + if ((th.type!=_POLY) || (other.type!=_POLY)){ +#ifndef NO_STDEXCEPT + settypeerr(gettext("subpoly")); +#endif + return gentypeerr(gettext("subpoly")); + } + vector< monomial >::const_iterator a=th._POLYptr->coord.begin(); + vector< monomial >::const_iterator a_end=th._POLYptr->coord.end(); + vector< monomial >::const_iterator b=other._POLYptr->coord.begin(); + vector< monomial >::const_iterator b_end=other._POLYptr->coord.end(); + if (b==b_end){ + return th; + } + ref_polynome * resptr=new ref_polynome(th._POLYptr->dim); + Sub_gen(a,a_end,b,b_end,resptr->t.coord,th._POLYptr->is_strictly_greater); + return resptr; + } + + polynome subpoly(const polynome & p,const gen & c){ + if (is_exactly_zero(c)) + return p; + polynome pcopy(p); + if ( (!p.coord.empty()) && p.coord.back().index.is_zero() ) { + pcopy.coord.back().value = pcopy.coord.back().value - c; + if (is_exactly_zero(pcopy.coord.back().value)) + pcopy.coord.pop_back(); + } + else + pcopy.coord.push_back(monomial(-c,pcopy.dim)); + return pcopy; + } + + static polynome subpoly(const gen & c,const polynome & p){ + if (is_exactly_zero(c)) + return -p; + polynome pcopy(-p); + if ( (!p.coord.empty()) && p.coord.back().index.is_zero() ) { + pcopy.coord.back().value = pcopy.coord.back().value + c; + if (is_exactly_zero(pcopy.coord.back().value)) + pcopy.coord.pop_back(); + } + else + pcopy.coord.push_back(monomial(c,pcopy.dim)); + return pcopy; + } + + static gen subgen_poly(const gen & a,const gen & b,bool inplace=false){ + vecteur & av=*a._VECTptr; + vecteur & bv=*b._VECTptr; + if (inplace){ + /* + int as=av.size(),bs=bv.size(); + if (asempty()?0:res; + } + + gen & operator_minus_eq (gen & a,const gen & b,GIAC_CONTEXT){ +#if defined(EMCC) || defined(EMCC2) + a=operator_minus(a,b,contextptr); + return a; +#endif + if (a.type==b.type){ +#ifdef SMARTPTR64 + if (*(ulonglong *)&a==*(ulonglong *)&b && a.type<=_CPLX) + return a=0; +#else + if (&a==&b && a.type<=_CPLX) + return a=0; +#endif + if (a.type==_DOUBLE_){ +#ifdef DOUBLEVAL + a._DOUBLE_val -= b._DOUBLE_val; return a; +#else + *((double *) &a) -= *((double *) &b); + a.type = _DOUBLE_; + return a; +#endif + } + if (a.type==_FLOAT_){ +#ifdef DOUBLEVAL + a._FLOAT_val -= b._FLOAT_val; return a; +#else + *((double *) &a) -= *((double *) &b); + a.type = _FLOAT_; + return a; +#endif + } + if (a.type==_INT_){ + longlong tmp=((longlong) a.val-b.val); + a.val=(int)tmp; + if (a.val==tmp && tmp!=-2147483648) + return a; + return a=tmp; + } + if (a.type==_ZINT && a.ref_count()==1){ + mpz_t * ptr=a._ZINTptr; + mpz_sub(*ptr,*ptr,*b._ZINTptr); + if (mpz_sizeinbase(*ptr,2)<32){ + return a=mpz_get_si(*ptr); + } + return a; + } + if (a.type==_VECT && a.subtype==_POLY1__VECT && a.ref_count()==1){ + if (subgen_poly(a,b,true)._VECTptr->empty()) + a=0; + return a; + } + } + if (a.type==_ZINT && b.type==_INT_ && a.ref_count()==1){ + mpz_t * ptr=a._ZINTptr; + if (b.val>0) + mpz_sub_ui(*ptr,*ptr,b.val); + else + mpz_add_ui(*ptr,*ptr,-b.val); + if (mpz_sizeinbase(*ptr,2)<32){ + return a=mpz_get_si(*ptr); + } + return a; + } + // if (!( (++control_c_counter) & control_c_counter_mask)) +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return a=gensizeerr(gettext("Stopped by user interruption.")); + } + return a=operator_minus(a,b,contextptr); + } + + gen operator_minus(const gen & a,const gen & b,unsigned t,GIAC_CONTEXT){ + // if (!( (++control_c_counter) & control_c_counter_mask)) +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + register ref_mpz_t * e; + switch ( t) { + case _ZINT__ZINT: + e = new ref_mpz_t; + mpz_sub(e->z,*a._ZINTptr,*b._ZINTptr); + return e; + case _DOUBLE___DOUBLE_: + return a._DOUBLE_val-b._DOUBLE_val; + case _FLOAT___FLOAT_: + return a._FLOAT_val-b._FLOAT_val; + case _VECT__VECT: + if (// abs_calc_mode(contextptr)==38 && + (a.subtype==_MATRIX__VECT ||b.subtype==_MATRIX__VECT)){ + if (!ckmatrix(a) || !ckmatrix(b)) + return gensizeerr(contextptr); + if (a._VECTptr->size()!=b._VECTptr->size() || a._VECTptr->front()._VECTptr->size()!=b._VECTptr->front()._VECTptr->size()) + return gendimerr(contextptr); + } + if (a.subtype==_POLY1__VECT) + return subgen_poly(a,b); + if (a.subtype==_PNT__VECT) + return gen(makenewvecteur(a._VECTptr->front()-b,a._VECTptr->back()),a.subtype); + if (a.subtype!=_POINT__VECT && equalposcomp((int *)_GROUP__VECT_subtype,a.subtype)) + return sym_sub(a,b,contextptr); + if (a.subtype==_POINT__VECT && b.subtype==_POINT__VECT) + return gen(subvecteur(*a._VECTptr,*b._VECTptr),0); + return gen(subvecteur(*a._VECTptr,*b._VECTptr),a.subtype); + case _MAP__MAP: + { + int arows,acols,an,brows,bcols,bn; + if ( (is_sparse_matrix(a,arows,acols,an) && is_sparse_matrix(b,brows,bcols,bn)) || (is_sparse_vector(a,arows,an) && is_sparse_vector(b,brows,bn)) ){ + gen_map res; + gen g(res); + sparse_sub(*a._MAPptr,*b._MAPptr,*g._MAPptr); + return g; + } + } + case _INT___ZINT: + e = new ref_mpz_t; + if (a.val<0) + mpz_add_ui(e->z,*b._ZINTptr,-a.val); + else + mpz_sub_ui(e->z,*b._ZINTptr,a.val); + mpz_neg(e->z,e->z); + return(e); + case _ZINT__INT_: + e = new ref_mpz_t; + if (b.val<0) + mpz_add_ui(e->z,*a._ZINTptr,-b.val); + else + mpz_sub_ui(e->z,*a._ZINTptr,b.val); + return(e); + case _INT___DOUBLE_: + return a.val-b._DOUBLE_val; + case _DOUBLE___INT_: + return a._DOUBLE_val-b.val; + case _INT___FLOAT_: + return giac_float(a.val)-b._FLOAT_val; + case _FLOAT___INT_: + return a._FLOAT_val-giac_float(b.val); + case _DOUBLE___FLOAT_: + return giac_float(a._DOUBLE_val)-b._FLOAT_val; + case _FLOAT___DOUBLE_: + return a._FLOAT_val-giac_float(b._DOUBLE_val); + case _FLOAT___FRAC: + return a-evalf2bcd(b,1,contextptr); + case _DOUBLE___FRAC: + return a-ck_evalf_double(b,contextptr); + case _FRAC__FLOAT_: + return evalf2bcd(a,1,contextptr)-b; + case _FRAC__DOUBLE_: + return ck_evalf_double(a,contextptr)-b; + case _ZINT__DOUBLE_: + return mpz_get_d(*a._ZINTptr)-b._DOUBLE_val; + case _DOUBLE___ZINT: + return a._DOUBLE_val-mpz_get_d(*b._ZINTptr); + case _DOUBLE___REAL: + return a._DOUBLE_val-real2double(*b._REALptr); + case _REAL__DOUBLE_: + return real2double(*a._REALptr)-b._DOUBLE_val; + case _CPLX__INT_: case _CPLX__ZINT: case _CPLX__DOUBLE_: case _CPLX__FLOAT_: case _CPLX__REAL: + return gen(*a._CPLXptr-b,*(a._CPLXptr+1)); + case _INT___CPLX: case _ZINT__CPLX: case _DOUBLE___CPLX: case _FLOAT___CPLX: case _REAL__CPLX: + return gen(a-*b._CPLXptr,-*(b._CPLXptr+1)); + case _CPLX__CPLX: + return adjust_complex_display(gen(*a._CPLXptr - *b._CPLXptr, *(a._CPLXptr+1) - *(b._CPLXptr+1)),a,b); + case _POLY__POLY: + return subpoly(a,b); + case _FRAC__FRAC: + return (*a._FRACptr)-(*b._FRACptr); + case _SPOL1__SPOL1: + return spsub(*a._SPOL1ptr,*b._SPOL1ptr,contextptr); + case _EXT__EXT: + return ext_sub(a,b,contextptr); + case _POLY__INT_: case _POLY__ZINT: case _POLY__DOUBLE_: case _POLY__FLOAT_: case _POLY__CPLX: case _POLY__MOD: case _POLY__REAL: case _POLY__USER: + return subpoly(*a._POLYptr,b); + case _INT___POLY: case _ZINT__POLY: case _DOUBLE___POLY: case _FLOAT___POLY: case _CPLX__POLY: case _MOD__POLY:case _USER__POLY: case _REAL__POLY: + return subpoly(a,*b._POLYptr); + case _MOD__MOD: +#ifdef SMARTPTR64 + return modsub( (ref_modulo *) (* ((ulonglong * ) &a) >> 16), (ref_modulo *) (* ((ulonglong * ) &b) >> 16) ); +#else + return modsub(a.__MODptr,b.__MODptr); +#endif + case _REAL__REAL: + return (*a._REALptr)-(*b._REALptr); + default: + if (is_undef(a)) + return a; + if (is_undef(b)) + return b; + if (a.type==_FLOAT_){ + gen b1; + if (b.type==_VECT) + return sym_sub(a,b,contextptr); + if (has_evalf(b,b1,1,contextptr) && b.type!=b1.type) + return operator_minus(a,b1,contextptr); + return operator_minus(evalf_double(a,1,contextptr),b,contextptr); + } + if (b.type==_FLOAT_){ + if (a.type==_VECT) + return sym_sub(a,b,contextptr); + gen a1; + if (has_evalf(a,a1,1,contextptr) && a.type!=a1.type) + return operator_minus(a1,b,contextptr); + return operator_minus(a,evalf_double(b,1,contextptr),contextptr); + } + if (a.type==_SPOL1) + return spsub(*a._SPOL1ptr,gen2spol1(b),contextptr); + if (b.type==_SPOL1) + return spsub(gen2spol1(a),*b._SPOL1ptr,contextptr); + if (a.type==_USER) + return (*a._USERptr)-b; + if (b.type==_USER) + return (-b)+a; + if (a.type==_REAL) + return a._REALptr->substract(b,contextptr); + if (b.type==_REAL) + return operator_plus(-(*b._REALptr),a,contextptr); + if (a.type==_STRNG) + return a; + return sym_sub(a,b,contextptr); + } + } + + gen operator_minus (const gen & a,const gen & b,GIAC_CONTEXT){ + register unsigned t=(a.type<< _DECALAGE) | b.type; + if (!t) + return((longlong) a.val-b.val); + return operator_minus(a,b,t,contextptr); + } + + gen operator - (const gen & a,const gen & b){ + register unsigned t=(a.type<< _DECALAGE) | b.type; + if (!t) + return((longlong) a.val-b.val); + return operator_minus(a,b,t,context0); + } + + gen sym_sub(const gen & a,const gen & b,GIAC_CONTEXT){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + if (a.is_symb_of_sommet(at_unit) || b.is_symb_of_sommet(at_unit)) + return a+(-b); + if ( a.is_approx()){ + gen b1; + if (has_evalf(b,b1,1,contextptr) && (b.type!=b1.type || b!=b1)){ +#ifdef HAVE_LIBMPFR + if (a.type==_REAL){ + gen b2=accurate_evalf(b,mpfr_get_prec(a._REALptr->inf)); + if (b2.is_approx()) + return a-b2; + } +#endif + return a-b1; + } + } + if ( b.is_approx()){ + gen a1; + if (has_evalf(a,a1,1,contextptr) && (a.type!=a1.type || a!=a1)){ +#ifdef HAVE_LIBMPFR + if (a.type==_REAL){ + gen a2=accurate_evalf(a,mpfr_get_prec(b._REALptr->inf)); + if (a2.is_approx()) + return a2-b; + } +#endif + return a1-b; + } + } + if ( (a.type==_SYMB) && equalposcomp(plot_sommets,a._SYMBptr->sommet) ){ + if ( (b.type==_SYMB) && equalposcomp(plot_sommets,b._SYMBptr->sommet) ) + return a._SYMBptr->feuille._VECTptr->front()-b._SYMBptr->feuille._VECTptr->front(); + else { + gen a_(a); + if (a.is_symb_of_sommet(at_curve) && a._SYMBptr->feuille.type==_VECT && a._SYMBptr->feuille._VECTptr->size()==2 && a._SYMBptr->feuille._VECTptr->front().type==_VECT){ + // adjust param and cartesian eq + vecteur v=*a._SYMBptr->feuille._VECTptr->front()._VECTptr; + if (v.size()==7) + v[6] -= b; + if (v.size()>=6){ + v[5]=subst(v[5],makevecteur(x__IDNT_e,y__IDNT_e),makevecteur(x__IDNT_e+re(b,contextptr),y__IDNT_e+im(b,contextptr)),false,contextptr); + a_=symbolic(at_curve,gen(makevecteur(gen(v,a._SYMBptr->feuille._VECTptr->front().subtype),a._SYMBptr->feuille._VECTptr->back()),a._SYMBptr->feuille.subtype)); + } + } + return symbolic_plot_makevecteur(a_._SYMBptr->sommet,a_._SYMBptr->feuille-b,true,contextptr); + } + } + if ( (b.type==_SYMB) && equalposcomp(plot_sommets,b._SYMBptr->sommet) ) + return sym_add(-b,a,contextptr); + gen var1,var2,res1,res2; + if (is_algebraic_program(a,var1,res1) && is_algebraic_program(b,var2,res2)){ + if (var1!=var2 && is_constant_wrt(res2,var1,contextptr)){ + res2=subst(res2,var2,var1,false,contextptr); + var2=var1; + } + if (var1==var2) + return symbolic(at_program,gen(makevecteur(var1,0,operator_minus(res1,res2,contextptr)),_SEQ__VECT)); + } + if (a.type==_VECT) + return sym_add(a,-b,contextptr); + if (b.type==_VECT) + return sym_add(-b,a,contextptr); + if (is_undef(a)) + return a; + if (is_undef(b)) + return b; + if (is_inf(a)){ + if (is_inf(b)){ + if ((a==plus_inf) && (b==minus_inf)) + return a; + if ((a==minus_inf) && (b==plus_inf)) + return a; + return undef; + } + else + return a; + } + if (a.type==_FRAC){ + if ( (b.type!=_SYMB) && (b.type!=_IDNT) ) + return (*a._FRACptr)-b; + if (b.is_symb_of_sommet(at_neg)) + return a+b._SYMBptr->feuille; + if (b.is_symb_of_sommet(at_inv) && is_cinteger(b._SYMBptr->feuille)) + return (*a._FRACptr)-fraction(1,b._SYMBptr->feuille); + return sym_sub(_FRAC2_SYMB(a),b,contextptr); + } + if (b.type==_FRAC){ + if ( (a.type!=_SYMB) && (a.type!=_IDNT) ) + return a-(*b._FRACptr); + if (a.is_symb_of_sommet(at_neg)) + return -(a._SYMBptr->feuille+b); + if (a.is_symb_of_sommet(at_inv) && is_cinteger(a._SYMBptr->feuille)) + return fraction(1,a._SYMBptr->feuille)-(*b._FRACptr); + return sym_sub(a,_FRAC2_SYMB(b),contextptr); + } + if (a.type==_EXT){ + if (a.is_constant() && (b.type==_POLY)) + return subpoly(a,*b._POLYptr); + else + return algebraic_EXTension(*a._EXTptr-b,*(a._EXTptr+1)); + } + if (b.type==_EXT){ + if (b.is_constant() && (a.type==_POLY)) + return subpoly(*a._POLYptr,b); + else + return algebraic_EXTension(a-*b._EXTptr,*(b._EXTptr+1)); + } + if (a==b) + return chkmod(zero,a); + if (is_inf(b)) + return -b; + if (is_exactly_zero(b)) + return a; + if (is_exactly_zero(a)) + return -b; + /* + if (a.type==_SYMB && a._SYMBptr->sommet==at_equal){ + vecteur & va=*a._SYMBptr->feuille._VECTptr; + if (b.type==_SYMB && b._SYMBptr->sommet==at_equal){ + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(at_equal,makesequence(va.front()-vb.front(),va.back()-vb.back()))); + } + else + return new_ref_symbolic(symbolic(at_equal,makesequence(va.front()-b,va.back()-b))); + } + if (b.type==_SYMB && b._SYMBptr->sommet==at_equal){ + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(at_equal,makesequence(a-vb.front(),a-vb.back()))); + } + */ + if (is_inequality(a) || is_inequality(b)) + return a+(-b); + if ((a.type==_SYMB) && (b.type==_SYMB)){ + if (a._SYMBptr->sommet==at_plus) { + if (b._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(at_plus,gen(mergevecteur(*(a._SYMBptr->feuille._VECTptr),negvecteur(*(b._SYMBptr->feuille._VECTptr))),_SEQ__VECT))); + else + return new_ref_symbolic(symbolic(*a._SYMBptr,-b)); + } + else { + if (b._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(*(-b)._SYMBptr,a)); + else + return new_ref_symbolic(symbolic(at_plus,makesequence(a,-b))); + } + } + if (b.type==_SYMB){ + if (b._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(*(-b)._SYMBptr,a)); + else + return new_ref_symbolic(symbolic(at_plus,makesequence(a,-b))); + } + if (a.type==_SYMB){ + if (a._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(*a._SYMBptr,-b)); + else + return new_ref_symbolic(symbolic(at_plus,makesequence(a,-b))); + } + if ((a.type==_IDNT) || (b.type==_IDNT)) + return new_ref_symbolic(symbolic(at_plus,makesequence(a,-b))); + if (a.type==_MOD) + return a-makemod(b,*(a._MODptr+1)); + if (b.type==_MOD) + return makemod(a,*(b._MODptr+1))-b; + return new_ref_symbolic(symbolic(at_plus,makesequence(a,-b))); + // settypeerr(gettext("sym_sub")); + } + + static vecteur negfirst(const vecteur & v){ + vecteur w(v); + if (!w.empty()) + w.front()=-w.front(); + return w; + } + + gen operator -(const gen & a){ + ref_mpz_t *e ; + switch (a.type ) { + case _INT_: + return(-a.val); + case _ZINT: + e=new ref_mpz_t; + mpz_neg(e->z,*a._ZINTptr); + return(e); + case _DOUBLE_: + return -(a._DOUBLE_val); + case _FLOAT_: + return -(a._FLOAT_val); + case _CPLX: { + const gen * aptr=a._CPLXptr; + if (a.subtype==3) + return adjust_complex_display(gen(-aptr->_DOUBLE_val,-(aptr+1)->_DOUBLE_val),a); + return adjust_complex_display(gen(-*aptr,-*(aptr+1)),a); + } + case _IDNT: + if ((a==undef) || (a==unsigned_inf)) + return a; + return new_ref_symbolic(symbolic(at_neg,a)); + case _SYMB: + if (a==plus_inf) + return minus_inf; + if (a==minus_inf) + return plus_inf; + if (a._SYMBptr->sommet==at_neg) + return a._SYMBptr->feuille; + if (a._SYMBptr->sommet==at_unit){ + // if (equalposcomp(lidnt(a),cst_pi)!=0) return -evalf(b,1,context0); + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(-a._SYMBptr->feuille._VECTptr->front(),a._SYMBptr->feuille._VECTptr->back()))); + } + if (a._SYMBptr->sommet==at_plus) + return new_ref_symbolic(symbolic(at_plus,gen(negvecteur(*a._SYMBptr->feuille._VECTptr),_SEQ__VECT))); + if (a._SYMBptr->sommet==at_interval && a._SYMBptr->feuille.type==_VECT && a._SYMBptr->feuille._VECTptr->size()==2){ + return new_ref_symbolic(symbolic(at_interval,gen(makenewvecteur(-a._SYMBptr->feuille._VECTptr->back(),-a._SYMBptr->feuille._VECTptr->front()),_SEQ__VECT))); + } + if (equalposcomp(plot_sommets,a._SYMBptr->sommet)){ + return symbolic_plot_makevecteur(a._SYMBptr->sommet,-a._SYMBptr->feuille,false,context0); + } + if (a.is_symb_of_sommet(at_program)){ + gen a1,b; + if (is_algebraic_program(a,a1,b)) + return symbolic(at_program,gen(makevecteur(a1,0,-b),_SEQ__VECT)); + } + if (a._SYMBptr->sommet==at_equal || a._SYMBptr->sommet==at_equal2 || a._SYMBptr->sommet==at_different || a._SYMBptr->sommet==at_same) + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,makesequence(-a._SYMBptr->feuille._VECTptr->front(),-a._SYMBptr->feuille._VECTptr->back()))); + if (is_inequality(a)) + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,makesequence(-a._SYMBptr->feuille._VECTptr->back(),-a._SYMBptr->feuille._VECTptr->front()))); + return new_ref_symbolic(symbolic(at_neg,a)); + case _VECT: + if (a.subtype==_VECTOR__VECT && a._VECTptr->size()==2) + return gen(makenewvecteur(a._VECTptr->back(),a._VECTptr->front()),_VECTOR__VECT); + if (a.subtype==_PNT__VECT) + return gen(negfirst(*a._VECTptr),a.subtype); + return gen(negvecteur(*a._VECTptr),a.subtype); + case _MAP:{ + gen_map res; + gen g(res); + *g._MAPptr=*a._MAPptr; + sparse_neg(*g._MAPptr); + return g; + } + case _POLY: + return -(*a._POLYptr); + case _EXT: + return algebraic_EXTension(-(*a._EXTptr),*(a._EXTptr+1)); + case _USER: + return -(*a._USERptr); + case _MOD: + return makemod(-*a._MODptr,*(a._MODptr+1)); + case _FRAC: + return fraction(-(a._FRACptr->num),a._FRACptr->den); + case _SPOL1: + return spneg(*a._SPOL1ptr,context0); + case _STRNG: + if (is_undef(a)) return a; + return string2gen("-"+(*a._STRNGptr),false); + case _REAL: + return -*a._REALptr; + default: + return new_ref_symbolic(symbolic(at_neg,a)); + } + } + + static gen mulpoly(const gen & th,const gen & other){ + if ((th.type!=_POLY) || (other.type!=_POLY)){ +#ifndef NO_STDEXCEPT + settypeerr(gettext("mulpoly")); +#endif + return gentypeerr(gettext("mulpoly")); + } + vector< monomial >::const_iterator ita = th._POLYptr->coord.begin(); + vector< monomial >::const_iterator ita_end = th._POLYptr->coord.end(); + vector< monomial >::const_iterator itb = other._POLYptr->coord.begin(); + vector< monomial >::const_iterator itb_end = other._POLYptr->coord.end(); + // first some trivial cases + if (ita==ita_end) + return(th); + if (itb==itb_end) + return(other); + if (is_one(*th._POLYptr)) + return other; + if (is_one(*other._POLYptr)) + return th; + // Now look if length a=1 or length b=1, happens frequently + // think of x^3*y^2*z translated to internal form + int c1=int(th._POLYptr->coord.size()); + if (c1==1) + return other._POLYptr->shift(th._POLYptr->coord.front().index,th._POLYptr->coord.front().value); + int c2=int(other._POLYptr->coord.size()); + if (c2==1) + return th._POLYptr->shift(other._POLYptr->coord.front().index,other._POLYptr->coord.front().value); + ref_polynome * resptr = new ref_polynome(th._POLYptr->dim); + mulpoly(*th._POLYptr,*other._POLYptr,resptr->t,0); + return resptr; + } + + static vecteur multfirst(const gen & a,const vecteur & v){ + vecteur w(v); + if (!w.empty()) + w.front()=v.front()*a; + return w; + } + + static gen multgen_poly(const gen & a,const vecteur & b,int subtype){ + gen res(vecteur(0),subtype); + multvecteur(a,b,*res._VECTptr); + return res; + } + + static gen multgen_poly(const vecteur & a,const vecteur & b){ + gen res(vecteur(0), _POLY1__VECT); + operator_times(a,b,0,*res._VECTptr); + return res; + } + + // a*b -> tmp, modifies tmp in place + void type_operator_times(const gen & a,const gen &b,gen & tmp){ + register unsigned t=(a.type<< _DECALAGE) | b.type; +#if !defined(EMCC) && !defined(EMCC2) + if (tmp.type==_DOUBLE_ && t==_DOUBLE___DOUBLE_){ +#ifdef DOUBLEVAL + tmp._DOUBLE_val=a._DOUBLE_val*b._DOUBLE_val; +#else + *((double *) &tmp) = (*((double *) &a)) * (*((double *) &b)); + tmp.type = _DOUBLE_; +#endif + return ; + } +#endif + if (!t && tmp.type==_INT_ ){ + register longlong ab=longlong(a.val)*b.val; + tmp.val=(int)ab; +#if 1 + if (ab>>31) + tmp=ab; +#else + if (tmp.val!=ab || tmp==-2147483648) + tmp=ab; +#endif + return; + } + if (tmp.type==_ZINT && tmp.ref_count()==1){ + mpz_t * ptr=tmp._ZINTptr; + switch (t){ + case _INT___INT_: + tmp=longlong(a.val)*b.val; + return; + case _ZINT__ZINT: + mpz_mul(*ptr,*a._ZINTptr,*b._ZINTptr); + return ; + case _ZINT__INT_: + if (b.val<0){ + mpz_mul_ui(*ptr,*a._ZINTptr,-b.val); + mpz_neg(*ptr,*ptr); + } + else + mpz_mul_ui(*ptr,*a._ZINTptr,b.val); + return; + case _INT___ZINT: + if (a.val<0){ + mpz_mul_ui(*ptr,*b._ZINTptr,-a.val); + mpz_neg(*ptr,*ptr); + } + else + mpz_mul_ui(*ptr,*b._ZINTptr,a.val); + return; + } + } + tmp=a*b; + } + + bool is_int_zint_vecteur(const vecteur & m){ + const_iterateur it=m.begin(),itend=m.end(); + for (;it!=itend;++it){ + int t=it->type; + if (t!=_INT_ && t!=_ZINT) return false; + } + return true; + } + + void type_operator_plus_times(const gen & a,const gen & b,gen & c){ + register unsigned t=(a.type<< _DECALAGE) | b.type; +#if !defined(EMCC) && !defined(EMCC2) + if (c.type==_DOUBLE_ && t==_DOUBLE___DOUBLE_){ +#ifdef DOUBLEVAL + c._DOUBLE_val += a._DOUBLE_val*b._DOUBLE_val; +#else + *((double *) &c) += (*((double *) &a)) * (*((double *) &b)); + c.type = _DOUBLE_; +#endif + return ; + } +#endif + if (c.type==_ZINT && c.ref_count()==1){ + switch (t){ + case _ZINT__ZINT: + mpz_addmul(*c._ZINTptr,*a._ZINTptr,*b._ZINTptr); + return; + case _ZINT__INT_: + if (b.val<0) + mpz_submul_ui(*c._ZINTptr,*a._ZINTptr,-b.val); + else + mpz_addmul_ui(*c._ZINTptr,*a._ZINTptr,b.val); + return; + case _INT___ZINT: + if (a.val<0){ + mpz_submul_ui(*c._ZINTptr,*b._ZINTptr,-a.val); + } + else + mpz_addmul_ui(*c._ZINTptr,*b._ZINTptr,a.val); + return; + } + } + if (c.type==_EXT && a.type==_EXT && b.type==_EXT){ + if ((c._EXTptr+1)->type==_VECT && *(a._EXTptr+1)==*(c._EXTptr+1) && *(b._EXTptr+1)==*(c._EXTptr+1) && a._EXTptr->type==_VECT && b._EXTptr->type==_VECT && c._EXTptr->type==_VECT){ + vecteur & v = *(c._EXTptr+1)->_VECTptr; + if (v.size()==3 && v[0]==1 && v[1]==0 && a._EXTptr->_VECTptr->size()==2 && b._EXTptr->_VECTptr->size()==2 && c._EXTptr->_VECTptr->size()==2){ + gen a1=a._EXTptr->_VECTptr->front(),a0=a._EXTptr->_VECTptr->back(),b1=b._EXTptr->_VECTptr->front(),b0=b._EXTptr->_VECTptr->back(),c1=c._EXTptr->_VECTptr->front(),c0=c._EXTptr->_VECTptr->back(); + gen d1=a1*b0+a0*b1+c1,d0=a0*b0-v[2]*a1*b1+c0; + if (is_zero(d1)){ c=d0; return; } + gen d=new ref_vecteur(2); + d._VECTptr->front()=d1; + d._VECTptr->back()=d0; + if (c.ref_count()==1) + *c._EXTptr=d; + else + c=algebraic_EXTension(d,*(c._EXTptr+1)); + } + else { + gen d=new ref_vecteur; + vecteur ab,rem; + operator_times(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,0,ab); + addmodpoly(ab,*c._EXTptr->_VECTptr,*d._VECTptr); + if (c.ref_count()==1){ + DivRem(*d._VECTptr,v,0,ab,rem); // take remainder! + if (rem.size()<2){ if (rem.empty()) c=0; else c=rem.front();} + else { + //gen dbg=ext_reduce(d,*(c._EXTptr+1)); + d._VECTptr->swap(rem); + *c._EXTptr=d; + //if (dbg!=c) CERR << "error" << '\n'; + } + } + else + c=ext_reduce(d,*(c._EXTptr+1)); + } + return; + } + } + if (c.type==_VECT && c.ref_count()==1 && a.type==_VECT && b.type==_VECT && a._VECTptr->size()size()begin(),a._VECTptr->end(),b._VECTptr->begin(),b._VECTptr->end(),0,*c._VECTptr); + return; + } + gen g; + type_operator_times(a,b,g); + if (g.type==_ZINT) + swapgen(c,g); + c += g; + } + + void type_operator_minus_times(const gen & a,const gen & b,gen & c){ + register unsigned t=(a.type<< _DECALAGE) | b.type; +#if !defined(EMCC) && !defined(EMCC2) + if (c.type==_DOUBLE_ && t==_DOUBLE___DOUBLE_){ +#ifdef DOUBLEVAL + c._DOUBLE_val -= a._DOUBLE_val*b._DOUBLE_val; +#else + *((double *) &c) -= (*((double *) &a)) * (*((double *) &b)); + c.type = _DOUBLE_; +#endif + return ; + } +#endif + if (c.type==_ZINT && c.ref_count()==1){ + switch (t){ + case _ZINT__ZINT: + mpz_submul(*c._ZINTptr,*a._ZINTptr,*b._ZINTptr); + return; + case _ZINT__INT_: + if (b.val<0) + mpz_addmul_ui(*c._ZINTptr,*a._ZINTptr,-b.val); + else + mpz_submul_ui(*c._ZINTptr,*a._ZINTptr,b.val); + return; + case _INT___ZINT: + if (a.val<0){ + mpz_addmul_ui(*c._ZINTptr,*b._ZINTptr,-a.val); + } + else + mpz_submul_ui(*c._ZINTptr,*b._ZINTptr,a.val); + return; + } + } + gen g; + type_operator_times(a,b,g); + c -= g; + } + + static gen double_times_frac(const gen & a,const fraction & b,GIAC_CONTEXT){ + gen n=a*b.num,d=b.den; + return rdiv(n,d,contextptr); + } + + static gen mult_cplx(const gen & a,const gen & b,GIAC_CONTEXT){ + gen * aptr=a._CPLXptr,*bptr=b._CPLXptr; + unsigned t= (aptr->type | ((aptr+1)->type << 8) | (bptr->type << 16) | ((bptr+1)->type << 24)); + if (t==(_DOUBLE_ | (_DOUBLE_<<8) | (_DOUBLE_ <<16) | (_DOUBLE_ <<24))){ + double ar=aptr->_DOUBLE_val,ai=(aptr+1)->_DOUBLE_val, + br=bptr->_DOUBLE_val,bi=(bptr+1)->_DOUBLE_val; + return gen(ar*br-ai* bi, br*ai+ar*bi); + } + if (t==(_ZINT | (_ZINT<<8) | (_ZINT <<16) | (_ZINT <<24))){ + mpz_t & ax=*aptr->_ZINTptr; + mpz_t & ay=*((aptr+1)->_ZINTptr); + mpz_t & bx=*bptr->_ZINTptr; + mpz_t & by=*((bptr+1)->_ZINTptr); + // (ax+i*ay)*(bx+i*by)=ax*bx-ay*by+i*(ax*by+ay*bx) + // imaginary part is also (ax+ay)*(bx+by)-ax*bx-ay*by, Karatsuba trick + mpz_t axbx,ayby,r; +#if defined USE_GMP_REPLACEMENTS || defined BF2GMP_H + mpz_init(axbx); mpz_init(ayby); mpz_init(r); +#else + int n1=mpz_size(ax)+mpz_size(bx),n2=mpz_size(ay)+mpz_size(by); + mpz_init2(axbx,n1); mpz_init2(ayby,n2); mpz_init2(r,giacmax(n1,n2)+2); +#endif + mpz_mul(axbx,ax,bx); + mpz_add(r,ax,ay); + mpz_add(ayby,bx,by); // temporary use + mpz_mul(r,r,ayby); + mpz_sub(r,r,axbx); + mpz_mul(ayby,ay,by); + mpz_sub(r,r,ayby); + gen I=r; + mpz_sub(r,axbx,ayby); + gen R=r; + R=gen(R,I); + mpz_clear(r); mpz_clear(ayby); mpz_clear(axbx); + return R; + } +#if defined HAVE_LIBMPFR && !defined NO_RTTI + if (t==(_REAL | (_REAL<<8) | (_REAL <<16) | (_REAL <<24))){ + real_object & ax=*aptr->_REALptr; + real_object & ay=*((aptr+1)->_REALptr); + real_object & bx=*bptr->_REALptr; + real_object & by=*((bptr+1)->_REALptr); + if (!dynamic_cast(&ax) || + !dynamic_cast(&ay) || + !dynamic_cast(&bx) || + !dynamic_cast(&by) ){ + mpfr_t axbx,ayby,r; + int nbits=mpfr_get_prec(ax.inf); + nbits=giacmin(nbits,mpfr_get_prec(bx.inf)); + mpfr_init2(axbx,nbits); mpfr_init2(ayby,nbits); mpfr_init2(r,nbits); + mpfr_mul(axbx,ax.inf,bx.inf,MPFR_RNDN); + mpfr_add(r,ax.inf,ay.inf,MPFR_RNDN); + mpfr_add(ayby,bx.inf,by.inf,MPFR_RNDN); // temporary use + mpfr_mul(r,r,ayby,MPFR_RNDN); + mpfr_sub(r,r,axbx,MPFR_RNDN); + mpfr_mul(ayby,ay.inf,by.inf,MPFR_RNDN); + mpfr_sub(r,r,ayby,MPFR_RNDN); + gen I=real_object(r); + mpfr_sub(r,axbx,ayby,MPFR_RNDN); + gen R=real_object(r); + R=gen(R,I); + mpfr_clear(r); mpfr_clear(ayby); mpfr_clear(axbx); + return R; + } + } +#endif + return gen(*aptr * (*bptr) - *(aptr+1)* (*(bptr+1)), + (*bptr) * (*(aptr+1)) + *(bptr+1) * (*aptr)); + } + + static gen operator_times(const gen & a,const gen & b,unsigned t,GIAC_CONTEXT){ + static bool warnpy=true; + // COUT << a << "*" << b << '\n'; + // if (!( (++control_c_counter) & control_c_counter_mask)) +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + register ref_mpz_t * e; + switch (t) { + case _ZINT__ZINT: + e=new ref_mpz_t(GIAC_MPZ_INIT_SIZE); // ((mpz_size(*b._ZINTptr)+mpz_size(*b._ZINTptr))*mp_bits_per_limb); + mpz_mul(e->z,*a._ZINTptr,*b._ZINTptr); + return e; + case _DOUBLE___DOUBLE_: + return a._DOUBLE_val*b._DOUBLE_val; + case _FLOAT___FLOAT_: + return a._FLOAT_val*b._FLOAT_val; + case _INT___ZINT: + if (a.val==1) return b; + e=new ref_mpz_t(GIAC_MPZ_INIT_SIZE); // (mpz_size(*b._ZINTptr)*mp_bits_per_limb); + if (a.val<0){ + mpz_mul_ui(e->z,*b._ZINTptr,-a.val); + mpz_neg(e->z,e->z); + } + else + mpz_mul_ui(e->z,*b._ZINTptr,a.val); + return gen(e); + case _ZINT__INT_: + if (b.val==1) return a; + e=new ref_mpz_t(GIAC_MPZ_INIT_SIZE); // (mpz_size(*a._ZINTptr)*mp_bits_per_limb); + if (b.val<0){ + mpz_mul_ui(e->z,*a._ZINTptr,-b.val); + mpz_neg(e->z,e->z); + } + else + mpz_mul_ui(e->z,*a._ZINTptr,b.val); + return gen(e); + case _INT___DOUBLE_: + return a.val*b._DOUBLE_val; + case _DOUBLE___INT_: + return a._DOUBLE_val*b.val; + case _INT___FLOAT_: + return giac_float(a.val)*b._FLOAT_val; + case _FLOAT___INT_: + return a._FLOAT_val*giac_float(b.val); + case _DOUBLE___FLOAT_: + return giac_float(a._DOUBLE_val)*b._FLOAT_val; + case _FLOAT___DOUBLE_: + return a._FLOAT_val*giac_float(b._DOUBLE_val); + case _FLOAT___FRAC: case _DOUBLE___FRAC: + return double_times_frac(a,*b._FRACptr,contextptr); + case _FRAC__FLOAT_: case _FRAC__DOUBLE_: + return double_times_frac(b,*a._FRACptr,contextptr); + case _INT___FRAC: case _ZINT__FRAC: + return a*(*b._FRACptr); + case _FRAC__INT_: case _FRAC_ZINT: + return (*a._FRACptr)*b; + case _DOUBLE___ZINT: + return a._DOUBLE_val*mpz_get_d(*b._ZINTptr); + case _DOUBLE___REAL: + return a._DOUBLE_val*real2double(*b._REALptr); + case _REAL__DOUBLE_: + return b._DOUBLE_val*real2double(*a._REALptr); + case _ZINT__DOUBLE_: + return mpz_get_d(*a._ZINTptr)*b._DOUBLE_val; + case _CPLX__INT_: + if (b.val==1) return a; + case _CPLX__ZINT: case _CPLX__DOUBLE_: case _CPLX__FLOAT_: case _CPLX__REAL: + return gen(*a._CPLXptr*b,*(a._CPLXptr+1)*b); + case _INT___CPLX: + return a.val==1?b:gen(a*(*b._CPLXptr),a*(*(b._CPLXptr+1))); + case _ZINT__CPLX: case _DOUBLE___CPLX: case _FLOAT___CPLX: case _REAL__CPLX: + return is_one(a)?b:gen(a*(*b._CPLXptr),a*(*(b._CPLXptr+1))); + case _CPLX__CPLX: + return adjust_complex_display(mult_cplx(a,b,contextptr),a,b); +#if 1 //ndef GIAC_GGB + case _INT___STRNG:{ + if (b.subtype==-1) return b; + string res; + for (int i=0;i=0 && python_compat(contextptr)==2){ + vecteur res; + res.reserve(a._VECTptr->size()*b.val); + const_iterateur it,itend=a._VECTptr->end(); + int n=b.val; + for (int i=0;ibegin();it!=itend;++it) + res.push_back(*it); + } + return gen(res,a.subtype); + } + case _VECT__ZINT: case _VECT__DOUBLE_: case _VECT__FLOAT_: case _VECT__CPLX: case _VECT__SYMB: case _VECT__IDNT: case _VECT__POLY: case _VECT__EXT: case _VECT__MOD: case _VECT__FRAC: case _VECT__REAL: { + gen A(a),B(b); + if (A.is_approx() && !is_fully_numeric(B)) + B=evalf(b,1,contextptr); + else { + if (B.is_approx() && !is_fully_numeric(A)){ + A=evalf(a,1,contextptr); + if (A.type!=_VECT) + A=a; + } + } + // matrix * point -> point + if (B.is_symb_of_sommet(at_pnt)){ + gen tmp=complex2vecteur(remove_at_pnt(B),contextptr); + if (ckmatrix(A)){ + tmp=multmatvecteur(*A._VECTptr,*tmp._VECTptr); + return _point(tmp,contextptr); + } + if (A._VECTptr->size()==tmp._VECTptr->size()) + return dotvecteur(*A._VECTptr,*tmp._VECTptr); + } + if (A.subtype==_VECTOR__VECT && A._VECTptr->size()==2) + return vector2vecteur(*A._VECTptr)*B; + if (A.subtype==_PNT__VECT) + return gen(multfirst(B,*A._VECTptr),_PNT__VECT); + if (A.subtype==_POLY1__VECT){ + if (is_zero(B,contextptr)) + return B; + //if (b.type==_POLY) return a*(*b._POLYptr); + } + return multgen_poly(B,*A._VECTptr,A.subtype); // gen(multvecteur(b,*a._VECTptr),a.subtype); + } + case _INT___VECT: + if (a.val>=0 && python_compat(contextptr)==2) + return operator_times(b,a,contextptr); + if (warnpy && a.val>=0 && python_compat(contextptr)){ + alert(gettext("Python compatibility, integer*list will do vector multiplication, run list*integer to duplicate list"),contextptr); + warnpy=false; + } + case _ZINT__VECT: case _DOUBLE___VECT: case _FLOAT___VECT: case _CPLX__VECT: case _SYMB__VECT: case _IDNT__VECT: case _POLY__VECT: case _EXT__VECT: case _MOD__VECT: case _FRAC__VECT: case _REAL__VECT: { + gen A(a),B(b); + if (A.is_approx() && !is_fully_numeric(B)){ + B=evalf(b,1,contextptr); + if (B.type!=_VECT) + B=b; + } + else { + if (B.is_approx() && !is_fully_numeric(A)){ + A=evalf(a,1,contextptr); + } + } + if (A.is_symb_of_sommet(at_pnt)){ + gen tmp=complex2vecteur(remove_at_pnt(A),contextptr); + if (ckmatrix(B)) + return _point(multvecteurmat(*tmp._VECTptr,*B._VECTptr),contextptr); + if (tmp._VECTptr->size()==B._VECTptr->size()) + return dotvecteur(*tmp._VECTptr,*B._VECTptr,contextptr); + } + if (B.subtype==_VECTOR__VECT && B._VECTptr->size()==2) + return A*vector2vecteur(*B._VECTptr); + if (B.subtype==_PNT__VECT) + return gen(multfirst(A,*B._VECTptr),_PNT__VECT); + if (B.subtype==_POLY1__VECT){ + if (is_zero(A,contextptr)) + return A; + // if (a.type==_POLY) return b*(*a._POLYptr); + } + return multgen_poly(A,*B._VECTptr,B.subtype); // gen(multvecteur(a,*b._VECTptr),b.subtype); + } + case _VECT__VECT: { + gen A(a),B(b); + if (A.subtype==_SET__VECT && B.subtype==_SET__VECT){ + vecteur res; res.reserve(A._VECTptr->size()*B._VECTptr->size()); + const_iterateur at=A._VECTptr->begin(),aend=A._VECTptr->end(),bt=B._VECTptr->begin(),bend=B._VECTptr->end(); + for (;at!=aend;++at){ + for (bt=B._VECTptr->begin();bt!=bend;++bt){ + if (at->type==_VECT && at->subtype==_TUPLE__VECT){ + if (bt->type==_VECT && bt->subtype==_TUPLE__VECT){ + res.push_back(gen(mergevecteur(*at->_VECTptr,*bt->_VECTptr),_TUPLE__VECT)); + } + else { + vecteur tmp(*at->_VECTptr); + tmp.push_back(*bt); + res.push_back(gen(tmp,_TUPLE__VECT)); + } + } + else { + if (bt->type==_VECT && bt->subtype==_TUPLE__VECT){ + vecteur tmp(*bt->_VECTptr); + tmp.insert(tmp.begin(),*at); + res.push_back(gen(tmp,_TUPLE__VECT)); + } + else + res.push_back(gen(makevecteur(*at,*bt),_TUPLE__VECT)); + } + } + } + return gen(res,_SET__VECT); + } + // FIXME should not convert 0 in B if A has intervals + if (A.is_approx() && !is_fully_numeric(B)){ + bool done=false; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + // workaround for lu e.g. a:=ranm(4,4); b:=convert(a,interval); p,l,u:=lu(b):; l*u; + if (!A._VECTptr->empty() && A._VECTptr->back().type==_VECT && !A._VECTptr->back()._VECTptr->empty() && A._VECTptr->back()._VECTptr->front().type==_REAL){ + if (real_interval * ptr=dynamic_cast(A._VECTptr->back()._VECTptr->front()._REALptr)){ + B=convert_interval(b,mpfi_get_prec(ptr->infsup),contextptr); + done=true; + } + } +#endif + if (!done) + B=evalf(b,1,contextptr); + if (B.type!=_VECT) + B=b; + } + else { + if (B.is_approx() && !is_fully_numeric(A)){ + A=evalf(a,1,contextptr); + if (A.type!=_VECT) + A=a; + } + } + if (// abs_calc_mode(contextptr)==38 && + (A.subtype==_MATRIX__VECT ||B.subtype==_MATRIX__VECT) && ckmatrix(A) && ckmatrix(B)){ + if (A._VECTptr->front()._VECTptr->size()!=B._VECTptr->size()) + return gendimerr(contextptr); + gen res(new ref_vecteur(0),_MATRIX__VECT); + mmult(*A._VECTptr,*B._VECTptr,*res._VECTptr); + return res; + } + if ( (A.subtype==_POLY1__VECT) || (B.subtype==_POLY1__VECT) ) + return multgen_poly(*A._VECTptr,*B._VECTptr); + if ( (A.subtype==_LIST__VECT) || (B.subtype==_LIST__VECT) ) + return matrix_apply(A,B,contextptr,operator_times); + if (A.subtype==_GGBVECT || (b.subtype==_GGBVECT && !ckmatrix(A))){ + gen res=dotvecteur(a,b); + if (res.type==_VECT) res.subtype=_GGBVECT; + return res; + } + { gen res=ckmultmatvecteur(*A._VECTptr,*B._VECTptr,contextptr); + if ( (calc_mode(contextptr)==1 || abs_calc_mode(contextptr)==38) && res.type==_VECT){ + res.subtype=B.subtype; + if (res.subtype==0) + res.subtype=A.subtype; + } + return res; + } + } + case _POLY__POLY: + return mulpoly(a,b); + case _FRAC__FRAC: + if (a._FRACptr->num.type==_EXT && b._FRACptr->num.type==_EXT) + return ((*a._FRACptr)*(*b._FRACptr)).normal(); + return (*a._FRACptr)*(*b._FRACptr); + case _SPOL1__SPOL1: + return spmul(*a._SPOL1ptr,*b._SPOL1ptr,contextptr); + case _EXT__EXT: + return ext_mul(a,b,contextptr); + case _MAP__MAP: + { + int arows,acols,an,brows,bcols,bn; + if (is_sparse_matrix(a,arows,acols,an) && is_sparse_matrix(b,brows,bcols,bn)){ + gen_map res; + gen g(res); + sparse_mult(*a._MAPptr,*b._MAPptr,*g._MAPptr); + return g; + } + } + case _MAP__VECT: + { + int arows,acols,an; + if (is_sparse_matrix(a,arows,acols,an)){ + if (acols>b._VECTptr->size()) + return gendimerr(contextptr); + if (ckmatrix(b)){ + vecteur A; + convert(*a._MAPptr,A); + return A*b; + } + smatrix as; + if (convert(*a._MAPptr,as)){ + vecteur res; + sparse_mult(as,*b._VECTptr,res); + return res; + } + gen_map res; + gen g(res); + if (!sparse_mult(*a._MAPptr,*b._VECTptr,*g._MAPptr)) + return gendimerr(contextptr); + // Should probably check if g is dense or not + return g; + } + } + case _VECT__MAP: + { + int brows,bcols,an; + if (is_sparse_matrix(b,brows,bcols,an)){ + if (brows>a._VECTptr->size()) + return gendimerr(contextptr); + if (ckmatrix(a)){ + vecteur B; + convert(*b._MAPptr,B); + return a*B; + } + smatrix bs; + if (convert(*b._MAPptr,bs)){ + vecteur res; + sparse_mult(*a._VECTptr,bs,res); + return res; + } + gen_map res; + gen g(res); + if (!sparse_mult(*a._VECTptr,*b._MAPptr,*g._MAPptr)) + return gendimerr(contextptr); + // Should probably check if g is dense or not + return g; + } + } + case _INT___MAP: case _ZINT__MAP: case _DOUBLE___MAP: case _FLOAT___MAP: case _CPLX__MAP: case _SYMB__MAP: case _IDNT__MAP: case _POLY__MAP: case _EXT__MAP: case _MOD__MAP: case _FRAC__MAP: case _REAL__MAP: { + if (is_one(a)) + return b; + int brows,bcols,bn; + if (is_sparse_matrix(b,brows,bcols,bn)){ + gen_map res; + gen g(res); + if (is_zero(a)) + return g; + *g._MAPptr=*b._MAPptr; + sparse_mult(a,*g._MAPptr); + return g; + } + break; + } + case _POLY__INT_: case _POLY__ZINT: case _POLY__DOUBLE_: case _POLY__FLOAT_: case _POLY__CPLX: case _POLY__USER: case _POLY__REAL: + if (is_one(b)) + return a; + return (*a._POLYptr) * b; + case _POLY__MOD: + return (*a._POLYptr) * b; + case _INT___POLY: case _ZINT__POLY: case _DOUBLE___POLY: case _FLOAT___POLY: case _CPLX__POLY: case _USER__POLY: case _REAL__POLY: + if (is_one(a)) + return b; + return a * (*b._POLYptr); + case _MOD__POLY: + return a * (*b._POLYptr); + case _MOD__MOD: +#ifdef SMARTPTR64 + return modmul( (ref_modulo *) (* ((ulonglong * ) &a) >> 16),(ref_modulo *) (* ((ulonglong * ) &b) >> 16) ); +#else + return modmul(a.__MODptr,b.__MODptr); +#endif + case _MOD__INT_: case _MOD__ZINT: + return makemod(*a._MODptr*b,*(a._MODptr+1)); + case _INT___MOD: case _ZINT__MOD: + return makemod(*b._MODptr*a,*(b._MODptr+1)); + case _REAL__REAL: + return (*a._REALptr)*(*b._REALptr); + default: + if (is_undef(a)) + return a; + if (is_undef(b)) + return b; + if (a.type==_FLOAT_){ + gen b1; + if (has_evalf(b,b1,1,contextptr)&& (b.type!=b1.type || b!=b1)) + return a*b1; + return operator_times(evalf_double(a,1,contextptr),b,contextptr); + } + if (b.type==_FLOAT_){ + gen a1; + if (has_evalf(a,a1,1,contextptr)&& (a.type!=a1.type || a!=a1)) + return a1*b; + return operator_times(a,evalf_double(b,1,contextptr),contextptr); + } + if (a.type==_SPOL1) + return spmul(*a._SPOL1ptr,gen2spol1(b),contextptr); + if (b.type==_SPOL1) + return spmul(gen2spol1(a),*b._SPOL1ptr,contextptr); + if (a.type==_USER) + return (*a._USERptr)*b; + if (b.type==_USER) + return (*b._USERptr)*a; + if (a.type==_REAL) + return a._REALptr->multiply(b,contextptr); + if (b.type==_REAL) + return b._REALptr->multiply(a,contextptr); + if (a.type==_STRNG || b.type==_STRNG) + return gensizeerr(contextptr); + return sym_mult(a,b,contextptr); + } + return undef; + } + + gen operator_times(const gen & a,const gen & b,GIAC_CONTEXT){ + register unsigned t=(a.type<< _DECALAGE) | b.type; + if (!t) + return gen((longlong) a.val*b.val); + return operator_times(a,b,t,contextptr); + } + + gen operator * (const gen & a,const gen & b){ + register unsigned t=(a.type<< _DECALAGE) | b.type; + if (!t) + return gen((longlong) a.val*b.val); + return operator_times(a,b,t,context0); + } + + bool has_i(const gen & g){ + if (g.type==_CPLX) + return true; + if (g.type==_FRAC) + return g._FRACptr->num.type==_CPLX || g._FRACptr->den.type==_CPLX; + if (g.type==_VECT){ + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it){ + if (has_i(*it)) + return true; + } + return false; + } + if (g.type==_SPOL1){ + sparse_poly1::const_iterator it=g._SPOL1ptr->begin(),itend=g._SPOL1ptr->end(); + for (;it!=itend;++it){ + if (has_i(it->coeff)) + return true; + } + return false; + } + if (g.type==_EXT) + return has_i(*g._EXTptr); + if (g.type!=_SYMB) + return false; + return has_i(g._SYMBptr->feuille); + } + + gen giac_pow(const gen & base,const gen & exponent,GIAC_CONTEXT){ + return pow(base,exponent,contextptr); + } + + // (-1)^n + static gen minus1pow(const gen & exponent,GIAC_CONTEXT,bool allow_recursion=true){ + if (exponent.type==_INT_) + return (exponent.val%2)?-1:1; + if (exponent.type==_ZINT){ + gen q,g=irem(exponent,2,q); + if (is_zero(g,contextptr)) + return 1; + return -1; + } + if (is_inf(exponent)) + return undef; + if (is_undef(exponent)) + return exponent; + if (exponent.is_symb_of_sommet(at_neg)){ + gen tmp=minus1pow(exponent._SYMBptr->feuille,contextptr); + if (is_assumed_integer(exponent,contextptr)) + return tmp; + //else return symb_inv(tmp); + } + if (exponent.is_symb_of_sommet(at_plus)){ + gen res(1); + gen & f=exponent._SYMBptr->feuille; + if (f.type!=_VECT) + return minus1pow(f,contextptr); + vecteur & v = *f._VECTptr; + int s=int(v.size()); + for (int i=0;ifeuille; + if (f.type==_VECT){ + vecteur & v = *f._VECTptr; + int i,s=int(v.size()); + bool even=false,perhapsone=true; + gen num=1,den=1; + for (i=0;ifeuille; + else + num=num*v[i]; + if (is_integer(v[i]) && is_zero(smod(v[i],2),contextptr)) + even=true; + if (!is_assumed_integer(v[i],contextptr)) + perhapsone=false; + } +#ifndef NO_STDEXCEPT + if (allow_recursion && perhapsone){ + gen num1=undef; + try { + num1=_irem(makesequence(num,2*den),contextptr); + } catch (std::runtime_error & err){ + num1=undef; + } + if (!is_undef(num1) && num1!=num) return minus1pow(symb_prod(num1,symb_inv(den)),contextptr,false); + } +#endif + if (even && perhapsone) + return 1; + if (num.type==_INT_ && den.type==_INT_ && den.val<=MAX_ALG_EXT_ORDER_SIZE){ + return exp(cst_i*exponent*cst_pi,contextptr); + } + } + } + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(-1,exponent),_SEQ__VECT))); + } + + static gen pow_iterative(const gen & base,const gen & exponent,GIAC_CONTEXT){ + if (is_positive(-exponent,contextptr)) + return pow_iterative(inv(base,contextptr),-exponent,contextptr); + gen res=1,expo=exponent; + gen basepow=base; + while (!is_zero(expo)){ + gen q,r=irem(expo,2,q); + if (!is_zero(r)) + res = res*basepow; + expo=q; + if ( !is_zero(expo) ) + basepow=basepow*basepow; + } + return res; + } + + gen pow(const gen & base,const gen & exponent,GIAC_CONTEXT){ + if (base.type==_VECT && exponent.type==_VECT && (base.subtype==_SET__VECT || exponent.subtype==_SET__VECT)){ + return _symmetric_difference(makesequence(base,exponent),contextptr); + } + // if (!( (++control_c_counter) & control_c_counter_mask)) +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + if (exponent.type==_INT_){ + if (exponent.val==1) return base; + if (exponent.val==2 && base.type<=_CPLX){ + if (base.type==_CPLX && base.subtype==3){ + double a=base._CPLXptr->_DOUBLE_val,b=(base._CPLXptr+1)->_DOUBLE_val; + return gen(a*a-b*b,2.0*a*b); + } + return operator_times(base,base,contextptr); + } + if (exponent.val%2==0 && base.is_symb_of_sommet(at_prod) && has_op(base,*at_pow)){ + const gen & f=base._SYMBptr->feuille; + if (f.type==_VECT){ + const vecteur & v=*f._VECTptr; + int s=v.size(); + vecteur w(v); + for (int i=0;inum==1 && exponent._FRACptr->den==2 && base.type==_SYMB){ + vecteur v=lvar(base); + if (v.size()==1 && v.front().is_symb_of_sommet(at_pow) && v.front()._SYMBptr->feuille[1]==plus_one_half && is_integer(v.front()._SYMBptr->feuille[0])){ + gen a,b,c=v.front()._SYMBptr->feuille[0]; + if (is_linear_wrt(base,v.front(),b,a,contextptr) && (is_integer(a) ||a.type==_FRAC) && (is_integer(b) || b.type==_FRAC)){ + gen d=a*a-b*b*c; + if (is_positive(d,contextptr)){ + d=sqrt(d,contextptr); + if (is_integer(d) || d.type==_FRAC){ + return sqrt((a+d)/2,contextptr)+sign(b,contextptr)*sqrt((a-d)/2,contextptr); + } + } + } + } + } + return pow(base,new_ref_symbolic(symbolic(at_prod,makesequence(exponent._FRACptr->num,symb_inv(exponent._FRACptr->den)))),contextptr); + } + if (is_inf(base)){ + if (is_zero(exponent,contextptr)) + return undef; + if (exponent==plus_inf){ + if (base==plus_inf) + return base; + return unsigned_inf; + } + if (exponent==minus_inf) + return 0; + gen d; + bool b=has_evalf(exponent,d,1,contextptr); + if (b && is_strictly_positive(-exponent,contextptr) ) + return 0; + if (b && base==plus_inf &&is_strictly_positive(exponent,contextptr)) + return plus_inf; + if ( (exponent.type==_INT_) ){ + if (exponent.val % 2) + return base; + else + return plus_inf; // for unsigned_inf in _DOUBLE_ mode only!! + } + if (b && is_strictly_positive(exponent,contextptr)) + return unsigned_inf; + return undef; + } + if (base.type==_SYMB){ + unary_function_ptr & u =base._SYMBptr->sommet; + if (u==at_unit){ + vecteur & v=*base._SYMBptr->feuille._VECTptr; + gen v1=v[1]; + vecteur w; + if (v1.is_symb_of_sommet(at_prod)) + w=gen2vecteur(v1._SYMBptr->feuille); + else + w.push_back(v1); + for (unsigned i=0;ifeuille[0],v1._SYMBptr->feuille[1]*exponent,contextptr); + else + v1=pow(v1,exponent,contextptr); + } + if (w.size()==1) v1=w.front(); else v1=symbolic(at_prod,gen(w,_SEQ__VECT)); + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(pow(v[0],exponent,contextptr),v1))); + } + if (u==at_abs && exponent.type==_INT_ && !complex_mode(contextptr) && !has_i(base)){ + int n=exponent.val,m; + if (n<0 && n%2) + m=n-1; + else + m=(n/2)*2; // or m=n%2?n-1:n; + gen basep=pow(base._SYMBptr->feuille,m); + if (n%2) + return base*basep; + else + return basep; + } + if (u==at_pnt && exponent.type==_INT_ && exponent.val%2==0){ + return pow(abs_norm2(remove_at_pnt(base),contextptr),exponent.val/2,contextptr); + } + if (u==at_sign && exponent.type==_INT_ && !complex_mode(contextptr) && !has_i(base)){ + int n=exponent.val; + if (n%2) + return base; + else + return 1; + } + if (u==at_exp){ + // (e^a)^b=e^(a*b) + // but we keep (e^a)^b if b is integer and e^(a*b) is not simplified + // for rational dependance + // or inside integration + gen res=exp(base._SYMBptr->feuille*exponent,contextptr); + if (exponent.type!=_INT_ || !res.is_symb_of_sommet(at_exp)) + return res; + } + if (u==at_inv && base._SYMBptr->feuille.type==_SYMB && (base._SYMBptr->feuille._SYMBptr->sommet==at_exp ||base._SYMBptr->feuille._SYMBptr->sommet==at_pow)) + return inv(pow(base._SYMBptr->feuille,exponent,contextptr),contextptr); + if (u==at_pow && !has_i(base)){ + vecteur & v=*base._SYMBptr->feuille._VECTptr; + gen & v1=v[1]; + gen new_exp=v1*exponent; + if (new_exp.type>_IDNT) + new_exp=normal(new_exp,contextptr); + if ( v1.type==_INT_ && v1.val%2==0 + && ((new_exp.type!=_INT_ && !is_assumed_integer(new_exp,contextptr)) || new_exp.val%2 ) + && !complex_mode(contextptr) ) + return pow(abs(v[0],contextptr),new_exp,contextptr); + else + return pow(v[0],new_exp,contextptr); + } + if (u==at_equal || u==at_equal2){ + vecteur & vb=*base._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(base._SYMBptr->sommet,makesequence(pow(vb.front(),exponent,contextptr),pow(vb.back(),exponent,contextptr)))); + } + if (exponent.type==_INT_){ + if (exponent.val==0) + return 1; + if (exponent.val==1) + return base; + return new_ref_symbolic(symbolic(at_pow,gen(makevecteur(base,exponent),_SEQ__VECT))); + } + } + if (abs_calc_mode(contextptr)==38 && !complex_mode(contextptr) && is_exactly_zero(base) && is_exactly_zero(exponent)) // was is_zero(,.contextptr) changed so that MINREAL^0 is not undef but 1 + return undef; + switch ( (base.type<< _DECALAGE) | exponent.type ) { + case _INT___INT_: case _ZINT__INT_: case _REAL__INT_: case _CPLX__INT_: case _IDNT__INT_: + return pow(base,exponent.val); + case _DOUBLE___DOUBLE_: + if (exponent._DOUBLE_val==int(std::floor(exponent._DOUBLE_val+.25))) + return pow(base,int(std::floor(exponent._DOUBLE_val+.25))); + if (base._DOUBLE_val>=0) +#ifdef _SOFTMATH_H + return std::giac_gnuwince_pow(base._DOUBLE_val,exponent._DOUBLE_val); +#else + return std::pow(base._DOUBLE_val,exponent._DOUBLE_val); +#endif + else + return exp(exponent*log(base,contextptr),contextptr); + case _FRAC__DOUBLE_: + return exp(exponent*log(base,contextptr),contextptr); + case _FLOAT___FLOAT_: + if (exponent._FLOAT_val==get_int(exponent._FLOAT_val)) + return pow(base,get_int(exponent._FLOAT_val)); + if (is_strictly_positive(-base,contextptr)) + return exp(exponent*ln(base,contextptr),contextptr); + return fpow(base._FLOAT_val,exponent._FLOAT_val); + case _INT___FLOAT_: + if (exponent._FLOAT_val==get_int(exponent._FLOAT_val)) + return pow(base,get_int(exponent._FLOAT_val)); + if (is_strictly_positive(-base,contextptr)) + return exp(exponent*ln(base,contextptr),contextptr); + return fpow(giac_float(base.val),exponent._FLOAT_val); + case _FLOAT___INT_: + return fpow(base._FLOAT_val,giac_float(exponent.val)); + case _DOUBLE___INT_: + if (base._DOUBLE_val>=0) +#ifdef _SOFTMATH_H + return std::giac_gnuwince_pow(base._DOUBLE_val,exponent.val); +#else + return std::pow(base._DOUBLE_val,exponent.val); +#endif + else + return (exponent.val%2?-1:1)*std::pow(-base._DOUBLE_val,exponent.val);//exp(exponent*log(-base,contextptr),contextptr); + case _INT___DOUBLE_: +#ifdef _SOFTMATH_H + return std::giac_gnuwince_pow(base.val,exponent._DOUBLE_val); +#else + return std::pow(double(base.val),exponent._DOUBLE_val); +#endif + case _ZINT__DOUBLE_: +#ifdef _SOFTMATH_H + return std::giac_gnuwince_pow(mpz_get_d(*base._ZINTptr),exponent._DOUBLE_val); +#else + return std::pow(mpz_get_d(*base._ZINTptr),exponent._DOUBLE_val); +#endif + case _DOUBLE___ZINT: + if (base._DOUBLE_val>=0) +#ifdef _SOFTMATH_H + return std::giac_gnuwince_pow(base._DOUBLE_val,mpz_get_d(*exponent._ZINTptr)); +#else + return std::pow(base._DOUBLE_val,mpz_get_d(*exponent._ZINTptr)); +#endif + else + return exp(exponent*log(base,contextptr),contextptr); + case _POLY__INT_: + if (exponent.val<0) + return fraction(1,pow(*base._POLYptr,-exponent.val)); + else + return pow(*base._POLYptr,exponent.val); + case _MAP__INT_: + if (exponent.val>=0) + return pow(base,exponent.val); + case _FRAC__INT_: + return pow(*base._FRACptr,exponent.val); + case _EXT__INT_: case _MOD__INT_: case _VECT__INT_: case _USER__INT_: + return pow(base,exponent.val); + case _MOD__ZINT: + return makemod(powmod(*base._MODptr,exponent,*(base._MODptr+1)),*(base._MODptr+1)); + default: + if (is_undef(base)) + return base; + if (is_undef(exponent)) + return exponent; + if (base.type==_STRNG || exponent.type==_STRNG) + return gensizeerr(contextptr); + if (is_one(base) && !is_inf(exponent)) + return base; + if (exponent.is_symb_of_sommet(at_prod) && exponent._SYMBptr->feuille.type==_VECT && exponent._SYMBptr->feuille._VECTptr->size()==2){ + gen e1=exponent._SYMBptr->feuille._VECTptr->front(); + gen e2=exponent._SYMBptr->feuille._VECTptr->back(); + if (e1.is_symb_of_sommet(at_ln) && e2.is_symb_of_sommet(at_inv) && e2._SYMBptr->feuille.is_symb_of_sommet(at_ln) && base==e2._SYMBptr->feuille._SYMBptr->feuille) + return e1._SYMBptr->feuille; + } + if (is_squarematrix(base)){ + if ((exponent.type==_REAL || exponent.type==_DOUBLE_ || exponent.type==_FLOAT_)) + return matpow(*base._VECTptr,exponent,contextptr); + if (exponent.type>=_IDNT) + *logptr(contextptr) << gettext("Use matpow to force computation of a power of matrix via jordanisation") << '\n'; + } + if (base.type==_REAL || base.type==_DOUBLE_ || + (base.type==_CPLX + // && base.subtype==3 + ) + || base.type==_FLOAT_ || ( (base.type<_POLY || base.type==_FLOAT_) && (exponent.type==_REAL || exponent.type==_DOUBLE_ || exponent.type==_FLOAT_))) + return exp(operator_times(exponent,log(base,contextptr),contextptr),contextptr); + /* + if (base.is_symb_of_sommet(at_neg)) + return minus1pow(exponent)*pow(base._SYMBptr->feuille,exponent); + */ + if ((base.type==_INT_) && (base.val<0)){ + if (exponent==plus_one_half) + return cst_i*sqrt(-base.val,contextptr); + // if (exponent==-one_half) + // return rdiv(cst_i,sqrt(-base.val)); + } + if (is_exactly_zero(base)){ + gen d; +#if 1 + // 0^k should return 0 if k is assumed to be positive + d=sign(exponent,contextptr); + if (is_one(d)) + return base; + if (is_minus_one(d)) + return unsigned_inf; +#else + bool b=has_evalf(exponent,d,1,contextptr); + if (b && is_positive(exponent,contextptr)) + return base; + if (b && is_positive(-exponent,contextptr)) + return unsigned_inf; +#endif + return undef; + } + if (base.type==_SPOL1) + return sppow(*base._SPOL1ptr,exponent,contextptr); + if (is_integer(base) && is_positive(-base,contextptr)){ +#if 0 + if (abs_calc_mode(contextptr)==38 && !complex_mode(contextptr)) + return gensizeerr(gettext("Negative to a fractional power")); +#endif + return minus1pow(exponent,contextptr)*pow(-base,exponent,contextptr); + } + if (is_inf(exponent)){ + if (base.type==_VECT) + return gensizeerr(contextptr); + return exp(exponent*ln(base,contextptr),contextptr); + } + // extract integral powers in a product exponent + if ((exponent.type==_SYMB) && (exponent._SYMBptr->sommet==at_prod)){ + gen subexponent_num(1),subexponent_deno(1); + gen superexponent(1); + const_iterateur it=exponent._SYMBptr->feuille._VECTptr->begin(),itend=exponent._SYMBptr->feuille._VECTptr->end(); + for (;it!=itend;++it){ + if (it->type==_INT_){ + superexponent = superexponent * (*it); + continue; + } + if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_inv)) + subexponent_deno = subexponent_deno * (it->_SYMBptr->feuille); + else + subexponent_num = subexponent_num * (*it); + } + if (superexponent.type!=_INT_ + || (!lidnt(exponent).empty() && absint(superexponent.val)>MAX_COMMON_ALG_EXT_ORDER_SIZE) + ) + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base,exponent),_SEQ__VECT))); + if (subexponent_deno.type!=_INT_ || (absint(subexponent_deno.val)>MAX_ALG_EXT_ORDER_SIZE && !lidnt(base).empty())){ + if (is_one(superexponent)) + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base,_FRAC2_SYMB(subexponent_num,subexponent_deno)),_SEQ__VECT))); + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base,_FRAC2_SYMB(subexponent_num,subexponent_deno)),_SEQ__VECT))),superexponent),_SEQ__VECT))); + } + int q=superexponent.val / subexponent_deno.val; + int r=superexponent.val % subexponent_deno.val; + gen res(1); + if (r){ + if (complex_mode(contextptr) && fastsign(base,contextptr)==-1){ // is_strictly_positive(-base,contextptr)){ + gen base1=-base; + res=exp((cst_i*cst_pi*subexponent_num)/subexponent_deno,contextptr); + res=new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(pow(base1,subexponent_num,contextptr),inv(subexponent_deno,contextptr)),_SEQ__VECT)))*res; + } + else + res=new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(pow(base,subexponent_num,contextptr),inv(subexponent_deno,contextptr)),_SEQ__VECT))); + if (r!=1) + res=new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(res,r),_SEQ__VECT))); + } + if (!q) + return res; + if (q==1){ + if (is_one(subexponent_num)) + return res*base; + return res*new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base,subexponent_num),_SEQ__VECT))); + } + if (q==-1) + return res*inv(pow(base,subexponent_num,contextptr),contextptr); + return res*new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(pow(base,subexponent_num,contextptr),q),_SEQ__VECT))); + } + gen var1,var2,res1,res2; + if (is_algebraic_program(base,var1,res1) && is_algebraic_program(exponent,var2,res2)){ + if (var1!=var2 && is_constant_wrt(res2,var1,contextptr)){ + res2=subst(res2,var2,var1,false,contextptr); + var2=var1; + } + if (var1==var2) + return symbolic(at_program,gen(makevecteur(var1,0,pow(res1,res2,contextptr)),_SEQ__VECT)); + } + if (exponent.type==_ZINT){ + if (base.type==_USER) + return pow_iterative(base,exponent,contextptr); + return exp(exponent*log(base,contextptr),contextptr); + } + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base,exponent),_SEQ__VECT))); + } + } + + gen sym_mult(const gen & a,const gen & b,GIAC_CONTEXT){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + if (is_undef(a)) + return a; + if (is_undef(b)) + return b; + if (is_inequality(a) && !is_equal(a)){ + int bs=fastsign(b,contextptr); + if (bs==-1) + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,makesequence(a._SYMBptr->feuille._VECTptr->back()*b,a._SYMBptr->feuille._VECTptr->front()*b))); + if (bs==1) + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,makesequence(a._SYMBptr->feuille._VECTptr->front()*b,a._SYMBptr->feuille._VECTptr->back()*b))); + } + if (is_inequality(b) && !is_equal(b)){ + int bs=fastsign(a,contextptr); + if (bs==-1) + return new_ref_symbolic(symbolic(b._SYMBptr->sommet,makesequence(a*b._SYMBptr->feuille._VECTptr->back(),a*b._SYMBptr->feuille._VECTptr->front()))); + if (bs==1) + return new_ref_symbolic(symbolic(b._SYMBptr->sommet,makesequence(a*b._SYMBptr->feuille._VECTptr->front(),a*b._SYMBptr->feuille._VECTptr->back()))); + } + if (a.is_symb_of_sommet(at_unit)){ + if (equalposcomp(lidnt(b),cst_pi)!=0) + return sym_mult(a,evalf(b,1,contextptr),contextptr); + vecteur & va=*a._SYMBptr->feuille._VECTptr; + if (b.is_symb_of_sommet(at_unit)){ + vecteur & v=*b._SYMBptr->feuille._VECTptr; + gen res=va[1]*v[1]; + res=ratnormal(res,contextptr); + if (is_one(res)) + return va[0]*v[0]; + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(operator_times(va[0],v[0],contextptr),res))); + } + else { + if (lidnt(b).empty()) + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(operator_times(va[0],b,contextptr),va[1]))); + } + } + if (b.is_symb_of_sommet(at_unit)){ + if (equalposcomp(lidnt(a),cst_pi)!=0) + return sym_mult(evalf(a,1,contextptr),b,contextptr); + if (lidnt(a).empty()){ + vecteur & v=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(operator_times(a,v[0],contextptr),v[1]))); + } + } + gen var1,var2,res1,res2; + if (is_algebraic_program(a,var1,res1)){ + if (is_algebraic_program(b,var2,res2)){ + if (var1!=var2 && is_constant_wrt(res2,var1,contextptr)){ + res2=subst(res2,var2,var1,false,contextptr); + var2=var1; + } + if (var1==var2) + return symbolic(at_program,gen(makevecteur(var1,0,operator_times(res1,res2,contextptr)),_SEQ__VECT)); + } + if (!is_constant_wrt(b,var1,contextptr)) + *logptr(contextptr) << "Warning function*constant with constant dependent of mute variable" << '\n'; + return symbolic(at_program,gen(makevecteur(var1,0,operator_times(res1,b,contextptr)),_SEQ__VECT)); + } + if (is_algebraic_program(b,var2,res2)){ + if (!is_constant_wrt(a,var2,contextptr)) + *logptr(contextptr) << "Warning constant*function with constant dependent of mute variable" << '\n'; + return symbolic(at_program,gen(makevecteur(var2,0,operator_times(a,res2,contextptr)),_SEQ__VECT)); + } + if (is_inf(a)){ + if (is_exactly_zero(normal(b,contextptr))) + return undef; + int s=fastsign(a,contextptr)*fastsign(b,contextptr); + if (s==1) + return plus_inf; + if (s) + return minus_inf; + return unsigned_inf; + } + if (is_inf(b)){ + if (is_exactly_zero(normal(a,contextptr))) + return undef; + int s=fastsign(a,contextptr)*fastsign(b,contextptr); + if (s==1) + return plus_inf; + if (s) + return minus_inf; + return unsigned_inf; + } + if (a.is_symb_of_sommet(at_inv) && a._SYMBptr->feuille==b) + return 1; + if (b.is_symb_of_sommet(at_inv) && b._SYMBptr->feuille==a) + return 1; + if (a.type==_INT_ && a.val==0 ) + return a; + if (a.type==_DOUBLE_ && a._DOUBLE_val==0 ) + return a; + if (a.type==_FLOAT_ && is_zero(a._FLOAT_val) ) + return a; + if (b.type==_INT_ && b.val==0) + return b; + if (b.type==_DOUBLE_ && b._DOUBLE_val==0 ) + return b; + if (b.type==_FLOAT_ && is_zero(b._FLOAT_val) ) + return b; + if ( a.is_approx()){ + gen b1; + if (has_evalf(b,b1,1,contextptr)&& (b.type!=b1.type || b!=b1)){ +#ifdef HAVE_LIBMPFR + if (a.type==_REAL){ + gen b2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(a._REALptr)) + b2=convert_interval(b,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + b2=accurate_evalf(b,mpfr_get_prec(a._REALptr->inf)); + if (b2.is_approx()) + return (*a._REALptr)*b2; + } + if (a.type==_CPLX && a._CPLXptr->type==_REAL){ + gen b2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(a._CPLXptr->_REALptr)) + b2=convert_interval(b,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + b2=accurate_evalf(b,mpfr_get_prec(a._CPLXptr->_REALptr->inf)); + if (b2.is_approx()) + return a*b2; + } +#endif + return a*b1; + } + } + if ( b.is_approx()){ + gen a1; + if (has_evalf(a,a1,1,contextptr) && (a.type!=a1.type || a!=a1)){ +#ifdef HAVE_LIBMPFR + if (b.type==_REAL){ + gen a2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(b._REALptr)) + a2=convert_interval(a,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + a2=accurate_evalf(a,mpfr_get_prec(b._REALptr->inf)); + if (a2.is_approx()) + return a2*b; + } + if (b.type==_CPLX && b._CPLXptr->type==_REAL){ + gen a2; +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (real_interval * ptr=dynamic_cast(b._CPLXptr->_REALptr)) + a2=convert_interval(a,mpfi_get_prec(ptr->infsup),contextptr); + else +#endif + a2=accurate_evalf(a,mpfr_get_prec(b._CPLXptr->_REALptr->inf)); + if (a2.is_approx()) + return a2*b; + } +#endif + return a1*b; + } + } + if (is_one(a) && ((a.type!=_MOD) || (b.type==_MOD) )) + return b; + if (is_one(b) && ((b.type!=_MOD) || (a.type==_MOD) )) + return a; + if ((a.type==_SYMB) && equalposcomp(plot_sommets,a._SYMBptr->sommet)){ + if (a._SYMBptr->sommet==at_curve) + return gensizeerr(gettext("Unable to multiply two graphic objects")); + gen tmp=remove_at_pnt(a); + if (tmp.type==_VECT && tmp.subtype==_VECTOR__VECT){ + if (b.type==_SYMB && equalposcomp(plot_sommets,b._SYMBptr->sommet)){ + gen tmpb=remove_at_pnt(b); + return dotvecteur(vector2vecteur(*tmp._VECTptr),vector2vecteur(*tmpb._VECTptr)); + } + return _vector(vector2vecteur(*tmp._VECTptr)*b,contextptr); + } + if ((b.type==_SYMB) && equalposcomp(plot_sommets,b._SYMBptr->sommet)){ + if (b._SYMBptr->sommet==at_curve) + return gensizeerr(gettext("Unable to multiply two graphic objects")); + gen tmpb=complex2vecteur(remove_at_pnt(b),contextptr); + tmp=complex2vecteur(tmp,contextptr); + if (tmpb._VECTptr->size()==tmp._VECTptr->size()) + return dotvecteur(*tmp._VECTptr,*tmpb._VECTptr,contextptr); + return gensizeerr(gettext("Unable to multiply two graphic objects")); + } + return symbolic_plot_makevecteur(a._SYMBptr->sommet,a._SYMBptr->feuille*b,false,contextptr); + } + if ((b.type==_SYMB) && equalposcomp(plot_sommets,b._SYMBptr->sommet)){ + gen tmp=remove_at_pnt(b); + if (tmp.type==_VECT && tmp.subtype==_VECTOR__VECT) + return _vector(a*vector2vecteur(*tmp._VECTptr),contextptr); + gen b_(b); + if (b_.is_symb_of_sommet(at_curve) && b_._SYMBptr->feuille.type==_VECT && b_._SYMBptr->feuille._VECTptr->size()==2 && b_._SYMBptr->feuille._VECTptr->front().type==_VECT){ + // adjust param and cartesian eq + vecteur v=*b_._SYMBptr->feuille._VECTptr->front()._VECTptr; + if (v.size()==7) + v[6] =v[6]*a; + if (v.size()>=6){ + gen ax,ay; + reim(inv(a,contextptr),ax,ay,contextptr); + v[5]=subst(v[5],makevecteur(x__IDNT_e,y__IDNT_e),makevecteur(ax*x__IDNT_e-ay*y__IDNT_e,ax*y__IDNT_e+ay*x__IDNT_e),false,contextptr); + b_=symbolic(at_curve,gen(makevecteur(gen(v,b_._SYMBptr->feuille._VECTptr->front().subtype),b_._SYMBptr->feuille._VECTptr->back()),b_._SYMBptr->feuille.subtype)); + } + } + return symbolic_plot_makevecteur(b_._SYMBptr->sommet,b_._SYMBptr->feuille*a,false,contextptr); + } + if (a.is_symb_of_sommet(at_neg)){ + if (b.is_symb_of_sommet(at_neg)) + return operator_times(a._SYMBptr->feuille,b._SYMBptr->feuille,contextptr); + return -operator_times(a._SYMBptr->feuille,b,contextptr); + } + if (b.is_symb_of_sommet(at_neg)) + return -operator_times(a,b._SYMBptr->feuille,contextptr); + if (a.type==_POLY && b.is_symb_of_sommet(at_inv) && b._SYMBptr->feuille.type==_POLY){ + polynome & A=*a._POLYptr; + polynome & B=*b._SYMBptr->feuille._POLYptr; + polynome Q ,R; + if (A.TDivRem(B,Q,R) && R.coord.empty()) + return Q; + } + if (b.type==_POLY && a.is_symb_of_sommet(at_inv) && a._SYMBptr->feuille.type==_POLY){ + polynome & A=*b._POLYptr; + polynome & B=*a._SYMBptr->feuille._POLYptr; + polynome Q ,R; + if (A.TDivRem(B,Q,R) && R.coord.empty()) + return Q; + } + if (a.type==_FRAC){ + if (b.is_symb_of_sommet(at_inv) && is_cinteger(b._SYMBptr->feuille)) + return (*a._FRACptr)*fraction(1,b._SYMBptr->feuille); + if ( (b.type!=_SYMB) && (b.type!=_IDNT) ) { + if (b.type==_EXT) + return fraction(a._FRACptr->num*b,a._FRACptr->den).normal(); + return (*a._FRACptr)*b; + } + return sym_mult(_FRAC2_SYMB(a),b,contextptr); + } + if (b.type==_FRAC){ + if (a.is_symb_of_sommet(at_inv) && is_cinteger(a._SYMBptr->feuille)) + return fraction(1,a._SYMBptr->feuille)*(*b._FRACptr); + if ( (a.type!=_SYMB) && (a.type!=_IDNT) ){ + if (a.type==_EXT) + return fraction(a*b._FRACptr->num,b._FRACptr->den).normal(); + return a*(*b._FRACptr); + } + return sym_mult(a,_FRAC2_SYMB(b),contextptr); + } + if (is_cinteger(a) && b.is_symb_of_sommet(at_inv) && is_cinteger(b._SYMBptr->feuille)) + return a/b._SYMBptr->feuille; + if (is_cinteger(b) && a.is_symb_of_sommet(at_inv) && is_cinteger(a._SYMBptr->feuille)) + return b/a._SYMBptr->feuille; + if (a.type<=_CPLX && b.is_symb_of_sommet(at_inv)&& b._SYMBptr->feuille.type<=_CPLX) + return fraction(a,b._SYMBptr->feuille).normal(); + if (b.type<=_CPLX && a.is_symb_of_sommet(at_inv)&& a._SYMBptr->feuille.type<=_CPLX) + return fraction(b,a._SYMBptr->feuille).normal(); + if ((a.type<=_REAL || a.type==_FLOAT_) && is_strictly_positive(-a,contextptr)) + return -sym_mult(-a,b,contextptr); + if ((b.type<=_REAL || b.type==_FLOAT_) && is_strictly_positive(-b,contextptr)) + return -sym_mult(a,-b,contextptr); + if (a.type==_EXT){ + if (a.is_constant() && (b.type==_POLY)) + return a*(*b._POLYptr); + else + return algebraic_EXTension(b*(*a._EXTptr),*(a._EXTptr+1)); + } + if (b.type==_EXT){ + if (b.is_constant() && (a.type==_POLY)) + return (*a._POLYptr)*b; + else + return algebraic_EXTension(a*(*b._EXTptr),*(b._EXTptr+1)); + } + if ( (a.type==_INT_) && (a.val<0) && (a.val!=1<<31)){ + if (b.is_symb_of_sommet(at_inv) && (b._SYMBptr->feuille.type<_POLY || b._SYMBptr->feuille.is_symb_of_sommet(at_neg))) + return sym_mult(-a,inv(-b._SYMBptr->feuille,contextptr),contextptr); + else + return -sym_mult(-a,b,contextptr); + } + if ( (b.type==_INT_) && (b.val<0) && (b.val!=1<<31)){ + if (a.is_symb_of_sommet(at_inv)) + return sym_mult(-b,inv(-a._SYMBptr->feuille,contextptr),contextptr); + else + return -sym_mult(-b,a,contextptr); + } + if (is_equal(a)){ + vecteur & va=*a._SYMBptr->feuille._VECTptr; + if (is_equal(b)){ + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,gen(makenewvecteur(va.front()*vb.front(),va.back()*vb.back()),_SEQ__VECT))); + } + else + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,gen(makenewvecteur(va.front()*b,va.back()*b),_SEQ__VECT))); + } + if (is_equal(b)){ + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(b._SYMBptr->sommet,gen(makenewvecteur(a*vb.front(),a*vb.back()),_SEQ__VECT))); + } + if ((a.type==_SYMB)&& (b.type==_SYMB)){ + if ((a._SYMBptr->sommet==at_prod) && (b._SYMBptr->sommet==at_prod)) + return new_ref_symbolic(symbolic(at_prod,gen(mergevecteur(*(a._SYMBptr->feuille._VECTptr),*(b._SYMBptr->feuille._VECTptr)),_SEQ__VECT))); + else { + if (a._SYMBptr->sommet==at_prod) + return new_ref_symbolic(symbolic(*a._SYMBptr,b)); + else { + if (b._SYMBptr->sommet==at_prod) + return new_ref_symbolic(symbolic(a,b._SYMBptr->sommet,b._SYMBptr->feuille)); + else + return new_ref_symbolic(symbolic(at_prod,gen(makenewvecteur(a,b),_SEQ__VECT))); + } + } + } + if (b.type==_SYMB){ + if (b._SYMBptr->sommet==at_prod) + return new_ref_symbolic(symbolic(a,b._SYMBptr->sommet,b._SYMBptr->feuille)); + else + return new_ref_symbolic(symbolic(at_prod,gen(makenewvecteur(a,b),_SEQ__VECT))); + } + if (a.type==_SYMB){ + if (a._SYMBptr->sommet==at_prod) + return new_ref_symbolic(symbolic(*a._SYMBptr,b)); + else + return new_ref_symbolic(symbolic(at_prod,gen(b.type==_INT_?makenewvecteur(b,a):makenewvecteur(a,b),_SEQ__VECT))); + } + if ((a.type==_IDNT) || (b.type==_IDNT)) + return new_ref_symbolic(symbolic(at_prod,gen(makenewvecteur(a,b),_SEQ__VECT))); + if (a.type==_MOD) + return a*makemod(b,*(a._MODptr+1)); + if (b.type==_MOD) + return b*makemod(a,*(b._MODptr+1)); + return new_ref_symbolic(symbolic(at_prod,gen(makenewvecteur(a,b),_SEQ__VECT))); + // settypeerr(gettext("sym_mult")); + } + + static vecteur inv__VECT(const vecteur & v,GIAC_CONTEXT){ + vecteur w; + if (is_squarematrix(v)) + w=minv(v,contextptr); + else { + vecteur::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + w.push_back(inv(*it,contextptr)); + } + return w; + } + + static vecteur invfirst(const vecteur & v){ + vecteur w(v); + if (!w.empty()) + w.front()=inv(w.front(),context0); + return w; + } + + static gen invdistrib(const gen & g,GIAC_CONTEXT){ + if (g.type!=_SYMB) + return inv(g,contextptr); + gen & f=g._SYMBptr->feuille; + if (g._SYMBptr->sommet==at_inv) + return f; + if (g._SYMBptr->sommet==at_pow) + return symbolic(at_pow,gen(makevecteur(f[0],-f[1]),_SEQ__VECT)); + if (g._SYMBptr->sommet==at_prod && f.type==_VECT){ + vecteur v = *f._VECTptr; + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + *it=invdistrib(*it,contextptr); + return symbolic(at_prod,gen(v,_SEQ__VECT)); + } + return inv(g,contextptr); + } + + gen inv_distrib(const gen & b,GIAC_CONTEXT){ + if (b.is_symb_of_sommet(at_prod)){ + gen f=b._SYMBptr->feuille; + return symbolic(at_prod,inv_distrib(f,contextptr)); + } + if (b.is_symb_of_sommet(at_pow)) + return pow(b._SYMBptr->feuille[0],-b._SYMBptr->feuille[1],contextptr); + if (b.is_symb_of_sommet(at_inv)) + return b._SYMBptr->feuille; + if (b.type==_VECT){ + vecteur v(*b._VECTptr); + for (unsigned i=0;iinv(); + case _DOUBLE_: + return 1/a._DOUBLE_val; + case _FLOAT_: + return finv(a._FLOAT_val); + case _CPLX: + if (is_exactly_zero(*a._CPLXptr)){ + if (is_one(abs(*(a._CPLXptr+1),contextptr))) + return -a; + } + if ( a._CPLXptr->type==_DOUBLE_ || a._CPLXptr->type==_FLOAT_ ||a._CPLXptr->type==_REAL || (a._CPLXptr+1)->type==_DOUBLE_ || (a._CPLXptr+1)->type==_FLOAT_ || (a._CPLXptr+1)->type==_REAL ){ + gen a2=no_context_evalf(a.squarenorm(contextptr)); + if (is_inf(a2)){ + gen theta=arg(a,contextptr); + theta=cos(theta,contextptr)-cst_i*sin(theta,contextptr); + a2=re(a*theta,contextptr); + return inv(a2,contextptr)*theta; + } + return gen(rdiv(no_context_evalf(a.re(contextptr)),a2,contextptr),rdiv(no_context_evalf(-a.im(contextptr)),a2,contextptr)); + } + return fraction(1,a); + case _IDNT: + if (a==undef) + return undef; + if (a==unsigned_inf) + return 0; + return new_ref_symbolic(symbolic(at_inv,a)); + case _SYMB: + if ((a==plus_inf) || (a==minus_inf)) + return 0; + { + vecteur v=alg_lvar(a); // change for limit(1/(1+sqrt(2)*cos(x))*sin(x-3*pi/4),x=3*pi/4); maybe we should only do evalf test and return undef + if (v.size()==1 && v.front().type==_VECT && v.front()._VECTptr->empty() && is_zero(evalf(a,1,contextptr)) && is_exactly_zero(recursive_normal(a,contextptr))) + return unsigned_inf; + } + if (a.is_symb_of_sommet(at_unit)){ + if (equalposcomp(lidnt(a),cst_pi)!=0) + return inv(evalf(a,1,contextptr),contextptr); + return new_ref_symbolic(symbolic(at_unit,makenewvecteur(inv(a._SYMBptr->feuille._VECTptr->front(),contextptr),inv_distrib(a._SYMBptr->feuille._VECTptr->back(),contextptr)))); + } + if (equalposcomp(plot_sommets,a._SYMBptr->sommet)) + return symbolic_plot_makevecteur( a._SYMBptr->sommet,inv(a._SYMBptr->feuille,contextptr),false,contextptr); + if (a._SYMBptr->sommet==at_inv) + return a._SYMBptr->feuille; + if (a._SYMBptr->sommet==at_NTHROOT && a._SYMBptr->feuille.type==_VECT && a._SYMBptr->feuille._VECTptr->size()==2){ + return symbolic(at_NTHROOT,makesequence(-a._SYMBptr->feuille._VECTptr->front(),a._SYMBptr->feuille._VECTptr->back())); + } + if (a._SYMBptr->sommet==at_neg) + return -inv(a._SYMBptr->feuille,contextptr); + else { + if (a._SYMBptr->sommet==at_prod) + return new_ref_symbolic(symbolic(at_prod,gen(inv__VECT(*(a._SYMBptr->feuille._VECTptr),contextptr),a._SYMBptr->feuille.subtype))); + else + return new_ref_symbolic(symbolic(at_inv,a)); + } + case _VECT: + if (a.subtype==_SEQ__VECT && a._VECTptr->size()==2 && a._VECTptr->back().subtype==_INT_SOLVER && is_squarematrix(a._VECTptr->front())){ + matrice res; + gen a0=a._VECTptr->front(); + if (minv(*a0._VECTptr,res,true,a._VECTptr->back().val,contextptr)) + return res; + } + if (a.subtype==_PNT__VECT) + return gen(invfirst(*a._VECTptr),a.subtype); + if (a.subtype==_POLY1__VECT) + return fraction(gen(vecteur(1,plus_one),_POLY1__VECT),a); + if (a.subtype==_MATRIX__VECT && !is_squarematrix(a)) + return gensizeerr(gettext("Inv of non-square matrix")); + return gen(inv__VECT(*a._VECTptr,contextptr),a.subtype); + case _EXT: + return inv_EXT(a); + case _SPOL1: + return spdiv(gen2spol1(1),*a._SPOL1ptr,contextptr); + case _USER: + return a._USERptr->inv(); + case _MOD: + return modinv(a); + case _FRAC: + if (a._FRACptr->num.type==_CPLX) + return fraction(a._FRACptr->den,a._FRACptr->num).normal(); + if (is_positive(a._FRACptr->num,contextptr)) + return fraction(a._FRACptr->den,a._FRACptr->num); + else + return fraction(-a._FRACptr->den,-a._FRACptr->num); + default: + if (is_undef(a)) + return a; + return new_ref_symbolic(symbolic(at_inv,a)); + // settypeerr(gettext("Inv")); + } + + } + + /* + gen inv(const gen & a,GIAC_CONTEXT){ + return inv(a,context0); + } + */ + + gen gen::inverse(GIAC_CONTEXT) const { return inv(*this,contextptr); } + + static void inpow(const gen & base,unsigned long int exponent,gen & res){ +#if 0 + res=1; + gen basepow=base; + while (exponent){ + if (exponent%2) + res = res*basepow; + if ( (exponent /=2) ) + basepow=basepow*basepow; + } +#else + if (exponent==1) + res=base; + else { + inpow(base,exponent/2,res); + res=res*res; + if (exponent %2) + res=res*base; + } +#endif + } + + gen pow(const gen & base, unsigned long int exponent){ + // if (!( (++control_c_counter) & control_c_counter_mask)) +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + ref_mpz_t * e; + gen res; + switch (base.type ) { + case _INT_: + if (base.val<0 && (exponent % 2)) + return(-pow(-base.val,exponent)); + else + return(pow(absint(base.val),exponent)); + case _DOUBLE_: +#ifdef _SOFTMATH_H + return std::giac_gnuwince_pow(base._DOUBLE_val,double(exponent)); +#else + return std::pow(base._DOUBLE_val,double(exponent)); +#endif + case _FLOAT_: + return fpow(base._FLOAT_val,giac_float(double(exponent))); + case _ZINT: + e=new ref_mpz_t; + mpz_pow_ui(e->z,*base._ZINTptr,exponent); + return e; + case _VECT: + if (base.subtype==_POLY1__VECT && base._VECTptr->size()<5){ + vecteur res; + if (miller_pow(*base._VECTptr,exponent,res)) + return gen(res,_POLY1__VECT); + } + /* no break, _VECT handled by next case */ + case _CPLX: case _REAL: case _EXT: case _MOD: case _USER: + // gauss integer power + if (!exponent){ + if (ckmatrix(base)) + return midn(int(base._VECTptr->size())); + if (base.type==_USER) + return base*inv(base,context0); + return base.type==_MOD?makemod(1,*(base._MODptr+1)):1; + } + inpow(base,exponent,res); + return(res); + case _IDNT: + if (is_undef(base)) + return base; + if (!exponent) + return 1; + if (exponent==1) + return base; + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base,(longlong)exponent),_SEQ__VECT))); + case _SYMB: + if (!exponent) + return 1; + if (exponent==1) + return base; + if (base._SYMBptr->sommet==at_pow){ + res= (*((base._SYMBptr->feuille)._VECTptr))[1]; + return pow( (base._SYMBptr->feuille)._VECTptr->front(),gen((longlong) (exponent)) * res,context0) ; + } + if ((exponent % 2==0) && base._SYMBptr->sommet==at_abs) + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base._SYMBptr->feuille,(longlong) exponent),_SEQ__VECT))); + return new_ref_symbolic(symbolic(at_pow,gen(makenewvecteur(base,(longlong) exponent),_SEQ__VECT))); + case _POLY: + return pow(*base._POLYptr,(int) exponent); + case _FRAC: + return pow(*base._FRACptr,(int) exponent); + case _MAP:{ + gen res; + inpow(base,exponent,res); + return res; + } + default: + if (is_undef(base)) + return base; + return gentypeerr(gettext("Pow")) ; + } + return 0; + } + + gen pow(const gen & base, int exponent){ + if (base==zero){ + if (exponent>0) + return base; + if (!exponent) + return undef; + if (exponent %2) + return unsigned_inf; + return plus_inf; + } + if (exponent<0){ + if (-exponent<0) + return gensizeerr("pow: int exponent underflow"); + return inv(pow(base,-exponent),context0); + } + if (is_one(base)) + return base; + if (is_minus_one(base)) + return exponent%2?base:base*base; + unsigned long int expo=exponent; + gen b; + if (base.type<=_ZINT && has_evalf(base,b,0,context0) && !is_inf(b) && + is_greater(abs(exponent*log(abs(b,context0),context0),context0),powlog2float,context0)){ + return gensizeerr("Exponent overflow"); + *logptr(context0) << "Exponent overflow" << '\n'; + if (is_strictly_greater(1,abs(b,context0),context0)) + return 0; + return (exponent%2==0 || is_greater(b,0,context0))?plus_inf:minus_inf; // overflow + // return pow(b,expo); + } + return(pow(base,expo)); + } + + gen pow(unsigned long int base, unsigned long int exponent){ + ref_mpz_t *e=new ref_mpz_t; +#if defined(EMCC) || defined(EMCC2) + mpz_set_si(e->z,base); + mpz_pow_ui(e->z,e->z,exponent); + return e; + if (base==int(base)){ // too slow! + mpz_set_si(e->z,1); + for (unsigned long int i=0;iz,e->z,int(base)); + } + return e; + } +#endif + mpz_set_si(e->z,base); + mpz_ui_pow_ui(e->z,base,exponent); + return e; + } + + static void _ZINTdiv (const gen & a,const gen & b,ref_mpz_t * & quo){ + // at least one is not an int, uncoerce remaining int + ref_mpz_t *aptr,*bptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr=new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + if (b.type!=_INT_) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &b) >> 16); +#else + bptr=b.__ZINTptr; +#endif + else { + bptr=new ref_mpz_t; + mpz_set_si(bptr->z,b.val); + } + quo=new ref_mpz_t; + mpz_tdiv_q(quo->z,aptr->z,bptr->z); + if (a.type==_INT_){ + delete aptr; + } + if (b.type==_INT_){ + delete bptr; + } + } + + // a and b must be integers or Gaussian integers + static gen iquobest(const gen & a,const gen & b){ + if (is_strictly_positive(-a,0)) + return -iquobest(-a,b); + return iquo(a+iquo(b,2),b); + } + + // a and b must be integers or Gaussian integers + static gen iquocmplx(const gen & a,const gen & b){ + gen b2=b.squarenorm(0); + gen ab=a*b.conj(0); + gen res(iquobest(re(ab,context0),b2),iquobest(im(ab,context0),b2)); // ok + return res; + } + + static polynome iquopoly(const polynome & a,const gen & b){ + polynome res(a); + vector< monomial >::iterator it=res.coord.begin(),itend=res.coord.end(); + for (;it!=itend;++it) + it->value=iquo(it->value,b); + return res; + } + + // integer quotient, use rdiv for symbolic division + gen iquo(const gen & a,const gen & b){ + if ((b.type==_INT_)){ + switch (b.val){ + case 1: + return a; + case -1: + return -a; + case 0: + return gensizeerr(gettext("Division by 0")); + } + } + if (a.type==_POLY) // may be called by resulant interpolation + return iquopoly(*a._POLYptr,b); + ref_mpz_t * quo; + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: + return(a.val/b.val); + case _ZINT__ZINT: case _INT___ZINT: case _ZINT__INT_: + _ZINTdiv(a,b,quo); + return quo; + case _CPLX__INT_: case _CPLX__ZINT: + return gen(iquo(*a._CPLXptr,b),iquo(*(a._CPLXptr+1),b)); + case _INT___CPLX: case _ZINT__CPLX: + return iquocmplx(a,b); + case _CPLX__CPLX: + return adjust_complex_display(iquocmplx(a,b),a,b); + case _EXT__INT_: case _EXT__ZINT: + return rdiv(a,b); + default: + return gentypeerr(gettext("iquo")); + } + return 0; + } + + // a and b must be integer or Gaussian integers + static gen rdivsimp(const gen & a,const gen & b){ + if (is_positive(-b,context0)) // ok + return rdivsimp(-a,-b); + gen c(gcd(a,b,context0)); + if (c.type==_CPLX) + c=gcd(c.re(context0),c.im(context0),context0); // ok + return fraction(iquo(a,c),iquo(b,c)); + } + + static gen divpoly(const polynome & p, const gen & e){ + if (p.coord.empty()) + return zero; + gen coefft; int pt=coefftype(p,coefft); + if (pt==_MOD || pt==_USER){ + polynome res(p); + mulpoly(res,coefft/(e*coefft),res); + return res; + } + gen d=gcd(Tcontent(p),e,context0); + if (d.type==_EXT) + d=_gcd(*d._EXTptr,context0); + if (is_one(d)){ + if (e==cst_i || e==minus_one || e==-cst_i) + return p/e; + return fraction(p,e); + } + gen den(rdiv(e,d,context0)); + gen iden(inv(den,context0)); + if ( (iden.type!=_SYMB) && (iden.type!=_FRAC)) + return (p/d)*iden; + else + return fraction(p/d,den); + } + + static gen divpoly(const gen & e,const polynome & p){ + if (is_exactly_zero(e)) + return e; + if (Tis_constant(p)&& p.coord.front().value.type<_POLY) + return rdiv(e,p.coord.front().value,context0); + gen d=gcd(Tcontent(p),e,context0); + gen tmp=polynome(rdiv(e,d,context0),p.dim); + return fraction(tmp,p/d); + } + + static gen divpolypoly(const gen & a,const gen &b){ + polynome ap(*a._POLYptr),bp(*b._POLYptr); + polynome q(ap.dim),r(ap.dim); + if (divrem1(ap,bp,q,r) && r.coord.empty()) + return q; + return normal(fraction(a,b),context0); // ok + } + + bool is_exactly_zero_normal(const gen &b,GIAC_CONTEXT){ + if (b.type!=_SYMB) + return is_exactly_zero(b); + const unary_function_ptr & u=b._SYMBptr->sommet; + if (u==at_neg) return is_exactly_zero_normal(b._SYMBptr->feuille,contextptr); + if (u==at_prod){ + gen f=b._SYMBptr->feuille; + if (f.type==_VECT){ + vecteur &v=*f._VECTptr; + for (int i=0;itype==_DOUBLE_ || a._CPLXptr->type==_FLOAT_) || ((a._CPLXptr+1)->type==_DOUBLE_ || (a._CPLXptr+1)->type==_FLOAT_) ) + return rdiv(no_context_evalf(a),no_context_evalf(b),contextptr); + if (a._CPLXptr->type==_REAL){ + if ((a._CPLXptr+1)->type==_REAL) + return rdiv(*a._CPLXptr,b,contextptr)+cst_i*rdiv(*(a._CPLXptr+1),b,contextptr); +#ifdef HAVE_LIBMPFR + return rdiv(*a._CPLXptr,b,contextptr)+cst_i*rdiv(real_object(*(a._CPLXptr+1),mpfr_get_prec(a._CPLXptr->_REALptr->inf)),b,contextptr); +#else + return rdiv(*a._CPLXptr,b,contextptr)+cst_i*rdiv(real_object(*(a._CPLXptr+1)),b,contextptr); +#endif + } + if ((a._CPLXptr+1)->type==_REAL){ +#ifdef HAVE_LIBMPFR + return rdiv(real_object(*a._CPLXptr,mpfr_get_prec((a._CPLXptr+1)->_REALptr->inf)),b,contextptr)+cst_i*rdiv(*(a._CPLXptr+1),b,contextptr); +#else + return rdiv(real_object(*a._CPLXptr),b)+cst_i*rdiv(*(a._CPLXptr+1),b,contextptr); +#endif + } + if (is_exactly_zero(b)) + return unsigned_inf; + if (is_exactly_zero(a%b)) + return iquo(a,b); + else + return rdivsimp(a,b); + case _CPLX__CPLX: + if (a.subtype==3 || b.subtype==3) + return a*inv(b,contextptr); + return adjust_complex_display(rdiv(a*conj(b,contextptr),b.squarenorm(contextptr),contextptr),a,b); + case _DOUBLE___CPLX: case _FLOAT___CPLX: case _INT___CPLX: case _ZINT__CPLX: case _REAL__CPLX: + if (is_one(a)) + return inv(b,contextptr); + return rdiv(a*conj(b,contextptr),b.squarenorm(contextptr),contextptr); + case _DOUBLE___DOUBLE_: + return a._DOUBLE_val/b._DOUBLE_val; + case _DOUBLE___INT_: + return a._DOUBLE_val/b.val; + case _INT___DOUBLE_: + return a.val/b._DOUBLE_val; + case _FLOAT___FLOAT_: + return a._FLOAT_val/b._FLOAT_val; + case _FLOAT___INT_: + return a._FLOAT_val/giac_float(b.val); + case _INT___FLOAT_: + return giac_float(a.val)/b._FLOAT_val; +#ifdef BCD + case _FLOAT___ZINT: + return a._FLOAT_val/giac_float(b._ZINTptr); + case _ZINT__FLOAT_: + return giac_float(a._ZINTptr)/b._FLOAT_val; +#endif + case _FLOAT___DOUBLE_: + return a._FLOAT_val/giac_float(b._DOUBLE_val); + case _DOUBLE___FLOAT_: + return giac_float(a._DOUBLE_val)/b._FLOAT_val; + case _ZINT__DOUBLE_: + return mpz_get_d(*a._ZINTptr)/b._DOUBLE_val; + case _CPLX__DOUBLE_: case _CPLX__REAL: + return gen(rdiv(*a._CPLXptr,b,contextptr),rdiv(*(a._CPLXptr+1),b,contextptr)); + case _DOUBLE___ZINT: + return a._DOUBLE_val/mpz_get_d(*b._ZINTptr); + // _CPLX__DOUBLE_, _DOUBLE___CPLX, _CPLX__CPLX, _ZINT__CPLX, _INT___CPLX + case _VECT__INT_: case _VECT__ZINT: case _VECT__DOUBLE_: case _VECT__FLOAT_: case _VECT__CPLX: case _VECT__FRAC: + case _VECT__SYMB: case _VECT__IDNT: case _VECT__POLY: case _VECT__EXT: + if (a.subtype==_VECTOR__VECT) + return a*inv(b,contextptr); + return gen(divvecteur(*a._VECTptr,b),a.subtype); + case _MAP__INT_: case _MAP__ZINT: case _MAP__DOUBLE_: case _MAP__FLOAT_: case _MAP__CPLX: + case _MAP__SYMB: case _MAP__IDNT: case _MAP__POLY: case _MAP__EXT: { + gen_map m; + gen g(m); + *g._MAPptr=*a._MAPptr; + sparse_div(*g._MAPptr,b); + return g; + } + case _VECT__VECT: + if (a.subtype==_POLY1__VECT || b.subtype==_POLY1__VECT) + return fraction(a,b).normal(); + if (is_squarematrix(b)){ + if (abs_calc_mode(contextptr)==38){ + *logptr(contextptr) << gettext("Warning: A/B with B a square matrix is a misleading notation interpreted as inv(B)*A") << '\n'; + return inv(b,contextptr)*a; + } + *logptr(contextptr) << gettext("Warning, pointwise division of a by b. For matrix division, please use inv(b)*a or a*inv(b)") << '\n'; + } + if (b._VECTptr->size()==1) + return rdiv(a,b._VECTptr->front(),contextptr); + return apply(a,b,contextptr,rdiv); + case _POLY__POLY: + return divpolypoly(a,b); + case _FRAC__FRAC: + if (a._FRACptr->num.type==_CPLX || a._FRACptr->den.type==_CPLX || + b._FRACptr->num.type==_CPLX || b._FRACptr->den.type==_CPLX){ + gen d=gcd(a._FRACptr->den,b._FRACptr->den,contextptr); + return (a._FRACptr->num*(b._FRACptr->den/d))/((a._FRACptr->den/d)*b._FRACptr->num); + } + return (*a._FRACptr)/(*b._FRACptr); + case _SPOL1__SPOL1: + return spdiv(*a._SPOL1ptr,*b._SPOL1ptr,contextptr); + case _POLY__DOUBLE_: case _POLY__FLOAT_: case _POLY__REAL: + return (*a._POLYptr)/b; + case _POLY__INT_: + if (b.val==1) return a; + case _POLY__ZINT: case _POLY__CPLX: + return divpoly(*a._POLYptr,b); + case _INT___POLY: case _ZINT__POLY: case _CPLX__POLY: + return divpoly(a,*b._POLYptr); + case _INT___FRAC: case _ZINT__FRAC: + if (is_positive(-b._FRACptr->num,contextptr)){ + // if (is_one(a)) return fraction(-b._FRACptr->den,-b._FRACptr->num); + return (-b._FRACptr->den*a)/(-b._FRACptr->num); + } + // if (is_one(a)) return fraction(b._FRACptr->den,b._FRACptr->num); + return (b._FRACptr->den*a)/b._FRACptr->num; + case _INT___VECT: case _ZINT__VECT: case _CPLX__VECT: case _DOUBLE___VECT: case _FLOAT___VECT: case _SYMB__VECT: + if (b.subtype==_LIST__VECT) + return apply2nd(a,b,contextptr,rdiv); + if (ckmatrix(b)) + return a*inv(b,contextptr); + if (calc_mode(contextptr)==1 && b.subtype!=_POLY1__VECT) + return apply2nd(a,b,contextptr,rdiv); + return fraction(a,b); + default: +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + return gensizeerr(gettext("Stopped by user interruption.")); + } + if (is_undef(a)) + return a; + if (is_undef(b)) + return b; + if (a.type==_STRNG || b.type==_STRNG) + return gensizeerr("string /"); + { + gen var1,var2,res1,res2; + if (is_algebraic_program(a,var1,res1)){ + if (is_algebraic_program(b,var2,res2)){ + if (var1!=var2 && is_constant_wrt(res2,var1,contextptr)){ + res2=subst(res2,var2,var1,false,contextptr); + var2=var1; + } + if (var1==var2) + return symbolic(at_program,gen(makevecteur(var1,0,rdiv(res1,res2,contextptr)),_SEQ__VECT)); + } + if (!is_constant_wrt(b,var1,contextptr)) + *logptr(contextptr) << "Warning function/constant with constant dependent of mute variable" << '\n'; + return symbolic(at_program,gen(makevecteur(var1,0,rdiv(res1,b,contextptr)),_SEQ__VECT)); + } + if (is_algebraic_program(b,var2,res2)){ + if (!is_constant_wrt(a,var2,contextptr)) + *logptr(contextptr) << "Warning constant/function with constant dependent of mute variable" << '\n'; + return symbolic(at_program,gen(makevecteur(var2,0,rdiv(a,res2,contextptr)),_SEQ__VECT)); + } + } + if (a.type==_FLOAT_) + return rdiv(evalf_double(a,1,contextptr),b,contextptr); + if (b.type==_FLOAT_) + return rdiv(a,evalf_double(b,1,contextptr),contextptr); + if (a.is_symb_of_sommet(at_unit) || b.is_symb_of_sommet(at_unit)) + return operator_times(a,inv(b,contextptr),contextptr); + if (is_one(b)) + return chkmod(a,b); + if (is_minus_one(b)) + return chkmod(-a,b); + if (is_exactly_zero(a)){ + if (!is_exactly_zero_normal(b,contextptr)) + return a; + else + return undef; + } + if (is_exactly_zero(b)) + return unsigned_inf; + if (is_inf(a)){ + if (is_inf(b)) + return undef; + if (is_zero(b)) + return unsigned_inf; + return a*b; + } + if (is_inf(b)){ + if (is_inf(a)) + return undef; + else + return zero; + } + if (a==b && a.type!=_REAL && b.type!=_REAL) + return chkmod(plus_one,a); + if (a.is_approx()){ + gen b1; + if (has_evalf(b,b1,1,contextptr) && (b.type!=b1.type || b!=b1)){ +#ifdef HAVE_LIBMPFR + if (a.type==_REAL){ + gen b2=accurate_evalf(b,mpfr_get_prec(a._REALptr->inf)); + if (b2.is_approx()) + return rdiv(a,b2,contextptr); + } + if (a.type==_CPLX && a._CPLXptr->type==_REAL){ + gen b2=accurate_evalf(b,mpfr_get_prec(a._CPLXptr->_REALptr->inf)); + if (b2.is_approx()) + return rdiv(a,b2,contextptr); + } +#endif + return rdiv(a,b1,contextptr); + } + } + if (b.is_approx()){ + gen a1; + if (has_evalf(a,a1,1,contextptr) && (a.type!=a1.type || a!=a1)){ +#ifdef HAVE_LIBMPFR + if (b.type==_REAL){ + gen a2=accurate_evalf(a,mpfr_get_prec(b._REALptr->inf)); + if (a2.is_approx()) + return rdiv(a2,b,contextptr); + } + if (b.type==_CPLX && b._CPLXptr->type==_REAL){ + gen a2=accurate_evalf(a,mpfr_get_prec(b._CPLXptr->_REALptr->inf)); + if (a2.is_approx()) + return rdiv(a2,b,contextptr); + } +#endif + return rdiv(a1,b,contextptr); + } + } + if (a.type==_REAL) + return (*a._REALptr)*inv(b,contextptr); + if (b.type==_REAL) + return a*b._REALptr->inv(); + if (a.type==_SPOL1) + return spdiv(*a._SPOL1ptr,gen2spol1(b),contextptr); + if (b.type==_SPOL1) + return spdiv(gen2spol1(a),*b._SPOL1ptr,contextptr); + if (a.type==_USER && b.type!=_USER) + return (*a._USERptr)/b; + if (a.type==_USER || b.type==_USER) + return a*inv(b,contextptr); + if (a.type==_FRAC){ + if ( (b.type!=_SYMB) && (b.type!=_IDNT) ) + return (*a._FRACptr)/b; + return rdiv(_FRAC2_SYMB(a),b,contextptr); + } + if (b.type==_FRAC){ + if ( a.type!=_SYMB && a.type!=_IDNT && !(a.type==_VECT && a.subtype==_POLY1__VECT) ) // POLY1__VECT check added feb 2017 for poly hermite normal form + return a/(*b._FRACptr); + //return rdiv(a,_FRAC2_SYMB(b),contextptr); + // return symbolic(at_prod,makesequence(a,b._FRACptr->den,symbolic(at_inv,b._FRACptr->num))); + return (b._FRACptr->den*a)/b._FRACptr->num; + } + if (is_equal(a)){ + vecteur & va=*a._SYMBptr->feuille._VECTptr; + if (is_equal(b)){ + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,makesequence(rdiv(va.front(),vb.front(),contextptr),rdiv(va.back(),vb.back(),contextptr)))); + } + else + return new_ref_symbolic(symbolic(a._SYMBptr->sommet,makesequence(rdiv(va.front(),b,contextptr),rdiv(va.back(),b,contextptr)))); + } + if (is_equal(b)){ + vecteur & vb=*b._SYMBptr->feuille._VECTptr; + return new_ref_symbolic(symbolic(b._SYMBptr->sommet,makesequence(rdiv(a,vb.front(),contextptr),rdiv(a,vb.back(),contextptr)))); + } + /* commented since * is not always commutative + if (a.is_symb_of_sommet(at_prod) && a._SYMBptr->feuille.type==_VECT){ + int i=equalposcomp(*a._SYMBptr->feuille._VECTptr,b); + if (i){ + vecteur v(*a._SYMBptr->feuille._VECTptr); + v.erase(v.begin()+i-1); + if (v.size()==1) + return v.front(); + else + return new_ref_symbolic(symbolic(at_prod,v)); + } + } + */ + if (b.is_symb_of_sommet(at_neg)) + return -rdiv(a,b._SYMBptr->feuille,contextptr); + if ((b.type<=_REAL || b.type==_FLOAT_) && is_strictly_positive(-b,context0)) + return -rdiv(a,-b,contextptr); + if ( (a.type==_SYMB) || (a.type==_IDNT) || (a.type==_FUNC) || (b.type==_SYMB) || (b.type==_IDNT) || (b.type==_FUNC) ){ + if (is_one(a)) return symb_inv(b); + if (is_minus_one(a)) return -symb_inv(b); + if (a.is_symb_of_sommet(at_prod) && a._SYMBptr->feuille.type==_VECT){ + ref_vecteur * vptr = new_ref_vecteur(0); + vptr->v.reserve(a._SYMBptr->feuille._VECTptr->size()+1); + vptr->v=*a._SYMBptr->feuille._VECTptr; + vptr->v.push_back(symb_inv(b)); + return symbolic(at_prod,gen(vptr,_SEQ__VECT)); + } + return operator_times(a,symb_inv(b),contextptr); + } + if (a.type==_STRNG || b.type==_STRNG) + return gentypeerr(gettext("rdiv")); + return fraction(a,b).normal(); + } + } + + /* Tests */ + // 0 if unknown, 1 if >0, -1 if <0 + // no test for symbolics if context_ptr=0 + int fastsign(const gen & a,GIAC_CONTEXT){ + if (is_zero(a,contextptr) || is_undef(a)) + return 0; + if (is_inf(a)){ + if (a==plus_inf) + return 1; + if (a==minus_inf) + return -1; + return 0; + } + switch (a.type) { + case _INT_: + if (a.val>0) + return 1; + else + return -1; + case _ZINT: + return signint(mpz_cmp_si(*a._ZINTptr,0)); + case _FRAC: + return fastsign(a._FRACptr->num,contextptr)*fastsign(a._FRACptr->den,contextptr); + case _CPLX: + return 0; + case _DOUBLE_: + if (a._DOUBLE_val>0) + return 1; + else + return -1; + case _FLOAT_: + return fsign(a._FLOAT_val); + case _REAL: + if (a._REALptr->maybe_zero()) + return 0; + return a._REALptr->is_positive(); // this is the sign + case _SYMB: + if (a._SYMBptr->sommet==at_neg) + return -fastsign(a._SYMBptr->feuille,contextptr); + if (a._SYMBptr->sommet==at_inv) + return fastsign(a._SYMBptr->feuille,contextptr); + if (a._SYMBptr->sommet==at_abs || (a._SYMBptr->sommet==at_exp && is_real(a._SYMBptr->feuille,contextptr))) + return 1; + if (a._SYMBptr->sommet==at_unit) + return fastsign(a._SYMBptr->feuille[0],contextptr); + } + if (a.type==_SYMB){ + bool aplus=a.is_symb_of_sommet(at_plus); + if (aplus || a.is_symb_of_sommet(at_prod)){ + gen f=a._SYMBptr->feuille; + if (f.type==_VECT){ + vecteur & v=*f._VECTptr; + int i=0,fs=v.size(),curs=0; + for (;ifeuille; + if (f.type==_VECT && f._VECTptr->size()==2){ + gen & ex = f._VECTptr->back(); + if (ex.type==_INT_){ + if (ex.val%2==0) + return 1; + return fastsign(f._VECTptr->front(),contextptr); + } + if (ex.type==_FRAC && ex._FRACptr->den.type==_INT_ && ex._FRACptr->den.val % 2 ==0 ) + return 1; + } + } + } + if (is_inf(a)){ + if (a==plus_inf) + return 1; + if (a==minus_inf) + return -1; + return 0; + } + if (a.type==_IDNT){ + vecteur v; + if (find_range(a,v,contextptr) && v.size()==1 && v.front().type==_VECT && v.front()._VECTptr->size()==2){ + if (is_positive(v.front()._VECTptr->front(),contextptr)) + return 1; + if (is_positive(-v.front()._VECTptr->back(),contextptr)) + return -1; + } + } + gen approx; + if (has_evalf(a,approx,1,contextptr) && (a.type!=approx.type ||a!=approx)) + return fastsign(approx,contextptr); + // FIXME GIAC_CONTEXT?? + /* + if (contextptr){ + gen test=superieur_strict(a,0,contextptr); + if (test.type==_INT_){ + if (test.val) + return test.val; + test=inferieur_strict(a,0,contextptr); + if (test.type==_INT_) + return -test.val; + } + } + */ + return 0; + } + + bool is_greater(const gen & a,const gen &b,GIAC_CONTEXT){ + gen test=superieur_egal(a,b,contextptr); + if ((test.type==_INT_) && (test.val==1)) + return true; + else + return false; + } + + bool is_strictly_greater(const gen & a,const gen &b,GIAC_CONTEXT){ + gen test=superieur_strict(a,b,contextptr); + if ((test.type==_INT_) && (test.val==1)) + return true; + else + return false; + } + + bool is_positive(const gen & a,GIAC_CONTEXT){ + switch (a.type){ + case _INT_: + return a.val>=0; + case _CPLX: + return is_zero(*(a._CPLXptr+1)) && is_positive(*a._CPLXptr,contextptr); + case _REAL: + return (a._REALptr->is_positive()>0) || a._REALptr->is_zero(); + case _ZINT: + if (mpz_sgn(*a._ZINTptr)==-1) + return false; + else + return true; + case _POLY: + return is_positive(a._POLYptr->coord.front()); + case _FRAC: + return (is_positive(a._FRACptr->num,contextptr) && is_positive(a._FRACptr->den,contextptr)) || (is_positive(-a._FRACptr->num,contextptr) && is_positive(-a._FRACptr->den,contextptr)); + case _EXT: + return false; + case _SYMB: + if (a==plus_inf) + return true; + if (a==minus_inf) + return false; + if (a._SYMBptr->sommet==at_exp) + return true; + if (a._SYMBptr->sommet==at_ln) + return is_positive(a._SYMBptr->feuille-1,contextptr); + if (a._SYMBptr->sommet==at_program) + return true; + if (a._SYMBptr->sommet==at_unit) + return is_positive(a._SYMBptr->feuille[0],contextptr); + return is_greater(a,0,contextptr); + case _FUNC: + return true; + default: + return is_greater(a,0,contextptr); + } + } + + bool is_strictly_positive(const gen & a,GIAC_CONTEXT){ + if (a.type==_REAL){ + if (a._REALptr->maybe_zero()) + return false; + } else { + if (is_exactly_zero(a)) + return false; + } + return is_positive(a,contextptr); + } + + bool ck_is_greater(const gen & a,const gen &b,GIAC_CONTEXT){ + if (a==b) + return true; + gen test=superieur_strict(a,b,contextptr); + if (test.type!=_INT_) + cksignerr(test); + if (test.val==1) + return true; + else + return false; + } + + bool ck_is_strictly_greater(const gen & a,const gen &b,GIAC_CONTEXT){ + gen test=superieur_strict(a,b,contextptr); + if (test.type!=_INT_) + cksignerr(test); + if (test.val==1) + return true; + else + return false; + } + + bool ck_is_positive(const gen & a,GIAC_CONTEXT){ + switch (a.type){ + case _INT_: + return a.val>=0; + case _ZINT: + if (mpz_sgn(*a._ZINTptr)==-1) + return false; + else + return true; + case _SYMB: + if (a==plus_inf) + return true; + if (a==minus_inf) + return false; + if (a._SYMBptr->sommet==at_exp) + return true; + if (a._SYMBptr->sommet==at_ln) + return ck_is_positive(a._SYMBptr->feuille-1,contextptr); + return ck_is_greater(a,0,contextptr); + default: + return ck_is_greater(a,0,contextptr); + } + } + + bool ck_is_strictly_positive(const gen & a,GIAC_CONTEXT){ + if (is_zero(a,contextptr)) + return false; + return ck_is_positive(a,contextptr); + } + + gen min(const gen & a, const gen & b,GIAC_CONTEXT){ + if (a.type==_DOUBLE_ && b.type==_DOUBLE_) + return a._DOUBLE_valfeuille; + if (f.type==_VECT && f._VECTptr->size()==2){ + return symbolic(ae?at_superieur_strict:at_superieur_egal,makesequence(f._VECTptr->back(),f._VECTptr->front())); + } + } + if (a.is_symb_of_sommet(at_and)){ + gen f=_not(a._SYMBptr->feuille,context0); + return symbolic(at_ou,f); + } + if (a.is_symb_of_sommet(at_ou)){ + gen f=_not(a._SYMBptr->feuille,context0); + return symbolic(at_and,f); + } + return symb_not(a); + } + } + + struct islesscomplexthanf_compare { + islesscomplexthanf_compare() {} + bool operator ()(const gen & a,const gen &b){ return islesscomplexthanf(a,b); } + }; + + void islesscomplexthanf_sort(iterateur it,iterateur itend){ + islesscomplexthanf_compare m; + sort(it,itend,m); + } + + struct f_compare { + bool (*f)(const gen &a,const gen &b); + f_compare():f(islesscomplexthanf){} + f_compare(bool (*f_)(const gen &a,const gen &b)):f(f_){} + inline bool operator () (const gen & a,const gen &b){ return f(a,b); } + }; + + void my_qsort(iterateur it,iterateur itend,bool (*f)(const gen &a,const gen &b)){ + if (itend-it<=1) + return; + int n=(itend-it); + iterateur itmid=it+n/2; + my_qsort(it,itmid,f); + my_qsort(itmid,itend,f); + iterateur ita=it,itb=itmid; + vecteur res; res.reserve(n); + for (;ita!=itmid && itb!=itend;){ + if (f(*ita,*itb)){ + res.push_back(*ita); + ++ita; + } + else { + res.push_back(*itb); + ++itb; + } + } + for (;ita!=itmid;++ita) + res.push_back(*ita); + for (;itb!=itend;++itb) + res.push_back(*itb); + iterateur jt=res.begin(); + for (;it!=itend;++it,++jt) + *it=*jt; + } + + void gen_sort_f(iterateur it,iterateur itend,bool (*f)(const gen &a,const gen &b)){ +#if 0 + my_qsort(it,itend,f); +#else + f_compare m(f); + sort(it,itend,m); +#endif + } + + + // equality of vecteurs representing geometrical lines + static bool geo_equal(const vecteur &v,const vecteur & w,int subtype,GIAC_CONTEXT){ + int vs=int(v.size()),ws=int(w.size()); + if (vs!=ws) + return false; + if (v==w) + return true; + if ( (subtype==_LINE__VECT) && (vs==2)){ + if (v[1]==v[0]) + return v==w; + // v[1]!=v[0] + if (!is_zero(im(rdiv(w[0]-v[0],v[1]-v[0],contextptr),contextptr),contextptr)) + return false; + if (!is_zero(im(rdiv(w[1]-v[0],v[1]-v[0],contextptr),contextptr),contextptr)) + return false; + return true; + } + if (subtype==_SET__VECT){ + vecteur w1(w),v1(v); +#if 1 + islesscomplexthanf_sort(w1.begin(),w1.end()); + islesscomplexthanf_sort(v1.begin(),v1.end()); +#else + sort(w1.begin(),w1.end(),islesscomplexthanf); + sort(v1.begin(),v1.end(),islesscomplexthanf); +#endif + return w1==v1; + } + return false; + } + + bool operator_equal(const gen & a,const gen & b,GIAC_CONTEXT){ + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: + return (a.val==b.val); + case _INT___MOD: case _ZINT__MOD: + return a==*b._MODptr; + case _MOD__INT_: case _MOD__ZINT: + return b==*a._MODptr; + case _INT___ZINT: + return (mpz_cmp_si(*b._ZINTptr,a.val)==0); + case _INT___DOUBLE_: + return double(a.val)==b._DOUBLE_val; + case _DOUBLE___INT_: + return a._DOUBLE_val==double(b.val); + case _REAL__INT_: case _INT___REAL: case _REAL__ZINT: case _ZINT__REAL: case _REAL__FRAC: case _FRAC__REAL: case _DOUBLE___FRAC: case _FRAC__DOUBLE_: case _FRAC__FLOAT_: case _FLOAT___FRAC: + return is_exactly_zero(a-b); + case _INT___FLOAT_: + return giac_float(a.val)==b._FLOAT_val; + case _FLOAT___INT_: + return a._FLOAT_val==giac_float(b.val); + case _ZINT__INT_: + return (mpz_cmp_si(*a._ZINTptr,b.val)==0); + case _ZINT__ZINT: + return (mpz_cmp(*a._ZINTptr,*b._ZINTptr)==0); + case _INT___CPLX: case _ZINT__CPLX: + return ( operator_equal(a,re(b,contextptr),contextptr) && is_zero(im(b,contextptr),contextptr)); + case _CPLX__ZINT: case _CPLX__INT_: + return ( operator_equal(re(a,contextptr),b,contextptr) && is_zero(im(a,contextptr),contextptr)) ; + case _CPLX__CPLX: + return( operator_equal(*a._CPLXptr,*b._CPLXptr,contextptr) && operator_equal(*(a._CPLXptr+1),*(b._CPLXptr+1),contextptr) ); + case _DOUBLE___DOUBLE_: + if (a._DOUBLE_val==b._DOUBLE_val) + return true; + if (my_isnan(a._DOUBLE_val) && my_isnan(b._DOUBLE_val)) + return true; // avoid infinite loop in evalf + return absdouble(a._DOUBLE_val-b._DOUBLE_val)name==b._IDNTptr->name || *a._IDNTptr->name==*b._IDNTptr->name); + return a._IDNTptr->id_name==b._IDNTptr->id_name || strcmp(a._IDNTptr->id_name,b._IDNTptr->id_name)==0; + case _SYMB__SYMB: + if (a._SYMBptr==b._SYMBptr) + return true; + if (a._SYMBptr->sommet!=b._SYMBptr->sommet) + return false; + return (a._SYMBptr->feuille==b._SYMBptr->feuille); + case _VECT__VECT: + if (a._VECTptr==b._VECTptr) + return true; + if (a.subtype!=b.subtype){ + if ( (a.subtype==_MATRIX__VECT && b.subtype==0) || + (b.subtype==_MATRIX__VECT && a.subtype==0) || + (a.subtype==_SORTED__VECT && b.subtype==_SEQ__VECT) || + (a.subtype==_SEQ__VECT && b.subtype==_SORTED__VECT)) + ; // don't consider them different + else + return false; + } + if (a.subtype) + return geo_equal(*a._VECTptr,*b._VECTptr,a.subtype,contextptr); + return *a._VECTptr==*b._VECTptr; + case _POLY__POLY: + if (a._POLYptr==b._POLYptr) + return true; + return (a._POLYptr->dim==b._POLYptr->dim) && (a._POLYptr->coord==b._POLYptr->coord); + case _FRAC__FRAC: + return (a._FRACptr->num==b._FRACptr->num) && (a._FRACptr->den==b._FRACptr->den); + case _STRNG__STRNG: + if (is_undef(a)) return false; + if (is_undef(b)) return false; + return (a._STRNGptr==b._STRNGptr) || (*a._STRNGptr==*b._STRNGptr); + case _FUNC__FUNC: + return (a._FUNCptr==b._FUNCptr) || (*a._FUNCptr==*b._FUNCptr); + case _MOD__MOD: + return ( (*a._MODptr==*b._MODptr) && (*(a._MODptr+1)==*(b._MODptr+1)) ); + case _EXT__EXT: + return ( change_subtype(*a._EXTptr,_POLY1__VECT)==change_subtype(*b._EXTptr,_POLY1__VECT) && (*(a._EXTptr+1)==*(b._EXTptr+1)) ); + case _SPOL1__SPOL1: + return *a._SPOL1ptr==*b._SPOL1ptr; + default: // Check pointers, type subtype + if ((a.type==b.type) && (a.subtype==b.subtype) && (a.val==b.val) && a._ZINTptr==b._ZINTptr) + return true; + if (a.type<=_REAL && b.type<=_REAL) + return is_zero(a-b,contextptr); + if ( (a.type==_FLOAT_ || a.type==_DOUBLE_ || a.type==_REAL) && (b.type<=_REAL || b.type==_FRAC || b.type==_FLOAT_)) + return is_zero(a-evalf(b,1,contextptr)); + if ( (b.type==_FLOAT_ || b.type==_DOUBLE_ || b.type==_REAL) && (a.type<=_REAL || a.type==_FRAC || a.type==_FLOAT_)) + return is_zero(evalf(a,1,contextptr)-b); + if (a.type==_USER) + return *a._USERptr==b; + if (b.type==_USER) + return *b._USERptr==a; + if (a.type==_INT_ && a.subtype==_INT_TYPE && b.type==_FUNC){ + if (a==_STRNG && b==at_string) return true; + if (a==_VECT && b==at_vector) return true; + if (a==_FLOAT_ && b==at_float) return true; + if (a==_DOUBLE_ && b==at_real) return true; + if (a==_CPLX && b==at_complex) return true; + if ( (a==_INT_||a==_ZINT) && b==at_int) return true; + } + if (b.type==_INT_ && b.subtype==_INT_TYPE && a.type==_FUNC) + return operator_equal(b,a,contextptr); + return false; + } + } + + bool identificateur::operator ==(const identificateur & i){ + return id_name==i.id_name || !strcmp(id_name,i.id_name); + } + + bool operator ==(const gen & a,const identificateur & i){ + return a.type==_IDNT && (a._IDNTptr->id_name==i.id_name || !strcmp(a._IDNTptr->id_name,i.id_name)); + } + + bool identificateur::operator ==(const gen & i){ + return i.type==_IDNT && (id_name==i._IDNTptr->id_name || !strcmp(id_name,i._IDNTptr->id_name)); + } + + bool operator ==(const gen & a,const gen & b){ + return operator_equal(a,b,context0); + } + + bool operator !=(const gen & a,const gen & b){ + return !(a==b); + } + + gen equal(const gen & a,const gen &b,GIAC_CONTEXT){ + if (a.type==_VECT && b.type==_VECT && !b._VECTptr->empty()){ + if (calc_mode(contextptr)==1 && a.subtype==_GGBVECT && b.subtype==_GGBVECT){ + return symbolic(at_equal,makesequence(a,b)); + } + else { + if (a._VECTptr->size()==b._VECTptr->size()) + return apply(a,b,contextptr,equal); + return apply2nd(a,b,contextptr,equal); + } + } + if (is_equal(a)) // so that equal(a=0 ,1) returns a=1, used for fsolve + return equal(a._SYMBptr->feuille[0],b,contextptr); + // only in ggb mode, because we want to be able to do subst(x[1],x=[1,2]) + if (calc_mode(contextptr)==1 && a.type==_IDNT && b.type==_VECT && b.subtype!=_SEQ__VECT && b.subtype!=_GGB__VECT){ + vecteur v=*b._VECTptr; + for (unsigned i=0;ifeuille[0],b,contextptr); + // only in ggb mode, because we want to be able to do subst(x[1],x=[1,2]) + if (calc_mode(contextptr)==1 && a.type==_IDNT && b.type==_VECT){ + vecteur v=*b._VECTptr; + for (unsigned i=0;ifeuille[1]; + if (f.type==_FRAC && f._FRACptr->den.type==_INT_ && f._FRACptr->den.val %2==0) + return 1; + } + } + if (a.is_symb_of_sommet(at_neg) && !is_inf(a)) + return -sign(a._SYMBptr->feuille,contextptr); + if (a.is_symb_of_sommet(at_inv)) + return sign(a._SYMBptr->feuille,contextptr); + if (a.is_symb_of_sommet(at_prod)){ + vecteur v=gen2vecteur(a._SYMBptr->feuille); + gen res=1; + for (int i=0;i1e-6) + *logptr(contextptr) << gettext("Warning, sign might return 0 incorrectly because the value of eps is too large ") << eps << '\n'; + switch (a.type){ + case _INT_: case _ZINT: + if (is_positive(a,contextptr)) + return 1; + else + return -1; + case _DOUBLE_: + if (a._DOUBLE_val>eps) + return 1.0; + if (a._DOUBLE_val<-eps) + return -1.0; + return 0.0; + case _FLOAT_: // NOTE: does not follow eps rule + if (a._FLOAT_val>0) + return giac_float(1.0); + if (a._FLOAT_val<0) + return giac_float(-1.0); + return giac_float(0.0); + case _REAL: + { + if (a._REALptr->is_zero()) + return 0; + if (a._REALptr->maybe_zero()) + return undef; + int res=a._REALptr->is_positive(); + if (res) + return res; + return undef; + } + return -1; + case _CPLX: + return a/abs(a,contextptr); + case _FRAC: + return sign(a._FRACptr->num,contextptr)*sign(a._FRACptr->den,contextptr); + } + int fs=fastsign(a,contextptr); + if (fs) + return fs; + gen b=evalf_double(a,1,contextptr); + if (b.type==_DOUBLE_){ + if (b._DOUBLE_val>eps) + return plus_one; + if (b._DOUBLE_val<-eps) + return minus_one; +#ifdef HAVE_LIBMPFR // FIXME try to avoid rounding errors + b=accurate_evalf(eval(a,1,contextptr),1000); + if (is_greater(b,1e-250,contextptr)) + return plus_one; + if (is_greater(-1e-250,b,contextptr)) + return minus_one; +#endif + // return zero; // returning 0 is wrong, sign(a) is much better! + } + if (b.type==_FLOAT_){ + if (b._FLOAT_val>eps) + return plus_one; + if (b._FLOAT_val<-eps) + return minus_one; + return zero; + } + if (is_zero(im(a,contextptr),contextptr)){ + int s=sturmsign(a,true,contextptr); + if (s && s!=-2) + return s; + } + return new_ref_symbolic(symbolic(at_sign,a)); + } + + static gen sym_is_greater(const gen & a,const gen & b,GIAC_CONTEXT){ + if (is_undef(a)) + return a; + if (is_undef(b)) + return b; + if (a==unsigned_inf || b==unsigned_inf || a.type==_VECT || b.type==_VECT) + return undef; + if (a==b) + return false; + if ( (b==plus_inf) || (a==minus_inf) ) + return false; + if ( (b==minus_inf) || (a==plus_inf) ) + return true; + if (is_equal(a) && is_equal(b) ){ + gen & af=a._SYMBptr->feuille; + gen & bf=b._SYMBptr->feuille; + if (af.type==_VECT && bf.type==_VECT && af._VECTptr->size()==2 && bf._VECTptr->size()==2 && af._VECTptr->front()==bf._VECTptr->front()) + return sym_is_greater(af._VECTptr->back(),bf._VECTptr->back(),contextptr); + } + if (a.type==_STRNG && b.type==_STRNG) + return *a._STRNGptr>=*b._STRNGptr; + if (a.type==_USER) + return (*a._USERptr>b); + if (b.type==_USER) + return (*b._USERptr<=a); + if (a.is_symb_of_sommet(at_superieur_strict) || a.is_symb_of_sommet(at_superieur_egal) || a.is_symb_of_sommet(at_inferieur_strict) || a.is_symb_of_sommet(at_inferieur_egal) ) + return false; + if (b.is_symb_of_sommet(at_superieur_strict) || b.is_symb_of_sommet(at_superieur_egal) || b.is_symb_of_sommet(at_inferieur_strict) || b.is_symb_of_sommet(at_inferieur_egal) ) + return false; + if (a.type==_CPLX || b.type==_CPLX) + return symb_superieur_strict(a,b); + if (a.is_symb_of_sommet(at_unit) && b.is_symb_of_sommet(at_unit)){ + gen c=a-b; + if (c.is_symb_of_sommet(at_unit)) + return is_positive(c._SYMBptr->feuille[0],contextptr); + } + gen approx; + if (has_evalf(a,approx,1,contextptr) && approx.type==_CPLX && !is_zero(im(approx,contextptr)/re(approx,contextptr),contextptr)) + return symb_superieur_strict(a,b); + if (has_evalf(a-b,approx,1,contextptr)){ + if (approx.type==_CPLX && is_zero(im(approx,contextptr)/re(approx,contextptr),contextptr)) + approx=re(approx,contextptr); + if (approx.type==_DOUBLE_ ){ +#ifdef HAVE_LIBMPFR + // FIXME?? try to avoid rounding error with more digits + if (fabs(approx._DOUBLE_val)<1e-5 && (a-b).type!=_FRAC){ + gen tmp=accurate_evalf(eval(a-b,1,contextptr),1100); // 1100 bits exceeds double precision, if a and b are equal up to double precision, this will be rounded to 0.0 + tmp=evalf_double(tmp,1,contextptr); + if (tmp.type==_DOUBLE_) + approx=tmp; + } +#endif + return (approx._DOUBLE_val>0); + } + if (approx.type==_REAL) + return is_strictly_positive(approx,contextptr); + if (approx.type==_FLOAT_ ) + return (approx._FLOAT_val>0); + } + gen g=sign(a-b,contextptr); + if (is_one(g)) + return plus_one; + if (is_minus_one(g)) + return false; + return symb_superieur_strict(a,b); + } + + gen superieur_strict(const gen & a,const gen & b,GIAC_CONTEXT){ + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: + return (a.val>b.val); + case _INT___ZINT: + return (mpz_cmp_si(*b._ZINTptr,a.val)<0); + case _ZINT__INT_: + return (mpz_cmp_si(*a._ZINTptr,b.val)>0); + case _ZINT__ZINT: + return (mpz_cmp(*a._ZINTptr,*b._ZINTptr)>0); + case _DOUBLE___DOUBLE_: + return a._DOUBLE_val>b._DOUBLE_val; + case _FRAC__FRAC: + if (is_positive(a._FRACptr->den,contextptr) && is_positive(b._FRACptr->den,contextptr)) + return superieur_strict(a._FRACptr->num*b._FRACptr->den,a._FRACptr->den*b._FRACptr->num,contextptr); + break; + case _FRAC__INT_: case _FRAC_ZINT: + if (is_positive(a._FRACptr->den,contextptr)) + return superieur_strict(a._FRACptr->num,a._FRACptr->den*b,contextptr); + break; + case _INT___FRAC: case _ZINT__FRAC: + if (is_positive(b._FRACptr->den,contextptr)) + return superieur_strict(b._FRACptr->den*a,b._FRACptr->num,contextptr); + break; + case _DOUBLE___INT_: + return a._DOUBLE_val>b.val; + case _INT___DOUBLE_: + return a.val>b._DOUBLE_val; + case _FLOAT___FLOAT_: + return a._FLOAT_val>b._FLOAT_val; + case _FLOAT___INT_: + return a._FLOAT_val>b.val; + case _INT___FLOAT_: + return a.val>b._FLOAT_val; + case _DOUBLE___ZINT: + return a._DOUBLE_val>mpz_get_d(*b._ZINTptr); + case _ZINT__DOUBLE_: + return mpz_get_d(*a._ZINTptr)>b._DOUBLE_val; + } + if (a.type<=_REAL && b.type<=_REAL) + return is_strictly_positive(a-b,contextptr); + return sym_is_greater(a,b,contextptr); + } + + gen inferieur_strict(const gen & a,const gen & b,GIAC_CONTEXT){ + return superieur_strict(b,a,contextptr); + } + + gen superieur_egal(const gen & a,const gen & b,GIAC_CONTEXT){ + if ( (a.type==_REAL && b.type<=_REAL) || + (b.type==_REAL && a.type<=_REAL) ){ + if (is_positive(a-b,contextptr)) + return 1; + return 0; + } + gen g=!superieur_strict(b,a,contextptr); + if (is_undef(g)) return g; + if (g.type==_INT_) + return g; + return symb_superieur_egal(a,b); + } + + gen inferieur_egal(const gen & a,const gen & b,GIAC_CONTEXT){ + return superieur_egal(b,a,contextptr); + } + + bool has_inf_or_undef(const gen & g){ + if (g.type!=_VECT) + return is_inf(g) || is_undef(g); + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it){ + if (has_inf_or_undef(*it)) + return true; + } + return false; + } + + bool is_inf(const gen & e){ + switch (e.type){ + case _IDNT: + return !strcmp(e._IDNTptr->id_name,string_infinity); + case _SYMB: + return is_inf(e._SYMBptr->feuille); + case _DOUBLE_: + return my_isinf(e._DOUBLE_val); + case _FLOAT_: + return fis_inf(e._FLOAT_val); + case _CPLX: + return is_inf(*e._CPLXptr) || is_inf(*(e._CPLXptr+1)); + default: + return false; + } + } + bool is_undef(const vecteur & v){ + return !v.empty() && is_undef(v.front()); + } + bool is_undef(const polynome & p){ + return !p.coord.empty() && is_undef(p.coord.front().value); + } + // we are using exponent as undef marker because coeff=undef is used + // for Landau notation O(x^exponent) + bool is_undef(const sparse_poly1 & s){ + return !s.empty() && is_undef(s.front().exponent); + } + bool is_undef(const gen & e){ + switch (e.type){ + case _IDNT: + return !strcmp(e._IDNTptr->id_name,string_undef); + case _STRNG: + return e.subtype==-1; + case _VECT: + return !e._VECTptr->empty() && is_undef(e._VECTptr->front()); + case _POLY: + return !e._POLYptr->coord.empty() && is_undef(e._POLYptr->coord.front().value); + case _SPOL1: + return !e._SPOL1ptr->empty() && is_undef(e._SPOL1ptr->front().exponent); + case _FLOAT_: + return fis_nan(e._FLOAT_val); + case _DOUBLE_: + return my_isnan(e._DOUBLE_val); + case _CPLX: + return is_undef(*e._CPLXptr) || is_undef(*(e._CPLXptr+1)); + case _FRAC: + return is_undef(e._FRACptr->num); + default: + return false; + } + } + + bool is_zero__VECT(const vecteur & v,GIAC_CONTEXT){ + vecteur::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (!is_zero(*it,contextptr)) + return false; + } + return true; + } + + bool is_zero(const gen & a,GIAC_CONTEXT){ + switch (a.type ) { + case _INT_: + return !a.val; + case _ZINT: + return (!mpz_sgn(*a._ZINTptr)); + case _REAL: + return fabs(evalf_double(a,1,contextptr)._DOUBLE_val)<=epsilon(contextptr);// return a._REALptr->is_zero(); + case _CPLX: + return (is_zero(*a._CPLXptr,contextptr) && is_zero(*(a._CPLXptr+1),contextptr)); + case _DOUBLE_: + return (fabs(a._DOUBLE_val)<=epsilon(contextptr)); + case _FLOAT_: + return is_exactly_zero(a._FLOAT_val); + case _VECT: + return is_zero__VECT(*a._VECTptr,contextptr); + case _POLY: + return a._POLYptr->coord.empty(); + case _FRAC: + return is_zero(a._FRACptr->num,contextptr); + case _MOD: + return is_zero(*a._MODptr,contextptr); + case _USER: + return a._USERptr->is_zero(); + case _SYMB: + if (a._SYMBptr->sommet==at_unit) + return is_zero(a._SYMBptr->feuille[0]); + default: + return false; + } + } + + bool is_exactly_zero(const gen & a){ + switch (a.type ) { + case _INT_: + return !a.val; + case _ZINT: + return (!mpz_sgn(*a._ZINTptr)); + case _REAL: + return a._REALptr->is_zero(); + case _CPLX: + return (is_exactly_zero(*a._CPLXptr) && is_exactly_zero(*(a._CPLXptr+1))); + case _DOUBLE_: + return a._DOUBLE_val==0; + case _FLOAT_: + return fis_exactly_zero(a._FLOAT_val); + case _POLY: + return a._POLYptr->coord.empty(); + case _FRAC: + return is_exactly_zero(a._FRACptr->num); + case _MOD: + return is_exactly_zero(*a._MODptr); + case _USER: + return a._USERptr->is_zero(); + default: + return false; + } + } + + bool is_one(const gen & a){ + switch (a.type ) { + case _INT_: + return a.val==1; + case _ZINT: + return mpz_cmp_si(*a._ZINTptr,1)==0; + case _CPLX: + return is_one(*a._CPLXptr) && is_zero(*(a._CPLXptr+1)); + case _DOUBLE_: + return a._DOUBLE_val==1; + case _FLOAT_: + return a._FLOAT_val==giac_float(1); + case _REAL: + return is_exactly_zero(a-1); + case _VECT: + return a._VECTptr->size()==1 && is_one(a._VECTptr->front()); + case _POLY: + return Tis_constant(*a._POLYptr) && (is_one(a._POLYptr->coord.front().value)); + case _FRAC: + return a._FRACptr->num == a._FRACptr->den; + case _MOD: + return is_one(*a._MODptr); + case _USER: + return a._USERptr->is_one(); + default: + return false; + } + } + + bool is_minus_one(const gen & a){ + switch (a.type ) { + case _INT_: + return a.val==-1; + case _ZINT: + return mpz_cmp_si(*a._ZINTptr,-1)==0; + case _CPLX: + return (is_minus_one(*a._CPLXptr) && is_zero(*(a._CPLXptr+1),context0)); + case _DOUBLE_: + return a._DOUBLE_val==-1; + case _FLOAT_: + return a._FLOAT_val==giac_float(-1); + case _REAL: + return is_exactly_zero(a+1); + case _VECT: + return a._VECTptr->size()==1 && is_minus_one(a._VECTptr->front()); + case _POLY: + return Tis_constant(*a._POLYptr) && (is_minus_one(a._POLYptr->coord.front().value)); + case _FRAC: + return a._FRACptr->num == -a._FRACptr->den; + case _MOD: + if (*(a._MODptr+1)==plus_two) + return is_one(*a._MODptr); + else + return is_minus_one(*a._MODptr); + case _SYMB: + return a._SYMBptr->sommet==at_neg && is_one(a._SYMBptr->feuille); + case _USER: + return a._USERptr->is_minus_one(); + default: + return false; + } + } + + bool is_sq_minus_one(const gen & a){ + switch (a.type ) { + case _CPLX: case _MOD: case _USER: + return is_minus_one(a*a); + case _VECT: + return a._VECTptr->size()==1 && is_sq_minus_one(a._VECTptr->front()); + case _POLY: + return Tis_constant(*a._POLYptr) && (is_sq_minus_one(a._POLYptr->coord.front().value)); + default: + return false; + } + } + + gen gen::operator [] (int i) const{ + return operator_at(i,context0); + } + + gen gen::operator_at(int i,GIAC_CONTEXT) const{ + if (type==_SYMB){ + if (!i) + return _SYMBptr->sommet; + if (_SYMBptr->feuille.type!=_VECT){ + if (i==1) + return _SYMBptr->feuille; + else + return gendimerr(contextptr); + } + if (unsigned(i)>_SYMBptr->feuille._VECTptr->size()) + return gendimerr(contextptr); + return (*(_SYMBptr->feuille._VECTptr))[i-1]; + } + if (type==_MOD){ + if (!i) + return _MOD; + if (i==1) + return *_MODptr; + if (i==2) + return *(_MODptr+1); + return gendimerr(contextptr); + } + if (type==_IDNT) + return symb_at(makesequence(*this,i)); + if (type==_FUNC){ + if (*this==at_ln){ + i=i+array_start(contextptr); // (xcas_mode(contextptr)!=0); + return inv(ln(i,contextptr),contextptr)*(*this); + } + if (*this==at_maple_root){ + identificateur tmp(" x"); + gen g=symb_program(tmp,zero,new_ref_symbolic(symbolic(at_makesuite,i,tmp)),contextptr); + g=makesequence(at_maple_root,g); + return symb_compose(g); + } + } + if (this->type!=_VECT){ + if (calc_mode(contextptr)==1) + return *this; + return gentypeerr(gettext("Gen [int]")); + } + if (i<0) i+=_VECTptr->size(); + if (unsigned(i)>=_VECTptr->size()){ + if (array_start(contextptr))//(xcas_mode(contextptr)!=0 || abs_calc_mode(contextptr)==38) + ++i; + return gendimerr(gettext("Index outside range : ")+ print_INT_(i)+", vector size is "+print_INT_(int(_VECTptr->size())) +#ifndef GIAC_HAS_STO_38 + +", syntax compatibility mode "+print_program_syntax(xcas_mode(contextptr)) +#endif + +"\n"); + } + return (*(this->_VECTptr))[i]; + } + + gen gen::operator [] (const gen & i) const { + return operator_at(i,context0); + } + + gen gen::operator_at(const gen & i,GIAC_CONTEXT) const { + if (type==_STRNG && subtype==-1) return *this; + if (i.type==_DOUBLE_){ + double id=i._DOUBLE_val; + if (int(id)==id) + return (*this)[int(id)]; + } + if (i.type==_FLOAT_){ + giac_float id=i._FLOAT_val; + if (giac_float(get_int(id))==id) + return (*this)[get_int(id)]; + } + if (i.type==_REAL){ + double id=i.evalf_double(1,contextptr)._DOUBLE_val; + if (int(id)==id) + return (*this)[int(id)]; + } + if ((type==_STRNG) && (i.type==_INT_)){ + int s=int(_STRNGptr->size()),I=i.val; + if (I<0) I+=s; + if ( (I=0)) + return string2gen(string()+'"'+(*_STRNGptr)[I]+'"'); + } + if (type==_IDNT) + return new_ref_symbolic(symbolic(at_at,gen(makenewvecteur(*this,i),_SEQ__VECT))); + if (type==_USER) + return (*_USERptr)[i]; + if (type==_MAP){ + gen_map::const_iterator it=_MAPptr->find(i),itend=_MAPptr->end(); + if (it!=itend) + return it->second; + if (subtype==_SPARSE_MATRIX) + return 0; + } + if (type==_SPOL1){ + sparse_poly1::const_iterator it=_SPOL1ptr->begin(),itend=_SPOL1ptr->end(); + for (;it!=itend;++it){ + if (it->exponent==i) + return it->coeff; + } + return 0; + } + if (is_symb_of_sommet(at_at)){ // add i at the end of the index + if (_SYMBptr->feuille.type==_VECT && _SYMBptr->feuille._VECTptr->size()==2){ + gen operand=_SYMBptr->feuille._VECTptr->front(); + vecteur indice=makevecteur(_SYMBptr->feuille._VECTptr->back()); + indice.push_back(i); + return symb_at(makenewvecteur(operand,gen(indice,_SEQ__VECT))); + } + } + if (i.type==_DOUBLE_) + return (*this)[(int) i._DOUBLE_val]; + if (i.type==_FLOAT_) + return (*this)[ get_int(i._FLOAT_val) ]; + if (i.type==_SYMB){ + bool ideuxpoints=i._SYMBptr->sommet==at_deuxpoints; + if (i._SYMBptr->sommet==at_interval || ideuxpoints) { + gen i1=_ceil(i._SYMBptr->feuille._VECTptr->front(),contextptr); + gen iback=i._SYMBptr->feuille._VECTptr->back(); + int step=1; + if (ideuxpoints && iback.is_symb_of_sommet(at_deuxpoints)){ + gen istep=iback._SYMBptr->feuille; + iback=istep[0]; + istep=istep[1]+array_start(contextptr); + if (!is_integral(istep) || istep.type!=_INT_ || istep.val==0) + return gendimerr(contextptr); + step=istep.val; + if (step<0 && is_zero(i1)) + i1=minus_one; + if (0 && step<0 && is_zero(iback)){ // detected during translation + *logptr(contextptr) << gettext("Warning, using :0:-step, use :-1:-step for ::") << '\n'; + } + } + gen i2=_floor(iback,contextptr); + if (is_integral(i1) && is_integral(i2)){ + int debut=i1.val,fin=i2.val+(ideuxpoints?(step<0?1:-1):0); + int S=1; + if (type==_STRNG) S=int(_STRNGptr->size()); + if (type==_VECT) S=int(_VECTptr->size()); + if (debut>=S) + return (type==_STRNG)?string2gen("",false):gen(vecteur(0),subtype); + if (debut<0) debut+=S; + if (fin<0) fin+=S; + fin=giacmin(fin,S-1); + debut=giacmin(debut,S-1); + if (debut<0 || step*double(fin-debut)<0 ) + return (type==_STRNG)?string2gen("",false):gen(vecteur(0),subtype); // swap(debut,fin); + if (step==1){ + if (type==_STRNG) + return string2gen('"'+_STRNGptr->substr(debut,fin-debut+1)+'"'); + if (type==_VECT) + return gen(vecteur(_VECTptr->begin()+debut,_VECTptr->begin()+fin+1),subtype); + } + if (type==_STRNG){ + const string & s=*_STRNGptr; + string res; + if (step<0){ + for (;debut>=fin;debut+=step) + res += s[debut]; + } + else { + for (;debut<=fin;debut+=step) + res += s[debut]; + } + return string2gen(res,false); + } + if (type==_VECT){ + const vecteur & v=*_VECTptr; + vecteur res; + res.reserve(absint(fin-debut)/step+1); + if (step<0){ + for (;debut>=fin;debut+=step) + res.push_back(v[debut]); + } + else { + for (;debut<=fin;debut+=step) + res.push_back(v[debut]); + } + return gen(res,subtype); + } + } + } + } + if (i.type==_VECT){ + const_iterateur it=i._VECTptr->begin(),itend=i._VECTptr->end(); + gen res (*this); + for (;it!=itend;++it){ + if (it->type==_VECT){ + vecteur tmp; + const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end(); + for (;jt!=jtend;++jt){ + tmp.push_back(res[*jt]); + } + return gen(tmp,it->subtype); + } + bool itdeuxpoints=it->type==_SYMB && it->_SYMBptr->sommet==at_deuxpoints; + if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_interval || itdeuxpoints) && (it+1!=itend) ){ + // submatrix extraction + gen i1=it->_SYMBptr->feuille._VECTptr->front(),iback=it->_SYMBptr->feuille._VECTptr->back(); + int step=1; + if (itdeuxpoints && iback.is_symb_of_sommet(at_deuxpoints)){ + gen istep=iback._SYMBptr->feuille; + iback=istep[0]; + istep=istep[1]+array_start(contextptr); + if (!is_integral(istep) || istep.type!=_INT_ || istep==0) + return gendimerr(contextptr); + step=istep.val; + if (step<0 && is_zero(i1)) + i1=minus_one; + if (step<0 && is_zero(iback)){ + *logptr(contextptr) << gettext("Warning, using :0:-step, use :-1:-step for ::") << '\n'; + } + } + if (i1.type==_INT_ && iback.type==_INT_){ + int debut=i1.val,fin=iback.val+(itdeuxpoints?(step<0?1:-1):0); + if (res.type==_VECT){ + int S=int(res._VECTptr->size()); + if (debut<0) debut +=S; + if (fin<0) fin +=S; + fin=giacmin(fin,S-1); + debut=giacmin(debut,S-1); + if (debut<0 || step*double(fin-debut)<0 ) + return gendimerr(contextptr); + iterateur jt=res._VECTptr->begin()+debut,jtend=_VECTptr->begin()+fin; + gen fin_it(vecteur(it+1,itend),_SEQ__VECT); + vecteur v; + v.reserve(absint(jtend-jt)/step+1); + if (step<0){ + for (;jt>=jtend;jt+=step) + v.push_back((*jt)[fin_it]); + } + else { + for (;jt<=jtend;jt+=step) + v.push_back((*jt)[fin_it]); + } + if (res.subtype==_MATRIX__VECT && !ckmatrix(v)) + return v; + return gen(v,res.subtype); + } + } + } + res = res[*it]; + } + return res; + } + if (i.type!=_INT_) + return symb_at(makesequence(*this,i)); + return this->operator_at(i.val,contextptr); + } + + /* + gen & gen::operator [](int i){ + if (this->type!=_VECT) + return gentypeerr(gettext("Gen [int]")); + if (i>=_VECTptr->size()) + return gendimerr(contextptr); + return (*(this->_VECTptr))[i]; + } + + gen & gen::operator [] (const gen & i) { + if (i.type==_DOUBLE_) + return (*this)[(int) i._DOUBLE_val]; + if (i.type!=_INT_) + return gentypeerr(gettext("Gen [gen]")); + if (this->type!=_VECT) + return gentypeerr(gettext("Gen [gen]")); + if (i.val>=_VECTptr->size()) + return gendimerr(gettext("Gen [_VECT]")); + return (*(this->_VECTptr))[i.val]; + } + */ + + gen gen::operator () (const gen & i,const context * contextptr) const{ + return (*this)(i,undef,contextptr); + } + + gen gen::operator () (const gen & i,const gen & progname,const context * contextptr) const{ + bool isprog=type==_FUNC || this->is_symb_of_sommet(at_program) || this->is_symb_of_sommet(*at_program); + if (!isprog){ + if (i.is_symb_of_sommet(at_equal)) + return _subst(makesequence(*this,i),contextptr); + if (i.type==_VECT){ + vecteur & v = *i._VECTptr; + vecteur vin,vout; + for (unsigned j=0;jfeuille[0]); + vout.push_back(v[j]._SYMBptr->feuille[1]); + } + if (vin.size()==v.size()) + return subst(*this,vin,vout,false,contextptr); + } + } + if (type==_SYMB){ + // Functional case for sommet + if (_SYMBptr->sommet==at_program) { + gen tmp=_SYMBptr->feuille; + if (tmp.type!=_VECT) + return gensizeerr(contextptr); + vecteur tmpv=*tmp._VECTptr; tmpv[1]=i; + return _program(gen(tmpv,tmp.subtype),progname,contextptr); + } +#ifndef RTOS_THREADX + if (_SYMBptr->sommet==at_rpn_prog){ + vecteur pile; + if (rpn_mode(contextptr)) + pile=history_out(contextptr); + if ( (i.type!=_VECT) || (i.subtype!=_SEQ__VECT)) + pile.push_back(i); + else + pile=mergevecteur(pile,*i._VECTptr); + vecteur prog; + if (_SYMBptr->feuille.type==_VECT) + prog=*_SYMBptr->feuille._VECTptr; + else + prog=vecteur(1,_SYMBptr->feuille); + return gen(rpn_eval(prog,pile,contextptr),_RPN_STACK__VECT); + } +#endif + if (_SYMBptr->sommet==at_compose){ + gen tmp=_SYMBptr->feuille; + if (tmp.type!=_VECT) + return tmp(i,contextptr); + gen res=i; + const_iterateur it=tmp._VECTptr->begin(),itend=tmp._VECTptr->end(); + for (;itend!=it;){ + --itend; + res=(*itend)(res,contextptr); + } + return res; + } + if (_SYMBptr->sommet==at_composepow){ + gen tmp=_SYMBptr->feuille; + if (tmp.type!=_VECT || tmp._VECTptr->size()!=2 || tmp._VECTptr->back().type!=_INT_) + return symb_of(tmp,i); + gen res=i; + int n=tmp._VECTptr->back().val; + if (n<0){ + // try to invert the function + gen x(identificateur("xinvert")),y(identificateur("yinvert")); + gen f=tmp._VECTptr->front(); + gen s=_solve(makesequence(symb_equal(f(x,contextptr),y),x),contextptr); + if (s.type!=_VECT || s._VECTptr->size()<1 || is_undef(s._VECTptr->front())) + return gensizeerr("Unable to invert function"); + if (s._VECTptr->size()>1) + *logptr(contextptr) << "Choosing first solution in "<front(),contextptr); + n=-n; + tmp=makesequence(f,n); + } + if (!n) + return i; + int ratnormal_test=MAX_RECURSION_LEVEL/2; + // otherwise f(x):=-3x+2; g:=(f@@300)(x):; simplifier(g); might segfault + tmp=tmp._VECTptr->front(); + for (int j=0;jsommet==at_derive || _SYMBptr->sommet==at_function_diff || _SYMBptr->sommet==at_of || _SYMBptr->sommet==at_at) + return new_ref_symbolic(symbolic(at_of,makesequence(*this,i))); + gen & f=_SYMBptr->feuille; + // distributions laws: add arguments and reeval + if (is_distribution(_SYMBptr->sommet)){ + vecteur args(gen2vecteur(f)); + if (i.type==_VECT && i.subtype==_SEQ__VECT) + args=mergevecteur(args,*i._VECTptr); + else + args.push_back(i); + return _SYMBptr->sommet(gen(args,_SEQ__VECT),contextptr); + } + if (string(_SYMBptr->sommet.ptr()->s)=="pari"){ + vecteur argv(gen2vecteur(f)); + if (i.type==_VECT && i.subtype!=_SEQ__VECT) + argv=mergevecteur(argv,vecteur(1,i)); + else + argv=mergevecteur(argv,gen2vecteur(i)); + return _SYMBptr->sommet(gen(argv,_SEQ__VECT),contextptr); + } + if (f==makenewvecteur(zero)){ + return _SYMBptr->sommet(i,contextptr); + } + // other case, apply feuille to i then apply sommet + if (f.type!=_VECT) + return _SYMBptr->sommet(f(i,contextptr),contextptr); + vecteur lid(lidnt(*this)); + if (lid.size()==1 && !has_algebraic_program(*this)){ + if (lid.front()==vx_var || lid.front()==t__IDNT_e || lid.front()==x__IDNT_e) + // suspect something like P:=x^3+1 then P(2) + *logptr(contextptr) << "Warning, evaluating univariate expression like if expression was a function.\nYou should write subst(" << *this << "," << lid.front() << "," << i << ")" << '\n'; + else + return gensizeerr("Expression used like a function "+this->print(contextptr)+"\nYou should write subst("+this->print(contextptr)+","+lid.front().print(contextptr)+","+i.print(contextptr)+")"); + return subst(*this,lid.front(),i,false,contextptr); + } + vecteur res(*f._VECTptr); + iterateur it=res.begin(),itend=res.end(); + bool warn=false; + for (;it!=itend;++it){ + if (it->type==_IDNT) + warn=true; + *it=(*it)(i,contextptr); + } + if (warn) + *logptr(contextptr) << gettext("Warning, evaluating (") << *this << ")(" << i << ") as a function not as a product" << '\n'; + return _SYMBptr->sommet(res,contextptr); + } + if (type==_FUNC){ + if ( (i.type==_VECT) && (i.subtype==_SEQ__VECT) && (i._VECTptr->size()==1)) + return (*_FUNCptr)(i._VECTptr->front(),contextptr); + else + return (*_FUNCptr)(i,contextptr); + } + if (i.type==_DOUBLE_ && giac_floor(i._DOUBLE_val)==i._DOUBLE_val ) + return (*this)((int) i._DOUBLE_val,contextptr); + if (i.type==_FLOAT_ && ffloor(i._FLOAT_val)==i._FLOAT_val ) + return (*this)(get_int(i._FLOAT_val),contextptr); + if (type==_INT_ && subtype==_INT_TYPE && i.type==_VECT){ + return gen(*i._VECTptr,type); + } + if (type<_IDNT ) + return *this; + if (type==_USER) + return (*_USERptr)(i,contextptr); + if (type==_STRNG){ + gen ii(i); + if (!is_integral(ii)) + return gensizeerr(gettext("Bad index")); + if (ii.val<1 || ii.val>int(_STRNGptr->size())) + return gendimerr(gettext("Index out of range")); + return string2gen(string(1,(*_STRNGptr)[ii.val-1]),false); + } + if (type==_VECT){ + if (of_pointer_38 && _VECTptr->size()==2 && _VECTptr->front().type==_POINTER_ && _VECTptr->front().subtype==_APPLET_POINTER && _VECTptr->back().type==_POINTER_ && _VECTptr->back().subtype==_VARFUNCDEF_POINTER ) + return of_pointer_38(_VECTptr->front()._POINTER_val,_VECTptr->back()._POINTER_val,i); + if (1 || + abs_calc_mode(contextptr)==38){ + if (i.type==_VECT){ + gen res=*this; + int is=int(i._VECTptr->size()); + for (int k=0;kfeuille; + if (ife.type==_VECT && ife._VECTptr->size()==2){ + const gen & if1=ife._VECTptr->front(); + const gen & if2=ife._VECTptr->back(); + if (if1.type==_INT_ && if2.type==_INT_ && if1.val>=1 && if2.val>=1 && if1.val<=if2.val && if1.val<=int(_VECTptr->size()) && if2.val<=int(_VECTptr->size())) + return gen(vecteur(_VECTptr->begin()+if1.val-1,_VECTptr->begin()+if2.val),subtype); + } + } + gen tmp=_floor(i,contextptr); + if (tmp.type!=_INT_) + return gendimerr(contextptr); + if (tmp.val<1 || tmp.val>int(_VECTptr->size()) ) + return gendimerr(contextptr); + return (*_VECTptr)[tmp.val-1]; + } + // Old code for _VECT type was just return (*this)[i]; + vecteur w(*_VECTptr); + iterateur it=w.begin(),itend=w.end(); + for (;it!=itend;++it) + *it=(*it)(i,contextptr); + return gen(w,subtype); + } + else { + if (has_inf_or_undef(i)) + return undef; + if (*this==x__IDNT_e || *this==t__IDNT_e){ + if (i.type==_IDNT && i._IDNTptr->quoted) + ; // for e.g. desolve(t*x'+x=0), we don't want x(t) to be evaled to t + else + return i; // avoid warning for expressions used as function if var is x or t + } + return symb_of(*this,i); + } + } + + static bool compare_VECT(const vecteur & v,const vecteur & w){ + int s1=int(v.size()),s2=int(w.size()); + if (s1!=s2) + return s1islesscomplexthan(*jt); + } + } + // setsizeerr(); should not happen... commented because it happens! + return false; + } + + // return true if *this is "strictly less complex" than other + bool gen::islesscomplexthan (const gen & other ) const { + // FIXME it is not the natural order, but used for pivot selection + if (type<_IDNT && is_zero(*this,context0)){ + // if (type==_INT_ && other.type==_INT_) return valid_name,other._IDNTptr->id_name)<0; + case _POLY: + if (_POLYptr->coord.size()!=other._POLYptr->coord.size()) + return _POLYptr->coord.size()coord.size(); + return _POLYptr->coord.front().value.islesscomplexthan(other._POLYptr->coord.front().value); + case _MOD: + if (*(_MODptr+1)!=*(other._MODptr+1)){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("islesscomplexthan mod")); +#endif + } + return _MODptr->islesscomplexthan(*other._MODptr); + case _SYMB: + if (_SYMBptr->sommet !=other._SYMBptr->sommet ){ +#ifdef GIAC_HAS_STO_38 // otherwise 1 test of chk_xavier fails, needs to check + int c=strcmp(_SYMBptr->sommet.ptr()->s,other._SYMBptr->sommet.ptr()->s); + if (c) return c<0; +#endif + return (alias_type) _SYMBptr->sommet.ptr() <(alias_type) other._SYMBptr->sommet.ptr(); + } + return _SYMBptr->feuille.islesscomplexthan(other._SYMBptr->feuille); + // return false; + case _VECT: + return compare_VECT(*_VECTptr,*other._VECTptr); + case _EXT: + if (*(_EXTptr+1)!=*(other._EXTptr+1)) + return (_EXTptr+1)->islesscomplexthan(*(other._EXTptr+1)); + return _EXTptr->islesscomplexthan(*(other._EXTptr)); + case _STRNG: + return *_STRNGptr<*other._STRNGptr; + default: + return this->print(context0)< other.print(context0); + } + } + + bool islesscomplexthanf(const gen & a,const gen & b){ + return a.islesscomplexthan(b); + } + + static gen monomial_degree(const gen & a){ + if (a.type<_IDNT) + return 0; + if (a.type==_IDNT){ + // detect constants of integration + if (strlen(a._IDNTptr->id_name)>=3 && a._IDNTptr->id_name[0]=='c' && a._IDNTptr->id_name[1]=='_') + return 0; + return 1; + } + if (a.type!=_SYMB) + return 0; + if (a._SYMBptr->sommet==at_neg) + return monomial_degree(a._SYMBptr->feuille); + if (a._SYMBptr->sommet==at_inv) + return -monomial_degree(a._SYMBptr->feuille); + if (a._SYMBptr->sommet==at_pow && a._SYMBptr->feuille.type==_VECT && a._SYMBptr->feuille._VECTptr->size()==2) + return (*a._SYMBptr->feuille._VECTptr)[1]; + if (a._SYMBptr->sommet==at_plus){ + gen af=a._SYMBptr->feuille; + if (af.type!=_VECT) + return monomial_degree(af); + gen res(0); + for (unsigned i=0;isize();++i){ + res = max(res,monomial_degree((*af._VECTptr)[i]),context0); + } + return res; + } + if (a._SYMBptr->sommet!=at_prod) + return 0; + gen af=a._SYMBptr->feuille; + if (af.type!=_VECT) + return monomial_degree(af); + gen res(0); + for (unsigned i=0;isize();++i){ + res += monomial_degree((*af._VECTptr)[i]); + } + return res; + } + + static bool is_monomial(const gen & a){ + if (a.type<=_IDNT) + return true; + if (a.type!=_SYMB) + return false; + if (a._SYMBptr->sommet==at_pow) + return true; + if (a._SYMBptr->sommet!=at_prod && a._SYMBptr->sommet!=at_plus && a._SYMBptr->sommet!=at_neg && a._SYMBptr->sommet!=at_inv) + return false; + gen af=a._SYMBptr->feuille; + if (af.type!=_VECT) + return is_monomial(af); + for (unsigned i=0;isize();++i){ + if (!is_monomial((*af._VECTptr)[i])) + return false; + } + return true; + } + + static bool islesscomplexthanf2(const gen & a,const gen & b,GIAC_CONTEXT){ + if (a==b) + return false; + if (a.type==_VECT && b.type==_VECT && a._VECTptr->size()==2 && b._VECTptr->size()==2){ + gen & a2=a._VECTptr->back(); + gen & b2=b._VECTptr->back(); + if (a2!=b2) + return islesscomplexthanf2(a2,b2,contextptr); + } + if (is_monomial(a) && is_monomial(b)){ + gen da=monomial_degree(a); + gen db=monomial_degree(b); + if (da!=db) + return increasing_power(contextptr)?is_greater(db,da,contextptr):is_greater(da,db,contextptr); + bool apow=a.is_symb_of_sommet(at_pow); + bool bpow=b.is_symb_of_sommet(at_pow); + if (apow && !bpow) + return true; + if (bpow && !apow) + return false; + } + if (a.type==b.type) + return a.islesscomplexthan(b); + if (a.type==_FRAC && b.type>=_POLY) + return false; + if (a.type>=_POLY && b.type==_FRAC) + return true; + return !a.islesscomplexthan(b); + } + + struct f_compare_context { + bool (*f)(const gen &a,const gen &b,GIAC_CONTEXT); + const context * ptr; + f_compare_context():f(islesscomplexthanf2),ptr(context0){} + f_compare_context(bool (*f_)(const gen &a,const gen &b,GIAC_CONTEXT),GIAC_CONTEXT):f(f_),ptr(contextptr){} + inline bool operator () (const gen & a,const gen &b){ return f(a,b,ptr); } + }; + + void gen_sort_f_context(iterateur it,iterateur itend,bool (*f)(const gen &a,const gen &b,GIAC_CONTEXT),GIAC_CONTEXT){ + f_compare_context m(f,contextptr); + sort(it,itend,m); + } + + int gen::symb_size () const { + if (type==_SYMB) + return _SYMBptr->size(); + else + return 1; + } + + bool symb_size_less(const gen & a,const gen & b){ + return a.symb_size() < b.symb_size(); + } + + bool gen::is_symb_of_sommet(const unary_function_ptr & u) const { + return type==_SYMB && _SYMBptr->sommet==u; + } + + bool gen::is_symb_of_sommet(const unary_function_ptr * u) const { + return type==_SYMB && _SYMBptr->sommet==u; + } + + gen operator && (const gen & a,const gen & b){ + if (a.type==_VECT && b.type==_VECT && (a.subtype==_SET__VECT || b.subtype==_SET__VECT)) + return _intersect(makesequence(a,b),context0); + if (is_zero(a,context0)){ + if (b.type==_DOUBLE_) + return 0.0; + if (b.type==_FLOAT_) + return giac_float(0); + return change_subtype(!is_zero(a),_INT_BOOLEAN); + } + if (is_zero(b,context0)){ + if (a.type==_DOUBLE_ ) + return 0.0; + if (a.type==_FLOAT_) + return giac_float(0); + return change_subtype(!is_zero(b),_INT_BOOLEAN); + } + if (a.type<=_CPLX || a.type==_FLOAT_ || a.type==_FRAC){ + if (b.type<=_CPLX || b.type==_FLOAT_ || b.type==_FRAC) + return change_subtype(!is_zero(b),_INT_BOOLEAN); + return b; + } + if (b.type<=_CPLX || b.type==_FLOAT_ || b.type==_FRAC){ + if (a.type<=_CPLX || a.type==_FLOAT_ || a.type==_FRAC) + return change_subtype(!is_zero(a),_INT_BOOLEAN); + return a; + } + if (a.is_symb_of_sommet(at_and)){ + if (b.is_symb_of_sommet(at_and)) + return new_ref_symbolic(symbolic(at_and,gen(mergevecteur(*a._SYMBptr->feuille._VECTptr,*b._SYMBptr->feuille._VECTptr),_SEQ__VECT))); + vecteur v=*a._SYMBptr->feuille._VECTptr; + v.push_back(b); + return new_ref_symbolic(symbolic(at_and,v)); + } + if (b.is_symb_of_sommet(at_and)){ + vecteur v=*b._SYMBptr->feuille._VECTptr; + v.push_back(a); + return new_ref_symbolic(symbolic(at_and,v)); + } + if ( ((a.type==_IDNT) || (a.type==_SYMB)) || ((b.type==_IDNT) || (b.type==_SYMB)) ) + return symb_and(a,b); + if ( (a.type==_DOUBLE_) || (b.type==_DOUBLE_) ) + return 1.0; + if ( (a.type==_FLOAT_) || (b.type==_FLOAT_) ) + return giac_float(1); + return change_subtype(plus_one,_INT_BOOLEAN); + } + + gen operator || (const gen & a,const gen & b){ + if (a.type==_VECT && b.type==_VECT && (a.subtype==_SET__VECT || b.subtype==_SET__VECT)) + return _union(makesequence(a,b),context0); + if (is_zero(a,context0)) + return change_subtype(!is_zero(b),_INT_BOOLEAN); + if (is_zero(b,context0)) + return change_subtype(!is_zero(a),_INT_BOOLEAN); + if (a.is_symb_of_sommet(at_ou)){ + if (b.is_symb_of_sommet(at_ou)) + return new_ref_symbolic(symbolic(at_ou,gen(mergevecteur(*a._SYMBptr->feuille._VECTptr,*b._SYMBptr->feuille._VECTptr),_SEQ__VECT))); + vecteur v=*a._SYMBptr->feuille._VECTptr; + v.push_back(b); + return new_ref_symbolic(symbolic(at_ou,v)); + } + if (b.is_symb_of_sommet(at_ou)){ + vecteur v=*b._SYMBptr->feuille._VECTptr; + v.push_back(a); + return new_ref_symbolic(symbolic(at_ou,v)); + } + if ( ((a.type==_IDNT) || (a.type==_SYMB)) || ((b.type==_IDNT) || (b.type==_SYMB)) ) + return symb_ou(a,b); + if ( (a.type==_DOUBLE_) || (b.type==_DOUBLE_) ) + return 1.0; + if ( (a.type==_FLOAT_) || (b.type==_FLOAT_) ) + return giac_float(1); + return change_subtype(plus_one,_INT_BOOLEAN); + } + + gen collect(const gen & g,GIAC_CONTEXT){ + if (g.type==_VECT) + return apply(g,collect,contextptr); + if (is_inf(g)) + return g; + return liste2symbolique(symbolique2liste(g,contextptr)); + } + + static bool modified_islesscomplexthanf(const gen& a,const gen& b){ + if (a.type!=b.type && (a.type<=_CPLX || b.type<=_CPLX)) + return a.typefeuille,b._SYMBptr->feuille); + return modified_islesscomplexthanf(a._SYMBptr->feuille,b); + } + if (b.is_symb_of_sommet(at_neg)) + return modified_islesscomplexthanf(a,b._SYMBptr->feuille); + if (a.is_symb_of_sommet(at_inv)){ + if (b.is_symb_of_sommet(at_inv)) + return modified_islesscomplexthanf(a._SYMBptr->feuille,b._SYMBptr->feuille); + if (a._SYMBptr->feuille.type<_IDNT) + return modified_islesscomplexthanf(a._SYMBptr->feuille,b); + return false; + } + if (b.is_symb_of_sommet(at_inv)){ + if (b._SYMBptr->feuille.type<_IDNT) + return modified_islesscomplexthanf(a,b._SYMBptr->feuille); + return true; + } + if (a.is_symb_of_sommet(at_pow)){ + if (b.is_symb_of_sommet(at_pow)) + return modified_islesscomplexthanf(a._SYMBptr->feuille[0],b._SYMBptr->feuille[0]); + return modified_islesscomplexthanf(a._SYMBptr->feuille[0],b); + } + if (b.is_symb_of_sommet(at_pow)) + return modified_islesscomplexthanf(a,b._SYMBptr->feuille[0]); + if (a.type!=b.type){ + if (a.type==_FRAC && b.type>=_POLY) + return true; + if (b.type==_FRAC && a.type>=_POLY) + return false; + } + return islesscomplexthanf(a,b); + } + + class modified_compare { + public: + modified_compare(){} + bool operator ()(const gen &a,const gen &b){ return modified_islesscomplexthanf(a,b);} + }; + + // return true if a is -basis^exp + static bool power_basis_exp(const gen& a,gen & basis,gen & expa){ + if (a.is_symb_of_sommet(at_neg)) + return !power_basis_exp(a._SYMBptr->feuille,basis,expa); + if (a.is_symb_of_sommet(at_inv)){ + gen & tmp=a._SYMBptr->feuille; + bool b=power_basis_exp(tmp,basis,expa); + expa=-expa; + return b; + } // de-commented 2/2/2013 so that regrouper(x^2/x) works + if (a.is_symb_of_sommet(at_pow)){ + gen & tmp=a._SYMBptr->feuille; + if (tmp.type!=_VECT || tmp._VECTptr->size()!=2){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("power_basis_exp")); +#endif + return false; + } + expa=tmp._VECTptr->back(); + basis=tmp._VECTptr->front(); + } + else { + basis=a; + expa=plus_one; + } + return false; + } + + static gen regroup_inv(const vecteur & vtmp){ + vecteur vtmp1,vtmp2; + gen tt(1); + for (unsigned i=0;ifeuille); + else + vtmp1.push_back(vtmp[i]); + } + if (!vtmp1.empty()){ + if (vtmp1.size()==1) + tt=vtmp1.front(); + else + tt=new_ref_symbolic(symbolic(at_prod,gen(vtmp1,_SORTED__VECT))); + } + if (!vtmp2.empty()){ + if (vtmp2.size()==1) + tt=tt/vtmp2.front(); + else + tt=tt/new_ref_symbolic(symbolic(at_prod,gen(vtmp2,_SORTED__VECT))); + } + return tt; + } + + // Helpers for symbolic addition + // from a product returns a list with the numeric coeff and the monomial + static vecteur terme2unitaire(const gen & x,bool sorted,GIAC_CONTEXT){ + if (x.type<_POLY) + return makevecteur(x,plus_one); + gen tmp; + if (x.type!=_SYMB || x._SYMBptr->sommet==at_program || x._SYMBptr->sommet==at_when) + return makevecteur(1,x); + if (x._SYMBptr->sommet==at_neg){ + vecteur v=terme2unitaire(x._SYMBptr->feuille,sorted,contextptr); + v[0]=-v[0]; + return v; + } + if (x._SYMBptr->sommet==at_binary_minus){ + vecteur v=terme2unitaire(x._SYMBptr->feuille,sorted,contextptr); + v[1]=-v[1]; + return v; + } + if (x._SYMBptr->sommet==at_prod && (tmp=x._SYMBptr->feuille).type==_VECT && !tmp._VECTptr->empty() ){ + vecteur & v = *tmp._VECTptr; + int s=int(v.size()); + if (s==2 && (sorted || tmp.subtype==_SORTED__VECT)) + return makevecteur(v[0],v[1]); + vecteur vtmp(v.begin(),v.end()); + for (unsigned i=0;ifeuille.is_symb_of_sommet(at_pow)){ + gen f= vtmp[i]._SYMBptr->feuille._SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()==2) + vtmp[i]=symbolic(at_pow,makesequence(f._VECTptr->front(),-f._VECTptr->back())); + } + } + if (equalposcomp(vtmp,undef)) + return makevecteur(1,undef); + if (equalposcomp(vtmp,0)){ + if (equalposcomp(vtmp,unsigned_inf)) + return makevecteur(1,undef); + return makevecteur(0,plus_one); + } +#if 1 // def NSPIRE + // COUT << "modified " << (int) modified_islesscomplexthanf << '\n'; wait_key_pressed() ; + modified_compare m; + sort(vtmp.begin(),vtmp.end(),m); + // COUT << "after modified " << '\n'; wait_key_pressed() ; +#else + sort(vtmp.begin(),vtmp.end(),modified_islesscomplexthanf); +#endif + // collect term with the same power + const_iterateur it=vtmp.begin(),itend=vtmp.end(); + vecteur vsorted; + vsorted.reserve(itend-it); + gen precbasis,precexpo,basis,expo,constcoeff(plus_one); + for (;it!=itend;++it){ + if (it->type<=_CPLX) + constcoeff=constcoeff*(*it); + else { + if (it->is_symb_of_sommet(at_inv) && it->_SYMBptr->feuille.type<=_CPLX) + constcoeff=constcoeff/it->_SYMBptr->feuille; + else + break; + } + } + if (!is_one(constcoeff)) + vsorted.push_back(constcoeff); + bool isneg(false),hasneg(false); + if (it!=itend){ + power_basis_exp(*it,precbasis,precexpo); + precexpo=zero; + for (;it!=itend;++it){ + if (power_basis_exp(*it,basis,expo)){ + isneg=!isneg; + hasneg=true; + } + if (!vsorted.empty() && basis==vsorted.back()){ + vsorted.pop_back(); + expo+=1; + } + if (basis==precbasis) + precexpo=precexpo+expo; + else { + if (!is_zero(precexpo,contextptr)){ + if (is_strictly_positive(-precexpo,contextptr)) + vsorted.push_back(inv(pow(precbasis,-precexpo,contextptr),contextptr)); + else + vsorted.push_back(pow(precbasis,precexpo,contextptr)); + } + // vsorted.push_back(pow(precbasis,precexpo,contextptr)); + precbasis=basis; + precexpo=expo; + } + } + if (!is_zero(precexpo,contextptr)){ + if (is_strictly_positive(-precexpo,contextptr)){ + gen tmp=pow(precbasis,-precexpo,contextptr); + if (tmp.is_symb_of_sommet(at_prod)) + tmp=symbolic(at_inv,tmp); + else + tmp=inv(tmp,contextptr); + vsorted.push_back(tmp); + } + else + vsorted.push_back(pow(precbasis,precexpo,contextptr)); + } + } + vecteur res; + if (hasneg){ + res=terme2unitaire(_prod(vsorted,contextptr),sorted,contextptr); + if (isneg) + res[0]=-res[0]; + return res; + } + if (vsorted.empty()) + vsorted.push_back(1); + if (vsorted.front().type<_POLY || vsorted.front().type==_FRAC){ + vtmp=vecteur(vsorted.begin()+1,vsorted.end()); + gen tt(1); + if (!vtmp.empty()){ + if (vtmp.size()==1) + tt=vtmp.front(); + else + tt=regroup_inv(vtmp); + } + res=makevecteur(vsorted.front(),tt); + } + else + res=makevecteur(plus_one,regroup_inv(vsorted)); + return res; + } + // recurse + if (x._SYMBptr->sommet==at_pow) + return makevecteur(plus_one,x._SYMBptr->sommet(collect(x._SYMBptr->feuille,contextptr),contextptr)); + tmp=collect(x._SYMBptr->feuille,contextptr); + if (x._SYMBptr->sommet==at_inv){ + if (is_zero(tmp)) + return makevecteur(1,unsigned_inf); + } + return makevecteur(plus_one,new_ref_symbolic(symbolic(x._SYMBptr->sommet,tmp))); + } + + // assumes v is a sorted list, shrink it + // should be written to a gen of type _VECT and subtype _SORTED__VECT + static vecteur fusionliste(const vecteur & v){ + const_iterateur it=v.begin(),itend=v.end(); + if (itend-it<2) + return v; + vecteur res; + gen current=(*it)[1]; + gen current_coeff=(*it)[0]; + ++it; + for (;it!=itend;++it){ + if ((*it)[1].type!=current.type || (current.type==_DOUBLE_ && current._DOUBLE_val!=(*it)[1]._DOUBLE_val) || (*it)[1]!=current ){ + res.push_back(makenewvecteur(current_coeff,current)); + current_coeff=(*it)[0]; + current=(*it)[1]; + } + else + current_coeff=current_coeff+(*it)[0]; + } + res.push_back(makenewvecteur(current_coeff,current)); + return res; + } + + struct tri_context { + const context * contextptr; + bool operator()(const gen & a,const gen &b){ return islesscomplexthanf2(a,b,contextptr); } + tri_context(const context * ptr):contextptr(ptr){}; + tri_context():contextptr(0){}; + }; + + // from a sum in x returns a list of [coeff monomial] + // e.g. 5+2x+3*x*y -> [ [5 1] [2 x] [ 3 x*y] ] + vecteur symbolique2liste(const gen & x,GIAC_CONTEXT){ + if (!x.is_symb_of_sommet(at_plus)) + return vecteur(1,terme2unitaire(x,false,contextptr)); + bool sorted=x._SYMBptr->feuille.subtype==_SORTED__VECT; + gen number; + vecteur varg=gen2vecteur(x._SYMBptr->feuille); + vecteur vres; + const_iterateur it=varg.begin(),itend=varg.end(); + for (;it!=itend;++it){ + if (it->type<_POLY || it->type==_FRAC) + number=number+(*it); + else + vres.push_back(terme2unitaire(*it,sorted,contextptr)); + } + if (!is_exactly_zero(number)) + vres.push_back(makenewvecteur(1,number)); + if (x._SYMBptr->feuille.subtype==_SORTED__VECT) + return vres; + sort(vres.begin(),vres.end(),tri_context(contextptr)); + return fusionliste(vres); + } + + /* + // assumes v1, v2 are sorted and shrinked, merge them -> sorted and shrinked + static vecteur fusion2liste(const vecteur & v1,const vecteur & v2){ + const_iterateur it=v1.begin(),itend=v1.end(),jt=v2.begin(),jtend=v2.end(); + vecteur res; + gen tmp; + for (;it!=itend;){ + if (jt==jtend){ + for (;it!=itend;++it) + res.push_back(*it); + return res; + } + // both iterator are valid + vecteur & vi=*it->_VECTptr; + vecteur & vj=*jt->_VECTptr; + if (vi[1]==vj[1]){ + tmp=vi[0]+vj[0]; + if (!is_exactly_zero(tmp)) + res.push_back(makenewvecteur(tmp,vi[1])); + ++it; + ++jt; + } + else { + if (vi[1].islesscomplexthan(vj[1])){ + res.push_back(*it); + ++it; + } + else { + res.push_back(*jt); + ++jt; + } + } // end tests + } // end for loop + // finish jt + for (;jt!=jtend;++jt) + res.push_back(*jt); + return res; + } + */ + + // v should be sorted and shrinked + gen liste2symbolique(const vecteur & v){ + vecteur res; + const_iterateur it=v.begin(),itend=v.end(); + res.reserve(itend-it); + for (;it!=itend;++it){ + vecteur & vtmp(*it->_VECTptr); + gen & tmp = vtmp.back(); + gen coeff=eval(vtmp.front(),1,context0); + if (is_exactly_zero(coeff)) + continue; + if (tmp.is_symb_of_sommet(at_prod) && tmp._SYMBptr->feuille.type==_VECT && tmp._SYMBptr->feuille._VECTptr->size()==1){ + res.push_back(coeff*tmp._SYMBptr->feuille._VECTptr->front()); + continue; + } + if (coeff.is_symb_of_sommet(at_neg)){ + res.push_back(-(coeff._SYMBptr->feuille*tmp)); + continue; + } + if ( (coeff.type==_FRAC || is_integer(coeff)) && is_positive(-coeff,context0)) + res.push_back(-((-coeff)*tmp)); + else + res.push_back(coeff*tmp); + } + int s=int(res.size()); + if (!s) + return zero; + if (s==1) + return res.front(); + return new_ref_symbolic(symbolic(at_plus,gen(res,_SORTED__VECT))); + } + + /* Euclidean-like Arithmetic */ + static void swap(int & a,int & b){ + int t=a; + a=b; + b=t; + } + +#ifndef TICE + int absint(int a){ + if (a<0){ + if (a==-2147483648) + return 2147483647; // better than returning -2147483648 + return -a; + } + else + return a; + } + + double absdouble(double a){ + if (a<0) + return -a; + else + return a; + } + + int giacmin(int a, int b){ + if (a0){ + if (n%2) + c=(c*b)%m; + n /= 2; + b=(b*b)%m; + } + } + else { + while (n>0){ + if (n%2) + c=(c*longlong(b))%m; + n /= 2; + b=(b*longlong(b))%m; + } + } + return c; + } + + int smod(int r,int m){ + if (m<=0){ + if (!m) + return r; + m=-m; + } + r = r % m; +#if 1 + r += (unsigned(r)>>31)*m; // make positive + return r-(unsigned((m>>1)-r)>>31)*m; +#else + longlong tmp= longlong(r)+r; + if (tmp>m) + return r-m; + if (tmp<=-m) + return r+m; + return r; +#endif + } + + int smod(longlong r,int m){ + int R=r%m; + R += (unsigned(R)>>31)*m; // make positive + int res2=R-(unsigned((m>>1)-R)>>31)*m; + return res2; + int res1=(R>m/2)?R-m:R; + if (res1!=res2) + CERR << "smod longlong " << r << " " << m << '\n'; + return res1; + //return smod(R,m); + } + + longlong smodll(longlong a,longlong b){ + longlong r=a%b; + if (r>b/2) + r -= b; + else { + if (r<=-b/2) + r += b; + } + return r; + } + + int gcd(int a,int b){ + if (a!=b){ + int r; + while (b){ + r=a%b; + a=b; + b=r; + } + } + return absint(a); + } + +#if defined(EMCC) || defined(EMCC2) + void my_mpz_gcd(mpz_t &z,const mpz_t & A,const mpz_t & B){ + mpz_t a,b; + mpz_init_set(a,A); + mpz_init_set(b,B); + while (mpz_cmp_si(b,0)){ + mpz_tdiv_r(z,a,b); + mpz_swap(a,b); + mpz_swap(b,z); + } + mpz_set(z,a); + mpz_abs(z,z); + mpz_clear(a); + mpz_clear(b); + } + void my_mpz_gcdext(mpz_t & d,mpz_t & u,mpz_t &v,const mpz_t & a,const mpz_t & b){ + mpz_t q,r1,r2,u1,u2,v1,v2; + // mpz_t r3,u3,v3; + mpz_init_set(r1,a); mpz_init_set(r2,b); + mpz_init_set_ui(u1,1); mpz_init_set_ui(u2,0); + mpz_init_set_ui(v1,0); mpz_init_set_ui(v2,1); + mpz_init(q); + // mpz_init(r3); mpz_init(u3); mpz_init(v3); + while (mpz_cmp_si(r2,0)){ + // CERR << "iegcd " << gen(r1) << " " << gen(r2) << '\n'; + mpz_tdiv_qr(q,r1,r1,r2); + mpz_swap(r1,r2); + mpz_submul(u1,q,u2); + mpz_swap(u1,u2); + mpz_submul(v1,q,v2); + mpz_swap(v1,v2); + } + if (mpz_cmp_si(r1,0)<0){ + mpz_neg(r1,r1); mpz_neg(u1,u1); mpz_neg(v1,v1); + } + mpz_swap(d,r1); mpz_swap(u,u1); mpz_swap(v,v1); +#if 0 // debugging + CERR << gen(d) << " " << gen(u) << " " << gen(v) << '\n'; + mpz_gcdext(d,u,v,a,b); + CERR << gen(d) << " " << gen(u) << " " << gen(v) << '\n'; +#endif + mpz_clear(q); mpz_clear(r1); mpz_clear(r2); + mpz_clear(u1); mpz_clear(u2); + mpz_clear(v1); mpz_clear(v2); + // mpz_clear(u3); mpz_clear(v3); mpz_clear(r3); + } + bool my_mpz_invert(mpz_t & ainv,const mpz_t & a,const mpz_t & m){ + mpz_t d,v; + mpz_init(d); mpz_init(v); + my_mpz_gcdext(d,ainv,v,a,m); + mpz_clear(v); + bool ok=mpz_cmp_si(d,1)==0; + mpz_clear(d); + return ok; + } +#else + void my_mpz_gcd(mpz_t &z,const mpz_t & a,const mpz_t & b){ + mpz_gcd(z,a,b); + } + void my_mpz_gcdext(mpz_t & d,mpz_t & u,mpz_t &v,const mpz_t & a,const mpz_t & b){ + mpz_gcdext(d,u,v,a,b); + } + bool my_mpz_invert(mpz_t & ainv,const mpz_t & a,const mpz_t & m){ + return mpz_invert(ainv,a,m)!=0; + } +#endif + + int simplify(int & a,int & b){ + int d=gcd(a,b); + a=a/d; + b=b/d; + return d; + } + + static gen _CPLXgcd(const gen & a,const gen & b){ // a & b must be gen + if (!is_cinteger(a) || !is_cinteger(b) ) + return plus_one; + gen acopy(a),bCopy(b),r; + for (;;){ + if (is_exactly_zero(bCopy)){ +#if 0 + complex c=gen2complex_d(acopy); + double d=arg(c); + int quadrant=int(std::floor((2*d)/M_PI)); + reim(acopy,bCopy,r,context0); + if (!is_positive(-bCopy,context0)){ + if (is_positive(r,context0)){ + if (quadrant!=0) + CERR << "cplxgcd 0 " << acopy << "\n"; + return acopy; + } + if (quadrant!=-1) + CERR << "cplxgcd -1 " << acopy << "\n"; + // re>=0, im<0 + return acopy*cst_i; + } + else { + if (is_positive(-r,context0)){ + if (is_zero(bCopy)) + return -r; + if (quadrant!=-2 && quadrant!=2) + CERR << "cplxgcd 2 " << acopy << "\n"; + return -acopy; + } + if (is_zero(bCopy)) + return r; + if (quadrant!=1) + CERR << "cplxgcd 1 " << acopy << "\n"; + return -acopy*cst_i; + } +#else + complex c=gen2complex_d(acopy); + double d=arg(c); + int quadrant=int(std::floor((2*d)/M_PI)); + switch (quadrant){ + case 0: + return acopy; + case 1: + return acopy*(-cst_i); + case -1: + return acopy*cst_i; + case 2: case -2: + return -acopy; + default: + return acopy; + } +#endif + } + r=acopy%bCopy; + acopy=bCopy; + bCopy=r; + } + } + + static gen polygcd(const polynome & a,const polynome & b){ + ref_polynome * resptr=new ref_polynome(a.dim); + gcd(a,b,resptr->t); + return resptr; + } + + // gcd(undef,x)=x to be used inside series + static gen symgcd(const gen & a,const gen& b,GIAC_CONTEXT){ + if (is_exactly_zero(a) || is_undef(a) || (is_one(b))) + return b; + if (is_one(a) || is_undef(b) || (is_exactly_zero(b))) + return a; + if (a==b) + return a; + if ( (a.type==_MOD) && (b.type==_MOD) && (a._MODptr->type<=_CPLX) && (b._MODptr->type<= _CPLX) ) + return chkmod(plus_one,a); + if (a.type==_MOD || b.type==_MOD || a.type==_DOUBLE_ || a.type==_FLOAT_ || a.type==_REAL || b.type==_DOUBLE_ || b.type==_FLOAT_ || b.type==_REAL ) + return plus_one; + if ( (a.type==_POLY) && (b.type==_POLY) ) + return polygcd(*a._POLYptr,*b._POLYptr); + if ( (a.type==_EXT) && (b.type ==_EXT) ){ + if ( (*(a._EXTptr+1)!=*(b._EXTptr+1)) || (a._EXTptr->type!=_VECT) || (b._EXTptr->type!=_VECT) ) + return plus_one; + environment *env=new environment; + vecteur g=gcd(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,env); + delete env; + return ext_reduce(g,*(a._EXTptr+1)); + } + if ( (a.type==_FRAC) || (b.type==_FRAC)) + return plus_one; + if (a.type==_EXT){ + if (a._EXTptr->type!=_VECT) + return gentypeerr(gettext("symgcd")); + if ( (a._EXTptr+1)->type!=_VECT) + return symgcd(ext_reduce(a),b,contextptr); + gen aa(lgcd(*a._EXTptr->_VECTptr)); + gen res=gcd(aa,b,contextptr),b2(rdiv(b,res,contextptr)); + if (is_one(b2) || is_minus_one(b2))// || b2.type==_POLY) + return res; + vecteur ua,u,v,dd; + divvecteur(*(a._EXTptr->_VECTptr),aa,ua); + const vecteur & uv=*((a._EXTptr+1)->_VECTptr); + egcd(ua,uv,0,u,v,dd); + // u and v are not used but we can't use gcd here because we want to + // "factor" dd=extension(ua,uv)*extension(u,uv) + gen dd0(dd.front()); + simplify(b2,dd0); + if (is_one(dd0)){ + res=res*algebraic_EXTension(ua,*(a._EXTptr+1)); + if (0) return res; + // changed 2025 April 22 for factor(โˆš(-5*(โˆš(92*x^2-12*x+45)*abs(x)+(-2*โˆš5)*x^2+(-3*โˆš5)*x)/โˆš5/36)); +#ifndef NO_STDEXCEPT + try { + gen resf=evalf(res,1,contextptr); + if (is_positive(-resf,contextptr)) + res=-res; + } catch (std::runtime_error&e){ + *logptr(contextptr) << "Previous error catched\n"; + } +#endif + } + return res; + } + if (b.type==_EXT) + return symgcd(b,a,contextptr); + if (a.type==_POLY) + return gcd(*a._POLYptr,polynome(b,a._POLYptr->dim)); + if (b.type==_POLY) + return gcd(*b._POLYptr,polynome(a,b._POLYptr->dim)); + if ( a.type!=_DOUBLE_ && a.type!=_FLOAT_ && a.type!=_VECT && b.type!=_DOUBLE_ && b.type!=_FLOAT_ && b.type!=_VECT ) + return rationalgcd(a,b,contextptr); + return plus_one; // return gentypeerr(gettext("symgcd")); + } + + gen simplify(gen & n, gen & d){ + if ( (d.type==_DOUBLE_ || d.type==_FLOAT_) || + ( (d.type==_CPLX) && + ((d._CPLXptr->type==_DOUBLE_ || d._CPLXptr->type==_FLOAT_) || + ((d._CPLXptr+1)->type==_DOUBLE_ || (d._CPLXptr+1)->type==_FLOAT_)) ) + ){ + gen dd=no_context_evalf(d); + gen nn=no_context_evalf(n); + // if (d==dd && n==nn) return 1; // avoid infinite recursion? + n=rdiv(nn,dd,context0); + d=plus_one; + return dd; + } + if ( (n.type==_DOUBLE_ || n.type==_FLOAT_) || + ( (n.type==_CPLX) && + ((n._CPLXptr->type==_DOUBLE_ || n._CPLXptr->type==_FLOAT_) || + ((n._CPLXptr+1)->type==_DOUBLE_ || (n._CPLXptr+1)->type==_FLOAT_)) ) + ){ + gen nn=no_context_evalf(n); + n=plus_one; + d=rdiv(no_context_evalf(d),nn,context0); + return nn*simplify(n,d); + } + if (n.type==_FRAC || d.type==_FRAC) + return plus_one; + if (is_one(d)) + return d; + if (is_zero(d)){ + n=undef; + d=1; + return n; + } + if (is_zero(n)){ + gen tmp=d; + d=1; + return tmp; + } + if ( (n.type==_MOD) && (d.type!=_MOD) ) + d=makemod(d,*(n._MODptr+1)); + if (d.type==_MOD){ + if (d._MODptr->is_cinteger()){ + gen dd(d); + n=n*inv(dd,context0); + d=makemodquoted(plus_one,*(d._MODptr+1)); + return dd; + } + } + if (is_one(n)) + return n; + if ((n.type==_POLY) && (d.type==_POLY)){ + polynome np(*n._POLYptr),dp(*d._POLYptr); + if (np.dim && dp.dim && np.dim!=dp.dim) + return gensizeerr(gettext("simplify: Polynomials do not have the same dimension")); + polynome g(np.dim); + g=simplify(np,dp); + n=np; + d=dp; + return g; + } + if (n.type==_VECT){ + if (d.type==_VECT){ + environment * env=new environment; + vecteur g=gcd(*n._VECTptr,*d._VECTptr,env); + delete env; + n=gen(*n._VECTptr/g,_POLY1__VECT); + d=gen(*d._VECTptr/g,_POLY1__VECT); + return gen(g,_POLY1__VECT); + } + gen gg=lgcd(*n._VECTptr,d); + if (!is_one(gg)){ + n=divvecteur(*n._VECTptr,gg); + d=d/gg; + } + return gg; + // old code + gen nd=_gcd(n,context0); + gen g=simplify(nd,d); + if (!is_one(g)) n=divvecteur(*n._VECTptr,g); + return g; + } + if (d.type==_VECT){ + gen dd=_gcd(d,context0); + gen g=simplify(n,dd); + d=divvecteur(*d._VECTptr,g); + return g; + } + if (d.type==_EXT){ + if ( (d._EXTptr->type==_INT_) || (d._EXTptr->type==_ZINT) ){ + n=n*inv(d,context0); + gen d_copy=d; + d=1; + return d_copy; + } + if ( (d._EXTptr+1)->type==_EXT || (d._EXTptr+1)->type==_FRAC){ + d=ext_reduce(d); + return simplify(n,d); + } + if (d._EXTptr->type==_VECT){ + vecteur u,v,dd; + if ( (d._EXTptr+1)->type!=_VECT) + return gensizeerr(gettext("gen.cc:simplify")); + egcd(*(d._EXTptr->_VECTptr),*((d._EXTptr+1)->_VECTptr),0,u,v,dd); + gen tmp=algebraic_EXTension(u,*((d._EXTptr+1)->_VECTptr)); + if (tmp.type!=_EXT){ + return gensizeerr(gettext("gen.cc:simplify/tmp.type!=_EXT")); + // return 1; + } + n=n*tmp; + d=d*tmp; + return simplify(n,d)*inv_EXT(tmp); + } + return gentypeerr(gettext("simplify")); + } + if (n.type==_EXT){ + gen n_EXT=*n._EXTptr; + gen g=simplify(n_EXT,d); + n=algebraic_EXTension(n_EXT,*(n._EXTptr+1)); + return g; + } + if (n.type==_POLY) { + return simplify3(n,d); // changed made 18 dec 2016 for speed + polynome np(*n._POLYptr),dp(d,n._POLYptr->dim); + polynome g(np.dim); + g=simplify(np,dp); + n=np; + d=dp; + return g; + } + if (d.type==_POLY){ + polynome np(n,d._POLYptr->dim),dp(*d._POLYptr); + polynome g(np.dim); + g=simplify(np,dp); + n=np; + d=dp; + return g; + } + vecteur l(lvar(n)); + lvar(d,l); + gen num=e2r(n,l,context0),den=e2r(d,l,context0),g=gcd(num,den,context0); // ok + den=rdiv(den,g,context0); + if (is_exactly_zero(re(den,context0))){ //ok + den=cst_i*den; + g=-cst_i*g; + } + if (is_positive(-den,context0)){ // ok + den=-den; + g=-g; + } + n=r2sym(rdiv(num,g,context0),l,context0); // ok + d=r2sym(den,l,context0); // ok + return r2sym(g,l,context0); // ok + } + + gen gcd(const gen & a,const gen & b){ + return gcd(a,b,context0); + } + gen gcd(const gen & a,const gen & b,GIAC_CONTEXT){ + ref_mpz_t * res; + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: + return(gcd(a.val,b.val)); + case _INT___ZINT: + if (a.val) + return(int(mpz_gcd_ui(NULL,*b._ZINTptr,absint(a.val)))); + else + return is_positive(b,contextptr)?b:-b; + case _ZINT__INT_: + if (b.val) + return(int(mpz_gcd_ui(NULL,*a._ZINTptr,absint(b.val)))); + else + return is_positive(a,contextptr)?a:-a; + case _ZINT__ZINT: +#if !defined USE_GMP_REPLACEMENTS && !defined BF2GMP_H + { + int test=mpz_cmp(*a._ZINTptr,*b._ZINTptr); + if (test==0 || (test>0 && mpz_divisible_p(*a._ZINTptr,*b._ZINTptr))) + return abs(b,contextptr); + if (test<0 && mpz_divisible_p(*b._ZINTptr,*a._ZINTptr)) + return abs(a,contextptr); + } +#endif + res = new ref_mpz_t; + my_mpz_gcd(res->z,*a._ZINTptr,*b._ZINTptr); + return(res); + case _INT___CPLX: case _ZINT__CPLX: + case _CPLX__INT_: case _CPLX__ZINT: + case _CPLX__CPLX: + return _CPLXgcd(a,b); + case _POLY__POLY: + return polygcd(*a._POLYptr,*b._POLYptr); + case _VECT__VECT: + return gen(gcd(*a._VECTptr,*b._VECTptr,0,ntl_on(contextptr) && a._VECTptr->size()>=NTL_MODGCD && b._VECTptr->size()>=NTL_MODGCD),_POLY1__VECT); + case _FRAC__FRAC: + return fraction(gcd(a._FRACptr->num,b._FRACptr->num,contextptr),lcm(a._FRACptr->den,b._FRACptr->den)); + default: + if (a.type==_FRAC) + return fraction(gcd(a._FRACptr->num,b,contextptr),a._FRACptr->den); + if (b.type==_FRAC) + return fraction(gcd(b._FRACptr->num,a,contextptr),b._FRACptr->den); + if (a.type==_USER) + return a._USERptr->gcd(b); + if (b.type==_USER) + return b._USERptr->gcd(a); + { + gen aa(a),bb(b); + if (is_integral(aa) && is_integral(bb)) + return gcd(aa,bb,contextptr); + } + return symgcd(a,b,contextptr); + } + } + + gen lcm(const gen & a,const gen & b){ + return normal(rdiv(a,gcd(a,b,context0),context0),context0)*b; // ok + } + + static void ciegcd(const gen &a_orig,const gen &b_orig, gen & u,gen &v,gen &d ){ + gen a(a_orig),b(b_orig),au(plus_one),bu(zero),q,r,ru; + while (!is_exactly_zero(b)){ + q=iquo(a,b); + r=a-b*q; + a=b; + b=r; + ru=au-bu*q; + au=bu; + bu=ru; + } + u=au; + d=a; + v=iquo(d-a_orig*u,b_orig); + } + + int iegcd(int a_,int b_,int &u,int & v){ + int a(a_),b(b_),au(1),bu(0),r,ru; + longlong q; + while (b){ + q=a/b; + r=a-b*q; + a=b; + b=r; + ru=au-bu*q; + au=bu; + bu=ru; + } + u=au; + v=(a-longlong(a_)*u)/b_; + return a; + } + + void egcd(const gen &ac,const gen &bc, gen & u,gen &v,gen &d ){ + gen a(ac),b(bc); + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: case _INT___ZINT: case _ZINT__INT_: case _ZINT__ZINT: + if (a.type==_INT_) + a.uncoerce(); + if (b.type==_INT_) + b.uncoerce(); + if (!u.type) + u.uncoerce(); + if (!v.type) + v.uncoerce(); + if (!d.type) + d.uncoerce(); + my_mpz_gcdext(*d._ZINTptr,*u._ZINTptr,*v._ZINTptr,*a._ZINTptr,*b._ZINTptr); + if (mpz_sizeinbase(*u._ZINTptr,2)<32) + u=mpz_get_si(*u._ZINTptr); + if (mpz_sizeinbase(*v._ZINTptr,2)<32) + v=mpz_get_si(*v._ZINTptr); + if (mpz_sizeinbase(*d._ZINTptr,2)<32) + d=mpz_get_si(*d._ZINTptr); + break; + default: + ciegcd(a,b,u,v,d); + break; + } + } + + static void _ZINTmod (const gen & a,const gen & b,ref_mpz_t * & rem){ + if (is_strictly_positive(-b,context0)) + return _ZINTmod(a,-b,rem); + // at least one is not an int, uncoerce remaining int + ref_mpz_t *aptr,*bptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr=new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + if (b.type!=_INT_) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &b) >> 16); +#else + bptr=b.__ZINTptr; +#endif + else { + bptr=new ref_mpz_t; + mpz_set_si(bptr->z,b.val); + } + rem=new ref_mpz_t; + mpz_tdiv_r(rem->z,aptr->z,bptr->z); + if (a.type==_INT_) + delete aptr; + if (b.type==_INT_) + delete bptr; + } + + gen operator %(const gen & a,const gen & b){ + ref_mpz_t * rem; + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: + if (b.val) + return(a.val % b.val); + else + return a.val; + case _ZINT__ZINT: case _INT___ZINT: case _ZINT__INT_: + _ZINTmod(a,b,rem); + return(rem); + case _CPLX__INT_: case _CPLX__ZINT: + return gen(smod((*a._CPLXptr), b), smod(*(a._CPLXptr+1), b) ); + case _INT___CPLX: case _ZINT__CPLX: case _CPLX__CPLX: + return(a-b*iquo(a,b)); + case _VECT__VECT: + return gen((*a._VECTptr)%(*b._VECTptr),_POLY1__VECT); + default: + return gentypeerr(gettext("%")); + } + return 0; + } + + bool is_multiple(const gen & a,const gen &b){ + if (a.type==_INT_){ + if (b.type!=_INT_) + return false; + return a.val%b.val==0; + } + if (a.type!=_ZINT) + return false; + if (b.type==_INT_) + return modulo(*a._ZINTptr,b.val)==0; + return a%b==0; + } + + static void _ZINTrem(const gen & a,const gen &b,gen & q,ref_mpz_t * & rem){ + // COUT << a << " irem " << b << '\n'; + ref_mpz_t *aptr,*bptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + if (b.type!=_INT_) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &b) >> 16); +#else + bptr=b.__ZINTptr; +#endif + else { + bptr = new ref_mpz_t; + mpz_set_si(bptr->z,b.val); + } + rem=new ref_mpz_t; + q.uncoerce(); + mpz_tdiv_qr(*q._ZINTptr,rem->z,aptr->z,bptr->z); + if (a.type==_INT_) + delete aptr; + if (b.type==_INT_) + delete bptr; + } + + gen irem(const gen & a,const gen & b,gen & q){ + ref_mpz_t * rem; + register int r; + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: + if (!b.val) + return a; + r=a.val % b.val; + /* + if (r<0){ + if (b.val>0){ + q=gen(a.val/b.val-1); + r += b.val; + } + else { + q=gen(a.val/b.val+1); + r -= b.val; + } + } + else + */ + q=gen(a.val/b.val); + return r; + case _ZINT__ZINT: case _INT___ZINT: case _ZINT__INT_: + _ZINTrem(a,b,q,rem); + return(rem); + case _INT___CPLX: case _ZINT__CPLX: case _CPLX__CPLX: case _CPLX__INT_: case _CPLX__ZINT: + q=iquo(a,b); + return(a-b*q); + default: + return gentypeerr(gettext("irem")); + } + return 0; + } + + static void _ZINTsmod(const gen & a, const gen & b, ref_mpz_t * & rem){ + // at least one is not an int, uncoerce remaining int + ref_mpz_t *aptr,*bptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + if (b.type!=_INT_) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &b) >> 16); +#else + bptr=b.__ZINTptr; +#endif + else { + bptr = new ref_mpz_t; + mpz_set_si(bptr->z,b.val); + } + rem = new ref_mpz_t; + mpz_t rem1,rem2,rem3; + mpz_init(rem1); mpz_init(rem2); mpz_init(rem3); + mpz_mod(rem1,aptr->z,bptr->z); // rem1 positive remainder + if (mpz_sgn(bptr->z)>0) + mpz_sub(rem2,rem1,bptr->z); // negative remainder + else + mpz_add(rem2,rem1,bptr->z); + // choose smallest one in abs value + mpz_neg(rem3,rem2); + if (mpz_cmp(rem1,rem3)>0) + mpz_set(rem->z,rem2); + else + mpz_set(rem->z,rem1); + if (a.type==_INT_) + delete aptr; + if (b.type==_INT_) + delete bptr; + mpz_clear(rem1); mpz_clear(rem2); mpz_clear(rem3); + } + + void smod(const vecteur & v,const gen & g,vecteur & w){ + const_iterateur it=v.begin(),itend=v.end(); + w.resize(itend-it); + iterateur jt=w.begin(); + for (;it!=itend;++jt,++it) + *jt=smod(*it,g); + } + + vecteur smod(const vecteur & v,const gen & g){ + vecteur w(v); + smod(w,g,w); + return w; + } + + static gen smodSYMB(const gen & a,const gen & b){ + vecteur lv(lvar(a)); + gen n,d,f; + f=e2r(a,lv,context0); // ok + fxnd(f,n,d); + n=smod(n,b); + d=smod(d,b); + f=n/d; + return r2e(f,lv,context0); // ok + } + + static gen fixfracmod(const gen & res, int modulo){ + gen n=res._FRACptr->num,d=res._FRACptr->den; + if (n.type!=_POLY) + return res; + if (d.type==_INT_) + return invmod(d.val,modulo)*n; + if (d.type!=_POLY) + return res; + polynome np=*n._POLYptr,dp=*d._POLYptr,tmp,quo,rem; + np=smod(np,modulo); + tmp=gcdmod(np,dp,modulo); + divremmod(np,tmp,modulo,quo,rem); + np=quo; + divremmod(dp,tmp,modulo,quo,rem); + dp=quo; + if (is_one(dp)) + return np; + return fraction(np,dp); + } + + gen smod(const gen & a,const gen & b){ + if (b.type==_INT_ && b.val==0) + return a; + ref_mpz_t * rem; + switch ( (a.type<< _DECALAGE) | b.type ) { + case _INT___INT_: + return smod(a.val,b.val); + case _ZINT__INT_: + return smod(modulo(*a._ZINTptr,absint(b.val)),b.val); + case _INT___ZINT: case _ZINT__ZINT: + _ZINTsmod(a,b,rem); + return(rem); + case _CPLX__INT_: case _CPLX__ZINT: + return gen(smod(*a._CPLXptr,b),smod(*(a._CPLXptr+1),b)); + case _POLY__INT_: case _POLY__ZINT: + return smod(*a._POLYptr,b); + case _VECT__INT_: case _VECT__ZINT: + if (a.ref_count()==1){ + smod(*a._VECTptr,b,*a._VECTptr); + if (a.subtype==_POLY1__VECT) + *a._VECTptr=trim(*a._VECTptr,0); + return a; + } + { + gen res(new_ref_vecteur(*a._VECTptr),a.subtype); + smod(*res._VECTptr,b,*res._VECTptr); + if (a.subtype==_POLY1__VECT) + *res._VECTptr=trim(*res._VECTptr,0); + return res; + } + default: + if (a.type==_SYMB) + return smodSYMB(a,b); + if (a.type==_FRAC && is_integer(b) && is_integer(a._FRACptr->den)) + return smod(a._FRACptr->num*invmod(a._FRACptr->den,b),b); + if (a.type==_FRAC && b.type==_INT_) + return fixfracmod(a,b.val); + if ( (b.type==_INT_) || (b.type==_ZINT) ) + return a; + // error, b must be _DOUBLE_ +#ifndef NO_STDEXCEPT + throw(std::runtime_error("smod 2nd argument must be _DOUBLE_")); +#endif + return undef; + } + } + + static bool _ZINTinvmod(const gen & a,const gen & modulo, ref_mpz_t * & res){ + ref_mpz_t *aptr,*bptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr = a.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + if (modulo.type) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &modulo) >> 16); +#else + bptr = modulo.__ZINTptr; +#endif + else { + bptr = new ref_mpz_t; + mpz_set_si(bptr->z,modulo.val); + } + res = new ref_mpz_t; + bool ok=my_mpz_invert(res->z,aptr->z,bptr->z)!=0; + if (a.type==_INT_) + delete aptr; + if (!modulo.type) + delete bptr; + if (!ok){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Not invertible ")+a.print(context0)+" mod "+modulo.print(context0)); +#endif + delete res; + res=0; + return false; + } + return true; + } + + gen invmod(const gen & a,const gen & modulo){ + if (a.type==_USER) + return a._USERptr->inv(); + if (a.type==_MOD){ + if (*(a._MODptr+1)!=modulo) + return gensizeerr("Incompatible modulo "+a.print(context0)+","+modulo.print(context0)); + return inv(a,context0); + } + if (a.type==_CPLX){ + gen r=re(a,context0),i=im(a,context0); // ok + gen n=invmod(r*r+i*i,modulo); + return smod(r*n,modulo)-cst_i*smod(i*n,modulo); + } + if (a.type==_POLY) + return fraction(1,a); + ref_mpz_t * res; + switch ( (a.type<< _DECALAGE) | modulo.type) { + case _INT___INT_: + return(invmod(a.val,modulo.val)); + case _INT___ZINT: case _ZINT__INT_: case _ZINT__ZINT: + if (!_ZINTinvmod(a,modulo,res)) + return gentypeerr(gettext("invmod")); + return gen(res); + default: + return gentypeerr(gettext("invmod")); + } + return 0; + } + + bool in_fracmod(const gen &m,const gen & a,mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t &u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t &sqrtm,mpz_t & tmp,gen & num,gen & den){ + mpz_set(d,*m._ZINTptr); + mpz_set(d1,*a._ZINTptr); + mpz_set_si(u,0); + mpz_set_si(u1,1); + mpz_tdiv_q_2exp(q,*m._ZINTptr,1); + mpz_sqrt(sqrtm,q); + // int signe; + for (;;){ + mpz_abs(absd1,d1); + if (mpz_cmp(absd1,sqrtm)<=0) + break; + mpz_fdiv_qr(q,r,d,d1); + // u-q*u1->ur, v-q*v1->vr + mpz_mul(tmp,q,u1); + mpz_sub(ur,u,tmp); + // u1 -> u, ur -> u1 ; v1 -> v, vr -> v1, d1 -> d, r -> d1 +#ifdef USE_GMP_REPLACEMENTS + mpz_set(u,u1); + mpz_set(u1,ur); + mpz_set(d,d1); + mpz_set(d1,r); +#else + mpz_swap(u,u1); + mpz_swap(u1,ur); + mpz_swap(d,d1); + mpz_swap(d1,r); +#endif + } + // u1*a+v1*m=d1 -> a=d1/u1 modulo m + if (mpz_sizeinbase(d1,2)<=30) + num=int(mpz_get_si(d1)); + else + num=d1; + if (mpz_sizeinbase(u1,2)<=30) + den=int(mpz_get_si(u1)); + else + den=u1; + mpz_set(q,*m._ZINTptr); + my_mpz_gcd(r,q,u1); + bool ok=mpz_cmp_ui(r,1)==0; + if (!ok){ + CERR << "Bad reconstruction a=" << a << " mod " << m << " u1=" << gen(u1) << " u1*a+v1*m= " << num << " gcd(u1,m)=" << gen(r) << '\n'; + simplify3(num,den); + return false; + } + return true; + } + + bool alloc_fracmod(const gen & a_orig,const gen & modulo,gen & res,mpz_t & d,mpz_t & d1,mpz_t & absd1,mpz_t &u,mpz_t & u1,mpz_t & ur,mpz_t & q,mpz_t & r,mpz_t &sqrtm,mpz_t & tmp){ + // write a as p/q with |p| and |q|begin(),itend=a_orig._VECTptr->end(); + vecteur v; + v.reserve(itend-it); + for (;it!=itend;++it){ + if (!alloc_fracmod(*it,modulo,res,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp)) + return false; + v.push_back(res); + } + res=gen(v,a_orig.subtype); + return true; + } + if (a_orig.type==_POLY){ + vector< monomial >::const_iterator it=a_orig._POLYptr->coord.begin(),itend=a_orig._POLYptr->coord.end(); + polynome v(a_orig._POLYptr->dim); + v.coord.reserve(itend-it); + for (;it!=itend;++it){ + if (!alloc_fracmod(it->value,modulo,res,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp)) + return false; + v.coord.push_back(monomial(res,it->index)); + } + res=gen(v); + return true; + } + if (a_orig.type==_CPLX){ + gen reres,imres; + if ( !alloc_fracmod(*a_orig._CPLXptr,modulo,reres,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp) || !alloc_fracmod(*(a_orig._CPLXptr+1),modulo,imres,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp) ) + return false; + res=reres+cst_i*imres; + return true; + } + gen a(a_orig),m(modulo),num,den; + if (a.type==_INT_) + a.uncoerce(); + if (m.type==_INT_) + m.uncoerce(); + if ( (a.type!=_ZINT) || (m.type!=_ZINT) ) + return false; + bool ok=in_fracmod(m,a,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp,num,den); + if (num.type==_ZINT && mpz_sizeinbase(*num._ZINTptr,2)<=30) + num=int(mpz_get_si(*num._ZINTptr)); + if (den.type==_ZINT && mpz_sizeinbase(*den._ZINTptr,2)<=30) + den=int(mpz_get_si(*den._ZINTptr)); + if (is_positive(den,context0)) // ok + res=fraction(num,den); + else + res=fraction(-num,-den); + return ok; + } + + bool fracmod(const gen & a_orig,const gen & modulo,gen & res){ + unsigned prealloc=a_orig.type==_ZINT?mpz_sizeinbase(*a_orig._ZINTptr,2):0; + mpz_t u,d,u1,d1,absd1,sqrtm,q,ur,r,tmp; + mpz_init2(u,prealloc); + mpz_init2(d,prealloc); + mpz_init2(u1,prealloc); + mpz_init(d1); + mpz_init(absd1); + mpz_init(sqrtm); + mpz_init(q); + mpz_init2(ur,prealloc); + mpz_init2(r,prealloc); + mpz_init2(tmp,prealloc); + bool b=alloc_fracmod(a_orig,modulo,res,d,d1,absd1,u,u1,ur,q,r,sqrtm,tmp); + mpz_clear(d); + mpz_clear(u); + mpz_clear(u1); + mpz_clear(d1); + mpz_clear(absd1); + mpz_clear(sqrtm); + mpz_clear(q); + mpz_clear(ur); + mpz_clear(r); + mpz_clear(tmp); + return b; + } + + gen fracmod(const gen & a_orig,const gen & modulo){ + if (a_orig==0) + return a_orig; + gen res; + if (!fracmod(a_orig,modulo,res)) + return gensizeerr(gettext("Reconstructed denominator is not prime with modulo")); + return res; + } + + static void _ZINTpowmod(const gen & base,const gen & expo,const gen & modulo, ref_mpz_t * & res){ + ref_mpz_t *aptr,*bptr; + if (base.type) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &base) >> 16); +#else + aptr=base.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,base.val); + } + if (modulo.type) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &modulo) >> 16); +#else + bptr=modulo.__ZINTptr; +#endif + else { + bptr = new ref_mpz_t; + mpz_set_si(bptr->z,modulo.val); + } + res = new ref_mpz_t; + if (!expo.type) + mpz_powm_ui(res->z,aptr->z,expo.val,*modulo._ZINTptr); + else + mpz_powm (res->z,aptr->z,*expo._ZINTptr,bptr->z); + if (!base.type) + delete aptr; + if (!modulo.type) + delete bptr; + } + + gen powmod(const gen &base,const gen & expo,const gen & modulo){ + if (is_exactly_zero(modulo)) + return pow(base,expo,context0); + if (base.type==_VECT){ + const_iterateur it=base._VECTptr->begin(),itend=base._VECTptr->end(); + vecteur res; + for (;it!=itend;++it) + res.push_back(powmod(*it,expo,modulo)); + return gen(res,base.subtype); + } + if ((expo.type!=_INT_) && (expo.type!=_ZINT)) + return gensizeerr(gettext("powmod")); // exponent must be a _DOUBLE_ integer + if (!is_positive(expo,context0)) // ok + return(powmod(invmod(base,modulo),-expo,modulo)); + if (modulo.type==_INT_){ + // try converting base to int and expo to a long + gen mybase(base % modulo); + if ( (expo.type==_INT_) && (mybase.type==_INT_) ){ + unsigned long tmp=expo.val; + return powmod(mybase.val,tmp,modulo.val); + } + } + ref_mpz_t * res; + switch ( (base.type<< _DECALAGE) | modulo.type) { + case _INT___INT_: case _INT___ZINT: case _ZINT__INT_: case _ZINT__ZINT: + _ZINTpowmod(base,expo,modulo,res); + return(res); + default: + return gentypeerr(gettext("powmod")); + } + return 0; + } + + // assuming amod and bmod are prime together, find c such that + // c = a mod amod and c = b mod bmod + // hence a + A*amod = b + B*bmod + // or A*amod -B*bmod = b - a + gen ichinrem(const gen & a,const gen &b,const gen & amod, const gen & bmod){ + if (a.type==_INT_ && b.type==_INT_ && amod.type==_INT_ && bmod.type==_INT_ && gcd(amod.val,bmod.val)==1){ + int amodinv=invmod(amod.val,bmod.val); + longlong res=a.val+((longlong(amodinv)*(b.val-longlong(a.val)))%bmod.val)*amod.val; + return res; + } + gen A,B,d,q; + egcd(amod,bmod,A,B,d); + if (is_one(d)) + q=b-a; + else + if (!is_exactly_zero(irem(b-a,d,q))) + return gensizeerr(gettext("No Integer Solution")); + A=A*q; + return smod(A*amod+a,amod*bmod); + } + + gen isqrt(const gen & a){ + if ( (a.type!=_INT_) && (a.type!=_ZINT)) + return gentypeerr(gettext("isqrt")); + ref_mpz_t *aptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + ref_mpz_t *res = new ref_mpz_t; + mpz_sqrt(res->z,aptr->z); + if (a.type==_INT_) + delete aptr; + return res; + } + + int is_perfect_square(const gen & a){ + if ( (a.type!=_INT_) && (a.type!=_ZINT)) + return false; + ref_mpz_t *aptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + int res= mpz_perfect_square_p(aptr->z); + if (a.type==_INT_) + delete aptr; + return res; + } + + bool miller_rabin(const gen & a,const gen & p){ + gen p1=p-1,q,s(p1),r; + int t=0; + // p-1=2^t*s + for (;;++t){ + gen Q; + r=irem(s,2,Q); + if (r!=0) + break; + s=Q; + } + gen A(powmod(a,s,p)); + if (A==1 || A==p1) return true; + for (int i=0;ia.val) + return 2; + if (a.val%p==0) + return 0; + } + } +#ifdef BF2GMP_H + for (int i=0;i> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + int res= mpz_probab_prime_p(aptr->z,TEST_PROBAB_PRIME); + if (a.type==_INT_) + delete aptr; + return res; +#endif // BF2GMP + } + + gen nextprime(const gen & a){ + if ( (a.type!=_INT_) && (a.type!=_ZINT)) + return gentypeerr(gettext("nextprime")); + gen res(a); + if (is_exactly_zero(smod(res,plus_two))) + res=res+1; + for ( ; ; res=res+2){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) + return gensizeerr(gettext("Interrupted")); + if (is_probab_prime_p(res)) + return(res); + } + } + + gen prevprime(const gen & a){ + if ( (a.type!=_INT_) && (a.type!=_ZINT)) + return gentypeerr(gettext("prevprime")); + if (a==2) + return a; + if (is_greater(2,a,context0)) + return gensizeerr(context0); + gen res(a); + if (is_exactly_zero(smod(res,plus_two))) + res=res-1; + for ( ; res.type==_ZINT || (res.type==_INT_ && res.val>1); res=res-2){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) + return gensizeerr(gettext("Interrupted")); + if (is_probab_prime_p(res)) + return(res); + } + return zero; + } + + int jacobi(const gen & a, const gen &b){ + if ( (a.type!=_INT_ && a.type!=_ZINT) || (b.type!=_INT_ && b.type!=_ZINT)){ +#ifndef NO_STDEXCEPT + settypeerr(gettext("jacobi")); +#endif + return -RAND_MAX; + } + ref_mpz_t *aptr,*bptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr = a.__ZINTptr; +#endif + else { + aptr = new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + if (b.type!=_INT_) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &b) >> 16); +#else + bptr=b.__ZINTptr; +#endif + else { + bptr = new ref_mpz_t; + mpz_set_si(bptr->z,b.val); + } + int res= mpz_jacobi(aptr->z,bptr->z); + if (a.type==_INT_) + delete aptr; + if (b.type==_INT_) + delete bptr; + return res; + } + + int legendre(const gen & a, const gen & b){ + if ( (a.type!=_INT_ && a.type!=_ZINT) || (b.type!=_INT_ && b.type!=_ZINT)){ +#ifndef NO_STDEXCEPT + settypeerr(gettext("legendre")); +#endif + return -RAND_MAX; + } + ref_mpz_t *aptr,*bptr; + if (a.type!=_INT_) +#ifdef SMARTPTR64 + aptr= (ref_mpz_t *) (* ((ulonglong * ) &a) >> 16); +#else + aptr=a.__ZINTptr; +#endif + else { + aptr= new ref_mpz_t; + mpz_set_si(aptr->z,a.val); + } + if (b.type!=_INT_) +#ifdef SMARTPTR64 + bptr= (ref_mpz_t *) (* ((ulonglong * ) &b) >> 16); +#else + bptr=b.__ZINTptr; +#endif + else { + bptr= new ref_mpz_t; + mpz_set_si(bptr->z,b.val); + } + int res=mpz_legendre(aptr->z,bptr->z); + if (a.type==_INT_) + delete aptr; + if (b.type==_INT_) + delete bptr; + return res; + } + + bool has_denominator(const gen & n){ + switch (n.type ) { + case _INT_: case _ZINT: case _CPLX: case _DOUBLE_: case _FLOAT_: case _IDNT: case _EXT: case _POLY: case _MOD: case _USER: case _REAL: case _VECT: + return false; + case _SYMB: case _FRAC: + return true; + default: +#ifndef NO_STDEXCEPT + settypeerr(gettext("has_denominator")); +#endif + return false; + } + return 0; + } + + + gen factorial(unsigned long int i){ + if (i>(unsigned long int)FACTORIAL_SIZE_LIMIT){ +#ifndef NO_STDEXCEPT + setstabilityerr(); +#endif + return plus_inf; + } + ref_mpz_t * e = new ref_mpz_t; + mpz_fac_ui(e->z,i); + return e; + } + + gen comb(unsigned long int i,unsigned long j){ + if (i>(unsigned long int)FACTORIAL_SIZE_LIMIT){ + double d=std::min(j,i-j)*std::log10(double(i)); + if (d>2*FACTORIAL_SIZE_LIMIT){ +#ifndef NO_STDEXCEPT + setstabilityerr(); +#endif + return undef; + } + } + ref_mpz_t * e = new ref_mpz_t; + if (iz,i,j); +#else + mpz_set_ui(e->z,1); + for (unsigned long int k=i;k>i-j;--k) + mpz_mul_ui(e->z,e->z,k); + mpz_t tmp,tmp1; + mpz_init(tmp); mpz_init(tmp1); + mpz_fac_ui(tmp,j); + mpz_fdiv_q(tmp1,e->z,tmp); + mpz_set(e->z,tmp1); + mpz_clear(tmp); mpz_clear(tmp1); +#endif + return e; + } + + gen perm(unsigned long int i,unsigned long j){ + if (i>(unsigned long int)FACTORIAL_SIZE_LIMIT){ + double d=j*std::log10(double(i)); + if (d>2*FACTORIAL_SIZE_LIMIT){ +#ifndef NO_STDEXCEPT + setstabilityerr(); +#endif + return undef; + } + } + ref_mpz_t * e = new ref_mpz_t; + if (iz,1); + for (unsigned long int k=i;k>i-j;--k) + mpz_mul_ui(e->z,e->z,k); + return e; + } + + /* I/O: Input routines */ + + gen chartab2gen(char * s,GIAC_CONTEXT){ + gen res; + // subtype=0; + // initialize as a null _INT_ + // type = _INT_; + // val = 0; + if (!*s) + return res; +#if defined(EMCC) || defined(EMCC2) + int base=10; +#else + int base=(abs_calc_mode(contextptr)==38 || calc_mode(contextptr)==1)?10:0; +#endif + if (s[0]=='#' || s[0]=='0') { + if (s[1]=='x' || s[1]=='X'){ + s[0]='0'; + s[1]='0'; + base=16; + } + if (s[1]=='o' || s[1]=='O'){ + s[0]='0'; + s[1]='0'; + base=8; + } + } + if (s[1]=='b' || s[1]=='B'){ + s[0]='0'; + s[1]='0'; + base=2; + } +#ifdef _LIB_CE_ERRNO_H +#ifndef BESTA_OS + __set_errno(0); +#endif +#else + errno = 0; +#endif + char * endchar; +#ifdef VISUALC + longlong ll=strtol(s,&endchar,base); +#else + longlong ll=strtoll(s,&endchar,base); +#endif + int l =int(strlen(s)); + if (l>0 && s[l-1]=='.'){ + // make a copy of s, call chartab2gen recursivly, + // because some implementations of strtod do not like a . at the end +#if 1 // def FREERTOS + ALLOCA(char, scopy, l+2); +#else + char * scopy=(char *)alloca(l+2); +#endif + strcpy(scopy,s); + scopy[l]='0'; + scopy[l+1]=0; + return chartab2gen(scopy,contextptr); + } + if (*endchar) {// non integer + int digits=decimal_digits(contextptr); + // count numeric char + int delta=0; + if (l && s[0]=='0') + ++delta; + for (int k=0;k'9') + ++delta; + } + if (l>digits+delta) + digits=l-delta; +#if !defined __MINGW_H && defined HAVE_LIBMPFR // #ifndef GIAC_HAS_STO_38 + if (digits>14){ +#if 1 // def HAVE_LIBMPFR + int nbits=digits2bits(digits); +#ifdef HAVE_LIBPTHREAD + int locked=pthread_mutex_trylock(&mpfr_mutex); + if (!locked) + mpfr_set_default_prec(nbits); + // mpf_set_default_prec (decimal_digits); + real_object r; + int res=mpfr_set_str(r.inf,s,10,MPFR_RNDN); + if (!locked) + pthread_mutex_unlock(&mpfr_mutex); +#else + mpfr_set_default_prec(nbits); + real_object r; + int res=mpfr_set_str(r.inf,s,10,MPFR_RNDN); +#endif // HAVE_LIBPTHREAD +#else // LIBMPFR + real_object r; + int res=mpf_set_str(r.inf,s,10); +#endif // LIBMPFR + gen rg(r); + // rg.dbgprint(); + if (!res) + return rg; + } // end if (digits>14) +#endif // LIBMPFR was GIAC_HAS_STO_38 + double d; +#if defined __MINGW_H || defined NSPIRE || defined FXCG +#ifdef NSPIRE + d=Strtod(s,&endchar); +#else + d=strtod(s,&endchar); +#endif // NSPIRE +#else // NSPIRE || FXCG +#if !defined __MINGW_H && defined HAVE_LIBPTHREAD + int locked=pthread_mutex_trylock(&locale_mutex); + if (!locked){ + char * lc=setlocale(LC_NUMERIC,(char *)NULL); + setlocale(LC_NUMERIC,"POSIX"); + d=strtod(s,&endchar); + setlocale(LC_NUMERIC,lc); + pthread_mutex_unlock(&locale_mutex); + } + else + d=strtod(s,&endchar); +#else + char * lc=setlocale(LC_NUMERIC,(char const *)NULL); + setlocale(LC_NUMERIC,"POSIX"); + d=strtod(s,&endchar); + setlocale(LC_NUMERIC,lc); +#endif // PTHREAD +#endif // NSPIRE + if (*endchar){ +#ifdef BCD + giac_float gf; + gf=strtobcd(s,(const char **)&endchar); + if (!*endchar) + return gf; + for (int i=0;i'9')) + base=16; + } + } + int maxsize = 5 + (s[0]=='-'); + if (base==10 && lz,s,base); + res= gen(ptr); + return res; + } + } + + gen string2gen(const string & ss,bool remove_ss_quotes){ + gen res; +#ifdef SMARTPTR64 + * ((ulonglong * ) &res) = ulonglong(new ref_string(remove_ss_quotes?ss.substr(1,ss.size()-2):ss)) << 16; +#else + res.__STRNGptr = new ref_string(remove_ss_quotes?ss.substr(1,ss.size()-2):ss); +#endif + res.type=_STRNG; + return res; + } + + int giac_yyparse(void * scanner); + + static int try_parse(const string & s_orig,GIAC_CONTEXT){ + string s=s_orig; + if (1 || abs_calc_mode(contextptr)!=38){ + // remove leading spaces + for (int i=0;i10 && (s.substr(0,5)=="\"def " || s.substr(0,10)=="\"function ")){ + string news=""; + int ss=s.size()-1; + for (;ss>5;--ss){ + if (s[ss]=='"') + break; + } + for (int i=1;istackaddr && thread_param_ptr(contextptr)->stacksize/2){ + gen er; + short int err=s.size(); + if (debug_infolevel>10000) + CERR << (size_t) &err << " " << ((size_t) thread_param_ptr(contextptr)->stackaddr)+4*65536 << '\n'; + if ( ((size_t) &err) < ((size_t) thread_param_ptr(contextptr)->stackaddr)+4*65536){ + gensizeerr(gettext("Too many recursion levels"),er); + parsed_gen(er,contextptr); + return 1; + } + } +#endif // pthread + int res; + int isqrt=i_sqrt_minus1(contextptr); +#ifndef NO_STDEXCEPT + try { +#endif + void * scanner; + YY_BUFFER_STATE state=set_lexer_string(s,scanner,contextptr); + if (xcas_mode(contextptr)==0 && try_parse_i(contextptr)) + i_sqrt_minus1(0,contextptr); + res=giac_yyparse(scanner); + delete_lexer_string(state,scanner); + // if xcas_mode(contextptr)<=0 scan for i:=something, if not present replace i by sqrt(-1) + if (xcas_mode(contextptr)==0 && try_parse_i(contextptr)){ + const gen& p = parsed_gen(contextptr); + if (1) { // p.type==_SYMB || p.type==_VECT){ + vecteur v(rlvarx(p,i__IDNT_e)); + if (!v.empty()){ + vecteur w=lop(v,at_program); + int i,vs=int(w.size()); + for (i=0;ifeuille; + if (args.type!=_VECT || args._VECTptr->empty()) + continue; + if (contains(args._VECTptr->front(),i__IDNT_e)){ + *logptr(contextptr) << gettext("Warning, i is usually sqrt(-1), I'm using a symbolic variable instead but you should check your input") << '\n'; + return res; + } + } + w=lop(v,at_local); + vs=int(w.size()); + for (i=0;ifeuille; + if (args.type!=_VECT || args._VECTptr->empty()) + continue; + if (contains(args._VECTptr->front(),i__IDNT_e)){ + *logptr(contextptr) << gettext("Warning, i is usually sqrt(-1), I'm using a symbolic variable instead but you should check your input") << '\n'; + return res; + } + } + v=lop(v,at_sto); + vs=int(v.size()); + for (i=0;ifeuille[1]==i__IDNT_e){ + *logptr(contextptr) << gettext("Warning, i is usually sqrt(-1), I'm using a symbolic variable instead but you should check your input") << '\n'; + break; + } + } + if (i==vs){ +#ifndef NSPIRE + my_ostream * log = logptr(contextptr); + logptr(0,contextptr); +#endif + i_sqrt_minus1(1,contextptr); + void * scanner2; + YY_BUFFER_STATE state2=set_lexer_string(s,scanner2,contextptr); + res=giac_yyparse(scanner2); +#ifndef NSPIRE + logptr(log,contextptr); +#endif + delete_lexer_string(state2,scanner2); + } + } + } + } // end if (xcas_mode(contextptr)==0 ... +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & error){ + i_sqrt_minus1(isqrt,contextptr); + if (!first_error_line(contextptr)) + first_error_line(lexer_line_number(contextptr),contextptr); + parser_error(error.what(),contextptr); +#ifdef HAVE_SIGNAL_H_OLD + messages_to_print += string(error.what()) + '\n'; +#endif + return 1; + } +#endif + i_sqrt_minus1(isqrt,contextptr); + return res; + } + + static gen aplatir_plus(const gen & g){ + // Quick check for embedded + at the left coming from parser + if (g.is_symb_of_sommet(at_plus) && g._SYMBptr->feuille.type==_VECT){ + iterateur it=g._SYMBptr->feuille._VECTptr->begin(),itend=g._SYMBptr->feuille._VECTptr->end(); + if (it==itend) + return 0; + vecteur v; + v.reserve(itend-it+1); + gen f; + for (;it!=itend;){ + for (--itend;itend!=it;--itend) + v.push_back(aplatir_fois_plus(*itend)); + if (!it->is_symb_of_sommet(at_plus)){ + v.push_back(aplatir_fois_plus(*it)); + break; + } + f=it->_SYMBptr->feuille; + if (f.type!=_VECT){ + v.push_back(*it); + break; + } + it=f._VECTptr->begin(); + itend=f._VECTptr->end(); + } + reverse(v.begin(),v.end()); + return new_ref_symbolic(symbolic(at_plus,gen(v,_SEQ__VECT))); + } + return g; + } + + gen aplatir_fois_plus(const gen & g){ + if (g.type==_VECT){ + vecteur v(*g._VECTptr); + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + *it=aplatir_fois_plus(*it); + return gen(v,g.subtype); + } + if (g.type!=_SYMB) + return g; + if (g._SYMBptr->sommet==at_pow && g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille.subtype!=_SEQ__VECT) + return symbolic(at_pow,change_subtype(g._SYMBptr->feuille,_SEQ__VECT)); + if (g._SYMBptr->sommet==at_plus) + return aplatir_plus(g); + gen & f=g._SYMBptr->feuille; + if (g._SYMBptr->sommet==at_prod && f.type==_VECT && f._VECTptr->size()==2) + return sym_mult(aplatir_fois_plus(f._VECTptr->front()),aplatir_fois_plus(f._VECTptr->back()),context0); + return new_ref_symbolic(symbolic(g._SYMBptr->sommet,aplatir_fois_plus(f))); + } + + static gen aplatir_plus_only(const gen & g){ + if (g.type==_VECT){ + const vecteur & v=*g._VECTptr; + vecteur w(v); + const_iterateur it=v.begin(),itend=v.end(); + iterateur jt=w.begin(); + for (;it!=itend;++jt,++it) + *jt=aplatir_plus_only(*it); + return gen(w,g.subtype); + } + if (g.type!=_SYMB) + return g; + // Quick check for embedded + at the left coming from parser + if (g.is_symb_of_sommet(at_plus) && g._SYMBptr->feuille.type==_VECT){ + const_iterateur it=g._SYMBptr->feuille._VECTptr->begin(),itend=g._SYMBptr->feuille._VECTptr->end(); + if (it==itend) + return 0; + vecteur v; + v.reserve(itend-it+1); + register const gen * f; + for (;it!=itend;){ + for (--itend;itend!=it;--itend) + v.push_back(*itend); + // Check first element of the vector g, if it's not a + add it to v and end + if (it->type!=_SYMB || it->_SYMBptr->sommet!=at_plus || (f=&it->_SYMBptr->feuille,f->type!=_VECT) ){ + v.push_back(*it); + break; + } + // first element was a plus, restart with all it's arguments + itend=f->_VECTptr->end(); + it=f->_VECTptr->begin(); + } + reverse(v.begin(),v.end()); + return gen(new_ref_symbolic(symbolic(at_plus,gen(v,_SEQ__VECT)))).change_subtype(g.subtype); + } + return gen(new_ref_symbolic(symbolic(g._SYMBptr->sommet,aplatir_plus_only(g._SYMBptr->feuille)))).change_subtype(g.subtype); + } + + static int protected_giac_yyparse(const string & chaine,gen & parse_result,GIAC_CONTEXT){ + int s; + s=int(chaine.size()); + if (!s) + return 1; +#ifdef HAVE_LIBPTHREAD + static pthread_mutex_t parse_mutex = PTHREAD_MUTEX_INITIALIZER; + int locked = pthread_mutex_lock(&parse_mutex); +#else // HAVE_LIBPTHREAD + int locked = 0; +#endif + int res = 1; +#ifndef NO_STDEXCEPT + try { +#endif + res=try_parse(chaine,contextptr); + gen g=parsed_gen(contextptr); + if (g.type<=_FLOAT_){ + parse_result=aplatir_plus_only(g); + // parse_result=aplatir_fois_plus(g); + if (g.type==_SYMB && parse_result.type==_SYMB) + parse_result.subtype=g.subtype; +#ifdef HAVE_LIBPTHREAD + if (!locked) + pthread_mutex_unlock(&parse_mutex); +#endif + return res; + } + parsed_gen(0,contextptr); + parse_result.type=0; + parse_result=0; + CERR << "Incomplete parse" << '\n'; +#ifdef HAVE_LIBPTHREAD + if (!locked) + pthread_mutex_unlock(&parse_mutex); +#endif +#ifndef NO_STDEXCEPT + } catch (std::runtime_error &e) { +#ifdef HAVE_LIBPTHREAD + if (!locked) + pthread_mutex_unlock(&parse_mutex); +#endif + } +#endif // exception + return res; + } + + gen::gen(const string & s,GIAC_CONTEXT){ + subtype=0; + string ss(s); + /* + string::iterator it=ss.begin(),itend=ss.end(); + for (;it!=itend;++it) + if (*it=='\\') + *it=' '; + */ + type=_INT_; + if (s==string(s.size(),' ')){ + *this=undef; + return; + } + if (protected_giac_yyparse(s,*this,contextptr)){ + if (ss.empty()) + ss=""""""; + if (ss[0]!='"') + ss = '"'+ss; + if ((ss.size()==1) || (ss[ss.size()-1]!='"')) + ss += '"'; +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_string(ss.substr(1,ss.size()-2))) << 16; + subtype=0; +#else + __STRNGptr = new ref_string(ss.substr(1,ss.size()-2)); +#endif + type=_STRNG; + } + } + + gen genfromstring(const string & s){ + return gen(s,context0); + } + + /* + gen::gen(const string & s,const vecteur & l,GIAC_CONTEXT){ + type=_INT_; + if (protected_giac_yyparse(s,*this,contextptr)){ + string ss(s); + if (ss.empty()) + ss=""""""; + if (ss[0]!='"') + ss = '"'+ss; + if ((ss.size()==1) || (ss[ss.size()-1]!='"')) + ss += '"'; +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_string(ss.substr(1,ss.size()-2))) << 16; +#else + __STRNGptr = new ref_string(ss.substr(1,ss.size()-2)); +#endif + type=_STRNG; + } + subtype=0; + } + */ + + gen::gen(const wchar_t * ws,GIAC_CONTEXT){ + size_t l=0; + const wchar_t * ptr=ws; + for (;*ptr;++ptr){ ++l; } + char * line=new char[4*l+1]; + unicode2utf8(ws,line,int(l)); + string ss(line); + delete [] line; + subtype=0; + type=_INT_; + if (ss==string(ss.size(),' ')){ + *this=undef; + return; + } +#ifdef HAVE_SSTREAM + ostringstream warnstream; +#endif // HAVE_SSTREAM + +#if !defined NSPIRE && !defined SDL_KHICAS + my_ostream * oldptr = logptr(contextptr); +#ifdef WITH_MYOSTREAM + my_ostream newptr(&warnstream); + logptr(&newptr,contextptr); +#else +#if !defined HAVE_SSTREAM || defined NSPIRE + logptr(&COUT,contextptr); +#else +#ifndef KHICAS + logptr(&warnstream,contextptr); +#endif +#endif // HAVE_SSTREAM +#endif // WITH_MYIOSTREAM +#endif // NSPIRE + if (protected_giac_yyparse(ss,*this,contextptr)){ + if (ss.empty()) + ss=""""""; + if (ss[0]!='"') + ss = '"'+ss; + if ((ss.size()==1) || (ss[ss.size()-1]!='"')) + ss += '"'; +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_string(ss.substr(1,ss.size()-2))) << 16; + subtype=0; +#else + __STRNGptr = new ref_string(ss.substr(1,ss.size()-2)); +#endif + type=_STRNG; + } +#if !defined NSPIRE && !defined SDL_KHICAS + logptr(oldptr,contextptr); +#endif +#if !defined HAVE_SSTREAM || defined NSPIRE +#else + if (!warnstream.str().empty()) + parser_error(warnstream.str(),contextptr); +#endif + } + + /* I/O: Print routines */ +int sprint_int(char * s,int r){ + char * ptr=s; + if (r<0){ + *ptr='-'; + ++ptr; + r=-r; + } + int i; + if (r==0){ + *ptr='0'; + *(ptr+1)=0; + return 1; + } + *(ptr+10)=0; + for (i=9;r;--i){ + *(ptr+i)='0'+r%10; + r/=10; + } + ++i; + if (i>0){ // shift left i char + char * buf; + for (buf=ptr+i;buf<=ptr+9;++buf){ + *(buf-i)=*buf; + } + *(buf-i)=0; + ptr=buf-i; + } + else + ptr += 10; + return ptr-s; +} + +void sprint_double(char * s,double d){ + char * buf=s; + if (my_isnan(d)){ + strcpy(buf,"nan"); + return; + } + if (d==0){ + strcpy(buf,"0.0"); + return; + } + if (d<0){ + *buf='-'; + ++buf; + d=-d; + } + int i=d; + if (i==d && d<1e9){ + sprint_int(buf,i); + return; + } + for (i=0;i<280 && d>=1.0;i+=14){ + d=d*1e-14; + } + for (;i>-280 && d<1.0;i-=14){ + d=d*1e14; + } + for (;i<310 && d>=1.0;++i){ + d=d*.1; + } + if (i==310){ + strcpy(buf,"inf"); + return; + } + for (;i>-310 && d<1.0;--i){ + d=d*10; + } + if (i==-310){ + strcpy(buf,"0.0"); + return; + } + // 1.0<=d<10, d*10^i + d=d/10; ++i; // 0.1<=d<1, d*10^i + *buf='.'; + char * ptr=buf; + ++buf; + int r=(int)(d*1e9+.5); + if (r>=1e9){ + r=r/10; + ++i; + } + buf += sprint_int(buf,r); + if (i>0 && i<7){ + // move . i positions to the right + for (int j=0;j3 || forme[1]<'0' || forme[1]>'9' || (forme.size()==3 && forme[2]<'0' && forme[2]>'9')) + return "invalid format"; + if (forme.size()==3){ + int dig=(forme[1]-'0')*10+forme[2]-'0'; + if (dig>17){ + forme[1]='1'; + forme[2]='7'; + } + } + if (my_isnan(d)) + return "undef"; + if (my_isinf(d)) + return "infinity"; + char s[512]; + string f2=string("%.")+forme.substr(1,forme.size()-1)+ch; + sprintfdouble(s,f2.c_str(),d); + return s; + } + if (xcas_mode(contextptr)==3 && double(int(d))==d) + return print_INT_(int(d)); + char s[256]; +#ifdef SOFTMATH + sprintfdouble(s,"%.14g",d); + return s; +#else + string form("%."+print_INT_(giacmin(decimal_digits(contextptr),14))); + int sf=scientific_format(contextptr); + switch (sf){ + case 0: case 2: + if (abs_calc_mode(contextptr)==38) + form += 'G'; + else + form += "g"; + break; + case 1: + form += "e"; // or "f" ?? + break; + case 3: + form += "a"; + } + if (calc_mode(contextptr)==1) + form[form.size()-1]=toupper(form[form.size()-1]); + if (sf==2){ + // engineering format + int ndigits=int(giac_floor(std::log10(d)+0.5)); + ndigits = 3*(ndigits /3); + sprintfdouble(s,form.c_str(),d/std::pow(10.0,ndigits)); + return s+("e"+print_INT_(ndigits)); + } + sprintfdouble(s,form.c_str(),d); + // 1073741824=2^30, fixme always try with a .0 for large numbers if longfloat not available? + if (sf +#if 1 // def HAVE_LIBMPFR + || d>=1073741824 || d<=-1073741824 +#endif + ) + return s; + for (int i=0;s[i];++i){ + if (s[i]=='.' || s[i]==',' || s[i]=='e' || s[i]=='E') + return s; + } + return string(s)+".0"; +#endif + } + + gen maptoarray(const gen_map & m,GIAC_CONTEXT){ + vecteur res; + gen_map::const_iterator it=m.begin(),itend=m.end(); + if (it==itend) + return gendimerr(gettext("Empty array")); + gen_map::const_reverse_iterator lastit=m.rbegin(); + // find index ranges + gen premidx=it->first,lastidx=lastit->first; + if (premidx.type!=_VECT || lastidx.type!=_VECT) + return gentypeerr(gettext("Bad array indexes")); + vecteur & pv=*premidx._VECTptr; + vecteur & lv=*lastidx._VECTptr; + unsigned ps=unsigned(pv.size()); + vector indexes(ps); + if (ps==0) + return res; + if (lv.size()!=ps ) + return gendimerr(contextptr); + for (unsigned i=0;isecond); + } + res.push_back(tmp); + } + else { + vecteur tmp(indexes[ps-1]); + for (int i=ps-2;i>=0;--i){ + vecteur newtmp; + for (int j=0;jtype!=_VECT) + return gendimerr(contextptr); + for (unsigned i=0;ifirst[i]-pv[i]).val; + if (pos<0 || unsigned(pos)>=tmpptr->_VECTptr->size()) + return gendimerr(contextptr); + tmpptr=&((*tmpptr->_VECTptr)[pos]); + } + *tmpptr = it->second; + } + res.push_back(tmp); + } + return new_ref_symbolic(symbolic(at_array,res)); + } + + static string printmap(const gen_map & m,GIAC_CONTEXT){ + string s("table(\n"); + gen_map::const_iterator it=m.begin(),itend=m.end(); + for (;it!=itend;){ + gen bb=it->first; + if (bb.type!=_STRNG && array_start(contextptr)){ + if (bb.type==_VECT) + bb=bb+vecteur(bb._VECTptr->size(),plus_one); + else + bb=bb+plus_one; + } + if (bb.type==_VECT && bb.subtype==_SEQ__VECT) + s+='('; + s += bb.print(contextptr); + if (bb.type==_VECT && bb.subtype==_SEQ__VECT) + s+=')'; + s += " = " + it->second.print(contextptr); + ++it; + if (it!=itend) + s += ','; + s += '\n'; + } + return s+")"; + } + + std::string printmpf_t(const mpf_t & inf,GIAC_CONTEXT){ +#if !defined USE_GMP_REPLACEMENTS && !defined BF2GMP_H +#ifdef VISUALC + char * ptr=new char[decimal_digits(contextptr)+30]; +#else + char ptr[decimal_digits(contextptr)+30]; +#endif + bool negatif=mpf_sgn(inf)<0; + mp_exp_t expo; + if (negatif){ + mpf_t inf2; + mpf_init(inf2); + mpf_neg(inf2,inf); + mpf_get_str(ptr,&expo,10,decimal_digits(contextptr),inf2); + mpf_clear(inf2); + } + else + mpf_get_str(ptr,&expo,10,decimal_digits(contextptr),inf); + std::string res(ptr),reste(res.substr(1,res.size()-1)); +#ifdef VISUALC + delete [] ptr; +#endif + res=res[0]+("."+reste); + if (expo!=1) + res += "e"+print_INT_(expo-1); + if (negatif) + return "-"+res; + else + return res; +#else // USE_GMP_REPLACEMENTS +#if defined NSPIRE || defined FXCG || defined KHICAS + return "mpf_t not implemented"; +#else + std::ostringstream out; +#ifdef LONGFLOAT_DOUBLE + out << std::setprecision(decimal_digits(contextptr)) << inf; +#else + out << std::setprecision(decimal_digits(contextptr)) << *inf; +#endif + return out.str(); +#endif // NSPIRE +#endif // USE_GMP_REPLACEMENTS + } + + + string print_ZINT(const mpz_t & a){ + /* + char * s =mpz_get_str (NULL, 10,a) ; + string res(s); + free(s); + return res; + */ + size_t l=mpz_sizeinbase (a, 10) + 2; + if (l>unsigned(MAX_PRINTABLE_ZINT)) + return "Integer_too_large_for_display"; +#if defined( VISUALC ) || defined( BESTA_OS ) + ALLOCA(char, s, l); //s = ( char * )alloca( l ); +#else + char s[l]; +#endif + mpz_get_str (s, 10,a) ; + string tmp(s); + + return tmp; + } + + string hexa_print_ZINT(const mpz_t & a){ + size_t l=mpz_sizeinbase (a, 16) + 2; + if (l>unsigned(MAX_PRINTABLE_ZINT)) + return "Integer_too_large"; +#if defined( VISUALC ) || defined( BESTA_OS ) + ALLOCA(char, s, l);//char * s = ( char * )alloca( l ); +#else + char s[l]; +#endif + string res("0x"); +#ifdef USE_GMP_REPLACEMENTS + if (mpz_sgn(a) == -1){ + mpz_t tmpint; + mpz_init(tmpint); + mpz_neg(tmpint, a); + mpz_get_str(s,16,tmpint); + mpz_clear(tmpint); + + res = "-" + res + s; + } + else { + mpz_get_str(s,16,a); + res += s; + } +#else + mpz_get_str (s,16,a) ; + res += s; +#endif // USE_GMP_REPLACEMENTS + + return res; + } + + string octal_print_ZINT(const mpz_t & a){ + size_t l=mpz_sizeinbase (a, 8) + 2; + if (l>unsigned(MAX_PRINTABLE_ZINT)) + return "Integer_too_large"; +#if defined( VISUALC ) || defined( BESTA_OS ) + ALLOCA(char, s, l);//char * s = ( char * )alloca( l ); +#else + char s[l]; +#endif + string res("0"); +#ifdef USE_GMP_REPLACEMENTS + if (mpz_sgn(a) == -1){ + mpz_t tmpint; + mpz_init(tmpint); + mpz_neg(tmpint, a); + mpz_get_str(s,8,tmpint); + mpz_clear(tmpint); + res = "-" + res + s; + } + else { + mpz_get_str(s,8,a); + res += s; + } +#else + mpz_get_str (s,8,a) ; + res += s; +#endif // USE_GMP_REPLACEMENTS + + return res; + } + + string binary_print_ZINT(const mpz_t & a){ + size_t l=mpz_sizeinbase (a, 2) + 2; + if (l>unsigned(MAX_PRINTABLE_ZINT)) + return "Integer_too_large"; +#if defined( VISUALC ) || defined( BESTA_OS ) + ALLOCA(char, s, l);//char * s = ( char * )alloca( l ); +#else + char s[l]; +#endif + string res("0b"); +#ifdef USE_GMP_REPLACEMENTS + if (mpz_sgn(a) == -1){ + mpz_t tmpint; + mpz_init(tmpint); + mpz_neg(tmpint, a); + mpz_get_str(s,2,tmpint); + mpz_clear(tmpint); + res = "-" + res + s; + } + else { + mpz_get_str(s,2,a); + res += s; + } +#else + mpz_get_str (s,2,a) ; + res += s; +#endif // USE_GMP_REPLACEMENTS + + return res; + } + + string printinner_VECT(const vecteur & v, int subtype,GIAC_CONTEXT){ + string s; + return add_printinner_VECT(s,v,subtype,contextptr); + } + + string & add_printinner_VECT(string & s,const vecteur &v,int subtype,GIAC_CONTEXT){ + vecteur::const_iterator it=v.begin(), itend=v.end(); + if (it==itend) + return s; + for(;;){ + if ( (subtype==_RPN_FUNC__VECT) && (it->type==_SYMB) && (it->_SYMBptr->sommet==at_quote)) + s += "'"+it->_SYMBptr->feuille.print(contextptr)+"'"; + else { + if ( (it->type==_SYMB && it->_SYMBptr->sommet==at_sto) + // || (it->type==_VECT && it->subtype==_SEQ__VECT && it->_VECTptr->size()>=2) + ) + s += "("+it->print(contextptr)+")"; + else + add_print(s,*it,contextptr); // s += it->print(contextptr); + } + ++it; + if (it==itend){ + return s; + } + if ( (subtype!=_RPN_FUNC__VECT) && + // (subtype || (!rpn_mode(contextptr)) ) && + ( ((it-1)->type!=_SYMB) || ((it-1)->_SYMBptr->sommet!=at_comment) ) + ) + s += ','; + else + s += ' '; + } + } + + string begin_VECT_string(int subtype,bool tex,GIAC_CONTEXT){ + string s; + switch (subtype){ + case _SEQ__VECT: + break; + case _SET__VECT: + if (xcas_mode(contextptr)>0 || calc_mode(contextptr)==1){ + if (tex) + s+="\\{"; + else + s="{"; + } + else + s="set["; + break; + case _RPN_STACK__VECT: + s="stack("; + break; + case _RPN_FUNC__VECT: + s="<< "; + break; + case _GROUP__VECT: + s="group["; + break; +#ifdef HAVE_LIBMPFI + case _INTERVAL__VECT: + s="i["; + break; +#endif + case _LINE__VECT: + s="line["; + break; + case _VECTOR__VECT: + s="vector["; + break; + case _GGBVECT: + s=(calc_mode(contextptr)==1?"ggbvect(":"ggbvect["); + break; +#if !defined(EMCC) && !defined(EMCC2) + case _LOGO__VECT: + s="logo["; + break; +#endif + case _PNT__VECT: + s="pnt["; + break; + case _POINT__VECT: + s="point["; + break; + case _TUPLE__VECT: + s="tuple["; + break; + case _MATRIX__VECT: + if (calc_mode(contextptr)==1) + s="{"; + else { + int pyc=python_compat(contextptr); + // s="matrix["; + if (!os_shell || pyc<0) + s="["; + else + s=abs_calc_mode(contextptr)==38?"[":"matrix["; + } + break; + case _POLY1__VECT: + if (!os_shell) + s="["; + else + s="poly1["; + break; + case _ASSUME__VECT: + s = "assume["; + break; + case _REALSET__VECT: + s = "realset["; + break; + case _FOLDER__VECT: + s = "folder["; + break; + case _POLYEDRE__VECT: + s= "polyedre["; + break; + case _RGBA__VECT: + s= "rgba["; + break; + case _LIST__VECT: + if (!os_shell) + s="["; + else { + if (tex) + s="\\{"; + else + s=abs_calc_mode(contextptr)==38?"{":"list["; + } + break; + case _GGB__VECT: + if (calc_mode(contextptr)==1) + s="("; // warning: can not be reparsed from giac + else + s="ggbpnt["; + break; + case _TABLE__VECT: + s="{/"; + break; + default: + s=calc_mode(contextptr)==1?"{":"["; + } + return s; + } + + string end_VECT_string(int subtype,bool tex,GIAC_CONTEXT){ + string s; + switch (subtype){ + case _SEQ__VECT: + return s; + case _SET__VECT: + if (xcas_mode(contextptr)>0 || calc_mode(contextptr)==1){ + if (tex) + return "\\}"; + else + return "}"; + } + else + return "]"; + case _RPN_STACK__VECT: + return ")"; + case _RPN_FUNC__VECT: + return " >>"; + case _LIST__VECT: + if (tex) + return "\\}"; + else + return abs_calc_mode(contextptr)==38?"}":"]"; + case _GGB__VECT: + if (calc_mode(contextptr)==1) + return ")"; + else + return "]"; + case _POINT__VECT: case _VECTOR__VECT: case _POLY1__VECT: case _PNT__VECT: + return "]"; + case _GGBVECT: + return calc_mode(contextptr)==1?")":"]"; + case 0: case _MATRIX__VECT: + return calc_mode(contextptr)==1?"}":"]"; + case _TABLE__VECT: + return "/}"; + default: + return calc_mode(contextptr)==1?"}":"]"; + } + } + + const char * svg2doutput(const gen & g,string & S,GIAC_CONTEXT){ +#if defined(EMCC) || defined(EMCC2) + bool fullview=true; + vector vx,vy,vz; + double window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax; + bool ortho=autoscaleg(g,vx,vy,vz,contextptr); + autoscaleminmax(vx,window_xmin,window_xmax,fullview); + autoscaleminmax(vy,window_ymin,window_ymax,fullview); + double xscale=window_xmax-window_xmin,yscale=window_ymax-window_ymin; + double ratio=yscale/xscale; + double gratio=0.6,gwidth=9; +#ifndef GIAC_GGB + gwidth=EM_ASM_DOUBLE_V({ + var hw=window.innerWidth; + if (typeof(svgwidth)!="undefined") + return svgwidth*1.0; + if (hw>=1000) + return 9.0*hw/1000.0; + else + return hw/60.0; + }); +#endif // GIAC_GGB + //CERR << gwidth << '\n'; + int maxgratio=ortho?10:3; + if (ratiomaxgratio*gratio) ortho=false; else ortho=true; + if (ortho){ + if (ratio>gratio){ // yscale>gratio*xscale, use yscale for x + double xc=(window_xmax+window_xmin)/2; + window_xmin=xc-yscale/(2*gratio); + window_xmax=xc+yscale/(2*gratio); + } + else { // xscale>yscale/gratio + double yc=(window_ymax+window_ymin)/2; + window_ymin=yc-gratio*xscale/2; + window_ymax=yc+gratio*xscale/2; + } + ratio=gratio; + ortho=false; + } + bool axes=overwrite_viewbox(g,window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax); + xscale=window_xmax-window_xmin;yscale=window_ymax-window_ymin; + ratio=yscale/xscale; + //COUT << window_xmin << " " << window_xmax << " " << window_ymin << " " << window_ymax << '\n'; + //g=_symetrie(makesequence(_droite(makesequence(0,1),contextptr),g),contextptr); + //S='"'+svg_preamble(7,7,gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,ortho,false,default_color(contextptr))+gen2svg(g,contextptr)+svg_grid(gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,default_color(contextptr))+"\""; + S='"'+svg_preamble_pixel(g,gwidth,gwidth*gratio,window_xmin,window_xmax,window_ymin,window_ymax,ortho,false,default_color(contextptr)); + plot_attr P; + title_legende(g,P); + S= S+(gen2svg(g,window_xmin,window_xmax,window_ymin,window_ymax,ratio/gratio,contextptr,false)+(axes?svg_grid(window_xmin,window_xmax,window_ymin,window_ymax,P,default_color(contextptr))+"\"":"")); +#endif + return S.c_str(); + } + + string print_VECT(const vecteur & v,int subtype,GIAC_CONTEXT){ + if (v.empty()){ + switch (subtype){ + case _SEQ__VECT: + return xcas_mode(contextptr)==1?"NULL":"seq[]"; + case _SET__VECT: + if (xcas_mode(contextptr)>0 || calc_mode(contextptr)==1) + return "{ }"; + else + return "set[ ]"; + case _RPN_FUNC__VECT: + return "<< >>"; + case _RPN_STACK__VECT: + return "stack()"; + } + } +#if 1 // for debugging/profiling pixon_print + if (!v.empty() && is_pnt_or_pixon(v.back())){ + gen f=v.back(); + if (f.is_symb_of_sommet(at_pnt)){ + f=f._SYMBptr->feuille; + if (f.type==_VECT) + f=f._VECTptr->front(); + } + if (f.is_symb_of_sommet(at_pixon)){ + string S; + pixon_print(v,S,contextptr); + return S; + } + } +#endif + string s; + if (subtype==_REALSET__VECT && v.size()>=2){ + // print as a union of intervals + gen v1=v[v.size()-2],v2=v.back(); + if (v1.type==_VECT && !v1._VECTptr->empty() && v2.type==_VECT){ + vecteur & interv=*v1._VECTptr; + vecteur & excl=*v2._VECTptr; + for (int i=0;isize()); + for (int i=0;;){ + int save_r,save_c; + vecteur & w=*v[i]._VECTptr; + s +='['; + for (int j=0;;){ + save_r=printcell_current_row(contextptr); + save_c=printcell_current_col(contextptr); + printcell_current_row(contextptr)=i; + printcell_current_col(contextptr)=j; + if (add_quotes){ + gen tmp=w[j]; + if (tmp.type==_VECT && tmp._VECTptr->size()>=2){ + vecteur & w=*tmp._VECTptr; + s += "['"+w[0].print(contextptr)+"',"; + s += "'"+w[1].print(contextptr)+"',"; + // COUT << i << " " << j << " " << w[1] << '\n'; + if (w[1].type==_STRNG && *w[1]._STRNGptr=="") + s += "'      ']"; + else { + string ms; + if (w[1].is_symb_of_sommet(at_pnt)){ + svg2doutput(w[1],ms,contextptr); // remove quotes + if (ms[0]=='"' && ms[ms.size()-1]=='"') + ms=ms.substr(1,ms.size()-2); + } +#ifndef GIAC_HAS_STO_38 + else + ms=*_mathml(makesequence(w[1],1),contextptr)._STRNGptr; +#endif + string res; + int l=ms.size(); + res.reserve(l); + const char * ch=ms.c_str(); + for (int i=0;i1; + if (paren) s+='('; + for(;;){ + s += it->print(contextptr); + ++it; + if (it==itend){ + if (paren) + return s+')'; + return s; + } + s += '+'; + } + } + + string print_the_type(int val,GIAC_CONTEXT){ + if (xcas_mode(contextptr)==1){ + switch(val){ + case _INT_: + return "integer"; + case _DOUBLE_: + return "double"; + case _FLOAT_: + return "float"; + case _ZINT: + return "integer"; + case _CPLX: + return "complex"; + case _VECT: + return "vector"; + case _IDNT: + return "symbol"; + case _SYMB: + return "algebraic"; + case _FRAC: + return "rational"; + case _MAPLE_LIST: + return "list"; + } + } + if (abs_calc_mode(contextptr)!=38){ + switch(val){ + case _DOUBLE_: + return "real"; + case _ZINT: + return "integer"; + case _CPLX: + return "complex"; + case _VECT: + return "vector"; + case _IDNT: + return "identifier"; + case _SYMB: + return "expression"; + case _FRAC: + return "rational"; + case _STRNG: + return "string"; + case _FUNC: + return "func"; + } + } + switch(val){ + case _INT_: + return "DOM_int"; + case _DOUBLE_: + return "DOM_FLOAT"; + case _FLOAT_: + return "DOM_SPECIALFLOAT"; + case _ZINT: + return "DOM_INT"; + case _CPLX: + return "DOM_COMPLEX"; + case _VECT: + return "DOM_LIST"; + case _IDNT: + return "DOM_IDENT"; + case _SYMB: + return "DOM_SYMBOLIC"; + case _FRAC: + return "DOM_RAT"; + case _STRNG: + return "DOM_STRING"; + case _FUNC: + return "DOM_FUNC"; + case _REAL: + return "DOM_LONGFLOAT"; + case _MAP: + return "DOM_MAP"; + case _SPOL1: + return "DOM_SERIES"; + } + return print_INT_(val); + } + + string print_STRNG(const string & s){ + string res("\""); + int l=int(s.size()); + for (int i=0;i0 || python_compat(contextptr)<0) + return "I"; + else + return "i"; + } + + static string print_EQW(const eqwdata & e){ + string s; + s += "eqwdata(position"+print_INT_(e.x)+","+print_INT_(e.y)+",dxdy,"+print_INT_(e.dx)+","+print_INT_(e.dy); + s += ",font,"+print_INT_(e.eqw_attributs.fontsize); + s += ",background," +print_INT_(e.eqw_attributs.background); + s += ",text_color," +print_INT_(e.eqw_attributs.text_color)+","; + if (e.selected) + s +="selected,"; + if (e.active) + s +="active,"; + s += e.g.print(context0)+")"; + return s; + } + + string gen::print() const{ + return print(context0); + } + + // FIXME!!! + int gen::sprint(std::string * sptr,GIAC_CONTEXT) const{ + return 0; + } + + string gen::print_universal(GIAC_CONTEXT) const{ + int lang=language(contextptr); + language(-1,contextptr); + string res; +#ifdef NO_STDEXCEPT + res=print(contextptr); +#else + try { + res=print(contextptr); + } + catch (...){ } +#endif + language(lang,contextptr); + return res; + } + + wchar_t * gen::wprint(GIAC_CONTEXT) const { + string s=print(contextptr); + unsigned int ss=unsigned(s.size()); + wchar_t * ptr = (wchar_t *) malloc(sizeof(wchar_t)*(ss+1)); + /* + unsigned int l=utf82unicode(s.c_str(),ptr,ss); + if (l0){ + if (val) + return "True"; + else + return "False"; + } + if (xcas_mode(contextptr)==2){ + if (val) + return "TRUE"; + else + return "FALSE"; + } + else { + if (val) + return "true"; + else + return "false"; + } + } + if (subtype==_INT_COLOR){ + switch (language(contextptr)){ + case 1: + switch (val){ + case _BLACK: + return "noir"; + case _RED: + return "rouge"; + case _GREEN: + return "vert"; + case _YELLOW: + return "jaune"; + case _BLUE: + return "bleu"; + case _MAGENTA: + return "magenta"; + case _CYAN: + return "cyan"; + case _WHITE: + return "blanc"; + case _FILL_POLYGON: + return "rempli"; + case _QUADRANT2: + return "quadrant2"; + case _QUADRANT3: + return "quadrant3"; + case _QUADRANT4: + return "quadrant4"; + case _POINT_LOSANGE: + return "point_losange"; + case _POINT_CARRE: + return "point_carre"; + case _POINT_PLUS: + return "point_plus"; + case _POINT_TRIANGLE: + return "point_triangle"; + case _POINT_ETOILE: + return "point_etoile"; + case _POINT_POINT: + return "point_point"; + case _POINT_INVISIBLE: + return "point_invisible"; + case 49: + return "gomme"; + case _LINE_WIDTH_2: + return "epaisseur_ligne_2"; + case _LINE_WIDTH_3: + return "epaisseur_ligne_3"; + case _LINE_WIDTH_4: + return "epaisseur_ligne_4"; + case _LINE_WIDTH_5: + return "epaisseur_ligne_5"; + case _LINE_WIDTH_6: + return "epaisseur_ligne_6"; + case _LINE_WIDTH_7: + return "epaisseur_ligne_7"; + case _LINE_WIDTH_8: + return "epaisseur_ligne_8"; + case _POINT_WIDTH_2: + return "epaisseur_point_2"; + case _POINT_WIDTH_3: + return "epaisseur_point_3"; + case _POINT_WIDTH_4: + return "epaisseur_point_4"; + case _POINT_WIDTH_5: + return "epaisseur_point_5"; + case _POINT_WIDTH_6: + return "epaisseur_point_6"; + case _POINT_WIDTH_7: + return "epaisseur_point_7"; + case _POINT_WIDTH_8: + return "epaisseur_point_8"; + case _HIDDEN_NAME: + return "nom_cache"; + case _DASH_LINE: + return "ligne_tiret"; + case _DOT_LINE: + return "ligne_point"; + case _DASHDOT_LINE: + return "ligne_tiret_point"; + case _DASHDOTDOT_LINE: + return "ligne_tiret_pointpoint"; + case _CAP_FLAT_LINE: + return "ligne_chapeau_plat"; + case _CAP_ROUND_LINE: + return "ligne_chapeau_rond"; + case _CAP_SQUARE_LINE: + return "ligne_chapeau_carre"; + } + break; + case 4: + switch (val){ + case _BLACK: + return "black"; + case _RED: + return "red"; + case _GREEN: + return "green"; + case _YELLOW: + return "yellow"; + case _BLUE: + return "blue"; + case _MAGENTA: + return "magenta"; + case _CYAN: + return "cyan"; + case _WHITE: + return "white"; + case _FILL_POLYGON: + return "filled"; + case _QUADRANT2: + return "quadrant2"; + case _QUADRANT3: + return "quadrant3"; + case _QUADRANT4: + return "quadrant4"; + case _POINT_LOSANGE: + return "ฯฮฟฮผฮฒฮฟฮตฮนฮดฮญฯ‚_ฯƒฮทฮผฮตฮฏฮฟ"; + case _POINT_CARRE: + return "ฯ„ฮตฯ„ฯฮฑฮณฯ‰ฮฝฮนฮบฯŒ_ฯƒฮทฮผฮตฮฏฮฟ"; + case _POINT_PLUS: + return "ฯƒฯ„ฮฑฯ…ฯฮฟฮตฮนฮดฮญฯ‚_ฯƒฮทฮผฮตฮฏฮฟ"; + case _POINT_TRIANGLE: + return "ฯ„ฯฮนฮณฯ‰ฮฝฮนฮบฯŒ_ฯƒฮทฮผฮตฮฏฮฟ"; + case _POINT_ETOILE: + return "ฮฑฯƒฯ„ฯฮฟฮตฮนฮดฮญฯ‚_ฯƒฮทฮผฮตฮฏฮฟ"; + case _POINT_POINT: + return "point_point"; + case _POINT_INVISIBLE: + return "ฮฑฯŒฯฮฑฯ„ฮฟ_ฯƒฮทฮผฮตฮฏฮฟ"; + case 49: + return "gomme"; + case _LINE_WIDTH_2: + return "ฮตฯฯฮฟฯ‚_ฮณฯฮฑฮผฮผฮฎฯ‚_2"; + case _LINE_WIDTH_3: + return "ฮตฯฯฮฟฯ‚_ฮณฯฮฑฮผฮผฮฎฯ‚_3"; + case _LINE_WIDTH_4: + return "ฮตฯฯฮฟฯ‚_ฮณฯฮฑฮผฮผฮฎฯ‚_4"; + case _LINE_WIDTH_5: + return "ฮตฯฯฮฟฯ‚_ฮณฯฮฑฮผฮผฮฎฯ‚_5"; + case _LINE_WIDTH_6: + return "ฮตฯฯฮฟฯ‚_ฮณฯฮฑฮผฮผฮฎฯ‚_6"; + case _LINE_WIDTH_7: + return "ฮตฯฯฮฟฯ‚_ฮณฯฮฑฮผฮผฮฎฯ‚_7"; + case _LINE_WIDTH_8: + return "ฮตฯฯฮฟฯ‚_ฮณฯฮฑฮผฮผฮฎฯ‚_8"; + case _POINT_WIDTH_2: + return "ฮตฯฯฮฟฯ‚_ฯƒฮทฮผฮตฮฏฮฟฯ…_2"; + case _POINT_WIDTH_3: + return "ฮตฯฯฮฟฯ‚_ฯƒฮทฮผฮตฮฏฮฟฯ…_3"; + case _POINT_WIDTH_4: + return "ฮตฯฯฮฟฯ‚_ฯƒฮทฮผฮตฮฏฮฟฯ…_4"; + case _POINT_WIDTH_5: + return "ฮตฯฯฮฟฯ‚_ฯƒฮทฮผฮตฮฏฮฟฯ…_5"; + case _POINT_WIDTH_6: + return "ฮตฯฯฮฟฯ‚_ฯƒฮทฮผฮตฮฏฮฟฯ…_6"; + case _POINT_WIDTH_7: + return "ฮตฯฯฮฟฯ‚_ฯƒฮทฮผฮตฮฏฮฟฯ…_7"; + case _POINT_WIDTH_8: + return "ฮตฯฯฮฟฯ‚_ฯƒฮทฮผฮตฮฏฮฟฯ…_8"; + case _HIDDEN_NAME: + return "hidden_name"; + case _DASH_LINE: + return "ฮณฯฮฑฮผฮผฮฎ_ฮดฮนฮฑฮบฮตฮบฮฟฮผฮผฮญฮฝฮท"; + case _DOT_LINE: + return "ฯ€ฮฑฯฮปฮฑ_ฯ„ฮตฮปฮตฮฏฮฑ"; + case _DASHDOT_LINE: + return "ฮณฯฮฑฮผฮผฮฎ_ฯ€ฮฑฯฮปฮฑ_ฯ„ฮตฮปฮตฮฏฮฑ"; + case _DASHDOTDOT_LINE: + return "ฮณฯฮฑฮผฮผฮฎ_ฯ€ฮฑฯฮปฮฑ_ฯ„ฮตฮปฮตฮฏฮฑฯ„ฮตฮปฮตฮฏฮฑ"; + case _CAP_FLAT_LINE: + return "ฮณฯฮฑฮผฮผฮฎ_ฮตฯ€ฮฏฯ€ฮตฮดฮฟ_ฮบฮฑฮฒฮฟฯฮบฮน"; + case _CAP_ROUND_LINE: + return "ฮณฯฮฑฮผฮผฮฎ_ฯƒฯ„ฯฮฟฮณฮณฯ…ฮปฯŒ_ฮบฮฑฮฒฮฟฯฮบฮน"; + case _CAP_SQUARE_LINE: + return "ฮณฯฮฑฮผฮผฮฎ_ฯ„ฮตฯ„ฯฮฌฮณฯ‰ฮฝฮฟ_ฮบฮฑฮฒฮฟฯฮบฮน"; + } + default: + switch (val){ + case _BLACK: + return "black"; + case _RED: + return "red"; + case _GREEN: + return "green"; + case _YELLOW: + return "yellow"; + case _BLUE: + return "blue"; + case _MAGENTA: + return "magenta"; + case _CYAN: + return "cyan"; + case _WHITE: + return "white"; + case _FILL_POLYGON: + return "filled"; + case _QUADRANT2: + return "quadrant2"; + case _QUADRANT3: + return "quadrant3"; + case _QUADRANT4: + return "quadrant4"; + case _POINT_LOSANGE: + return "rhombus_point"; + case _POINT_CARRE: + return "square_point"; + case _POINT_PLUS: + return "plus_point"; + case _POINT_TRIANGLE: + return "triangle_point"; + case _POINT_ETOILE: + return "star_point"; + case _POINT_POINT: + return "point_point"; + case _POINT_INVISIBLE: + return "invisible_point"; + case 49: + return "gomme"; + case _LINE_WIDTH_2: + return "line_width_2"; + case _LINE_WIDTH_3: + return "line_width_3"; + case _LINE_WIDTH_4: + return "line_width_4"; + case _LINE_WIDTH_5: + return "line_width_5"; + case _LINE_WIDTH_6: + return "line_width_6"; + case _LINE_WIDTH_7: + return "line_width_7"; + case _LINE_WIDTH_8: + return "line_width_8"; + case _POINT_WIDTH_2: + return "point_width_2"; + case _POINT_WIDTH_3: + return "point_width_3"; + case _POINT_WIDTH_4: + return "point_width_4"; + case _POINT_WIDTH_5: + return "point_width_5"; + case _POINT_WIDTH_6: + return "point_width_6"; + case _POINT_WIDTH_7: + return "point_width_7"; + case _POINT_WIDTH_8: + return "point_width_8"; + case _HIDDEN_NAME: + return "hidden_name"; + case _DASH_LINE: + return "dash_line"; + case _DOT_LINE: + return "dot_line"; + case _DASHDOT_LINE: + return "dashdot_line"; + case _DASHDOTDOT_LINE: + return "dashdotdot_line"; + case _CAP_FLAT_LINE: + return "cap_flat_line"; + case _CAP_ROUND_LINE: + return "cap_round_line"; + case _CAP_SQUARE_LINE: + return "cap_square_line"; + } + } + // switch (val){ } + } + if (subtype==_INT_PLOT){ + switch(val){ + case _ADAPTIVE: + return "adaptive"; + case _AXES: + return "axes"; + case _COLOR: + return "color"; + case _FILLED: + return "filled"; + case _FILLED+_POINT_WIDTH_7: + return "filled_1"; + case _FILLED+_POINT_WIDTH_6: + return "filled_2"; + case _FILLED+_POINT_WIDTH_5: + return "filled_3"; + case _FILLED+_POINT_WIDTH_4: + return "filled_4"; + case _FILLED+_POINT_WIDTH_3: + return "filled_5"; + case _FILLED+_POINT_WIDTH_2: + return "filled_6"; + case _FONT: + return "font"; + case _LABELS: + return "labels"; + case _LEGEND: + return "legend"; + case _LINESTYLE: + return "linestyle"; + case _RESOLUTION: + return "resolution"; + case _SAMPLE: + return "sample"; + case _SCALING: + return "scaling"; + case _STYLE: + return "style"; + case _SYMBOL: + return "symbol"; + case _SYMBOLSIZE: + return "symbolsize"; + case _THICKNESS: + return "thickness"; + case _TITLE: + return "title"; + case _TITLEFONT: + return "titlefont"; + case _VIEW: + return "view"; + case _AXESFONT: + return "axesfont"; + case _COORDS: + return "coords"; + case _LABELFONT: + return "labelfont"; + case _LABELDIRECTIONS: + return "labeldirections"; + case _NUMPOINTS: + return "numpoints"; + case _TICKMARKS: + return "tickmarks"; + case _XTICKMARKS: + return "xtickmarks"; + case _NSTEP: + return "nstep"; + case _XSTEP: + return "xstep"; + case _YSTEP: + return "ystep"; + case _ZSTEP: + return "zstep"; + case _TSTEP: + return "tstep"; + case _USTEP: + return "ustep"; + case _VSTEP: + return "vstep"; + case _FRAMES: + return "frames"; + case _GL_TEXTURE: + return "gl_texture"; + case _GL_LIGHT0: + return "gl_light0"; + case _GL_LIGHT1: + return "gl_light1"; + case _GL_LIGHT2: + return "gl_light2"; + case _GL_LIGHT3: + return "gl_light3"; + case _GL_LIGHT4: + return "gl_light4"; + case _GL_LIGHT5: + return "gl_light5"; + case _GL_LIGHT6: + return "gl_light6"; + case _GL_LIGHT7: + return "gl_light7"; + case _GL_AMBIENT: + return "gl_ambient"; + case _GL_SPECULAR: + return "gl_specular"; + case _GL_DIFFUSE: + return "gl_diffuse"; + case _GL_POSITION: + return "gl_position"; + case _GL_SPOT_DIRECTION: + return "gl_spot_direction"; + case _GL_SPOT_EXPONENT: + return "gl_spot_exponent"; + case _GL_SPOT_CUTOFF: + return "gl_spot_cutoff"; + case _GL_CONSTANT_ATTENUATION: + return "gl_constant_attenuation"; + case _GL_LINEAR_ATTENUATION: + return "gl_linear_attenuation"; + case _GL_QUADRATIC_ATTENUATION: + return "gl_quadratic_attenuation"; + case _GL_OPTION: + return "gl_option"; + case _GL_SMOOTH: + return "gl_smooth"; + case _GL_FLAT: + return "gl_flat"; + case _GL_SHININESS: + return "gl_shininess"; + case _GL_FRONT: + return "gl_front"; + case _GL_BACK: + return "gl_back"; + case _GL_FRONT_AND_BACK: + return "gl_front_and_back"; + case _GL_AMBIENT_AND_DIFFUSE: + return "gl_ambient_and_diffuse"; + case _GL_EMISSION: + return "gl_emission"; + case _GL_LIGHT_MODEL_AMBIENT: + return "gl_light_model_ambient"; + case _GL_LIGHT_MODEL_LOCAL_VIEWER: + return "gl_light_model_local_viewer"; + case _GL_LIGHT_MODEL_TWO_SIDE: + return "gl_light_model_two_side"; + case _GL_LIGHT_MODEL_COLOR_CONTROL: + return "gl_light_model_color_control"; + case _GL_BLEND: + return "gl_blend"; + case _GL_SRC_ALPHA: + return "gl_src_alpha"; + case _GL_ONE_MINUS_SRC_ALPHA: + return "gl_one_minus_src_alpha"; + case _GL_SEPARATE_SPECULAR_COLOR: + return "gl_separate_specular_color"; + case _GL_SINGLE_COLOR: + return "gl_single_color"; + case _GL_MATERIAL: + return "gl_material"; + case _GL_COLOR_INDEXES: + return "gl_color_indexes"; + case _GL_LIGHT: + return "gl_light"; + case _GL_PERSPECTIVE: + return "gl_perspective"; + case _GL_ORTHO: + return "gl_ortho"; + case _GL_QUATERNION: + return "gl_quaternion"; + case _GL_ROTATION_AXIS: + return "gl_rotation_axis"; + case _GL_X: + return "gl_x"; + case _GL_Y: + return "gl_y"; + case _GL_Z: + return "gl_z"; + case _GL_XTICK: + return "gl_xtick"; + case _GL_YTICK: + return "gl_ytick"; + case _GL_ZTICK: + return "gl_ztick"; + case _GL_ANIMATE: + return "gl_animate"; + case _GL_SHOWAXES: + return "gl_showaxes"; + case _GL_SHOWNAMES: + return "gl_shownames"; + case _GL_X_AXIS_NAME: + return "gl_x_axis_name"; + case _GL_Y_AXIS_NAME: + return "gl_y_axis_name"; + case _GL_Z_AXIS_NAME: + return "gl_z_axis_name"; + case _GL_X_AXIS_UNIT: + return "gl_x_axis_unit"; + case _GL_Y_AXIS_UNIT: + return "gl_y_axis_unit"; + case _GL_Z_AXIS_UNIT: + return "gl_z_axis_unit"; + case _GL_LOGX: + return "gl_logx"; + case _GL_LOGY: + return "gl_logy"; + case _GL_LOGZ: + return "gl_logz"; + } + } + if (subtype==_INT_MAPLELIB){ + switch (val){ + case _LINALG: + return "linalg"; + case _NUMTHEORY: + return "numtheory"; + case _GROEBNER: + return "groebner"; + } + } + if (subtype==_INT_MAPLECONVERSION){ + switch (val){ + case _MAPLE_LIST: + return "list"; + case _SET__VECT: + return "set"; + case _REALSET__VECT: + return "realset"; + case _MATRIX__VECT: + return "matrix"; + case _POLY1__VECT: + return "polynom"; + case _TRIG: + return "trig"; + case _EXPLN: + return "expln"; + case _PARFRAC: + return "parfrac"; + case _FULLPARFRAC: + return "fullparfrac"; + case _CONFRAC: + return "confrac"; + case _BASE: + return "base"; + case _POSINT: + return "posint"; + case _NEGINT: + return "negint"; + case _NONPOSINT: + return "nonposint"; + case _NONNEGINT: + return "nonnegint"; + case _LP_BINARY: + return "lp_binary"; + case _LP_BINARYVARIABLES: + return "lp_binaryvariables"; + case _LP_DEPTHLIMIT: + return "lp_depthlimit"; + case _LP_INTEGER: + return "lp_integer"; + case _LP_INTEGERVARIABLES: + return "lp_integervariables"; + case _LP_MAXIMIZE: + return "lp_maximize"; + case _LP_NONNEGATIVE: + return "lp_nonnegative"; + case _LP_NONNEGINT: + return "lp_nonnegint"; + case _LP_ASSUME: + return "lp_assume"; + case _LP_NODE_LIMIT: + return "lp_nodelimit"; + case _LP_METHOD: + return "lp_method"; + case _LP_SIMPLEX: + return "lp_simplex"; + case _LP_INTERIOR_POINT: + return "lp_interiorpoint"; + case _LP_MAX_CUTS: + return "lp_maxcuts"; + case _LP_GAP_TOLERANCE: + return "lp_gaptolerance"; + case _LP_NODESELECT: + return "lp_nodeselect"; + case _LP_VARSELECT: + return "lp_varselect"; + case _LP_FIRSTFRACTIONAL: + return "lp_firstfractional"; + case _LP_LASTFRACTIONAL: + return "lp_lastfractional"; + case _LP_MOSTFRACTIONAL: + return "lp_mostfractional"; + case _LP_PSEUDOCOST: + return "lp_pseudocost"; + case _LP_DEPTHFIRST: + return "lp_depthfirst"; + case _LP_BREADTHFIRST: + return "lp_breadthfirst"; + case _LP_BEST_LOCAL_BOUND: + return "lp_bestlocalbound"; + case _LP_BEST_PROJECTION: + return "lp_bestprojection"; + case _LP_HYBRID: + return "lp_hybrid"; + case _LP_ITERATION_LIMIT: + return "lp_iterationlimit"; + case _LP_TIME_LIMIT: + return "lp_timelimit"; + case _LP_VERBOSE: + return "lp_verbose"; + case _LP_HEURISTIC: + return "lp_heuristic"; + case _NLP_PRESOLVE: + return "nlp_presolve"; + case _NLP_METHOD: + return "nlp_method"; + case _NLP_SAMPLES: + return "nlp_samples"; + case _NLP_INTEGER: + return "nlp_integer"; + case _NLP_INTEGERVARIABLES: + return "nlp_integervariables"; + case _NLP_BINARY: + return "nlp_binary"; + case _NLP_BINARYVARIABLES: + return "nlp_binaryvariables"; + case _NLP_NONNEGINT: + return "nlp_nonnegint"; + case _NLP_TOLERANCE: + return "nlp_tolerance"; + case _NLP_VERBOSE: + return "nlp_verbose"; + case _NLP_FEAS_TOL: + return "nlp_feasibilitytolerance"; + case _NLP_INT_TOL: + return "nlp_integertolerance"; + case _LP_PRESOLVE: + return "lp_presolve"; + case _NLP_INITIALPOINT: + return "nlp_initialpoint"; + case _NLP_ITERATIONLIMIT: + return "nlp_iterationlimit"; + case _NLP_NONNEGATIVE: + return "nlp_nonnegative"; + case _NLP_PRECISION: + return "nlp_precision"; + case _NLP_MAXIMIZE: + return "nlp_maximize"; + case _GT_CONNECTED: + return "connected"; + case _GT_SPRING: + return "spring"; + case _GT_TREE: + return "tree"; + case _GT_PLANAR: + return "planar"; + case _GT_DIRECTED: + return "directed"; + case _GT_WEIGHTED: + return "weighted"; + case _GT_WEIGHTS: + return "weights"; + case _GT_BIPARTITE: + return "bipartite"; + case _GT_ACYCLIC: + return "acyclic"; + case _KDE_BANDWIDTH: + return "bandwidth"; + case _KDE_BINS: + return "bins"; + case _ANN_LEARNING_RATE: + return "learning_rate"; + case _ANN_WEIGHT_DECAY: + return "weight_decay"; + case _ANN_RELU: + return "ReLU"; + case _ANN_HALF_MSE: + return "MSE"; + case _ANN_CROSS_ENTROPY: + return "cross_entropy"; + case _ANN_LOG_LOSS: + return "log_loss"; + case _ANN_BLOCK_SIZE: + return "block_size"; + case _ANN_MOMENTUM: + return "momentum"; + case _ANN_TOPOLOGY: + return "topology"; + } + } + if (subtype==_INT_MUPADOPERATOR){ + switch (val){ + case _DELETE_OPERATOR: + return "Delete"; + case _PREFIX_OPERATOR: + return "Prefix"; + case _POSTFIX_OPERATOR: + return "Postfix"; + case _BINARY_OPERATOR: + return "Binary"; + case _NARY_OPERATOR: + return "Nary"; + } + } + if (subtype==_INT_GROEBNER){ + switch (val){ + case _REVLEX_ORDER: + return "revlex"; + case _PLEX_ORDER: + return "plex"; + case _TDEG_ORDER: + return "tdeg"; + case _WITH_COCOA: + return "with_cocoa"; + case _WITH_F5: + return "with_f5"; + case _MODULAR_CHECK: + return "modular_check"; + case _RUR_REVLEX: + return "rur"; + } + } + return print_INT_(val); + } + + static void print_float(const float & f,char * ch){ + sprintfdouble(ch,"%.14g",f); + } + + string print_FLOAT_(const giac_float & f,GIAC_CONTEXT){ + char ch[1024]; +#ifdef BCD +#ifndef CAS38_DISABLED + int i=get_int(f); + if (is_zero(f-i)) + return print_INT_(i)+'.'; +#endif + print_float(f,ch); +#else + print_float(f,ch); +#endif + return ch; + } + + static string print_FRAC(const gen & f,GIAC_CONTEXT){ + if (f._FRACptr->num.type==_INT_ && f._FRACptr->den.type==_INT_){ + string s(f._FRACptr->num.print(contextptr)); + s += "/"; + add_print(s,f._FRACptr->den,contextptr); + return s; + } + if (calc_mode(contextptr)==1 && f._FRACptr->den.type==_CPLX){ + gen n=f._FRACptr->num,d=f._FRACptr->den,dr,di; + reim(d,dr,di,contextptr); + n=n*gen(dr,-di); + d=dr*dr+di*di; + gen nd=fraction(n,d); + if (nd.type==_FRAC) + return print_FRAC(nd,contextptr); + else + return nd.print(contextptr); + } + return _FRAC2_SYMB(f).print(contextptr); + } + + string gen::print(GIAC_CONTEXT) const{ + switch (type ) { + case _INT_: + if (val<0 && val != (1<<31) && calc_mode(contextptr)==38) + return "โˆ’"+(-*this).print(contextptr); + if (subtype) + return localize(printint32(val,subtype,contextptr),language(contextptr)); + switch (integer_format(contextptr)){ + case 16: + return hexa_print_INT_(val); + case 8: + return octal_print_INT_(val); + case 2: + return binary_print_INT_(val); + default: + return print_INT_(val); + } + case _DOUBLE_: + return print_DOUBLE_(_DOUBLE_val,contextptr); + case _FLOAT_: + if (abs_calc_mode(contextptr)==38 && is_strictly_positive(-*this,contextptr)) return "โˆ’"+print_FLOAT_(-_FLOAT_val,contextptr); + return print_FLOAT_(_FLOAT_val,contextptr); + case _ZINT: + if (abs_calc_mode(contextptr)==38 && is_strictly_positive(-*this,contextptr)) + return "โˆ’"+(-*this).print(contextptr); + switch (integer_format(contextptr)){ + case 16: + return hexa_print_ZINT(*_ZINTptr); + case 8: + return octal_print_ZINT(*_ZINTptr); + case 2: + return binary_print_ZINT(*_ZINTptr); + default: + return print_ZINT(*_ZINTptr); + } + case _REAL: + return _REALptr->print(contextptr); + case _CPLX: + // if (abs_calc_mode(contextptr)==38) return "("+_CPLXptr->print(contextptr)+","+(_CPLXptr+1)->print(contextptr)+")"; + if (is_exactly_zero(*(_CPLXptr+1))) + return _CPLXptr->print(contextptr); +#ifndef GIAC_GGB + if (*complex_display_ptr(*this) &1){ +#ifdef BCD + if (_CPLXptr->type==_FLOAT_ && (_CPLXptr+1)->type==_FLOAT_) +#ifdef GIAC_HAS_STO_38 + //grad + return abs(*this,contextptr).print(contextptr)+"\xe2\x88\xa1"+print_FLOAT_(atan2f(_CPLXptr->_FLOAT_val,(_CPLXptr+1)->_FLOAT_val,angle_radian(contextptr)?AMRad:(angle_degree(contextptr)?AMDeg:AMGrad)),contextptr); +#else + return abs(*this,contextptr).print(contextptr)+"\xe2\x88\xa1"+print_FLOAT_(atan2f(_CPLXptr->_FLOAT_val,(_CPLXptr+1)->_FLOAT_val,angle_radian(contextptr)),contextptr); +#endif +#endif + // return abs(*this,contextptr).print(contextptr)+"\xe2\x88\xa1"+(angle_radian(contextptr)?arg(*this,contextptr):arg(*this,contextptr)*rad2deg_g).print(contextptr); + return abs(*this,contextptr).print(contextptr)+"\xe2\x88\xa1"+arg(*this,contextptr).print(contextptr); + } +#endif // GIAC_GGB + if (is_exactly_zero(*_CPLXptr)){ + if (is_one(*(_CPLXptr+1))) + return printi(contextptr); + if (is_minus_one(*(_CPLXptr+1))) + return (abs_calc_mode(contextptr)==38?string("โˆ’"):string("-"))+printi(contextptr); + return ((_CPLXptr+1)->print(contextptr) + string("*"))+printi(contextptr); + } + if (is_one(*(_CPLXptr+1))) + return (_CPLXptr->print(contextptr) + string("+"))+printi(contextptr); + if (is_minus_one(*(_CPLXptr+1))) + return (_CPLXptr->print(contextptr) + string("-"))+printi(contextptr); + if (is_positive(-(*(_CPLXptr+1)),contextptr)) + return (_CPLXptr->print(contextptr) + string("-") + (-(*(_CPLXptr+1))).print(contextptr) + "*")+printi(contextptr); + return (_CPLXptr->print(contextptr) + string("+") + (_CPLXptr+1)->print(contextptr) + "*")+printi(contextptr); + case _IDNT: + if (calc_mode(contextptr)==1 && (is_inf(*this) || + is_undef(*this) || + strcmp(_IDNTptr->id_name,"undefined")==0)) + return "?"; + return _IDNTptr->print(contextptr); + case _SYMB: + { + int d=depth(*this,0,print_max_depth); + if (d>=print_max_depth) + return "Too many embeddings"; + } + if (is_inf(_SYMBptr->feuille)){ + if (_SYMBptr->sommet==at_plus){ +#ifdef KHICAS + return "oo"; +#else + if ( + // calc_mode(contextptr)!=1 + abs_calc_mode(contextptr)==38 + ) + return "โˆž"; + else + return "+infinity"; +#endif + } + if (_SYMBptr->sommet==at_neg){ +#ifdef KHICAS + return "-oo"; +#else + if ( + // calc_mode(contextptr)!=1 + abs_calc_mode(contextptr)==38 + ) + return "-โˆž"; + else + return "-infinity"; +#endif + } + } + if (subtype==_SPREAD__SYMB){ + if (_SYMBptr->sommet==at_sto) + return "=("+_SYMBptr->print(contextptr)+")"; + return "="+_SYMBptr->print(contextptr); + } + else + return _SYMBptr->print(contextptr); + case _VECT: + if (subtype==_GRAPH__VECT){ + string s; + if (is_graphe(*this)) + return '"'+s+'"'; + } + return print_VECT(*_VECTptr,subtype,contextptr); + case _POLY: + return _POLYptr->print() ; + case _SPOL1: + return print_SPOL1(*_SPOL1ptr,contextptr); + case _EXT: { + string s("%%{"); + s += _EXTptr->print(contextptr); + s += ':'; + s += (*(_EXTptr+1)).print(contextptr); + s += "%%}"; + return s; + } + case _USER: + return _USERptr->print(contextptr); + case _MOD: +#ifdef GIAC_HAS_STO_38 + if ( (_MODptr->type==_SYMB && _MODptr->_SYMBptr->sommet!=at_pow) || (_MODptr->type==_VECT && _MODptr->subtype==_SEQ__VECT) ) + return "("+_MODptr->print(contextptr)+") %% "+(*(_MODptr+1)).print(contextptr); + return _MODptr->print(contextptr)+" %% "+(*(_MODptr+1)).print(contextptr); +#else + if ( (_MODptr->type==_SYMB && _MODptr->_SYMBptr->sommet!=at_pow) || (_MODptr->type==_VECT && _MODptr->subtype==_SEQ__VECT) ) + return "("+_MODptr->print(contextptr)+")"+(python_compat(contextptr)?" mod ":" % ")+(*(_MODptr+1)).print(contextptr); + return _MODptr->print(contextptr)+(python_compat(contextptr)?" mod ":" % ")+(*(_MODptr+1)).print(contextptr); +#endif + case _FRAC: + return print_FRAC(*this,contextptr); + case _STRNG: +#ifdef GIAC_HAS_STO_38 + // if (subtype==-1) + // return AspenPrintErrorString(*_STRNGptr); +#endif + return print_STRNG(*_STRNGptr); + case _FUNC: + if (*this==at_return){ + if (xcas_mode(contextptr)==3) + return "Return"; + else + return "return ;"; + } + if (*this==at_display) + return "display"; + if (rpn_mode(contextptr) || _FUNCptr->ptr()->printsommet==&printastifunction || subtype==0) + return _FUNCptr->ptr()->print(contextptr); + else + return string("'")+_FUNCptr->ptr()->print(contextptr)+"'"; + case _MAP: + if (subtype==1) + return maptoarray(*_MAPptr,contextptr).print(contextptr); + else + return printmap(*_MAPptr,contextptr); + case _EQW: + return print_EQW(*_EQWptr); + case _POINTER_: { + // handle 64 bits pointers + unsigned long long u=(unsigned long long)_POINTER_val; + if (u<(1U<<31)) + return "pointer("+hexa_print_INT_(int((alias_type)_POINTER_val))+","+print_INT_(subtype)+")"; + gen z=longlong(u); + return "pointer("+hexa_print_ZINT(*z._ZINTptr)+","+print_INT_(subtype)+")"; + } + default: +#ifndef NO_STDEXCEPT + settypeerr(gettext("print")); +#endif + return "print error"; + } + return "print error"; + } + +#ifdef ConnectivityKit + const char * gen::dbgprint() const { return "Done";} +#else +#if defined(VISUALC) && defined GIAC_HAS_STO_38 && !defined(MS_SMART) +#include + const char * gen::dbgprint() const { ATLTRACE2("%s\r\n", this->print(0).c_str()); return "Done";} +#else + const char * gen::dbgprint() const{ + if (this->type==_POLY) + return _POLYptr->dbgprint(); + static string *sptr=0; + if (!sptr) sptr=new string; + *sptr=this->print(context0); +#if 0 // ndef NSPIRE + COUT << *sptr; +#endif + return sptr->c_str(); + } +#endif +#endif + +#if defined KHICAS || defined SDL_KHICAS + stdostream & operator << (stdostream & os,const gen & a){ + return os << a.print(context0); + } +#endif +#ifndef NSPIRE + ostream & operator << (ostream & os,const gen & a) { return os << a.print(context0); } +#endif + + string monome::print(GIAC_CONTEXT) const { + // if (abs_calc_mode(contextptr)==38 ) + return "%%%{" + coeff.print(contextptr) + ',' + exponent.print(contextptr) + "%%%}" ; + //return "<<" + coeff.print(contextptr) + ',' + exponent.print(contextptr) + ">>" ; + } + + const char * monome::dbgprint() const { + static string *sptr=0; + if (!sptr) sptr=new string; + *sptr=this->print(context0); +#if 0 // ndef NSPIRE + COUT << *sptr; +#endif + return sptr->c_str(); + } + +#ifndef NSPIRE + ostream & operator << (ostream & os,const monome & m){ + return os << m.print(context0) ; + } +#endif + + /* + gen string2_ZINT(string s,int l,int & pos){ + char ss[l+1]; + int neg=1; + if (s[pos]=='-'){ + pos++; + neg=-1; + } + int i=0; + for (;(pos='0') && (s[pos]<='9');pos++,i++) + ss[i]=s[pos]; + if ((!i) && (s[pos]=='i') || (s[pos]=='I')){ + return(neg); + } + assert(i); + ss[i]=char(0); + mpz_t *mpzin = new mpz_t[1]; + mpz_init(*mpzin); + mpz_set_str (*mpzin, ss, 10); + if (neg>0) + return(gen(mpzin)); + else + return(-gen(mpzin)); + } + + istream & operator >> (istream & is,gen & a){ + string s; + is >> s; + int l=s.size(); + int pos=0; + a=gen(0); + while (pos nio::ios_base & operator>>(nio::ios_base & is,gen & a){ + string s; + is >> s; + a = gen(s,context0); + return is; + } +#else + istream & operator >> (istream & is,gen & a){ + string s; + is >> s; + a = gen(s,context0); + return is; + } +#endif + + /* Some string utilities not use anymore */ + // Note that this function should be optimized for large input + string cut_string(const string & chaine,int nchar,vector & ligne_end) { + // CERR << CLOCK() << '\n'; + int pos; + if (ligne_end.empty()) + pos=0; + else + pos=ligne_end.back()+1; + int l=int(chaine.size()); + string res; + for (int i=0;i=l-1)) ){ + ligne_end.push_back(pos+l); + // CERR << CLOCK() << '\n'; + return res+chaine.substr(i,l-i); + } + if ((k>=i) && (k & endlines,vector & positions){ + string res; + endlines.clear(); + positions.clear(); + int s_in=int(history_in.size()),s_out=int(history_out.size()); + int s=giacmax(s_in,s_out); + for (int i=0;i=0) && (pospos1;){ + --i; + char ch = s[i]; + if (ch=='(') + ++counter1; + if (ch==')') + --counter1; + if (ch=='[') + ++counter2; + if (ch==']') + --counter2; + } + } + for (;pos1>=0;--pos1){ + char ch=s[pos1]; + if ( (!counter1) && (!counter2) && ( (ch=='(') || (ch=='[') || (ch=='+') || (ch=='-') || (ch==',') )){ + if ( (pos1=0;--pos1) + if (!isalphan(s[pos1])) + break; + ++pos1; + } + break; + } + } + if (ch==')') + --counter1; + if (ch=='['){ + ++counter2; + if ( (!counter1) && (!counter2) ){ + if (s[pos2-1]==']') + break; + if ( pos1 && isalphan(s[pos1-1])){ + --pos1; + for (;pos1>=0;--pos1) + if (!isalphan(s[pos1])) + break; + ++pos1; + } + break; + } + } + if (ch==']') + --counter2; + } + } + + static void find_right(const string & s,int & pos1,int & pos2){ + int l=int(s.size()); + pos1=giacmin(giacmax(pos1,0),l); + pos2=giacmax(giacmin(pos2,l),0); + int pos2orig=pos2; + int counter1=0,counter2=0; + for (int i=pos1;(ipos2orig)){ + --pos2; + break; + } + if (ch=='(') + ++counter1; + if (ch==')'){ + --counter1; + if ( (!counter1) && (!counter2) ){ + if ( (pos1>0) && (s[pos1]=='(') && isalphan(s[pos1-1])){ + --pos1; + for (;pos1>=0;--pos1) + if (!isalphan(s[pos1])) + break; + ++pos1; + } + break; + } + } + if (ch=='[') + ++counter2; + if (ch==']'){ + --counter2; + if ( (!counter1) && (!counter2) ){ + if ( (pos1>0) && (s[pos1]=='[') && isalphan(s[pos1-1])){ + --pos1; + for (;pos1>=0;--pos1) + if (!isalphan(s[pos1])) + break; + ++pos1; + } + break; + } + } + } + if (pos2==l+1) + find_left(s,pos1,pos2); + } + + void increase_selection(const string & s,int & pos1,int& pos2){ + int l=int(s.size()); + int pos1_orig(pos1),pos2_orig(pos2); + // adjust selection (does not change anything on a valid selection) + find_left(s,pos1,pos2); + find_right(s,pos1,pos2); + if ( (pos1!=pos1_orig) || (pos2!=pos2_orig) ) + return; + if (pos1 && (pos21){ + char op=s[pos1-1]; + --pos1; + for (;pos1;--pos1){ + if (s[pos1]==',') + op=0; + if (!is_operator_char(s[pos1],op)) + break; + } + if (s[pos1]=='(' && pos1){ + --pos1; + for (;pos1;--pos1){ + if (!isalphan(s[pos1])) + break; + } + ++pos1; + } + find_left(s,pos1,pos2); + find_right(s,pos1,pos2); + return; + } + pos1=0; + ++pos2; + find_right(s,pos1,pos2); + } + + void decrease_selection(const string & s,int & pos1,int& pos2){ + int l=int(s.size()); + int pos2_orig(pos2); + // adjust selection (does not change anything on a valid selection) + find_left(s,pos1,pos2); + if (pos2!=l) + --pos2; + if (!pos2) + return; + int counter1=0,counter2=0; + char op=' '; + if (pos2pos1;--pos2){ + char ch=s[pos2]; + if (ch=='('){ + ++counter1; + if ( (!counter1) && (!counter2) && pos2_orig && (s[pos2_orig-1]==')') ){ + pos1=pos2+1; + pos2=pos2_orig-1; + return; + } + } + if (ch==')') + --counter1; + if (ch=='[') + ++counter2; + if (ch==']') + --counter2; + if (ch==',') + op=0; + if ( (!counter1) && (!counter2) && ( is_operator_char(ch,op) || (ch==',')) ) + return; + } + for (;pos10;--pos2){ + if (s[pos2-1]==',') + op=0; + if (!is_operator_char(s[pos2-1],op) && (s[pos2-1]!='(') && (s[pos2-1]!='[') ) + break; + } + if (pos2<=0){ + pos1=0; + pos2=0; + return; + } + pos1=pos2-1; + find_left(s,pos1,pos2); + find_right(s,pos1,pos2); + } + + string remove_extension(const string & chaine){ + int s=int(chaine.size()); + if (s>4 && chaine.substr(s-4,4)==".tns") + return remove_extension(chaine.substr(0,s-4)); + int l=int(chaine.find_last_of('.',s)); + int ll=int(chaine.find_last_of('/',s)); + if (l>0 && l=s || l>ll) + return chaine.substr(0,l); + } + return chaine; + } + + //environment * env=new environment; + + // Real object and real interval functions + + real_object & real_object::operator = (const real_object & g) { +#ifdef HAVE_LIBMPFR + mpfr_clear(inf); + mpfr_init2(inf,mpfr_get_prec(g.inf)); + mpfr_set(inf,g.inf,MPFR_RNDN); +#else + mpf_clear(inf); + mpf_init_set(inf,g.inf); +#endif + return *this; + } + +#ifdef HAVE_LIBMPFI + real_interval::real_interval(const mpfi_t & interv) { + int nbits=mpfi_get_prec(interv); + mpfr_set_prec(inf,nbits); + mpfi_get_fr(inf,interv); + mpfi_init2(infsup,nbits); + mpfi_set(infsup,interv); + } +#endif + + real_object & real_interval::operator = (const real_interval & g) { +#ifdef HAVE_LIBMPFR + mpfr_clear(inf); +#else + mpf_clear(inf); +#endif +#ifdef HAVE_LIBMPFI + mpfi_clear(infsup); +#else +#ifdef HAVE_LIBMPFR + mpfr_clear(sup); +#else + mpf_clear(sup); +#endif +#endif +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,mpfr_get_prec(g.inf)); + mpfr_set(inf,g.inf,MPFR_RNDN); +#else + mpf_init_set(inf,g.inf); +#endif +#ifdef HAVE_LIBMPFI + mpfi_init2(infsup,mpfi_get_prec(g.infsup)); + mpfi_set(infsup,g.infsup); +#else +#ifdef HAVE_LIBMPFR + mpfr_init2(sup,mpfr_get_prec(g.sup)); + mpfr_set(sup,g.sup,MPFR_RNDN); +#else + mpf_init_set(sup,g.sup); +#endif +#endif + return *this; + } + + real_object & real_interval::operator = (const real_object & g) { +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast (&g); +#endif + if (ptr) + return *this=*ptr; +#ifdef HAVE_LIBMPFR + mpfr_clear(inf); +#ifdef HAVE_LIBMPFI + mpfi_clear(infsup); +#else + mpfr_clear(sup); +#endif + mpfr_init2(inf,mpfr_get_prec(g.inf)); + mpfr_set(inf,g.inf,MPFR_RNDN); +#ifdef HAVE_LIBMPFI + mpfi_init2(infsup,mpfr_get_prec(g.inf)); + mpfi_set_fr(infsup,g.inf); +#else + mpfr_init2(sup,mpfr_get_prec(g.inf)); + mpfr_set(sup,g.inf,MPFR_RNDN); +#endif +#else // HAVE_LIBMPFR + mpf_clear(inf); +#ifdef HAVE_LIBMPFI + mpfi_clear(infsup); +#else + mpf_clear(sup); +#endif + mpf_init_set(inf,g.inf); +#ifdef HAVE_LIBMPFI + mpfi_init_set_fr(infsup,g.inf); +#else + mpf_init_set(sup,g.inf); +#endif +#endif // HAVE_LIBMPFR + return *this; + } + + real_object::real_object() { +#ifdef HAVE_LIBMPFR + mpfr_init(inf); +#else + mpf_init(inf); +#endif + } + + real_object::real_object(const real_object & g){ +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,mpfr_get_prec(g.inf)); + mpfr_set(inf,g.inf,MPFR_RNDN); +#else + mpf_init_set(inf,g.inf); +#endif + } + + real_object::real_object(double d) { +#ifdef HAVE_LIBMPFR + mpfr_init_set_d(inf,d,MPFR_RNDN); +#else + mpf_init_set_d(inf,d); +#endif + } + +#ifdef HAVE_LIBMPFR + real_object::real_object(const mpfr_t & d) { + mpfr_init2(inf,mpfr_get_prec(d)); + mpfr_set(inf,d,MPFR_RNDN); + } +#endif + + real_object::real_object(const mpf_t & d) { +#ifdef HAVE_LIBMPFR + mpfr_init(inf); + mpfr_set_f(inf,d,MPFR_RNDN); +#else + mpf_init_set(inf,d); +#endif + } + + real_object::real_object(const gen & g){ + switch (g.type){ + case _INT_: +#ifdef HAVE_LIBMPFR + mpfr_init_set_si(inf,g.val,MPFR_RNDN); +#else + mpf_init_set_si(inf,g.val); +#endif + return; + case _DOUBLE_: +#ifdef HAVE_LIBMPFR + mpfr_init_set_d(inf,g._DOUBLE_val,MPFR_RNDN); +#else + mpf_init_set_d(inf,g._DOUBLE_val); +#endif + return; + case _ZINT: +#ifdef HAVE_LIBMPFR + mpfr_init(inf); + mpfr_set_z(inf,*g._ZINTptr,MPFR_RNDN); +#else + mpf_init(inf); + mpf_set_z(inf,*g._ZINTptr); +#endif + return; + case _REAL: +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,mpfr_get_prec(g._REALptr->inf)); + mpfr_set(inf,g._REALptr->inf,MPFR_RNDN); +#else + mpf_init_set(inf,g._REALptr->inf); +#endif + return; + } + if (g.type==_FRAC){ + gen tmp=real_object(g._FRACptr->num)/real_object(g._FRACptr->den); + if (tmp.type==_REAL){ +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,mpfr_get_prec(tmp._REALptr->inf)); + mpfr_set(inf,tmp._REALptr->inf,MPFR_RNDN); +#else + mpf_init_set(inf,tmp._REALptr->inf); +#endif + return; + } + } +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Unable to convert to real ")+g.print(context0)); +#endif + return; + } + + real_object::real_object(const gen & g,unsigned int precision){ + switch (g.type){ + case _INT_: +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,precision); + mpfr_set_si(inf,g.val,MPFR_RNDN); +#else + mpf_init_set_si(inf,g.val); +#endif + return; + case _DOUBLE_: +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,precision); + mpfr_set_d(inf,g._DOUBLE_val,MPFR_RNDN); +#else + mpf_init_set_d(inf,g._DOUBLE_val); +#endif + return; + case _ZINT: +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,precision); + mpfr_set_z(inf,*g._ZINTptr,MPFR_RNDN); +#else + mpf_init(inf); + mpf_set_z(inf,*g._ZINTptr); +#endif + return; + case _REAL: +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,precision); + mpfr_set(inf,g._REALptr->inf,MPFR_RNDN); +#else + mpf_init_set(inf,g._REALptr->inf); +#endif + return; + } + if (g.type==_FRAC){ + gen tmp=real_object(g._FRACptr->num,precision)/real_object(g._FRACptr->den,precision); + if (tmp.type==_REAL){ +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,mpfr_get_prec(tmp._REALptr->inf)); + mpfr_set(inf,tmp._REALptr->inf,MPFR_RNDN); +#else + mpf_init_set(inf,tmp._REALptr->inf); +#endif + return; + } + } + int save_decimal_digits=decimal_digits(context0); + set_decimal_digits(giacmax(20,std::ceil(precision* + 0.30102999566398119 + //M_LN2/M_LN10 + )),context0); + gen tmp=re(evalf(g,1,context0),context0); + set_decimal_digits(save_decimal_digits,context0); + if (tmp.type!=_REAL){ +#ifndef NO_STDEXCEPT + setsizeerr(gettext("Unable to convert to real ")+g.print(context0)); +#endif + return; + } +#ifdef HAVE_LIBMPFR + mpfr_init2(inf,precision); + mpfr_set(inf,tmp._REALptr->inf,MPFR_RNDN); +#else + mpf_init_set(inf,tmp._REALptr->inf); +#endif + } + + gen::gen(const real_object & g){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_real_object) << 16; +#else + __REALptr = new ref_real_object; +#endif + type = _REAL; + subtype=0; +#ifdef HAVE_LIBMPFR + mpfr_set_prec(_REALptr->inf,mpfr_get_prec(g.inf)); + mpfr_set(_REALptr->inf,g.inf,MPFR_RNDN); +#else + mpf_set(_REALptr->inf,g.inf); +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _REALptr > stackptr) + ctrl_c=interrupted=true; +#endif + } + + gen::gen(const real_interval & g){ +#ifdef SMARTPTR64 + * ((ulonglong * ) this) = ulonglong(new ref_real_interval) << 16; +#else + __REALptr = (ref_real_object *) new ref_real_interval; +#endif +#if defined KHICAS && !defined SIMU + if ((size_t) _REALptr > stackptr) + ctrl_c=interrupted=true; +#endif + type = _REAL; + subtype=0; +#ifdef NO_RTTI + real_interval * ptr=0; +#else + real_interval * ptr=dynamic_cast(_REALptr); +#endif +#ifdef HAVE_LIBMPFR + mpfr_set_prec(ptr->inf,mpfr_get_prec(g.inf)); + mpfr_set(ptr->inf,g.inf,MPFR_RNDN); +#else + mpf_set(ptr->inf,g.inf); +#endif +#ifdef HAVE_LIBMPFI + int nbits=mpfi_get_prec(g.infsup); + mpfi_set_prec(ptr->infsup,nbits); + mpfi_set(ptr->infsup,g.infsup); +#else +#ifdef HAVE_LIBMPFR + mpfr_set(ptr->sup,g.sup,MPFR_RNDN); +#else + mpf_set(ptr->sup,g.sup); +#endif +#endif + } + + double real_object::evalf_double() const{ +#ifdef HAVE_LIBMPFR + return mpfr_get_d(inf,MPFR_RNDN); +#else + return mpf_get_d(inf); +#endif + } + + gen real_object::addition (const gen & g,GIAC_CONTEXT) const{ + switch (g.type){ + case _REAL: + return *this+*g._REALptr; + case _CPLX: + return gen(this->addition(*g._CPLXptr,contextptr),*(g._CPLXptr+1)); + case _FRAC: + if (!is_integer(g._FRACptr->num) || !is_integer(g._FRACptr->den)) + return sym_add(*this,g,contextptr); + case _INT_: case _DOUBLE_: case _ZINT: +#ifdef HAVE_LIBMPFR + return *this+real_object(g,mpfr_get_prec(inf)); +#else + return *this+real_object(g); +#endif + default: + return sym_add(*this,g,contextptr); + } + return gensizeerr(gettext("real_object + gen")+this->print(contextptr)+","+g.print(contextptr)); + } + + gen real_interval::addition (const gen & g,GIAC_CONTEXT) const{ + switch (g.type){ + case _REAL: + return *this+*g._REALptr; + case _CPLX: + return gen(this->addition(*g._CPLXptr,contextptr),*(g._CPLXptr+1)); + case _FRAC: + if (!is_integer(g._FRACptr->num) || !is_integer(g._FRACptr->den)) + return sym_add(*this,g,contextptr); + case _INT_: case _DOUBLE_: case _ZINT: +#ifdef HAVE_LIBMPFR + return *this+real_object(g,mpfr_get_prec(inf)); +#else + return *this+real_object(g); +#endif + default: + return sym_add(*this,g,contextptr); + } + return gensizeerr(gettext("real_object + gen")+this->print(contextptr)+","+g.print(contextptr)); + } + + gen real_object::operator + (const gen & g) const{ + return addition(g,context0); + } + + static real_interval add(const real_interval & i,const real_interval & g){ + real_interval res(i); +#ifdef HAVE_LIBMPFR + mpfr_add(res.inf,i.inf,g.inf,MPFR_RNDD); +#ifdef HAVE_LIBMPFI + mpfi_add(res.infsup,i.infsup,g.infsup); +#else + mpfr_add(res.sup,i.sup,g.sup,MPFR_RNDU); +#endif +#else // HAVE_LIBMPFR + mpf_add(res.inf,i.inf,g.inf); +#ifdef HAVE_LIBMPFI + mpfi_add(res.infsup,i.infsup,g.infsup); +#else + mpf_add(res.sup,i.sup,g.sup); +#endif +#endif // HAVE_LIBMPFR + return res; + } + + real_interval real_interval::operator + (const real_interval & g) const{ + return add(*this,g); + } + + static real_interval add(const real_interval & i,const real_object & g){ +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast(&g); +#endif + if (ptr) + return add(i,*ptr); + real_interval res(i); +#ifdef HAVE_LIBMPFR + mpfr_add(res.inf,i.inf,g.inf,MPFR_RNDD); +#ifdef HAVE_LIBMPFI + mpfi_add_fr(res.infsup,i.infsup,g.inf); +#else + mpfr_add(res.sup,i.sup,g.inf,MPFR_RNDU); +#endif +#else // HAVE_LIBMPFR + mpf_add(res.inf,i.inf,g.inf); +#ifdef HAVE_LIBMPFI + mpfi_add_fr(res.infsup,i.infsup,g.inf); +#else + mpf_add(res.sup,i.sup,g.inf); +#endif +#endif // HAVE_LIBMPFR + return res; + } + + gen real_interval::operator + (const real_object & g) const{ + return add(*this,g); + } + + gen real_object::operator + (const real_object & g) const{ +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast(&g); +#endif + if (ptr) + return add(*ptr,*this); +#ifdef HAVE_LIBMPFR + mpfr_t sum; + mpfr_init2(sum,giacmin(mpfr_get_prec(this->inf),mpfr_get_prec(g.inf))); + mpfr_add(sum,this->inf,g.inf,MPFR_RNDN); + real_object res(sum); + mpfr_clear(sum); +#else + mpf_t sum; + mpf_init(sum); + mpf_add(sum,this->inf,g.inf); +#ifdef LONGFLOAT_DOUBLE + real_object res; res.inf=sum; +#else + real_object res(sum); +#endif + mpf_clear(sum); +#endif + return res; + } + + gen real_object::subtract (const gen & g,GIAC_CONTEXT) const{ + return substract(g,contextptr); + } + gen real_object::substract (const gen & g,GIAC_CONTEXT) const{ + switch (g.type){ + case _REAL: + return *this-*g._REALptr; + case _FRAC: + if (!is_integer(g._FRACptr->num) || !is_integer(g._FRACptr->den)) + return sym_sub(*this,g,contextptr); + case _INT_: case _DOUBLE_: case _ZINT: +#ifdef HAVE_LIBMPFR + return *this - real_object(g,mpfr_get_prec(inf)); +#else + return *this - real_object(g); +#endif + default: + return sym_sub(*this,g,contextptr); + } + return gensizeerr(gettext("real_object + gen")+this->print(contextptr)+","+g.print(contextptr)); + } + gen real_interval::subtract (const gen & g,GIAC_CONTEXT) const{ + return substract(g,contextptr); + } + gen real_interval::substract (const gen & g,GIAC_CONTEXT) const{ + switch (g.type){ + case _REAL: + return *this-*g._REALptr; + case _FRAC: + if (!is_integer(g._FRACptr->num) || !is_integer(g._FRACptr->den)) + return sym_sub(*this,g,contextptr); + case _INT_: case _DOUBLE_: case _ZINT: +#ifdef HAVE_LIBMPFR + return *this - real_object(g,mpfr_get_prec(inf)); +#else + return *this - real_object(g); +#endif + default: + return sym_sub(*this,g,contextptr); + } + return gensizeerr(gettext("real_object + gen")+this->print(contextptr)+","+g.print(contextptr)); + } + + gen real_object::operator - (const gen & g) const{ + return substract(g,context0); + } + + static real_interval sub(const real_interval & i,const real_interval & g){ + real_interval res(i); +#ifdef HAVE_LIBMPFI + mpfi_sub(res.infsup,i.infsup,g.infsup); + mpfr_sub(res.inf,i.inf,g.inf,MPFR_RNDD); +#else +#ifdef HAVE_LIBMPFR + mpfr_sub(res.inf,i.sup,g.inf,MPFR_RNDD); + mpfr_sub(res.sup,i.inf,g.sup,MPFR_RNDU); +#else + mpf_sub(res.inf,i.sup,g.inf); + mpf_sub(res.sup,i.inf,g.sup); +#endif +#endif + return res; + } + + real_interval real_interval::operator - (const real_interval & g) const{ + return sub(*this,g); + } + + static real_interval sub(const real_interval & i,const real_object & g){ +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast(&g); +#endif + if (ptr) + return sub(i,*ptr); + real_interval res(i); +#ifdef HAVE_LIBMPFI + mpfi_sub_fr(res.infsup,i.infsup,g.inf); + mpfr_sub(res.inf,i.inf,g.inf,MPFR_RNDD); +#else +#ifdef HAVE_LIBMPFR + mpfr_sub(res.inf,i.sup,g.inf,MPFR_RNDD); + mpfr_sub(res.sup,i.inf,g.inf,MPFR_RNDU); +#else + mpf_sub(res.inf,i.sup,g.inf); + mpf_sub(res.sup,i.inf,g.inf); +#endif +#endif + return res; + } + + gen real_interval::operator - (const real_object & g) const{ + return sub(*this,g); + } + + gen real_object::operator - (const real_object & g) const{ +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast(&g); +#endif + if (ptr) + return -(*ptr)+(*this); +#ifdef HAVE_LIBMPFR + mpfr_t sum; + mpfr_init2(sum,giacmin(mpfr_get_prec(this->inf),mpfr_get_prec(g.inf))); + mpfr_sub(sum,this->inf,g.inf,MPFR_RNDN); + real_object res(sum); + mpfr_clear(sum); +#else + mpf_t sum; + mpf_init(sum); + mpf_sub(sum,this->inf,g.inf); +#ifdef LONGFLOAT_DOUBLE + real_object res; res.inf=sum; +#else + real_object res(sum); +#endif + mpf_clear(sum); +#endif + return res; + } + + gen real_object::operator -() const { +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast(this); +#endif + if (ptr) + return -*ptr; + real_object res(*this); +#ifdef HAVE_LIBMPFR + mpfr_neg(res.inf,res.inf,MPFR_RNDN); +#else + mpf_neg(res.inf,res.inf); +#endif + return res; + } + + gen real_object::inv() const { + real_object res(*this); +#ifdef HAVE_LIBMPFR + mpfr_ui_div(res.inf,1,res.inf,MPFR_RNDN); +#else + mpf_ui_div(res.inf,1,res.inf); +#endif + return res; + } + + gen real_object::sqrt() const { +#if defined LONGFLOAT_DOUBLE && !defined HAVE_LIBMPFR + real_object res; res.inf=std::sqrt(inf); return res; +#else + real_object res(*this); +#ifdef HAVE_LIBMPFR + mpfr_sqrt(res.inf,res.inf,MPFR_RNDN); +#else + mpf_sqrt(res.inf,res.inf); +#endif + return res; +#endif + } + + gen real_object::abs() const { +#ifdef HAVE_LIBMPFR + if (mpfr_sgn(inf)>=0) +#else + if (mpf_sgn(inf)>=0) +#endif + return *this; + return -(*this); + } + + static void compile_with_mpfr(){ + setsizeerr(gettext("Compile with MPFR or USE_GMP_REPLACEMENTS if you want transcendental long float support")); + } + + gen real_object::exp() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::exp(res.inf); +#else + *res.inf = ::exp(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_exp(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif // USE_GMP_REPLACEMENTS + return res; + } + + gen real_object::log() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::log(res.inf); +#else + *res.inf = ::log(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_log(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::sin() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::sin(res.inf); +#else + *res.inf = ::sin(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_sin(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::cos() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::cos(res.inf); +#else + *res.inf = ::cos(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_cos(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::tan() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::tan(res.inf); +#else + *res.inf = ::tan(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_tan(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::sinh() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::sinh(res.inf); +#else + *res.inf = ::sinh(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_sinh(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::cosh() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::cosh(res.inf); +#else + *res.inf = ::cosh(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_cosh(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::tanh() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::tanh(res.inf); +#else + *res.inf = ::tanh(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_tanh(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::asin() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::asin(res.inf); +#else + *res.inf = ::asin(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_asin(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::acos() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::acos(res.inf); +#else + *res.inf = ::acos(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_acos(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::atan() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::atan(res.inf); +#else + *res.inf = ::atan(*res.inf); +#endif +#else +#ifdef HAVE_LIBMPFR + mpfr_atan(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::asinh() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf= std::log(res.inf+std::sqrt(res.inf*res.inf+1)); +#else + *res.inf = ::asinh(*res.inf); +#endif +#else +#if defined HAVE_LIBMPFR && !defined BF2GMP_H + mpfr_asinh(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::acosh() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::log(res.inf+std::sqrt(res.inf+1)*std::sqrt(res.inf-1)); +#else + *res.inf = ::acosh(*res.inf); +#endif +#else +#if defined HAVE_LIBMPFR && !defined BF2GMP_H + mpfr_acosh(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_object::atanh() const { + real_object res(*this); +#ifdef USE_GMP_REPLACEMENTS +#ifdef LONGFLOAT_DOUBLE + res.inf=std::log((1+res.inf)/(1-res.inf))/2; +#else + *res.inf = ::atanh(*res.inf); +#endif +#else +#if defined HAVE_LIBMPFR && !defined BF2GMP_H + mpfr_atanh(res.inf,res.inf,MPFR_RNDN); +#else + compile_with_mpfr(); +#endif +#endif + return res; + } + + gen real_interval::operator -() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFR + mpfr_neg(res.inf,res.inf,MPFR_RNDU); +#ifdef HAVE_LIBMPFI + mpfi_neg(res.infsup,res.infsup); +#else + mpfr_neg(res.sup,res.sup,MPFR_RNDD); + mpfr_swap(res.inf,res.sup); +#endif +#else // MPFR + mpf_neg(res.inf,res.inf); +#ifdef HAVE_LIBMPFI + mpfi_neg(res.infsup,res.infsup); +#else + mpf_neg(res.sup,res.sup); +#ifdef mpf_swap + mpf_swap(res.inf,res.sup); +#endif +#endif +#endif // MPFR + return res; + } + + gen real_interval::inv() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_ui_div(res.infsup,1,res.infsup); + mpfr_ui_div(res.inf,1,res.inf,MPFR_RNDD); +#else + // FIXME check sign +#ifndef NO_STDEXCEPT + setsizeerr(gettext("real_interval inv")); +#endif + /* mpf_neg(res.inf,res.inf); + mpf_neg(res.sup,res.sup); + mpf_swap(res.inf,res.sup); */ +#endif + return res; + } + + gen real_interval::sqrt() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_sqrt(res.infsup,res.infsup); + mpfr_sqrt(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::abs() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_abs(res.infsup,res.infsup); + mpfr_abs(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval abs")); +#endif + } + + gen real_interval::exp() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_exp(res.infsup,res.infsup); + mpfr_exp(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::log() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_log(res.infsup,res.infsup); + mpfr_log(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::sin() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_sin(res.infsup,res.infsup); + mpfr_sin(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::cos() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_cos(res.infsup,res.infsup); + mpfr_cos(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::tan() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_tan(res.infsup,res.infsup); + mpfr_tan(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::sinh() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_sinh(res.infsup,res.infsup); + mpfr_sinh(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::cosh() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_cosh(res.infsup,res.infsup); + mpfr_cosh(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::tanh() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_tanh(res.infsup,res.infsup); + mpfr_tanh(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::asin() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_asin(res.infsup,res.infsup); + mpfr_asin(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::acos() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_acos(res.infsup,res.infsup); + mpfr_acos(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::atan() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_atan(res.infsup,res.infsup); + mpfr_atan(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::asinh() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_asinh(res.infsup,res.infsup); + mpfr_asinh(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::acosh() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_acosh(res.infsup,res.infsup); + mpfr_acosh(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_interval::atanh() const { + real_interval res(*this); +#ifdef HAVE_LIBMPFI + mpfi_atanh(res.infsup,res.infsup); + mpfr_atanh(res.inf,res.inf,MPFR_RNDD); + return res; +#else + return gensizeerr(gettext("real_interval sqrt")); +#endif + } + + gen real_object::multiply (const gen & g,GIAC_CONTEXT) const{ + switch (g.type){ + case _REAL: + return *this * *g._REALptr; + case _CPLX: + return gen(this->multiply(*g._CPLXptr,contextptr),this->multiply(*(g._CPLXptr+1),contextptr)); + case _FRAC: + if (!is_integer(g._FRACptr->num) || !is_integer(g._FRACptr->den)) + return sym_mult(*this,g,contextptr); + case _INT_: case _DOUBLE_: case _ZINT: +#ifdef HAVE_LIBMPFR + return *this * real_object(g,mpfr_get_prec(inf)); +#else + return *this * real_object(g); +#endif + default: + return sym_mult(*this,g,contextptr); + } + } + + gen real_interval::multiply (const gen & g,GIAC_CONTEXT) const{ + switch (g.type){ + case _REAL: + return *this * *g._REALptr; + case _CPLX: + return gen(this->multiply(*g._CPLXptr,contextptr),this->multiply(*(g._CPLXptr+1),contextptr)); + case _FRAC: + if (!is_integer(g._FRACptr->num) || !is_integer(g._FRACptr->den)) + return sym_mult(*this,g,contextptr); + case _INT_: case _DOUBLE_: case _ZINT: +#ifdef HAVE_LIBMPFR + return *this * real_object(g,mpfr_get_prec(inf)); +#else + return *this * real_object(g); +#endif + default: + return sym_mult(*this,g,contextptr); + } + } + + gen real_object::operator * (const gen & g) const{ + return multiply(g,context0); + } + + gen real_object::operator / (const gen & g) const{ + return *this * g.inverse(context0); + } + + gen real_object::divide (const gen & g,GIAC_CONTEXT) const{ + return multiply(g.inverse(contextptr),contextptr); + } + + gen real_interval::divide (const gen & g,GIAC_CONTEXT) const{ + return multiply(g.inverse(contextptr),contextptr); + } + + gen real_object::operator / (const real_object & g) const{ + return *this * g.inv(); + } + + static real_interval mul(const real_interval & i,const real_interval & g){ + real_interval res(i); +#ifdef HAVE_LIBMPFR + mpfr_mul(res.inf,i.inf,g.inf,MPFR_RNDN); +#else + mpf_mul(res.inf,i.inf,g.inf); +#endif +#ifdef HAVE_LIBMPFI + mpfi_mul(res.infsup,i.infsup,g.infsup); +#else + // FIXME: should check signs for interval arithmetic!! +#ifndef NO_STDEXCEPT + setsizeerr(gettext("real_interval mul")); +#endif + // mpf_mul(res.sup,i.sup,g.sup); +#endif + return res; + } + + real_interval real_interval::operator * (const real_interval & g) const{ + return mul(*this,g); + } + + static real_interval mul(const real_interval & i,const real_object & g){ +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast(&g); +#endif + if (ptr) + return mul(i,*ptr); + real_interval res(i); +#ifdef HAVE_LIBMPFR + mpfr_mul(res.inf,i.inf,g.inf,MPFR_RNDN); +#else + mpf_mul(res.inf,i.inf,g.inf); +#endif +#ifdef HAVE_LIBMPFI + mpfi_mul_fr(res.infsup,i.infsup,g.inf); +#else + // FIXME: should check signs for interval arithmetic!! +#ifndef NO_STDEXCEPT + setsizeerr(gettext("real_interval mul 2")); +#endif + // mpf_mul(res.sup,i.sup,g.inf); +#endif + return res; + } + + gen real_interval::operator * (const real_object & g) const{ + return mul(*this,g); + } + + gen real_object::operator * (const real_object & g) const{ +#ifdef NO_RTTI + const real_interval * ptr=0; +#else + const real_interval * ptr=dynamic_cast(&g); +#endif + if (ptr) + return mul(*ptr,*this); +#ifdef HAVE_LIBMPFR + mpfr_t sum; + mpfr_init2(sum,giacmin(mpfr_get_prec(this->inf),mpfr_get_prec(g.inf))); + mpfr_mul(sum,this->inf,g.inf,MPFR_RNDN); + real_object res(sum); + mpfr_clear(sum); +#else + mpf_t sum; + mpf_init(sum); + mpf_mul(sum,this->inf,g.inf); +#ifdef LONGFLOAT_DOUBLE + real_object res; res.inf=sum; +#else + real_object res(sum); +#endif + mpf_clear(sum); +#endif + return res; + } + + int real_object::is_positive() const{ +#ifdef HAVE_LIBMPFR + return mpfr_sgn(inf); +#else + return mpf_sgn(inf); +#endif + } + + int real_interval::is_positive() const{ +#ifdef HAVE_LIBMPFI + if (mpfi_is_zero(infsup)>0) + return 0; + if (mpfi_is_pos(infsup)) + return 1; + if (mpfi_is_nonpos(infsup)) + return -1; + return 0; +#else +#ifdef HAVE_LIBMPFR + return mpfr_sgn(inf); +#else + return mpf_sgn(inf); +#endif +#endif + } + + string print_binary(const real_object & r){ +#ifdef HAVE_LIBMPFR + mp_exp_t expo; + int dd=mpfr_get_prec(r.inf); +#ifdef VISUALC + char * ptr=new char[dd+2]; +#else + char ptr[dd+2]; +#endif + if (!mpfr_get_str(ptr,&expo,2,dd,r.inf,MPFR_RNDN) || !(*ptr)) + return "MPFR print binary error "+r.print(context0); + string res; + if (ptr[0]=='-') + res="-0000."+string(ptr+1); + else + res="0000."+string(ptr); +#ifdef VISUALC + delete [] ptr; +#endif // VISUALC + return res+"E"+print_INT_(expo); +#else // MPFR + return "Error no MPFR printing "+r.print(context0); +#endif + } + + gen read_binary(const string & s,unsigned int precision){ +#ifdef HAVE_LIBMPFR + real_object r; + mpfr_set_prec(r.inf,precision); +#ifndef HAVE_MPFR_SET_STR_RAW + // MPFR 2.2 + mpfr_strtofr (r.inf, (char *)s.c_str(), 0, 2, MPFR_RNDN); +#else + // FOR MPFR 2.0 use instead + mpfr_set_str_raw(r.inf,(char *)s.c_str()); +#endif // GNUWINCE + return r; + return gensizeerr(gettext("MPFR error reading binary ")+s); +#else // HAVE_LIBMPFR + return gensizeerr(gettext("Error no MPFR reading ")+s); +#endif // HAVE_LIBMPFR + return undef; + } + + std::string real_object::print(GIAC_CONTEXT) const{ +#if defined HAVE_LIBMPFI && !defined NO_RTTI + if (const real_interval * ptr=dynamic_cast(this)){ + mpfr_t l,u; + int nbits=mpfi_get_prec(ptr->infsup); + mpfr_init2(l,nbits); mpfr_init2(u,nbits); + mpfi_get_left(l,ptr->infsup); mpfi_get_right(u,ptr->infsup); + real_object L(l),U(u); + mpfr_clear(l); mpfr_clear(u); + string s("["); + s += L.print(contextptr); + s += ".."; + s += U.print(contextptr); + s += "]"; + return s; + } +#endif +#ifdef HAVE_LIBMPFR + if (mpfr_nan_p(inf)) + return "undef"; + bool negatif=mpfr_sgn(inf)<0; + if (mpfr_inf_p(inf)) + return negatif?"-infinity":"+infinity"; + mp_exp_t expo; + int dd=mpfr_get_prec(inf); +#if defined(EMCC) || defined(EMCC2) // workaround: mpfr_set_prec or get_prec has problems with emcc + if (dd==53) + dd=100; +#endif + dd=bits2digits(dd); + dd--; +#ifdef VISUALC + char * ptr=new char[dd+2]; +#else + char ptr[dd+2]; +#endif + if (negatif){ + mpfr_t inf2; + mpfr_init2(inf2,mpfr_get_prec(inf)); + mpfr_neg(inf2,inf,MPFR_RNDN); + mpfr_get_str(ptr,&expo,10,dd,inf2,MPFR_RNDN); + mpfr_clear(inf2); + } + else + mpfr_get_str(ptr,&expo,10,dd,inf,MPFR_RNDN); + std::string res(ptr); +#ifndef BF2GMP_H + if (expo){ + if (expo==1){ + string reste(res.substr(1,res.size()-1)); + res=res[0]+("."+reste); + } + else { + res = "0."+res; + res += calc_mode(contextptr)==1?'E':'e'; + res += print_INT_(expo); + } + } + else + res="0."+res; +#endif +#ifdef VISUALC + delete [] ptr; +#endif + if (negatif) + return "-"+res; + else + return res; +#else + return printmpf_t(inf,contextptr); +#endif + } + + bool real_object::is_zero() const{ +#ifdef HAVE_LIBMPFR + return !mpfr_sgn(inf); +#else + return mpf_sgn(inf)==0; +#endif + } + + bool real_object::maybe_zero() const{ +#ifdef HAVE_LIBMPFR + return !mpfr_sgn(inf); +#else + return mpf_sgn(inf)==0; +#endif + } + + bool real_interval::is_zero() const { +#ifdef HAVE_LIBMPFI + return mpfi_is_zero(infsup); +#else + return real_object::is_zero(); +#endif + } + + bool real_interval::maybe_zero() const{ +#ifdef HAVE_LIBMPFI + return mpfi_has_zero(infsup); +#else + return real_object::maybe_zero(); +#endif + } + + bool real_object::is_inf() const{ +#ifdef HAVE_LIBMPFR + return !mpfr_inf_p(inf); +#else +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; +#endif + } + + bool real_interval::is_inf() const{ +#ifdef HAVE_LIBMPFI + return !mpfi_inf_p(infsup); +#else + return real_object::is_inf(); +#endif + } + + bool real_object::is_nan() const{ +#ifdef HAVE_LIBMPFR + return !mpfr_nan_p(inf); +#else +#ifndef NO_STDEXCEPT + setsizeerr(); +#endif + return false; +#endif + } + + bool real_interval::is_nan() const{ +#ifdef HAVE_LIBMPFI + return !mpfi_nan_p(infsup); +#else + return real_object::is_nan(); +#endif + } + + gen iprotecteval(const gen & g,int level,GIAC_CONTEXT){ +#ifdef KHICAS + enable_back_interrupt(); + gen res=protecteval(g,level,contextptr); + disable_back_interrupt(); + return res; +#else + return protecteval(g,level,contextptr); +#endif + } + +#if 0 // def KHICAS +#undef HAVE_LIBPTHREAD +#endif + +#ifdef HAVE_LIBPTHREAD + struct caseval_param{ + const char * s; + gen ans; + context * contextptr; + pthread_mutex_t mutex; + }; + void * thread_caseval(void * ptr_){ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); + caseval_param * ptr=(caseval_param *)ptr_; + pthread_mutex_lock(&ptr->mutex); + gen g(ptr->s,ptr->contextptr); + g=equaltosto(g,ptr->contextptr); + ptr->ans=iprotecteval(g,1,ptr->contextptr); + pthread_mutex_unlock(&ptr->mutex); + return ptr; + } +#endif + + bool islogo(const gen & g){ + if (g.type!=_VECT || g._VECTptr->empty()) return false; + if (g.subtype==_LOGO__VECT) return true; + const vecteur & v=*g._VECTptr; + if (islogo(v.back())) + return true; + for (size_t i=0;istack; + if (limit==0) + limit=init_stack_ptr; + if (limit==0) // not initialized, no check + return true; + if (cur<=limit){ + size_t d=limit-cur; + // CERR << d << '\n'; + if (dsizeof(buf)) + S=S.substr(0,sizeof(buf)-1); + strcpy(buf,S.c_str()); + } + xcas::textedit(buf,sizeof(buf),true,contextptr,filename); + s=buf; + //S=buf; + //return S.c_str(); + } + if (!strcmp(s,"toolbox menu")){ + char buf[1024]=""; + showCatalog(buf,0,0,&C); + drawRectangle(0,0,320,222,_WHITE); + S=buf; + return S.c_str(); + } + if (!strcmp(s,"var menu")){ + gen g=select_var(contextptr); + drawRectangle(0,0,320,222,_WHITE); + S=g.type==_STRNG?*g._STRNGptr:g.print(contextptr); + if (!strcmp(S.c_str(),"undef")) + S=""; + return S.c_str(); + } + if (!strcmp(s,".")){ + xcas::displaylogo(); + S=turtle_state(contextptr).print(&C); + return S.c_str(); + } + if (!strcmp(s,"..")){ + _efface_logo(vecteur(0),contextptr); + return "turtle cleared"; + } +#endif + const char init[]="init geogebra"; + const char close[]="close geogebra"; + if (!strcmp(s,init)){ + init_geogebra(1,&C); + return "geogebra mode on"; + } + if (!strcmp(s,close)){ + init_geogebra(0,&C); + return "geogebra mode off"; + } +#ifdef TIMEOUT + if (strlen(s)>8){ + string args(s); + if (args.substr(0,8)=="timeout "){ + string t=args.substr(8,args.size()-8); + double f=atof(t.c_str()); + if (f>=0 && f<24*60){ + caseval_maxtime=f; + S="Max eval time set to "+gen(f).print(); + return S.c_str(); + } + } + if (args.substr(0,8)=="ckevery "){ + string t=args.substr(8,args.size()-8); + int f=atoi(t.c_str()); + if (f>0 && f<1e6){ + caseval_mod=f; + S="Check every "+gen(f).print(); + return S.c_str(); + } + } + } + ctrl_c=false; + interrupted=false; + caseval_begin=time(0); +#endif +#ifdef HAVE_LIBPTHREAD + gen g; + caseval_param cp={s,0,&C,PTHREAD_MUTEX_INITIALIZER}; + pthread_t pth; + pthread_attr_t attr; + pthread_attr_init(&attr); + int cres=pthread_create(&pth,&attr,thread_caseval,(void *)&cp); + if (cres){ + g=gen(s,&C); + g=equaltosto(g,&C); + g=iprotecteval(g,1,&C); + } + else { + // void * ptr; +#ifdef TIMEOUT + double d=caseval_maxtime; +#else + double d=3; +#endif + usleep(10000); + for (;d>0;--d){ + for (unsigned k=0;k<100;++k){ + if (ctrl_c || interrupted){ + d=0; + break; + } + int locked=pthread_mutex_trylock(&cp.mutex); + if (!locked){ + pthread_mutex_unlock(&cp.mutex); + void * ptr; + cres=pthread_join(pth,&ptr); + d=-1; + if (cres){ + g=string2gen("Thread join error",false); + g.subtype=-1; + } + else + g=cp.ans; + break; + } + usleep(10000); + } + } + if (d==0){ + ctrl_c=interrupted=true; + usleep(200000); + pthread_cancel(pth); + // cres=pthread_join(pth,NULL); // does not work + g=string2gen("Timeout",false); + g.subtype=-1; + } + pthread_attr_destroy(&attr); + } +#else + gen g(s,&C); + g=equaltosto(g,&C); + if (g.type==_VECT && !g._VECTptr->empty() && g._VECTptr->front().is_symb_of_sommet(at_set_language)){ + vecteur v=*g._VECTptr; + iprotecteval(v.front(),1,&C); + v.erase(v.begin()); + if (g.subtype==_SEQ__VECT && v.size()==1) + g=v.front(); + else + g=gen(v,g.subtype); + } + gen gp=g; + if (gp.is_symb_of_sommet(at_add_autosimplify)) + gp=gp._SYMBptr->feuille; +#ifdef KHICAS + bool push=false; +#else + bool push=!gp.is_symb_of_sommet(at_mathml) && !gp.is_symb_of_sommet(at_set_language); +#endif + //bool push=!g.is_symb_of_sommet(at_mathml); + if (push){ + history_in(&C).push_back(g); + // COUT << "hin " << g << '\n'; + } + g=iprotecteval(g,1,&C); + if (push){ + history_out(&C).push_back(g); + // COUT << "hout " << g << '\n'; + } +#endif +#if (defined(EMCC) || defined(EMCC2)) && !defined SDL_KHICAS + // compile with -s LEGACY_GL_EMULATION=1 + gen last=g; + while (last.type==_VECT && last.subtype!=_LOGO__VECT && !last._VECTptr->empty()){ + gen tmp=last._VECTptr->back(); + if (tmp.is_symb_of_sommet(at_equal)) + last=vecteur(last._VECTptr->begin(),last._VECTptr->end()-1); + else + last=tmp; + } + if (last.type==_VECT && last.subtype==_LOGO__VECT){ + S="gr2d(logo("+last.print(&C)+"))"; + return S.c_str(); + } + if (calc_mode(&C)!=1 && (last.is_symb_of_sommet(at_pnt) || last.is_symb_of_sommet(at_pixon))){ +#if !defined(GIAC_GGB) && (defined(EMCC) || defined EMCC2) && !defined SDL_KHICAS + if (is3d(last)){ + int worker=0; + worker=EM_ASM_INT_V({ + if (typeof(UI)!=="undefined" && typeof(UI.disable3d) !== 'undefined' && UI.disable3d) + return UI.disable3d; + if (Module.worker) return 1; else return 0; + }); + if (worker==-1) return "gl3d_not_supported"; + if (worker) return "gl3d_not_supported_if_workers_are_enabled"; + //giac_renderer(last.print(&C).c_str()); + int n=giac_gen_renderer(g,&C); + S="gl3d "+print_INT_(n); + return S.c_str(); + } +#endif // GIAC_GGB + last=remove_at_pnt(last); + if (last.is_symb_of_sommet(at_pixon)){ + S="gr2d(pixon("; + pixon_print(g,S,&C); + S+="))"; + return S.c_str(); + } + return svg2doutput(g,S,&C); + } +#endif // EMCC + if (calc_mode(&C)==1 && !lop(g,at_rootof).empty()) + g=evalf(g,1,&C); + if (has_undef_stringerr(g,S)){ + S="GIAC_ERROR: "+S; + } + else { + gen last=g; + while (last.type==_VECT && last.subtype!=_LOGO__VECT && !last._VECTptr->empty()){ + gen tmp=last._VECTptr->back(); + if (tmp.is_symb_of_sommet(at_equal)) + last=vecteur(last._VECTptr->begin(),last._VECTptr->end()-1); + else + last=tmp; + } +#if defined KHICAS || defined SDL_KHICAS // replace ],[ by ][ + if (last.is_symb_of_sommet(at_pnt)){ + if (os_shell || nspirelua) + xcas::displaygraph(g,gp,&C); + S="Graphic_object"; + } + else { + if (os_shell){ + if (islogo(g)) + xcas::displaylogo(); + else { + if ( (g.type==_SYMB || (warn_symb_program_sto && g.type==_VECT && !g._VECTptr->empty() && g._VECTptr->front().type!=_STRNG)) && taille(g,256)<=256) + g=xcas::eqw(g,true,&C); + } + } + if (taille(g,100)>=100) + S="Large_object"; + else + S=g.print(&C); + } + if (!os_shell){ + string S_; + S_ += S[0]; + for (size_t i=1;i+11) + S_ +=S[S.size()-1]; + S=S_; + if (S.size()>=3 && S[0]=='[' && S[1]!='[' && S[S.size()-1]==']') + S='['+S+']'; // vector/list not allowed in Numworks calc app + } +#else + if (calc_mode(contextptr)!=1 && last.is_symb_of_sommet(at_pnt)) + S="Graphic_object"; + else if (islogo(g)) + S="Logo_turtle"; + else + S=g.print(&C); +#if !defined GIAC_GGB +#if defined EMCC || defined EMCC2 + double add_evalf=EM_ASM_DOUBLE_V({ + if (typeof(UI)!=="undefined" && typeof(UI.add_evalf)!="undefined") + return UI.add_evalf*1.0; + return 1.0; + }), + js_bigint=EM_ASM_DOUBLE_V({ + if (typeof(UI)!=="undefined" && typeof(UI.js_bigint)!="undefined") + return UI.js_bigint*1.0; + return 0.0; + }); +#else + double add_evalf=false,js_bigint=false; +#endif + if (g.type==_FRAC || g.type==_ZINT){ + if (add_evalf){ + S += "="; + S += evalf_double(g,1,&C).print(&C); + } + } + if (js_bigint && is_integer(g)) + S += "n"; + if (add_evalf && g.type==_SYMB){ + g=evalf_double(g,1,&C); + if (g.type<=_CPLX){ + S += "="; + S += g.print(&C); + } + } +#endif // !defined GIAC_GGB +#endif // NUWMORKS + } + return S.c_str(); + } + + gen nws_ans=0; + gen replace_ans(const gen & g,GIAC_CONTEXT){ + if (g==at_ans) + return nws_ans; + if (g.type==_VECT) + return apply(*g._VECTptr,replace_ans,contextptr); + if (g.type!=_SYMB) + return g; + return symbolic(g._SYMBptr->sommet,replace_ans(g._SYMBptr->feuille,contextptr)); + } + +const char * nws_caseval(const char * s){ + static string * sptr=0; +#if DBG + confirm("caseval",s); +#endif + if (!sptr) sptr=new string; + string & S=*sptr; + static context * contextptr=0; + if (!contextptr) contextptr=new context; + int pc=python_compat(contextptr); + python_compat(0,contextptr); + logptr(0,contextptr); +#if defined KHICAS || defined SDL_KHICAS + int dc=xcas::dconsole_mode; + xcas::dconsole_mode=0; +#endif + calc_mode(110,contextptr); // print pi, don't use 38 (breaks Poincare) + gen g(s,contextptr); + g=equaltosto(g,contextptr); + if (g.type==_SYMB){ + gen ff=g._SYMBptr->feuille; // skip regroup() + if (ff.type==_SYMB){ + gen f=ff._SYMBptr->feuille; // workaround for args of command in matrix + if (f.type==_VECT && f._VECTptr->size()==2){ + vecteur v=*f._VECTptr; + if (v.front().type==_FUNC){ + ff=symbolic(*v.front()._FUNCptr,v[1]); + f=ff._SYMBptr->feuille; + g=symbolic(g._SYMBptr->sommet,ff); + } + } + if (f.type==_VECT && f._VECTptr->size()==1){ + f=f._VECTptr->front(); + if (f.type==_VECT){ + f.subtype=_SEQ__VECT; + g=symbolic(ff._SYMBptr->sommet,f); + } + } + } + } +#if DBG + confirm("parsed 1",g.print(contextptr).c_str()); +#endif + if (g.type==_VECT && !g._VECTptr->empty() && g._VECTptr->front().is_symb_of_sommet(at_set_language)){ + vecteur v=*g._VECTptr; + protecteval(v.front(),1,contextptr); + v.erase(v.begin()); + if (g.subtype==_SEQ__VECT && v.size()==1) + g=v.front(); + else + g=gen(v,g.subtype); + } + g=replace_ans(g,contextptr); +#if 0 // def EMCC + EM_ASM({ + var value = UTF8ToString($0); + console.log(value); + },("nws_casval "+g.print()).c_str()); +#endif + gen gp=g; + if (gp.is_symb_of_sommet(at_add_autosimplify)) + gp=gp._SYMBptr->feuille; + bool push=!gp.is_symb_of_sommet(at_set_language); + //bool push=!g.is_symb_of_sommet(at_mathml); + if (push){ + history_in(contextptr).push_back(g); + // COUT << "hin " << g << endl; + } + gen name; + if (gp.is_symb_of_sommet(at_sto)) + name=gp._SYMBptr->feuille[1]; + g=protecteval(g,1,contextptr); + if (strncmp("angle_radian:=",s,14)) + nws_ans=g; +#if DBG + confirm("evaled",g.print(contextptr).c_str()); +#endif + if (push){ + history_out(contextptr).push_back(g); + // COUT << "hout " << g << endl; + } + if (!lop(g,at_rootof).empty()) + g=evalf(g,1,contextptr); + if (has_undef_stringerr(g,S)){ + //confirm("GIAC_ERROR: ",S.c_str()); + S="undef"; + } + else if (g==minus_inf) + S="-oo"; + else if (is_inf(g)) + S="oo"; + else if (g.is_symb_of_sommet(at_program)){ + gen a,b; + S="function"; + //confirm(name.print(contextptr).c_str(),g.print(contextptr).c_str()); + if (name.type==_IDNT && is_algebraic_program(g,a,b)){ + if (a.type==_VECT && a._VECTptr->size()==1) + a=a._VECTptr->front(); + if (a.type==_IDNT){ + // string to create the same function in Epsilon + S +=' '; + if (a!=x__IDNT_e) + b = subst(b,a,x__IDNT_e,false,contextptr); + S += b.print(contextptr); + // sto + S += (char) 0xe2; S+= (char) 0x86; S+= (char) 0x92; + S += name.print(contextptr); + S +="(x)"; + python_compat(pc,contextptr); +#if defined KHICAS || defined SDL_KHICAS + xcas::dconsole_mode=dc; +#endif + return S.c_str(); + } + } + } + else { + S=""; + if (g.type==_VECT) + g.subtype=0; + if (ckmatrix(g)){ + S += "["; + vecteur & v=*g._VECTptr; + for (int i=0;iempty()) + S="empty"; + else if (g._VECTptr->front().type!=_VECT) + S='['+S+']'; + } + else if (name.type!=_IDNT && (g.type==_FRAC || g.type==_ZINT)){ + S += "="; + S += evalf_double(g,1,contextptr).print(contextptr); + } + else if (name.type!=_IDNT && g.type==_SYMB){ + g=evalf_double(g,1,contextptr); + if (g.type<=_CPLX){ + S += "="; + S += g.print(contextptr); + } + } + } + } + if (name.type==_IDNT){ + S="variable "+S; + S += (char) 0xe2; S+= (char) 0x86; S+= (char) 0x92; + S += name.print(contextptr); + } + // confirm("evaled",S.c_str()); + python_compat(pc,contextptr); +#if defined KHICAS || defined SDL_KHICAS + xcas::dconsole_mode=dc; +#endif + return S.c_str(); +} + +#ifdef EMCC_BIND + EMSCRIPTEN_BINDINGS(cas){ + emscripten::function("caseval",&caseval,emscripten::allow_raw_pointers()); + } +#endif + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/global.cc b/android/app/src/main/cpp/giac/src/giac/cpp/global.cc new file mode 100644 index 0000000..c8cd829 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/global.cc @@ -0,0 +1,9432 @@ +/* -*- compile-command: "g++-3.4 -I.. -g -c global.cc -DHAVE_CONFIG_H -DIN_GIAC" -*- */ +#ifdef WIN32 +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "first.h" +#ifdef __MINGW_H +#include +#endif +#endif + +#include "giacPCH.h" +#if defined(EMCC) || defined(EMCC2) +#include +#endif + +/* + * Copyright (C) 2000,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifdef KHICAS + extern "C" double millis(); //extern int time_shift; +#endif + +using namespace std; +#ifdef HAVE_SSTREAM +#include +#else +#include +#endif +#if !defined GIAC_HAS_STO_38 && !defined NSPIRE && !defined FXCG +#include +#endif +#include "global.h" +// #include +#if !defined BESTA_OS && !defined FXCG +#include +#endif +#include +#ifndef WINDOWS +#include // for uintptr_t +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#include +#include +#include +#if !defined RTOS_THREADX +//#include +#endif +#if !defined BESTA_OS && !defined FXCG +#include +#endif +#include "gen.h" +#include "identificateur.h" +#include "symbolic.h" +#include "sym2poly.h" +#include "plot.h" +#include "rpn.h" +#include "prog.h" +#include "usual.h" +#include "tex.h" +#include "path.h" +#include "input_lexer.h" +#include "giacintl.h" +#ifdef HAVE_LOCALE_H +#include +#endif +#ifdef _HAS_LIMITS +#include +#endif +#ifndef BESTA_OS +#ifdef WIN32 +#if defined VISUALC +#if !defined FREERTOS +#include +#include +#endif +#else +#if !defined(GNUWINCE) && !defined(__MINGW_H) +#include +#endif +#if !defined(GNUWINCE) +#include +#endif // ndef gnuwince +#endif // ndef visualc +#endif // win32 +#endif // ndef bestaos + +#ifdef HAVE_LIBFLTK +#include +#endif + +#if defined VISUALC && defined GIAC_HAS_STO_38 && !defined BESTA_OS && !defined RTOS_THREADX && !defined FREERTOS +#include +#endif + +#ifdef BESTA_OS +#include +#endif // besta_os + +#include +#include + +#ifdef QUICKJS +#include "qjsgiac.h" +string js_vars; +void update_js_vars(){ + const char VARS[]="function update_js_vars(){let res=''; for(var b in globalThis) { let prop=globalThis[b]; if (globalThis.hasOwnProperty(b)) res+=b+' ';} return res;}; update_js_vars()"; + char * names=js_ck_eval(VARS,&global_js_context); + if (names){ + js_vars=names; + free(names); + } +} +int js_token(const char * buf){ + return js_token(js_vars.c_str(),buf); +} +#else // QUICKJS +void update_js_vars(){} +int js_token(const char * buf){ + return 0; +} +#endif +int js_token(const char * list,const char * buf){ + int bufl=strlen(buf); + for (const char * p=list;*p;){ + if (p[0]=='\'') + ++p; + if (strncmp(p,buf,bufl)==0 && + (p[bufl]==0 || p[bufl]==' ' || p[bufl]=='\'')){ + return (p[bufl]=='\'')?3:2; + } + // skip to next keyword in p + for (;*p;++p){ + if (*p==' '){ + ++p; break; + } + } + } + return 0; +} + + int nwstore_skip_sys(const unsigned char * ptr,int nwstoresize){ + int pos=4; ptr+=4; + for (;pos +#endif + +#if defined NUMWORKS && defined DEVICE +extern "C" const char * extapp_fileRead(const char * filename, size_t *len, int storage); +extern "C" bool extapp_erasesector(void *); +extern "C" bool extapp_writememory(unsigned char * dest,const unsigned char * data,size_t length); +#endif + + +#ifdef NUMWORKS +size_t pythonjs_stack_size=30*1024, +#ifdef DEVICE + pythonjs_heap_size=_heap_size/2.4; +#else + pythonjs_heap_size=40*1024; +#endif // DEVICE +#else // NUMWORKS + size_t pythonjs_stack_size=128*1024,pythonjs_heap_size=(2*1024-256-64)*1024; +#endif +void * bf_ctx_ptr=0; +size_t bf_global_prec=128; // global precision for BF + +int sprintf512(char * s, const char * format, ...){ + int z; + va_list ap; + va_start(ap,format); +#if defined(FIR) && !defined(FIR_LINUX) + z = firvsnprintf(s, 512, format, ap); +#else + z = vsnprintf(s, 512, format, ap); +#endif + va_end(ap); + return z; +} + +int my_sprintf(char * s, const char * format, ...){ + int z; + va_list ap; + va_start(ap,format); +#if defined(FIR) && !defined(FIR_LINUX) + z = firvsprintf(s, format, ap); +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + z = vsprintf(s, format, ap); + // z = vsnprintf(s, RAND_MAX,format, ap); +#pragma clang diagnostic pop +#endif + va_end(ap); + return z; +} + +int ctrl_c_interrupted(int exception){ + if (!giac::ctrl_c && !giac::interrupted) + return 0; + giac::ctrl_c=giac::interrupted=0; +#ifndef NO_STDEXCEPT + if (exception) + giac::setsizeerr("Interrupted"); +#endif + return 1; +} + +void console_print(const char * s){ + *logptr(giac::python_contextptr) << s; +} + +const char * console_prompt(const char * s){ + static string S; + giac::gen g=giac::_input(giac::string2gen(s?s:"?",false),giac::python_contextptr); + S=g.print(giac::python_contextptr); + return S.c_str(); +} + +#if !defined USE_GMP_REPLACEMENTS && !defined GIAC_HAS_STO_38 + + /********************************************************************* + * Filename: sha256.c/.h + * Author: Brad Conte (brad AT bradconte.com) + * Copyright: + * Disclaimer: This code is presented "as is" without any guarantees. + * Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. + *********************************************************************/ + + /****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + + /**************************** VARIABLES *****************************/ + static const WORD32 k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + }; + + /*********************** FUNCTION DEFINITIONS ***********************/ + void giac_sha256_transform(SHA256_CTX *ctx, const BYTE data[]) + { + WORD32 a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; + } + + void giac_sha256_init(SHA256_CTX *ctx) + { + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; + } + + void giac_sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) + { + WORD32 i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + giac_sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } + } + + void giac_sha256_final(SHA256_CTX *ctx, BYTE hash[]) + { + WORD32 i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + giac_sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + giac_sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } + } + /* END OF SHA256 */ + + +#endif + +// support for tar archive in flash on the numworks +char * buf64k=0; // we only have 64k of RAM buffer on the Numworks +const size_t buflen=(1<<16); +#if defined NUMWORKS_SLOTB +int numworks_maxtarsize=0x200000-0x10000; +#else +#ifdef NUMWORKS_SLOTAB +int numworks_maxtarsize=0x400000; +#else +int numworks_maxtarsize=0x600000-0x10000; +#endif +#endif +size_t tar_first_modified_offset=0; // set to non 0 if tar data comes from Numworks + + +// erase sector containing address if required +// returns true if erased, false otherwise +// if false is returned, it means that [address..end of sector] contains 0xff +// i.e. the remaining part of this sector is ready to write without erasing +void erase_sector(const char * buf){ +#if defined NUMWORKS && defined DEVICE + extapp_erasesector((void *)buf); +#else + char * nxt=(char *) ((((size_t) buf)/buflen +1)*buflen); + char * start=nxt-buflen; + for (int i=0;inxt-target) + delta=nxt-target; + // first copy current sector in buf64k before erasing + char * prev=(char *)nxt-buflen; + memcpy(buf64k,prev,buflen); + memcpy(buf64k+(target-prev),src,delta); + erase_sector(target); + WriteMemory(prev,buf64k,buflen); + length -= delta; + src += delta; + target += delta; + while (length>0){ + memcpy(buf64k,target,buflen); + delta=length; + if (delta>buflen) + delta=buflen; + memcpy(buf64k,src,delta); + erase_sector(target); + WriteMemory(target,buf64k,buflen); + length -= delta; + src += delta; + target += delta; + } +} +#endif + +// TAR: tar file format support +int tar_filesize(int s){ + int h=(s/512+1)*512; + if (s%512) + h +=512; + return h; +} + +// adapted from tarballjs https://github.com/ankitrohatgi/tarballjs +string giac_readString(const char * buffer,size_t str_offset, size_t size) { + int i = 0; + string rtnStr = ""; + while(i=128) break; + rtnStr += ch; + i++; + } + return rtnStr; +} +string giac_readFileName(const char * buffer,size_t header_offset) { + return giac_readString(buffer,header_offset, 100); +} +string giac_readFileType(const char * buffer,size_t header_offset) { + // offset: 156 + const char typeStr = buffer[header_offset+156]; + if (typeStr == '0') + return "file"; + if (typeStr == '5') + return "directory"; + return string(1,typeStr); +} +int giac_readFileSize(const char * buffer,size_t header_offset) { + // offset: 124 + const char * szView = buffer+ header_offset+124; + int res=0; + for (int i = 0; i < 11; i++) { + char tmp=szView[i]; + if (tmp<'0' || tmp>'9') return -1; // invalid file size + res *= 8; + res += (tmp-'0'); + } + return res; +} + +int giac_readMode(const char * buffer,size_t header_offset) { + // offset: 100 + const char * szView = buffer+ header_offset+100; + int res=0; + for (int i = 0; i < 7; i++) { + char tmp=szView[i]; + if (tmp==' ') + return res; + if (tmp<'0' || tmp>'9') + return -1; // invalid file size + res *= 10; + res += (tmp-'0'); + } + return res; +} + +void tar_clear(char * buffer){ + for (int i=0;i<1024;++i) + buffer[i]=0; +} + +std::vector tar_fileinfo(const char * buffer,size_t byteLength){ + vector fileInfo; + if (!buffer) return fileInfo; + size_t offset=0,file_size=0; + string file_name = ""; + string file_type = ""; + char star[]={0,'u','s','t','a','r',0}; + if (memcmp(buffer+0x100,star,6)){ + offset=0x200000; + printf("tar_fileinfo warning: buffer does not point to a tarfile, trying at offset %i\n",offset); + if (memcmp(buffer+offset+0x100,star,6)) + return fileInfo; + } + while (byteLength==0 || offset f=tar_fileinfo(buffer,byteLength); + if (f.empty()) return 0; + fileinfo_t i=f[f.size()-1]; + size_t offset=i.header_offset+tar_filesize(i.size); + return offset; +} + +std::string leftpad(const string & s,size_t targetLength) { + if (targetLength<=s.size()) + return s; + string add(targetLength-s.size(),'0'); + return add+s; +} + +void tar_writestring(char * buffer,const string & str, size_t offset, size_t size) { + for (size_t i = 0; i < size; i++) { + if (i < str.size()) + buffer[i+offset] = str[i]; + else + buffer[i+offset] = 0; + } +} + +std::string toString8(longlong chksum){ + if (chksum<0) + return "-"+toString8(-chksum); + if (chksum==0) + return "0"; + string res; + for (;chksum;chksum/=8){ + res = string(1,'0'+(chksum % 8))+res; + } + return res; +} + +ulonglong fromstring8(const char * ptr){ + ulonglong res=0; char ch; + for (;(ch=*ptr);++ptr){ + if (ch==' ') + return res; + if (ch<'0' || ch>'8') + return -1; + res *= 8; + res += ch-'0'; + } + return res; +} + +void tar_writechecksum(char * buffer,size_t header_offset) { + // offset: 148 + tar_writestring(buffer," ", header_offset+148, 8); // first fill with spaces + // add up header bytes + int chksum = 0; + for (int i = 0; i < 512; i++) { + chksum += buffer[header_offset+i]; + } + tar_writestring(buffer,leftpad(toString8(chksum),6), header_offset+148, 8); + tar_writestring(buffer," ",header_offset+155,1); // add space inside chksum field +} + +void tar_fillheader(char * buffer,size_t offset,int exec=0){ + int uid = 501; + int gid = 20; + string mode = exec?"755":"644"; +#if !defined HAVE_NO_SYS_TIMES_H && defined HAVE_SYS_TIME_H + struct timeval t; + gettimeofday(&t, NULL); + longlong mtime=t.tv_sec; +#else + longlong mtime=(2021LL-1970)*24*365.2425*3600; +#ifdef KHICAS + mtime = millis()/1000; +#endif +#endif + string user = "user"; + string group = "group"; + + tar_writestring(buffer,leftpad(mode,7)+" ", offset+100, 8); + tar_writestring(buffer,leftpad(toString8(uid),6)+" ",offset+108,8); + tar_writestring(buffer,leftpad(toString8(gid),6)+" ",offset+116,8); + tar_writestring(buffer,leftpad(toString8(mtime),11)+" ",offset+136,12); + + //UI.tar_writestring(buffer,"ustar", offset+257,6); // magic string + //UI.tar_writestring(buffer,"00", offset+263,2); // magic version + tar_writestring(buffer,"ustar ", offset+257,8); + + tar_writestring(buffer,user, offset+265,32); // user + tar_writestring(buffer,group, offset+297,32); //group + tar_writestring(buffer,"000000 ",offset+329,7); //devmajor + tar_writestring(buffer,"000000 ",offset+337,7); //devmajor + tar_writechecksum(buffer,offset); +} + +// flash version +int flash_adddata(const char * buffer_,const char * filename,const char * data,size_t datasize,int exec){ + vector finfo=tar_fileinfo(buffer_,numworks_maxtarsize); + size_t s=finfo.size(),offset=0; + if (s){ + fileinfo_t last=finfo[s-1]; + offset=last.header_offset; + offset += tar_filesize(last.size); + } + if (offset+1024+datasize>numworks_maxtarsize) return 0; + buffer_ += offset; + char * nxt=(char *) ((((size_t) buffer_)/buflen +1)*buflen); + char * prev=nxt-buflen; + size_t pos=buffer_-prev; + for (int i=0;ibuflen-pos) + length=buflen-pos; + memcpy(buffer,data,length); + buffer += length; + for (;(size_t) buffer % 512;++buffer) + *buffer=0; + erase_sector(prev); + WriteMemory(prev,buf64k,buflen); + datasize -= length; + data += length; + prev += buflen; + while (datasize>0){ + // copy remaining data + length=datasize finfo=tar_fileinfo(buffer,buffersize); + size_t s=finfo.size(),offset=0; + if (s){ + fileinfo_t last=finfo[s-1]; + offset=last.header_offset; + offset += tar_filesize(last.size); + } + buffersize=offset; + size_t newsize=offset+1024+datasize; + newsize=10240*((newsize+10239)/10240); + if (newsize>numworks_maxtarsize) return 0; + // console.log(buffer.byteLength,newsize); + // resize buffer + if (buffersize data; + FILE * f = fopen(filename,"rb"); + while (1){ + char ch=fgetc(f); + if (feof(f)) + break; + data.push_back(ch); + } + fclose(f); + int exec=1; + for (int i=0;filename[i];++i){ + if (filename[i]=='.') + exec=0; + } + string fname=filename; + for (int i=0;filename[i];++i){ + if (filename[i]=='/') + fname=filename+i+1; + } + return flash_adddata(buffer,fname.c_str(),&data.front(),data.size(),exec); +#endif +} + +// RAM version +int tar_addfile(char * & buffer,const char * filename,size_t * buffersizeptr){ + FILE * f = fopen(filename,"rb"); + vector data; + while (1){ + char ch=fgetc(f); + if (feof(f)) + break; + data.push_back(ch); + } + fclose(f); + int exec=1; + for (int i=0;filename[i];++i){ + if (filename[i]=='.') + exec=0; + } + string fname=giac::remove_path(filename); + return tar_adddata(buffer,buffersizeptr,fname.c_str(),&data.front(),data.size(),exec); +} + +int tar_savefile(char * buffer,const char * filename){ + vector finfo=tar_fileinfo(buffer,0); + int s=finfo.size(); + if (s==0) return 0; + fileinfo_t info; + for (int i=0;i finfo=tar_fileinfo(buffer,0); + int s=finfo.size(); + if (s==0) return 0; + fileinfo_t info; + for (int i=0;i finfo=tar_fileinfo(buffer,0); + int s=finfo.size(); + for (int i=0;i=fl) return false; + int i=fl-el,j=0; + for (;j finfo; + finfo=tar_fileinfo(buf,0); + int s=finfo.size(); + if (s==0) return 0; + int j=0; + for (int i=0;i finfo=tar_fileinfo(buffer,0); + int s=finfo.size(); + if (s==0) return 0; + fileinfo_t info; + for (int i=0;i & finfo,int cur,fileinfo_t & f){ + int s=finfo.size(); + for (int i=cur;i & finfo,size_t * tar_first_modif_offsetptr){ + vector oinfo=tar_fileinfo(buffer,0); + int s=finfo.size(); + if (oinfo.size()!=finfo.size()) + return 0; + for (int i=0;if.header_offset) + *tar_first_modif_offsetptr=f.header_offset; + // copy current sector + size_t sector_begin=(f.header_offset/buflen)*buflen,sector_end=sector_begin+buflen; + memcpy(buf64k,buffer+sector_begin,buflen); + // modify all records in this sector + for (;i=buflen){ + break; + } + char * headbuf=buf64k+sector_pos; + strcpy(headbuf,f.filename.c_str()); + if ( (f.mode/100 & 4) ==0) + headbuf[104] = '0'+((headbuf[104]-'0') &3); + else + headbuf[104] = '0'+((headbuf[104]-'0') |4); + tar_writechecksum(headbuf,0); + } + erase_sector(buffer+sector_begin); + WriteMemory((char *)buffer+sector_begin,buf64k,buflen); + } + return 1; +} + +int flash_emptytrash(const char * buffer,const vector & finfo,size_t * tar_first_modif_offsetptr){ + size_t flash_end=0x90800000LL-buflen,flash_begin=0x90200000LL; + int s=finfo.size(); + if (s==0) return 0; + // find 1st offset marked non readable + int i; // record position + fileinfo_t f,fnxt; + for (i=0;if.header_offset) + *tar_first_modif_offsetptr=f.header_offset; + // find current sector + size_t sector_begin=(f.header_offset/buflen)*buflen,sector_end=sector_begin+buflen; + memcpy(buf64k,buffer+sector_begin,buflen); + size_t sector_pos=f.header_offset-sector_begin; // in [0,buflen[ + int nwrite=0; + for (;i0){ + size_t nbytes=length; + if (length>buflen-sector_pos) + nbytes=buflen-sector_pos; + memcpy(buf64k+sector_pos,buffer+src,nbytes); + sector_pos += nbytes; + for (int j=sector_pos;jflash_end-flash_begin) + return 1; + sector_end += buflen; + sector_pos = 0; + memcpy(buf64k,buffer+sector_begin,buflen); + } + } + i=nxti; + } + if (sector_pos>0){ + erase_sector((char *)buffer+sector_begin); + for (int j=sector_pos;j finfo=tar_fileinfo(buffer,0); + return flash_emptytrash(buffer,finfo,tar_first_modif_offsetptr); +} + +char * file_gettar(const char * filename){ + FILE * f=fopen(filename,"rb"); + if (!f) return 0; + vector res; + while (1){ + char ch=fgetc(f); + if (feof(f)) + break; + res.push_back(ch); + } + fclose(f); + size_t size=res.size(); + size_t bufsize=65536*((size+65535)/65536); + char * buffer=(char *)malloc(bufsize); + memcpy(buffer,&res.front(),size); + return buffer; +} + +char * file_gettar_aligned(const char * filename,char * & freeptr){ + size_t size=numworks_maxtarsize; + size_t bufsize=buflen*((size+(buflen-1))/buflen); + char * buffer=(char *)malloc(bufsize+2*buflen); + freeptr=buffer; + // align buffer + buffer=(char *) ((((size_t) buffer)/buflen +1)*buflen); + FILE * f=fopen(filename,"rb"); + if (!f){ + for (size_t i=0;i res; + while (1){ + char ch=fgetc(f); + if (feof(f)) + break; + res.push_back(ch); + } + fclose(f); + size=res.size(); + if (size>numworks_maxtarsize) + size=numworks_maxtarsize; + memcpy(buffer,&res.front(),size); + return buffer; +} + + +int file_savetar(const char * filename,char * buffer,size_t buffersize){ + size_t l=tar_totalsize(buffer,buffersize); + if (l==0) return 0; + FILE * f=fopen(filename,"wb"); + if (!f) return 0; + fwrite(buffer,l,1,f); + char buf[1024]; + for (int i=0;i<1024;++i) + buf[i]=0; + fwrite(buf,1024,1,f); + fclose(f); + return 1; +} +#if !defined KHICAS && !defined SDL_KHICAS && !defined USE_GMP_REPLACEMENTS && !defined GIAC_HAS_STO_38// + +#ifdef HAVE_LIBDFU +extern "C" { +#include "dfu_lib.h" +} +#endif + +// Numworks calculator +int dfu_exec(const char * s_){ + CERR << s_ << "\n"; +#if 0 // def HAVE_LIBDFU + std::istringstream ss(s_); + std::string arg; + std::vector ls; + std::vector v; + while (ss >> arg) + { + ls.push_back(arg); + v.push_back(const_cast(ls.back().c_str())); + } + v.push_back(0); // need terminating null pointer + int res=dfu_main(v.size()-1,&v[0]); + return res; +#else +#ifdef WIN32 + string s(s_); +#ifdef __MINGW_H + if (giac::is_file_available("c:\\xcaswin\\dfu-util.exe")) + s="c:\\xcaswin\\"+s; + // otherwise dfu-util should be in the path +#else + if (giac::is_file_available("/cygdrive/c/xcas64/dfu-util.exe")) + s="/cygdrive/c/xcas64/"+s; + else + s="./"+s; +#endif + return system(s.c_str()); +#else // WIN32 +#ifdef __APPLE__ + string s(s_); + s="/Applications/usr/bin/"+s; + if (giac::is_file_available(s.c_str())) + return giac::system_no_deprecation(s.c_str()); + s=s_; s="/opt/homebrew/bin/"+s; + return giac::system_no_deprecation(s.c_str()); +#else + return system(s_); +#endif +#endif // WIN32 +#endif +} + +const int dfupos=15; // position of ...-a0 or -a1 in dfu command + +bool dfu_get_scriptstore_addr(size_t & start,size_t & taille,char & altdfu){ + // first try multi-boot + const char * slots[]={"0x90000000","0x90180000","0x90400000"}; + const char * slots1[]={"0x90010000","0x90190000","0x90410000"}; + const char * slots2[]={"0x90020000","0x90190000","0x90420000"}; + unsigned char r[32]; + altdfu='0'; + for (int j=0;j32768){ + FILE * f=fopen(fname,"rb"); + if (!f) + return false; + unsigned char buf[32]; // fixed: was [24] but fread reads 32 bytes + int i=fread(buf,1,32,f); + fclose(f); + if (i!=32) + return false; + if (buf[4]!=0x14 || buf[5]!=0 || strcmp((const char *)buf+6,"pr.sys") || strcmp((const char *)buf+0x1a,"gp.sys")){ // read calc settings + char filename[]="__calc.nws"; + FILE * f=0; + if ( (!dfu_get_scriptstore(filename) || !(f=fopen(filename,"rb")))) + return false; + unsigned char * buf=(unsigned char *) malloc(taille); memset(buf,0,taille); + int s=0x2e; + i=fread(buf,1,s,f); + if (f) fclose(f); + if (i!=s) return false; + f=fopen(fname,"rb"); + fread(buf,1,4,f); // read magic + // append rest of file + for(;!feof(f) && s=0 && i<=9) + return '0'+i; + return 'A'+(i-10); +} + +// send to 0x90000000+offset*0x10000 +bool dfu_send_firmware(const char * fname,int offset){ + string s=string("dfu-util -i0 -a0 -s 0x90"); + s[dfupos]=dfu_alt(); + s += hex2char(offset/16); + s += hex2char(offset); + s += "0000 -D "; + s += fname; + return !dfu_exec(s.c_str()); +} + +bool dfu_send_apps(const char * fname){ + string s=string("dfu-util -i0 -a0 -s 0x90200000 -D ")+ fname; + return !dfu_exec(s.c_str()); +} + +bool dfu_send_slotab(const char * fnamea1,const char * fnamea2,const char * fnameb1,const char * fnameb2){ + size_t start,taille; char altdfu; + if (!dfu_get_scriptstore_addr(start,taille,altdfu)) + return false; + string s; + if (fnamea1 && fnamea2){ + s=string("dfu-util -i0 -a0 -s 0x90260000 -D ")+ (start>=0x24000000?fnamea1:fnamea2); + if (dfu_exec(s.c_str())) + return false; + } + s=string("dfu-util -i0 -a0 -s 0x90400000 -D ")+ (start>=0x24000000?fnameb2:fnameb1); + return !dfu_exec(s.c_str()); +} + +bool dfu_get_epsilon_internal(const char * fname){ + unlink(fname); + string s=string("dfu-util -i0 -a0 -s 0x08000000:0x8000:force -U ")+ fname; + s[dfupos]=dfu_alt(); + return !dfu_exec(s.c_str()); +} + +bool dfu_send_bootloader(const char * fname){ + unlink(fname); + string s=string("dfu-util -i0 -a0 -s 0x08000000 -D ")+ fname; + s[dfupos]=dfu_alt(); + return !dfu_exec(s.c_str()); +} + +bool dfu_get_slot(const char * fname,int slot){ + unlink(fname); + string s=string("dfu-util -i0 -a0 -s "); + s[dfupos]=dfu_alt(); + switch (slot){ + case 1: + s += "0x90000000:0x130000"; + break; + case 2: + s += "0x90180000:0x80000"; + break; + case 0: + s += "0x90000000:0x200000"; + break; + case 26: + s += "0x90260000:0x190000"; + break; + case 40: + s += "0x90400000:0x3f0000"; + break; + default: + return false; + } + s += ":force -U "; + s += fname; + if (dfu_exec(s.c_str())) + return false; + if (slot!=1 && slot!=2) + return true; + // exam mode modifies flash sector at offset 0x1000 + // restore this part to initial values + FILE * f=fopen(fname,"rb"); + if (!f) return false; + unsigned char buf[0x130000]; + int l=slot==1?0x130000:0x80000; + int i=fread(buf,1,l,f); + fclose(f); + if (i!=l) + return false; + for (int j=0x1000;j<0x2000;++j) + buf[j]=0xff; + for (int j=0x2000;j<0x3000;++j) + buf[j]=0; + f=fopen(fname,"wb"); + if (!f) return false; + i=fwrite(buf,1,l,f); + fclose(f); + if (i!=l) + return false; + return true; +} + +#if 0 +// check that we can really read/write on the Numworks at 0x90120000 +// and get the same +// SHOULD NOT BE USED ANYMORE +bool dfu_check_epsilon2(const char * fname){ + FILE * f=fopen(fname,"wb"); + int n=0xe0000; + char * ptr=(char *) malloc(n); + srand(time(NULL)); + int i; + for (i=0;i oldv=tar_fileinfo(oldbuffer,0),v=tar_fileinfo(buffer,0); + // add files from oldbuffer that are not in buffer + for (int i=0;i v=tar_fileinfo(buffer+buffer_offset,buffersize); + if (v.empty()) + return false; + fileinfo_t info=v[v.size()-1]; + size_t end=info.header_offset+tar_filesize(info.size)+1024; + if (end>numworks_maxtarsize || end<=tar_first_modif_offset) return false; + for (size_t i=end-1024;i init + // buf:=tar(1 or 2); init from calc 0x90200000 + // buf:=tar(4); init from calc 0x90400000 + // tar(buf) -> list files + // tar(buf,0,"filename") -> remove filename + // tar(buf,1,"filename") -> add filename + // tar(1,filename) -> add filename + // tar(buf,2) -> save to calc at 0x90200000 + // tar(buf,4) -> save to calc at 0x90400000 + // tar(buf,"file.tar") -> write buf to file.tar + // purge(buf) -> free buffer + gen _tar(const gen & g_,GIAC_CONTEXT){ + gen g(eval(g_,eval_level(contextptr),contextptr)); + if (g.type==_STRNG){ + char * buf=file_gettar(g._STRNGptr->c_str()); + if (!buf) return 0; + tar_first_modified_offset=0; + return gen((void *)buf,_BUFFER_POINTER); + } + if (g.type==_POINTER_ && g.subtype==_BUFFER_POINTER){ + char * buf= (char *) g._POINTER_val; + if (!buf) return 0; + vector v=tar_fileinfo(buf,0); + vecteur res1,res2,res3,res4; + for (int i=0;i=2 && v.front().type==_POINTER_){ + char * buf= (char *) v[0]._POINTER_val; + if (!buf) return 0; + if (s==2 && v[1].type==_STRNG) + return file_savetar(v[1]._STRNGptr->c_str(),buf,0); +#if !defined KHICAS && !defined SDL_KHICAS && !defined USE_GMP_REPLACEMENTS && !defined GIAC_HAS_STO_38 + if (s==2 && v[1].type==_INT_){ + if (v[1].val==2) + return numworks_sendtar(buf,0,tar_first_modified_offset); + } +#endif + if (s==3 && v[1].type==_INT_ && v[2].type==_STRNG){ + int val=v[1].val; + if (val==0) + return tar_removefile(buf,v[2]._STRNGptr->c_str(),0); + if (val==1 && tar_addfile(buf,v[2]._STRNGptr->c_str(),0)){ + gen res=gen((void *)buf,_BUFFER_POINTER); + if (g_.type==_VECT && !g_._VECTptr->empty()) + return sto(res,g_._VECTptr->front(),contextptr); + return res; + } + if (val==2) + return tar_savefile(buf,v[2]._STRNGptr->c_str()); + } + } + } + return gensizeerr(contextptr); + } + static const char _tar_s []="tar"; + static define_unary_function_eval_quoted (__tar,&_tar,_tar_s); + define_unary_function_ptr5( at_tar ,alias_at_tar,&__tar,_QUOTE_ARGUMENTS,true); + + std::string dos2unix(const std::string & src){ + std::string unixsrc; // convert newlines to Unix + for (int i=0;i+1=nwstoresize) + return false; + return true; + } + + bool map2scriptstore(const nws_map & m,const char * fname,int nwstoresize){ + unsigned char buf[nwstoresize]; memset(buf,0,sizeof(buf)); + unsigned char * ptr=buf; + *(unsigned *) ptr= 0xee0bddba; + ptr += 4; + nws_map::const_iterator it,itend=m.end(); + int total=0,sys=2; + for (;sys>=0;--sys){ + if (sys==2){ + it=m.find("pr.sys"); + if (it==itend){ // force + unsigned char prsys[]={0,0xa,0,0,0,0,0,0,0}; + string s("pr.sys"); + unsigned l1=s.size(),l2=sizeof(prsys); // 9 + short unsigned L=2+l1+1+1+l2+1; // 20=0x14 + total += L; + if (total>=nwstoresize) + return false; + *ptr=L % 256; ++ptr; *ptr=L/256; ++ptr; + memcpy(ptr,s.c_str(),l1+1); ptr += l1+1; + *ptr=0; ++ptr; + memcpy(ptr,prsys,l2); ptr+=l2; + *ptr=0; ++ptr; + continue; + } + } + else if (sys==1){ + it=m.find("gp.sys"); + if (it==itend){ // force + unsigned char gpsys[]={0x78,0,0,0,1,4,1,1,0x30,0x75,0}; // 11 + string s("gp.sys"); + unsigned l1=s.size(),l2=sizeof(gpsys); + short unsigned L=2+l1+1+1+l2+1; // 22=0x16 + total += L; + if (total>=nwstoresize) + return false; + *ptr=L % 256; ++ptr; *ptr=L/256; ++ptr; + memcpy(ptr,s.c_str(),l1+1); ptr += l1+1; + *ptr=1; ++ptr; + memcpy(ptr,gpsys,l2); ptr+=l2; + *ptr=0; ++ptr; + continue; + } + } + else + it=m.begin(); + for (;it!=itend;++it){ + const string & s=it->first; + if (sys==0 && (s=="pr.sys" || s=="gp.sys")) + continue; + unsigned l1=s.size(); + unsigned l2=it->second.data.size(); + short unsigned L=2+l1+1+1+l2+1; + total += L; + if (total>=nwstoresize) + return false; + *ptr=L % 256; ++ptr; *ptr=L/256; ++ptr; + memcpy(ptr,s.c_str(),l1+1); ptr += l1+1; + *ptr=it->second.type; ++ptr; + memcpy(ptr,&it->second.data[0],l2); ptr+=l2; + *ptr=0; ++ptr; + if (sys) break; // only one copy + } + } + FILE * f=fopen(fname,"wb"); + if (!f) + return false; + fwrite(buf,1,total,f); + fclose(f); + return true; + } +#endif + + + +#if !defined KHICAS && !defined SDL_KHICAS && !defined USE_GMP_REPLACEMENTS && !defined GIAC_HAS_STO_38 + const unsigned char rsa_n_tab[]= + { + 0xf2,0x0e,0xd4,0x9d,0x44,0x04,0xc4,0xc8,0x6a,0x5b,0xc6,0x9a,0xd6,0xdf, + 0x9c,0xf5,0x56,0xf2,0x0d,0xad,0x6c,0x34,0xb4,0x48,0xf7,0xa7,0xa8,0x27,0xa0, + 0xc8,0xbe,0x36,0xb1,0xc0,0x95,0xf8,0xc2,0x72,0xfb,0x78,0x0f,0x3f,0x15,0x22, + 0xaf,0x51,0x96,0xe3,0xdc,0x39,0xb4,0xc6,0x40,0x6d,0x58,0x56,0x1f,0xad,0x55, + 0x55,0x08,0xf1,0xde,0x5a,0xbc,0xd3,0xcc,0x16,0x3d,0x33,0xee,0x83,0x3f,0x32, + 0xa7,0xa7,0xb8,0x95,0x2f,0x35,0xeb,0xf6,0x32,0x4d,0x22,0xd9,0x60,0xb7,0x5e, + 0xbd,0xea,0xa5,0xcb,0x9c,0x69,0xeb,0xfd,0x9f,0x2b,0x5f,0x3d,0x38,0x5a,0xe1, + 0x2b,0x63,0xf8,0x92,0x35,0x91,0xea,0x77,0x07,0xcc,0x4b,0x7a,0xbc,0xe0,0xa0, + 0x8b,0x82,0x98,0xa2,0x87,0x10,0x2c,0xe2,0x23,0x53,0x2f,0x70,0x03,0xec,0x2d, + 0x22,0x34,0x72,0x57,0x4d,0x24,0x2e,0x97,0xc9,0xfb,0x23,0xb0,0x05,0xff,0x87, + 0x6e,0xbf,0x94,0x2d,0xf0,0x36,0xed,0xd7,0x9a,0xac,0x0c,0x21,0x94,0xa2,0x75, + 0xfc,0x39,0x9b,0xba,0xf2,0xc6,0xc9,0x34,0xa0,0xb2,0x66,0x5a,0xcc,0xc9,0x5c, + 0xc7,0xdb,0xce,0xfb,0x3a,0x10,0xee,0xc1,0x82,0x9a,0x43,0xef,0xed,0x87,0xbd, + 0x6c,0xe4,0xc1,0x36,0xd0,0x0a,0x85,0x6e,0xca,0xcd,0x13,0x29,0x65,0xb5,0xd4, + 0x13,0x4a,0x14,0xaa,0x65,0xac,0x0e,0x6f,0x19,0xb0,0x62,0x47,0x65,0x0e,0x40, + 0x82,0x37,0xd6,0xf0,0x17,0x48,0xaa,0x8c,0x7b,0xc4,0x5e,0x4a,0x72,0x26,0xa6, + 0x08,0x2e,0xff,0x2d,0x9d,0x0e,0x2e,0x19,0xe9,0x6a,0x4c,0x7c,0x3e,0xe9,0xbc, + 0x78,0x95 + }; + + int rsa_check(const char * sigfilename,int maxkeys,BYTE hash[][SHA256_BLOCK_SIZE],int * tailles,vector & fnames){ + gen rsa_n(tabunsignedchar2gen(rsa_n_tab,sizeof(rsa_n_tab))); + gen N=pow(gen(2),768),q; + // read by blocks of 2048 bits=256 bytes + FILE * f=fopen(sigfilename,"r"); + if (!f) + return 0; + char firmwarename[256]; + int i=0; + for (;i='0' && c<='9') + c=c-'0'; + else { + if (c>='a' && c<='f') + c=10+c-'a'; + else { + fclose(f); + return 0; + } + } + unsigned char d=fgetc(f); + if (feof(f)){ + fclose(f); + return 0; + } + if (d==' ' || d=='\n'){ + key = key/16+int(c); + break; + } + if (d>='0' && d<='9') + d=d-'0'; + else { + if (d>='a' && d<='f') + d=10+d-'a'; + else { + fclose(f); + return 0; + } + } + key += int(c)*16+int(d); + } + // public key decrypt and keep only 768 low bits + key=powmod(key,65537,rsa_n); + key=irem(key,N,q); + if (q!=12345){ + fclose(f); + return 0; + } + // check that key is valid and write in hash[i] + for (int j=0;j<32;++j){ + // divide 3 times by 256, remainder must be in '0'..'9' + int o=0; + int tab[]={1,10,100}; + for (int k=0;k<3;++k){ + gen r=irem(key,256,q); + key=q; + if (r.type!=_INT_ || r.val>'9' || r.val<'0'){ + fclose(f); + return 0; + } + o+=(r.val-'0')*tab[k]; + } + if (o<0 || o>255){ + fclose(f); + return 0; + } + if (i fnames; + int nkeys=rsa_check(sigfilename,MAXKEYS,hash,tailles,fnames); + if (nkeys==0) return false; + BYTE buf[SHA256_BLOCK_SIZE]; + SHA256_CTX ctx; + string text; + FILE * f=fopen(filename,"rb"); + if (!f) + return false; + int taille=0; + for (;;++taille){ + unsigned char c=fgetc(f); + if (feof(f)) + break; + text += c; + } + fclose(f); + unsigned char * ptr=(unsigned char *)text.c_str(); + for (int i=0;i=16 + external apps + if (!dfu_get_slot(epsilon,26)) return false; + *logptr(contextptr) << "Verification de signature externe KhiCAS A\n" ; + if (!sha256_check(sig.c_str(),epsilon,"khi110a")) return false; + if (!dfu_get_slot(epsilon,40)) return false; + *logptr(contextptr) << "Verification de signature externe KhiCAS B\n" ; + if (!sha256_check(sig.c_str(),epsilon,"khi110ab.tar")) return false; + return true; + } + // Khi+Epsilon 15.5 + *logptr(contextptr) << "Extraction du firmware externe slot 2\n" ; + if (!dfu_get_slot(epsilon,2)) return false; + *logptr(contextptr) << "Verification de signature externe slot 2\n" ; + if (!sha256_check(sig.c_str(),epsilon,"khi.B.bin")) return false; + *logptr(contextptr) << "Signature firmware conforme\nExtraction des applications\n" ; + if (!dfu_get_apps(apps)) return false; + *logptr(contextptr) << "Verification de signature applications externes\n" ; + if (!sha256_check(sig.c_str(),apps,"apps.tar")) return false; + const char eps2name[]="eps2__"; + if (withoverwrite && + ( // !dfu_check_epsilon2(eps2name) || + !dfu_check_apps2(eps2name) + )){ + *logptr(contextptr) << "Le test d'ecriture et relecture a echoue.\nLe firwmare n'est peut-etre pas conforme ou la flash est endommagee.\n"; + return false; + } + *logptr(contextptr) << "Signature applications conforme\nCalculatrice conforme ร  la reglementation\nCertification par le logiciel Xcas\nInstitut Fourier\nUniversitรฉ de Grenoble Alpes\nAssurez-vous d'avoir tรฉlรฉchargรฉ Xcas sur\nwww-fourier.ujf-grenoble.fr/~parisse/install_fr.html\n" ; + return true; + } +#endif + + const context * python_contextptr=0; + + void opaque_double_copy(void * source,void * target){ + *((double *) target) = * ((double *) source); + } + + double opaque_double_val(const void * source){ + longlong r = * (longlong *)(source) ; + (* (gen *) (&r)).type = 0; + return * (double *)(&r); + } + + // FIXME: make the replacement call for APPLE + int system_no_deprecation(const char *command) { +#if defined _IOS_FIX_ || defined FXCG || defined OSXIOS + return 0; +#else + return system(command); +#endif + } + + double min_proba_time=10; // in seconds + +#ifdef FXCG + void control_c(){ + int i=0 ; // KeyPressed(); // check for EXIT key pressed? + if (i==1){ ctrl_c=true; interrupted=true; } + } +#endif + +#ifdef TIMEOUT +#if !defined(EMCC) && !defined(EMCC2) + double time(int ){ + return double(CLOCK())/1000000; // CLOCKS_PER_SEC; + } +#endif + time_t caseval_begin,caseval_current; + double caseval_maxtime=15; // max 15 seconds + int caseval_n=0,caseval_mod=0,caseval_unitialized=-123454321; +#if !defined POCKETCAS + void control_c(){ +#if defined NSPIRE || defined KHICAS || defined SDL_KHICAS + if ( +#if defined NSPIRE || defined NSPIRE_NEWLIB + on_key_enabled && on_key_pressed() +#else + back_key_pressed() +#endif + ){ + kbd_interrupted=true; + ctrl_c=interrupted=true; + } +#else + if (caseval_unitialized!=-123454321){ + caseval_unitialized=-123454321; + caseval_mod=0; + caseval_n=0; + caseval_maxtime=15; + } + if (caseval_mod>0){ + ++caseval_n; + if (caseval_n >=caseval_mod){ + caseval_n=0; + caseval_current=time(0); +#if defined(EMCC) || defined(EMCC2) + if (difftime(caseval_current,caseval_begin)>caseval_maxtime) +#else + if (caseval_current>caseval_maxtime+caseval_begin) +#endif + { + CERR << "Timeout" << '\n'; ctrl_c=true; interrupted=true; + caseval_begin=caseval_current; + } + } + } +#endif // NSPIRE + } +#endif // POCKETCAS +#endif // TIMEOUT + +#if defined KHICAS || defined SDL_KHICAS + void usleep(int t){ + os_wait_1ms(t/1000); + } +#else +#ifdef NSPIRE_NEWLIB + void usleep(int t){ + msleep(t/1000); + } +#endif + +#endif + +#if defined VISUALC || defined BESTA_OS +#if !defined FREERTOS && !defined HAVE_LIBMPIR + int R_OK=4; +#endif + int access(const char *path, int mode ){ + // return _access(path, mode ); + return 0; + } +#if (defined RTOS_THREADX || defined VISUALC) && !defined FREERTOS && !defined WIN32 +extern "C" void Sleep(unsigned int miliSecond); +#endif + +#if 0 + extern "C" void Sleep(unsigned int ms){ + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + } +#endif + + void usleep(int t){ +#ifdef RTOS_THREADX + Sleep(t/1000); +#else + Sleep(int(t/1000.+.5)); +#endif + } +#endif + +#ifdef __APPLE__ + int PARENTHESIS_NWAIT=10; +#else + int PARENTHESIS_NWAIT=100; +#endif + + // FIXME: threads allowed curently disabled + // otherwise fermat_gcd_mod_2var crashes at puccini + bool threads_allowed=true,mpzclass_allowed=true; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t interactive_mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t fork_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + + std::vector * & vector_aide_ptr (){ + static std::vector * ans = 0; + if (!ans) ans=new std::vector; + return ans; + } + std::vector * & vector_completions_ptr (){ + static std::vector * ans = 0; + if (!ans) ans=new std::vector; + return ans; + } +#ifdef NSPIRE_NEWLIB + const context * context0=new context; +#else + const context * context0=0; +#endif + // Global variable when context is 0 + void (*fl_widget_delete_function)(void *) =0; +#ifndef NSPIRE + ostream & (*fl_widget_archive_function)(ostream &,void *)=0; + gen (*fl_widget_unarchive_function)(istream &)=0; +#endif + gen (*fl_widget_updatepict_function)(const gen & g)=0; + std::string (*fl_widget_texprint_function)(void * ptr)=0; + + const char * _last_evaled_function_name_=0; + const char * & last_evaled_function_name(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_last_evaled_function_name_; + else + return _last_evaled_function_name_; + } + + const char * _currently_scanned=0; + const char * & currently_scanned(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_currently_scanned_; + else + return _currently_scanned; + } + + const gen * _last_evaled_argptr_=0; + const gen * & last_evaled_argptr(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_last_evaled_argptr_; + else + return _last_evaled_argptr_; + } + + static int _language_=0; + int & language(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_language_; + else + return _language_; + } + void language(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_language_=b; +#if !defined(EMCC) && !defined(EMCC2) + else +#endif + _language_=b; + } + + static int _max_sum_sqrt_=3; + int & max_sum_sqrt(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_max_sum_sqrt_; + else + return _max_sum_sqrt_; + } + void max_sum_sqrt(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_max_sum_sqrt_=b; + else + _max_sum_sqrt_=b; + } + +#ifdef GIAC_HAS_STO_38 // Prime sum(x^2,x,0,100000) crash on hardware + static int _max_sum_add_=10000; +#else + static int _max_sum_add_=100000; +#endif + int & max_sum_add(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_max_sum_add_; + else + return _max_sum_add_; + } + + static int _default_color_=FL_BLACK; + int & default_color(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_default_color_; + else + return _default_color_; + } + void default_color(int c,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + contextptr->globalptr->_default_color_=c; + else + _default_color_=c; + } + + static void * _evaled_table_=0; + void * & evaled_table(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_evaled_table_; + else + return _evaled_table_; + } + + static void * _extra_ptr_=0; + void * & extra_ptr(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_extra_ptr_; + else + return _extra_ptr_; + } + + static int _spread_Row_=0; + int & spread_Row(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_spread_Row_; + else + return _spread_Row_; + } + void spread_Row(int c,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + contextptr->globalptr->_spread_Row_=c; + else + _spread_Row_=c; + } + + static int _spread_Col_=0; + int & spread_Col(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_spread_Col_; + else + return _spread_Col_; + } + void spread_Col(int c,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + contextptr->globalptr->_spread_Col_=c; + else + _spread_Col_=c; + } + + static int _printcell_current_row_=0; + int & printcell_current_row(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_printcell_current_row_; + else + return _printcell_current_row_; + } + void printcell_current_row(int c,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + contextptr->globalptr->_printcell_current_row_=c; + else + _printcell_current_row_=c; + } + + static int _printcell_current_col_=0; + int & printcell_current_col(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_printcell_current_col_; + else + return _printcell_current_col_; + } + void printcell_current_col(int c,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + contextptr->globalptr->_printcell_current_col_=c; + else + _printcell_current_col_=c; + } + + static double _total_time_=0.0; + double & total_time(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_total_time_; + else + return _total_time_; + } + +#if 1 + static double _epsilon_=1e-12; +#else +#ifdef __SGI_CPP_LIMITS + static double _epsilon_=100*numeric_limits::epsilon(); +#else + static double _epsilon_=1e-12; +#endif +#endif + double & epsilon(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_epsilon_; + else + return _epsilon_; + } + void epsilon(double c,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + contextptr->globalptr->_epsilon_=c; + else + _epsilon_=c; + } + + static double _proba_epsilon_=1e-15; + double & proba_epsilon(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_proba_epsilon_; + else + return _proba_epsilon_; + } + + static bool _expand_re_im_=true; + bool & expand_re_im(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_expand_re_im_; + else + return _expand_re_im_; + } + void expand_re_im(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_expand_re_im_=b; + else + _expand_re_im_=b; + } + + static int _scientific_format_=0; + int & scientific_format(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_scientific_format_; + else + return _scientific_format_; + } + void scientific_format(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_scientific_format_=b; + else + _scientific_format_=b; + } + + static int _decimal_digits_=12; + + int & decimal_digits(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_decimal_digits_; + else + return _decimal_digits_; + } + void decimal_digits(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_decimal_digits_=b; + else + _decimal_digits_=b; + } + + static int _minchar_for_quote_as_string_=1; + + int & minchar_for_quote_as_string(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_minchar_for_quote_as_string_; + else + return _minchar_for_quote_as_string_; + } + void minchar_for_quote_as_string(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_minchar_for_quote_as_string_=b; + else + _minchar_for_quote_as_string_=b; + } + + static int _xcas_mode_=0; + int & xcas_mode(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_xcas_mode_; + else + return _xcas_mode_; + } + void xcas_mode(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_xcas_mode_=b; + else + _xcas_mode_=b; + } + + + static int _integer_format_=0; + int & integer_format(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_integer_format_; + else + return _integer_format_; + } + void integer_format(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_integer_format_=b; + else + _integer_format_=b; + } + static int _latex_format_=0; + int & latex_format(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_latex_format_; + else + return _latex_format_; + } +#ifdef BCD + static u32 _bcd_decpoint_='.'|('E'<<16)|(' '<<24); + u32 & bcd_decpoint(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_bcd_decpoint_; + else + return _bcd_decpoint_; + } + + static u32 _bcd_mantissa_=12+(15<<8); + u32 & bcd_mantissa(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_bcd_mantissa_; + else + return _bcd_mantissa_; + } + + static u32 _bcd_flags_=0; + u32 & bcd_flags(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_bcd_flags_; + else + return _bcd_flags_; + } + + static bool _bcd_printdouble_=false; + bool & bcd_printdouble(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_bcd_printdouble_; + else + return _bcd_printdouble_; + } + +#endif + + static bool _integer_mode_=true; + bool & integer_mode(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_integer_mode_; + else + return _integer_mode_; + } + + void integer_mode(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_integer_mode_=b; + else + _integer_mode_=b; + } + + bool python_color=false; +#ifdef NSPIRE_NEWLIB + bool os_shell=false; +#else + bool os_shell=true; +#endif + +#ifdef KHICAS + static int _python_compat_=true; +#else + static int _python_compat_=false; +#endif + int & python_compat(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_python_compat_; + else + return _python_compat_; + } + + void python_compat(int b,GIAC_CONTEXT){ + python_color=b; //cout << "python_color " << b << '\n'; + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_python_compat_=b; + else + _python_compat_=b; + } + + static bool _complex_mode_=false; + bool & complex_mode(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_complex_mode_; + else + return _complex_mode_; + } + + void complex_mode(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_complex_mode_=b; + else + _complex_mode_=b; + } + + static bool _escape_real_=true; + bool & escape_real(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_escape_real_; + else + return _escape_real_; + } + + void escape_real(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_escape_real_=b; + else + _escape_real_=b; + } + + static bool _do_lnabs_=true; + bool & do_lnabs(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_do_lnabs_; + else + return _do_lnabs_; + } + + void do_lnabs(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_do_lnabs_=b; + else + _do_lnabs_=b; + } + + static bool _eval_abs_=true; + bool & eval_abs(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_eval_abs_; + else + return _eval_abs_; + } + + void eval_abs(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_eval_abs_=b; + else + _eval_abs_=b; + } + + static bool _eval_equaltosto_=true; + bool & eval_equaltosto(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_eval_equaltosto_; + else + return _eval_equaltosto_; + } + + void eval_equaltosto(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_eval_equaltosto_=b; + else + _eval_equaltosto_=b; + } + + static bool _all_trig_sol_=false; + bool & all_trig_sol(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_all_trig_sol_; + else + return _all_trig_sol_; + } + + void all_trig_sol(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_all_trig_sol_=b; + else + _all_trig_sol_=b; + } + + static bool _try_parse_i_=true; + bool & try_parse_i(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_try_parse_i_; + else + return _try_parse_i_; + } + + void try_parse_i(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_try_parse_i_=b; + else + _try_parse_i_=b; + } + + static bool _specialtexprint_double_=false; + bool & specialtexprint_double(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_specialtexprint_double_; + else + return _specialtexprint_double_; + } + + void specialtexprint_double(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_specialtexprint_double_=b; + else + _specialtexprint_double_=b; + } + + static bool _atan_tan_no_floor_=false; + bool & atan_tan_no_floor(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_atan_tan_no_floor_; + else + return _atan_tan_no_floor_; + } + + void atan_tan_no_floor(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_atan_tan_no_floor_=b; + else + _atan_tan_no_floor_=b; + } + + static bool _keep_acosh_asinh_=false; + bool & keep_acosh_asinh(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_keep_acosh_asinh_; + else + return _keep_acosh_asinh_; + } + + void keep_acosh_asinh(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_keep_acosh_asinh_=b; + else + _keep_acosh_asinh_=b; + } + + static bool _keep_algext_=false; + bool & keep_algext(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_keep_algext_; + else + return _keep_algext_; + } + + void keep_algext(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_keep_algext_=b; + else + _keep_algext_=b; + } + + static bool _auto_assume_=false; + bool & auto_assume(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_auto_assume_; + else + return _auto_assume_; + } + + void auto_assume(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_auto_assume_=b; + else + _auto_assume_=b; + } + + static bool _parse_e_=false; + bool & parse_e(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_parse_e_; + else + return _parse_e_; + } + + void parse_e(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_parse_e_=b; + else + _parse_e_=b; + } + + static bool _convert_rootof_=true; + bool & convert_rootof(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_convert_rootof_; + else + return _convert_rootof_; + } + + void convert_rootof(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_convert_rootof_=b; + else + _convert_rootof_=b; + } + + static bool _lexer_close_parenthesis_=true; + bool & lexer_close_parenthesis(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_lexer_close_parenthesis_; + else + return _lexer_close_parenthesis_; + } + + void lexer_close_parenthesis(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_lexer_close_parenthesis_=b; + else + _lexer_close_parenthesis_=b; + } + + static bool _rpn_mode_=false; + bool & rpn_mode(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_rpn_mode_; + else + return _rpn_mode_; + } + + void rpn_mode(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_rpn_mode_=b; + else + _rpn_mode_=b; + } + +#ifdef __MINGW_H + static bool _ntl_on_=false; +#else + static bool _ntl_on_=true; +#endif + + bool & ntl_on(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_ntl_on_; + else + return _ntl_on_; + } + + void ntl_on(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_ntl_on_=b; + else + _ntl_on_=b; + } + + static bool _complex_variables_=false; + bool & complex_variables(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_complex_variables_; + else + return _complex_variables_; + } + + void complex_variables(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_complex_variables_=b; + else + _complex_variables_=b; + } + + static bool _increasing_power_=false; + bool & increasing_power(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_increasing_power_; + else + return _increasing_power_; + } + + void increasing_power(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_increasing_power_=b; + else + _increasing_power_=b; + } + + static vecteur & _history_in_(){ + static vecteur * ans = 0; + if (ans) + ans=new vecteur; + return *ans; + } + vecteur & history_in(GIAC_CONTEXT){ + if (contextptr) + return *contextptr->history_in_ptr; + else + return _history_in_(); + } + + static vecteur & _history_out_(){ + static vecteur * ans = 0; + if (!ans) + ans=new vecteur; + return *ans; + } + vecteur & history_out(GIAC_CONTEXT){ + if (contextptr) + return *contextptr->history_out_ptr; + else + return _history_out_(); + } + + static vecteur & _history_plot_(){ + static vecteur * ans = 0; + if (!ans) + ans=new vecteur; + return *ans; + } + vecteur & history_plot(GIAC_CONTEXT){ + if (contextptr){ + vecteur * hist=contextptr->history_plot_ptr; + if (hist->size()>=256) + hist->erase(hist->begin(),hist->end()-128); + return *hist; + } + else + return _history_plot_(); + } + + static bool _approx_mode_=false; + bool & approx_mode(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_approx_mode_; + else + return _approx_mode_; + } + + void approx_mode(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_approx_mode_=b; + else + _approx_mode_=b; + } + + static char _series_variable_name_='h'; + char & series_variable_name(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_series_variable_name_; + else + return _series_variable_name_; + } + + void series_variable_name(char b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_series_variable_name_=b; + else + _series_variable_name_=b; + } + + static unsigned short _series_default_order_=5; + unsigned short & series_default_order(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_series_default_order_; + else + return _series_default_order_; + } + + void series_default_order(unsigned short b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_series_default_order_=b; + else + _series_default_order_=b; + } + + static int _angle_mode_=0; + bool angle_radian(GIAC_CONTEXT) + { + if(contextptr && contextptr->globalptr) + return contextptr->globalptr->_angle_mode_ == 0; + else + return _angle_mode_ == 0; + } + + void angle_radian(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_angle_mode_=(b?0:1); + else + _angle_mode_=(b?0:1); + } + + bool angle_degree(GIAC_CONTEXT) + { + if(contextptr && contextptr->globalptr) + return contextptr->globalptr->_angle_mode_ == 1; + else + return _angle_mode_ == 1; + } + + int get_mode_set_radian(GIAC_CONTEXT) + { + int mode; + if(contextptr && contextptr->globalptr) + { + mode = contextptr->globalptr->_angle_mode_; + contextptr->globalptr->_angle_mode_ = 0; + } + else + { + mode = _angle_mode_; + _angle_mode_ = 0; + } + return mode; + } + + void angle_mode(int b, GIAC_CONTEXT) + { + if(contextptr && contextptr->globalptr){ +#ifdef POCKETCAS + _angle_mode_ = b; +#endif + contextptr->globalptr->_angle_mode_ = b; + } + else + _angle_mode_ = b; + } + + int & angle_mode(GIAC_CONTEXT) + { + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_angle_mode_; + else + return _angle_mode_; + } + + static bool _show_point_=true; + bool & show_point(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_show_point_; + else + return _show_point_; + } + + void show_point(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_show_point_=b; + else + _show_point_=b; + } + + static int _show_axes_=1; + int & show_axes(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_show_axes_; + else + return _show_axes_; + } + + void show_axes(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_show_axes_=b; + else + _show_axes_=b; + } + + static bool _io_graph_=false; + // DO NOT SET TO true WITH non-zero contexts or fix symadd when points are added + bool & io_graph(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_io_graph_; + else + return _io_graph_; + } + + void io_graph(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_io_graph_=b; + else + _io_graph_=b; + } + + static bool _variables_are_files_=false; + bool & variables_are_files(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_variables_are_files_; + else + return _variables_are_files_; + } + + void variables_are_files(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_variables_are_files_=b; + else + _variables_are_files_=b; + } + + static int _bounded_function_no_=0; + int & bounded_function_no(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_bounded_function_no_; + else + return _bounded_function_no_; + } + + void bounded_function_no(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_bounded_function_no_=b; + else + _bounded_function_no_=b; + } + + static int _series_flags_=0x3; + int & series_flags(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_series_flags_; + else + return _series_flags_; + } + + void series_flags(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_series_flags_=b; + else + _series_flags_=b; + } + + static int _step_infolevel_=0; + int & step_infolevel(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_step_infolevel_; + else + return _step_infolevel_; + } + + void step_infolevel(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_step_infolevel_=b; + else + _step_infolevel_=b; + } + + static bool _local_eval_=true; + bool & local_eval(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_local_eval_; + else + return _local_eval_; + } + + void local_eval(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_local_eval_=b; + else + _local_eval_=b; + } + + static bool _withsqrt_=true; + bool & withsqrt(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_withsqrt_; + else + return _withsqrt_; + } + + void withsqrt(bool b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_withsqrt_=b; + else + _withsqrt_=b; + } + +#ifdef WITH_MYOSTREAM + my_ostream my_cerr (&CERR); + static my_ostream * _logptr_= &my_cerr; + + my_ostream * logptr(GIAC_CONTEXT){ + my_ostream * res; + if (contextptr && contextptr->globalptr ) + res=contextptr->globalptr->_logptr_; + else + res= _logptr_; + return res?res:&my_cerr; + } +#else +#ifdef NSPIRE + static nio::console * _logptr_=&CERR; + nio::console * logptr(GIAC_CONTEXT){ + return &CERR; + } +#else +#ifdef FXCG + static ostream * _logptr_=0; +#else +#if defined KHICAS || defined SDL_KHICAS + stdostream os_cerr; + static my_ostream * _logptr_=&os_cerr; +#else + static my_ostream * _logptr_=&CERR; +#endif +#endif + my_ostream * logptr(GIAC_CONTEXT){ + my_ostream * res; + if (contextptr && contextptr->globalptr ) + res=contextptr->globalptr->_logptr_; + else + res= _logptr_; +#if (defined(EMCC) || defined(EMCC2)) && !defined SDL_KHICAS + return res?res:&COUT; +#else +#ifdef FXCG + return 0; +#else +#if defined KHICAS || defined SDL_KHICAS + return res?res:&os_cerr; +#else + return res?res:&CERR; +#endif +#endif +#endif + } +#endif +#endif + + void logptr(my_ostream * b,GIAC_CONTEXT){ +#ifdef NSPIRE +#else + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_logptr_=b; + else + _logptr_=b; +#endif + } + + thread_param::thread_param(): _kill_thread(0), thread_eval_status(-1), v(6) +#ifdef HAVE_LIBPTHREAD +#ifdef __MINGW_H + ,eval_thread(),stackaddr(0) +#else + ,eval_thread(0),stackaddr(0) +#endif +#endif + ,stack(0) + { + } + + thread_param * & context0_thread_param_ptr(){ + static thread_param * ans=0; + if (!ans) + ans=new thread_param(); + return ans; + } + +#if 0 + static thread_param & context0_thread_param(){ + return *context0_thread_param_ptr(); + } +#endif + + thread_param * thread_param_ptr(const context * contextptr){ + return (contextptr && contextptr->globalptr)?contextptr->globalptr->_thread_param_ptr:context0_thread_param_ptr(); + } + + int kill_thread(GIAC_CONTEXT){ + thread_param * ptr= (contextptr && contextptr->globalptr )?contextptr->globalptr->_thread_param_ptr:0; + return ptr?ptr->_kill_thread:context0_thread_param_ptr()->_kill_thread; + } + + void kill_thread(int b,GIAC_CONTEXT){ + thread_param * ptr= (contextptr && contextptr->globalptr )?contextptr->globalptr->_thread_param_ptr:0; + if (!ptr) + ptr=context0_thread_param_ptr(); + ptr->_kill_thread=b; + } + + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t _mutexptr = PTHREAD_MUTEX_INITIALIZER,_mutex_eval_status= PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t * mutexptr(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + return contextptr->globalptr->_mutexptr; + return &_mutexptr; + } + + bool is_context_busy(GIAC_CONTEXT){ + int concurrent=pthread_mutex_trylock(mutexptr(contextptr)); + bool res=concurrent==EBUSY; + if (!res) + pthread_mutex_unlock(mutexptr(contextptr)); + return res; + } + + int thread_eval_status(GIAC_CONTEXT){ + int res; + if (contextptr && contextptr->globalptr){ + pthread_mutex_lock(contextptr->globalptr->_mutex_eval_status_ptr); + res=contextptr->globalptr->_thread_param_ptr->thread_eval_status; + pthread_mutex_unlock(contextptr->globalptr->_mutex_eval_status_ptr); + } + else { + pthread_mutex_lock(&_mutex_eval_status); + res=context0_thread_param_ptr()->thread_eval_status; + pthread_mutex_unlock(&_mutex_eval_status); + } + return res; + } + + void thread_eval_status(int val,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr){ + pthread_mutex_lock(contextptr->globalptr->_mutex_eval_status_ptr); + contextptr->globalptr->_thread_param_ptr->thread_eval_status=val; + pthread_mutex_unlock(contextptr->globalptr->_mutex_eval_status_ptr); + } + else { + pthread_mutex_lock(&_mutex_eval_status); + context0_thread_param_ptr()->thread_eval_status=val; + pthread_mutex_unlock(&_mutex_eval_status); + } + } + +#else + bool is_context_busy(GIAC_CONTEXT){ + return false; + } + + int thread_eval_status(GIAC_CONTEXT){ + return -1; + } + + void thread_eval_status(int val,GIAC_CONTEXT){ + } + +#endif + + static int _eval_level=DEFAULT_EVAL_LEVEL; + int & eval_level(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_eval_level; + else + return _eval_level; + } + + void eval_level(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_eval_level=b; + else + _eval_level=b; + } + +#ifdef FXCG // defined(GIAC_HAS_STO_38) || defined(ConnectivityKit) + static unsigned int _rand_seed=123457; +#else + static tinymt32_t _rand_seed; +#endif + +#ifdef FXCG // defined(GIAC_HAS_STO_38) || defined(ConnectivityKit) + unsigned int & rand_seed(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_rand_seed; + else + return _rand_seed; + } +#else + tinymt32_t * rand_seed(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return &contextptr->globalptr->_rand_seed; + else + return &_rand_seed; + } +#endif + + void rand_seed(unsigned int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_rand_seed=b; + else + _rand_seed=b; + } + + int std_rand(){ +#if 1 // def NSPIRE + static unsigned int r = 0; + r = unsigned ((1664525*ulonglong(r)+1013904223)%(ulonglong(1)<<31)); + return r; +#else + return std::rand(); +#endif + } + + int giac_rand(GIAC_CONTEXT){ +#ifdef FXCG // defined(GIAC_HAS_STO_38) || defined(ConnectivityKit) + unsigned int & r = rand_seed(contextptr); + // r = (2147483629*ulonglong(r)+ 2147483587)% 2147483647; + r = unsigned ((1664525*ulonglong(r)+1013904223)%(ulonglong(1)<<31)); + return r; +#else + for (;;){ + unsigned r=tinymt32_generate_uint32(rand_seed(contextptr)) >> 1; + if (!(r>>31)) + return r; + } +#endif // tinymt32 + } + + static int _prog_eval_level_val=1; + int & prog_eval_level_val(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_prog_eval_level_val; + else + return _prog_eval_level_val; + } + + void prog_eval_level_val(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_prog_eval_level_val=b; + else + _prog_eval_level_val=b; + } + + void cleanup_context(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ){ + contextptr->globalptr->_eval_level=DEFAULT_EVAL_LEVEL; + } + eval_level(contextptr)=DEFAULT_EVAL_LEVEL; + if (!contextptr) + protection_level=0; + local_eval(true,contextptr); + } + + + static parser_lexer & _pl(){ + static parser_lexer * ans = 0; + if (!ans) + ans=new parser_lexer(); + ans->_i_sqrt_minus1_=1; + return * ans; + } + int & lexer_column_number(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._lexer_column_number_; + else + return _pl()._lexer_column_number_; + } + int & lexer_line_number(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._lexer_line_number_; + else + return _pl()._lexer_line_number_; + } + void lexer_line_number(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._lexer_line_number_=b; + else + _pl()._lexer_line_number_=b; + } + void increment_lexer_line_number(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + ++contextptr->globalptr->_pl._lexer_line_number_; + else + ++_pl()._lexer_line_number_; + } + + int & index_status(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._index_status_; + else + return _pl()._index_status_; + } + void index_status(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._index_status_=b; + else + _pl()._index_status_=b; + } + + int & i_sqrt_minus1(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._i_sqrt_minus1_; + else + return _pl()._i_sqrt_minus1_; + } + void i_sqrt_minus1(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._i_sqrt_minus1_=b; + else + _pl()._i_sqrt_minus1_=b; + } + + int & opened_quote(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._opened_quote_; + else + return _pl()._opened_quote_; + } + void opened_quote(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._opened_quote_=b; + else + _pl()._opened_quote_=b; + } + + int & in_rpn(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._in_rpn_; + else + return _pl()._in_rpn_; + } + void in_rpn(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._in_rpn_=b; + else + _pl()._in_rpn_=b; + } + + int & spread_formula(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._spread_formula_; + else + return _pl()._spread_formula_; + } + void spread_formula(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._spread_formula_=b; + else + _pl()._spread_formula_=b; + } + + int & initialisation_done(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._initialisation_done_; + else + return _pl()._initialisation_done_; + } + void initialisation_done(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._initialisation_done_=b; + else + _pl()._initialisation_done_=b; + } + + static int _calc_mode_=0; + int & calc_mode(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_calc_mode_; + else + return _calc_mode_; + } + int abs_calc_mode(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return absint(contextptr->globalptr->_calc_mode_); + else + return absint(_calc_mode_); + } + static std::string & _autoname_(){ + static string * ans = 0; + if (!ans){ +#ifdef GIAC_HAS_STO_38 + ans= new string("GA"); +#else + ans = new string("A"); +#endif + } + return *ans; + } + void calc_mode(int b,GIAC_CONTEXT){ + if ( (b==38 || b==-38) && strcmp(_autoname_().c_str(),"GA")<0) + autoname("GA",contextptr); + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_calc_mode_=b; + else + _calc_mode_=b; + } + + int array_start(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr){ + bool hp38=absint(contextptr->globalptr->_calc_mode_)==38; + return (!contextptr->globalptr->_python_compat_ && (contextptr->globalptr->_xcas_mode_ || hp38))?1:0; + } + return (!_python_compat_ && (_xcas_mode_ || absint(_calc_mode_)==38))?1:0; + } + + std::string autoname(GIAC_CONTEXT){ + std::string res; + if (contextptr && contextptr->globalptr ) + res=contextptr->globalptr->_autoname_; + else + res=_autoname_(); + for (;;){ + gen tmp(res,contextptr); + if (tmp.type==_IDNT){ + gen tmp1=eval(tmp,1,contextptr); + if (tmp==tmp1) + break; + } + autoname_plus_plus(res); + } + return res; + } + std::string autoname(const std::string & s,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_autoname_=s; + else + _autoname_()=s; + return s; + } + + static std::string & _autosimplify_(){ + static string * ans = 0; + if (!ans) + ans=new string("regroup"); + return *ans; + } + std::string autosimplify(GIAC_CONTEXT){ + std::string res; + if (contextptr && contextptr->globalptr ) + res=contextptr->globalptr->_autosimplify_; + else + res=_autosimplify_(); + return res; + } + std::string autosimplify(const std::string & s,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_autosimplify_=s; + else + _autosimplify_()=s; + return s; + } + + static std::string & _lastprog_name_(){ + static string * ans = 0; + if (!ans) + ans=new string("lastprog"); + return *ans; + } + std::string lastprog_name(GIAC_CONTEXT){ + std::string res; + if (contextptr && contextptr->globalptr ) + res=contextptr->globalptr->_lastprog_name_; + else + res=_lastprog_name_(); + return res; + } + std::string lastprog_name(const std::string & s,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_lastprog_name_=s; + else + _lastprog_name_()=s; + return s; + } + + static std::string & _format_double_(){ + static string * ans = 0; + if (!ans) + ans=new string(""); + return * ans; + } + std::string & format_double(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_format_double_; + else + return _format_double_(); + } + + std::string comment_s(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._comment_s_; + else + return _pl()._comment_s_; + } + void comment_s(const std::string & b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._comment_s_=b; + else + _pl()._comment_s_=b; + } + + void increment_comment_s(const std::string & b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._comment_s_ += b; + else + _pl()._comment_s_ += b; + } + + void increment_comment_s(char b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._comment_s_ += b; + else + _pl()._comment_s_ += b; + } + + std::string parser_filename(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._parser_filename_; + else + return _pl()._parser_filename_; + } + void parser_filename(const std::string & b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._parser_filename_=b; + else + _pl()._parser_filename_=b; + } + + std::string parser_error(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._parser_error_; + else + return _pl()._parser_error_; + } + void parser_error(const std::string & b,GIAC_CONTEXT){ +#ifndef GIAC_HAS_STO_38 + if (!first_error_line(contextptr)) + alert(b,contextptr); + else + *logptr(contextptr) << b << '\n'; +#endif + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._parser_error_=b; + else + _pl()._parser_error_=b; + } + + std::string error_token_name(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._error_token_name_; + else + return _pl()._error_token_name_; + } + void error_token_name(const std::string & b0,GIAC_CONTEXT){ + string b(b0); + if (b0.size()==2 && b0[0]==-61 && b0[1]==-65) + b="end of input"; + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._error_token_name_=b; + else + _pl()._error_token_name_=b; + } + + int & first_error_line(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_pl._first_error_line_; + else + return _pl()._first_error_line_; + } + void first_error_line(int b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + contextptr->globalptr->_pl._first_error_line_=b; + else + _pl()._first_error_line_=b; + } + + static gen & _parsed_gen_(){ + static gen * ans = 0; + if (!ans) + ans=new gen; + return * ans; + } + gen parsed_gen(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return *contextptr->globalptr->_parsed_genptr_; + else + return _parsed_gen_(); + } + void parsed_gen(const gen & b,GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + *contextptr->globalptr->_parsed_genptr_=b; + else + _parsed_gen_()=b; + } + + static logo_turtle & _turtle_(){ + static logo_turtle * ans = 0; + if (!ans) + ans=new logo_turtle; + return *ans; + } + logo_turtle & turtle(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr ) + return contextptr->globalptr->_turtle_; + else + return _turtle_(); + } + +#if !defined KHICAS && !defined SDL_KHICAS + // protect turtle access by a lock + // turtle changes are mutually exclusive even in different contexts +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t turtle_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + std::vector & _turtle_stack_(){ + static std::vector * ans = 0; + if (!ans) + ans=new std::vector(1,_turtle_()); +#ifdef HAVE_LIBPTHREAD + ans->reserve(20000); +#endif + return *ans; + } + std::vector & turtle_stack(GIAC_CONTEXT){ +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&turtle_mutex); +#endif + std::vector * ans=0; + if (contextptr && contextptr->globalptr ) + ans=&contextptr->globalptr->_turtle_stack_; + else + ans=&_turtle_stack_(); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&turtle_mutex); +#endif + return *ans; + } +#endif + + // Other global variables +#ifdef NSPIRE + bool secure_run=false; +#else + bool secure_run=true; +#endif + bool center_history=false; + bool in_texmacs=false; + bool block_signal=false; + bool CAN_USE_LAPACK = true; + bool simplify_sincosexp_pi=true; + int history_begin_level=0; + // variable used to avoid copying the whole history between processes +#ifdef WIN32 // Temporary + int debug_infolevel=0; +#else + int debug_infolevel=0; +#endif + int printprog=0; +#if defined __APPLE__ || defined VISUALC || defined __MINGW_H || defined BESTA_OS || defined NSPIRE || defined FXCG || defined NSPIRE_NEWLIB || defined KHICAS || defined SDL_KHICAS +#ifdef _WIN32 + int threads=atoi(getenv("NUMBER_OF_PROCESSORS")); +#else + int threads=1; +#endif +#else + int threads=sysconf (_SC_NPROCESSORS_ONLN); +#endif + unsigned max_pairs_by_iteration=32768; + // gbasis max number of pairs by F4 iteration + // setting to 2000 accelerates cyclic9mod but cyclic9 would be slower + // 32768 is enough for cyclic10mod without truncation and not too large for yang1 + unsigned simult_primes=20,simult_primes2=20,simult_primes3=20,simult_primes_seuil2=-1,simult_primes_seuil3=-1; + // gbasis modular algorithm on Q: simultaneous primes (more primes means more parallel threads but also more memory required) + double gbasis_reinject_ratio=0.2; + // gbasis modular algo on Q: if new basis element exceed this ratio, new elements are reinjected in the ideal generators for the remaining computations + double gbasis_reinject_speed_ratio=1./8; // modified from 1/6. for cyclic8 + // gbasis modular algo on Q: new basis elements are reinjected if the 2nd run with learning CPU speed / 1st run without learning CPU speed is >= + int gbasis_logz_age_sort=0,gbasis_stop=0; + // rur_do_gbasis==-1 no gbasis Q recon for rur, ==0 always gbasis Q recon, >0 size limit in monomials of the gbasis for gbasis Q recon + // rur_do_certify==-1 do not certify, ==0 full certify, >0 certify equation if total degree is <= rur_do_certify. Beware of the 1 shift with the user command. + int rur_do_gbasis=-1,rur_do_certify=0,rur_certify_maxthreads=6; + bool rur_error_ifnot0dimensional=false; + unsigned short int GIAC_PADIC=50; + const char cas_suffixe[]=".cas"; + int MAX_PROD_EXPAND_SIZE=4096; + int MAX_SIMPLIFIER_VECTSIZE=256; + int ABERTH_NMAX=25; + int ABERTH_NBITSMAX=8192; + int LAZY_ALG_EXT=0; + int ALG_EXT_DIGITS=180; +#if defined RTOS_THREADX || defined BESTA_OS || defined(KHICAS) || defined SDL_KHICAS +#ifdef BESTA_OS + int LIST_SIZE_LIMIT = 100000 ; + int FACTORIAL_SIZE_LIMIT = 1000 ; + int CALL_LAPACK = 1111; +#else + int LIST_SIZE_LIMIT = 1000 ; + int FACTORIAL_SIZE_LIMIT = 254 ; + int CALL_LAPACK = 1111; +#endif + int GAMMA_LIMIT = 100 ; + int NEWTON_DEFAULT_ITERATION=40; + int NEWTON_MAX_RANDOM_RESTART=5; + int TEST_PROBAB_PRIME=25; + int GCDHEU_MAXTRY=5; + int GCDHEU_DEGREE=100; + int DEFAULT_EVAL_LEVEL=5; + int MODFACTOR_PRIMES =5; + int NTL_MODGCD=1<<30; // default: ntl gcd disabled + int NTL_RESULTANT=382; + int NTL_XGCD=50; + int HGCD=128;//16384; + int HENSEL_QUADRATIC_POWER=25; + int KARAMUL_SIZE=13; + int INT_KARAMUL_SIZE=300; + int FFTMUL_SIZE=100; + int FFTMUL_INT_MAXBITS=1024; + int MAX_ALG_EXT_ORDER_SIZE = 4; + int MAX_COMMON_ALG_EXT_ORDER_SIZE = 16; + int TRY_FU_UPRIME=5; + int TRY_FU_UPRIME_MAXLEAFSIZE=128; + int SOLVER_MAX_ITERATE=25; + int MAX_PRINTABLE_ZINT=10000; + int MAX_RECURSION_LEVEL=9; + int GBASIS_COEFF_STRATEGY=0; + float GBASIS_COEFF_MAXLOGRATIO=2; + int GBASIS_DETERMINISTIC=20; + int GBASISF4_MAX_TOTALDEG=1024; + int GBASISF4_MAXITER=256; + int RUR_PARAM_MAX_DEG=128; + // int GBASISF4_BUCHBERGER=5; + const int BUFFER_SIZE=512; +#else + int CALL_LAPACK=1111; +#if defined(EMCC) || defined(EMCC2) + int LIST_SIZE_LIMIT = 10000000 ; +#else + int LIST_SIZE_LIMIT = 500000000 ; +#endif +#ifdef USE_GMP_REPLACEMENTS + int FACTORIAL_SIZE_LIMIT = 10000 ; +#else + int FACTORIAL_SIZE_LIMIT = 10000000 ; +#endif + int GAMMA_LIMIT = 100 ; + int NEWTON_DEFAULT_ITERATION=60; +#ifdef GIAC_GGB + int NEWTON_MAX_RANDOM_RESTART=20; +#else + int NEWTON_MAX_RANDOM_RESTART=5; +#endif + int TEST_PROBAB_PRIME=25; + int GCDHEU_MAXTRY=5; + int GCDHEU_DEGREE=100; + int DEFAULT_EVAL_LEVEL=25; + int MODFACTOR_PRIMES =5; + int NTL_MODGCD=1<<30; // default: ntl gcd disabled + int NTL_RESULTANT=382; + int NTL_XGCD=50; + int HGCD=128;//16384; + int HENSEL_QUADRATIC_POWER=25; + int KARAMUL_SIZE=13; + int INT_KARAMUL_SIZE=300; + int FFTMUL_SIZE=100; + int FFTMUL_INT_MAXBITS=1024; +#if 0 // def GIAC_GGB + int MAX_ALG_EXT_ORDER_SIZE = 3; +#else + int MAX_ALG_EXT_ORDER_SIZE = 6; +#endif +#if defined EMCC || defined NO_TEMPLATE_MULTGCD || defined GIAC_HAS_STO_38 + int MAX_COMMON_ALG_EXT_ORDER_SIZE = 16; +#else + int MAX_COMMON_ALG_EXT_ORDER_SIZE = 64; +#endif + int TRY_FU_UPRIME=5; + int TRY_FU_UPRIME_MAXLEAFSIZE=128; + int SOLVER_MAX_ITERATE=25; + int MAX_PRINTABLE_ZINT=1000000; + int MAX_RECURSION_LEVEL=100; + int GBASIS_COEFF_STRATEGY=0; + float GBASIS_COEFF_MAXLOGRATIO=2; + int GBASIS_DETERMINISTIC=50; + int GBASISF4_MAX_TOTALDEG=16384; + int GBASISF4_MAXITER=1024; + int RUR_PARAM_MAX_DEG=128; + // int GBASISF4_BUCHBERGER=5; + const int BUFFER_SIZE=16384; +#endif + volatile bool ctrl_c=false,interrupted=false,kbd_interrupted=false; +#ifdef GIAC_HAS_STO_38 + double powlog2float=1e4*10; // increase max int size for HP Prime + int MPZ_MAXLOG2=8600*10; // max 2^8600 about 1K*10 +#else + double powlog2float=1e8; + int MPZ_MAXLOG2=80000000; // 100 millions bits +#endif +#ifdef HAVE_LIBNTL + int PROOT_FACTOR_MAXDEG=300; +#else + int PROOT_FACTOR_MAXDEG=30; +#endif + int MODRESULTANT=20; + int ABS_NBITS_EVALF=1000; + int SET_COMPARE_MAXIDNT=20; + + // used by WIN32 for the path to the xcas directory + string & xcasroot(){ + static string * ans=0; + if (!ans) + ans=new string; + return * ans; + } + string & xcasrc(){ +#ifdef WIN32 + static string * ans=0; + if (!ans) ans=new string("xcas.rc"); +#else + static string * ans=0; + if (!ans) ans=new string(".xcasrc"); +#endif + return *ans; + } + +#if defined HAVE_SIGNAL_H && !defined HAVE_NO_SIGNAL_H + pid_t parent_id=getpid(); +#else + pid_t parent_id=0; +#endif + pid_t child_id=0; // child process (to replace by a vector of childs?) + + void ctrl_c_signal_handler(int signum){ + ctrl_c=true; +#if !defined KHICAS && !defined SDL_KHICAS && !defined NSPIRE_NEWLIB && !defined WIN32 && !defined BESTA_OS && !defined NSPIRE && !defined FXCG && !defined POCKETCAS && !defined __MINGW_H + if (child_id) + kill(child_id,SIGINT); +#endif +#if defined HAVE_SIGNAL_H && !defined HAVE_NO_SIGNAL_H + cerr << "Ctrl-C pressed (pid " << getpid() << ")" << '\n'; +#endif + } +#if !defined NSPIRE && !defined FXCG + gen catch_err(const std::runtime_error & error){ + cerr << error.what() << '\n'; + debug_ptr(0)->sst_at_stack.clear(); + debug_ptr(0)->current_instruction_stack.clear(); + debug_ptr(0)->args_stack.clear(); + protection_level=0; + debug_ptr(0)->debug_mode=false; + return string2gen(string(error.what()),false); + } +#endif + +#if 0 + static vecteur subvect(const vecteur & v,int i){ + int s=v.size(); + if (i<0) + i=-i; + vecteur res(v); + for (;s(pid_t) 1) + return child_id; // exists + signal_child=false; + signal(SIGUSR2,child_launched_signal_handler); // don't do anything, just wait for child ready + child_id=fork(); + if (child_id<(pid_t) 0) + throw(std::runtime_error("Make_child error: Unable to fork")); + if (child_id){ // parent process +#ifdef HAVE_LIBPTHREAD + for (;;){ + pthread_mutex_lock(&fork_mutex); + bool b=signal_child; + pthread_mutex_unlock(&fork_mutex); + if (b) + break; + usleep(1); + } +#else + signal_child=false; + // parent process, wait child ready + /* Wait for SIGUSR2. */ + while (!signal_child) + usleep(1); +#endif + +#ifdef SIGNALDBG + cerr << "Parent received signal for child ready" << '\n'; +#endif + /* OK */ + signal(SIGUSR2,intermediate_signal_handler); + } else { +#ifdef SIGNALDBG + cerr << "Child launched" << '\n'; +#endif + // child process, redirect input/output + sigset_t mask, oldmask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + signal(SIGUSR1,child_signal_handler); + signal(SIGUSR2,child_intermediate_done); + signal_child=false; + gen args; + /* Wait for a signal to arrive. */ + sigprocmask (SIG_BLOCK, &mask, &oldmask); + kill(parent_id,SIGUSR2); + signal_child=false; + for (int no=0;;++no){ +#ifdef SIGNALDBG + cerr << "Child ready" << '\n'; +#endif +#ifndef WIN32 + while (!signal_child) + sigsuspend (&oldmask); + sigprocmask (SIG_UNBLOCK, &mask, NULL); +#endif +#ifdef SIGNALDBG + cerr << "Child reads and eval" << '\n'; +#endif + // read and evaluate input + CLOCK_T start, end; + double elapsed; + start = CLOCK(); + string messages_to_print=""; + ifstream child_in(cas_entree_name().c_str()); + // Unarchive step + try { + args=unarchive(child_in,contextptr); + } + catch (std::runtime_error & error ){ + last_evaled_argptr(contextptr)=NULL; + args = string2gen("Child unarchive error:"+string(error.what()),false); + } +#ifdef SIGNALDBG + cerr << "Child reads " << args << '\n'; +#endif + child_in.close(); + // Clone the context, so that we don't disturb anything + context * ptr=clone_context(contextptr); + gen args_evaled; + if (ptr){ + try { + args_evaled=args.eval(1,ptr); + } + catch (std::runtime_error & error){ + last_evaled_argptr(contextptr)=NULL; + args_evaled=catch_err(error); + } + delete ptr; + } else args_evaled=string2gen("Unable to clone context",false); +#ifdef SIGNALDBG + cerr << "Child result " << args_evaled << '\n'; +#endif + block_signal=false; + end = CLOCK(); + elapsed = ((double) (end - start)) / CLOCKS_PER_SEC; + ofstream child_out(cas_sortie_name().c_str()); + archive(child_out,args,contextptr) ; + int ta=taille(args_evaled,RAND_MAX); + if (ta>=forkmaxleafsize){ + CERR << "Maxleafsize exceeded " << ta << ">=" << forkmaxleafsize << "\nYou can change maxleafsize by running fork_timeout(n) with a larger value of n\n"; + archive(child_out,undef,contextptr) ; + } + else + archive(child_out,args_evaled,contextptr) ; + child_out << messages_to_print ; + int mm=messages_to_print.size(); + if (mm && (messages_to_print[mm-1]!='\n')) + child_out << '\n'; + child_out << "Time: " << elapsed << char(-65) ; + child_out.close(); + // cerr << "Child sending signal to " << parent_id << '\n'; + /* Wait for a signal to arrive. */ + sigprocmask (SIG_BLOCK, &mask, &oldmask); + signal_child=false; +#ifndef WIN32 +#ifdef SIGNALDBG + cerr << "Child sends SIGUSR1 to parent" << '\n'; +#endif + kill(parent_id,SIGUSR1); +#endif + } + } +#ifdef SIGNALDBG + cerr << "Forked " << parent_id << " to " << child_id << '\n'; +#endif + return child_id; + } + + static void archive_write_error(){ + cerr << "Archive error on " << cas_entree_name() << '\n'; + } + + // return true if entree has been sent to evalation by child process + static bool child_eval(const string & entree,bool numeric,bool is_run_file,GIAC_CONTEXT){ +#if defined(HAVE_NO_SIGNAL_H) || defined(DONT_FORK) + return false; +#else + if (is_run_file || rpn_mode(context0)) + history_begin_level=0; + // added signal re-mapping because PARI seems to mess signal on the ipaq + signal(SIGUSR1,data_signal_handler); + signal(SIGUSR2,intermediate_signal_handler); + if (!child_id) + child_id=make_child(contextptr); + if (child_busy || data_ready) + return false; + gen entr; + CLOCK_T start, end; + start = CLOCK(); + try { + ofstream parent_out(cas_entree_name().c_str()); + if (!signal_plot_parent){ + parent_out << rpn_mode(context0) << " " << global_window_ymin << " " << history_begin_level << '\n'; + archive(parent_out,vecteur(history_in(context0).begin()+history_begin_level,history_in(context0).end()),context0); + archive(parent_out,vecteur(history_out(context0).begin()+history_begin_level,history_out(context0).end()),context0); + } + if (is_run_file){ + ifstream infile(entree.c_str()); + char c; + string s; + while (!infile.eof()){ + infile.get(c); + s += c; + } + entr = gen(s,context0); + if (entr.type!=_VECT) + entr=gen(makevecteur(entr),_RUNFILE__VECT); + else + entr.subtype=_RUNFILE__VECT; + } + else { + entr = gen(entree,context0); + if (numeric) + entr = symbolic(at_evalf,gen(entree,context0)); + } + archive(parent_out,entr,context0); + if (!parent_out) + setsizeerr(); + parent_out.close(); + if (!parent_out) + setsizeerr(); + } catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + archive_write_error(); + return false; + } + child_busy=true; + if (signal_plot_parent){ + // cerr << "child_eval: Sending SIGUSR2 to child" << '\n'; + signal_plot_parent=false; +#ifndef WIN32 + kill(child_id,SIGUSR2); +#endif + return true; + } + // cerr << "Sending SIGUSR1 to " << child_id << '\n'; +#ifndef WIN32 + kill(child_id,SIGUSR1); +#endif + running_file=is_run_file; + end = CLOCK(); + // cerr << "# Save time" << double(end-start)/CLOCKS_PER_SEC << '\n'; + return true; +#endif /// HAVE_NO_SIGNAL_H + } + + static bool child_reeval(int history_begin_level,GIAC_CONTEXT){ +#if defined(HAVE_NO_SIGNAL_H) || defined(DONT_FORK) + return false; +#else + signal(SIGUSR1,data_signal_handler); + signal(SIGUSR2,intermediate_signal_handler); + if (!child_id) + child_id=make_child(contextptr); + if (child_busy || data_ready) + return false; + string messages_to_print=""; + try { + ofstream parent_out(cas_entree_name().c_str()); + parent_out << rpn_mode(context0) << " " << global_window_ymin << " " << -1-history_begin_level << " " << synchronize_history << '\n'; + if (synchronize_history){ + archive(parent_out,history_in(context0),context0); + archive(parent_out,vecteur(history_out(context0).begin(),history_out(context0).begin()+history_begin_level),context0); + } + else + archive(parent_out,history_in(context0)[history_begin_level],context0); + if (!parent_out) + setsizeerr(); + parent_out.close(); + if (!parent_out) + setsizeerr(); + } catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + archive_write_error(); + return false; + } + child_busy=true; + running_file=true; + // erase the part of the history that we are computing again + if (run_modif_possommet)){ +#ifdef WITH_GNUPLOT + plot_instructions.push_back(sortie); +#endif + if ((sortie._SYMBptr->feuille.type==_VECT) && (sortie._SYMBptr->feuille._VECTptr->size()==3) && (sortie._SYMBptr->feuille._VECTptr->back().type==_STRNG) && ( ((*sortie._SYMBptr->feuille._VECTptr)[1].type==_VECT) || is_zero((*sortie._SYMBptr->feuille._VECTptr)[1])) ){ + string lab=*(sortie._SYMBptr->feuille._VECTptr->back()._STRNGptr); +#ifdef WITH_GNUPLOT + if (lab.size() && (lab>=PICTautoname)){ + PICTautoname=lab; + PICTautoname_plus_plus(); + } +#endif + } + } + else { + if ( ((sortie.type==_SYMB) && (sortie._SYMBptr->sommet==at_erase)) || + ((sortie.type==_FUNC) && (*sortie._FUNCptr==at_erase)) ){ +#ifdef WITH_GNUPLOT + plot_instructions.clear(); +#endif + } + else { + if ( (sortie.type==_VECT) && (sortie._VECTptr->size()) && (sortie._VECTptr->back().type==_SYMB) && (equalposcomp(plot_sommets,sortie._VECTptr->back()._SYMBptr->sommet))){ +#ifdef WITH_GNUPLOT + plot_instructions.push_back(sortie); +#endif + sortie=sortie._VECTptr->back(); + if ((sortie._SYMBptr->feuille.type==_VECT) && (sortie._SYMBptr->feuille._VECTptr->size()==3) && (sortie._SYMBptr->feuille._VECTptr->back().type==_STRNG) ){ + string lab=*(sortie._SYMBptr->feuille._VECTptr->back()._STRNGptr); +#ifdef WITH_GNUPLOT + if (lab.size() && (lab>=PICTautoname)){ + PICTautoname=lab; + PICTautoname_plus_plus(); + } +#endif + } + } + else { +#ifdef WITH_GNUPLOT + plot_instructions.push_back(zero); +#endif + } + } + } + } // end for (;it!=itend;++it) + } + + static void signal_child_ok(){ + child_busy=true; + data_ready=false; + signal_plot_parent=false; +#ifndef WIN32 + kill(child_id,SIGUSR2); +#endif // WIN32 + } + + static const unary_function_eval * parent_evalonly_sommets_alias[]={*(const unary_function_eval **) &at_widget_size,*(const unary_function_eval **) &at_keyboard,*(const unary_function_eval **) &at_current_sheet,*(const unary_function_eval **) &at_Row,*(const unary_function_eval **) &at_Col,0}; + static const unary_function_ptr * parent_evalonly_sommets=(const unary_function_ptr *) parent_evalonly_sommets_alias; + static bool update_data(gen & entree,gen & sortie,GIAC_CONTEXT){ + // if (entree.type==_IDNT) + // entree=symbolic(at_sto,makevecteur(sortie,entree)); + // discarded sto autoadd otherwise files with many definitions + // are overwritten + debug_ptr(contextptr)->debug_mode=false; + if (signal_plot_parent){ + // cerr << "Child signaled " << entree << " " << sortie << '\n'; + if ( entree.type==_SYMB ){ + if ( (entree._SYMBptr->sommet==at_click && entree._SYMBptr->feuille.type==_VECT && entree._SYMBptr->feuille._VECTptr->empty() ) + || (entree._SYMBptr->sommet==at_debug) + ) { + debug_ptr(contextptr)->debug_mode=(entree._SYMBptr->sommet==at_debug); + // cerr << "Child waiting" << '\n'; + data_ready=false; + *debug_ptr(contextptr)->debug_info_ptr=entree._SYMBptr->feuille; + debug_ptr(contextptr)->debug_refresh=true; + return true; + } + if ( entree._SYMBptr->sommet==at_click || entree._SYMBptr->sommet==at_inputform || entree._SYMBptr->sommet==at_interactive ){ + // cerr << entree << '\n'; + gen res=entree.eval(1,contextptr); + // cerr << res << '\n'; + ofstream parent_out(cas_entree_name().c_str()); + archive(parent_out,res,contextptr); + parent_out.close(); + signal_child_ok(); + return true; + } + // cerr << "Child signaled " << entree << " " << sortie << '\n'; + } + if (sortie.type==_SYMB){ + if (sortie._SYMBptr->sommet==at_SetFold){ + current_folder_name=sortie._SYMBptr->feuille; + signal_child_ok(); + return false; + } + if (sortie._SYMBptr->sommet==at_sto && sortie._SYMBptr->feuille.type==_VECT){ + vecteur & v=*sortie._SYMBptr->feuille._VECTptr; + // cerr << v << '\n'; + if ((v.size()==2) && v[1].type==_IDNT && v[1]._IDNTptr->ref_count_ptr!=(int*)-1){ + if (v[1]._IDNTptr->value) + delete v[1]._IDNTptr->value; + v[1]._IDNTptr->value = new gen(v[0]); + } + signal_child_ok(); + return false; + } + if (sortie._SYMBptr->sommet==at_purge){ + gen & g=sortie._SYMBptr->feuille; + if (g.type==_IDNT && (g._IDNTptr->value) && g._IDNTptr->ref_count_ptr!=(int *) -1){ + delete g._IDNTptr->value; + g._IDNTptr->value=0; + } + signal_child_ok(); + return false; + } + if ((sortie._SYMBptr->sommet==at_cd) && (sortie._SYMBptr->feuille.type==_STRNG)){ +#ifndef HAVE_NO_CWD + chdir(sortie._SYMBptr->feuille._STRNGptr->c_str()); +#endif + signal_child_ok(); + return false; + } + if ( sortie._SYMBptr->sommet==at_insmod || sortie._SYMBptr->sommet==at_rmmod || sortie._SYMBptr->sommet==at_user_operator ){ + protecteval(sortie,DEFAULT_EVAL_LEVEL,contextptr); + signal_child_ok(); + return false; + } + if (sortie._SYMBptr->sommet==at_xyztrange){ + gen f=sortie._SYMBptr->feuille; + if ( (f.type==_VECT) && (f._VECTptr->size()>=12)){ + protecteval(sortie,2,contextptr); + signal_child_ok(); + return false; + } + } + if (sortie._SYMBptr->sommet==at_cas_setup){ + gen f=sortie._SYMBptr->feuille; + if ( (f.type==_VECT) && (f._VECTptr->size()>=7)){ + vecteur v=*f._VECTptr; + cas_setup(v,contextptr); + signal_child_ok(); + return false; + } + } + } +#if 0 + if (entree.type==_SYMB && entree._SYMBptr->sommet==at_signal && sortie.type==_SYMB && equalposcomp(parent_evalonly_sommets,sortie._SYMBptr->sommet) ) { + gen res=sortie.eval(1,contextptr); + ofstream parent_out(cas_entree_name().c_str()); + archive(parent_out,res,contextptr); + parent_out.close(); + signal_child_ok(); + return false; + } +#endif + } // end signal_plot_parent + // cerr << "# Parse time" << double(end-start)/CLOCKS_PER_SEC << '\n'; + // see if it's a PICT update + vecteur args; + // update history + if (rpn_mode(contextptr)) { + if ((sortie.type==_VECT)&& (sortie.subtype==_RPN_STACK__VECT)){ + history_out(contextptr)=*sortie._VECTptr; + history_in(contextptr)=vecteur(history_out(contextptr).size(),undef); + int i=erase_pos(contextptr); + args=vecteur(history_out(contextptr).begin()+i,history_out(contextptr).end()); +#ifdef WITH_GNUPLOT + plot_instructions.clear(); +#endif + } + else { + if (entree.type==_FUNC){ + int s=giacmin(giacmax(entree.subtype,0),(int)history_out(contextptr).size()); + vecteur v(s); + for (int k=s-1;k>=0;--k){ + v[k]=history_out(contextptr).back(); + history_out(contextptr).pop_back(); + history_in(contextptr).pop_back(); + } + entree=symbolic(*entree._FUNCptr,v); + } + history_in(contextptr).push_back(entree); + history_out(contextptr).push_back(sortie); + int i=erase_pos(contextptr); + args=vecteur(history_out(contextptr).begin()+i,history_out(contextptr).end()); +#ifdef WITH_GNUPLOT + plot_instructions.clear(); +#endif + } + } + else { + bool fait=false; + if (running_file) { + if (entree.type==_VECT && sortie.type==_VECT) { + history_in(contextptr)=mergevecteur(history_in(contextptr),*entree._VECTptr); + history_out(contextptr)=mergevecteur(history_out(contextptr),*sortie._VECTptr); + fait=true; + } + if (is_zero(entree) && is_zero(sortie)) + fait=true; + } + if (!fait){ + if (in_texmacs){ + COUT << GIAC_DATA_BEGIN << "verbatim:"; + COUT << "ans(" << history_out(contextptr).size() << ") " << sortie << "\n"; + + COUT << GIAC_DATA_BEGIN << "latex:$$ " << gen2tex(entree,contextptr) << "\\quad = \\quad " << gen2tex(sortie,contextptr) << "$$" << GIAC_DATA_END; + COUT << "\n"; + COUT << GIAC_DATA_BEGIN << "channel:prompt" << GIAC_DATA_END; + COUT << "quest(" << history_out(contextptr).size()+1 << ") "; + COUT << GIAC_DATA_END; + fflush (stdout); + } + history_in(contextptr).push_back(entree); + history_out(contextptr).push_back(sortie); + // for PICT update + args=vecteur(1,sortie); + } + if (running_file){ + // for PICT update + int i=erase_pos(contextptr); + args=vecteur(history_out(contextptr).begin()+i,history_out(contextptr).end()); + // CERR << "PICT clear" << '\n'; +#ifdef WITH_GNUPLOT + plot_instructions.clear(); +#endif + //running_file=false; + } + // now do the update + } + updatePICT(args); + data_ready=false; + if (signal_plot_parent) + signal_child_ok(); + return true; + } + + static void archive_read_error(){ + CERR << "Read error on " << cas_sortie_name() << '\n'; + data_ready=false; +#ifndef WIN32 + if (child_id) + kill(child_id,SIGKILL); +#endif + child_id=0; + } + + static bool read_data(gen & entree,gen & sortie,string & message,GIAC_CONTEXT){ + if (!data_ready) + return false; + message=""; + try { + ifstream parent_in(cas_sortie_name().c_str()); + if (!parent_in) + setsizeerr(); + CLOCK_T start, end; + start = CLOCK(); + entree=unarchive(parent_in,contextptr); + sortie=unarchive(parent_in,contextptr); + end = CLOCK(); + parent_in.getline(buf,BUFFER_SIZE,char(-65)); + if (buf[0]=='\n') + message += (buf+1); + else + message += buf; + if (!parent_in) + setsizeerr(); + } catch (std::runtime_error & ){ + last_evaled_argptr(contextptr)=NULL; + archive_read_error(); + return false; + } + return update_data(entree,sortie,contextptr); + } + + gen _fork_timeout(const gen & args,GIAC_CONTEXT){ + signal(SIGUSR1,SIG_IGN); + // cerr << "fork_timeout step 1\n"; + if (args.type==_INT_){ + int n=args.val; + forkmaxleafsize=giacmin(giacmax(n,16),65536); + return forkmaxleafsize; + } + if (args.type==_VECT && args._VECTptr->empty()) + return forkmaxleafsize; + if (args.type!=_VECT || args._VECTptr->size()<2) + return gensizeerr(contextptr); + gen entr=args._VECTptr->front(); + int ta=taille(entr,RAND_MAX); + if (ta>=forkmaxleafsize){ + CERR << "Maxleafsize exceeded " << ta << ">=" << forkmaxleafsize << "\nYou can change maxleafsize by running fork_timeout(n) with a larger value of n\n"; + return undef; + } + // cerr << "fork_timeout step 2\n"; + gen tout=evalf((*args._VECTptr)[1],1,contextptr); + bool killchild=false; + // fork_timeout(expression,dt,1) will not kill the child if it already exists, this is faster *but* the context/variables from parent are not copied + if (args._VECTptr->size()==3) + killchild=is_zero(args._VECTptr->back()); + if (tout.type!=_DOUBLE_) + return gensizeerr(contextptr); + double dt=tout._DOUBLE_val; + if (dt<1e-3) + return gensizeerr("Invalid timeout, should be at least 1e-3"); + // fork every time now, maybe improved by sending context to child + if (killchild || child_busy || data_ready){ + if (child_id>1){ + kill(child_id,SIGKILL); + usleep(1); + } + child_id=1; + child_busy=data_ready=false; + } + // cerr << "fork_timeout step 3\n"; + if (child_id<=1) + child_id=make_child(contextptr); + // signal(SIGUSR2,intermediate_signal_handler); + // cerr << "fork_timeout step 4\n"; + try { + ofstream parent_out(cas_entree_name().c_str()); + archive(parent_out,entr,contextptr); + if (!parent_out) + setsizeerr(); + parent_out.close(); + if (!parent_out) + setsizeerr(); + } catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + archive_write_error(); + return gensizeerr("Fork_timeout; archive write error"); + } + // cerr << "fork_timeout step 5\n"; + CLOCK_T start, end; + start = CLOCK(); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&fork_mutex); + child_busy=true; + pthread_mutex_unlock(&fork_mutex); +#else + child_busy=true; +#endif + signal(SIGUSR1,data_signal_handler); +#ifdef SIGNALDBG + cerr << "Sending SIGUSR1 to " << child_id << '\n'; +#endif + kill(child_id,SIGUSR1); + // now wait for timeout or signal + gen g_in=entr,g_out; string msg; int N=dt/1e-3; + double debut=realtime(); + for (;;){ +#if 0 // def SIGNALDBG + CERR << "data_ready " << data_ready << " child_busy " << child_busy << "\n"; +#endif +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&fork_mutex); + bool b=!data_ready || child_busy; + pthread_mutex_unlock(&fork_mutex); +#else + bool b=!data_ready || child_busy; +#endif + if (b){ + usleep(1); + double cur=realtime()-debut; +#if 0 // def SIGNALDBG + CERR << "Waiting for " << cur << "\n"; +#endif + if (cur>dt){ + CERR << "Timeout\n"; + kill(child_id,SIGKILL); + usleep(10); + child_id=1; + g_out=string2gen("timeout",false); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&fork_mutex); + child_busy=data_ready=false; + pthread_mutex_unlock(&fork_mutex); +#else + child_busy=data_ready=false; +#endif + break; + } + continue; + } +#ifdef SIGNALDBG + CERR << "Data ready\n"; +#endif + string message=""; + try { + ifstream parent_in(cas_sortie_name().c_str()); + if (!parent_in) + setsizeerr(); + g_in=unarchive(parent_in,contextptr); + g_out=unarchive(parent_in,contextptr); + parent_in.getline(buf,BUFFER_SIZE,char(-65)); + if (buf[0]=='\n') + message += (buf+1); + else + message += buf; + if (!parent_in) + setsizeerr(); + // FIXME: at the end of icas, remove \#cas* + } catch (std::runtime_error & err){ + last_evaled_argptr(contextptr)=NULL; + archive_read_error(); + g_out=string2gen(err.what(),false); + } + break; + } + // cerr << "# Save time" << double(end-start)/CLOCKS_PER_SEC << '\n'; + return g_out; + } + static const char _fork_timeout_s []="fork_timeout"; + static define_unary_function_eval_quoted (__fork_timeout,&_fork_timeout,_fork_timeout_s); + define_unary_function_ptr5( at_fork_timeout ,alias_at_fork_timeout,&__fork_timeout,_QUOTE_ARGUMENTS,true); + +#endif // HAVE_SIGNAL_H_OLD || HAVE_SIGNAL_H + + string home_directory(){ + string s("/"); +#ifdef FXCG + return s; +#else + if (getenv("GIAC_HOME")) + s=getenv("GIAC_HOME"); + else { + if (getenv("XCAS_HOME")) + s=getenv("XCAS_HOME"); + } + if (!s.empty() && s[s.size()-1]!='/') + s += '/'; + if (s.size()!=1) + return s; +#ifdef HAVE_NO_HOME_DIRECTORY + return s; +#else + if (access("/etc/passwd",R_OK)) + return ""; + uid_t u=getuid(); + passwd * p=getpwuid(u); + if (p) s=p->pw_dir; + return s+"/"; +#endif +#endif + } + +#ifndef FXCG + +#if defined HAVE_SYS_TYPES_H && defined HAVE_UNISTD_H && !defined __MINGW_H + string tmpfs(){ + static string tmpfs=""; + if (tmpfs.size()==0){ + int id=getuid(); + if (id>0){ // Debian tmpfs + tmpfs="/run/user/"+print_INT_(id)+"/"; + if (!is_file_available(tmpfs.c_str())) + tmpfs="/tmp/"; + } + else + tmpfs="/tmp/"; + } + return tmpfs; + } +#else + string tmpfs(){ + return "/tmp/"; + } +#endif + + string cas_entree_name(){ + if (getenv("XCAS_TMP")) + return getenv("XCAS_TMP")+("/#cas_entree#"+print_INT_(parent_id)); + string tmp=tmpfs(); + if (tmp=="/tmp/") + tmp=home_directory(); + return tmp+"#cas_entree#"+print_INT_(parent_id); + } + + string cas_sortie_name(){ + if (getenv("XCAS_TMP")) + return getenv("XCAS_TMP")+("/#cas_sortie#"+print_INT_(parent_id)); + string tmp=tmpfs(); + if (tmp=="/tmp/") + tmp=home_directory(); + return tmp+"#cas_sortie#"+print_INT_(parent_id); + } +#endif + + void read_config(const string & name,GIAC_CONTEXT,bool verbose){ +#if !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 +#if !defined __MINGW_H + if (access(name.c_str(),R_OK)) { + if (verbose) + CERR << "// Unable to find config file " << name << '\n'; + return; + } +#endif + ifstream inf(name.c_str()); + if (!inf) + return; + vecteur args; + if (verbose) + CERR << "// Reading config file " << name << '\n'; + readargs_from_stream(inf,args,contextptr); + gen g(args); + if (debug_infolevel || verbose) + CERR << g << '\n'; + g.eval(1,contextptr); + if (verbose){ + CERR << "// User configuration done" << '\n'; + CERR << "// Maximum number of parallel threads " << threads << '\n'; + CERR << "Threads allowed " << threads_allowed << '\n'; + } + if (debug_infolevel){ +#ifdef HASH_MAP_NAMESPACE + CERR << "Using hash_map_namespace"<< '\n'; +#endif + CERR << "Mpz_class allowed " << mpzclass_allowed << '\n'; + // CERR << "Heap multiplication " << heap_mult << '\n'; + } +#endif + } + + // Unix: configuration is read from xcas.rc in the giac_aide_location dir + // then from the user ~/.xcasrc + // Win: configuration from $XCAS_ROOT/xcas.rc then from home_dir()+xcasrc + // or if not available from current dir xcasrc + void protected_read_config(GIAC_CONTEXT,bool verbose){ +#ifndef NO_STDEXCEPT + try { +#endif + string s; +#ifdef WIN32 + s=home_directory(); +#ifdef GNUWINCE + s = xcasroot(); +#else + if (s.size()<2 && getenv("XCAS_ROOT")){ + s=getenv("XCAS_ROOT"); + if (debug_infolevel || verbose) + CERR << "Found XCAS_ROOT " << s << '\n'; + } +#endif // GNUWINCE +#else + s=giac_aide_location; + s=s.substr(0,s.size()-8); +#endif + if (s.size()){ + if (s[s.size()-1]=='/') + read_config(s+"xcas.rc",contextptr,verbose); + else + read_config(s+"/xcas.rc",contextptr,verbose); + } + s=home_directory(); + if (s.size()<2) + s=""; + read_config(s+xcasrc(),contextptr,verbose); +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + CERR << "Error in config file " << xcasrc() << " " << e.what() << '\n'; + } +#endif + } + + string giac_aide_dir(){ +#if defined NSPIRE || defined FXCG || defined MINGW32 + return xcasroot(); +#else + if (!access((xcasroot()+"aide_cas").c_str(),R_OK)){ + return xcasroot(); + } + if (getenv("XCAS_ROOT")){ + string s=getenv("XCAS_ROOT"); + return s; + } + if (xcasroot().size()>4 && xcasroot().substr(xcasroot().size()-4,4)=="bin/"){ + string s(xcasroot().substr(0,xcasroot().size()-4)); + s+="share/giac/"; + if (!access((s+"aide_cas").c_str(),R_OK)){ + return s; + } + } +#ifdef __APPLE__ + if (!access("/Applications/usr/share/giac/",R_OK)) + return "/Applications/usr/share/giac/"; + return "/Applications/usr/share/giac/"; +#endif +#if defined WIN32 // check for default install path +#ifdef MINGW + string ns("c:\\xcaswin\\"); +#else + string ns("/cygdrive/c/xcas/"); +#endif + if (!access((ns+"aide_cas").c_str(),R_OK)){ + CERR << "// Giac share root-directory:" << ns << '\n'; + return ns; + } +#endif // WIN32 + string s(giac_aide_location); // ".../aide_cas" + // test if aide_cas is there, if not test at xcasroot() return "" + if (!access(s.c_str(),R_OK)){ + s=s.substr(0,s.size()-8); + CERR << "// Giac share root-directory:" << s << '\n'; + return s; + } + return ""; +#endif // __MINGW_H + } + + std::string absolute_path(const std::string & orig_file){ +#ifdef BESTA_OS + // BP: FIXME + return orig_file; +#else +#if (!defined WIN32) || (defined VISUALC) + if (orig_file[0]=='/') + return orig_file; + else + return giac_aide_dir()+orig_file; +#else +#if !defined GNUWINCE && !defined __MINGW_H + string res=orig_file; + const char *_epath; + _epath = orig_file.c_str() ; + /* If we have a POSIX path list, convert to win32 path list */ + if (_epath != NULL && *_epath != 0 + && cygwin_posix_path_list_p (_epath)){ +#ifdef x86_64 + int s = cygwin_conv_path (CCP_POSIX_TO_WIN_A , _epath, NULL, 0); + char * _win32path = (char *) malloc(s); + cygwin_conv_path(CCP_POSIX_TO_WIN_A,_epath, _win32path,s); + s=strlen(_win32path); +#else + char * _win32path = (char *) malloc + (cygwin_posix_to_win32_path_list_buf_size (_epath)); + cygwin_posix_to_win32_path_list (_epath, _win32path); + int s=strlen(_win32path); +#endif + res.clear(); + for (int i=0;i=4 && file.substr(0,4)=="http" || file.substr(0,4)=="mail"){ + url=true; + s="'"+file+"'"; + } + else { + if (file[0]!='/'){ +#ifdef WIN32 + file=giac_aide_dir()+file; +#else + s=giac_aide_dir(); +#endif + } + s="file:"+s+file; + } + if (debug_infolevel) + CERR << s << '\n'; +#ifdef WIN32 + bool with_firefox=false; + /* + string firefox="/cygdrive/c/Program Files/Mozilla Firefox/firefox.exe"; + if (getenv("BROWSER")){ + string tmp=getenv("BROWSER"); + if (tmp=="firefox" || tmp=="mozilla"){ + with_firefox=!access(firefox.c_str(),R_OK); + if (!with_firefox){ + firefox="/cygdrive/c/Program Files/mozilla.org/Mozilla/mozilla.exe"; + with_firefox=!access(firefox.c_str(),R_OK); + } + } + } + */ + if (!url && (file.substr(0,10)=="/cygdrive/" || (file[0]!='/' && file[1]!=':')) ){ + string s1=xcasroot(); + if (file.substr(0,10)=="/cygdrive/") + s1=file[10]+(":"+file.substr(11,file.size()-11)); + else { + // remove /cygdrive/ + if (s1.substr(0,10)=="/cygdrive/") + s1=s1[10]+(":"+s1.substr(11,s1.size()-11)); + else + s1="c:/xcas/"; + s1 += s.substr(5,s.size()-5); + } + CERR << "s1=" << s1 << '\n'; + string s2; + if (with_firefox) + s2=s1; + else { + int t=int(s1.size()); + for (int i=0;i0;--ss){ + if (s[ss]=='#' || s[ss]=='.' || s[ss]=='/' ) + break; + } + if (ss && s[ss]!='.') + s=s.substr(0,ss); + s=xcasroot()+"cygstart.exe '"+s+"' &"; + /* + if (with_firefox){ + s="'"+firefox+"' '"+s+"' &"; + } + else { + if (getenv("BROWSER")) + s=getenv("BROWSER")+(" '"+s+"' &"); + else + s="'/cygdrive/c/Program Files/Internet Explorer/IEXPLORE.EXE' '"+s+"' &"; + } + */ +#else + string browser; + if (getenv("BROWSER")) + browser=getenv("BROWSER"); + else { +#ifdef __APPLE__ + browser="open" ; // browser="/Applications/Safari.app/Contents/MacOS/Safari"; + // Remove file: that seems not supported by Safari + if (!url) + s = s.substr(5,s.size()-5); + // Remove # trailing part of URL + int ss=s.size(); + for (--ss;ss>0;--ss){ + if (s[ss]=='#' || s[ss]=='.' || s[ss]=='/' ) + break; + } + if (ss && s[ss]!='.') + s=s.substr(0,ss); +#else + browser="mozilla"; + if (!access("/usr/bin/dillo",R_OK)) + browser="dillo"; + if (!access("/usr/bin/xdg-open",R_OK)) + browser="xdg-open"; + if (!access("/usr/bin/chromium",R_OK)) + browser="chromium"; + if (!access("/usr/bin/firefox",R_OK)) + browser="firefox"; + if (!access("/usr/bin/open",R_OK)) + browser="open"; +#endif + } + // find binary name + int bs=browser.size(),i; + for (i=bs-1;i>=0;--i){ + if (browser[i]=='/') + break; + } + ++i; + string browsersub=browser.substr(i,bs-i); + if (s[0]!='\'') s='\''+s+'\''; + if (browsersub=="mozilla" || browsersub=="mozilla-bin" + //|| browsersub=="firefox" + || browsersub=="chromium"){ + s="if ! "+browser+" -remote \"openurl("+s+")\" ; then "+browser+" "+s+" & fi &"; + } + else + s=browser+" "+s+" &"; +#endif + //if (debug_infolevel) + CERR << "// Running command:"+ s<<'\n'; + return s; +#endif // __MINGW_H + } + + bool system_browser_command(const string & file){ +#ifdef EMCC2 + EM_ASM_ARGS({ + var url=UTF8ToString($0); + console.log('system_browser_command',url); + window.open(url, '_blank').focus(); + },file.c_str()); + return true; +#endif +#if defined BESTA_OS || defined POCKETCAS + return false; +#else +#ifdef WIN32 + string res=file; + if (file.size()>4 && file.substr(0,4)!="http" && file.substr(0,4)!="file" && file.substr(0,4)!="mail"){ + if (res[0]!='/') + res=giac_aide_dir()+res; + if (file.substr(0,4)!="xcas" && file.substr(0,8)!="doc/xcas"){ + // Remove # trailing part of URL + int ss=int(res.size()); + for (--ss;ss>0;--ss){ + if (res[ss]=='#' || res[ss]=='.' || res[ss]=='/' ) + break; + } + if (ss && res[ss]!='.') + res=res.substr(0,ss); + } + CERR << res << '\n'; +#if !defined VISUALC && !defined __MINGW_H && !defined NSPIRE && !defined FXCG + /* If we have a POSIX path list, convert to win32 path list */ + const char *_epath; + _epath = res.c_str() ; + if (_epath != NULL && *_epath != 0 + && cygwin_posix_path_list_p (_epath)){ +#ifdef x86_64 + int s = cygwin_conv_path (CCP_POSIX_TO_WIN_A , _epath, NULL, 0); + char * _win32path = (char *) malloc(s); + cygwin_conv_path(CCP_POSIX_TO_WIN_A,_epath, _win32path,s); +#else + char * _win32path = (char *) malloc (cygwin_posix_to_win32_path_list_buf_size (_epath)); + cygwin_posix_to_win32_path_list (_epath, _win32path); +#endif + res = _win32path; + free(_win32path); + } +#endif + } + CERR << res << '\n'; +#if !defined VISUALC && !defined NSPIRE && !defined FXCG +#ifdef __MINGW_H + while (res.size()>=2 && res.substr(0,2)=="./") + res=res.substr(2,res.size()-2); + if (res.size()<4 || (res.substr(0,4)!="http" && res.substr(0,4)!="mail")) + res = "file:///c:/xcaswin/"+res; + CERR << "running open on " << res << '\n'; + //ShellExecute(NULL,"open","file:///c:/xcaswin/doc/fr/cascmd_fr/index.html",\ +NULL,NULL,SW_SHOWNORMAL); + ShellExecute(NULL,"open",res.c_str(),NULL,NULL,SW_SHOWNORMAL); +#else + // FIXME: works under visualc but not using /UNICODE flag + // find correct flag + ShellExecute(NULL,NULL,res.c_str(),NULL,NULL,1); +#endif +#endif + return true; +#else +#ifdef BESTA_OS + return false; // return 1; +#else + return !system_no_deprecation(browser_command(file).c_str()); +#endif +#endif +#endif + } + + vecteur remove_multiples(vecteur & ww){ + vecteur w; + if (!ww.empty()){ + islesscomplexthanf_sort(ww.begin(),ww.end()); + gen prec=ww[0]; + for (unsigned i=1;i v,int i){ + vector::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + if (*it==i) + return int(it-v.begin())+1; + return 0; + } + + int equalposcomp(const vector v,int i){ + vector::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + if (*it==i) + return int(it-v.begin())+1; + return 0; + } + + int equalposcomp(int tab[],int f){ + for (int i=1;*tab!=0;++tab,++i){ + if (*tab==f) + return i; + } + return 0; + } + + std::string find_lang_prefix(int i){ + switch (i){ + case 1: + return "fr/"; + case 2: + return "en/"; + case 3: + return "es/"; + case 4: + return "el/"; + case 9: + return "pt/"; + case 6: + return "it/"; + /* + case 7: + return "tr/"; + break; + */ + case 8: + return "zh/"; + case 5: + return "de/"; + break; + default: + return "local/"; + } + } + + std::string find_doc_prefix(int i){ + switch (i){ + case 1: + return "doc/fr/"; + break; + case 2: + return "doc/en/"; + break; + case 3: + return "doc/es/"; + break; + case 4: + return "doc/el/"; + break; + case 9: + return "doc/pt/"; + break; + case 6: + return "doc/it/"; + break; + /* + case 7: + return "doc/tr/"; + break; + */ + case 8: + return "doc/zh/"; + break; + case 5: + return "doc/de/"; + break; + default: + return "doc/local/"; + } + } + + void update_completions(){ + if (vector_completions_ptr()){ + vector_completions_ptr()->clear(); + int n=int(vector_aide_ptr()->size()); + for (int k=0;k10) + CERR << "+ " << (*vector_aide_ptr())[k].cmd_name << '\n'; + vector_completions_ptr()->push_back((*vector_aide_ptr())[k].cmd_name); + } + } + } + + void add_language(int i,GIAC_CONTEXT){ +#ifdef FXCG + return; +#else + if (!equalposcomp(lexer_localization_vector(),i)){ + lexer_localization_vector().push_back(i); + update_lexer_localization(lexer_localization_vector(),lexer_localization_map(),back_lexer_localization_map(),contextptr); +#if !defined(EMCC) && !defined(EMCC2) + if (vector_aide_ptr()){ + // add locale command description + int count; + string filename=giac_aide_dir()+find_doc_prefix(i)+"aide_cas"; + readhelp(*vector_aide_ptr(),filename.c_str(),count,false); + // add synonyms + multimap::iterator it,backend=back_lexer_localization_map().end(),itend; + vector::iterator jt = vector_aide_ptr()->begin(),jtend=vector_aide_ptr()->end(); + for (;jt!=jtend;++jt){ + it=back_lexer_localization_map().find(jt->cmd_name); + itend=back_lexer_localization_map().upper_bound(jt->cmd_name); + if (it!=backend){ + for (;it!=itend;++it){ + if (it->second.language==i) + jt->synonymes.push_back(it->second); + } + } + } + int s = int(vector_aide_ptr()->size()); + for (int j=0;jsecond.language==i){ + a.cmd_name=it->second.chaine; + a.language=it->second.language; + vector_aide_ptr()->push_back(a); + } + } + } + } +#if !defined KHICAS && !defined SDL_KHICAS + CERR << "Added " << vector_aide_ptr()->size()-s << " synonyms" << '\n'; +#endif + sort(vector_aide_ptr()->begin(),vector_aide_ptr()->end(),alpha_order); + update_completions(); + } +#endif + } +#endif // FXCG + } + + void remove_language(int i,GIAC_CONTEXT){ +#ifdef FXCG + return; +#else + if (int pos=equalposcomp(lexer_localization_vector(),i)){ + if (vector_aide_ptr()){ + vector nv; + int s=int(vector_aide_ptr()->size()); + for (int j=0;j::iterator jt = vector_aide_ptr()->begin(),jtend=vector_aide_ptr()->end(); + for (;jt!=jtend;++jt){ + vector syno; + vector::const_iterator kt=jt->synonymes.begin(),ktend=jt->synonymes.end(); + for (;kt!=ktend;++kt){ + if (kt->language!=i) + syno.push_back(*kt); + } + jt->synonymes=syno; + } + } + --pos; + lexer_localization_vector().erase(lexer_localization_vector().begin()+pos); + update_lexer_localization(lexer_localization_vector(), lexer_localization_map(), back_lexer_localization_map(), contextptr); + } +#endif + } + + int string2lang(const string & s){ + if (s=="fr") + return 1; + if (s=="en") + return 2; + if (s=="sp" || s=="es") + return 3; + if (s=="el") + return 4; + if (s=="pt") + return 9; + if (s=="it") + return 6; + if (s=="tr") + return 7; + if (s=="zh") + return 8; + if (s=="de") + return 5; + return 0; + } + + std::string set_language(int i,GIAC_CONTEXT){ +#if defined(EMCC) || defined(EMCC2) + if (language(contextptr)!=i){ + language(i,contextptr); + add_language(i,contextptr); + } +#else + language(i,contextptr); + add_language(i,contextptr); +#endif +#if (defined KHICAS || defined SDL_KHICAS) && !defined NUMWORKS_SLOTBFR + lang=i; +#endif + return find_doc_prefix(i); + } + + std::string read_env(GIAC_CONTEXT,bool verbose){ +#ifndef RTOS_THREADX +#ifndef BESTA_OS + if (getenv("GIAC_LAPACK")){ + CALL_LAPACK=atoi(getenv("GIAC_LAPACK")); + if (verbose) + CERR << "// Will call lapack if dimension is >=" << CALL_LAPACK << '\n'; + } + if (getenv("GIAC_PADIC")){ + GIAC_PADIC=atoi(getenv("GIAC_PADIC")); + if (verbose) + CERR << "// Will use p-adic algorithm if dimension is >=" << GIAC_PADIC << '\n'; + } +#endif +#endif + if (getenv("XCAS_RPN")){ + if (verbose) + CERR << "// Setting RPN mode" << '\n'; + rpn_mode(contextptr)=true; + } + if (getenv("GIAC_XCAS_MODE")){ + xcas_mode(contextptr)=atoi(getenv("GIAC_XCAS_MODE")); + if (verbose) + CERR << "// Setting maple mode " << xcas_mode(contextptr) << '\n'; + } + if (getenv("GIAC_C")){ + xcas_mode(contextptr)=0; + if (verbose) + CERR << "// Setting giac C mode" << '\n'; + } + if (getenv("GIAC_MAPLE")){ + xcas_mode(contextptr)=1; + if (verbose) + CERR << "// Setting giac maple mode" << '\n'; + } + if (getenv("GIAC_MUPAD")){ + xcas_mode(contextptr)=2; + if (verbose) + CERR << "// Setting giac mupad mode" << '\n'; + } + if (getenv("GIAC_TI")){ + xcas_mode(contextptr)=3; + if (verbose) + CERR << "// Setting giac TI mode" << '\n'; + } + if (getenv("GIAC_MONO")){ + if (verbose) + CERR << "// Threads polynomial * disabled" << '\n'; + threads_allowed=false; + } + if (getenv("GIAC_MPZCLASS")){ + if (verbose) + CERR << "// mpz_class enabled" << '\n'; + mpzclass_allowed=true; + } + if (getenv("GIAC_DEBUG")){ + debug_infolevel=atoi(getenv("GIAC_DEBUG")); + CERR << "// Setting debug_infolevel to " << debug_infolevel << '\n'; + } + if (getenv("GBASIS_COEFF_STRATEGY")){ + GBASIS_COEFF_STRATEGY=atoi(getenv("GBASIS_COEFF_STRATEGY")); + CERR << "// Setting gbasis_coeff_strategy to " << GBASIS_COEFF_STRATEGY << '\n'; + } + if (getenv("GBASIS_COEFF_MAXLOGRATIO")){ + GBASIS_COEFF_MAXLOGRATIO=atof(getenv("GBASIS_COEFF_MAXLOGRATIO")); + CERR << "// Setting gbasis_coeff_maxlogratio to " << GBASIS_COEFF_MAXLOGRATIO << '\n'; + } + if (getenv("GIAC_PRINTPROG")){ + // force print of prog at parse, 256 for python compat mode print + printprog=atoi(getenv("GIAC_PRINTPROG")); + CERR << "// Setting printprog to " << printprog << '\n'; + } + string s; + if (getenv("LANG")) + s=getenv("LANG"); + else { // __APPLE__ workaround +#if !defined VISUALC && !defined NSPIRE && !defined FXCG + if (!strcmp(gettext("File"),"Fich")){ + setenv("LANG","fr_FR.UTF8",1); + s="fr_FR.UTF8"; + } + else { + s="en_US.UTF8"; + setenv("LANG",s.c_str(),1); + } + if (!strcmp(gettext("File"),"Datei")){ + setenv("LANG","de_DE.UTF8",1); + s="de_DE.UTF8"; + } +#endif + } + if (debug_infolevel) + cout << "LANG " << s << "\n"; + if (s.size()>=2){ + s=s.substr(0,2); + int i=string2lang(s); + if (i){ + language(i,contextptr); + return find_doc_prefix(i); + } + } + language(0,contextptr); + return find_doc_prefix(0); + } + + string cas_setup_string(GIAC_CONTEXT){ + string s("cas_setup("); + s += print_VECT(cas_setup(contextptr),_SEQ__VECT,contextptr); + s += "),"; + s += "xcas_mode("; + s += print_INT_(xcas_mode(contextptr)+python_compat(contextptr)*256); + s += ")"; + return s; + } + + string geo_setup_string(){ + return xyztrange(gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,gnuplot_zmin,gnuplot_zmax,gnuplot_tmin,gnuplot_tmax,global_window_xmin,global_window_xmax,global_window_ymin,global_window_ymax,_show_axes_,class_minimum,class_size, +#ifdef WITH_GNUPLOT + gnuplot_hidden3d,gnuplot_pm3d +#else + 1,1 +#endif + ).print(context0); + } + + string add_extension(const string & s,const string & ext,const string & def){ + if (s.empty()) + return def+"."+ext; + int i=int(s.size()); + for (--i;i>0;--i){ + if (s[i]=='.') + break; + } + if (i<=0) + return s+"."+ext; + return s.substr(0,i)+"."+ext; + } + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t context_list_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + + vector & context_list(){ + static vector * ans=0; + if (!ans) ans=new vector(1,(context *) 0); + return *ans; + } + context::context() { + // CERR << "new context " << this << '\n'; + parent=0; + tabptr=new sym_tab; + globalcontextptr=this; previous=0; globalptr=new global; + quoted_global_vars=new vecteur; + rootofs=new vecteur; + history_in_ptr=new vecteur; + history_out_ptr=new vecteur; + history_plot_ptr=new vecteur; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&context_list_mutex); +#endif + context_list().push_back(this); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&context_list_mutex); +#endif + } + +#ifndef RTOS_THREADX +#if !defined BESTA_OS && !defined NSPIRE && !defined FXCG && !defined(KHICAS) && !defined SDL_KHICAS + std::map * context_names = new std::map ; + + context::context(const string & name) { + // CERR << "new context " << this << '\n'; + parent=0; + tabptr=new sym_tab; + globalcontextptr=this; previous=0; globalptr=new global; + quoted_global_vars=new vecteur; + rootofs=new vecteur; + history_in_ptr=new vecteur; + history_out_ptr=new vecteur; + history_plot_ptr=new vecteur; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&context_list_mutex); +#endif + context_list().push_back(this); + if (context_names) + (*context_names)[name]=this; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&context_list_mutex); +#endif + } +#endif +#endif + + context::context(const context & c) { + *this = c; + } + + context * context::clone() const{ + context * ptr = new context; + *ptr->globalptr = *globalptr; + return ptr; + } + + void clear_context(context * ptr){ + if (!ptr) + return; + ptr->parent=0; + if (ptr->history_in_ptr) + delete ptr->history_in_ptr; + if (ptr->history_out_ptr) + delete ptr->history_out_ptr; + if (ptr->history_plot_ptr) + delete ptr->history_plot_ptr; + if (ptr->quoted_global_vars) + delete ptr->quoted_global_vars; + if (ptr->rootofs) + delete ptr->rootofs; + if (ptr->globalptr) + delete ptr->globalptr; + if (ptr->tabptr) + delete ptr->tabptr; + ptr->tabptr=new sym_tab; + ptr->globalcontextptr=ptr; ptr->previous=0; ptr->globalptr=new global; + ptr->quoted_global_vars=new vecteur; + ptr->rootofs=new vecteur; + ptr->history_in_ptr=new vecteur; + ptr->history_out_ptr=new vecteur; + ptr->history_plot_ptr=new vecteur; + //init_context(ptr); + } + + void init_context(context * ptr){ + if (!ptr){ + CERR << "init_context on null context" << '\n'; + return; + } + ptr->globalptr->_xcas_mode_=_xcas_mode_; +#ifdef GIAC_HAS_STO_38 + ptr->globalptr->_calc_mode_=-38; +#else + ptr->globalptr->_calc_mode_=_calc_mode_; +#endif + ptr->globalptr->_decimal_digits_=_decimal_digits_; + ptr->globalptr->_minchar_for_quote_as_string_=_minchar_for_quote_as_string_; + ptr->globalptr->_scientific_format_=_scientific_format_; + ptr->globalptr->_integer_format_=_integer_format_; + ptr->globalptr->_integer_mode_=_integer_mode_; + ptr->globalptr->_latex_format_=_latex_format_; +#ifdef BCD + ptr->globalptr->_bcd_decpoint_=_bcd_decpoint_; + ptr->globalptr->_bcd_mantissa_=_bcd_mantissa_; + ptr->globalptr->_bcd_flags_=_bcd_flags_; + ptr->globalptr->_bcd_printdouble_=_bcd_printdouble_; +#endif + ptr->globalptr->_expand_re_im_=_expand_re_im_; + ptr->globalptr->_do_lnabs_=_do_lnabs_; + ptr->globalptr->_eval_abs_=_eval_abs_; + ptr->globalptr->_eval_equaltosto_=_eval_equaltosto_; + ptr->globalptr->_complex_mode_=_complex_mode_; + ptr->globalptr->_escape_real_=_escape_real_; + ptr->globalptr->_try_parse_i_=_try_parse_i_; + ptr->globalptr->_specialtexprint_double_=_specialtexprint_double_; + ptr->globalptr->_atan_tan_no_floor_=_atan_tan_no_floor_; + ptr->globalptr->_keep_acosh_asinh_=_keep_acosh_asinh_; + ptr->globalptr->_keep_algext_=_keep_algext_; + ptr->globalptr->_auto_assume_=_auto_assume_; + ptr->globalptr->_parse_e_=_parse_e_; + ptr->globalptr->_convert_rootof_=_convert_rootof_; + ptr->globalptr->_python_compat_=_python_compat_; + ptr->globalptr->_complex_variables_=_complex_variables_; + ptr->globalptr->_increasing_power_=_increasing_power_; + ptr->globalptr->_approx_mode_=_approx_mode_; + ptr->globalptr->_series_variable_name_=_series_variable_name_; + ptr->globalptr->_series_default_order_=_series_default_order_; + ptr->globalptr->_autosimplify_=_autosimplify_(); + ptr->globalptr->_lastprog_name_=_lastprog_name_(); + ptr->globalptr->_angle_mode_=_angle_mode_; + ptr->globalptr->_variables_are_files_=_variables_are_files_; + ptr->globalptr->_bounded_function_no_=_bounded_function_no_; + ptr->globalptr->_series_flags_=_series_flags_; // bit1= full simplify, bit2=1 for truncation + ptr->globalptr->_step_infolevel_=_step_infolevel_; // bit1= full simplify, bit2=1 for truncation + ptr->globalptr->_local_eval_=_local_eval_; + ptr->globalptr->_default_color_=_default_color_; + ptr->globalptr->_epsilon_=_epsilon_<=0?1e-12:_epsilon_; + ptr->globalptr->_proba_epsilon_=_proba_epsilon_; + ptr->globalptr->_withsqrt_=_withsqrt_; + ptr->globalptr->_show_point_=_show_point_; // show 3-d point + ptr->globalptr->_io_graph_=_io_graph_; // show 2-d point in io + ptr->globalptr->_show_axes_=_show_axes_; + ptr->globalptr->_spread_Row_=_spread_Row_; + ptr->globalptr->_spread_Col_=_spread_Col_; + ptr->globalptr->_printcell_current_row_=_printcell_current_row_; + ptr->globalptr->_printcell_current_col_=_printcell_current_col_; + ptr->globalptr->_all_trig_sol_=_all_trig_sol_; + ptr->globalptr->_lexer_close_parenthesis_=_lexer_close_parenthesis_; + ptr->globalptr->_rpn_mode_=_rpn_mode_; + ptr->globalptr->_ntl_on_=_ntl_on_; + ptr->globalptr->_prog_eval_level_val =_prog_eval_level_val ; + ptr->globalptr->_eval_level=_eval_level; + ptr->globalptr->_rand_seed=_rand_seed; + ptr->globalptr->_language_=_language_; + ptr->globalptr->_last_evaled_argptr_=_last_evaled_argptr_; + ptr->globalptr->_last_evaled_function_name_=_last_evaled_function_name_; + ptr->globalptr->_currently_scanned_=""; + ptr->globalptr->_max_sum_sqrt_=_max_sum_sqrt_; + ptr->globalptr->_max_sum_add_=_max_sum_add_; + + } + + context * clone_context(const context * contextptr) { + context * ptr = new context; + if (contextptr){ + *ptr->globalptr = *contextptr->globalptr; + *ptr->tabptr = *contextptr->tabptr; + } + else { + init_context(ptr); + } + return ptr; + } + + context::~context(){ + // CERR << "delete context " << this << '\n'; + if (!previous){ + if (history_in_ptr) + delete history_in_ptr; + if (history_out_ptr) + delete history_out_ptr; + if (history_plot_ptr) + delete history_plot_ptr; + if (quoted_global_vars) + delete quoted_global_vars; + if (rootofs) + delete rootofs; + if (globalptr) + delete globalptr; + if (tabptr) + delete tabptr; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&context_list_mutex); +#endif + int s=int(context_list().size()); + for (int i=s-1;i>0;--i){ + if (context_list()[i]==this){ + context_list().erase(context_list().begin()+i); + break; + } + } +#ifndef RTOS_THREADX +#if !defined BESTA_OS && !defined NSPIRE && !defined FXCG && !defined(KHICAS) && !defined SDL_KHICAS + if (context_names){ + map::iterator it=context_names->begin(),itend=context_names->end(); + for (;it!=itend;++it){ + if (it->second==this){ + context_names->erase(it); + break; + } + } + } +#endif +#endif +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&context_list_mutex); +#endif + } + } + +#ifndef CLK_TCK +#define CLK_TCK 1 +#endif + +#ifndef HAVE_NO_SYS_TIMES_H + double delta_tms(struct tms tmp1,struct tms tmp2){ +#if defined(HAVE_SYSCONF) && !defined(EMCC) && !defined(EMCC2) + return double( tmp2.tms_utime+tmp2.tms_stime+tmp2.tms_cutime+tmp2.tms_cstime-(tmp1.tms_utime+tmp1.tms_stime+tmp1.tms_cutime+tmp1.tms_cstime) )/sysconf(_SC_CLK_TCK); +#else + return double( tmp2.tms_utime+tmp2.tms_stime+tmp2.tms_cutime+tmp2.tms_cstime-(tmp1.tms_utime+tmp1.tms_stime+tmp1.tms_cutime+tmp1.tms_cstime) )/CLK_TCK; +#endif + } +#elif defined(__MINGW_H) + double delta_tms(clock_t tmp1,clock_t tmp2) { + return (double)(tmp2-tmp1)/CLOCKS_PER_SEC; + } +#endif /// HAVE_NO_SYS_TIMES_H + + string remove_filename(const string & s){ + int l=int(s.size()); + for (;l;--l){ + if (s[l-1]=='/') + break; + } + return s.substr(0,l); + } + +#ifdef HAVE_LIBPTHREAD + static void * in_thread_eval(void * arg){ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); + vecteur *v = (vecteur *) arg; + context * contextptr=(context *) (*v)[2]._POINTER_val; + thread_param * ptr =thread_param_ptr(contextptr); + pthread_attr_getstacksize(&ptr->attr,&ptr->stacksize); + ptr->stackaddr=(void *) ((uintptr_t) &ptr-ptr->stacksize); + ptr->stack=(size_t) &ptr; +#ifndef __MINGW_H + struct tms tmp1,tmp2; + times(&tmp1); +#else + int beg=CLOCK(); +#endif + gen g = (*v)[0]; + g = protecteval(g,(*v)[1].val,contextptr); +#ifndef NO_STDEXCEPT + try { +#endif +#ifndef __MINGW_H + times(&tmp2); + double dt=delta_tms(tmp1,tmp2); + total_time(contextptr) += dt; + (*v)[4]=dt; +#else + int end=CLOCK(); + (*v)[4]=end-beg; +#endif + (*v)[5]=g; +#ifndef NO_STDEXCEPT + } catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + } +#endif + ptr->stackaddr=0; ptr->stack=0; + thread_eval_status(0,contextptr); + pthread_exit(0); + return 0; + } + + // create a new thread for evaluation of g at level level in context + bool make_thread(const gen & g,int level,const giac_callback & f,void * f_param,const context * contextptr){ + if (is_context_busy(contextptr)) + return false; + thread_param * ptr =thread_param_ptr(contextptr); + if (!ptr || ptr->v.size()!=6) + return false; + pthread_mutex_lock(mutexptr(contextptr)); + ptr->v[0]=g; + ptr->v[1]=level; + ptr->v[2]=gen((void *)contextptr,_CONTEXT_POINTER); + ptr->f=f; + ptr->f_param=f_param; + thread_eval_status(1,contextptr); + pthread_attr_init(&ptr->attr); + int cres=pthread_create (&ptr->eval_thread, &ptr->attr, in_thread_eval,(void *)&ptr->v); + if (cres){ + thread_eval_status(0,contextptr); + pthread_mutex_unlock(mutexptr(contextptr)); + } + return !cres; + } + + // check if contextptr has a running evaluation thread + // if not returns -1 + // if evaluation is not finished return 1 + // if evaluation is finished, clear mutex lock and + // call the thread_param_ptr callback function with the evaluation value + // and returns 0 + // otherwise returns status, 2=debug, 3=wait click + int check_thread(context * contextptr){ + if (!is_context_busy(contextptr)) + return -1; + int status=thread_eval_status(contextptr); + if (status!=0 && !kill_thread(contextptr)) + return status; + thread_param tp = *thread_param_ptr(contextptr); + if (status==0){ + // unsigned thread_return_value=0; + // void * ptr_return=&thread_return_value; + // pthread_join(eval_thread,&ptr_return); + if ( +#ifdef __MINGW_H + 1 +#else + tp.eval_thread +#endif + ){ + giac_callback f=tp.f; + gen arg_callback=tp.v[5]; + void * param_callback=tp.f_param; + double tt=tp.v[4]._DOUBLE_val; + pthread_join(tp.eval_thread,0); + pthread_mutex_unlock(mutexptr(contextptr)); + // double tt=double(tp.v[4].val)/CLOCKS_PER_SEC; + if (tt>0.4) + (*logptr(contextptr)) << gettext("\nEvaluation time: ") << tt << '\n'; + if (f) + f(arg_callback,param_callback); + else + (*logptr(contextptr)) << arg_callback << '\n'; + return 0; + } + } + if (kill_thread(contextptr)==1){ + kill_thread(0,contextptr); + thread_eval_status(0,contextptr); + clear_prog_status(contextptr); + cleanup_context(contextptr); + if (tp.f) + tp.f(string2gen("Aborted",false),tp.f_param); +#if !defined __MINGW_H && !defined KHICAS && !defined SDL_KHICAS + *logptr(contextptr) << gettext("Thread ") << tp.eval_thread << " has been cancelled" << '\n'; +#endif +#ifdef NO_STDEXCEPT + pthread_cancel(tp.eval_thread) ; +#else + try { + pthread_cancel(tp.eval_thread) ; + } catch (...){ + } +#endif + pthread_mutex_unlock(mutexptr(contextptr)); + return -1; + } + return status; + } + + // check contexts in context_list starting at index i, + // returns at first context with status >= 2 + // return value is -2 (invalid range), -1 (ok) or context number + int check_threads(int i){ + int s,ans=-1; + context * cptr; + if (// i>=s || + i<0) + return -2; + for (;;++i){ + pthread_mutex_lock(&context_list_mutex); + s=context_list().size(); + if (i=s) + break; + int res=check_thread(cptr); + if (res>1){ + ans=i; + break; + } + } + return ans; + } + + gen thread_eval(const gen & g_,int level,context * contextptr,void (* wait_0001)(context *) ){ + gen g=equaltosto(g_,contextptr); + /* launch a new thread for evaluation only, + no more readqueue, readqueue is done by the "parent" thread + Ctrl-C will kill the "child" thread + wait_001 is a function that should wait 0.001 s and update thinks + for example it could remove idle callback of a GUI + then call the wait function of the GUI and readd callbacks + */ + pthread_t eval_thread; + vecteur v(6); + v[0]=g; + v[1]=level; + v[2]=gen(contextptr,_CONTEXT_POINTER); + pthread_mutex_lock(mutexptr(contextptr)); + thread_eval_status(1,contextptr); + int cres=pthread_create (&eval_thread, (pthread_attr_t *) NULL, in_thread_eval,(void *)&v); + if (!cres){ + for (;;){ + int eval_status=thread_eval_status(contextptr); + if (!eval_status) + break; + wait_0001(contextptr); + if (kill_thread(contextptr)==1){ + kill_thread(0,contextptr); + clear_prog_status(contextptr); + cleanup_context(contextptr); +#if !defined __MINGW_H && !defined KHICAS && !defined SDL_KHICAS + *logptr(contextptr) << gettext("Cancel thread ") << eval_thread << '\n'; +#endif +#ifdef NO_STDEXCEPT + pthread_cancel(eval_thread) ; +#else + try { + pthread_cancel(eval_thread) ; + } catch (...){ + } +#endif + pthread_mutex_unlock(mutexptr(contextptr)); + return undef; + } + } + // unsigned thread_return_value=0; + // void * ptr=&thread_return_value; + pthread_join(eval_thread,0); // pthread_join(eval_thread,&ptr); + // Restore pointers and return v[3] + pthread_mutex_unlock(mutexptr(contextptr)); + // double tt=double(v[4].val)/CLOCKS_PER_SEC; + double tt=v[4]._DOUBLE_val; + if (tt>0.1) + (*logptr(contextptr)) << gettext("Evaluation time: ") << tt << '\n'; + return v[5]; + } + pthread_mutex_unlock(mutexptr(contextptr)); + return protecteval(g,level,contextptr); + } +#else + + bool make_thread(const gen & g,int level,const giac_callback & f,void * f_param,const context * contextptr){ + return false; + } + + int check_thread(context * contextptr){ + return -1; + } + + int check_threads(int i){ + return -1; + } + + gen thread_eval(const gen & g,int level,context * contextptr,void (* wait_001)(context * )){ + return protecteval(g,level,contextptr); + } +#endif // HAVE_LIBPTHREAD + + debug_struct::debug_struct():indent_spaces(0),debug_mode(false),sst_mode(false),sst_in_mode(false),debug_allowed(true),current_instruction(-1),debug_refresh(false){ + debug_info_ptr=new gen; + fast_debug_info_ptr=new gen; + debug_prog_name=new gen; + debug_localvars=new gen; + debug_contextptr=0; + } + + debug_struct::~debug_struct(){ + delete debug_info_ptr; + delete fast_debug_info_ptr; + delete debug_prog_name; + delete debug_localvars; + } + + debug_struct & debug_struct::operator =(const debug_struct & dbg){ + indent_spaces=dbg.indent_spaces; + args_stack=dbg.args_stack; + debug_breakpoint=dbg.debug_breakpoint; + debug_watch=dbg.debug_watch ; + debug_mode=dbg.debug_mode; + sst_mode=dbg.sst_mode ; + sst_in_mode=dbg.sst_in_mode ; + debug_allowed=dbg.debug_allowed; + current_instruction_stack=dbg.current_instruction_stack; + current_instruction=dbg.current_instruction; + sst_at_stack=dbg.sst_at_stack; + sst_at=dbg.sst_at; + if (debug_info_ptr) + delete debug_info_ptr; + debug_info_ptr=new gen(dbg.debug_info_ptr?*dbg.debug_info_ptr:0) ; + if (fast_debug_info_ptr) + delete fast_debug_info_ptr; + fast_debug_info_ptr= new gen(dbg.fast_debug_info_ptr?*dbg.fast_debug_info_ptr:0); + if (debug_prog_name) + delete debug_prog_name; + debug_prog_name=new gen(dbg.debug_prog_name?*dbg.debug_prog_name:0); + if (debug_localvars) + delete debug_localvars; + debug_localvars=new gen(dbg.debug_localvars?*dbg.debug_localvars:0); + debug_refresh=dbg.debug_refresh; + debug_contextptr=dbg.debug_contextptr; + return *this; + } + + static debug_struct & _debug_data(){ + static debug_struct * ans = 0; + if (!ans) ans=new debug_struct; + return *ans; + } + + debug_struct * debug_ptr(GIAC_CONTEXT){ + if (contextptr && contextptr->globalptr) + return contextptr->globalptr->_debug_ptr; + return &_debug_data(); + } + + void clear_prog_status(GIAC_CONTEXT){ + debug_struct * ptr=debug_ptr(contextptr); + if (ptr){ + ptr->args_stack.clear(); + ptr->debug_mode=false; + ptr->sst_at_stack.clear(); + if (!contextptr) + protection_level=0; + } + } + + + global::global() : _xcas_mode_(0), + _calc_mode_(0),_decimal_digits_(12),_minchar_for_quote_as_string_(1), + _scientific_format_(0), _integer_format_(0), _latex_format_(0), +#ifdef BCD + _bcd_decpoint_('.'|('E'<<16)|(' '<<24)),_bcd_mantissa_(12+(15<<8)), _bcd_flags_(0),_bcd_printdouble_(false), +#endif + _expand_re_im_(true), _do_lnabs_(true), _eval_abs_(true),_eval_equaltosto_(true),_integer_mode_(true),_complex_mode_(false), _escape_real_(true),_complex_variables_(false), _increasing_power_(false), _approx_mode_(false), _variables_are_files_(false), _local_eval_(true), + _withsqrt_(true), + _show_point_(true), _io_graph_(true), + _all_trig_sol_(false), +#ifdef __MINGW_H + _ntl_on_(false), +#else + _ntl_on_(true), +#endif +#ifdef WITH_MYOSTREAM + _lexer_close_parenthesis_(true),_rpn_mode_(false),_try_parse_i_(true),_specialtexprint_double_(false),_atan_tan_no_floor_(false),_keep_acosh_asinh_(false),_keep_algext_(false),_auto_assume_(false),_parse_e_(false),_convert_rootof_(true), +#ifdef KHICAS + _python_compat_(true), +#else + _python_compat_(false), +#endif + _angle_mode_(0), _bounded_function_no_(0), _series_flags_(0x3),_step_infolevel_(0),_default_color_(FL_BLACK), _epsilon_(1e-12), _proba_epsilon_(1e-15), _show_axes_(1),_spread_Row_ (-1), _spread_Col_ (-1),_logptr_(&my_CERR),_prog_eval_level_val(1), _eval_level(DEFAULT_EVAL_LEVEL), _rand_seed(123457),_last_evaled_function_name_(0),_currently_scanned_(""),_last_evaled_argptr_(0),_max_sum_sqrt_(3), +#ifdef GIAC_HAS_STO_38 // Prime sum(x^2,x,0,100000) crash on hardware + _max_sum_add_(10000), +#else + _max_sum_add_(100000), +#endif + _total_time_(0),_evaled_table_(0),_extra_ptr_(0),_series_variable_name_('h'),_series_default_order_(5), +#else + _lexer_close_parenthesis_(true),_rpn_mode_(false),_try_parse_i_(true),_specialtexprint_double_(false),_atan_tan_no_floor_(false),_keep_acosh_asinh_(false),_keep_algext_(false),_auto_assume_(false),_parse_e_(false),_convert_rootof_(true), +#ifdef KHICAS + _python_compat_(true), +#else + _python_compat_(false), +#endif + _angle_mode_(0), _bounded_function_no_(0), _series_flags_(0x3),_step_infolevel_(0),_default_color_(FL_BLACK), _epsilon_(1e-12), _proba_epsilon_(1e-15), _show_axes_(1),_spread_Row_ (-1), _spread_Col_ (-1), +#if (defined(EMCC) || defined(EMCC2)) && !defined SDL_KHICAS + _logptr_(&COUT), +#else +#ifdef FXCG + _logptr_(0), +#else +#if defined KHICAS || defined SDL_KHICAS + _logptr_(&os_cerr), +#else + _logptr_(&CERR), +#endif +#endif +#endif + _prog_eval_level_val(1), _eval_level(DEFAULT_EVAL_LEVEL), _rand_seed(123457),_last_evaled_function_name_(0),_currently_scanned_(""),_last_evaled_argptr_(0),_max_sum_sqrt_(3), +#ifdef GIAC_HAS_STO_38 // Prime sum(x^2,x,0,100000) crash on hardware + _max_sum_add_(10000), +#else + _max_sum_add_(100000), +#endif + _total_time_(0),_evaled_table_(0),_extra_ptr_(0),_series_variable_name_('h'),_series_default_order_(5) +#endif + { + _pl._i_sqrt_minus1_=1; +#if !defined KHICAS && !defined SDL_KHICAS + _turtle_stack_.push_back(_turtle_); +#endif + _debug_ptr=new debug_struct; + _thread_param_ptr=new thread_param; + _parsed_genptr_=new gen; +#ifdef GIAC_HAS_STO_38 + _autoname_="GA"; +#else + _autoname_="A"; +#endif + _autosimplify_="regroup"; + _lastprog_name_="lastprog"; + _format_double_=""; +#ifdef HAVE_LIBPTHREAD + _mutexptr = new pthread_mutex_t; + pthread_mutex_init(_mutexptr,0); + _mutex_eval_status_ptr = new pthread_mutex_t; + pthread_mutex_init(_mutex_eval_status_ptr,0); +#endif + } + + global & global::operator = (const global & g){ + _xcas_mode_=g._xcas_mode_; + _calc_mode_=g._calc_mode_; + _decimal_digits_=g._decimal_digits_; + _minchar_for_quote_as_string_=g._minchar_for_quote_as_string_; + _scientific_format_=g._scientific_format_; + _integer_format_=g._integer_format_; + _integer_mode_=g._integer_mode_; + _latex_format_=g._latex_format_; +#ifdef BCD + _bcd_decpoint_=g._bcd_decpoint_; + _bcd_mantissa_=g._bcd_mantissa_; + _bcd_flags_=g._bcd_flags_; + _bcd_printdouble_=g._bcd_printdouble_; +#endif + _expand_re_im_=g._expand_re_im_; + _do_lnabs_=g._do_lnabs_; + _eval_abs_=g._eval_abs_; + _eval_equaltosto_=g._eval_equaltosto_; + _complex_mode_=g._complex_mode_; + _escape_real_=g._escape_real_; + _complex_variables_=g._complex_variables_; + _increasing_power_=g._increasing_power_; + _approx_mode_=g._approx_mode_; + _series_variable_name_=g._series_variable_name_; + _series_default_order_=g._series_default_order_; + _angle_mode_=g._angle_mode_; + _atan_tan_no_floor_=g._atan_tan_no_floor_; + _keep_acosh_asinh_=g._keep_acosh_asinh_; + _keep_algext_=g._keep_algext_; + _auto_assume_=g._auto_assume_; + _parse_e_=g._parse_e_; + _convert_rootof_=g._convert_rootof_; + _python_compat_=g._python_compat_; + _variables_are_files_=g._variables_are_files_; + _bounded_function_no_=g._bounded_function_no_; + _series_flags_=g._series_flags_; // bit1= full simplify, bit2=1 for truncation, bit3=?, bit4=1 do not convert back SPOL1 to symbolic expression + _step_infolevel_=g._step_infolevel_; // bit1= full simplify, bit2=1 for truncation + _local_eval_=g._local_eval_; + _default_color_=g._default_color_; + _epsilon_=g._epsilon_; + _proba_epsilon_=g._proba_epsilon_; + _withsqrt_=g._withsqrt_; + _show_point_=g._show_point_; // show 3-d point + _io_graph_=g._io_graph_; // show 2-d point in io + _show_axes_=g._show_axes_; + _spread_Row_=g._spread_Row_; + _spread_Col_=g._spread_Col_; + _printcell_current_row_=g._printcell_current_row_; + _printcell_current_col_=g._printcell_current_col_; + _all_trig_sol_=g._all_trig_sol_; + _ntl_on_=g._ntl_on_; + _prog_eval_level_val =g._prog_eval_level_val ; + _eval_level=g._eval_level; + _rand_seed=g._rand_seed; + _language_=g._language_; + _last_evaled_argptr_=g._last_evaled_argptr_; + _last_evaled_function_name_=g._last_evaled_function_name_; + _currently_scanned_=g._currently_scanned_; + _max_sum_sqrt_=g._max_sum_sqrt_; + _max_sum_add_=g._max_sum_add_; + _turtle_=g._turtle_; +#if !defined KHICAS && !defined SDL_KHICAS + _turtle_stack_=g._turtle_stack_; +#endif + _autoname_=g._autoname_; + _format_double_=g._format_double_; + _extra_ptr_=g._extra_ptr_; + return *this; + } + + global::~global(){ + delete _parsed_genptr_; + delete _thread_param_ptr; + delete _debug_ptr; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_destroy(_mutexptr); + delete _mutexptr; + pthread_mutex_destroy(_mutex_eval_status_ptr); + delete _mutex_eval_status_ptr; +#endif + } + +#ifdef FXCG + bool my_isinf(double d){ + return 1/d==0.0; + } + bool my_isnan(double d){ + return d==d+1 && !my_isinf(d); + } +#else // FXCG +#ifdef __APPLE__ + bool my_isnan(double d){ +#if 1 // TARGET_OS_IPHONE + return isnan(d); +#else + return __isnand(d); +#endif + } + + bool my_isinf(double d){ +#if 1 // TARGET_OS_IPHONE + return isinf(d); +#else + return __isinfd(d); +#endif + } + +#else // __APPLE__ + bool my_isnan(double d){ +#if defined VISUALC || defined BESTA_OS +#if !defined RTOS_THREADX && !defined FREERTOS + return _isnan(d)!=0; +#else + return isnan(d); +#endif +#else +#if defined(FIR_LINUX) || defined(FIR_ANDROID) + return std::isnan(d); +#else + return isnan(d); +#endif +#endif + } + + bool my_isinf(double d){ +#if defined VISUALC || defined BESTA_OS + double x=0.0; + return d==1.0/x || d==-1.0/x; +#else +#if defined(FIR_LINUX) || defined(FIR_ANDROID) + return std::isinf(d); +#else + return isinf(d); +#endif +#endif + } + +#endif // __APPLE__ +#endif // FXCG + + double giac_floor(double d){ + double maxdouble=longlong(1)<<30; + if (d>=maxdouble || d<=-maxdouble) + return std::floor(d); + if (d>0) + return int(d); + double k=int(d); + if (k==d) + return k; + else + return k-1; + } + double giac_ceil(double d){ + double maxdouble=longlong(1)<<54; + if (d>=maxdouble || d<=-maxdouble) + return d; + if (d<0) + return double(longlong(d)); + double k=double(longlong(d)); + if (k==d) + return k; + else + return k+1; + } + + + +/* --------------------------------------------------------------------- */ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF-16 and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + Jan 2013: Jean-Yves Avenard adapted to only calculate size if + destination pointer are null + +------------------------------------------------------------------------ */ + + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + +/* --------------------------------------------------------------------- */ + +unsigned int ConvertUTF16toUTF8 ( + const UTF16* sourceStart, const UTF16* sourceEnd, + UTF8* targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = sourceStart; + UTF8* target = targetStart; + UTF32 ch; + while ((source < sourceEnd) && (ch = *source)) { + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + UTF32 ch2; + if ((source < sourceEnd) && (ch2 = *source)) { + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if ((uintptr_t)target > (uintptr_t)targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: target--; if (targetStart) { *target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; } + case 3: target--; if (targetStart) { *target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; } + case 2: target--; if (targetStart) { *target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; } + case 1: target--; if (targetStart) { *target = (UTF8)(ch | firstByteMark[bytesToWrite]); } + } + target += bytesToWrite; + } + + unsigned int length = int(target - targetStart); + return length; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +unsigned int ConvertUTF8toUTF16 (const UTF8* sourceStart, const UTF8* sourceEnd, UTF16* targetStart, UTF16* targetEnd, ConversionFlags flags) +#if 0 //def GIAC_HAS_STO_38 +{ + wchar_t *d= targetStart; +#define read(a) if (sourceStart>=sourceEnd) break; a= *sourceStart++ + while (sourceStart= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if ((uintptr_t)target >= (uintptr_t)targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + if (targetStart) + *target = UNI_REPLACEMENT_CHAR; + target++; + } + } else { + if (targetStart) + *target = (UTF16)ch; /* normal case */ + target++; + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if ((uintptr_t)target + 1 >= (uintptr_t)targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + if (targetStart) + { + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + else + target += 2; + } + } + + unsigned int length = unsigned(target - targetStart); + return length; +} + + unsigned int utf82unicode(const char * line, wchar_t * wline, unsigned int n){ + if (!line){ + if (wline) wline[0]=0; + return 0; + } + + unsigned int j = ConvertUTF8toUTF16 ( + (const UTF8*) line,((line + n) < line) ? (const UTF8*)~0 : (const UTF8*)(line + n), + (UTF16*)wline, (UTF16*)~0, + lenientConversion); + + if (wline) wline[j] = 0; + + return j; + } + + // convert position n in utf8-encoded line into the corresponding position + // in the same string encoded with unicode + unsigned int utf8pos2unicodepos(const char * line,unsigned int n,bool skip_added_spaces){ + if (!line) return 0; + unsigned int i=0,j=0,c; + for (;i=0x2000 && masked<0x2c00) + j -= 2; + } + continue; + } + if ( (c & 0xf8) == 0xf0) { // 4 char 11110/xxx/ 10/xxxxxx/ 10/xxxxxx/ 10/xxxxxx/ + i++; + c = (c & 0x07) << 6 | (line[i] & 0x3f); + i++; + c = c << 6 | (line[i] & 0x3f); + i++; + c = c << 6 | (line[i] & 0x3f); + j++; + continue; + } + // FIXME complete for 5 and 6 char + c = 0xfffd; + j++; + } + return j; + } + + unsigned int wstrlen(const char * line, unsigned int n){ + if (!line) return 0; + return utf82unicode(line, NULL, n); + } + + // convert UTF8 string to unicode, allocate memory with new + wchar_t * utf82unicode(const char * idname){ + if (!idname) + return 0; + int l=int(strlen(idname)); + wchar_t * wname=new wchar_t[l+1]; + utf82unicode(idname,wname,l); + return wname; + } + +#if defined NSPIRE || defined FXCG + unsigned wcslen(const wchar_t * c){ + unsigned i=0; + for (;*c;++i) + ++c; + return i; + } +#endif + + char * unicode2utf8(const wchar_t * idname){ + if (!idname) + return 0; + int l=int(wcslen(idname)); + char * name=new char[4*l+1]; + unicode2utf8(idname,name,l); + return name; + } + + unsigned int wstrlen(const wchar_t * wline){ + if (!wline) + return 0; + unsigned int i=0; + for (;*wline;wline++){ i++; } + return i; + } + + // return length required to translate from unicode to UTF8 + unsigned int utf8length(const wchar_t * wline){ + return unicode2utf8(wline,0,wstrlen(wline)); + } + + unsigned int unicode2utf8(const wchar_t * wline,char * line,unsigned int n){ + if (!wline){ + if (line) line[0]=0; + return 0; + } + + unsigned int j = ConvertUTF16toUTF8( + (UTF16*)wline, ((wline + n) < wline) ? (const UTF16*)~0 : (const UTF16*)(wline + n), + (UTF8*)line, (UTF8*)-1, + lenientConversion); + + if (line) line[j]=0; + + return j; + } + + // Binary archive format for a gen: + // 8 bytes=the gen itself (i.e. type, subtype, etc.) + // Additionnally for pointer types + // 4 bytes = total size of additionnal data + // _CPLX: both real and imaginary parts + // _FRAC: numerator and denominator + // _MOD: 2 gens + // _REAL, _ZINT: long int/real binary archive + // _VECT: 4 bytes = #rows #cols (#cols=0 if not a matrix) + list of elements + // _SYMB: feuille + sommet + // _FUNC: 2 bytes = -1 + string or index + // _IDNT or _STRNG: the name + // count number of bytes required to save g in a file + static size_t countfunction(void const* p, size_t nbBytes,size_t NbElements, void *file) + { + (*(unsigned *)file)+= unsigned(nbBytes*NbElements); + return nbBytes*NbElements; + } + unsigned archive_count(const gen & g,GIAC_CONTEXT){ + unsigned size= 0; + archive_save((void*)&size, g, countfunction, contextptr, true); + return size; + } + + /* + unsigned archive_count(const gen & g,GIAC_CONTEXT){ + if (g.type<=_DOUBLE_ || g.type==_FLOAT_) + return sizeof(gen); + if (g.type==_CPLX) + return sizeof(gen)+sizeof(unsigned)+archive_count(*g._CPLXptr,contextptr)+archive_count(*(g._CPLXptr+1),contextptr); + if (g.type==_REAL || g.type==_ZINT) + return sizeof(gen)+sizeof(unsigned)+g.print(contextptr).size(); + if (g.type==_FRAC) + return sizeof(gen)+sizeof(unsigned)+archive_count(g._FRACptr->num,contextptr)+archive_count(g._FRACptr->den,contextptr); + if (g.type==_MOD) + return sizeof(gen)+sizeof(unsigned)+archive_count(*g._MODptr,contextptr)+archive_count(*(g._MODptr+1),contextptr); + if (g.type==_VECT){ + unsigned res=sizeof(gen)+sizeof(unsigned)+4; + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it) + res += archive_count(*it,contextptr); + return res; + } + if (g.type==_SYMB){ + if (archive_function_index(g._SYMBptr->sommet)) // ((equalposcomp(archive_function_tab(),g._SYMBptr->sommet)) + return sizeof(gen)+sizeof(unsigned)+sizeof(short)+archive_count(g._SYMBptr->feuille,contextptr); + return sizeof(gen)+sizeof(unsigned)+sizeof(short)+archive_count(g._SYMBptr->feuille,contextptr)+strlen(g._SYMBptr->sommet.ptr()->s); + } + if (g.type==_IDNT) + return sizeof(gen)+sizeof(unsigned)+strlen(g._IDNTptr->id_name); + if (g.type==_FUNC){ + if (archive_function_index(*g._FUNCptr)) // (equalposcomp(archive_function_tab(),*g._FUNCptr)) + return sizeof(gen)+sizeof(unsigned)+sizeof(short); + return sizeof(gen)+sizeof(unsigned)+sizeof(short)+strlen(g._FUNCptr->ptr()->s); + } + return sizeof(gen)+sizeof(unsigned)+strlen(g.print().c_str()); // not handled + } + */ + +#define DBG_ARCHIVE 0 + + bool archive_save(void * f,const gen & g,size_t writefunc(void const* p, size_t nbBytes,size_t NbElements, void *file),GIAC_CONTEXT, bool noRecurse){ + // write the gen first + writefunc(&g,sizeof(gen),1,f); + if (g.type<=_DOUBLE_ || g.type==_FLOAT_) + return true; + // heap allocated object, find size + unsigned size=0; + if (!noRecurse) size=archive_count(g,contextptr); + writefunc(&size,sizeof(unsigned),1,f); + if (g.type==_CPLX) + return archive_save(f,*g._CPLXptr,writefunc,contextptr,noRecurse) && archive_save(f,*(g._CPLXptr+1),writefunc,contextptr,noRecurse); + if (g.type==_MOD) + return archive_save(f,*g._MODptr,writefunc,contextptr,noRecurse) && archive_save(f,*(g._MODptr+1),writefunc,contextptr,noRecurse); + if (g.type==_FRAC) + return archive_save(f,g._FRACptr->num,writefunc,contextptr,noRecurse) && archive_save(f,g._FRACptr->den,writefunc,contextptr,noRecurse); + if (g.type==_VECT){ + unsigned short rows=g._VECTptr->size(),cols=0; + if (ckmatrix(g)) + cols=g._VECTptr->front()._VECTptr->size(); + writefunc(&rows,sizeof(short),1,f); + writefunc(&cols,sizeof(short),1,f); + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it){ + if (!archive_save(f,*it,writefunc,contextptr,noRecurse)) + return false; + } + return true; + } + if (g.type==_IDNT){ +#if DBG_ARCHIVE + std::ofstream ofs; + ofs.open ("e:\\tmp\\logsave", std::ofstream::out | std::ofstream::app); + ofs << "IDNT " << g << '\n'; + ofs.close(); +#endif + // fprintf(f,"%s",g._IDNTptr->id_name); + writefunc(g._IDNTptr->id_name,1,strlen(g._IDNTptr->id_name),f); + return true; + } + if (g.type==_SYMB){ + if (!archive_save(f,g._SYMBptr->feuille,writefunc,contextptr,noRecurse)) + return false; +#if DBG_ARCHIVE + std::ofstream ofs; + ofs.open ("e:\\tmp\\logsave", std::ofstream::out | std::ofstream::app); + ofs << "SYMB " << g << '\n'; + ofs.close(); +#endif + short i=archive_function_index(g._SYMBptr->sommet); // equalposcomp(archive_function_tab(),g._SYMBptr->sommet); + writefunc(&i,sizeof(short),1,f); + if (i) + return true; + // fprintf(f,"%s",g._SYMBptr->sommet.ptr()->s); + writefunc(g._SYMBptr->sommet.ptr()->s,1,strlen(g._SYMBptr->sommet.ptr()->s),f); + return true; + } + if (g.type==_FUNC){ + short i=archive_function_index(*g._FUNCptr); // equalposcomp(archive_function_tab(),*g._FUNCptr); + writefunc(&i,sizeof(short),1,f); + if (!i){ + // fprintf(f,"%s",g._FUNCptr->ptr()->s); + writefunc(g._FUNCptr->ptr()->s,1,strlen(g._FUNCptr->ptr()->s),f); + } + return true; + } + string s; + if (g.type==_ZINT) + s=hexa_print_ZINT(*g._ZINTptr); + else + s=g.print(contextptr); + // fprintf(f,"%s",s.c_str()); + writefunc(s.c_str(),1,s.size(),f); + return true; + //return false; + } + + + bool archive_save(void * f,const gen & g,GIAC_CONTEXT){ + return archive_save(f,g,(size_t (*)(void const* p, size_t nbBytes,size_t NbElements, void *file))fwrite,contextptr); + } + +#ifdef GIAC_HAS_STO_38 + // return true/false to tell if s is recognized. return the appropriate gen if true + int lexerCompare(void const *a, void const *b) { + charptr_gen_unary const * ptr=(charptr_gen_unary const *)b; + const char * aptr=(const char *) a; + return strcmp(aptr, ptr->s); + } + + bool casbuiltin(const char *s, gen &g){ + // binary search in builtin_lexer_functions +#if 1 // def SMARTPTR64 + int n=builtin_lexer_functions_number; + charptr_gen_unary const * f = (charptr_gen_unary const *)bsearch(s, builtin_lexer_functions, n, sizeof(builtin_lexer_functions[0]), lexerCompare); + if (f != NULL) { + g = 0; + int pos = int(f - builtin_lexer_functions); + size_t val = builtin_lexer_functions_[pos]; + unary_function_ptr * at_val = (unary_function_ptr *)val; + g = at_val; + if (builtin_lexer_functions[pos]._FUNC_%2){ +#ifdef SMARTPTR64 + unary_function_ptr tmp=*at_val; + tmp._ptr+=1; + g=tmp; +#else + g._FUNC_ +=1; +#endif // SMARTPTR64 + } + return true; + } +#else + charptr_gen_unary const * f = (charptr_gen_unary const *)bsearch(s, builtin_lexer_functions, builtin_lexer_functions_number, sizeof(builtin_lexer_functions[0]), lexerCompare); + if (f != NULL) { + g = gen(0); + int pos=f - builtin_lexer_functions; + *(size_t *)(&g) = builtin_lexer_functions_[pos] + f->_FUNC_; + g = gen(*g._FUNCptr); + return true; + } +#endif + if (strlen(s)==1 && s[0]==':'){ + g=at_deuxpoints; + return true; + } + return false; + } + +#endif + + // restore a gen from an opened file + gen archive_restore(void * f,size_t readfunc(void * p, size_t nbBytes,size_t NbElements, void *file),GIAC_CONTEXT){ + gen g; + if (!readfunc(&g,sizeof(gen),1,f)) + return undef; + if (g.type<=_DOUBLE_ || g.type==_FLOAT_) + return g; + unsigned char t=g.type; + signed char s=g.subtype; + g.type=0; // required to avoid destructor of g to mess up the pointer part + unsigned size; + if (!readfunc(&size,sizeof(unsigned),1,f)) + return undef; + if (t==_CPLX || t==_MOD || t==_FRAC){ + gen g1=archive_restore(f,readfunc,contextptr); + gen g2=archive_restore(f,readfunc,contextptr); + if (t==_CPLX) + return g1+cst_i*g2; + if (t==_FRAC) + return fraction(g1,g2); + if (t==_MOD) + return makemodquoted(g1,g2); + } + size -= sizeof(gen)+sizeof(unsigned); // adjust for gen size and length + if (t==_VECT){ + unsigned short rows,cols; + if (!readfunc(&rows,sizeof(unsigned short),1,f)) + return undef; + if (!readfunc(&cols,sizeof(unsigned short),1,f)) + return undef; +// if (!rows) return undef; + vecteur v(rows); + for (int i=0;isecond; + else { + res=identificateur(sch); + syms()[sch]=res; + } + unlock_syms_mutex(); +#if DBG_ARCHIVE + std::ofstream ofs; + ofs.open ("e:\\tmp\\logrestore", std::ofstream::out | std::ofstream::app); + ofs << "IDNT " << res << '\n'; + ofs.close(); +#endif + return res; + } + if (t==_SYMB){ + gen fe=archive_restore(f,readfunc,contextptr); + short index; + if (!readfunc(&index,sizeof(short),1,f)) + return undef; + if (index>0){ + const unary_function_ptr * aptr=archive_function_tab(); + if (index p=equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(),std::pair(ch,0),tri); + if (p.first!=p.second && p.first!=builtin_lexer_functions_end()){ + res = p.first->second; + res.subtype=1; + res=gen(int((*builtin_lexer_functions_())[p.first-builtin_lexer_functions_begin()]+p.first->second.val)); + res=gen(*res._FUNCptr); + } + } +#else + if (builtin_lexer_functions_){ +#ifdef GIAC_HAS_STO_38 + if (!casbuiltin(ch,res)){ +#if DBG_ARCHIVE + std::ofstream ofs; + ofs.open ("e:\\tmp\\logrestore", std::ofstream::out | std::ofstream::app); + ofs << "archive_restore error _SYMB " << ch << '\n'; + ofs.close(); +#endif + res=0; + } +#else + std::pair p=equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(),std::pair(ch,0),tri); + if (p.first!=p.second && p.first!=builtin_lexer_functions_end()){ + res = p.first->second; + res.subtype=1; + res=gen(int(builtin_lexer_functions_[p.first-builtin_lexer_functions_begin()]+p.first->second.val)); + res=gen(*res._FUNCptr); + } +#endif + } +#endif + } + if (is_zero(res)){ +#if DBG_ARCHIVE + std::ofstream ofs; + ofs.open ("e:\\tmp\\logrestore", std::ofstream::out | std::ofstream::app); + ofs << "archive_restore error _SYMB 0 " << ch << '\n'; + ofs.close(); +#endif + res=gen(ch,contextptr); + } + delete [] ch; + if (res.type!=_FUNC){ + return undef; + } + g=symbolic(*res._FUNCptr,fe); + } + g.subtype=s; +#if DBG_ARCHIVE + std::ofstream ofs; + ofs.open ("e:\\tmp\\logrestore", std::ofstream::out | std::ofstream::app); + ofs << "SYMB " << g << '\n'; + ofs.close(); +#endif + return g; + } + if (t==_FUNC){ + short index; + if (!readfunc(&index,sizeof(short),1,f)) + return undef; + if (index>0) + g = archive_function_tab()[index-1]; + else { + size -= sizeof(short); + char * ch=new char[size+1]; + ch[size]=0; + if (readfunc(ch,1,size,f)!=size){ + delete [] ch; + return undef; + } + g = gen(ch,contextptr); + delete [] ch; + if (g.type!=_FUNC) + return undef; + } + g.subtype=s; + return g; + } + char * ch=new char[size+1]; + ch[size]=0; + if (readfunc(ch,1,size,f)!=size){ + delete [] ch; + return undef; + } + gen res; + if (t==_STRNG) + res=string2gen(ch,true); + else + res=gen(ch,contextptr); + delete [] ch; + return res; + } + + gen archive_restore(FILE * f,GIAC_CONTEXT){ + return archive_restore(f,(size_t (*)(void * p, size_t nbBytes,size_t NbElements, void *file))fread,contextptr); + } + + void init_geogebra(bool on,GIAC_CONTEXT){ +#ifndef FXCG + setlocale(LC_NUMERIC,"POSIX"); +#endif + _decimal_digits_=on?13:12; + _all_trig_sol_=on; + _withsqrt_=!on; + _calc_mode_=on?1:0; + _eval_equaltosto_=on?0:1; + eval_equaltosto(on?0:1,contextptr); + decimal_digits(on?13:12,contextptr); + all_trig_sol(on,contextptr); + withsqrt(!on,contextptr); + calc_mode(on?1:0,contextptr); + powlog2float=3e4; + MPZ_MAXLOG2=33300; +#ifdef TIMEOUT + //caseval_maxtime=5; + caseval_n=0; + caseval_mod=10; +#endif + } + + vecteur giac_current_status(bool save_history,GIAC_CONTEXT){ + // cas and geo config + vecteur res; + if (abs_calc_mode(contextptr)==38) + res.push_back(cas_setup(contextptr)); + else + res.push_back(symbolic(at_cas_setup,cas_setup(contextptr))); + res.push_back(xyztrange(gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,gnuplot_zmin,gnuplot_zmax,gnuplot_tmin,gnuplot_tmax,global_window_xmin,global_window_xmax,global_window_ymin,global_window_ymax,show_axes(contextptr),class_minimum,class_size, +#ifdef WITH_GNUPLOT + gnuplot_hidden3d,gnuplot_pm3d +#else + 1,1 +#endif + )); + if (abs_calc_mode(contextptr)==38) + res.back()=res.back()._SYMBptr->feuille; + // session + res.push_back(save_history?history_in(contextptr):vecteur(0)); + res.push_back(save_history?history_out(contextptr):vecteur(0)); + // user variables + if (contextptr && contextptr->tabptr){ + sym_tab::const_iterator jt=contextptr->tabptr->begin(),jtend=contextptr->tabptr->end(); + for (;jt!=jtend;++jt){ + gen a=jt->second; + gen b=identificateur(jt->first); + res.push_back(symb_sto(a,b)); + } + } + else { + lock_syms_mutex(); + sym_string_tab::const_iterator it=syms().begin(),itend=syms().end(); + for (;it!=itend;++it){ + gen id=it->second; + if (id.type==_IDNT && id._IDNTptr->value && id._IDNTptr->ref_count_ptr!=(int *) -1) + res.push_back(symb_sto(*id._IDNTptr->value,id)); + } + unlock_syms_mutex(); + } + int xc=xcas_mode(contextptr); + if (xc==0 && python_compat(contextptr)) + xc=256*python_compat(contextptr); + if (abs_calc_mode(contextptr)==38) + res.push_back(xc); + else + res.push_back(symbolic(at_xcas_mode,xc)); + return res; + } + + bool unarchive_session(const gen & g,int level,const gen & replace,GIAC_CONTEXT,bool with_history){ + int l; + if (g.type!=_VECT || (l=int(g._VECTptr->size()))<4) + return false; + vecteur v=*g._VECTptr; + if (v[2].type!=_VECT || v[3].type!=_VECT || (v[2]._VECTptr->size()!=v[3]._VECTptr->size() && v[2]._VECTptr->size()!=v[3]._VECTptr->size()+1)) + return false; + if (v[2]._VECTptr->size()==v[3]._VECTptr->size()+1) + v[2]._VECTptr->pop_back(); +#ifndef DONT_UNARCHIVE_HISTORY + history_in(contextptr)=*v[2]._VECTptr; + history_out(contextptr)=*v[3]._VECTptr; +#ifndef GNUWINCE + if (v[0].type==_VECT) + _cas_setup(v[0],contextptr); + else + protecteval(v[0],eval_level(contextptr),contextptr); + if (v[1].type==_VECT) + _xyztrange(v[1],contextptr); + else + protecteval(v[1],eval_level(contextptr),contextptr); +#endif +#endif + // restore variables + for (int i=4;i=0 + if (level<0 || level>=l){ + history_in(contextptr).push_back(replace); + history_out(contextptr).push_back(protecteval(replace,eval_level(contextptr),contextptr)); + } + else { + history_in(contextptr)[level]=replace; + for (int i=level;i= begin and < end + for (;;){ + cur=(beg+end)/2; + test=strcmp(s,tab[cur]); + if (!test) + return cur; + if (cur==beg) + return -1; + if (test>0) + beg=cur; + else + end=cur; + } + return -1; + } + + gen add_autosimplify(const gen & g,GIAC_CONTEXT){ + if (g.type==_VECT) + return apply(g,add_autosimplify,contextptr); + if (g.type==_SYMB){ + if (g._SYMBptr->sommet==at_program) + return g; +#ifdef GIAC_HAS_STO_38 + const char * c=g._SYMBptr->sommet.ptr()->s; +#else + string ss=g._SYMBptr->sommet.ptr()->s; + if (g._SYMBptr->sommet==at_sto && g._SYMBptr->feuille.type==_VECT){ + vecteur & v=*g._SYMBptr->feuille._VECTptr; + if (v.size()==2 && v.front().type==_SYMB) + ss=v.front()._SYMBptr->sommet.ptr()->s; + } + ss=unlocalize(ss); + const char * c=ss.c_str(); +#endif +#if 1 + if (dichotomic_search(do_not_autosimplify,sizeof(do_not_autosimplify)/sizeof(char*)-1,c)!=-1) + return g; +#else + const char ** ptr=do_not_autosimplify; + for (;*ptr;++ptr){ + if (!strcmp(*ptr,c)) + return g; + } +#endif + } + std::string s=autosimplify(contextptr); + if (s.size()<1 || s=="'nop'") + return g; + gen a(s,contextptr); + if (a.type==_FUNC) + return symbolic(*a._FUNCptr,g); + if (a.type>=_IDNT) + return symb_of(a,g); + return g; + } + + bool csv_guess(const char * data,int count,char & sep,char & nl,char & decsep){ + bool ans=true; + int nb[256],pointdecsep=0,commadecsep=0; + for (int i=0;i<256;++i) + nb[i]=0; + // count occurrence of each char + // and detect decimal separator between . or , + for (int i=1;i='0' && data[i-1]<='9' && data[i+1]>='0' && data[i+1]<='9'){ + if (data[i]=='.') + ++pointdecsep; + if (data[i]==',') + ++commadecsep; + } + } + decsep=commadecsep>pointdecsep?',':'.'; + // detect nl (ctrl-M or ctrl-J) + nl=nb[10]>nb[13]?10:13; + // find in control characters and : ; the most used (except 10/13) + int nbmax=0,imax=-1; + for (int i=0;i<60;++i){ + if (i==10 || i==13 || (i>=' ' && i<='9') ) + continue; + if (nb[i]>nbmax){ + imax=i; + nbmax=nb[i]; + } + } + // compare . with , (44) + if (nb[unsigned(',')] && nb[unsigned(',')]>=nbmax){ + imax=','; + nbmax=nb[unsigned(',')]; + } + if (nbmax && nbmax>=nb[unsigned(nl)] && imax!=decsep) + sep=imax; + else + sep=' '; + return ans; + } + + void (*my_gprintf)(unsigned special,const string & format,const vecteur & v,GIAC_CONTEXT)=0; + + +#if defined(EMCC) || defined(EMCC2) + static void newlinestobr(string &s,const string & add){ + int l=int(add.size()); + for (int i=0;i=int(format.size())) + break; + newlinestobr(s,format.substr(pos,p-pos)); +#if !defined(UPSILON) && (defined(EMCC) || defined(EMCC2)) + gen tmp; + if (v[i].is_symb_of_sommet(at_pnt)) + tmp=_svg(v[i],contextptr); + else + tmp=_mathml(makesequence(v[i],1),contextptr); + s = s+((tmp.type==_STRNG)?(*tmp._STRNGptr):v[i].print(contextptr)); +#else + s += v[i].print(contextptr); +#endif + pos=p+4; + } + newlinestobr(s,format.substr(pos,format.size()-pos)); + *logptr(contextptr) << s << '\n'; +#if !defined(UPSILON) && (defined(EMCC) || defined(EMCC2)) + *logptr(contextptr) << char(3) << '\n'; // end mixed text/mathml + *logptr(contextptr) << '\n'; +#endif + } + + void gprintf(const string & format,const vecteur & v,GIAC_CONTEXT){ + gprintf(step_nothing_special,format,v,contextptr); + } + + void gprintf(const string & format,const vecteur & v,int step_info,GIAC_CONTEXT){ + gprintf(step_nothing_special,format,v,step_info,contextptr); + } + + // moved from input_lexer.ll for easier debug + const char invalid_name[]="Invalid name"; + +#if defined USTL || defined GIAC_HAS_STO_38 || (defined KHICAS && !defined(SIMU)) || defined SDL_KHICAS +#if defined GIAC_HAS_STO_38 || defined KHICAS || defined SDL_KHICAS +void update_lexer_localization(const std::vector & v,std::map &lexer_map,std::multimap &back_lexer_map,GIAC_CONTEXT){} +#endif +#else + vecteur * keywords_vecteur_ptr(){ + static vecteur v; + return &v; + } + + static void in_update_lexer_localization(istream & f,int lang,const std::vector & v,std::map &lexer_map,std::multimap &back_lexer_map,GIAC_CONTEXT){ + char * line = (char *)malloc(1024); + std::string giac_kw,local_kw; + size_t l; + for (;;){ + f.getline(line,1023,'\n'); + l=strlen(line); + if (f.eof()){ + break; + } + if (l>3 && line[0]!='#'){ + if (line[l-1]=='\n') + --l; + // read giac keyword + size_t j; + giac_kw=""; + for (j=0;jpush_back(localgen); + sto(gen(giac_kw,contextptr),localgen,contextptr); +#else + lexer_map[local_kw]=giac_kw; + back_lexer_map.insert(pair(giac_kw,localized_string(lang,local_kw))); +#endif + } + local_kw=""; + } + else + local_kw += line[j]; + } + if (!local_kw.empty()){ +#if defined(EMCC) || defined(EMCC2) + gen localgen(gen(local_kw,contextptr)); + keywordsptr->push_back(localgen); + sto(gen(giac_kw,contextptr),localgen,contextptr); +#else + lexer_map[local_kw]=giac_kw; + back_lexer_map.insert(pair(giac_kw,localized_string(lang,local_kw))); +#endif + } + } + } + free(line); + } + + void update_lexer_localization(const std::vector & v,std::map &lexer_map,std::multimap &back_lexer_map,GIAC_CONTEXT){ + lexer_map.clear(); + back_lexer_map.clear(); + int s=int(v.size()); + for (int i=0;i=1 && lang<=4){ + std::string doc=find_doc_prefix(lang); + std::string file=giac_aide_dir()+doc+"keywords"; + //COUT << "keywords " << file << '\n'; + ifstream f(file.c_str()); + if (f.good()){ + in_update_lexer_localization(f,lang,v,lexer_map,back_lexer_map,contextptr); + // COUT << "// Using keyword file " << file << '\n'; + } // if (f) + else { + if (lang==1){ +#ifdef HAVE_SSTREAM + istringstream f( +#else + istrstream f( +#endif + "# enter couples\n# giac_keyword translation\n# for example, to define integration as a translation for integrate \nintegrate integration\neven est_pair\nodd est_impair\n# geometry\nbarycenter barycentre\nisobarycenter isobarycentre\nmidpoint milieu\nline_segments aretes\nmedian_line mediane\nhalf_line demi_droite\nparallel parallele\nperpendicular perpendiculaire\ncommon_perpendicular perpendiculaire_commune\nenvelope enveloppe\nequilateral_triangle triangle_equilateral\nisosceles_triangle triangle_isocele\nright_triangle triangle_rectangle\nlocus lieu\ncircle cercle\nconic conique\nreduced_conic conique_reduite\nquadric quadrique\nreduced_quadric quadrique_reduite\nhyperbola hyperbole\ncylinder cylindre\nhalf_cone demi_cone\nline droite\nplane plan\nparabola parabole\nrhombus losange\nsquare carre\nhexagon hexagone\npyramid pyramide\nquadrilateral quadrilatere\nparallelogram parallelogramme\northocenter orthocentre\nexbisector exbissectrice\nparallelepiped parallelepipede\npolyhedron polyedre\ntetrahedron tetraedre\ncentered_tetrahedron tetraedre_centre\ncentered_cube cube_centre\noctahedron octaedre\ndodecahedron dodecaedre\nicosahedron icosaedre\nbisector bissectrice\nperpen_bisector mediatrice\naffix affixe\naltitude hauteur\ncircumcircle circonscrit\nexcircle exinscrit\nincircle inscrit\nis_prime est_premier\nis_equilateral est_equilateral\nis_rectangle est_rectangle\nis_parallel est_parallele\nis_perpendicular est_perpendiculaire\nis_orthogonal est_orthogonal\nis_collinear est_aligne\nis_concyclic est_cocyclique\nis_element est_element\nis_included est_inclus\nis_coplanar est_coplanaire\nis_isosceles est_isocele\nis_square est_carre\nis_rhombus est_losange\nis_parallelogram est_parallelogramme\nis_conjugate est_conjugue\nis_harmonic_line_bundle est_faisceau_droite\nis_harmonic_circle_bundle est_faisceau_cercle\nis_inside est_dans\narea aire\nperimeter perimetre\ndistance longueur\ndistance2 longueur2\nareaat aireen\nslopeat penteen\nangleat angleen\nperimeterat perimetreen\ndistanceat distanceen\nareaatraw aireenbrut\nslopeatraw penteenbrut\nangleatraw angleenbrut\nperimeteratraw perimetreenbrut\ndistanceatraw distanceenbrut\nextract_measure extraire_mesure\ncoordinates coordonnees\nabscissa abscisse\nordinate ordonnee\ncenter centre\nradius rayon\npowerpc puissance\nvertices sommets\npolygon polygone\nisopolygon isopolygone\nopen_polygon polygone_ouvert\nhomothety homothetie\nsimilarity similitude\n# affinity affinite\nreflection symetrie\nreciprocation polaire_reciproque\nscalar_product produit_scalaire\n# solid_line ligne_trait_plein\n# dash_line ligne_tiret\n# dashdot_line ligne_tiret_point\n# dashdotdot_line ligne_tiret_pointpoint\n# cap_flat_line ligne_chapeau_plat\n# cap_round_line ligne_chapeau_rond\n# cap_square_line ligne_chapeau_carre\n# line_width_1 ligne_epaisseur_1\n# line_width_2 ligne_epaisseur_2\n# line_width_3 ligne_epaisseur_3\n# line_width_4 ligne_epaisseur_4\n# line_width_5 ligne_epaisseur_5\n# line_width_6 ligne_epaisseur_6\n# line_width_7 ligne_epaisseur_7\n# line_width_8 ligne_epaisseur_8\n# rhombus_point point_losange\n# plus_point point_plus\n# square_point point_carre\n# cross_point point_croix\n# triangle_point point_triangle\n# star_point point_etoile\n# invisible_point point_invisible\ncross_ratio birapport\nradical_axis axe_radical\npolar polaire\npolar_point point_polaire\npolar_coordinates coordonnees_polaires\nrectangular_coordinates coordonnees_rectangulaires\nharmonic_conjugate conj_harmonique\nharmonic_division div_harmonique\ndivision_point point_div\n# harmonic_division_point point_division_harmonique\ndisplay affichage\nvertices_abc sommets_abc\nvertices_abca sommets_abca\nline_inter inter_droite\nsingle_inter inter_unique\ncolor couleur\nlegend legende\nis_harmonic est_harmonique\nbar_plot diagramme_batons\nbarplot diagrammebatons\nhistogram histogramme\nprism prisme\nis_cospherical est_cospherique\ndot_paper papier_pointe\ngrid_paper papier_quadrille\nline_paper papier_ligne\ntriangle_paper papier_triangule\nvector vecteur\nplotarea tracer_aire\nplotproba graphe_probabiliste\nmult_c_conjugate mult_conjugue_C\nmult_conjugate mult_conjugue\ncanonical_form forme_canonique\nibpu integrer_par_parties_u\nibpdv integrer_par_parties_dv\nwhen quand\nslope pente\ntablefunc table_fonction\ntableseq table_suite\nfsolve resoudre_numerique\ninput saisir\nprint afficher\nassume supposons\nabout domaine\nbreakpoint point_arret\nwatch montrer\nrmwatch ne_plus_montrer\nrmbreakpoint suppr_point_arret\nrand alea\nInputStr saisir_chaine\nOx_2d_unit_vector vecteur_unitaire_Ox_2d\nOy_2d_unit_vector vecteur_unitaire_Oy_2d\nOx_3d_unit_vector vecteur_unitaire_Ox_3d\nOy_3d_unit_vector vecteur_unitaire_Oy_3d\nOz_3d_unit_vector vecteur_unitaire_Oz_3d\nframe_2d repere_2d\nframe_3d repere_3d\nrsolve resoudre_recurrence\nassume supposons\ncumulated_frequencies frequences_cumulees\nfrequencies frequences\nnormald loi_normale\nregroup regrouper\nosculating_circle cercle_osculateur\ncurvature courbure\nevolute developpee\nvector vecteur\n"); + in_update_lexer_localization(f,1,v,lexer_map,back_lexer_map,contextptr); + } + else + CERR << "// Unable to find keyword file " << file << '\n'; + } + } + } + } +#endif + +#if !defined NSPIRE + +#include "input_parser.h" + + bool has_special_syntax(const char * s){ +#ifdef USTL + ustl::pair p= + ustl::equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(), + std::pair(s,0), + tri); +#else + std::pair p= + equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(), + std::pair(s,0), + tri); +#endif + if (p.first!=p.second && p.first!=builtin_lexer_functions_end()) + return (p.first->second.subtype!=T_UNARY_OP-256); + map_charptr_gen::const_iterator i = lexer_functions().find(s); + if (i==lexer_functions().end()) + return false; + return (i->second.subtype!=T_UNARY_OP-256); + } + + bool lexer_functions_register(const unary_function_ptr & u,const char * s,int parser_token){ + map_charptr_gen::const_iterator i = lexer_functions().find(s); + if (i!=lexer_functions().end()) + return false; + if (doing_insmod){ + if (debug_infolevel) CERR << "insmod register " << s << '\n'; + registered_lexer_functions().push_back(user_function(s,parser_token)); + } + if (!builtin_lexer_functions_sorted){ +#ifndef STATIC_BUILTIN_LEXER_FUNCTIONS +#if defined NSPIRE_NEWLIB || defined KHICAS || defined NUMWORKS + builtin_lexer_functions_begin()[builtin_lexer_functions_number]=std::pair(s,gen(u)); +#else + builtin_lexer_functions_begin()[builtin_lexer_functions_number].first=s; + builtin_lexer_functions_begin()[builtin_lexer_functions_number].second.type=0; + builtin_lexer_functions_begin()[builtin_lexer_functions_number].second=gen(u); +#endif + if (parser_token==1) + builtin_lexer_functions_begin()[builtin_lexer_functions_number].second.subtype=T_UNARY_OP-256; + else + builtin_lexer_functions_begin()[builtin_lexer_functions_number].second.subtype=parser_token-256; + builtin_lexer_functions_number++; +#endif + if (debug_infolevel) CERR << "insmod register builtin " << s << '\n'; + } + else { + lexer_functions()[s] = gen(u); + if (parser_token==1) + lexer_functions()[s].subtype=T_UNARY_OP-256; + else + lexer_functions()[s].subtype=parser_token-256; + if (debug_infolevel) CERR << "insmod register lexer_functions " << s << '\n'; + } + // If s is a library function name (with ::), update the library + int ss=int(strlen(s)),j=0; + for (;j >::iterator it=library_functions().find(libname); +#else + std::map >::iterator it=library_functions().find(libname); +#endif + if (it!=library_functions().end()) + it->second.push_back(funcname); + else + library_functions()[libname]=vector(1,funcname); + } + return true; + } + + bool lexer_function_remove(const vector & v){ + vector::const_iterator it=v.begin(),itend=v.end(); + map_charptr_gen::const_iterator i,iend; + bool ok=true; + for (;it!=itend;++it){ + i = lexer_functions().find(it->s.c_str()); + iend=lexer_functions().end(); + if (i==iend) + ok=false; + else + lexer_functions().erase(it->s.c_str()); + } + return ok; + } + +#if defined EMCC || defined EMCC2 || defined SIMU + bool cas_builtin(const char * s,GIAC_CONTEXT){ + std::pair p=std::equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(),std::pair(s,0),tri); + bool res=p.first!=p.second && p.first!=builtin_lexer_functions_end(); + if (res) + return res; + gen g; + int token=find_or_make_symbol(s,g,0,false,contextptr); + if (g.type!=_IDNT) + return false; + gen evaled; + if (!g._IDNTptr->in_eval(1,g,evaled,contextptr,false)) + return false; + //confirm("builtin?",evaled.print(contextptr).c_str()); + return evaled.is_symb_of_sommet(at_program); + return res; + } +#endif + + bool my_isalpha(char c){ + return (c>='a' && c<='z') || (c>='A' && c<='Z'); + } + + int find_or_make_symbol(const string & s,gen & res,void * scanner,bool check38,GIAC_CONTEXT){ + int tmpo=opened_quote(contextptr); + if (tmpo & 2) + check38=false; + if (s.size()==1){ +#ifdef GIAC_HAS_STO_38 + if (0 && s[0]>='a' && s[0]<='z'){ + index_status(contextptr)=1; + res=*tab_one_letter_idnt[s[0]-'a']; + return T_SYMBOL; + } + if (check38 && s[0]>='a' && s[0]<='z' && calc_mode(contextptr)==38) + giac_yyerror(scanner,invalid_name); +#else + if (s[0]>='a' && s[0]<='z'){ + if (check38 && calc_mode(contextptr)==38) + giac_yyerror(scanner,invalid_name); + index_status(contextptr)=1; + res=*tab_one_letter_idnt[s[0]-'a']; + return T_SYMBOL; + } +#endif + switch (s[0]){ + case '+': + res=at_plus; + return T_UNARY_OP; + case '-': + res=at_neg; + return T_UNARY_OP; + case '*': + res=at_prod; + return T_UNARY_OP; + case '/': + res=at_division; + return T_UNARY_OP; + case '^': + res=at_pow; + return T_UNARY_OP; + } + } + string ts(s); +#ifdef USTL + ustl::map::const_iterator trans=lexer_localization_map().find(ts); + if (trans!=lexer_localization_map().end()) + ts=trans->second; + ustl::map >::const_iterator j=lexer_translator().find(ts); + if (j!=lexer_translator().end() && !j->second.empty()) + ts=j->second.back(); + ustl::pair p=ustl::equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(),std::pair(ts.c_str(),0),tri); +#else + std::map::const_iterator trans=lexer_localization_map().find(ts); + if (trans!=lexer_localization_map().end()) + ts=trans->second; + std::map >::const_iterator j=lexer_translator().find(ts); + if (j!=lexer_translator().end() && !j->second.empty()) + ts=j->second.back(); + std::pair p=equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(),std::pair(ts.c_str(),0),tri); +#endif + if (p.first!=p.second && p.first!=builtin_lexer_functions_end()){ + if (p.first->second.subtype==T_TO-256) + res=plus_one; + else + res = p.first->second; + res.subtype=1; + if (builtin_lexer_functions_){ +#ifdef NSPIRE + res=gen(int((*builtin_lexer_functions_())[p.first-builtin_lexer_functions_begin()]+p.first->second.val)); + res=gen(*res._FUNCptr); +#else +#if !defined NSPIRE_NEWLIB || defined KHICAS + res=0; + int pos=int(p.first-builtin_lexer_functions_begin()); +#if defined KHICAS && !defined SDL_KHICAS && !defined x86_64 && !defined __ARM_ARCH_ISA_A64 && !defined __MINGW_H + const unary_function_ptr * at_val=*builtin_lexer_functions_[pos]; +#else + size_t val=builtin_lexer_functions_[pos]; + unary_function_ptr * at_val=(unary_function_ptr *)val; +#endif + res=at_val; +#if defined GIAC_HAS_STO_38 || (defined KHICAS && defined DEVICE) + if (builtin_lexer_functions[pos]._FUNC_%2){ +#ifdef SMARTPTR64 + unary_function_ptr tmp=*at_val; + tmp._ptr+=1; + res=tmp; +#else + res._FUNC_ +=1; +#endif // SMARTPTR64 + } +#endif // GIAC_HAS_STO_38 +#else // keep this code, required for the nspire otherwise evalf(pi)=reboot + res=gen(int(builtin_lexer_functions_[p.first-builtin_lexer_functions_begin()]+p.first->second.val)); + res=gen(*res._FUNCptr); +#endif +#endif + } + index_status(contextptr)=(p.first->second.subtype==T_UNARY_OP-256); + int token=p.first->second.subtype; + token += (token<0)?512:256 ; + return token; + } + lexer_tab_int_type tst={ts.c_str(),0,0,0,0}; +#ifdef USTL + ustl::pair pp = ustl::equal_range(lexer_tab_int_values,lexer_tab_int_values_end,tst,tri1); +#else + std::pair pp = equal_range(lexer_tab_int_values,lexer_tab_int_values_end,tst,tri1); +#endif + if (pp.first!=pp.second && pp.first!=lexer_tab_int_values_end){ + index_status(contextptr)=pp.first->status; + res=int(pp.first->value); + res.subtype=pp.first->subtype; + return pp.first->return_value; + } + // CERR << "lexer_functions search " << ts << '\n'; + map_charptr_gen::const_iterator i = lexer_functions().find(ts.c_str()); + if (i!=lexer_functions().end()){ + // CERR << "lexer_functions found " << ts << '\n'; + if (i->second.subtype==T_TO-256) + res=plus_one; + else + res = i->second; + res.subtype=1; + index_status(contextptr)=(i->second.subtype==T_UNARY_OP-256); + return i->second.subtype+256 ; + } + lock_syms_mutex(); + sym_string_tab::const_iterator i2 = syms().find(s),i2end=syms().end(); + if (i2 == i2end) { + unlock_syms_mutex(); + const char * S = s.c_str(); + // std::CERR << "lexer new" << s << '\n'; + if (check38 && calc_mode(contextptr)==38 && strcmp(S,string_pi) && strcmp(S,string_euler_gamma) && strcmp(S,string_infinity) && strcmp(S,string_undef) && S[0]!='G'&& (!is_known_name_38 || !is_known_name_38(0,S))){ + // detect invalid names and implicit multiplication + size_t ss=strlen(S); + vecteur args; + for (size_t i=0;i='E' && ch<='H') || ch=='L' || ch=='M' || ch=='R' + /* || ch=='S' */ + || ch=='U' || ch=='V' || (ch>='X' && ch<='Z') ){ + string name; + name += ch; + char c=0; + if (i='0' && c<='9'){ + name += c; + ++i; + } + res = identificateur(name); + lock_syms_mutex(); + syms()[name] = res; + unlock_syms_mutex(); + args.push_back(res); + } + else { + string coeff; + for (++i;i32 && my_isalpha(s[i])){ + --i; + break; + } + if (scanner && (s[i]<0 || s[i]>'z')){ + giac_yyerror(scanner,invalid_name); + res=undef; + return T_SYMBOL; + } + coeff += s[i]; + } + if (coeff.empty()) + res=1; + else + res=strtod(coeff.c_str(),0); + if (ch=='i') + res=res*cst_i; + else { + if (ch=='e') + res=std::exp(1.0)*res; + else { + // Invalid ident name, report error + if ( (ch>'Z' || ch<0) && scanner){ + giac_yyerror(scanner,invalid_name); + res=undef; + return T_SYMBOL; + } + coeff=string(1,ch); + gen tmp = identificateur(coeff); + // syms()[coeff.c_str()]=tmp; + res=res*tmp; + } + } + args.push_back(res); + } + } + if (args.size()==1) + res=args.front(); + else + res=_prod(args,contextptr); + lock_syms_mutex(); + syms()[s]=res; + unlock_syms_mutex(); + return T_SYMBOL; + } // end 38 compatibility mode + res = identificateur(s); + lock_syms_mutex(); + syms()[s] = res; + unlock_syms_mutex(); + return T_SYMBOL; + } // end if ==syms.end() + res = i2->second; + unlock_syms_mutex(); + return T_SYMBOL; + } + + // Add to the list of predefined symbols + void set_lexer_symbols(const vecteur & l,GIAC_CONTEXT){ + if (initialisation_done(contextptr)) + return; + initialisation_done(contextptr)=true; + const_iterateur it=l.begin(),itend=l.end(); + for (; it!=itend; ++it) { + if (it->type!=_IDNT) + continue; + lock_syms_mutex(); + sym_string_tab::const_iterator i = syms().find(it->_IDNTptr->id_name),iend=syms().end(); + if (i==iend) + syms()[it->_IDNTptr->name()] = *it; + unlock_syms_mutex(); + } + } + + string replace(const string & s,char c1,char c2){ + string res; + int l=s.size(); + res.reserve(l); + const char * ch=s.c_str(); + for (int i=0;i=int(res.size())) + break; + int pos2=res.find(pattern,pos1+3); + if (pos2<0 || pos2+3>=int(res.size())) + break; + if (rep) + res=res.substr(0,pos1)+'"'+replace(res.substr(pos1+3,pos2-pos1-3),'\n',' ')+'"'+res.substr(pos2+3,res.size()-pos2-3); + else + res=res.substr(0,pos1)+res.substr(pos2+3,res.size()-pos2-3); + } + return res; + } + + struct int_string { + int decal; + std::string endbloc; + int_string():decal(0){} + int_string(int i,string s):decal(i),endbloc(s){} + }; + + static bool instruction_at(const string & s,int pos,int shift){ + if (pos && isalphan(s[pos-1])) + return false; + if (pos+shift=0 && posif1) + cur[pos]='%'; + } + } + + string glue_lines_backslash(const string & s){ + int ss=s.size(); + int i=s.find('\\'); + if (i<0 || i>=ss) + return s; + string res,line; + for (i=0;i=0;--j){ + if (line[j]!=' ') + break; + } + if (line[j]!='\\' || (j && line[j-1]=='\\')){ + res += line+'\n'; + line =""; + } + else + line=line.substr(0,j); + } + return res+line; + } + + static void python_import(string & cur,int cs,int posturtle,int poscmath,int posmath,int posnumpy,int posmatplotlib,GIAC_CONTEXT){ + if (posmatplotlib>=0 && posmatplotlib=0 && posnumpy=0 && posturtle=0 && poscmath=0 && posmath + // int is the number of white spaces at the start of the next line + // def ... : -> function [ffunction] + // for ... : -> for ... do [od] + // while ... : -> while ... do [od] + // if ...: -> if ... then [fi] + // else: -> else [nothing in stack] + // elif ...: -> elif ... then [nothing in stack] + // try: ... except: ... + std::string python2xcas(const std::string & s_orig,GIAC_CONTEXT){ + if (strncmp(s_orig.c_str(),"spreadsheet[",12)==0) + return s_orig; + if (strncmp(s_orig.c_str(),"function",8)==0 || strncmp(s_orig.c_str(),"fonction",8)==0){ + python_compat(contextptr)=0; + return s_orig; + } + if (xcas_mode(contextptr)>0 && abs_calc_mode(contextptr)!=38) + return s_orig; + if (abs_calc_mode(contextptr)==38){ + if (s_orig.substr(0,4)=="#cas"){ + int pos=s_orig.find("#end"); + if (pos>0 && pos=0 && first=0 && first=sss){ + first=s_orig.find('\''); // derivative or Python string delimiter? + if (first>=0 && first=sss) + return s_orig; + } + } + bool pythoncompat=python_compat(contextptr); + bool pythonmode=false; + first=0; + if (sss>19 && s_orig.substr(first,17)=="add_autosimplify(") + first+=17; + if (s_orig[first]=='/' ) + return s_orig; + //if (sss>first+2 && s_orig[first]=='@' && s_orig[first+1]!='@') return s_orig.substr(first+1,sss-first-1); + if (sss>first+2 && s_orig.substr(first,2)=="@@"){ + pythonmode=true; + pythoncompat=true; + } + if (s_orig[first]=='#' || (s_orig[first]=='_' && !my_isalpha(s_orig[first+1])) || s_orig.substr(first,4)=="from" || s_orig.substr(first,7)=="import " || s_orig.substr(first,4)=="def "){ + pythonmode=true; + pythoncompat=true; + } + if (pythoncompat){ + int pos=s_orig.find("{"); + if (pos>=0 && pos=0 && pos=0 && pos=0 && pos=0 && pos=0 && pos=0 && pos=0 && pos=sss){ + first=s_orig.find(':',first); + if (first<0 || first>=sss){ + return s_orig; // not Python like + } + } + pos=s_orig.find("lambda"); + if (pos>=0 && pos=sss) + endl=sss; + ++first; + if (first18 && res.substr(0,17)=="add_autosimplify(" + && res[res.size()-1]==')' + ) + res=res.substr(17,res.size()-18); + if (res.size()>2 && res.substr(0,2)=="@@") + res=res.substr(2,res.size()-2); + res=remove_comment(res,"\"\"\"",true); + res=remove_comment(res,"'''",true); + res=glue_lines_backslash(res); + first=res.find('\t'); + if (first>=0 && first stack; + string s,cur; + s.reserve(res.capacity()); + if (pythoncompat) pythonmode=true; + for (;res.size();){ + int pos=-1; + bool cherche=true; + for (;cherche;){ + pos=res.find('\n',pos+1); + if (pos<0 || pos>=int(res.size())) + break; + cherche=false; + char ch=0; + // check if we should skip to next newline, look at previous non space + for (int pos2=0;pos2=0;--pos2){ + ch=res[pos2]; + if (ch!=' ' && ch!=9 && ch!='\r'){ + if (ch=='{' || ch=='[' || ch==',' || ch=='-' || ch=='+' || ch=='/'){ + if (pos2>0 && (ch=='+' || ch=='-') && ch==res[pos2-1]) + ; + else + cherche=true; + } + break; + } + } + for (size_t pos2=pos+1;pos2=int(res.size())){ + cur=res; res=""; + } + else { + cur=res.substr(0,pos); // without \n + res=res.substr(pos+1,res.size()-pos-1); + } + // detect comment (outside of a string) and lambda expr:expr + bool instring=false,chkfrom=true; + for (pos=0;pos0 && p'9') + str=true; + if (p-q>=minchar_for_quote_as_string(contextptr)) + str=true; + for (;!str && qpos+8 && (cur.substr(pos,8)=="# local " || cur.substr(pos,7)=="#local ")){ + cur.erase(cur.begin()+pos); + if (cur[pos]==' ') + cur.erase(cur.begin()+pos); + } + else + cur=cur.substr(0,pos); + pythonmode=true; + break; + } + // skip from * import * + if (chkfrom && ch=='f' && pos+15=int(cur.size())) + posi = cur.find(" import*"); + if (posi>pos+5 && posi=cur.size()) + posmatplotlib=cur.find("pylab"); + int cs=int(cur.size()); + pythonmode=true; +#if defined KHICAS || defined SDL_KHICAS + if ( + (posturtle<0 || posturtle>=cs) && + (poscmath<0 || poscmath>=cs) && + (posmath<0 || posmath>=cs) && + (posnumpy<0 || posnumpy>=cs) && + (posmatplotlib<0 || posmatplotlib>=cs) + ){ + string filename=cur.substr(pos+5,posi-pos-5)+".py"; + // CERR << "import " << filename << endl; + const char * ptr=read_file(filename.c_str()); + if (ptr) + s += python2xcas(ptr,contextptr); // recursive call + cur =""; + // CERR << s << endl; + continue; + } + else +#endif + { + cur=cur.substr(0,pos); + python_import(cur,cs,posturtle,poscmath,posmath,posnumpy,posmatplotlib,contextptr); + } + break; + } + } + chkfrom=false; + // import * as ** -> **:=* + if (ch=='i' && pos+7=cur.size()) + posmatplotlib=cur.find("pylab"); + int cs=int(cur.size()); + int posi=cur.find(" as "); + int posp=cur.find('.'); + if (posp>=posi || posp<0) + posp=posi; + if (posi>pos+5 && posipos+7 && posdot"+cur.substr(posdot+1,cur.size()-posdot-1); + } + } + if (ch=='e' && pos+4=0;--pos){ + if (cur[pos]!=' ' && cur[pos]!=char(9) && cur[pos]!='\r') + break; + } + if (pos<0){ + s+='\n'; + continue; + } + if (cur[pos]!=':'){ // detect oneliner and function/fonction + int p; + for (p=0;p0;--p){ + if (instr){ + if (cur[p]=='"' && cur[p-1]!='\\') + instr=false; + continue; + } + if (cur[p]==':' && (cur[p+1]!=';' && cur[p+1]!='=')) + break; + if (cur[p]=='"' && cur[p-1]!='\\') + instr=true; + } + if (p==0){ + // = or return expr if cond else alt_expr => ifte(cond,expr,alt_expr) + int cs=int(cur.size()); + int elsepos=cur.find("else"); + if (elsepos>0 && elsepos0 && ifpos=cs){ + retpos=cur.find("="); + endretpos=retpos+1; + } + if (retpos>=0 && retpos0){ + int cs=int(cur.size()),q=4; + int progpos=cur.find("elif");; + if (progpos<0 || progpos>=cs){ + progpos=cur.find("if"); + q=2; + } + if (p>progpos && progpos>=0 && progposprogpos && progpos>=0 && progposprogpos && progpos>=0 && progposprogpos && progpos>=0 && progposprogpos && progpos>=0 && progpos=0 && progpos1){ + int indent=stack[stack.size()-1].decal; + if (ws1 && stack[stack.size()-1].decal>ws){ + s += ' '+stack.back().endbloc+';'; + stack.pop_back(); + } + if (nl) + s += '\n'; + } + } + s += cur.substr(0,pos)+"\n"; + continue; + } + progpos=cur.find("except"); + if (progpos>=0 && progpos1){ + int indent=stack[stack.size()-1].decal; + if (ws1 && stack[stack.size()-1].decal>ws){ + s += ' '+stack.back().endbloc+';'; + stack.pop_back(); + } + if (nl) + s += '\n'; + } + } + s += cur.substr(0,progpos)+"then\n"; + continue; + } + progpos=cur.find("elif"); + if (progpos>=0 && progpos1){ + int indent=stack[stack.size()-1].decal; + if (ws1 && stack[stack.size()-1].decal>ws){ + s += ' '+stack.back().endbloc+';'; + stack.pop_back(); + } + if (nl) + s += '\n'; + } + } + cur=cur.substr(0,pos); + convert_python(cur,contextptr); + s += cur+" then\n"; + continue; + } + } + if (!stack.empty()){ + int indent=stack.back().decal; + if (ws<=indent){ + // remove last \n and add explicit endbloc delimiters from stack + int ss=s.size(); + bool nl= ss && s[ss-1]=='\n'; + if (nl) + s=s.substr(0,ss-1); + while (!stack.empty() && stack.back().decal>=ws){ + int sb=stack.back().decal; + s += ' '+stack.back().endbloc+';'; + stack.pop_back(); + // indent must match one of the saved indent + if (sb!=ws && !stack.empty() && stack.back().decal=0 && progpos=0 && progpos=0 && progpos for x_ + cur=cur.substr(0,pos); + if (progpos+5=0 && progpos=0 && progpos ... and : + string entete=cur.substr(progpos+3,pos-progpos-3); + int posfleche=entete.find("->"); + if (posfleche>0 || posfleche=0 && curpos!=';' && curpos!=',' && curpos!='{' && curpos!='(' && curpos!='[' && curpos!=':' && curpos!='+' && curpos!='-' && curpos!='*' && curpos!='/' && curpos!='%') + cur = cur +';'; + if (pythonmode) + convert_python(cur,contextptr); + cur = cur +'\n'; + s = s+cur; + } + } + while (!stack.empty()){ + s += ' '+stack.back().endbloc+';'; + stack.pop_back(); + } + if (pythonmode){ + char ch; + while (s.size()>1 && + ( ((ch=s[s.size()-1])==';' && s[s.size()-2]!=':') || (ch=='\n')) + ) + s=s.substr(0,s.size()-1); + // replace ;) by ) + for (int i=s.size()-1;i>=2;--i){ + if (s[i]==')' && s[i-1]=='\n' && s[i-2]==';'){ + s.erase(s.begin()+i-2); + break; + } + } + if (s.size()>10 && s.substr(s.size()-9,9)=="ffunction") + s += ":;"; + else { + int pos=s.find('\n'); + if (pos>=0 && pos * builtin_lexer_functions_(){ + static vector * res=0; + if (res) return res; + res = new vector; + res->reserve(builtin_lexer_functions_number+1); +#include "static_lexer_at.h" + return res; + } +#else + // Array added because GH compiler stores builtin_lexer_functions in RAM +#if defined KHICAS || defined NSPIRE_NEWLIB + const unary_function_ptr * const * const builtin_lexer_functions_[]={ +#include "static_lexer__numworks.h" + }; +#else + const size_t builtin_lexer_functions_[]={ +#if defined(GIAC_HAS_STO_38) && defined(CAS38_DISABLED) +#include "static_lexer_38_.h" +#else +#include "static_lexer_.h" +#endif + }; +#endif // KHICAS +#endif // STATIC_BUILTIN + +#ifdef SMARTPTR64 + charptr_gen * builtin_lexer_functions64(){ + static charptr_gen * ans=0; + if (!ans){ + ans = new charptr_gen[builtin_lexer_functions_number]; + for (unsigned i=0;i> 16); +#endif + } +#endif + delete ®istered_lexer_functions(); + delete &lexer_functions(); + delete &library_functions(); + delete &lexer_translator(); + delete &back_lexer_localization_map(); + delete &lexer_localization_map(); + delete &lexer_localization_vector(); + delete &syms(); + delete &unit_conversion_map(); + delete &xcasrc(); + //delete &usual_units(); + if (vector_aide_ptr()) delete vector_aide_ptr(); + delete &symbolic_rootof_list(); + delete &proot_list(); + delete &galoisconj_list(); + delete &_autoname_(); + delete &_lastprog_name_(); + return 0; + } + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC \ No newline at end of file diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/help.cc b/android/app/src/main/cpp/giac/src/giac/cpp/help.cc new file mode 100644 index 0000000..d2b6cc1 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/help.cc @@ -0,0 +1,2024 @@ +// -*- mode:C++ ; compile-command: "g++ -I.. -g -c help.cc -Wall" -*- +//#define _SCL_SECURE_NO_WARNINGS +#include "giacPCH.h" + +#include "path.h" +/* + * Copyright (C) 2000,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using namespace std; +#include +#include "gen.h" +#include "help.h" +#include +#if !defined GIAC_HAS_STO_38 && !defined NSPIRE && !defined FXCG +#include +#endif +#include "global.h" +#ifdef HAVE_UNISTD_H +#include +#endif + +#if defined MICROPY_LIB || defined HAVE_LIBMICROPYTHON +extern "C" int mp_token(const char * line); +#endif + +#if defined KHICAS || defined SDL_KHICAS +#include "kdisplay.h" // for select_item, +#if defined MICROPY_LIB || defined HAVE_LIBMICROPYTHON +extern "C" int xcas_python_eval; +#endif +#endif + +#if defined VISUALC || defined BESTA_OS + + +#define opendir FindFirstFile +#define readdir FindNextFile +#define closedir FindClose +#define DIR WIN32_FIND_DATA +#define GNUWINCE 1 + +#else // VISUALC or BESTA_OS + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#if !defined BESTA_OS && !defined NSPIRE && !defined FXCG && !defined KHICAS // test should always return true +#include +#endif + +#endif // VISUALC or BESTA_OS + +#include "input_lexer.h" + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + const int HELP_LANGUAGES=5; + + struct static_help_t { + const char * cmd_name; + const char * cmd_howto[HELP_LANGUAGES]; + const char * cmd_syntax; + const char * cmd_related; + const char * cmd_examples; + }; + + const static_help_t static_help[]={ +#if defined NSPIRE_NEWLIB || (defined NUMWORKS && !defined NUMWORKS_SLOTB ) || ( !defined(KHICAS) && !defined POCKETCAS) +#include "static_help.h" +#else + { "", { "", "", "", "",""}, "", "", "" }, +#endif + }; + + const int static_help_size=sizeof(static_help)/sizeof(static_help_t); + + struct static_help_sort { + static_help_sort() {} + inline bool operator () (const static_help_t & a ,const static_help_t & b){ + return strcmp(a.cmd_name, b.cmd_name) < 0; + } + }; + + inline int mon_max(int a,int b){ + if (a>b) + return a; + else + return b; + } + + bool seconddec (const pair & a,const pair & b){ + return a.second>b.second; + } + + const char * python_keywords[] = { // List of known giac keywords... + "False", + "None", + "True", + "and", + "break", + "continue", + "def", + "default", + "elif", + "else", + "except", + "for", + "from", + "global", + "if", + "import", + "not", + "or", + "return", + "try", + "while", + "xor", + "yield", + }; + const char * const python_builtins[]={ + "NoneType", + "__call__", + "__class__", + "__delitem__", + "__dir__", + "__enter__", + "__exit__", + "__getattr__", + "__getitem__", + "__hash__", + "__init__", + "__int__", + "__iter__", + "__len__", + "__main__", + "__module__", + "__name__", + "__new__", + "__next__", + "__qualname__", + "__repr__", + "__setitem__", + "__str__", + "abs", + "all", + "any", + "append", + "args", + "bool", + "builtins", + "bytearray", + "bytecode", + "bytes", + "callable", + "chr", + "classmethod", + "clear", + "close", + "const", + "copy", + "count", + "dict", + "dir", + "divmod", + "end", + "endswith", + "eval", + "exec", + "extend", + "find", + "format", + "from_bytes", + "get", + "getattr", + "globals", + "hasattr", + "hash", + "id", + "index", + "insert", + "int", + "isalpha", + "isdigit", + "isinstance", + "islower", + "isspace", + "issubclass", + "isupper", + "items", + "iter", + "join", + "key", + "keys", + "len", + "list", + "little", + "locals", + "lower", + "lstrip", + "main", + "map", + "micropython", + "next", + "object", + "open", + "ord", + "pop", + "popitem", + "pow", + "print", + "range", + "read", + "readinto", + "readline", + "remove", + "replace", + "repr", + "reverse", + "rfind", + "rindex", + "round", + "rsplit", + "rstrip", + "self", + "send", + "sep", + "set", + "setattr", + "setdefault", + "sort", + "sorted", + "split", + "start", + "startswith", + "staticmethod", + "step", + "stop", + "str", + "strip", + "sum", + "super", + "throw", + "to_bytes", + "tuple", + "type", + "update", + "upper", + "utf-8", + "value", + "values", + "write", + "xcas", + "zip", + }; + + bool is_python_keyword(const char * s){ + return dichotomic_search(python_keywords,sizeof(python_keywords)/sizeof(char*),s)!=-1; + } + + bool is_python_builtin(const char * s){ + return dichotomic_search(python_builtins,sizeof(python_builtins)/sizeof(char*),s)!=-1; + } + const char *js_keywords[]={ + "Infinity", + "NaN", + "break", + "case", + "catch", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "export", + "extends", + "false", + "finally", + "for", + "function", + "if", + "import", + "in", + "instanceof", + "let", + "module", + "new", + "null", + "return", + "super", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "undefined", + "var", + "while", + "with", + "yield", + }; + bool is_js_keyword(const char * s){ + return dichotomic_search(js_keywords,sizeof(js_keywords)/sizeof(char*),s)!=-1; + } + + + // NB: cmd_name may be localized but related is not localized + bool has_static_help(const char * & cmd_name,int lang,const char * & howto,const char * & syntax,const char * & related,const char * & examples){ +#ifdef GIAC_HAS_STO_38 + const char nullstring[]=" "; +#else + const char nullstring[]=""; +#endif + bool tooltip=lang & 0x100; + if (tooltip) + lang=lang & 0xff; + if (lang<=0) + lang=2; + if (lang>HELP_LANGUAGES) + lang=2; + string s=unlocalize(cmd_name); + int l=int(s.size()); + if (l==0) return false; + if ( (l>2) && (s[0]=='\'') && (s[l-1]=='\'') ) + s=s.substr(1,l-2); +#if defined KHICAS || defined SDL_KHICAS + static string res; + int pos=0,kk,ks=s.size(); + for (;pos=0) + break; + } + const char * items[1+static_help_size]; + kk=0; +#ifdef MICROPY_LIB + if (xcas_python_eval && !python_heap){ + python_init(pythonjs_stack_size,pythonjs_heap_size); + } +#endif + for (;pos0){ + if (!is_python_builtin(ptr) && mp_token(ptr)==0){ + --kk; + continue; + } + } +#endif + if (strcmp(ptr,s.c_str())==0){ + howto=sh.cmd_howto[lang-1]; + if (!howto) + howto=sh.cmd_howto[1]; + syntax=sh.cmd_syntax; + if (!syntax) + syntax=nullstring; + related=sh.cmd_related; + if (!related) + related=nullstring; + examples=sh.cmd_examples; + if (!examples) + examples=nullstring; + return true; + } + if (strlen(ptr)1){ + res=""; + for (int i=0;i p=equal_range(static_help,static_help+static_help_size,h,static_help_sort()); + if (p.first!=p.second && p.first!=static_help+static_help_size){ + howto=p.first->cmd_howto[lang-1]; + if (!howto) + howto=p.first->cmd_howto[1]; + syntax=p.first->cmd_syntax; + if (!syntax) + syntax=nullstring; + related=p.first->cmd_related; + if (!related) + related=nullstring; + examples=p.first->cmd_examples; + if (!examples) + examples=nullstring; + return true; + } +#if (defined EMCC || defined EMCC2) && !defined SDL_KHICAS + // Find closest string + syntax=nullstring; + related=nullstring; + static string res; + res=""; + int best_score=0,cur_score; + vector< pair > best_j; + for (int j=0;jbest_score){ + best_score=cur_score; + vector< pair > tmp; + for (unsigned k=0;k=best_score-6) + tmp.push_back(best_j[k]); + } + best_j=tmp; + best_j.push_back(pair(j,cur_score)); + continue; + } + if (cur_score>=mon_max(best_score-6,0)){ + best_j.push_back(pair(j,cur_score)); + } + } + if (best_score>0){ + sort(best_j.begin(),best_j.end(),seconddec); + vector< pair >::iterator it=best_j.begin(),itend=best_j.end(); + for (int k=1;(k<10) && (it!=itend);++k,++it){ + res = res+static_help[it->first].cmd_name; + res = res+","; + } + if (!res.empty()) + res=res.substr(0,res.size()-1); + } + static string syn; + syn = gettext("Best match has score ") + printint(best_score) + "\n"; + howto = syn.c_str(); + examples = res.c_str(); + return true; +#else + return false; +#endif + } + + static std::string output_quote(const string s){ + string res; + int ss=int(s.size()); + for (int i=0;i longhelp.js or longhelp_en.js: html_mtt + // replace string \244 with : + // macro replace /usr/share/giac/doc/en/cascmd_en/ with ' and #... with ' + // longhelp*.js should begin with var longhelp = { + // and end with }; + static bool output_static_help(vector & v,const vector & langv){ +#if !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 + add_language(5,context0); // add german help de/aide_cas + cout << "Generating xcascmds, for UI.xcascmds in xcas.js, sort and esc-x replace-string ctrl-Q ctrl-j ret ret" << endl; + cout << "Copy in python.js. For xcasmod.js, replace \",\" by | " << endl; + cout << "Generating static_help.h (sort it in emacs)" << endl; + cout << "Generating static_help_w.h (same but UTF16)" << endl; + ofstream cmds("xcascmds"); + cmds << "[" << endl; + ofstream of("static_help.h"); + vector::iterator it=v.begin(),itend=v.end(); + for (;it!=itend;){ + cmds << '"' << output_quote(it->cmd_name) << '"' << "," << endl; + of << "{"; + of << '"' << output_quote(it->cmd_name) << '"' << ","; + std::vector & blabla = it->blabla; + sort(blabla.begin(),blabla.end()); + int blablapos=0; + of << "{"; + for (int i=0;isyntax) << '"' << ',' ; + std::vector & examples = it->examples; + int bs=int(examples.size()); + if (bs){ + of << '"'; + for (int i=0;i & related = it->related; + bs=int(related.size()); + if (bs){ + of << '"'; + for (int i=0;icmd_name; + ofw << 'L' << '"' << output_quote(cmd) << '"' << ","; + if (cmd.size()>16) + cmd=cmd.substr(0,16); + ofwindex << "{NULL,NULL, " << 'L' << '"' << output_quote(cmd) << '"' << ", HIDVoid }" ; + std::vector & blabla = it->blabla; + sort(blabla.begin(),blabla.end()); + int bs=int(blabla.size()); + ofw << "{"; + for (int i=0;icmd_name) << '(' << output_quote(it->syntax) << ')' << '"' << ',' ; + std::vector & examples = it->examples; + bs=int(examples.size()); + if (bs>=1){ + ofw << 'L' << '"'; + ofw << output_quote(examples[0]) ; + ofw << '"' << ','; + if (bs>=2){ + ofw << 'L' << '"'; + ofw << output_quote(examples[1]) ; + ofw << '"' << ','; + } + else + ofw << 0 << ","; + } + else + ofw << 0 << "," << 0 << ","; + std::vector & related = it->related; + bs=int(related.size()); + if (bs>=1){ + ofw << 'L' << '"'; + ofw << output_quote(related[0].chaine) ; + ofw << '"' << ','; + if (bs>=2){ + ofw << 'L' << '"'; + ofw << output_quote(related[1].chaine) ; + ofw << '"' << ','; + } + else + ofw << 0 << ","; + } + else + ofw << 0 << "," << 0 << ","; + ofw << "}"; + ++it; + if (it==itend) + break; + ofw << "," << endl; + ofwindex << "," << endl; + } + ofw << endl; + ofwindex << "};" << endl; +#endif + return true; + } + +#if !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 && !defined KHICAS && !defined SDL_KHICAS + static bool output_ia_mcptools(vector & v,const vecteur & listcmd,int lang){ + ofstream tools("tools.py"); + tools << " async def _handle_tools_list(self, request_id: str) -> Dict[str, Any]:\n"; + tools << " \"\"\"Liste des outils disponibles\"\"\"\n"; + tools << " tools = [\n"; + vector::iterator it=v.begin(),itend=v.end(); + for (;it!=itend;){ + gen cmd(it->cmd_name,context0); + if (!equalposcomp(listcmd,cmd)){ + ++it; + continue; + } + tools << " {\n"; + tools << " \"name\": \"" << output_quote(it->cmd_name) << "\",\n"; + std::vector & blabla = it->blabla; + sort(blabla.begin(),blabla.end()); + int blablapos=0; + tools << " \"description\": \"" << output_quote(blabla[lang].chaine) << "\",\n"; + tools << " \"inputSchema\": {\n"; + tools << " \"type\": \"object\",\n"; + // parse syntax + gen G; + try { + G=gen(it->syntax,context0); + } catch (std::runtime_error & err){ + G=gen("Expr",context0); + } + vecteur v(gen2vecteur(G)); + tools << " \"properties\": {\n"; + string req; + for (int i=0;i-1;--length,i/=10) + s[length]=i%10+'0'; +#if defined VISUALC || defined BESTA_OS + string res=s; + delete [] s; + return res; +#else + return s; +#endif + } +#endif + + inline int max(int a,int b,int c){ + if (a>=b){ + if (a>=c) + return a; + else + return c; + } + if (b>=c) + return b; + else + return c; + } + + int score(const string & s,const string & t){ + int ls=int(s.size()),lt=int(t.size()); + if (!ls) return -1; + vector cur_l, new_l(lt+1,0); + for (int j=0;j<=lt;++j) + cur_l.push_back(-j); + vector::iterator newbeg=new_l.begin(),newend=new_l.end(),newit=newbeg; + vector::iterator curbeg=cur_l.begin(),curit;//curend=cur_l.end(), + for (int i=0;i & current_synonymes){ + current_synonymes.clear(); + // parse curren_aide.cmd_name for synonyms + string s=cmd_name,s1; + int i; + for (;;){ + // cout << s << endl; + i=int(s.find(' ')); + if (i<=0){ + if (!s.empty()) + current_synonymes.push_back(localized_string(0,s)); + break; + } + s1=s.substr(0,i); + current_synonymes.push_back(localized_string(0,s1)); + /* add also keyword translations of s1 + multimap::iterator it=back_lexer_localization_map().find(s1),backend=back_lexer_localization_map().end(),itend=back_lexer_localization_map().upper_bound(s1); + if (it!=backend){ + for (;it!=itend;++it){ + current_synonymes.push_back(it->second); + } + } + */ + s=s.substr(i+1,s.size()-i-1); + } // end for (;;) + } + + + vector readhelp(const char * f_name,int & count,bool warn){ + vector v(1); + readhelp(v,f_name,count,warn); + return v; + } + // FIXME: aide_cas may end with synonyms (# cmd synonym1 ...) + void readhelp(vector & v,const char * f_name,int & count,bool warn){ + count=0; +#if !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 && !defined KHICAS && !defined SDL_KHICAS + if (access(f_name,R_OK)){ + if (warn) + std::cerr << "Help file " << f_name << " not found" << endl; + return ; + } + // v.reserve(1600); + ifstream f(f_name); + char fs[HELP_MAXLENSIZE+1]; + vector current_blabla; + vector current_related; + vector current_examples; + aide current_aide; + vector vposition; + int vpositions; + string current_line; + vector current_synonymes; + while (f){ + f.getline(fs,HELP_MAXLENSIZE,'\n'); + if (!fs[0]) + continue; + current_line=fs; + if (fs[0]=='#'){ + current_aide.blabla=current_blabla; + current_aide.examples=current_examples; + current_aide.related=current_related; + if (!current_aide.cmd_name.empty()){ + find_synonymes(current_aide.cmd_name,current_synonymes); + current_aide.synonymes=current_synonymes; + vector::const_iterator it=current_synonymes.begin(),itend=current_synonymes.end(); + vpositions=int(vposition.size()); + for (int pos=0;it!=itend;++it,++pos){ + current_aide.cmd_name=it->chaine; + if (pos2?current_line.substr(2,current_line.size()-2):""; + // search if cmd_name is already present in v + // if so set vposition, current_blabla/examples/related accordingly + find_synonymes(current_aide.cmd_name,current_synonymes); + vector::const_iterator itbeg=current_synonymes.begin(),itend=current_synonymes.end(),it; + vector::iterator itpos; + for (it=itbeg;it!=itend;++it){ + itpos=lower_bound(v.begin(),v.end(),current_aide,alpha_order); + if (itpos!=v.end()){ + // --itpos; + if (itpos->cmd_name==it->chaine){ // already documented + current_synonymes=itpos->synonymes; + current_blabla=itpos->blabla; + current_examples=itpos->examples; + current_related=itpos->related; + vposition.push_back(int(itpos-v.begin())); + } + } + } + continue; + } + // look for space + int l=int(current_line.find_first_of(' ')); + if ( (l==1) && (current_line[0]=='0') ){ + int cs=int(current_line.size()); + while (l'9')){ + n=0; + break; + } + else + n=10*n+(current_line[i]-int('0')); + } + if (!positif) + n=-n; + if (n>0) + current_blabla.push_back(localized_string(n,current_line.substr(l+1,current_line.size()-l))); + else { + if (n<0) + current_related.push_back(indexed_string(-n,current_line.substr(l+1,current_line.size()-l))); + else + current_examples.push_back(current_line); + } + } // end reading help from file + if (!current_aide.cmd_name.empty()){ + current_aide.synonymes=vector(1,localized_string(0,current_aide.cmd_name)); + current_aide.blabla=current_blabla; + current_aide.examples=current_examples; + current_aide.related=current_related; + v.push_back(current_aide); + count++; + } + sort(v.begin(),v.end(),alpha_order); + if (debug_infolevel==-2){ + vector langv; + langv.push_back(1); + langv.push_back(2); + langv.push_back(3); + langv.push_back(4); + langv.push_back(5); + output_static_help(v,langv); + } + if (debug_infolevel==-3 || debug_infolevel==-4){ + vecteur cmd=makevecteur(at_eval,at_subst,at_integrate,at_derive,at_solve,at_csolve,at_plot,at_desolve,at_rsolve); + cmd=mergevecteur(cmd,makevecteur(at_simplify,at_normal,at_texpand)); + output_ia_mcptools(v,cmd,-3-debug_infolevel); + } +#endif + } + + static aide add_synonyme_name_to_examples(const aide & a){ + aide res(a); + std::vector::iterator it=res.examples.begin(),itend=res.examples.end(); + for (;it!=itend;++it){ + if (!it->empty() && (*it)[0]==' ') + continue; + // look for a ( + unsigned i=unsigned(it->find('(')); + if (i>0 && isize()){ // check whether the beginning of the string is in synonyms + string cmd=it->substr(0,i); + std::vector::const_iterator jt=res.synonymes.begin(),jtend=res.synonymes.end(); + for (;jt!=jtend;++jt){ + if (jt->chaine==cmd) + break; + } + if (jt!=jtend) // Yes, replace it + *it=res.cmd_name+it->substr(i,it->size()-i); + else + *it=res.cmd_name+'('+*it+')'; + } + else + *it=res.cmd_name+'('+*it+')'; + } + return res; + } + + aide helpon(const string & demande,const vector & v,int language,int count,bool with_op){ + aide result; + string current(demande); + if (with_op) + result.syntax = gettext("No help available for ") +current +"\n"; + else + result.syntax="NULL"; + if (!count){ + return result; + } + for (int i=1;;++i){ + if (i==count){ + if (!with_op) + return result; + // Find closest string + int best_score=0,cur_score; + vector< pair > best_j; + for (int j=1;jbest_score){ + best_score=cur_score; + vector< pair > tmp; + for (unsigned k=0;k=best_score-6) + tmp.push_back(best_j[k]); + } + best_j=tmp; + best_j.push_back(pair(j,cur_score)); + continue; + } + if (cur_score>=mon_max(best_score-6,0)){ + best_j.push_back(pair(j,cur_score)); + } + } + if (best_score>0){ + sort(best_j.begin(),best_j.end(),seconddec); + vector< pair >::iterator it=best_j.begin(),itend=best_j.end(); + for (int k=1;(k<10) && (it!=itend);++k,++it) + result.related.push_back(indexed_string(k,v[it->first].cmd_name)); + } + result.syntax += gettext("Best match has score ") + printint(best_score) + "\n"; + result.cmd_name = current; + return result; + } + if (current==v[i].cmd_name){ + result=v[i]; + if (!with_op) + return add_synonyme_name_to_examples(result); + result.syntax= current + "(" +result.syntax +")\n"; + return add_synonyme_name_to_examples(result); + } + } // end for i + } + + string writehelp(const aide & cur_aide,int language){ + string result=cur_aide.syntax; + vector::const_iterator it=cur_aide.blabla.begin(),itend=cur_aide.blabla.end(); + for (;it!=itend;++it){ + if (it->language==language){ + result += it->chaine +'\n' ; + break; + } + } + vector::const_iterator iti=cur_aide.related.begin(),itiend=cur_aide.related.end(); + if (itiend!=iti){ + result += gettext("See also: "); + for (;iti!=itiend;++iti){ + result += printint(iti->index) + "/ " + iti->chaine + " "; + } + result += '\n' ; + } + vector::const_iterator its=cur_aide.examples.begin(),itsend=cur_aide.examples.end(); + for (int i=1;its!=itsend;++its,++i){ + string current = "Ex" + printint(i)+':'+*its ; + result += current +'\n' ; + // system(current.c_str()); + } + return result; + } + +#if !defined(NSPIRE_NEWLIB) && !defined(RTOS_THREADX) && !defined(EMCC) && !defined(NSPIRE) && !defined FXCG && !defined(KHICAS) && !defined GIAC_HAS_STO_38 + multimap html_mtt,html_mall; + std::vector html_vtt,html_vall; + + // WARNING rebuilding caches works with old version of hevea (1.10) but not with hevea 2.29 + // find index nodes in file file + static bool find_index(const std::string & current_dir,const std::string & file,multimap&mtt,multimap&mall,bool is_index=false,bool warn=false){ + if (access(file.c_str(),R_OK)) + return false; + ifstream i(file.c_str()); + // Skip navigation panel +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + char * buf=new char[BUFFER_SIZE+1]; +#else + char buf[BUFFER_SIZE+1]; +#endif + for (;i && !i.eof();){ + i.getline(buf,BUFFER_SIZE,'\n'); + string s(buf),stmp; + if (s=="") // latex2html? + break; + int t=int(s.size()); + if (t>24 && ((stmp=s.substr(t-24,24))=="
  • " || stmp=="
  • ")){ + // hevea file contains index + for (;i && !i.eof(); ){ + i.getline(buf,BUFFER_SIZE,'\n'); + s=buf; + t=int(s.size()); + if (t>29 && ((stmp=s.substr(0,29))=="
  • " || stmp=="
  • ")){ + s=s.substr(29,s.size()-29); + t=int(s.size()); + if (!t) + continue; + if (s[0]=='<'){ // skip index words with special color/font + if (t<30 || s.substr(0,36)!="") + continue; + s=s.substr(36,s.size()-1); + } + int endcmd=int(s.find("<")); // position of end of commandname + if (endcmd>2 && endcmd hrefs; + for (;;){ + t=int(s.size()); + endcmd=int(s.find("=t){ + endcmd=int(s.find("=t) + break; + } + s=s.substr(endcmd+9,s.size()-endcmd-9); + t=int(s.size()); + endcmd=int(s.find("\"")); + if (endcmd<0 || endcmd+2>=t) + break; + string link=s.substr(0,endcmd); + if (link[0]=='#') + link = file + link; + else + link = current_dir + link; + s=s.substr(endcmd+2,s.size()-endcmd-2); + t=int(s.size()); + if (t<3) + break; + if (s.substr(0,3)=="" || (t>30 && s.substr(0,29)=="::const_iterator it=hrefs.begin(),itend=hrefs.end(); + for (;it!=itend;++it){ + if (it==hrefs.begin()) + mtt.insert(pair(cmdname,*it)); + mall.insert(pair(cmdname,*it)); + } + } // if (endcmd>2 && endcmd29 &&... + } // for (;i && !i.eof();) end of file +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + delete [] buf; +#endif + return true; + } // end hevea file with index + // latex2html only? + if (t>14 && s.substr(t-14,14)=="Index "){ + // look in the corresponding index file instead + int t1=int(s.find("HREF"))+6; + if (t1>=0 && t1> tmp; + int l=int(tmp.size()); + string tts; + if (is_index){ + if (l<13) + continue; + int tmpl=0; + if (tmp.substr(0,8)=="") + tmpl=8; + if (tmp.substr(0,12)=="
    ") + tmpl=12; + if (!tmpl) + continue; + int l1=int(tmp.find("")); + if (l1<=tmpl || l1>=l) + continue; + tts=tmp.substr(tmpl,l1-tmpl); + } + else { + if (l<2 || tmp.substr(l-2,2)!="4 && tmp.substr(s-4,4)=="
    "){ + // no found, truncate tmp to the first found + int l=int(tmp.find("")); + if (l0) + tmp=tmp.substr(0,l); + s=int(tmp.size()); + break; + } + if (s>8 && tmp.substr(s-8,8)==""){ + // Find backward the first occurrence of 0;--l){ + if (tmp[l]=='<' && tmp[l+1]=='A') + break; + } + if (l){ + tmp=tmp.substr(l,s-l); + s -= l; + } + break; + } + } + // cerr << tmp << endl; + // analysis, search for HREF + int href=int(tmp.find("HREF=\"")); + if (href<0 || href+6>=s) + continue; + string hrefs(current_dir); + int hrefend=0; + for (int j=href+6;j(tts,hrefs)); + mall.insert(pair(tts,hrefs)); + } + else { + // search for TT + int tt=int(tmp.find("")),ttend=tt; + if (tt>=0 && tt+6(tts,hrefs)); + mall.insert(pair(tts,hrefs)); + tmp=tmp.substr(0,tt)+tmp.substr(ttend,tmp.size()-ttend); + } + // add href for all normal words + s=int(tmp.size()); + int j=hrefend+1; + for (;jj && pos(tmpins,hrefs)); + } + if (pos==-1){ + string tmpins(tmp.substr(j,s-j)); + mall.insert(pair(tmpins,hrefs)); + break; + } + j=pos+1; + } + } // end else is_index + } + return false; + } + + static const string subdir_strings[]={"cascmd","casgeo","casrouge","cassim","castor","tutoriel","casinter","casexo","cascas"}; + static const int subdir_taille=sizeof(subdir_strings)/sizeof(string); + static int equalposcomp(const string * tab,const string & s){ + int i=int(s.size())-1; + for (;i>=0;--i){ + if (s[i]=='/') + break; + } + ++i; + string t=s.substr(i,s.size()-i); + i=int(t.size())-1; + for (;i>=0;--i){ + if (t[i]=='_') + t=t.substr(0,i); + } + for (i=0;id_name); + // cerr << s << endl; + int t=s.size(); + if (s[t-1]=='\\'){ + return s!="." && s!=".."; + } + if (t<9) + return 0; + if (s[t-1]=='l'){ + s=s.substr(0,t-1); + --t; + } + if (t>9) + s=s.substr(t-9,9); + return s=="index.htm"; + } +#else +// __APPLE_CC__ == 5666 on Mac OS X 10.6, 5658 on geogebra build system OS X 10.8 +// should check __APPLE__ OS X version instead! +#if ( defined(__MAC_OS_X_VERSION_MAX_ALLOWED)&& __MAC_OS_X_VERSION_MAX_ALLOWED< 1080 ) || ( defined(__IPHONE_OS_VERSION_MAX_ALLOWED)&& __IPHONE_OS_VERSION_MAX_ALLOWED< 60100 ) || ( defined(__OpenBSD__)&& OpenBSD<201905) || ( defined(__FreeBSD_version)&& __FreeBSD_version<800501) + static int dir_select (struct dirent *d){ +#else + static int dir_select (const struct dirent *d){ +#endif + string s(d->d_name); + if (d->d_type==DT_DIR || equalposcomp(subdir_strings,s)){ + return s!="." && s!=".."; + } + int t=s.size(); + if (t<9) + return 0; + if (s[t-1]=='l'){ + s=s.substr(0,t-1); + --t; + } + if (t>9) + s=s.substr(t-9,9); + return s=="index.htm"; + } +#endif +#endif // visualc + +#ifdef __MINGW_H + int giac_errno=0; + int get_errno(){ + return giac_errno; + } + void set_errno(int i){ + giac_errno=i; + } + +/* scandir.cc + + Copyright 1998, 1999, 2000, 2001 Red Hat, Inc. + + Written by Corinna Vinschen + + This file is part of Cygwin. + + scandir is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ +extern "C" +int +scandir (const char *dir, + struct dirent ***namelist, + int (*select) (const struct dirent *), + int (*compar) (const struct dirent **, const struct dirent **)) +{ + DIR *dirp; + struct dirent *ent, *etmp, **nl = NULL, **ntmp; + int count = 0; + int allocated = 0; + + if (!(dirp = opendir (dir))) + return -1; + + int prior_errno = get_errno (); + set_errno (0); + + while ((ent = readdir (dirp))) + { + if (!select || select (ent)) + { + + /* Ignore error from readdir/select. See POSIX specs. */ + set_errno (0); + + if (count == allocated) + { + + if (allocated == 0) + allocated = 10; + else + allocated *= 2; + + ntmp = (struct dirent **) realloc (nl, allocated * sizeof *nl); + if (!ntmp) + { + set_errno (ENOMEM); + break; + } + nl = ntmp; + } + + if (!(etmp = (struct dirent *) malloc (sizeof *ent))) + { + set_errno (ENOMEM); + break; + } + *etmp = *ent; + nl[count++] = etmp; + } + } + + if ((prior_errno = get_errno ()) != 0) + { + closedir (dirp); + if (nl) + { + while (count > 0) + free (nl[--count]); + free (nl); + } + /* Ignore errors from closedir() and what not else. */ + set_errno (prior_errno); + return -1; + } + + closedir (dirp); + set_errno (prior_errno); + + qsort (nl, count, sizeof *nl, (int (*)(const void *, const void *)) compar); + if (namelist) + *namelist = nl; + return count; +} + +extern "C" +int +alphasort (const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} +#endif + + void find_all_index(const std::string & subdir,multimap & mtt,multimap & mall){ +#if defined GNUWINCE || defined __ANDROID__ || defined EMCC|| defined EMCC2 || defined NSPIRE_NEWLIB || defined FXCG || defined KHICAS || defined SDL_KHICAS + return; +#else + // cerr << "HTML help Scanning " << subdir << endl; + DIR *dp; + struct dirent *ep; + + dp = opendir (subdir.c_str()); + if (dp != NULL){ + string s; + int t; + while ( (ep = readdir (dp)) ){ + s=ep->d_name; + t=s.size(); + if (t>5 && s.substr(t-4,4)=="html") + html_vall.push_back(subdir+s); + } + closedir (dp); + } + + struct dirent **eps; + int n; +#if defined APPLE_SMART || defined NO_SCANDIR + n =-1; +#else + n = scandir (subdir.c_str(), &eps, dir_select, alphasort); +#endif + if (n >= 0){ + bool index_done=false; + int cnt; + for (cnt = -1; cnt < n; ++cnt){ + string s; + if (cnt==-1) + s="index.html"; + else + s=eps[cnt]->d_name; + s= subdir+s; +#if defined WIN32 || !defined DT_DIR + int t=s.size(); + if (s[t-1]=='\\') + find_all_index(s+"/",mtt,mall); + else { + if (!index_done) + index_done=find_index(subdir,s,mtt,mall); + } +#else + unsigned char type=cnt>=0?eps[cnt]->d_type:0; + if (type==DT_DIR || equalposcomp(subdir_strings,s)) + find_all_index(s+"/",mtt,mall); + else { + if (!index_done) + index_done=find_index(subdir,s,mtt,mall); + } +#endif + } + } +#endif // GNUWINCE + } + + // Return all HTML nodes refered to s in mtt + std::vector html_help(multimap & mtt,const std::string & s){ + vector v; + multimap::const_iterator it=mtt.lower_bound(s),itend=mtt.upper_bound(s); + for (;it!=itend;++it){ + v.push_back(it->second); + } + return v; + } + + string xcasroot_dir(const char * arg){ + string xcasroot; + if (getenv("XCAS_ROOT")){ + xcasroot=string(getenv("XCAS_ROOT")); + if (xcasroot.empty()) + xcasroot="/"; + if (xcasroot[xcasroot.size()-1]!='/') + xcasroot+='/'; + } + else { + xcasroot=arg; + int xcasroot_size=int(xcasroot.size())-1; + for (;xcasroot_size>=0;--xcasroot_size){ + if (xcasroot[xcasroot_size]=='/') + break; + } + if (xcasroot_size>0) + xcasroot=xcasroot.substr(0,xcasroot_size)+"/"; + else { + if (access("/usr/bin/xcas",R_OK)==0) + xcasroot="/usr/bin/"; + else { +#ifdef __APPLE__ + if (access("/Applications/usr/bin/xcas",R_OK)==0) + xcasroot="/Applications/usr/bin"; +#else + if (access("/usr/local/bin/xcas",R_OK)==0) + xcasroot="/usr/local/bin/"; +#endif + else + xcasroot="./"; + } + } + } + // ofstream of("/tmp/xcasroot"); + // of << xcasroot << endl; + return xcasroot; + } + + // extern int debug_infolevel; + static bool get_index_from_cache(const char * filename, multimap & multi,bool verbose){ +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + char * buf = new char[BUFFER_SIZE]; +#else + char buf[BUFFER_SIZE]; +#endif + ifstream if_mtt(filename); + if (verbose){ + bool b=if_mtt && !if_mtt.eof(); + cout << "get_index_from_cache " << filename << (b?" OK":" BAD") << "\n"; + } + int n=0; + while (if_mtt && !if_mtt.eof()){ + if_mtt.getline(buf,BUFFER_SIZE,char(0xa4)); // was 'ค', utf8 not compatible, octal \244 + if (!if_mtt || if_mtt.eof()){ + if (verbose) + cout << "// Read " << n << " entries from cache " << filename << endl; +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + delete [] buf; +#endif + return true; + } + string first(buf); + if_mtt.getline(buf,BUFFER_SIZE,char(0xa4)); + if (!if_mtt || if_mtt.eof()){ +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + delete [] buf; +#endif + return false; + } + multi.insert(pair(first,buf)); +#ifndef EMCC2 + if (!(n%100)){ // check every 100 links if link exists + first=buf; + int l=int(first.size()),j; + char ch=0; + for (j=l-1;j>=0;--j){ + ch=first[j]; + if (ch=='#' || ch=='/') + break; + } + if (j>0 && ch=='#') + first=first.substr(0,j); + if (access(first.c_str(),R_OK)){ + multi.clear(); + cerr << "Wrong cache! " << filename << endl; + if_mtt.close(); +#if !defined RTOS_THREADX && !defined BESTA_OS && !defined FREERTOS + if (unlink(filename)==-1) + cerr << "You don't have write permissions on " << filename <<".\nYou must ask someone who has write permissions to remove " << filename << endl; + else + cerr << "Cache file "<< filename << " has been deleted" << endl; +#endif +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + delete [] buf; +#endif + return false; + } + } +#endif + ++n; + if_mtt.getline(buf,BUFFER_SIZE,'\n'); + } + if (verbose) + cerr << "// Read " << n << " entries from cache " << filename ; +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + delete [] buf; +#endif + return true; + } + + static bool get_index_from_cache(const char * filename, vector & multi,bool verbose){ +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + char * buf = new char[BUFFER_SIZE]; +#else + char buf[BUFFER_SIZE]; +#endif + ifstream if_mtt(filename); + int n=0; + while (if_mtt && !if_mtt.eof()){ + if_mtt.getline(buf,BUFFER_SIZE,char(0xa4)); + if (!if_mtt || if_mtt.eof()){ +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + delete [] buf; +#endif + if (verbose) + cerr << "// Read " << n << " entries from cache " << filename << endl; + return true; + } + multi.push_back(buf); + ++n; + if_mtt.getline(buf,BUFFER_SIZE,'\n'); + } +#if defined VISUALC || defined BESTA_OS || defined FREERTOS + delete [] buf; +#endif + if (verbose) + cerr << "// Read " << n << " entries from cache " << filename ; + return true; + } + + string html_help_init(const char * arg,int language,bool verbose,bool force_rebuild){ + string xcasroot=xcasroot_dir(arg); + // HTML online help + string html_help_dir=xcasroot+"doc/"; + if (access(html_help_dir.c_str(),R_OK)){ +#ifdef __APPLE__ + if (!access("/Applications/usr/bin/icas",R_OK)) + html_help_dir="/Applications/usr/share/giac/doc/"; +#else + if (!access("/usr/bin/xcas",R_OK)) + html_help_dir="/usr/share/giac/doc/"; +#endif + else { + if (!access("/usr/local/bin/xcas",R_OK)) + html_help_dir="/usr/local/share/giac/doc/"; + } + } + if (access(html_help_dir.c_str(),R_OK) && xcasroot.size()>4 && xcasroot.substr(xcasroot.size()-4,4)=="bin/") + html_help_dir=xcasroot.substr(0,xcasroot.size()-4)+"share/giac/doc/"; + html_help_dir += find_lang_prefix(language); +#ifdef WIN32 + string html_help_dir_save=html_help_dir; + html_help_dir +="cascmd_"+find_lang_prefix(giac::language(context0)); // temporary workaround, for win archive copy doc/fr/html_vall to doc/fr/cascmd_fr/html_vall and change path +#endif + html_mtt.clear(); + html_mall.clear(); + html_vall.clear(); + // Get indices from file cache if it exists +#ifdef EMCC2 + int b1=1,b2=1,b3=1; +#ifndef UPSILON + printf("html_help_dir=%s mtt=%i mall=%i vall=%i\n",html_help_dir.c_str(),b1,b2,b3); +#endif +#else + int b1=!access((html_help_dir+"html_mtt").c_str(),R_OK), b2=!access((html_help_dir+"html_mall").c_str(),R_OK), b3=!access((html_help_dir+"html_vall").c_str(),R_OK); + if (access(html_help_dir.c_str(),R_OK)) + cerr << "Unable to open HTML doc directory " << html_help_dir << endl; +#endif + if (!force_rebuild && b1 && b2 && b3){ + cout << "Reading from cache "<< html_help_dir << "\n"; + if (get_index_from_cache((html_help_dir+"html_mtt").c_str(),html_mtt,verbose)&& + get_index_from_cache((html_help_dir+"html_mall").c_str(),html_mall,verbose)&& + get_index_from_cache((html_help_dir+"html_vall").c_str(),html_vall,verbose) ) + return html_help_dir; + } + find_all_index(html_help_dir,html_mtt,html_mall); +#ifdef WIN32 + for (unsigned i=0;i::const_iterator it=html_mtt.begin(),itend=html_mtt.end(); + for (;it!=itend;++it) + of_mtt << it->first << char(0xa4) << it->second << char(0xa4) << endl; + of_mtt.close(); + ofstream of_mall((html_help_dir+"html_mall").c_str()); + it=html_mall.begin();itend=html_mall.end(); + for (;it!=itend;++it) + of_mall << it->first << char(0xa4) << it->second << char(0xa4) << endl; + of_mall.close(); + ofstream of_vall((html_help_dir+"html_vall").c_str()); + vector::const_iterator st=html_vall.begin(),stend=html_vall.end(); + for (;st!=stend;++st) + of_vall << *st << char(0xa4) << endl; + of_vall.close(); + /* + if (debug_infolevel){ + vector::const_iterator it=html_vall.begin(),itend=html_vall.end(); + for (;it!=itend;++it) + cerr << *it << endl; + } + */ + return html_help_dir; + } + + static bool multigrep(FILE * f,const string & s){ + int l=int(s.size()); + // find spaces + string tmp; + vector vs; + for (int i=0;i='A' && c<='F') + code = code*base + c-'A'+10; + if (c>='a' && c<='f') + code = code*base + c-'a'+10; + if (c>='0' && c<='9') + code = code*base + c-'0'; + } + } + else{ + switch (code){ + case 0xe8: case 0xe9: case 0xea: + c='e'; + break; + case 0xe0: case 0xe2: + c='a'; + break; + case 0xf4: + c='o'; + break; + case 0xf9: case 0xfb: + c='u'; + break; + case 0xe7: + c='c'; + break; + case 238: + c='i'; + break; + } + break; + } + } + } + } + if (c==' '){ + if (!tmp.empty()){ // search tmp in vs + unsigned tmpl=unsigned(tmp.size()),tmpvs; + for (int i=0;i='0' && ch<='9') + return true; + if (ch>='a' && ch<='z') + return true; + if (ch>='A' && ch<='Z') + return true; + if (unsigned(ch)>128) + return true; + if (ch=='_' || ch=='.' || ch=='~') + return true; + /* + char * ptr=otherchars; + for (;*ptr;++ptr){ + if (ch==*ptr) + return true; + } + */ + return false; + } + + std::string unlocalize(const std::string & s){ + std::string res,tmp; + int ss=int(s.size()); + std::map::const_iterator it,itend=lexer_localization_map().end(); + int mode=0; // 1 if inside a string + for (int i=0;;++i){ + char ch=s[i]; + if (mode){ + if (ch=='"'){ + if (res.empty() || res[res.size()-1]!='\\') + mode=0; + } + res += ch; + if (i==ss) + break; + continue; + } + if (isecond; // it is -> we must translate to giac + res += tmp; + tmp = ""; + if (ch=='"'){ + if (res.empty() || res[res.size()-1]!='\\') + mode=1; + } + if (i::const_iterator it0,it,itend,backend=back_lexer_localization_map().end(); + for (int i=0;;++i){ + char ch=s[i]; + if (mode){ + if (ch=='"'){ + if (res.empty() || res[res.size()-1]!='\\') + mode=0; + } + res += ch; + if (i==ss) + break; + continue; + } + if (isecond.language==language){ + tmp = it->second.chaine; + break; + } + } + if (it==itend) + tmp = it0->second.chaine; + } + res += tmp; + tmp = ""; + if (ch=='"'){ + if (res.empty() || res[res.size()-1]!='\\') + mode=1; + } + if (i. + */ +using namespace std; +#include +#if !defined GIAC_HAS_STO_38 && !defined NSPIRE && !defined FXCG +#include +#endif +#include +#ifdef HP39 +char *strdup(const char *s){ + char * ptr=(char *)malloc(strlen(s)+1); + strcpy(ptr,s); + return ptr; +} +#endif +//#include // For reading arguments from file +#include "identificateur.h" +#include "gen.h" +#include "sym2poly.h" +#include "rpn.h" +#include "prog.h" +#include "usual.h" +#include "giacintl.h" + +#ifdef BESTA_OS +// Local replacement for strdup on BESTA OS. +static char* strdup(char* str) +{ + if ( ! str ) + { + return str; + } + + int len = strlen(str) + 2; + char* p = new char[len]; + strcpy(p, str); + return p; +} +#endif + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + // bool variables_are_files=true; // FIXME -> false and change rpn.cc at_VARS + int protection_level=0; // for local variables in null context + + struct int_string_shortint_bool { + int i; + const char * s; + short int b; + bool s_dynalloc; + }; + +#ifdef DOUBLEVAL // #ifdef GIAC_GENERIC_CONSTANTS + const char string_euler_gamma[]="euler_gamma"; + identificateur _IDNT_euler_gamma(string_euler_gamma,(double) .577215664901533); + gen cst_euler_gamma(_IDNT_euler_gamma); + + const char string_pi[]="pi"; + identificateur & _IDNT_pi(){ + static identificateur * ans=new identificateur(string_pi,(double) M_PI); + return * ans; + } + // identificateur _IDNT_pi(string_pi,(double) M_PI); + alias_ref_identificateur ref_pi={-1,0,0,string_pi,0,0}; + + gen cst_pi(_IDNT_pi()); + + const char string_infinity[]="infinity"; + identificateur & _IDNT_infinity(){ + static identificateur * ans=new identificateur("infinity"); + return * ans; + } + gen unsigned_inf(_IDNT_infinity()); + alias_gen & alias_unsigned_inf = *(alias_gen *) & unsigned_inf; + alias_ref_identificateur ref_infinity={-1,0,0,string_infinity,0,0}; + + const char string_undef[]="undef"; + identificateur & _IDNT_undef(){ + static identificateur * ans=new identificateur("undef"); + return * ans; + } + gen undef(_IDNT_undef()); + +#else + const char string_euler_gamma[]="euler_gamma"; + static const alias_ref_identificateur ref_euler_gamma={-1,0,0,string_euler_gamma,0,0}; + const define_alias_gen(alias_cst_euler_gamma,_IDNT,0,&ref_euler_gamma); + const gen & cst_euler_gamma = * (gen *) & alias_cst_euler_gamma; + + const char string_pi[]="pi"; + static const alias_identificateur alias_identificateur_pi={0,0,string_pi,0,0}; + const identificateur & _IDNT_pi(){ + return *(const identificateur *) & alias_identificateur_pi; + } + const alias_ref_identificateur ref_pi={-1,0,0,string_pi,0,0}; + const define_alias_gen(alias_cst_pi,_IDNT,0,&ref_pi); + const gen & cst_pi = * (gen *) & alias_cst_pi; + + const char string_infinity[]="infinity"; + static const alias_identificateur alias_identificateur_infinity={0,0,string_infinity,0,0}; + const identificateur & _IDNT_infinity(){ + return * (const identificateur *) &alias_identificateur_infinity; + } + const alias_ref_identificateur ref_infinity={-1,0,0,string_infinity,0,0}; + const define_alias_gen(alias_unsigned_inf,_IDNT,0,&ref_infinity); + const gen & unsigned_inf = * (gen *) & alias_unsigned_inf; + + const char string_undef[]="undef"; + static const alias_identificateur alias_identificateur_undef={0,0,string_undef,0,0}; + const identificateur & _IDNT_undef(){ + return * (const identificateur *) &alias_identificateur_undef; + } + static const alias_ref_identificateur ref_undef={-1,0,0,string_undef,0,0}; + const define_alias_gen(alias_undef,_IDNT,0,&ref_undef); + const gen & undef = * (gen *) & alias_undef; + +#endif // GIAC_GENERIC_CONSTANTS + +#if defined GIAC_HAS_STO_38 || defined NSPIRE || defined NSPIRE_NEWLIB || defined KHICAS || defined FXCG +#if 0 // 38 mode + static const alias_identificateur alias_identificateur_a38={0,0,"A",0,0}; + const identificateur & a__IDNT=* (const identificateur *) &alias_identificateur_a38; + const alias_ref_identificateur ref_a38={-1,0,0,"A",0,0}; + const define_alias_gen(alias_a38,_IDNT,0,&ref_a38); +// const gen & a__IDNT_e = * (gen *) & alias_a38; + + static const alias_identificateur alias_identificateur_b38={0,0,"B",0,0}; + const identificateur & b__IDNT=* (const identificateur *) &alias_identificateur_b38; + const alias_ref_identificateur ref_b38={-1,0,0,"B",0,0}; + const define_alias_gen(alias_b38,_IDNT,0,&ref_b38); +// const gen & b__IDNT_e = * (gen *) & alias_b38; + + static const alias_identificateur alias_identificateur_c38={0,0,"C",0,0}; + const identificateur & c__IDNT=* (const identificateur *) &alias_identificateur_c38; + const alias_ref_identificateur ref_c38={-1,0,0,"C",0,0}; + const define_alias_gen(alias_c38,_IDNT,0,&ref_c38); +// const gen & c__IDNT_e = * (gen *) & alias_c38; + + static const alias_identificateur alias_identificateur_d38={0,0,"D",0,0}; + const identificateur & d__IDNT=* (const identificateur *) &alias_identificateur_d38; + const alias_ref_identificateur ref_d38={-1,0,0,"D",0,0}; + const define_alias_gen(alias_d38,_IDNT,0,&ref_d38); +// const gen & d__IDNT_e = * (gen *) & alias_d38; + + static const alias_identificateur alias_identificateur_e38={0,0,"E",0,0}; + const identificateur & e__IDNT=* (const identificateur *) &alias_identificateur_e38; + const alias_ref_identificateur ref_e38={-1,0,0,"E",0,0}; + const define_alias_gen(alias_e38,_IDNT,0,&ref_e38); +// const gen & e__IDNT_e = * (gen *) & alias_e38; + + static const alias_identificateur alias_identificateur_f38={0,0,"F",0,0}; + const identificateur & f__IDNT=* (const identificateur *) &alias_identificateur_f38; + const alias_ref_identificateur ref_f38={-1,0,0,"F",0,0}; + const define_alias_gen(alias_f38,_IDNT,0,&ref_f38); +// const gen & f__IDNT_e = * (gen *) & alias_f38; + + static const alias_identificateur alias_identificateur_g38={0,0,"G",0,0}; + const identificateur & g__IDNT=* (const identificateur *) &alias_identificateur_g38; + const alias_ref_identificateur ref_g38={-1,0,0,"G",0,0}; + const define_alias_gen(alias_g38,_IDNT,0,&ref_g38); +// const gen & g__IDNT_e = * (gen *) & alias_g38; + + static const alias_identificateur alias_identificateur_h38={0,0,"H",0,0}; + const identificateur & h__IDNT=* (const identificateur *) &alias_identificateur_h38; + const alias_ref_identificateur ref_h38={-1,0,0,"H",0,0}; + const define_alias_gen(alias_h38,_IDNT,0,&ref_h38); +// const gen & h__IDNT_e = * (gen *) & alias_h38; + + static const alias_identificateur alias_identificateur_i38={0,0,"I",0,0}; + const identificateur & i__IDNT=* (const identificateur *) &alias_identificateur_i38; + const alias_ref_identificateur ref_i38={-1,0,0,"I",0,0}; + const define_alias_gen(alias_i38,_IDNT,0,&ref_i38); +// const gen & i__IDNT_e = * (gen *) & alias_i38; + + static const alias_identificateur alias_identificateur_j38={0,0,"J",0,0}; + const identificateur & j__IDNT=* (const identificateur *) &alias_identificateur_j38; + const alias_ref_identificateur ref_j38={-1,0,0,"J",0,0}; + const define_alias_gen(alias_j38,_IDNT,0,&ref_j38); +// const gen & j__IDNT_e = * (gen *) & alias_j38; + + static const alias_identificateur alias_identificateur_k38={0,0,"K",0,0}; + const identificateur & k__IDNT=* (const identificateur *) &alias_identificateur_k38; + const alias_ref_identificateur ref_k38={-1,0,0,"K",0,0}; + const define_alias_gen(alias_k38,_IDNT,0,&ref_k38); +// const gen & k__IDNT_e = * (gen *) & alias_k38; + + static const alias_identificateur alias_identificateur_l38={0,0,"L",0,0}; + const identificateur & l__IDNT=* (const identificateur *) &alias_identificateur_l38; + const alias_ref_identificateur ref_l38={-1,0,0,"L",0,0}; + const define_alias_gen(alias_l38,_IDNT,0,&ref_l38); +// const gen & l__IDNT_e = * (gen *) & alias_l38; + + static const alias_identificateur alias_identificateur_m38={0,0,"M",0,0}; + const identificateur & m__IDNT=* (const identificateur *) &alias_identificateur_m38; + const alias_ref_identificateur ref_m38={-1,0,0,"M",0,0}; + const define_alias_gen(alias_m38,_IDNT,0,&ref_m38); +// const gen & m__IDNT_e = * (gen *) & alias_m38; + + static const alias_identificateur alias_identificateur_n38={0,0,"N",0,0}; + const identificateur & n__IDNT=* (const identificateur *) &alias_identificateur_n38; + const alias_ref_identificateur ref_n38={-1,0,0,"N",0,0}; + const define_alias_gen(alias_n38,_IDNT,0,&ref_n38); +// const gen & n__IDNT_e = * (gen *) & alias_n38; + + static const alias_identificateur alias_identificateur_o38={0,0,"O",0,0}; + const identificateur & o__IDNT=* (const identificateur *) &alias_identificateur_o38; + const alias_ref_identificateur ref_o38={-1,0,0,"O",0,0}; + const define_alias_gen(alias_o38,_IDNT,0,&ref_o38); +// const gen & o__IDNT_e = * (gen *) & alias_o38; + + static const alias_identificateur alias_identificateur_p38={0,0,"P",0,0}; + const identificateur & p__IDNT=* (const identificateur *) &alias_identificateur_p38; + const alias_ref_identificateur ref_p38={-1,0,0,"P",0,0}; + const define_alias_gen(alias_p38,_IDNT,0,&ref_p38); +// const gen & p__IDNT_e = * (gen *) & alias_p38; + + static const alias_identificateur alias_identificateur_q38={0,0,"Q",0,0}; + const identificateur & q__IDNT=* (const identificateur *) &alias_identificateur_q38; + const alias_ref_identificateur ref_q38={-1,0,0,"Q",0,0}; + const define_alias_gen(alias_q38,_IDNT,0,&ref_q38); +// const gen & q__IDNT_e = * (gen *) & alias_q38; + + static const alias_identificateur alias_identificateur_r38={0,0,"R",0,0}; + const identificateur & r__IDNT=* (const identificateur *) &alias_identificateur_r38; + const alias_ref_identificateur ref_r38={-1,0,0,"R",0,0}; + const define_alias_gen(alias_r38,_IDNT,0,&ref_r38); +// const gen & r__IDNT_e = * (gen *) & alias_r38; + + static const alias_identificateur alias_identificateur_s38={0,0,"S",0,0}; + const identificateur & s__IDNT=* (const identificateur *) &alias_identificateur_s38; + const alias_ref_identificateur ref_s38={-1,0,0,"S",0,0}; + const define_alias_gen(alias_s38,_IDNT,0,&ref_s38); +// const gen & s__IDNT_e = * (gen *) & alias_s38; + + static const alias_identificateur alias_identificateur_t38={0,0,"T",0,0}; + const identificateur & t__IDNT=* (const identificateur *) &alias_identificateur_t38; + const alias_ref_identificateur ref_t38={-1,0,0,"T",0,0}; + const define_alias_gen(alias_t38,_IDNT,0,&ref_t38); +// const gen & t__IDNT_e = * (gen *) & alias_t38; + + static const alias_identificateur alias_identificateur_u38={0,0,"U",0,0}; + const identificateur & u__IDNT=* (const identificateur *) &alias_identificateur_u38; + const alias_ref_identificateur ref_u38={-1,0,0,"U",0,0}; + const define_alias_gen(alias_u38,_IDNT,0,&ref_u38); +// const gen & u__IDNT_e = * (gen *) & alias_u38; + + static const alias_identificateur alias_identificateur_v38={0,0,"V",0,0}; + const identificateur & v__IDNT=* (const identificateur *) &alias_identificateur_v38; + const alias_ref_identificateur ref_v38={-1,0,0,"V",0,0}; + const define_alias_gen(alias_v38,_IDNT,0,&ref_v38); +// const gen & v__IDNT_e = * (gen *) & alias_v38; + + static const alias_identificateur alias_identificateur_w38={0,0,"W",0,0}; + const identificateur & w__IDNT=* (const identificateur *) &alias_identificateur_w38; + const alias_ref_identificateur ref_w38={-1,0,0,"W",0,0}; + const define_alias_gen(alias_w38,_IDNT,0,&ref_w38); +// const gen & w__IDNT_e = * (gen *) & alias_w38; + + static const alias_identificateur alias_identificateur_x38={0,0,"X",0,0}; + const identificateur & x__IDNT=* (const identificateur *) &alias_identificateur_x38; + const alias_ref_identificateur ref_x38={-1,0,0,"X",0,0}; + const define_alias_gen(alias_x38,_IDNT,0,&ref_x38); +// const gen & x__IDNT_e = * (gen *) & alias_x38; + + static const alias_identificateur alias_identificateur_xx38={0,0,"x",0,0}; + const identificateur & xx__IDNT=* (const identificateur *) &alias_identificateur_xx38; + const alias_ref_identificateur ref_xx38={-1,0,0,"x",0,0}; + const define_alias_gen(alias_xx38,_IDNT,0,&ref_xx38); +// const gen & xx__IDNT_e = * (gen *) & alias_xx38; + + static const alias_identificateur alias_identificateur_y38={0,0,"Y",0,0}; + const identificateur & y__IDNT=* (const identificateur *) &alias_identificateur_y38; + const alias_ref_identificateur ref_y38={-1,0,0,"Y",0,0}; + const define_alias_gen(alias_y38,_IDNT,0,&ref_y38); +// const gen & y__IDNT_e = * (gen *) & alias_y38; + + static const alias_identificateur alias_identificateur_z38={0,0,"Z",0,0}; + const identificateur & z__IDNT=* (const identificateur *) &alias_identificateur_z38; + const alias_ref_identificateur ref_z38={-1,0,0,"Z",0,0}; + const define_alias_gen(alias_z38,_IDNT,0,&ref_z38); +// const gen & z__IDNT_e = * (gen *) & alias_z38; + +#else // 38 mode + static const alias_identificateur alias_identificateur_a38={0,0,"a",0,0}; + const identificateur & a__IDNT=* (const identificateur *) &alias_identificateur_a38; + const alias_ref_identificateur ref_a38={-1,0,0,"a",0,0}; + const define_alias_gen(alias_a38,_IDNT,0,&ref_a38); +// const gen & a__IDNT_e = * (gen *) & alias_a38; + + static const alias_identificateur alias_identificateur_b38={0,0,"b",0,0}; + const identificateur & b__IDNT=* (const identificateur *) &alias_identificateur_b38; + const alias_ref_identificateur ref_b38={-1,0,0,"b",0,0}; + const define_alias_gen(alias_b38,_IDNT,0,&ref_b38); +// const gen & b__IDNT_e = * (gen *) & alias_b38; + + static const alias_identificateur alias_identificateur_c38={0,0,"c",0,0}; + const identificateur & c__IDNT=* (const identificateur *) &alias_identificateur_c38; + const alias_ref_identificateur ref_c38={-1,0,0,"c",0,0}; + const define_alias_gen(alias_c38,_IDNT,0,&ref_c38); +// const gen & c__IDNT_e = * (gen *) & alias_c38; + + static const alias_identificateur alias_identificateur_d38={0,0,"d",0,0}; + const identificateur & d__IDNT=* (const identificateur *) &alias_identificateur_d38; + const alias_ref_identificateur ref_d38={-1,0,0,"d",0,0}; + const define_alias_gen(alias_d38,_IDNT,0,&ref_d38); +// const gen & d__IDNT_e = * (gen *) & alias_d38; + + static const alias_identificateur alias_identificateur_e38={0,0,"e",0,0}; + const identificateur & e__IDNT=* (const identificateur *) &alias_identificateur_e38; + const alias_ref_identificateur ref_e38={-1,0,0,"e",0,0}; + const define_alias_gen(alias_e38,_IDNT,0,&ref_e38); +// const gen & e__IDNT_e = * (gen *) & alias_e38; + + static const alias_identificateur alias_identificateur_f38={0,0,"f",0,0}; + const identificateur & f__IDNT=* (const identificateur *) &alias_identificateur_f38; + const alias_ref_identificateur ref_f38={-1,0,0,"f",0,0}; + const define_alias_gen(alias_f38,_IDNT,0,&ref_f38); +// const gen & f__IDNT_e = * (gen *) & alias_f38; + + static const alias_identificateur alias_identificateur_g38={0,0,"g",0,0}; + const identificateur & g__IDNT=* (const identificateur *) &alias_identificateur_g38; + const alias_ref_identificateur ref_g38={-1,0,0,"g",0,0}; + const define_alias_gen(alias_g38,_IDNT,0,&ref_g38); +// const gen & g__IDNT_e = * (gen *) & alias_g38; + + static const alias_identificateur alias_identificateur_h38={0,0,"h",0,0}; + const identificateur & h__IDNT=* (const identificateur *) &alias_identificateur_h38; + const alias_ref_identificateur ref_h38={-1,0,0,"h",0,0}; + const define_alias_gen(alias_h38,_IDNT,0,&ref_h38); +// const gen & h__IDNT_e = * (gen *) & alias_h38; + + static const alias_identificateur alias_identificateur_i38={0,0,"i",0,0}; + const identificateur & i__IDNT=* (const identificateur *) &alias_identificateur_i38; + const alias_ref_identificateur ref_i38={-1,0,0,"i",0,0}; + const define_alias_gen(alias_i38,_IDNT,0,&ref_i38); +// const gen & i__IDNT_e = * (gen *) & alias_i38; + + static const alias_identificateur alias_identificateur_j38={0,0,"j",0,0}; + const identificateur & j__IDNT=* (const identificateur *) &alias_identificateur_j38; + const alias_ref_identificateur ref_j38={-1,0,0,"j",0,0}; + const define_alias_gen(alias_j38,_IDNT,0,&ref_j38); +// const gen & j__IDNT_e = * (gen *) & alias_j38; + + static const alias_identificateur alias_identificateur_k38={0,0,"k",0,0}; + const identificateur & k__IDNT=* (const identificateur *) &alias_identificateur_k38; + const alias_ref_identificateur ref_k38={-1,0,0,"k",0,0}; + const define_alias_gen(alias_k38,_IDNT,0,&ref_k38); +// const gen & k__IDNT_e = * (gen *) & alias_k38; + + static const alias_identificateur alias_identificateur_l38={0,0,"l",0,0}; + const identificateur & l__IDNT=* (const identificateur *) &alias_identificateur_l38; + const alias_ref_identificateur ref_l38={-1,0,0,"l",0,0}; + const define_alias_gen(alias_l38,_IDNT,0,&ref_l38); +// const gen & l__IDNT_e = * (gen *) & alias_l38; + + static const alias_identificateur alias_identificateur_m38={0,0,"m",0,0}; + const identificateur & m__IDNT=* (const identificateur *) &alias_identificateur_m38; + const alias_ref_identificateur ref_m38={-1,0,0,"m",0,0}; + const define_alias_gen(alias_m38,_IDNT,0,&ref_m38); +// const gen & m__IDNT_e = * (gen *) & alias_m38; + + static const alias_identificateur alias_identificateur_n38={0,0,"n",0,0}; + const identificateur & n__IDNT=* (const identificateur *) &alias_identificateur_n38; + const alias_ref_identificateur ref_n38={-1,0,0,"n",0,0}; + const define_alias_gen(alias_n38,_IDNT,0,&ref_n38); +// const gen & n__IDNT_e = * (gen *) & alias_n38; + + static const alias_identificateur alias_identificateur_o38={0,0,"o",0,0}; + const identificateur & o__IDNT=* (const identificateur *) &alias_identificateur_o38; + const alias_ref_identificateur ref_o38={-1,0,0,"o",0,0}; + const define_alias_gen(alias_o38,_IDNT,0,&ref_o38); +// const gen & o__IDNT_e = * (gen *) & alias_o38; + + static const alias_identificateur alias_identificateur_p38={0,0,"p",0,0}; + const identificateur & p__IDNT=* (const identificateur *) &alias_identificateur_p38; + const alias_ref_identificateur ref_p38={-1,0,0,"p",0,0}; + const define_alias_gen(alias_p38,_IDNT,0,&ref_p38); +// const gen & p__IDNT_e = * (gen *) & alias_p38; + + static const alias_identificateur alias_identificateur_q38={0,0,"q",0,0}; + const identificateur & q__IDNT=* (const identificateur *) &alias_identificateur_q38; + const alias_ref_identificateur ref_q38={-1,0,0,"q",0,0}; + const define_alias_gen(alias_q38,_IDNT,0,&ref_q38); +// const gen & q__IDNT_e = * (gen *) & alias_q38; + + static const alias_identificateur alias_identificateur_r38={0,0,"r",0,0}; + const identificateur & r__IDNT=* (const identificateur *) &alias_identificateur_r38; + const alias_ref_identificateur ref_r38={-1,0,0,"r",0,0}; + const define_alias_gen(alias_r38,_IDNT,0,&ref_r38); +// const gen & r__IDNT_e = * (gen *) & alias_r38; + + static const alias_identificateur alias_identificateur_s38={0,0,"s",0,0}; + const identificateur & s__IDNT=* (const identificateur *) &alias_identificateur_s38; + const alias_ref_identificateur ref_s38={-1,0,0,"s",0,0}; + const define_alias_gen(alias_s38,_IDNT,0,&ref_s38); +// const gen & s__IDNT_e = * (gen *) & alias_s38; + + static const alias_identificateur alias_identificateur_t38={0,0,"t",0,0}; + const identificateur & t__IDNT=* (const identificateur *) &alias_identificateur_t38; + const alias_ref_identificateur ref_t38={-1,0,0,"t",0,0}; + const define_alias_gen(alias_t38,_IDNT,0,&ref_t38); +// const gen & t__IDNT_e = * (gen *) & alias_t38; + + static const alias_identificateur alias_identificateur_u38={0,0,"u",0,0}; + const identificateur & u__IDNT=* (const identificateur *) &alias_identificateur_u38; + const alias_ref_identificateur ref_u38={-1,0,0,"u",0,0}; + const define_alias_gen(alias_u38,_IDNT,0,&ref_u38); +// const gen & u__IDNT_e = * (gen *) & alias_u38; + + static const alias_identificateur alias_identificateur_v38={0,0,"v",0,0}; + const identificateur & v__IDNT=* (const identificateur *) &alias_identificateur_v38; + const alias_ref_identificateur ref_v38={-1,0,0,"v",0,0}; + const define_alias_gen(alias_v38,_IDNT,0,&ref_v38); +// const gen & v__IDNT_e = * (gen *) & alias_v38; + + static const alias_identificateur alias_identificateur_w38={0,0,"w",0,0}; + const identificateur & w__IDNT=* (const identificateur *) &alias_identificateur_w38; + const alias_ref_identificateur ref_w38={-1,0,0,"w",0,0}; + const define_alias_gen(alias_w38,_IDNT,0,&ref_w38); +// const gen & w__IDNT_e = * (gen *) & alias_w38; + + static const alias_identificateur alias_identificateur_x38={0,0,"x",0,0}; + const identificateur & x__IDNT=* (const identificateur *) &alias_identificateur_x38; + const alias_ref_identificateur ref_x38={-1,0,0,"x",0,0}; + const define_alias_gen(alias_x38,_IDNT,0,&ref_x38); +// const gen & x__IDNT_e = * (gen *) & alias_x38; + + static const alias_identificateur alias_identificateur_xx38={0,0,"x",0,0}; + const identificateur & xx__IDNT=* (const identificateur *) &alias_identificateur_xx38; + const alias_ref_identificateur ref_xx38={-1,0,0,"x",0,0}; + const define_alias_gen(alias_xx38,_IDNT,0,&ref_xx38); +// const gen & x__IDNT_e = * (gen *) & alias_xx38; + + static const alias_identificateur alias_identificateur_y38={0,0,"y",0,0}; + const identificateur & y__IDNT=* (const identificateur *) &alias_identificateur_y38; + const alias_ref_identificateur ref_y38={-1,0,0,"y",0,0}; + const define_alias_gen(alias_y38,_IDNT,0,&ref_y38); +// const gen & y__IDNT_e = * (gen *) & alias_y38; + + static const alias_identificateur alias_identificateur_z38={0,0,"z",0,0}; + const identificateur & z__IDNT=* (const identificateur *) &alias_identificateur_z38; + const alias_ref_identificateur ref_z38={-1,0,0,"z",0,0}; + const define_alias_gen(alias_z38,_IDNT,0,&ref_z38); +// const gen & z__IDNT_e = * (gen *) & alias_z38; +#endif // else 38 + + static const alias_identificateur alias_identificateur_laplace_var={0,0," s",0,0}; + const identificateur & laplace_var=* (const identificateur *) &alias_identificateur_laplace_var; + const alias_ref_identificateur ref_laplace_var={-1,0,0," s",0,0}; + const define_alias_gen(alias_laplace_var,_IDNT,0,&ref_laplace_var); + const gen & laplace_var_e = * (gen *) & alias_laplace_var; + + static const alias_identificateur alias_identificateur_theta38={0,0,"ฮธ",0,0}; + const identificateur & theta__IDNT=* (const identificateur *) &alias_identificateur_theta38; + const alias_ref_identificateur ref_theta38={-1,0,0,"ฮธ",0,0}; + const define_alias_gen(alias_theta38,_IDNT,0,&ref_theta38); + const gen & theta__IDNT_e = * (gen *) & alias_theta38; + + static const alias_identificateur alias_identificateur_CST38={0,0,"CST",0,0}; + const identificateur & CST__IDNT=* (const identificateur *) &alias_identificateur_CST38; + const alias_ref_identificateur ref_CST38={-1,0,0,"CST",0,0}; + const define_alias_gen(alias_CST38,_IDNT,0,&ref_CST38); + const gen & CST__IDNT_e = * (gen *) & alias_CST38; + + static const alias_identificateur alias_identificateur_at38={0,0,"at",0,0}; + const identificateur & _IDNT_id_at=* (const identificateur *) &alias_identificateur_at38; + const alias_ref_identificateur ref_at38={-1,0,0,"at",0,0}; + const define_alias_gen(alias_at38,_IDNT,0,&ref_at38); + const gen & at__IDNT_e = * (gen *) & alias_at38; + +#ifndef FXCG +#ifdef CAS38_DISABLED + define_alias_gen(alias_vx38,_IDNT,0,&ref_x38); +#else + define_alias_gen(alias_vx38,_IDNT,0,&ref_xx38); +#endif +#endif + +#if defined NSPIRE || defined FXCG +#ifdef NSPIRE + // gen & vx_var = * (gen *) & alias_vx38; + gen vx_var; +#else + gen & get_vx_var(){ + static gen * ptr=0; + if (!ptr){ + ptr=new gen(identificateur("x")); + } + //* ((char *)ptr->_IDNTptr->id_name)=xthetat?'t':'x'; + return * ptr; + } +#endif +#else + gen vx_var(identificateur("x")); +#endif + + /* model + static const alias_identificateur alias_identificateur_zzz38={0,0,"ZZZ",0,0}; + const identificateur & zzz__IDNT=* (const identificateur *) &alias_identificateur_zzz38; + const alias_ref_identificateur ref_zzz38={-1,0,0,"ZZZ",0,0}; + const define_alias_gen(alias_zzz38,_IDNT,0,&ref_zzz38); + const gen & zzz__IDNT_e = * (gen *) & alias_zzz38; + + */ + +#else // GIAC_HAS_STO_38 + identificateur a__IDNT("a"); + gen a__IDNT_e(a__IDNT); + identificateur b__IDNT("b"); + gen b__IDNT_e(b__IDNT); + identificateur c__IDNT("c"); + gen c__IDNT_e(c__IDNT); + identificateur d__IDNT("d"); + gen d__IDNT_e(d__IDNT); + identificateur e__IDNT("e"); + gen e__IDNT_e(e__IDNT); + identificateur f__IDNT("f"); + gen f__IDNT_e(f__IDNT); + identificateur g__IDNT("g"); + gen g__IDNT_e(g__IDNT); + identificateur h__IDNT("h"); + gen h__IDNT_e(h__IDNT); + identificateur i__IDNT("i"); + gen i__IDNT_e(i__IDNT); + identificateur j__IDNT("j"); + gen j__IDNT_e(j__IDNT); + identificateur k__IDNT("k"); + gen k__IDNT_e(k__IDNT); + identificateur l__IDNT("l"); + gen l__IDNT_e(l__IDNT); + identificateur m__IDNT("m"); + gen m__IDNT_e(m__IDNT); + identificateur n__IDNT("n"); + gen n__IDNT_e(n__IDNT); + identificateur o__IDNT("o"); + gen o__IDNT_e(o__IDNT); + identificateur p__IDNT("p"); + gen p__IDNT_e(p__IDNT); + identificateur q__IDNT("q"); + gen q__IDNT_e(q__IDNT); + identificateur r__IDNT("r"); + gen r__IDNT_e(r__IDNT); + identificateur s__IDNT("s"); + gen s__IDNT_e(s__IDNT); + identificateur t__IDNT("t"); + gen t__IDNT_e(t__IDNT); + identificateur u__IDNT("u"); + gen u__IDNT_e(u__IDNT); + identificateur v__IDNT("v"); + gen v__IDNT_e(v__IDNT); + identificateur w__IDNT("w"); + gen w__IDNT_e(w__IDNT); + identificateur x__IDNT("x"); + gen x__IDNT_e(x__IDNT); + identificateur y__IDNT("y"); + gen y__IDNT_e(y__IDNT); + identificateur z__IDNT("z"); + gen z__IDNT_e(z__IDNT); +#ifdef FXCG + identificateur laplace_var("S"); +#else + identificateur laplace_var(" s"); +#endif + gen laplace_var_e(laplace_var); + identificateur theta__IDNT("ฮธ"); + gen theta__IDNT_e(theta__IDNT); + identificateur CST__IDNT("CST"); + gen CST__IDNT_e(CST__IDNT); + identificateur _IDNT_id_at("id_at"); + gen vx_var(x__IDNT_e); +#endif // GIAC_HAS_STO_38 + + const gen * const tab_one_letter_idnt[]={&a__IDNT_e,&b__IDNT_e,&c__IDNT_e,&d__IDNT_e,&e__IDNT_e,&f__IDNT_e,&g__IDNT_e,&h__IDNT_e,&i__IDNT_e,&j__IDNT_e,&k__IDNT_e,&l__IDNT_e,&m__IDNT_e,&n__IDNT_e,&o__IDNT_e,&p__IDNT_e,&q__IDNT_e,&r__IDNT_e,&s__IDNT_e,&t__IDNT_e,&u__IDNT_e,&v__IDNT_e,&w__IDNT_e,&x__IDNT_e,&y__IDNT_e,&z__IDNT_e}; + + identificateur::identificateur(){ + int_string_shortint_bool * ptr = new int_string_shortint_bool; + ptr->i=1; + ptr->b=0; + ptr->s_dynalloc=true; +#if defined GIAC_HAS_STO_38 || defined NSPIRE + string tmp=string("_"+print_INT_(std_rand())); +#else + string tmp=string(" "+print_INT_(std_rand())); +#endif + int l=int(tmp.size()); + char * c = new char[l+1]; + strcpy(c,tmp.c_str()); + ptr->s=c; + ref_count_ptr = &ptr->i ; + value = NULL; + quoted = &ptr->b ; + localvalue = 0; + id_name = ptr->s ; + } + + identificateur::identificateur(const string & s){ + bool b=strchr(s.c_str(),' ')?true:false; + int_string_shortint_bool * ptr = new int_string_shortint_bool; + ptr->i=1; + ptr->b=0; + ptr->s_dynalloc=true; + char * c = new char[s.size()+(b?3:1)]; +#if defined NSPIRE || defined FXCG + if (b){ + string s1=('`'+s+'`'); + ptr->s=strcpy(c,s1.c_str()); + } + else + ptr->s=strcpy(c,s.c_str()); +#else + ptr->s=strcpy(c,b?('`'+s+'`').c_str():s.c_str()); +#endif +#if defined GIAC_HAS_STO_38 || defined NSPIRE || defined FXCG + for (;*c;++c){ + if (*c==' ') + *c='_'; + } +#endif + ref_count_ptr = &ptr->i ; + value = NULL; + quoted = &ptr->b ; + localvalue = 0; + id_name = ptr->s ; + } + + identificateur::identificateur(const string & s,const gen & e){ + bool b=strchr(s.c_str(),' ')?true:false; + int_string_shortint_bool * ptr = new int_string_shortint_bool; + ptr->i=1; + ptr->b=0; + ptr->s_dynalloc=true; + char * c = new char[s.size()+(b?3:1)]; +#if defined NSPIRE || defined FXCG + if (b){ + string s1=('`'+s+'`'); + ptr->s=strcpy(c,s1.c_str()); + } + else + ptr->s=strcpy(c,s.c_str()); +#else + ptr->s=strcpy(c,b?('`'+s+'`').c_str():s.c_str()); +#endif + /* #if defined GIAC_HAS_STO_38 || defined NSPIRE + for (;*c;++c){ + if (*c==' ') + *c='_'; + } + #endif */ + ref_count_ptr = &ptr->i ; + quoted = &ptr->b ; + localvalue = 0; + id_name = ptr->s ; + value = new gen(e); + } + + identificateur::identificateur(const char * s){ + if (strchr(s,' ')){ + ref_count_ptr=0; + string S(s); +#if defined GIAC_HAS_STO_38 || defined NSPIRE || defined FXCG + for (unsigned i=0;ii=1; + ptr->b=0; + ptr->s=s; + ptr->s_dynalloc=false; + ref_count_ptr = &ptr->i ; + value = NULL; + quoted = &ptr->b ; + localvalue = 0; + id_name = ptr->s ; + } + +#ifdef GIAC_HAS_STO_38 + identificateur::identificateur(const char * s, bool StringIsNowYours){ + if (strchr(s,' ')){ + ref_count_ptr=0; + string S(s); + // #ifdef GIAC_HAS_STO_38 + for (unsigned i=0;ii=1; + ptr->b=0; + ptr->s=s; + ptr->s_dynalloc= StringIsNowYours; + ref_count_ptr = &ptr->i ; + value = NULL; + quoted = &ptr->b ; + localvalue = 0; + id_name = ptr->s ; + } +#endif + + identificateur::identificateur(const char * s,const gen & e){ + if (strchr(s,' ')){ + ref_count_ptr=0; + *this=identificateur(string(s),e); + return; + } + int_string_shortint_bool * ptr = new int_string_shortint_bool; + ptr->i=1; + ptr->b=0; + ptr->s=s; + ptr->s_dynalloc=false; + ref_count_ptr = &ptr->i ; + quoted = &ptr->b ; + localvalue = 0; + id_name = ptr->s ; + value = new gen(e); + } + + identificateur::identificateur(const identificateur & s){ + ref_count_ptr=s.ref_count_ptr; + if (ref_count_ptr) + ++(*ref_count_ptr); + value=s.value; + quoted=s.quoted; + localvalue=s.localvalue; + id_name=s.id_name; + } + + identificateur::~identificateur(){ + if (ref_count_ptr){ + --(*ref_count_ptr); + if (!(*ref_count_ptr)){ + int_string_shortint_bool * ptr = (int_string_shortint_bool *) ref_count_ptr; + if (ptr->s_dynalloc) + delete [] ptr->s; + delete ptr; + if (value) + delete value; + if (localvalue) + delete localvalue; + } + } + } + + void identificateur::MakeCopyOfNameIfNotLocal() { + int_string_shortint_bool * ptr = (int_string_shortint_bool *) ref_count_ptr; + if (ptr->s_dynalloc) return; + id_name = ptr->s= strdup(ptr->s); + ptr->s_dynalloc= true; + } + + identificateur & identificateur::operator =(const identificateur & s){ + if (ref_count_ptr){ + --(*ref_count_ptr); + if (!(*ref_count_ptr)){ + int_string_shortint_bool * ptr = (int_string_shortint_bool *) ref_count_ptr; + if (ptr->s_dynalloc) + delete [] ptr->s; + delete ptr; + if (value) + delete value; + if (localvalue) + delete localvalue; + } + } + ref_count_ptr=s.ref_count_ptr; + if (ref_count_ptr) + ++(*ref_count_ptr); + value=s.value; + quoted=s.quoted; + localvalue=s.localvalue; + id_name=s.id_name; + return *this; + } + + gen globalize(const gen & g){ + gen tmp(g); + switch (tmp.type){ + case _IDNT: + tmp.subtype=_GLOBAL__EVAL; + break; + case _VECT: + if (lidnt(tmp).empty()) + return g; + tmp=apply(tmp,globalize); + break; + case _SYMB: + if (tmp._SYMBptr->sommet!=at_program) + tmp=symbolic(tmp._SYMBptr->sommet,globalize(tmp._SYMBptr->feuille)); + break; + } + return tmp; + } + + // make g identificateurs evaluated as global + gen global_eval(const gen & g,int level){ + if (g.type<_IDNT) + return g; + bool save_local_eval=local_eval(context0); + local_eval(false,context0); + gen tmp; +#ifndef NO_STDEXCEPT + try { +#endif + tmp=g.eval(level,context0); +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & e){ + cerr << e.what() << '\n'; + // eval_level(level,contextptr); + } +#endif + local_eval(save_local_eval,context0); + return globalize(tmp); + } + + bool check_not_assume(const gen & not_evaled,gen & evaled, bool evalf_after,const context * contextptr); + + // make g identificateurs evaluated as global + gen global_evalf(const gen & g,int level){ + if (g.type<_IDNT) + return g; + bool save_local_eval=local_eval(context0); + local_eval(false,context0); + gen tmp; +#ifndef NO_STDEXCEPT + try { +#endif + tmp=g.eval(level,context0); + if (tmp.type==_IDNT){ + gen evaled(tmp._IDNTptr->eval(level,tmp,context0)); + if (check_not_assume(tmp,evaled,true,context0)) + tmp=evaled; + } +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & e){ + cerr << e.what() << '\n'; + // eval_level(level,contextptr); + } +#endif + local_eval(save_local_eval,context0); + return globalize(tmp); + } + + gen _prod(const gen & args,GIAC_CONTEXT); +#if 0 + static inline bool eval_38(int level,const gen & orig,gen & res,const char * s,GIAC_CONTEXT){ + if (storcl_38 && storcl_38(res,0,s,undef,false,contextptr,NULL)){ + return true; + } + return false; + size_t ss=strlen(s); +#ifdef GIAC_HAS_STO_38 + if ( + (ss>1 && s[0]=='G') +#ifndef CAS38_DISABLED + || (ss==1 && s[0]>='a' && s[0]<='z') +#endif + ){ // checking for a geometry global variables + if (contextptr){ + sym_tab::const_iterator it=contextptr->globalcontextptr->tabptr->find(s); + if (it!=contextptr->globalcontextptr->tabptr->end()){ + res=it->second; + return true; + } + } + res=orig; + return false; + } +#endif + if (calc_mode(contextptr)!=38 || !strcmp(s,string_pi) || !strcmp(s,string_euler_gamma) || !strcmp(s,string_infinity) || !strcmp(s,string_undef)){ + res=orig; + return false; + } + if (ss<=1){ + if (s[0]>'Z'){ + res=orig; + return false; + } + res=0.0; + return true; + } + if (ss==2 && s[1]<='9') { + res=orig; + gen tmp,evaled; + switch(s[0]){ + case 'C': case 'L': + res=gen(vecteur(0),_LIST__VECT); + break; + case 'E': case 'H': /* case 'S': */ + return false; + case 'G': // FIXME: grob + return false; + case 'F': case 'R': case 'U': case 'X': case 'Y': + if (calc_mode(contextptr)==38) + res=gensizeerr(gettext("Function not defined")); + return true; + case 'M': + res=makevecteur(makevecteur(0)); + break; + case 'V': + res=makevecteur(0); + break; + case 'Z': + res=0.0; + break; + case 'i': + res=(s[1]-'0')*cst_i; + break; + case 'e': + res=(s[1]-'0')*std::exp(1.0); + break; + default: + tmp=identificateur(string(1,s[0])); + if (tmp._IDNTptr->in_eval(1,tmp,evaled,contextptr)) + res=(s[1]-'0')*evaled; + else + res=0.0; + } + return true; + } + char ch; + for (size_t i=0;i'Z' && ch!='i' && ch!='e')|| ch<'0'){ + res=orig; + return false; + } + } + // all chars are regular 38 characters, split as a product + vecteur args; + gen g; + for (size_t i=0;i='E' && ch<='H') || ch=='L' || ch=='M' || ch=='R' + /* || ch=='S' */ + || ch=='U' || ch=='V' || (ch>='X' && ch<='Z')){ + string name; + name += ch; + char c=0; + if (i='0' && c<='9'){ + name += c; + ++i; + } + g=identificateur(name); + g=g.eval(level,contextptr); + args.push_back(g); + } + else { + string coeff; + for (++i;i32 && my_isalpha(s[i])){ + --i; + break; + } + coeff += s[i]; + } + if (coeff.empty()) + g=1; + else + g=atof(coeff.c_str()); + if (ch=='i') + g=g*cst_i; + else { + if (ch=='e') + g=std::exp(1.0)*g; + else { + coeff=""; + coeff += ch; + gen tmp=identificateur(coeff),evaled; + if (tmp._IDNTptr->in_eval(1,tmp,evaled,contextptr)) + g=g*evaled; + else + g=0.0; + } + } + args.push_back(g); + } + } + res=_prod(args,contextptr); + return true; + } +#endif + + gen identificateur::eval(int level,const gen & orig,const context * contextptr) { + if (!ref_count_ptr && !contextptr) + return orig; + gen evaled; + // cerr << "idnt::eval " << *this << " " << level << '\n'; + if (level<=0){ + if (level==0) + return orig; + // If 38 is there, let it look at the current state and decide if it needs to evaluate the name or if it needs to let the CAS do it + // This will depend on the order of priorities and the status of the requested variable (local/global...) +#ifndef FXCG + if (storcl_38 && abs_calc_mode(contextptr)==38 && storcl_38(evaled,NULL,id_name,undef,false,contextptr,NULL,false)) return evaled; +#endif + if (contextptr){ + sym_tab::const_iterator it=contextptr->tabptr->find(id_name),itend=contextptr->tabptr->end(); + if (it!=itend) + return it->second; + //if (abs_calc_mode(contextptr)==38){ + // gen evaled; + // if (eval_38(level,orig,evaled,id_name,contextptr)) + // return evaled; + //} + return orig; + } + else { + if (!localvalue || localvalue->empty()) + return orig; + iterateur jtend=localvalue->end(); + return (protection_level>(jtend-2)->val)?localvalue->back():orig; + } + } + --level; + if (in_eval(level,orig,evaled,contextptr)) + return evaled; + else + return *this; + /* + int save_level=eval_level(contextptr); + eval_level(level,contextptr); + gen res=in_eval(level,contextptr); + eval_level(save_level,contextptr); + return res; + */ + } + + // if globalize is true, use global value in eval + gen do_local_eval(const identificateur & i,int level,bool globalize) { + if (!i.localvalue) + return i; + gen res; + iterateur jtend=i.localvalue->end(); + if (protection_level>(jtend-2)->val) + res=i.localvalue->back(); + else { + for (iterateur jt=i.localvalue->begin();;){ + if (jt==jtend) + break; + --jtend; + --jtend; + if (protection_level>jtend->val){ + ++jtend; + ++jtend; + break; + } + } + i.localvalue->erase(jtend,i.localvalue->end()); + if (!i.localvalue->empty()) + res=i.localvalue->back(); + } + return globalize?global_eval(res,level):res; + } + + void printsymtab(sym_tab * ptr){ + sym_tab::const_iterator it=ptr->begin(),itend=ptr->end(); + for (;it!=itend;++it) + CERR << it->first << ":" << it->second << '\n'; + } + + bool identificateur::in_eval(int level,const gen & orig,gen & evaled,const context * contextptr, bool No38Lookup) { + // if (!ref_count_ptr) return false; // does not work for cst ref identificateur + if (contextptr){ // Look for local variables... + // If 38 is there, let it look at variable priorities, but ONLY looking at local for the moment! We do not want to look as globals as they might need to be quoted... +#ifndef FXCG + if (storcl_38!=NULL && !No38Lookup && abs_calc_mode(contextptr)==38 && storcl_38(evaled,NULL,id_name,undef,false,contextptr, NULL, true)) + return true; +#endif + const context * cur=contextptr; + int pythoncompat=python_compat(contextptr)?2:0; + for (;cur->previous;cur=cur->previous){ + sym_tab::const_iterator it=cur->tabptr->find(id_name); + if (it!=cur->tabptr->end()){ + if (!level || !it->second.in_eval(level,evaled,contextptr->globalcontextptr)) + evaled=it->second; + return true; + } + if (pythoncompat){ + --pythoncompat; + if (!pythoncompat){ + while (cur->previous) + cur=cur->previous; + break; + } + } + } + // now at global level + // check for quoted + if (cur->quoted_global_vars && !cur->quoted_global_vars->empty() && equalposcomp(*cur->quoted_global_vars,orig)) + return false; + // If 38 is there, look again, but now it is allowed to look at local and globals! +#ifndef FXCG + if (storcl_38!=NULL && !No38Lookup && abs_calc_mode(contextptr)==38 && storcl_38(evaled,NULL,id_name,undef,false,contextptr, NULL, false)) + return true; +#endif + // printsymtab(cur->tabptr); + sym_tab::const_iterator it=cur->tabptr->find(id_name); + if (it==cur->tabptr->end()){ + //if (No38Lookup) return false; + //if (storcl_38 && abs_calc_mode(contextptr)==38) + // return eval_38(level,orig,evaled,id_name,contextptr); + return false; + } + else { + if (!it->second.in_eval(level,evaled,contextptr->globalcontextptr)) + evaled=it->second; + return true; + } + //if (!No38Lookup && storcl_38){ // && abs_calc_mode(contextptr)==38) + // if (eval_38(level,orig,evaled,id_name,contextptr)) + // return true; + //} + } + if (local_eval(contextptr) && localvalue && !localvalue->empty()){ + evaled=do_local_eval(*this,level,true); + return true; + } + if (quoted && *quoted & 1) + return false; +#ifndef FXCG + if (current_folder_name.type==_IDNT && current_folder_name._IDNTptr->value && current_folder_name._IDNTptr->value->type==_VECT){ + evaled=find_in_folder(*current_folder_name._IDNTptr->value->_VECTptr,orig); + return (evaled!=orig); + } +#endif + if (value){ + evaled=value->eval(level,contextptr); + return true; + } + // look in current directory for a value + if ( secure_run || (!variables_are_files(contextptr)) +#if !defined __MINGW_H && !defined NSPIRE && !defined FXCG + || (access((name()+string(cas_suffixe)).c_str(),R_OK)) +#endif + ){ + evaled=orig; + if (!local_eval(contextptr)) + evaled.subtype=_GLOBAL__EVAL; + return true; + } +#if !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 + // set current value + ifstream inf((name()+string(cas_suffixe)).c_str()); + evaled=read1arg_from_stream(inf,contextptr); + if (child_id) + return true; + value = new gen(evaled); + evaled=evaled.eval(level,contextptr); +#endif + return true; + } + + void identificateur::push(int protection,const gen & e){ + if (!localvalue) + localvalue=new vecteur; + localvalue->push_back(protection); + localvalue->push_back(e); + } + + const char * identificateur::print(GIAC_CONTEXT) const{ + if (!strcmp(id_name,string_pi)){ +#if defined NUMWORKS || defined HP39 + return string_pi; +#endif +#if !defined KHICAS + if (abs_calc_mode(contextptr)==38) +#endif + return "ฯ€"; + switch (xcas_mode(contextptr)){ + case 1: + return "Pi"; + case 2: + return "PI"; + default: + return string_pi; + } + } + if ( + //calc_mode(contextptr)!=1 && + abs_calc_mode(contextptr)==38 && + !strcmp(id_name,string_infinity)) + return "ยฑโˆž"; + // index != sqrt(-1) wich has different notations + if (xcas_mode(contextptr)==0){ + if (strcmp(id_name,"i")==0) + return "i_i_"; + } + else { + if (strcmp(id_name,"I")==0) + return "i_i_"; + } + /* + if (!localvalue->empty()) + return string("_") + *name ; + if (value) + return string("~") + *name ; + else + */ + return id_name ; + } + +#ifdef NSPIRE + template + nio::ios_base & operator << (nio::ios_base & os,const identificateur & s) { return os << s.print(context0);} +#else + ostream & operator << (ostream & os,const identificateur & s) { return os << s.print(context0);} +#endif + + int removecomments(const char * ss,char * ss2){ + int j=0,k=0; + for (;ss[j];j++){ + if (ss[j]=='#'){ + ss2[k]=char(0); // end ss2 string + break; + } + if (ss[j]>31){ // supress control chars + ss2[k]=ss[j]; + k++; + } + } + return k; + } + + void identificateur::unassign(){ + if (value){ + delete(value); + value = NULL; + } + } + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/ifactor.cc b/android/app/src/main/cpp/giac/src/giac/cpp/ifactor.cc new file mode 100644 index 0000000..7ff31d7 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/ifactor.cc @@ -0,0 +1,5465 @@ +// -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c ifactor.cc -DHAVE_CONFIG_H -DIN_GIAC" -*- +#include "giacPCH.h" +#if defined NSPIRE_NEWLIB || !defined KHICAS +#define GIAC_MPQS // define if you want to use giac for sieving +#endif + +#ifdef BF2GMP_H +#undef HAVE_LIBECM +#undef HAVE_LIBBERNMM +#endif + +#if defined HAVE_LIBECM +#include +#endif + +#if defined HAVE_LIBBERNMM +#include +#include +#endif + +#include "path.h" +/* + * Copyright (C) 2003,14 R. De Graeve & B. Parisse, + * Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using namespace std; +#ifdef GIAC_HAS_STO_38 +//#undef clock +//#undef clock_t +#else +#include +//#include // For reading arguments from file +#include "ifactor.h" +#include "pari.h" +#include "usual.h" +#include "sym2poly.h" +#include "rpn.h" +#include "prog.h" +#include "misc.h" +#include "giacintl.h" +#endif + +#ifdef GIAC_HAS_STO_38 +#define BESTA_OS +#endif +// Trying to make ifactor(2^128+1) work on ARM +#if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE +//#define OLD_AFACT +#define GIAC_ADDITIONAL_PRIMES 16// if defined, additional primes are used in sieve +#else +#define GIAC_ADDITIONAL_PRIMES 32// if defined, additional primes are used in sieve +#endif + + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + +#if 0 + struct int256 { + longlong a; + ulonglong b,c,d; + }; + struct int128 { + longlong a; + ulonglong b; + }; + + void sub(int256 A,int b,int256 & C){ + bool Apos=A.a>=0; + if (Apos){ + if (b<0){ + add(A,b,C); + return; + } + bool carry=A.d=0; + if (Apos){ + if (b<0){ + sub(A,-b,C); + return; + } + A.d += b; + if (A.d>32; + p1=A1; + p = p1*p2; + p += C1; + unsigned short carry = (p>32; + C2 += carry; + carry = (C2 & crible,unsigned p){ + crible.resize((p-1)/64+1); + unsigned cs=crible.size(); + unsigned lastnum=64*cs; + unsigned lastsieve=int(std::sqrt(double(lastnum))); + unsigned primesieved=1; + crible[0] = 0xfffffffe; // 1 is not prime and not sieved (2 is not sieved) + for (unsigned i=1;i & crible,unsigned p){ + // assumes crible has been filled + ++p; + if (p%2==0) + ++p; + unsigned pos=(p-1)/2,cs=crible.size()*32; + if (2*cs+1<=p) + return nextprime(int(p)).val; + for (;pos + static void printbool(nio::ios_base & os,const vector & v,int C=1){ + if (C) + C=giacmin(C,int(v.size())); + else + C=v.size(); + for (int c=0;c> s & 1)==1)?1:0) << " "; + } + } + os << '\n'; + } + + template + void printbool(nio::ios_base & os,const vector< vector > & m,int L=32){ + if (L) + L=giacmin(L,int(m.size())); + else + L=m.size(); + for (int l=0;l & v,int C=1){ + if (C) + C=giacmin(C,int(v.size())); + else + C=int(v.size()); + for (int c=0;c> s & 1)==1)?1:0) << " "; + } + } + os << '\n'; + } + + void printbool(ostream & os,const vector< vector > & m,int L=32){ + if (L) + L=giacmin(L,int(m.size())); + else + L=int(m.size()); + for (int l=0;l + inline void swap(T * & ptr1, T * & ptr2){ + T * tmp=ptr1; + ptr1=ptr2; + ptr2=tmp; + } + +#ifdef x86_64 +#define GIAC_RREF_UNROLL 4 +#else +#define GIAC_RREF_UNROLL 4 +#endif + + // #define RREF_SORT +#ifdef RREF_SORT + struct line_t { + unsigned * tab; + unsigned count; + }; + + bool operator < (const line_t & l1,const line_t & l2){ + if (!l1.count) + return false; + if (!l2.count) + return true; + return l1.count>= 1; + } + } + return r; + } + +#else + struct line_t { + unsigned * tab; + }; +#endif + + + // mode=0: full reduction, 1 subreduction, 2 finish full reduction from subreduction + void rref(vector< line_t > & m,int L,int C32,int mode){ + int i,l=0,c=0,C=C32*32; + for (;l> c2) & 1) + break; + } + if (i==L){ // none found in this column + ++c; + continue; + } + if (i!=l) + swap(m[i].tab,m[l].tab); // don't care about count... + int start=mode==1?l+1:0, end=mode==2?l:L; +#ifdef x86_64 + ulonglong * pivend, * pivbeg; + pivbeg = (ulonglong *) (m[l].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL); + pivend = (ulonglong *) (m[l].tab+C32); +#else + unsigned * pivbeg = m[l].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL, * pivend = m[l].tab+C32; +#endif + for (i=start;i> c2) & 1)!=1) + continue; + // line combination l and i +#ifdef x86_64 + ulonglong * curptr=(ulonglong *) (m[i].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL); + for (ulonglong * pivptr=pivbeg;pivptr!=pivend;curptr += GIAC_RREF_UNROLL/2,pivptr += GIAC_RREF_UNROLL/2){ + // small optimization (loop unroll), assumes mult of 4(*32) columns + // PREFETCH(curptr+8); + *curptr ^= *pivptr; + curptr[1] ^= pivptr[1]; +#if GIAC_RREF_UNROLL==8 + curptr[2] ^= pivptr[2]; + curptr[3] ^= pivptr[3]; +#endif + } +#else + unsigned * curptr=m[i].tab+(c1/GIAC_RREF_UNROLL)*GIAC_RREF_UNROLL; + for (unsigned * pivptr=pivbeg;pivptr!=pivend;curptr += GIAC_RREF_UNROLL,pivptr += GIAC_RREF_UNROLL){ + // small optimization (loop unroll), assumes mult of 4(*32) columns + // PREFETCH(curptr+16); + *curptr ^= *pivptr; + curptr[1] ^= pivptr[1]; + curptr[2] ^= pivptr[2]; + curptr[3] ^= pivptr[3]; +#if GIAC_RREF_UNROLL==8 + curptr[4] ^= pivptr[4]; + curptr[5] ^= pivptr[5]; + curptr[6] ^= pivptr[6]; + curptr[7] ^= pivptr[7]; +#endif + } +#endif + } + ++l; + ++c; + } + } + + template + void release_memory(vector & slice){ + // release memory from slice + vector tmp; + swap(slice,tmp); + } + +#ifdef USE_GMP_REPLACEMENTS + int modulo(const mpz_t & a,unsigned b){ + if (mpz_cmp_ui(a,0)<0){ + mpz_neg(*(mpz_t *)&a,a); + int res=modulo(a,b); + mpz_neg(*(mpz_t *)&a,a); + return b-res; + } + mp_digit C; + mp_mod_d((mp_int *)&a,b,&C); + return C; + } +#else + int modulo(const mpz_t & a,unsigned b){ + return mpz_fdiv_ui(a,b); + } +#endif + + int modulo(const gen & a,unsigned b){ + if (a.type==_INT_) + return a.val % b; + return modulo(*a._ZINTptr,b); + } + +#if defined RTOS_THREADX || defined BESTA_OS || defined NSPIRE + typedef unsigned short pui_t ; + typedef unsigned short ushort_t; + typedef short short_t; +#else + typedef unsigned pui_t ; + // #ifndef USE_GMP_REPLACEMENTS // uncomment for Aspen debugging +#define PRIMES32 + // #endif +#ifdef PRIMES32 + typedef unsigned ushort_t; + typedef int short_t; +#else + typedef unsigned short ushort_t; + typedef unsigned short int short_t; +#endif + +#if defined(EMCC) || defined(EMCC2) +#include +#endif +#if (defined EMCC || defined EMCC2 || defined(HASH_MAP_NAMESPACE)) && defined(PRIMES32) && !defined(ADDITIONAL_PRIMES_HASHMAP) +#define ADDITIONAL_PRIMES_HASHMAP +#endif +#endif // RTOS_THREADX || BESTA_OS + + struct axbinv { +#if 0 + unsigned short aindex; + unsigned short bindex; +#else + unsigned aindex; + unsigned bindex; +#endif + int shiftpos; + pui_t first,second; // indexes in the "puissancestab" table + axbinv(ushort_t a_,int shiftpos_,ushort_t b_,pui_t f_,pui_t s_):aindex(a_),bindex(b_),shiftpos(shiftpos_),first(f_),second(s_) {}; + axbinv() {}; + }; + +#ifdef ADDITIONAL_PRIMES_HASHMAP + unsigned largep(const axbinv & A,ushort_t * puissancestab) { + // return A.largeprime; + if (A.second-A.first<3) return 0; +#ifdef PRIMES32 + if (*(puissancestab+A.second-2)!=1) + return 0; + return *(puissancestab+A.second-1); +#else + if (*(puissancestab+A.second-3)!=1) + return 0; + return (unsigned(*(puissancestab+A.second-2)) << 16) + *(puissancestab+A.second-1); +#endif + } +#endif + +#ifdef ADDITIONAL_PRIMES_HASHMAP +#if defined(EMCC) || defined(EMCC2) // container does not seem to be important for <= 70 digits + typedef map additional_map_t; +#else + typedef HASH_MAP_NAMESPACE::hash_map additional_map_t ; +#endif +#endif + +#if !defined(RTOS_THREADX) && !defined(BESTA_OS) && !defined NSPIRE + // #define WITH_INVA +#if defined(__APPLE__) || defined(x86_64) +#define LP_TAB_SIZE 15 // slice size will be 2^LP_TAB_SIZE + // #define LP_SMALL_PRIMES +#define LP_TAB_TOGETHER +#define USE_MORE_PRIMES +#else +#define LP_TAB_SIZE 15 // slice size will be 2^LP_TAB_SIZE +#endif // APPLE or 64 bits +#endif // !defined RTOS_THREADX and BESTA_OS + +#ifdef LP_TAB_SIZE +#define LP_MASK ((1< lp_tab_t; +#endif + +#ifdef LP_TAB_SIZE +#define LP_BIT_LIMIT 15 +#else +#define LP_BIT_LIMIT 15 +#endif + +#if GIAC_ADDITIONAL_PRIMES==16 + typedef unsigned short additional_t; +#else + typedef int additional_t; +#endif + + inline int _equalposcomp(const std::vector & v, additional_t w){ + int n=1; + for (std::vector::const_iterator it=v.begin(),itend=v.end();it!=itend;++it){ + if ((*it)==w) + return n; + else + n++; + } + return 0; + } + + // #define SQRTMOD_OUTSIDE +#define WITH_LOGP // if defined primes should not exceed 2^24 (perhaps 2^25, choice of sqrt) + + struct small_basis_t { + unsigned short root1; + unsigned short root2; + unsigned short p; + unsigned short logp; + }; + +#ifdef SQRTMOD_OUTSIDE + struct basis_t { + unsigned root1; // first root position in slice + unsigned root2; // second root position + ushort_t p:24; // the prime p +#ifdef WITH_LOGP + unsigned char logp:8; // could be unsigned char +#endif + basis_t():root1(0),root2(0),p(2) { +#ifdef WITH_LOGP + logp=sizeinbase2(p); +#endif + } + basis_t(ushort_t _p):root1(0),root2(0),p(_p) { +#ifdef WITH_LOGP + logp=sizeinbase2(p); +#endif + } + } ; + +#else // SQRTMOD_OUTSIDE + struct basis_t { + unsigned root1; // first root position in slice + unsigned root2; // second root position + ushort_t p; // the prime p + unsigned sqrtmod:24; +#ifdef WITH_LOGP + unsigned char logp:8; // could be unsigned char +#endif + basis_t():root1(0),root2(0),p(2),sqrtmod(0) { +#ifdef WITH_LOGP + logp=sizeinbase2(p); +#endif + } + basis_t(ushort_t _p):root1(0),root2(0),p(_p),sqrtmod(0) { +#ifdef WITH_LOGP + logp=sizeinbase2(p); +#endif + } + basis_t(ushort_t _p,ushort_t _sqrtmod):root1(0),root2(0),p(_p),sqrtmod(_sqrtmod) { +#ifdef WITH_LOGP + logp=sizeinbase2(p); +#endif +} + } ; +#endif // SQRTMOD_OUTSIDE + +#ifdef LP_SMALL_PRIMES + static inline void core_sieve(slicetype * slice,small_basis_t * bit,small_basis_t * bitend) { + for (;bit!=bitend;++bit){ + // first root is at bit->root1 + register unsigned p=bit->p; + register unsigned char nbits=bit->logp; + register unsigned pos=bit->root1,pos2=bit->root2; + if (pos==pos2){ + for (;pos<32768; pos += p){ + slice[pos] -= nbits; + } + bit->root2=bit->root1 = pos-32768; // save for next slice + } + else { + for (;pos<32768; pos += p){ + slice[pos] -= nbits; + } + bit->root1 = pos-32768; // save for next slice + // second root, polynomial has 2 distinct roots + for (;pos2<32768;pos2 += p){ + slice[pos2] -= nbits; + } + bit->root2 = pos2-32768; + } + } + } + +#else // LP_SMALL_PRIMES + +#ifdef LP_TAB_SIZE +#define SLICEEND (1<p); + // int next=1 << nbits; + for (;bit!=bitend;++bit){ + // first root is at bit->root1 + register ushort_t p=bit->p; +#ifdef WITH_LOGP + nbits=bit->logp; +#else + if (p>next){ + ++nbits; +#if !defined(BESTA_OS) && !defined(RTOS_THREADX) && !defined NSPIRE + if (nbits==LP_BIT_LIMIT+1) + break; +#endif + next *=2; + } +#endif + register unsigned pos=bit->root1,pos2=bit->root2; + if (pos==pos2){ + for (;int(pos)root2=bit->root1 = pos-SLICEEND; // save for next slice + } + else { + for (;int(pos)root1 = pos-SLICEEND; // save for next slice + // second root, polynomial has 2 distinct roots + for (;int(pos2)root2 = pos2-SLICEEND; + } + } +#if !defined(RTOS_THREADX) && !defined(BESTA_OS) && !defined NSPIRE +#ifndef LP_TAB_SIZE + for (;bit!=bitend;++bit){ + // same as above but we are sieving with primes >2^15, no need to check for nbits increase + register ushort_t p=bit->p; + register unsigned pos=bit->root1; + for (;posroot1 = pos-ss; // save for next slice + // if (sameroot) continue; + pos=bit->root2; + for (;posroot2 = pos-ss; + } +#endif +#endif + return bit; + } +#endif // LP_SMALL_PRIMES + + // sieve in [sqrtN+shift,sqrtN+shift+slice.size()-1] + // return -1 if memory problem, or the number of relations + int msieve(const gen & a,const vecteur & sqrtavals, + const vecteur &bvals,const mpz_t& c, + vector & basis,unsigned lp_basis_pos, +#ifdef LP_SMALL_PRIMES + vector & small_basis, +#endif + unsigned maxadditional, +#ifdef ADDITIONAL_PRIMES_HASHMAP + additional_map_t & additional_primes_map, +#else + vector & additional_primes,vector & additional_primes_twice, +#endif + const gen & N,const gen & isqrtN, + slicetype * slice,int ss,int shift, + ushort_t * puissancesbegin,ushort_t* & puissancesptr,ushort_t * puissancesend, + vector & curpuissances,vector &recheck, + vector & axbmodn, + mpz_t & z1,mpz_t & z2,mpz_t & z3,mpz_t & alloc1,mpz_t & alloc2,mpz_t & alloc3,mpz_t & alloc4,mpz_t & alloc5, +#ifdef LP_TAB_SIZE + const lp_tab_t & lp_tab, +#endif + GIAC_CONTEXT){ + int nrelations=0; + // first fill slice with expected number of bits of + // (isqrtN+shift)^2-N = 2*shift*isqrtN + negl. + // -> log(2*isqrtN)+log(shift) + int shiftss=absint(shift+ss),absshift=absint(shift); + int nbits=mpz_sizeinbase(*isqrtN._ZINTptr,2)+sizeinbase2(absshift>shiftss?absshift:shiftss); + // int nbits1=int(0.5+std::log(evalf_double(isqrtN,1,context0)._DOUBLE_val/2.*(absshift>shiftss?absshift:shiftss))/std::log(2.)); + // int curbits=0; + int bs=int(basis.size()); + double up_to=1.5; + if (nbits>70) + up_to += (0.8*(nbits-70))/70; + if (debug_infolevel>7) + *logptr(contextptr) << CLOCK() << gettext("Sieve tolerance factor ") << up_to << '\n'; + unsigned char logB=(unsigned char) (nbits-int(up_to*sizeinbase2(basis.back().p)+.5)); + // unsigned char logB=(unsigned char) (nbits-int(up_to*std::log(double(basis.back().p))/std::log(2.0)+.5)); + if (debug_infolevel>6) + *logptr(contextptr) << CLOCK() << gettext(" reset") << '\n'; + // assumes slice type is size 1 byte and multiple of 32 +#ifdef x86_64 + ulonglong * ptr=(ulonglong *) &slice[0]; + ulonglong * ptrend=ptr+ss/8; + ulonglong pattern=(logB <<24)|(logB<<16)|(logB<<8) | logB; + pattern = (pattern << 32) | pattern; + for (;ptr!=ptrend;++ptr){ + *ptr=pattern; + } +#else + unsigned * ptr=(unsigned *) &slice[0]; + unsigned * ptrend=ptr+ss/4; + unsigned pattern=(logB <<24)|(logB<<16)|(logB<<8) | logB; + for (;ptr!=ptrend;++ptr){ + *ptr=pattern; + } +#endif + if (debug_infolevel>8) + *logptr(contextptr) << CLOCK() << gettext(" end reset, nbits ") << nbits << '\n'; + // now for all primes p in basis move in slice from p to p + // decrease slice[] by number of bits in p + // determines the first prime used in basis +#if 0 // def WITH_LOGP + nbits=2*mpz_sizeinbase(*isqrtN._ZINTptr,2); + int next=50; + // note that msieve leaves 20 to 22 primes for normal range, and 15 for large + nbits = sizeinbase2(next); +#else + if (nbits>120) + nbits = 7; + else { + if (nbits>90) + nbits = 6; + else { + if (nbits>78) + nbits=5; + else + nbits = 4; + } + } + int next = 1 << (nbits-1); +#endif + unsigned bstart; + for (bstart=0;bstartnext){ + if (debug_infolevel>7) + *logptr(contextptr) << gettext("Sieve first prime ") << p << " nbits " << nbits << '\n'; + break; + } +#ifdef LP_SMALL_PRIMES + int pos=small_basis[bstart].root1; + pos=(pos-ss)%p; + if (pos<0) + pos+=p; + small_basis[bstart].root1=pos; + pos=small_basis[bstart].root2; + pos=(pos-ss)%p; + if (pos<0) + pos+=p; + small_basis[bstart].root2=pos; +#else + // update pos_root_mod for later check + int pos=basis[bstart].root1; + pos=(pos-ss)%p; + if (pos<0) + pos+=p; + basis[bstart].root1=pos; + pos=basis[bstart].root2; + pos=(pos-ss)%p; + if (pos<0) + pos+=p; + basis[bstart].root2=pos; +#endif + } + next *= 2; + if (debug_infolevel>8) + *logptr(contextptr) << CLOCK() << gettext(" sieve begin ") << '\n'; + // bool sameroot; // Should be there to avoid counting twice the same root but it's faster to ignore it..; +#ifdef LP_SMALL_PRIMES + small_basis_t * bit=&small_basis[bstart], * bitend=&small_basis[0]+small_basis.size(); + core_sieve(slice,bit,bitend); +#else + basis_t * bit=&basis[bstart], * bitend=&basis[0]+bs; +#ifdef LP_TAB_SIZE + bitend=core_sieve(slice,ss,bit,&basis[0]+lp_basis_pos); +#else + bitend=core_sieve(slice,ss,bit,bitend); +#endif +#endif + slicetype * st=slice, * stend=slice+ss; +#ifdef LP_TAB_SIZE + // sieve for large prime using saved position + if (!lp_tab.empty()){ + const lp_entry_t * lpit=&lp_tab[0],*lpitend=lpit+lp_tab.size(),*lpitend1=lpitend-8; + if (lpitend-lpit>8){ + for (;lpitpos] -= 16; + slice[lpit[1].pos] -= 16; + slice[lpit[2].pos] -= 16; + slice[lpit[3].pos] -= 16; + slice[lpit[4].pos] -= 16; + slice[lpit[5].pos] -= 16; + slice[lpit[6].pos] -= 16; + slice[lpit[7].pos] -= 16; + } + } + for (;lpitpos] -= 16; + } +#endif + unsigned cl=0; + if (debug_infolevel>6) + cl=CLOCK(); + if (debug_infolevel>8) + *logptr(contextptr) << cl << gettext("relations ") << '\n'; + // now find relations + st=slice; stend=slice+ss; +#ifdef x86_64 + ulonglong * st8=(ulonglong *) &slice[0],*st8end=st8+ss/8; +#else + unsigned * st4=(unsigned *) &slice[0],*st4end=st4+ss/4; +#endif + for ( +#ifdef x86_64 + ;st8!=st8end;st8+=4 +#else + ;st4 posss + int posss=ss-pos; // always positive + for (;basisptr!=basisend;++basisptr){ + register int bi=basisptr->p; + // check if we have a root + register int check=bi-(posss%bi); + if (check!=bi && check!=int(basisptr->root1) && check!=int(basisptr->root2)) + continue; + if (check==bi && basisptr->root1 && basisptr->root2) + continue; + recheck.push_back(bi); + } // end for on (small) primes +#ifdef LP_TAB_SIZE + // add primes from large prime hashtable + lp_tab_t::const_iterator lpit=lp_tab.begin(),lpend=lp_tab.end(); + int hash_pos=recheck.size(); + for (;lpit!=lpend;++lpit){ + if (pos==int(lpit->pos)){ + recheck.push_back(lpit->p); + } + } + if (int(recheck.size())>hash_pos+1) + sort(recheck.begin(),recheck.end()); +#endif + // now divide first by product of elements of recheck + double prod=1,nextprod=1; + for (unsigned k=0;k255){ + curpuissances.push_back(0); + done=true; + } + if (done){ + for (;j;--j) + curpuissances.push_back(bi); + } + else { + for (;j>=256;j-=256) + curpuissances.push_back(bi<<8); + if (j) + curpuissances.push_back( (bi << 8) | j); + } + } + if (small_) + mpz_set_si(z1,Z1); + if (mpz_cmp_si(z1,1)==0){ // is_one(tmp)){ + ++nrelations; + if (debug_infolevel>6) + *logptr(contextptr) << CLOCK() << gettext(" true relation ") << '\n'; + axbmodn.push_back(axbinv(int(sqrtavals.size())-1,shiftpos,int(bvals.size())-1,int(puissancesptr-puissancesbegin),int(puissancesptr-puissancesbegin)+int(curpuissances.size()))); + for (unsigned i=0;i=puissancesend) + return -1; + *puissancesptr=curpuissances[i]; + } + } + else { + unsigned param2; +#if (GIAC_ADDITIONAL_PRIMES==16) + param2=0xffff; +#else + param2=maxadditional; +#endif + if (mpz_cmp_ui(z1,param2)>0){ + if (debug_infolevel>6) + *logptr(contextptr) << gen(z1) << gettext(" Sieve large remainder:") << '\n'; + } + else { +#ifdef GIAC_ADDITIONAL_PRIMES + additional_t P=mpz_get_ui(z1); + // if (int(P)>2*int(basis.back())) continue; + // if (debug_infolevel>5) + if (debug_infolevel>6) + *logptr(contextptr) << CLOCK() << " " << P << " remain " << '\n'; +#ifdef ADDITIONAL_PRIMES_HASHMAP + // add relation + ++nrelations; + curpuissances.push_back(1); // marker +#if (GIAC_ADDITIONAL_PRIMES==32) +#ifndef PRIMES32 + curpuissances.push_back(P >> 16); +#endif +#endif + curpuissances.push_back(P); + for (unsigned i=0;i=puissancesend) + return -1; + *puissancesptr=curpuissances[i]; + } + additional_map_t::iterator it=additional_primes_map.find(P),itend=additional_primes_map.end(); + if (it!=itend) // build a large prime relation (P is the large prime) + axbmodn.push_back(axbinv(sqrtavals.size()-1,shiftpos,bvals.size()-1,(puissancesptr-puissancesbegin)-curpuissances.size(),(puissancesptr-puissancesbegin))); + else // record a partial relation + additional_primes_map[P]=axbinv(sqrtavals.size()-1,shiftpos,bvals.size()-1,(puissancesptr-puissancesbegin)-curpuissances.size(),(puissancesptr-puissancesbegin)); +#else + int Ppos=_equalposcomp(additional_primes,P); // this is in O(additional^2)=o(B^3) + if (Ppos){ + if (debug_infolevel>6) + *logptr(contextptr) << P << gettext(" already additional") << '\n'; + --Ppos; + additional_primes_twice[Ppos]=true; + } else { + // add a prime in additional_primes if <=QS_B_BOUND + if (int(additional_primes.size())>=4*bs +#if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE + || bs+additional_primes.size()>700 +#endif + ) + continue; + additional_primes.push_back(P); + additional_primes_twice.push_back(false); + Ppos=int(additional_primes.size())-1; + } + // add relation + curpuissances.push_back(1); // marker +#if GIAC_ADDITIONAL_PRIMES==32 +#ifndef PRIMES32 + curpuissances.push_back(P >> 16); +#endif +#endif + curpuissances.push_back(P); + axbmodn.push_back(axbinv(int(sqrtavals.size())-1,shiftpos,int(bvals.size())-1,int(puissancesptr-puissancesbegin),int(puissancesptr-puissancesbegin)+int(curpuissances.size()))); + for (unsigned i=0;i=puissancesend) + return -1; + *puissancesptr=curpuissances[i]; + } +#endif // ADDITIONAL_PRIMES_HASHMAP +#endif // GIAC_ADDITIONAL_PRIMES + } + } + } + } // end for loop on slice array + if (debug_infolevel>6){ + unsigned cl2=CLOCK(); + *logptr(contextptr) << cl2 << gettext(" end relations ") << cl2-cl << '\n'; + } + return nrelations; + } + + // #define MP_MODINV_1 +#ifdef MP_MODINV_1 + static inline unsigned mp_modinv_1(unsigned a, unsigned p) { + + unsigned ps1, ps2, dividend, divisor, rem, q, t; + unsigned parity; + + q = 1; rem = a; dividend = p; divisor = a; + ps1 = 1; ps2 = 0; parity = 0; + + while (divisor > 1) { + rem = dividend - divisor; + t = rem - divisor; + if (rem >= divisor) { q += ps1; rem = t; t -= divisor; + if (rem >= divisor) { q += ps1; rem = t; t -= divisor; + if (rem >= divisor) { q += ps1; rem = t; t -= divisor; + if (rem >= divisor) { q += ps1; rem = t; t -= divisor; + if (rem >= divisor) { q += ps1; rem = t; t -= divisor; + if (rem >= divisor) { q += ps1; rem = t; t -= divisor; + if (rem >= divisor) { q += ps1; rem = t; t -= divisor; + if (rem >= divisor) { q += ps1; rem = t; + if (rem >= divisor) { + q = dividend / divisor; + rem = dividend % divisor; + q *= ps1; + } + } + } + } + } + } + } + } + } + + q += ps2; + parity = ~parity; + dividend = divisor; + divisor = rem; + ps2 = ps1; + ps1 = q; + } + + if (parity == 0) + return ps1; + else + return p - ps1; + } +#endif + +#if (defined __i386__ || defined __x86_64__) && !defined PIC && !defined _I386_ && !defined __APPLE__ && !defined VISUALC && !defined(FIR_LINUX) && !defined(FIR_ANDROID) + #define _I386_ +#endif + +#ifdef _I386_ + // a->a+b*c mod m + inline void addmultmod(int & a,int b,int c,int m){ + asm volatile("testl %%ebx,%%ebx\n\t" /* sign bit=1 if negative */ + "jns .Lok%=\n\t" + "addl %%edi,%%ebx\n" /* a+=m*/ + ".Lok%=:\t" + "imull %%ecx; \n\t" /* b*c in edx:eax */ + "addl %%ebx,%%eax; \n\t" /* b*c+a */ + "adcl $0x0,%%edx; \n\t" /* b*c+a carry */ + "idivl %%edi; \n\t" + :"=d"(a) + :"a"(b),"b"(a),"c"(c),"D"(m) + ); + } +#endif + + inline + int modmult(int a,int b,unsigned p){ +#ifdef _I386_ + register int res; + asm volatile("imull %%edx\n\t" /* a*b-> edx:eax */ + "idivl %%ecx\n\t" /* edx:eax div p -> quotient=eax, remainder=edx */ + :"=d"(res) + :"a"(a),"d"(b),"c"(p) + : + ); + return res; +#else + return a*longlong(b) % p; +#endif + } + + // assumes b>0 and |a|0 so that all remainders below are >=0 + a+=b; +#ifdef _I386_ // works only for ushort_t == unsigned short + // int res=mp_modinv_1(a,b),p=b; + /* GDB: si will step in assembly, info registers show register content, x/i $pc show next ins */ + asm volatile("movl $0,%%edi\n\t" + "movl $1,%%ecx\n\t" + "movl $0,%%edx\n\t" + ".Lloop%=:\t" + "movl %%esi,%%eax\n\t" + "andl $0x80000000,%%esi\n\t" + "xorl $0x80000000,%%esi\n\t" /* parity indicator for sign */ + "andl $0x7fffffff,%%eax\n\t" /* clear high bit of ax */ + "divl %%ebx\n\t" /* divide si by bx, ax=quotient, dx=rem */ + "orl %%ebx,%%esi\n\t" /* copy bx in si but keep high bit of si */ + "movl %%edx,%%ebx\n\t" /* si now contains bx and bx the remainder */ + "mull %%ecx\n\t" /* quotient*cx is in ax (dx=0) */ + "addl %%eax,%%edi\n\t" /* di <- di+q*cx*/ + "xchgl %%edi,%%ecx\n\t" /* cx <- origi di+q*cx, di <- orig cx */ + "testl %%ebx,%%ebx\n\t" + "jne .Lloop%=\n\t" + :"=D"(a),"=S"(b) + :"S"(b),"b"(a) + :"%eax","%ecx","%edx" + ); + if (b<0) + b=b&0x7fffffff; + else + a=-a; + a=(b==1)?a:0; + // if ((a-res)%p) + // CERR << "error" << '\n'; + return a; +#else // i386 + +#ifdef MP_MODINV_1 + return mp_modinv_1(a,b); +#endif + // r0=b=ab*a+1*b + // r1=a=aa*a+0*b + int aa(1),ab(0),ar(0); +#if 0 // def FXCG + ushort_t q,r; + while (a){ + q=b/a; + ar=ab-q*aa; + r=b-q*a; + if (!r) + return a==1?aa:0; + q=a/r; + ab=aa-q*ar; + b=a-q*r; + if (!b) + return r==1?ar:0; + q=r/b; + aa=ar-q*ab; + a=r-q*b; + } + return b==1?ab:0; +#else + div_t qr; + while (a){ + qr=div(b,a); + ar=ab-qr.quot*aa; + b=a; + a=qr.rem; + ab=aa; + aa=ar; + } + if (b==1) + return ab; + return 0; +#endif +#endif // i386 + } + +#if 0 // def PRIMES32 + // assumes |a|0 so that all remainders below are >=0 + a+=b; + // r0=b=ab*a+1*b + // r1=a=aa*a+0*b + longlong aa(1),ab(0),ar(0); + longlong q,r; + lldiv_t qr; + while (a){ + qr=lldiv(b,a); + ar=ab-qr.quot*aa; + b=a; + a=qr.rem; + ab=aa; + aa=ar; + } + if (b==1) + return ab; + return 0; + } +#endif + + static int find_multiplier(const gen & n,double & delta,GIAC_CONTEXT){ + delta=0; + if (n.type!=_ZINT) + return 1; + static const unsigned char mult[] = + { 1, 3, 5, 7, 11, 13, 15, 17, 19, + 21, 23, 29, 31, 33, 35, 37, 39, 41, 43, 47}; // only odd values for multiplier + unsigned nmult=sizeof(mult)/sizeof(unsigned char); + double scores[50]; + int nmodp=modulo(*n._ZINTptr,8),knmodp; + // init scores and set value for 2 + double ln2=std::log(2.0); + for (unsigned i=0;i6){ + for (unsigned i=0;i relations,unsigned j,ushort_t * curpui,ushort_t * curpuiend,const vector & basis,const vector & additional_primes){ + unsigned curpuisize=unsigned(curpuiend-curpui); + bool done=false; + unsigned i=0; // position in basis + unsigned k=0; // position in curpui + additional_t p=0; // prime + unsigned bs=unsigned(basis.size()); + for (;k>= 8; + } + else { + int c=1; + for (;k+1 & p,vector & add_p,const gen & N,const vector & basis,const vector & additional_primes,const vecteur & sqrtavals,const vecteur & bvals,ushort_t * puissancestab,mpz_t & zq,mpz_t & zr,mpz_t & alloc1, mpz_t & alloc2,mpz_t & alloc3,mpz_t & alloc4, mpz_t & alloc5){ + // x=x*(a*shiftpos+b), y =y*sqrta; + mpz_set_si(alloc2,A.shiftpos); + if (sqrtavals[A.aindex].type==_INT_){ + mpz_mul_ui(alloc1,alloc2,sqrtavals[A.aindex].val); + mpz_mul_ui(alloc2,alloc1,sqrtavals[A.aindex].val); + mpz_mul_ui(zy,zy,sqrtavals[A.aindex].val); + } + else { + mpz_mul(alloc1,alloc2,*sqrtavals[A.aindex]._ZINTptr); + mpz_mul(alloc2,alloc1,*sqrtavals[A.aindex]._ZINTptr); + mpz_mul(zy,zy,*sqrtavals[A.aindex]._ZINTptr); + } + mpz_add(alloc1,alloc2,*bvals[A.bindex]._ZINTptr); + // mpz_mul(alloc2,alloc1,*invsqrtamodnvals[A.aindex]._ZINTptr); + mpz_mul(zr,zx,alloc1); +#ifdef USE_GMP_REPLACEMENTS + mp_grow(&alloc1,zr.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = zr.used +2 ; + mpz_set(alloc2,zr); + mpz_set(alloc3,*N._ZINTptr); + // mpz_set_si(alloc4,0); + // mpz_set_si(alloc5,0); + alloc_mp_div(&zr,N._ZINTptr,&zq,&zx,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); + mp_grow(&alloc1,zy.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = zy.used +2 ; + mpz_set(alloc2,zy); + mpz_set(alloc3,*N._ZINTptr); + // mpz_set_si(alloc4,0); + // mpz_set_si(alloc5,0); + alloc_mp_div(&zy,N._ZINTptr,&zq,&zy,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); +#else + mpz_tdiv_r(zx,zr,*N._ZINTptr); + mpz_tdiv_r(zy,zy,*N._ZINTptr); +#endif + bool done=false; + unsigned bi=0; + ushort_t * it=puissancestab+A.first,* itend=puissancestab+A.second; + for (;it!=itend;++it){ + if (*it==0xffff) + continue; + if (*it==1){ + ++it; + additional_t p=*it; +#if GIAC_ADDITIONAL_PRIMES==32 +#ifndef PRIMES32 + p <<= 16; + ++it; + p += *it; +#endif +#endif + int pos=_equalposcomp(additional_primes,p); + if (pos) + ++add_p[pos-1]; + else { + // otherwise ERROR!!! + } + break; + } + if (!*it){ + done=true; + continue; + } + if (done){ + while (bi>8)) + ++bi; + p[bi]+=(*it&0xff); + } + } + } + + void find_bv_be(int tmp,int & bv,int &be){ + bv=1; be=-1; + while (tmp%2==0){ + ++bv; + tmp /= 2; + } + tmp /= 2; + if (tmp%2) + be=1; + else + be=-1; + } + + +#ifdef PRIMES32 + // Change b coeff of polynomial: update roots for small primes + // for large primes do it depending on LP_TAB_TOGETHER +#ifdef LP_SMALL_PRIMES + void copy(vector & basis,vector & small_basis){ + small_basis_t * small_basisptr=&small_basis[0], * small_basisend=small_basisptr+small_basis.size(); + basis_t * basisptr=&basis[0]; + unsigned next=2,logp=1; + if (small_basis[0].p==0){ + for (;small_basisptrroot1=basisptr->root1; + small_basisptr->root2=basisptr->root2; + register unsigned short p =basisptr->p; + small_basisptr->p = p; + small_basisptr->logp=logp; + if (p>next){ + ++logp; + next *= 2; + } + } + } + else { + for (;small_basisptrroot1=basisptr->root1; + small_basisptr->root2=basisptr->root2; + } + } + } + + void switch_roots(const vector & bainv2,vector & basis,vector & small_basis,unsigned lp_basis_pos,unsigned nslices,unsigned slicesize,unsigned bv,int be,int afact,const vector & pos,gen b,mpz_t & zq,int M){ + unsigned bs=basis.size(); + const int * bvpos=&bainv2[(bv-1)*bs]; +#ifdef LP_TAB_TOGETHER + const int * bvposend=bvpos+lp_basis_pos; +#else + const int * bvposend=bvpos+bs; +#endif + basis_t * basisptr=&basis[0]; + if (be>0){ + for (;bvposp; + register int r=basisptr->root1-(*bvpos); + if (r<0) + r+=p; + basisptr->root1=r; + r=basisptr->root2-(*bvpos); + if (r<0) + r+=p; + basisptr->root2=r; + } + } + else { + for (;bvposp; + register int r=basisptr->root1+(*bvpos); + if (r>p) + r-=p; + basisptr->root1=r; + r=basisptr->root2+(*bvpos); + if (r>p) + r-=p; + basisptr->root2=r; + } + } + // adjust sieve position for prime factors of a, + for (int j=0;j & bainv2,vector & basis,unsigned lp_basis_pos,unsigned nslices,unsigned slicesize,unsigned bv,int be,int afact,const vector & pos,gen b,mpz_t & zq,int M){ + unsigned bs=basis.size(); +#ifdef LP_TAB_SIZE + const int * bvpos=&bainv2[(bv-1)*bs],* bvposend=bvpos+lp_basis_pos; +#else + const int * bvpos=&bainv2[(bv-1)*bs],* bvposend=bvpos+bs; +#endif + basis_t * basisptr=&basis[0]; + unsigned decal0=nslices*slicesize; + if (decal0>=basis.back().p){ + if (be<0){ + for (;bvposp; + register unsigned decal = (decal0+(*bvpos))% p; + register unsigned r=basisptr->root1+decal; + if (r>p) + r -= p; + basisptr->root1 = r; + r = basisptr->root2+decal; + if (r>p) + r -= p; + basisptr->root2 = r; + } + } + else { + for (;bvposp; + register unsigned decal = (decal0-(*bvpos))% p; + register unsigned r=basisptr->root1+decal; + if (r>p) + r -= p; + basisptr->root1 = r; + r = basisptr->root2+decal; + if (r>p) + r -= p; + basisptr->root2 = r; + } + } + } + else + { // should not be reached since Mtarget is about basis.back() + for (;bvposp; + register unsigned decal = (decal0+p-be*(*bvpos))% p; + register unsigned r=basisptr->root1+decal; + if (r>p) + r -= p; + basisptr->root1 = r; + r = basisptr->root2+decal; + if (r>p) + r -= p; + basisptr->root2 = r; + } + } + // adjust sieve position for prime factors of a, + for (int j=0;j0){ + for (;bvposp; + register int r=basisptr->root1-(*bvpos); + if (r<0) + r+=p; + basisptr->root1=r; + r=basisptr->root2-(*bvpos); + if (r<0) + r+=p; + basisptr->root2=r; + } + } + else { + for (;bvposp; + register int r=basisptr->root1+(*bvpos); + if (r>int(p)) + r-=p; + basisptr->root1=r; + r=basisptr->root2+(*bvpos); + if (r>int(p)) + r-=p; + basisptr->root2=r; + } + } +#endif + } +#endif // LP_SMALL_PRIMES +#endif // PRIMES32 + + // Change a, the leading coeff of polynomial: initialize all roots (small and large primes) + void init_roots(vector & basis, +#ifdef LP_SMALL_PRIMES + vector & small_basis, +#endif +#ifdef WITH_INVA + vector & Inva, +#endif +#ifdef SQRTMOD_OUTSIDE + const vector & sqrtmod, +#endif +#ifdef PRIMES32 + vector & bainv2,int afact,int afact0, +#else + ulonglong usqrta, +#endif + const gen & a,const gen & b,const vecteur & bvalues,mpz_t & zq,unsigned M){ + unsigned bs=unsigned(basis.size()); + basis_t * basisptr=&basis.front(),*basisend=basisptr+bs; +#ifdef SQRTMOD_OUTSIDE + vector::const_iterator sqrtmodit=sqrtmod.begin(); +#endif + for (int i=0;basisptr!=basisend;++i,++basisptr){ + ushort_t p=basisptr->p; + // find inverse of a mod p +#ifdef PRIMES32 + int j=invmodnoerr(modulo(*a._ZINTptr,p),p); + // deltar[i]=((2*ulonglong(basis[i].sqrtmod))*j)%p; +#else // PRIMES32 + unsigned modu=usqrta%p; + modu=(modu*modu)%p; + int j=invmodnoerr(modu,p); +#endif // PRIMES32 + if (j<0) + j += p; + unsigned inva=j; +#ifdef WITH_INVA + Inva[i]=inva; +#else +#ifdef PRIMES32 + // set roots change values for all b coeffs for this a + if (afact>afact0){ + int * ptr=&bainv2[i]; + for (int j=1;jsqrtmod; +#endif + int bmodp=p-modulo(*b._ZINTptr,p); + if (inva){ + if (p<=37000){ + // sqrtm<=p/2, bmodproot1=(M+(bmodp+sqrtm)*inva) % p; + basisptr->root2=(M+(bmodp+p-sqrtm)*inva) % p; + continue; + } +#ifdef _I386_ + register int q=M; + addmultmod(q,bmodp+sqrtm,inva,p); + basisptr->root1=q; + q=M; + addmultmod(q,bmodp+p-sqrtm,inva,p); + basisptr->root2=q; +#else + basisptr->root1=(M+longlong(bmodp+sqrtm)*inva) % p; + basisptr->root2=(M+longlong(bmodp+p-sqrtm)*inva) % p; +#endif + continue; + } + int cmodp=modulo(zq,p); + int q=(M+longlong(cmodp)*invmodnoerr((2*bmodp)%p,p))%p; + if (q<0) + q+=p; + basisptr->root2=q; + basisptr->root1=q; + } +#ifdef WITH_INVA +#ifdef PRIMES32 + if (afact>afact0){ + int * bainv2ptr=&bainv2.front(); + basis_t * basisptr,*basisend=&basis.front()+bs; + for (int j=1;j::const_iterator invait=Inva.begin(); + for (basisptr=&basis.front();basisptrp; + if (r<0) + r += basisptr->p; + *bainv2ptr=r; + } + } + else { + // longlong up1=up1tmp[2*j]; + // longlong tmp=up1tmp[2*j+1]; + // tmp is <= P^2 where P is the largest factor of a + mpz_t & bz=*bvalues[j]._ZINTptr; + vector::const_iterator invait=Inva.begin(); + for (basisptr=&basis.front();basisptrp; + *bainv2ptr=((modulo(bz,p))*longlong(2*(*invait))) % p; + } + } + } + } +#endif // PRIMES32 +#endif // WITH_INVA + +#ifdef LP_SMALL_PRIMES // copy primes<2^16 into small_basis + copy(basis,small_basis); +#endif + } + + // find relations using (a*x+b)^2=a*(a*x^2+b*x+c) mod n where + // we sieve on [-M,M] for as many polynomials as required + // a is a square, approx sqrt(2*n)/M, and n is a square modulo all primes dividing a + // b satisifies b^2=n mod a (b in [0,a[) + // c=(n-b^2)/a + bool msieve(const gen & n_orig,gen & pn,GIAC_CONTEXT){ + if (n_orig.type!=_ZINT) + return false; + // find multiplier + double delta; + int multiplier=find_multiplier(n_orig,delta,contextptr); + gen N(multiplier*n_orig); + double Nd=evalf_double(N,1,contextptr)._DOUBLE_val; +#if defined RTOS_THREADX || defined NSPIRE + if (Nd>1e40) return false; +#endif +#ifdef BESTA_OS + if (Nd>1e40) return false; +#endif +#ifdef PRIMES32 + if (Nd>1e76) return false; +#else + if (Nd>1e63) return false; +#endif + int Ndl=int(std::log10(Nd)-std::log10(double(multiplier))+.5); // +2*delta); +#ifdef LP_TAB_SIZE + int slicesize=(1 << LP_TAB_SIZE); +#else + int slicesize=(QS_SIZE>=65536 && Ndl<61)?32768:QS_SIZE; +#endif + double B=std::exp(std::sqrt(2.0)/4*std::sqrt(std::log(Nd)*std::log(std::log(Nd))))*0.45; + if (B<200) B=200; + int pos1=70,pos0=23,afact=2,afixed=0; // pos position in the basis, afact number of factors + // FIXME Will always include the 3 first primes of the basis + // set a larger Mtarget gives less polynomials but also use less memory +#if defined(RTOS_THREADX) || defined(RTOS_THREADX) || defined NSPIRE + double Mtarget=0.95e5; + if (Nd>1e36) + Mtarget=1.2e5; +#else + double Mtarget=0.55e5; +#ifndef USE_MORE_PRIMES // FIXME improve! in fact use more primes on Core, less on Opteron + if (Ndl>=50){ + Ndl-=50; + short int Btab[]={ + // 50 + 1900,2100,2300,2500,2700,2900,3100,3400,3700,4000, + // 60 + 4300,4600,4900,5300,5700,6200,6800,7500,8300,9200, + // 70 + 10000,11000,12000,13000,14000,15000,16000 + }; + if (Ndl7) + Mtarget=0.95e5; + if (Ndl>11) + Mtarget=1.3e5; + if (Ndl>15) + Mtarget=1.6e5; + if (Ndl>19) + Mtarget=1.92e5; + } +#else + if (Ndl>=50) + Mtarget=0.85e5; + if (Ndl>65) + Mtarget=1.3e5; +#endif +#endif + if (debug_infolevel) + *logptr(contextptr) << " " << CLOCK() << gettext(" sieve on ") << N << '\n' << gettext("Number of primes ") << B << '\n'; + // first compute the prime basis and sqrt(N) mod p, p in basis + vector basis; + basis.reserve(unsigned(B)); +#ifdef SQRTMOD_OUTSIDE + vector sqrtmod; + sqrtmod.reserve(basis.capacity()); + basis.push_back(2); + sqrtmod.push_back(1); +#else + basis.push_back(basis_t(2,1)); // I assume that N is odd... hence has sqrt 1 mod 2 +#endif + N.uncoerce(); + // vector N256; + int i; + mpz_t zx,zy,zq,zr; + mpz_init(zx); mpz_init(zy); mpz_init(zq); mpz_init(zr); + // fastsmod_prepare(N,zx,zy,zr,N256); + for (i=1;i6 && (i%500==99)) + *logptr(contextptr) << CLOCK() << gettext(" sieve current basis size ") << basis.size() << '\n'; +#if 1 // def USE_GMP_REPLACEMENTS + // int n=fastsmod_compute(N256,j); + int n=modulo(*N._ZINTptr,j),s; +#else + int n=smod(N,j).val,s; +#endif + if (n<0) + n+=j; + if (n==0){ +#ifdef SQRTMOD_OUTSIDE + basis.push_back(j); + sqrtmod.push_back(0); +#else + basis.push_back(basis_t(j,0)); +#endif + } + else { + if (powmod(n,(unsigned long)((j-1)/2),(int)j)==1){ + s=sqrt_mod(n,int(j),true,contextptr).val; + if (s<0) + s+=j; +#ifdef SQRTMOD_OUTSIDE + basis.push_back(j); + sqrtmod.push_back(s); +#else + basis.push_back(basis_t(j,s)); +#endif + } + } + if (basis.size()>=B) + break; + } + vector crible; + int jp=0; + if (basis.size() 2^16 in the basis + for (;basis.size()65535){ + break; + } +#endif + if (debug_infolevel>6 && (i%500==99)) + *logptr(contextptr) << CLOCK() << gettext(" sieve current basis size ") << basis.size() << '\n'; +#if 1 // def USE_GMP_REPLACEMENTS + // int n=fastsmod_compute(N256,jp); + int n=modulo(*N._ZINTptr,jp),s; +#else + int n=smod(N,jp).val,s; +#endif + if (n<0) + n+=jp; + if (powmod(n,(unsigned long)((jp-1)/2),jp)==1){ + s=sqrt_mod(n,jp,true,contextptr).val; + if (s<0) + s += jp; +#ifdef LP_TAB_SIZE + if (!lp_basis_pos && jp> (1< small_basis(lp_basis_pos); // will be filled by primes<2^16 +#endif +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted){ + mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); + return false; + } + double dtarget=1.1; + if (Mtarget>16))*basis.back().p*ps; +#else + unsigned maxadditional=3*basis.back().p*ps; +#endif + if (debug_infolevel) + *logptr(contextptr) << CLOCK() << gettext(" sieve basis OK, size ") << basis.size() << " largest prime in basis " << basis.back().p << " large prime " << maxadditional << " Mtarget " << Mtarget << '\n' ; + int bs=int(basis.size()); + gen isqrtN=isqrt(N); + isqrtN.uncoerce(); + // now compare isqrtN to a^2 for a in the basis + double seuil=1.414*evalf_double(isqrtN,1,contextptr)._DOUBLE_val/Mtarget; // should be a + seuil=std::sqrt(seuil); // should be product of primes of the basis +#ifdef OLD_AFACT + double dfactors=std::log10(seuil)/3; + // fixed primes are choosen at basis[pos0], variables are choosen around 2000 + afact=int(dfactors+.5); + if (afact<=1){ + afact=1; + int i=20; + for (;i<3*bs/4;++i){ + if (seuil=3*bs/4){ + afact=2; + for (;i<3*bs/4;++i){ + if (seuil=3, + if (dfactors>5.4){ + dfactors -= 3; // 3 large primes + afixed = dfactors/.8; // at least 3 fixed + afact = 3 + afixed; + } + else { + dfactors -= 2; // 2 large primes + afixed = dfactors/.8; + if (afixed==0) + afixed=1; + afact = 2 +afixed; + } + for (int i=0;iafact){ + afixed=i; + afact=i+ivariable; + curseuil=seuiltest; + } + } + } + for (int i=0;i isqrtN256; + // fastsmod_prepare(isqrtN,zx,zy,zr,isqrtN256); + vector isqrtNmodp(bs); + for (int i=0;i axbmodn; // contains (sqrta,b,x) + vector additional_primes; +#ifndef ADDITIONAL_PRIMES_HASHMAP + vector additional_primes_twice; +#endif +#ifdef LP_TAB_SIZE + vector lp_map(128); // at most 128 slices in a sieve +#endif + vecteur sqrtavals,bvals; +#ifdef GIAC_ADDITIONAL_PRIMES +#ifdef ADDITIONAL_PRIMES_HASHMAP +#if defined(EMCC) || defined(EMCC2) + additional_map_t additional_primes_map; +#else + additional_map_t additional_primes_map(8*bs); +#endif + axbmodn.reserve(bs); +#else +#if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE + additional_primes.reserve(bs); + additional_primes_twice.reserve(bs); + axbmodn.reserve(2*bs); +#else + additional_primes.reserve(4*bs); + additional_primes_twice.reserve(4*bs); + axbmodn.reserve(5*bs); +#endif + sqrtavals.reserve(bs/7); + bvals.reserve(2*bs/7); +#endif // ADDITIONAL_PRIMES_HASHMAP +#else // GIAC_ADDITIONAL_PRIMES + axbmodn.reserve(bs+1); +#endif + // now sieve + unsigned todo_rel; + unsigned marge=bs/100; + if (marge<15) + marge=15; + mpz_t alloc1,alloc2,alloc3,alloc4,alloc5; + mpz_init(alloc1); mpz_init(alloc2); mpz_init(alloc3); mpz_init(alloc4); mpz_init(alloc5); + // vector a256,b256,tmpv; + vector curpuissances,recheck,pos(afact); +#ifdef WITH_INVA + vector Inva(bs); +#endif + vecteur bvalues; // will contain values of b if afact<=afact0 or components of b if afact>afact0 + // array for efficient polynomial switch (same a change b) when at least afact0 factors/a +#ifdef PRIMES32 + const int afact0=3; + vector bainv2((afact-1)*bs); + vector up1tmp; +#endif + for (int i=0;i1) + end_pos1=pos1+100; + if (avar>2) + end_pos1=pos1+30; + if (int(lp_basis_pos)=end_pos1 || basis[pos.back()].p>=45000){ + int i=afact-2; + for (;i>afixed;--i){ + if (int(pos[i])=3, so that we can move pos[1] by thread + while (Mval>1.1*Mtarget && int(pos[afixed-1])10){ + // Mval is too small, decrease one factor of a + --pos[0]; + if (pos[0]<=10){ + Mval=0; + break; + } + double coeff=basis[pos[0]].p/double(basis[pos[0]+1].p); + Mval=Mval/(coeff*coeff); + } + } + if ( Mval <0.7*Mtarget ){ + if (pos1>pos0+afixed+5 || Mval<32768){ + // CERR << pos ; + int i=afact-1; + for (;i>afixed+1;--i){ + if (pos[i]>pos[i-1]+5) + break; + } + if (i<=afixed+1){ + --pos1; + for (i=0;i=todo_rel) + break; + int nrelationsa=0; + // Not finished yet, construct a new value of a around ad=sqrt(2*n)/M + // using a product of afact square of primes that are in the basis + // and construct a vector of 2^(afact-1) corresponding values of b + // and compute the values of inverses of a mod p + ulonglong usqrta(basis[pos[0]].p); + for (int i=1;i6) + *logptr(contextptr) << CLOCK() << gettext(" initial value for M= ") << M << '\n'; + int nslices=int(std::ceil((2.*M)/slicesize)); + M=(nslices*slicesize)/2; + bvalues.clear(); + gen curprod=1; + for (int i=0;;){ +#ifdef SQRTMOD_OUTSIDE + int s=sqrtmod[pos[i]]; +#else + int s=basis[pos[i]].sqrtmod; +#endif + int p=basis[pos[i]].p; + longlong p2=p*longlong(p); + // Hensel lift s to be a sqrt of n mod p^2: (s+p*r)^2=s^2+2p*r*s=n => r=(n-s^2)/p*inv(2*s mod p) + int r=p<37000?int((modulo(*N._ZINTptr,p2)-s*s)/p):((smod(N,p2)-s*s)/p).val; + r=(r*invmod(2*s,p))%p; + // overflow should not happen because p is a factor of a hence choosen + // in the 1000 range (perhaps up to 10 000, but not much larger) + // if ((longlong(r)*p)!=r*p) CERR << "overflow" << '\n'; + s += p*r; +#ifdef PRIMES32 + if (afact>afact0){ + // store s*(inv( product(basis[pos[j]]^2,j!=i) mod p2)) in bvalues[i] + longlong up1=(usqrta/p); + longlong up=up1%p2; + up=(up*up)%p2; + //longlong tmp=(s*invmodnoerr(up,p2))%p2; + //up1tmp.push_back(up1); + //up1tmp.push_back(tmp); + gen tmp=smod(s*invmod(gen(up),gen(p2)),p2); + if (is_greater(0,tmp,contextptr)) tmp=-tmp; + gen gup1(up1); + bvalues.push_back(gup1*gup1*tmp); + bvalues.back().uncoerce(); + } + else +#endif + { + if (bvalues.empty()) + bvalues.push_back(s); + else { + int js=int(bvalues.size()); + for (int j=0;j6) + *logptr(contextptr) << CLOCK() << gettext(" Computing inverses mod p of the basis ") << '\n'; + // fastsmod_prepare(a,zx,zy,zr,a256); + gen b; + for (int i=0;i< (1<<(afact-1));++i){ +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) + break; +#ifdef ADDITIONAL_PRIMES_HASHMAP + todo_rel=bs+marge; +#else + todo_rel=bs+marge+unsigned(additional_primes.size()); +#endif + if (axbmodn.size()>=todo_rel) + break; + if (debug_infolevel>6) + *logptr(contextptr) << CLOCK() << gettext(" Computing c ") << '\n'; +#ifdef PRIMES32 + int bv=1,be=-1; + if (afact>afact0){ + if (i==0){ + b=0; + for (unsigned j=0;j6) + *logptr(contextptr) << CLOCK() << gettext(" Computing roots mod the basis ") << '\n'; + // fastsmod_prepare(b,zx,zy,zr,b256); +#ifdef PRIMES32 + if (i && afact>afact0) + switch_roots(bainv2,basis, +#ifdef LP_SMALL_PRIMES + small_basis, +#endif + lp_basis_pos,nslices,slicesize,bv,be,afact,pos,b,zq,M); + else { + init_roots(basis, +#ifdef LP_SMALL_PRIMES + small_basis, +#endif +#ifdef WITH_INVA + Inva, +#endif +#ifdef SQRTMOD_OUTSIDE + sqrtmod, +#endif + bainv2,afact,afact0, + a,b,bvalues,zq,M); +#ifdef LP_TAB_TOGETHER + // init all hashtable for large primes at once + unsigned cl; + if (debug_infolevel>3){ + cl=CLOCK(); + *logptr(contextptr) << cl << gettext(" Init large prime hashtables ") << '\n'; + } + int total=(nslices << (afact-1)); + if (int(lp_map.size()) < total) + lp_map.resize(total); + for (int k=0;k< total;++k) + lp_map[k].clear(); + if (lp_basis_pos){ + for (int k=0;;){ + basis_t * bit=&basis[0]+lp_basis_pos, * bitend=&basis[0]+bs; + unsigned endpos=nslices*slicesize; + lp_tab_t * ptr=&lp_map[0]+k*nslices; + for (;bit!=bitend;++bit){ + register ushort_t p=bit->p; + register unsigned pos=bit->root1; + for (;pos> LP_TAB_SIZE))->push_back(lp_entry_t((pos & LP_MASK),p)); + } + pos=bit->root2; + for (;pos> LP_TAB_SIZE))->push_back(lp_entry_t((pos & LP_MASK),p)); + } + } + ++k; + if (k== (1 << (afact-1))){ + if (debug_infolevel>3){ + unsigned cl2=CLOCK(); + *logptr(contextptr) << cl2 << gettext(" End large prime hashtables ") << cl2-cl << '\n'; + } + break; + } + find_bv_be(k,bv,be); + // switch roots to next polynomial + int * bvpos=&bainv2[(bv-1)*bs],* bvposend=bvpos+bs; + bvpos += lp_basis_pos; + basis_t * basisptr=&basis[0]+lp_basis_pos; + if (be>0){ + for (;bvposp; + register int r=basisptr->root1-(*bvpos); + if (r<0) + r+=p; + basisptr->root1=r; + r=basisptr->root2-(*bvpos); + if (r<0) + r+=p; + basisptr->root2=r; + } + } + else { + for (;bvposp; + register int r=basisptr->root1+(*bvpos); + if (r>int(p)) + r-=p; + basisptr->root1=r; + r=basisptr->root2+(*bvpos); + if (r>int(p)) + r-=p; + basisptr->root2=r; + } + } + } + } +#endif // LP_TAB_TOGETHER + } // end else of if i==0 +#if defined(LP_TAB_SIZE) && !defined(LP_TAB_TOGETHER) + if (int(lp_map.size()) < nslices) + lp_map.resize(nslices); + for (int k=0;k< nslices;++k) + lp_map[k].clear(); + if (lp_basis_pos){ + basis_t * bit=&basis[0]+lp_basis_pos, * bitend=&basis[0]+bs; + unsigned endpos=nslices*slicesize; + for (;bit!=bitend;++bit){ + register ushort_t p=bit->p; + register unsigned pos=bit->root1; + for (;pos> LP_TAB_SIZE].push_back(lp_entry_t((pos & LP_MASK),p)); + } + pos=bit->root2; + for (;pos> LP_TAB_SIZE].push_back(lp_entry_t((pos & LP_MASK),p)); + } + } + } +#endif // LP_TAB_SIZE && !LP_TAB_TOGETHER +#else // PRIMES32 + init_roots(basis, +#ifdef WITH_INVA + Inva, +#endif +#ifdef SQRTMOD_OUTSIDE + sqrtmod, +#endif + usqrta,a,b,bvalues,zq,M); +#endif // PRIMES32 + // we can now sieve in [-M,M[ by slice of size slicesize +#ifndef GIAC_HAS_STO_38 + if (debug_infolevel>5){ + *logptr(contextptr) << CLOCK(); + *logptr(contextptr) << gettext(" Polynomial a,b,M=") << a << "," << b << "," << M << " (" << pos << ")" ; + *logptr(contextptr) << CLOCK() << '\n'; + } +#endif + int nrelationsb=0; +#ifdef LP_TAB_SIZE +#endif + for (int l=0;l=todo_rel) + break; + int shift=-M+l*slicesize; + int slicerelations=msieve(a,sqrtavals, + bvals,zq,basis,lp_basis_pos, +#ifdef LP_SMALL_PRIMES + small_basis, +#endif + maxadditional, +#ifdef ADDITIONAL_PRIMES_HASHMAP + additional_primes_map, +#else + additional_primes,additional_primes_twice, +#endif + N,isqrtN, + slice,slicesize,shift,puissancestab,puissancesptr,puissancesend,curpuissances,recheck, + axbmodn, + zx,zy,zr,alloc1,alloc2,alloc3,alloc4,alloc5, +#ifdef LP_TAB_SIZE +#ifdef LP_TAB_TOGETHER + lp_map[l+nslices*i], +#else + lp_map[l], +#endif +#endif + contextptr); + if (slicerelations==-1){ + *logptr(contextptr) << gettext("Sieve error: Not enough memory ") << '\n'; + break; + } + nrelationsb += slicerelations; +#ifdef ADDITIONAL_PRIMES_HASHMAP + todo_rel=bs+marge; +#else + todo_rel=bs+marge+unsigned(additional_primes.size()); +#endif + } + if (nrelationsb==0) + bvals.pop_back(); + else + nrelationsa += nrelationsb; + } +#if defined( RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE + if (debug_infolevel){ +#ifdef NSPIRE + static int count_print=0; + ++count_print; + if (count_print%4==0) +#endif + *logptr(contextptr) << axbmodn.size() << " of " << todo_rel << " (" << 100-100*(todo_rel-axbmodn.size())/double(bs+marge) << "%)" << '\n'; + } +#endif + if (nrelationsa==0){ + sqrtavals.pop_back(); + } +#if !defined(RTOS_THREADX) && !defined(BESTA_OS) && !defined NSPIRE + if (debug_infolevel>1) + *logptr(contextptr) << CLOCK()<< gettext(" sieved : ") << axbmodn.size() << " of " << todo_rel << " (" << 100-100*(todo_rel-axbmodn.size())/double(bs+marge) << "%), M=" << M << '\n'; +#endif + } // end sieve loop + if (debug_infolevel) + *logptr(contextptr) << gettext("Polynomials a,b in use: #a ") << sqrtavals.size() << " and #b " << bvals.size() << '\n'; + delete [] slice; +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted || puissancesptr==puissancesend){ + mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); + mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); + delete [] puissancestab; + return false; + } + // We have enough relations, make matrix, reduce it then find x^2=y^2 mod n congruences + if (debug_infolevel) + *logptr(contextptr) << CLOCK() << gettext(" sieve done: used ") << (puissancesptr-puissancestab)*0.002 << " K for storing relations (of " << puissancestablength*0.002 << ")" << '\n'; + release_memory(isqrtNmodp); +#ifdef GIAC_ADDITIONAL_PRIMES +#ifdef ADDITIONAL_PRIMES_HASHMAP + additional_primes.reserve(axbmodn.size()); + vector::const_iterator it=axbmodn.begin(),itend=axbmodn.end(); + for (;it!=itend;++it) { + unsigned u=largep(*it,puissancestab); + if (u) + additional_primes.push_back(u); + } + sort(additional_primes.begin(),additional_primes.end()); // for binary search later +#else + if (debug_infolevel) + *logptr(contextptr) << CLOCK() << gettext(" removing additional primes") << '\n'; + // remove relations with additional primes which are used only once + int lastp=int(axbmodn.size())-1,lasta=int(additional_primes.size())-1; + for (int i=0;i<=lastp;++i){ + ushort_t * curbeg=puissancestab+axbmodn[i].first, * curend=puissancestab+axbmodn[i].second; + bool done=false; + for (;curbeg!=curend;++curbeg){ + if (*curbeg==1) + break; + } + if (curbeg==curend) + continue; + ++curbeg; + additional_t u=*curbeg; +#if GIAC_ADDITIONAL_PRIMES==32 && !defined(PRIMES32) + u <<=16 ; + ++curbeg; + u += *curbeg; +#endif + int pos=_equalposcomp(additional_primes,u); + if (!pos) + continue; + if (pos>lasta){ + // *logptr(contextptr) << cur << '\n'; + continue; + } + --pos; + if (additional_primes_twice[pos]) + continue; + axbmodn[i]=axbmodn[lastp]; + --lastp; + additional_primes[pos]=additional_primes[lasta]; + additional_primes_twice[pos]=additional_primes_twice[lasta]; + --lasta; + --i; // recheck at current index + } + axbmodn.resize(lastp+1); + additional_primes.resize(lasta+1); + if (debug_infolevel) + *logptr(contextptr) << CLOCK() << gettext(" end removing additional primes") << '\n'; +#endif // ADDTIONAL_PRIMES_HASHMAP +#endif // GIAC_ADDITIONAL_PRIMES + // Make relations matrix (currently dense, FIXME improve to sparse and Lanczos algorithm) + int C32=int(std::ceil(axbmodn.size()/32./GIAC_RREF_UNROLL))*GIAC_RREF_UNROLL; + unsigned * tab=new unsigned[axbmodn.size()*C32],*tabend=tab+axbmodn.size()*C32; + if (!tab){ + mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); + mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); + delete [] puissancestab; + return false; + } + // init tab + for (unsigned * ptr=tab;ptr!=tabend;++ptr) + *ptr=0; + int l32=C32*32; + vector< line_t > relations(axbmodn.size()); + for (unsigned i=0;i2){ + cout << i << ", p="; + if (i==0) + cout << "-1"; + else { + if (i<=bs) + cout << basis[i-1].p << " " << relations[i].count << '\n'; + else + cout << '\n'; + } + } + } + if (debug_infolevel) + *logptr(contextptr) << CLOCK() << " begin rref size " << relations.size() << "x" << l32 << " K " << 0.004*relations.size()*C32 << ", " << count0 << " null lines, " << count1 << " 1-line" << '\n'; +#if 0 // debug only + for (int i=0;i relations2(l32); + i=0; + int j=0,rs=int(relations.size()); + for (;i p(bs), add_p(additional_primes.size()); + for (int j=0;j=sqrtavals.size() || axbmodn[j].bindex>=bvals.size()) + return false; // check added because ifactor(nextprime(alog10(17))*nextprime(alog10(19))); fails on Prime (and unable to do parallel debug in giac) + update_xy(axbmodn[j],zx,zy,p,add_p,N,basis,additional_primes,sqrtavals,bvals,puissancestab,zq,zr,alloc1,alloc2,alloc3,alloc4,alloc5); +#ifdef ADDITIONAL_PRIMES_HASHMAP + unsigned u=largep(axbmodn[j],puissancestab); + if (u) + update_xy(additional_primes_map[u],zx,zy,p,add_p,N,basis,additional_primes,sqrtavals,bvals,puissancestab,zq,zr,alloc1,alloc2,alloc3,alloc4,alloc5); +#endif + } // end if (j6) + *logptr(contextptr) << CLOCK() << gettext("checking gcd") << cur << " " << N << '\n'; + if ( (cur.type==_INT_ && cur.val>7) || + (cur.type==_ZINT && is_strictly_greater(n_orig,cur,contextptr))){ + pn=cur; + mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); + mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); + delete [] puissancestab; + delete [] tab; + return true; + } + } + mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr); + mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5); + delete [] puissancestab; + delete [] tab; + return false; + } + + // elliptic curve method, + // http://math.univ-lyon1.fr/~roblot/resources/factorisation.pdf + // This is a very naive implementation + // It does not use Montgomery representation and only phase 1 + // For professional implementations, cf. + // https://members.loria.fr/PZimmermann/papers/ecm-submitted.pdf + // https://pdfs.semanticscholar.org/e8eb/13b75292b15dd63c3e7e4b1c8dc334d278ba.pdf + // ecm will be used if available +#define ECM_MAXITER 1000 + static gen L(double alpha,double beta,double N){ + double lnN=std::log(N); + return std::exp(beta*std::pow(lnN,alpha)*std::pow(std::log(lnN),1-alpha)); + } + + +#ifndef USE_GMP_REPLACEMENTS + // addition in elliptic curve, returns 1 on success or 0 and m=a divisor of n + int ecm_add(const mpz_t &x1,const mpz_t &y1,const mpz_t & x2,const mpz_t &y2,const mpz_t & a,const mpz_t & n,mpz_t & m,mpz_t & x,mpz_t &y){ + if (mpz_cmp(x1,x2)){ + mpz_sub(x,x2,x1); // x=x2-x1 + int res=mpz_invert(m,x,n); // m=inv(x2-x1) mod n + if (res==0){ // not invertible + mpz_gcd(m,x,n); + return 0; // m has non trivial gcd with n + } + mpz_sub(y,y2,y1); + mpz_mul(m,m,y); // m=(y2-y1)*invmod(x2-x1,n); + } + else { + mpz_mul_ui(y,y1,2); + int res=mpz_invert(m,y,n); // m=inv(2*y) mod n + if (res==0){ // not invertible + mpz_gcd(m,y,n); + return 0; // m has non trivial gcd with n + } + mpz_mul(x,x1,x1); + mpz_mul_ui(x,x,3); + mpz_add(x,x,a); + mpz_mul(m,m,x); // m=(3*x1*x1+a)*invmod(2*y1,n); + } + mpz_fdiv_r(m,m,n); // m=mod(m,n); + mpz_mul(x,m,m); + mpz_sub(x,x,x1); + mpz_sub(x,x,x2); + mpz_fdiv_r(x,x,n); // x=mod(m*m-x1-x2,n); + mpz_sub(y,x1,x); + mpz_mul(y,m,y); + mpz_sub(y,y,y1); + mpz_fdiv_r(y,y,n); // y=mod(m*(x1-x)-y1,n); + // smod x and y + mpz_add(m,x,x); + if (mpz_cmp(m,n)>0) + mpz_sub(x,x,n); + mpz_add(m,y,y); + if (mpz_cmp(m,n)>0) + mpz_sub(y,y,n); + return 1; + } +#endif + + gen ecm_add(const gen &x1,const gen &y1,const gen & x2,const gen &y2,const gen & a,const gen & n,gen & m,gen & x,gen &y){ + if (is_inf(x1)){ + x=x2; y=y2; return 1; + } + if (is_inf(x2)){ + x=x1; y=y1; return 1; + } + if (y1+y2==0){ + y=x=unsigned_inf; return 1; + } +#ifndef USE_GMP_REPLACEMENTS + if (x1.type==_ZINT && y1.type==_ZINT && x2.type==_ZINT && y2.type==_ZINT && a.type==_ZINT && n.type==_ZINT ){ + m=gen(1LL<<33); + x=gen(1LL<<33); + y=gen(1LL<<33); + if (!ecm_add(*x1._ZINTptr,*y1._ZINTptr,*x2._ZINTptr,*y2._ZINTptr,*a._ZINTptr,*n._ZINTptr,*m._ZINTptr,*x._ZINTptr,*y._ZINTptr)){ + return gen(*m._ZINTptr); + } + return 1; + } +#endif + if (x1!=x2){ + m=gcd(x2-x1,n); + if (m!=1) + return m; + m=(y2-y1)*invmod(x2-x1,n); + } + else { + m=gcd(y1,n); + if (m!=1) + return m; + m=(3*x1*x1+a)*invmod(2*y1,n); + } + m=smod(m,n); + x=smod(m*m-x1-x2,n); + y=smod(m*(x1-x)-y1,n); + return 1; + } + // multiplication in elliptic curve, + gen ecm_mult(const gen &x1,const gen &y1,ulonglong m,const gen & a,const gen & n,gen & x,gen &y){ + gen x2(x1),y2(y1),xtmp,ytmp,g,M; + y=x=plus_inf; + while (m){ + if (m%2){ + g=ecm_add(x,y,x2,y2,a,n,M,xtmp,ytmp); + if (g!=1) + return g; + swapgen(x,xtmp); swapgen(y,ytmp);// x=xtmp; y=ytmp; + } + m/=2; + g=ecm_add(x2,y2,x2,y2,a,n,M,xtmp,ytmp); // improve: ecmdup + if (g!=1) + return g; + swapgen(x2,xtmp);swapgen(y2,ytmp);// x2=xtmp; y2=ytmp; + } + return 1; + } + gen _ecm_factor(const gen &n_,GIAC_CONTEXT){ + gen B,n(n_); + int maxiter(ECM_MAXITER); + if (n.type==_VECT && n._VECTptr->size()>=2){ + const vecteur & v=*n._VECTptr; + B=v[1]; + if (v.size()>=3 && v[2].type==_INT_) + maxiter=giacmax(1,v[2].val); + n=v.front(); + } + if (!is_integer(n) || is_positive(-n,contextptr)) + return gensizeerr(contextptr); + if (_isprime(n,contextptr)!=0) + return n; + double logp=.5*std::log(evalf_double(n,1,contextptr)._DOUBLE_val); +#ifdef HAVE_LIBECM + double epsilon=.02; // to be adjusted +#else + double epsilon=.45; // to be adjusted +#endif + if (logp>80) // research factors of size not exceeding 35 digits + logp=80; + if (B==0) + B=L(.5,0.707+epsilon,std::exp(logp)); + // B=1000; + B=_ceil(B,contextptr); +#ifdef HAVE_LIBECM + *logptr(contextptr) << "ECM-GMP factor n="<< n << " , B=" << B << ", #curves <=" << maxiter << '\n'; + n.uncoerce(); + double B1=evalf_double(B,1,contextptr)._DOUBLE_val; + /* From ECM README, table of optimal values of B1 + digits D optimal B1 default B2 expected curves + N(B1,B2,D) + -power 1 default poly + 20 11e3 1.9e6 74 74 [x^1] + 25 5e4 1.3e7 221 214 [x^2] + 30 25e4 1.3e8 453 430 [D(3)] + 35 1e6 1.0e9 984 904 [D(6)] + 40 3e6 5.7e9 2541 2350 [D(6)] + 45 11e6 3.5e10 4949 4480 [D(12)] + 50 43e6 2.4e11 8266 7553 [D(12)] + 55 11e7 7.8e11 20158 17769 [D(30)] + 60 26e7 3.2e12 47173 42017 [D(30)] + 65 85e7 1.6e13 77666 69408 [D(30)] + + */ + int res; + gen F(1LL<<33); + for (int i=0;imaxiter) + maxiter=nd1; + int m,m1,a,a1,j; + m1=m=2; + a1=a=1; + int c=0; + mpz_t g,x,x1,x2,x2k,y,y1,p,q,tmpq,alloc1,alloc2,alloc3,alloc4,alloc5; + mpz_init_set_si(g,1); // ? mp_init_size to specify size + mpz_init_set_si(x,2); + mpz_init_set_si(x1,2); + mpz_init_set_si(y,2); + mpz_init(y1); + mpz_init(x2); + mpz_init(x2k); + mpz_init_set_si(p,1); + mpz_init(q); + mpz_init(tmpq); + mpz_init(alloc1); + mpz_init(alloc2); + mpz_init(alloc3); + mpz_init(alloc4); + mpz_init(alloc5); + while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0) { +#ifdef TIMEOUT + control_c(); +#endif + a=2*a+1;//a=2^(e+1)-1=2*l(m)-1 + while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0 && a>m) { // ok +#ifdef TIMEOUT + control_c(); +#endif + // x=f(x,k,n,q); +#ifdef USE_GMP_REPLACEMENTS + mp_sqr(&x,&x2); + mpz_add(x2k,x2,*k._ZINTptr); + if (mpz_cmp(x2k,*n._ZINTptr)>0){ + mp_grow(&alloc1,x2k.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = x2k.used +2 ; + mpz_set(alloc2,x2k); + mpz_set(alloc3,*n._ZINTptr); + // mpz_set_si(alloc4,0); + // mpz_set_si(alloc5,0); + alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); + } + else + mpz_set(x,x2k); +#else + mpz_mul(x2,x,x); + mpz_add(x2k,x2,*k._ZINTptr); + mpz_tdiv_r(x,x2k,*n._ZINTptr); +#endif + m += 1; + if (debug_infolevel && ((m % +#if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE + (1<<10) +#else + (1<<18) +#endif + )==0)) + *logptr(contextptr) << CLOCK() << gettext(" Pollard-rho try ") << m << '\n'; + if (m > maxiter ){ + if (debug_infolevel) + *logptr(contextptr) << CLOCK() << gettext(" Pollard-rho failure, ntries ") << m << '\n'; + mpz_clear(alloc5); + mpz_clear(alloc4); + mpz_clear(alloc3); + mpz_clear(alloc2); + mpz_clear(alloc1); + mpz_clear(tmpq); + mpz_clear(x); + mpz_clear(x1); + mpz_clear(x2); + mpz_clear(x2k); + mpz_clear(y); + mpz_clear(y1); + mpz_clear(p); + mpz_clear(q); + return -1; + } + // p=irem(p*(x1-x),n,q); + mpz_sub(q,x1,x); + mpz_mul(x2,p,q); +#if 0 // def USE_GMP_REPLACEMENTS + if (mpz_cmp(x2,*n._ZINTptr)>0){ + mp_grow(&alloc1,x2.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = x2.used +2 ; + mpz_set(alloc2,x2); + mpz_set(alloc3,*n._ZINTptr); + // mpz_set_si(alloc4,0); + // mpz_set_si(alloc5,0); + alloc_mp_div(&x2,n._ZINTptr,&tmpq,&p,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); + } + else + mpz_set(p,x2); +#else + mpz_tdiv_r(p,x2,*n._ZINTptr); +#endif + c += 1; + if (c==POLLARD_GCD) { + // g=gcd(abs(p,context0),n); + mpz_abs(q,p); + my_mpz_gcd(g,q,*n._ZINTptr); + if (mpz_cmp_si(g,1)==0) { + mpz_set(y,x); // y=x; + mpz_set(y1,x1); // y1=x1; + mpz_set_si(p,1); // p=1; + a1=a; + m1=m; + c=0; + } + } + }//m=a=2^e-1=l(m) + if (mpz_cmp_si(g,1)==0) { + mpz_set(x1,x); // x1=x;//x1=x_m=x_l(m)-1 + j=3*(a+1)/2; // j=3*iquo(a+1,2); + for (long i=m+1;i<=j;i++){ + // x=f(x,k,n,q); + mpz_mul(x2,x,x); + mpz_add(x2k,x2,*k._ZINTptr); +#if 0 // def USE_GMP_REPLACEMENTS + if (mpz_cmp(x2k,*n._ZINTptr)>0){ + mp_grow(&alloc1,x2k.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = x2k.used +2 ; + mpz_set(alloc2,x2k); + mpz_set(alloc3,*n._ZINTptr); + // mpz_set_si(alloc4,0); + // mpz_set_si(alloc5,0); + alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); + } + else + mpz_set(x,x2); +#else + mpz_tdiv_r(x,x2k,*n._ZINTptr); +#endif + } + m=j; + } + } + //g<>1 ds le paquet de POLLARD_GCD + if (debug_infolevel>5) + CERR << CLOCK() << " Pollard-rho nloops " << m << '\n'; + mpz_set(x,y); // x=y; + mpz_set(x1,y1); // x1=y1; + mpz_set_si(g,1); // g=1; + a=(a1-1)/2; // a=iquo(a1-1,2); + m=m1; + while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0) { +#ifdef TIMEOUT + control_c(); +#endif + a=2*a+1; + while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0 && a>m) { // ok +#ifdef TIMEOUT + control_c(); +#endif + // x=f(x,k,n,q); + mpz_mul(x2,x,x); + mpz_add(x2k,x2,*k._ZINTptr); +#if 0 // def USE_GMP_REPLACEMENTS + if (mpz_cmp(x2k,*n._ZINTptr)>0){ + mp_grow(&alloc1,x2k.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = x2k.used +2 ; + mpz_set(alloc2,x2k); + mpz_set(alloc3,*n._ZINTptr); + alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); + } + else + mpz_set(x,x2k); +#else + mpz_tdiv_r(x,x2k,*n._ZINTptr); +#endif + m += 1; + if (m > maxiter ){ + mpz_clear(alloc5); + mpz_clear(alloc4); + mpz_clear(alloc3); + mpz_clear(alloc2); + mpz_clear(alloc1); + mpz_clear(tmpq); + mpz_clear(x); + mpz_clear(x1); + mpz_clear(x2); + mpz_clear(x2k); + mpz_clear(y); + mpz_clear(y1); + mpz_clear(p); + mpz_clear(q); + return -1; + } + // p=irem(x1-x,n,q); + mpz_sub(q,x1,x); +#if 0 // def USE_GMP_REPLACEMENTS + if (mpz_cmp(q,*n._ZINTptr)>0){ + mp_grow(&alloc1,q.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = q.used +2 ; + mpz_set(alloc2,q); + mpz_set(alloc3,*n._ZINTptr); + // mpz_set_si(alloc4,0); + // mpz_set_si(alloc5,0); + alloc_mp_div(&q,n._ZINTptr,&tmpq,&p,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); + } + else + mpz_set(p,q); +#else + mpz_tdiv_r(p,q,*n._ZINTptr); +#endif + // g=gcd(abs(p,context0),n); // ok + mpz_abs(q,p); + my_mpz_gcd(g,q,*n._ZINTptr); + } + if (mpz_cmp_si(g,1)==0) { + mpz_set(x1,x); // x1=x; + j=3*(a+1)/2; // j=3*iquo(a+1,2); + for (long i=m+1;j>=i;i++){ + // x=f(x,k,n,q); + mpz_mul(x2,x,x); + mpz_add(x2k,x2,*k._ZINTptr); + mpz_tdiv_qr(tmpq,x,x2k,*n._ZINTptr); + } + m=j; + } + } + mpz_clear(alloc5); + mpz_clear(alloc4); + mpz_clear(alloc3); + mpz_clear(alloc2); + mpz_clear(alloc1); + mpz_clear(tmpq); + mpz_clear(x); + mpz_clear(x1); + mpz_clear(x2); + mpz_clear(x2k); + mpz_clear(y); + mpz_clear(y1); + mpz_clear(p); + mpz_clear(q); +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted){ + mpz_clear(g); + return 0; + } + if (mpz_cmp(g,*n._ZINTptr)==0) { + if (k==1) { + mpz_clear(g); + return(pollard(n,-1,contextptr)); + } + else { + if (k*k==1){ + mpz_clear(g); + return(pollard(n,3,contextptr)); + } + else { + if (is_greater(k,50,contextptr)){ +#if 1 + return -1; +#else + ref_mpz_t * ptr=new ref_mpz_t; + mpz_init_set(ptr->z,g); + mpz_clear(g); + return ptr; +#endif + } + else { + mpz_clear(g); + return(pollard(n,k+2,contextptr)); + } + } + } + } + ref_mpz_t * ptr=new ref_mpz_t; + mpz_init_set(ptr->z,g); + mpz_clear(g); + return ptr; + } + + // const short int giac_primes[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997}; + + bool eratosthene(double n,vector * & v){ + static vector *ptr=0; + if (!ptr) + ptr=new vector; + vector &erato=*ptr; + v=ptr; + if (n+1>erato.size()){ + unsigned N=int(n); + ++N; +#if defined BESTA_OS + if (N>2e6) + return false; +#else + if (N>2e9) + return false; +#endif + N = (N*11)/10; + erato=vector(N+1,true); + // insure that we won't recompute all again from start for ithprime(i+1) + for (unsigned p=2;;++p){ + while (!erato[p]) // find next prime + ++p; + if (p*p>N) // finished + return true; + for (unsigned i=2*p;i<=N;i+=p) + erato[i]=false; // remove p multiples + } + } + return true; + } + + bool eratosthene2(double n,vector * & v){ + static vector *ptr=0; + if (!ptr) + ptr=new vector; + vector &erato=*ptr; + v=ptr; + if (n/2>=erato.size()){ + unsigned N=int(n); + ++N; +#if defined BESTA_OS + if (N>4e6) + return false; +#else + if (N>2e9) + return false; +#endif + // 11/20 insures that we won't recompute all again from start for ithprime(i+1) + N = (ulonglong(N)*11)/20; // keep only odd numbers in sieve + erato=vector(N+1,true); //erato[i] stands for 2*i+1 <-> n corresponds to erato[n/2] + for (unsigned p=3;;p+=2){ + while (!erato[p/2]) // find next prime (first one is p==3) + p+=2; + if (p*p>2*N+1) // finished + return true; + // p is prime, set p*p, (p+2)*p, etc. to be non prime + for (unsigned i=(p*p)/2;i<=N;i+=p) + erato[i]=false; // remove p multiples + } + } + return true; + } + + // ithprime(n) is approx invli(n)+invli(sqrt(n))/4 where invli is reciproc. + // of Li(x)=Ei(ln(x)) + // For fast code, cf. https://github.com/kimwalisch/primecount + static const char _ithprime_s []="ithprime"; + static symbolic symb_ithprime(const gen & args){ + return symbolic(at_ithprime,args); + } + static gen ithprime(const gen & g_,GIAC_CONTEXT){ + gen g(g_); + if (!is_integral(g)) + return gentypeerr(contextptr); + if (g.type!=_INT_) + return gensizeerr(contextptr); // symb_ithprime(g); + int i=g.val; + if (i<0) + return gensizeerr(contextptr); + if (i==0) + return 1; + if (i<=int(sizeof(giac_primes)/sizeof(short int))) + return giac_primes[i-1]; + vector * vptr=0; +#if 1 + if (!eratosthene2(i*std::log(double(i))*1.1,vptr)) + return gensizeerr(contextptr); + unsigned count=2; + unsigned s=unsigned(vptr->size()); + for (unsigned k=2;ksize(); + for (unsigned k=4;k * vptr=0; + if (!eratosthene2(i+2,vptr)) + return gensizeerr(contextptr); + unsigned count=1; // 2 is prime, then count odd primes + i=(i-1)/2; + for (int k=1;k<=i;++k){ + if ((*vptr)[k]) + ++count; + } + return int(count); + } + gen _nprimes(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type==_VECT) + return apply(args,_nprimes,contextptr); + return nprimes(args,contextptr); + } + static define_unary_function_eval (__nprimes,&_nprimes,_nprimes_s); + define_unary_function_ptr5( at_nprimes ,alias_at_nprimes,&__nprimes,0,true); + + bool is_divisible_by(const gen & n,unsigned long a){ + if (n.type==_ZINT){ +#if defined USE_GMP_REPLACEMENTS + mp_digit c; + mp_mod_d(n._ZINTptr, a, &c); + return c==0; +#else + return mpz_divisible_ui_p(*n._ZINTptr,a); +#endif + } + return n.val%a==0; + } + + // find trivial factors of n, + // if add_last is true the remainder is put in the vecteur, + // otherwise n contains the remainder + vecteur pfacprem(gen & n,bool add_last,GIAC_CONTEXT){ + gen a; + gen q; + int p,i,prime; + vecteur v(2); + vecteur u; + if (is_zero(n)) + return u; + if (n.type==_ZINT){ + ref_mpz_t * cur = new ref_mpz_t; + mpz_t div,q,r,alloc1,alloc2,alloc3,alloc4,alloc5; + mpz_set(cur->z,*n._ZINTptr); + mpz_init_set(q,*n._ZINTptr); + mpz_init(r); + mpz_init(div); + mpz_init(alloc1); + mpz_init(alloc2); + mpz_init(alloc3); + mpz_init(alloc4); + mpz_init(alloc5); + for (i=0;iz,1)==0) + break; + prime=giac_primes[i]; + mpz_set_ui(div,prime); +#ifdef USE_GMP_REPLACEMENTS + for (p=0;;p++){ + mp_grow(&alloc1,cur->z.used+2); + mpz_set_ui(alloc1,0); + alloc1.used = cur->z.used +2 ; + mpz_set(alloc2,cur->z); + mpz_set(alloc3,div); + alloc_mp_div(&cur->z,&div,&q,&r,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5); + // mpz_tdiv_qr(q,r,cur->z,div); + if (mpz_cmp_si(r,0)) + break; + mp_exch(&cur->z,&q); + } + // *logptr(contextptr) << "Factor " << prime << " " << p << '\n'; + if (p){ + u.push_back(prime); + u.push_back(p); + } +#else + if (mpz_divisible_ui_p(cur->z,prime)){ + mpz_set_ui(div,prime); + for (p=0;;p++){ + mpz_tdiv_qr(q,r,cur->z,div); + if (mpz_cmp_si(r,0)) + break; + mpz_swap(cur->z,q); + } + // *logptr(contextptr) << "Factor " << prime << " " << p << '\n'; + u.push_back(prime); + u.push_back(p); + } +#endif + } // end for on smal primes + mpz_clear(alloc5); + mpz_clear(alloc4); + mpz_clear(alloc3); + mpz_clear(alloc2); + mpz_clear(alloc1); + mpz_clear(div); mpz_clear(r); mpz_clear(q); + n=cur; + } + else { + for (i=0;iTerminal.MakeUnvisible(); +#endif +#endif + return res; + } +#else // USE_GMP_REPLACEMENTS + static gen pollardsieve(const gen &a,gen k,bool & do_pollard,GIAC_CONTEXT){ + gen b=do_pollard?pollard(a,k,contextptr):-1; +#ifdef TIMEOUT + control_c(); +#endif +#ifdef HAVE_LIBECM + if (is_greater(a,1e60,context0) && b==-1 && !ctrl_c && !interrupted && _isprime(a,contextptr)==0){ + int res; + gen F(1LL<<33); + for (int i=0;i<200;++i){ // searching factors of size about 20 digits + res=ecm_factor(*F._ZINTptr, *a._ZINTptr, 11e3, 0); + if (res!=0) break; + } + if (res!=0) + b=F; + } +#endif +#ifdef GIAC_MPQS + if (b==-1 && !ctrl_c && !interrupted){ + do_pollard=false; + if (msieve(a,b,contextptr)) return b; else return -1; } +#else + if (b==-1) + *logptr(contextptr) << "Integer too large for factorization algorithm\n"; +#endif + if (b==-1) + b=a; + return b; + } +#endif // USE_GMP_REPLACEMENTS + + static gen ifactor2(const gen & n,vecteur & v,bool & do_pollard,GIAC_CONTEXT){ + if (is_greater(giac_last_prime*giac_last_prime,n,contextptr) || is_probab_prime_p(n) ){ + v.push_back(n); + return 1; + } + // Check for power of integer: arg must be > 1e4, n*ln(arg)=d => n2 && i%2==0) || + (i>3 && i%3==0) || + (i>5 && i%5==0) || + (i>7 && i%7==0) ) + continue; + gen u; + if (i==2) + u=isqrt(n); + else { + double x=std::pow(d,1./i); + u=longlong(x); + } + if (pow(u,i,contextptr)==n){ + vecteur w; + do_pollard=true; + ifactor2(u,w,do_pollard,contextptr); + for (int j=0;j5) + CERR << "Pollard begin " << CLOCK() << '\n'; + bool do_pollard=true; + gen a=ifactor2(n,v,do_pollard,contextptr); + if (a==-1) + return makevecteur(gensizeerr(gettext("Quadratic sieve failure, perhaps number too large"))); + if (is_zero(a)) + return makevecteur(gensizeerr(gettext("Stopped by user interruption"))); + n=1; + return v; + } + + void mergeifactors(const vecteur & f,const vecteur &g,vecteur & h){ + h=f; + for (unsigned i=0;iempty()) + return giac_ifactors(n0._VECTptr->front(),contextptr); + if (!is_integer(n0) || is_zero(n0)) + return vecteur(1,gensizeerr(gettext("ifactors"))); + if (is_one(n0)) + return vecteur(0); + if (_isprime(n0,contextptr)!=0) + return makevecteur(n0,1); +#if 1 // set to 0 to disable ecm and pari, using giac sieve only + bool ifactor_pari=true; +#ifdef HAVE_LIBECM + int res; + gen F(1LL<<33); + double B1=1e6; + int nbits=sizeinbase2(n0); + int maxiter=ECM_MAXITER; + if (nbits<242) + maxiter = 32; + else if (nbits<244) + maxiter = 64; + else if (nbits<246) + maxiter = 128; + else if (nbits<248) + maxiter = 256; + else if (nbits<250) + maxiter = 512; + for (int i=0;i=256; +#endif +#ifdef HAVE_LIBPARI + if (ifactor_pari){ +#ifdef __APPLE__ + return vecteur(1,gensizeerr(gettext("(Mac OS) Large number, you can try pari(); pari_factor(")+n0.print(contextptr)+")")); +#endif + gen g(pari_ifactor(n0),contextptr); + if (g.type==_VECT){ + matrice m(mtran(*g._VECTptr)); + vecteur res; + const_iterateur it=m.begin(),itend=m.end(); + for (;it!=itend;++it){ + if (it->type!=_VECT) return vecteur(1,gensizeerr(gettext("ifactor.cc/ifactors"))); + res.push_back(it->_VECTptr->front()); + res.push_back(it->_VECTptr->back()); + } + return res; + } + } +#endif // LIBPARI +#endif + return giac_ifactors(n0,contextptr); + } + + vecteur ifactors(const gen & n0,GIAC_CONTEXT){ + gen n(n0); + vecteur f=pfacprem(n,false,contextptr); + if (is_undef(f)) + return f; + vecteur g=ifactors1(n,contextptr); + if (is_undef(g)) + return g; + return mergevecteur(f,g); + } + + vecteur ifactors(const gen & r,const gen & i,const gen & ri,GIAC_CONTEXT){ + gen norm=r*r+i*i; + gen reste(ri); + const vecteur & facto = ifactors(norm,contextptr); + if (is_undef(facto)) + return facto; + int l=int(facto.size())/2; + vecteur res; + for (int i=0;i0;--mult,++multp){ + if (!is_zero(reste % prime)) + break; + reste=reste/prime; + } + if (multp){ + res.push_back(prime); + res.push_back(multp); + } + if (mult){ + prime=conj(prime,contextptr); + res.push_back(prime); + res.push_back(mult); + reste=reste/pow(prime,mult,contextptr); + } + } + if (!is_one(reste)){ + res.insert(res.begin(),1); + res.insert(res.begin(),reste); + } + return res; + } + + gen ifactors(const gen & args,int maplemode,GIAC_CONTEXT){ + if ( (args.type==_INT_) || (args.type==_ZINT)){ + if (is_zero(args)){ + if (maplemode==1) + return makevecteur(args,vecteur(0)); + else + return makevecteur(args); + } + vecteur v(ifactors(abs(args,contextptr),contextptr)); // ok + if (!v.empty() && is_undef(v.front())) + return v.front(); + if (maplemode!=1){ + if (is_positive(args,context0)) + return v; + return mergevecteur(makevecteur(minus_one,plus_one),v); + } + vecteur res; + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;it+=2){ + res.push_back(makevecteur(*it,*(it+1))); + } + if (is_positive(args,context0)) + return makevecteur(plus_one,res); + else + return makevecteur(minus_one,res); + } + if (args.type==_CPLX && is_integer(*args._CPLXptr) && is_integer(*(args._CPLXptr+1))) + return ifactors(*args._CPLXptr,*(args._CPLXptr+1),args,contextptr); + return gentypeerr(gettext("ifactors")); + } + + gen _ifactors(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type==_VECT && args.subtype==_SEQ__VECT && args._VECTptr->size()==2 ){ + gen g=args._VECTptr->front(); + gen b=args._VECTptr->back(); + if (b==at_matrix || b==at_prod){ + g=_ifactors(g,contextptr); + if (g.type!=_VECT || g._VECTptr->size()%2) + return g; + if (b==at_prod){ + vecteur & v =*g._VECTptr; + vecteur l; + for (int i=0;isize()/2,2,g),contextptr); + } +#if !defined EMCC && defined HAVE_LIBPARI + if (b.type==_SYMB){ + gen res; + // b is assumed to be a minimal polynomial check if g is a norm + if (!pari_intnorm(g,b,lvar(b),res,contextptr)) + return gensizeerr(gettext("Not implemented. Try to compile with PARI")); + return res; + } +#endif + } + if (args.type==_VECT) + return apply(args,_ifactors,contextptr); + gen g(args); + if (!is_integral(g)) + return gensizeerr(contextptr); + if (calc_mode(contextptr)==1){ // ggb returns factors repeted instead of multiplicites + vecteur res; + gen in=ifactors(g,0,contextptr); + if (in.type==_VECT){ + for (unsigned i=0;isize();i+=2){ + gen f=in[i],m=in[i+1]; + if (m.type==_INT_){ + for (int j=0;jsommet; + if (u==at_inv){ + vecteur v=in_factors(gf._SYMBptr->feuille,contextptr); + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;it+=2) + *(it+1)=-*(it+1); + return v; + } + if (u==at_neg){ + vecteur v=in_factors(gf._SYMBptr->feuille,contextptr); + v.push_back(minus_one); + v.push_back(plus_one); + return v; + } + if ( (u==at_pow) && (gf._SYMBptr->feuille._VECTptr->back().type==_INT_) ){ + vecteur v=in_factors(gf._SYMBptr->feuille._VECTptr->front(),contextptr); + gen k=gf._SYMBptr->feuille._VECTptr->back(); + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;it+=2) + *(it+1)=k* *(it+1); + return v; + } + if (u!=at_prod) + return makevecteur(gf,plus_one); + vecteur res; + const_iterateur it=gf._SYMBptr->feuille._VECTptr->begin(),itend=gf._SYMBptr->feuille._VECTptr->end(); + for (;it!=itend;++it){ + res=mergevecteur(res,in_factors(*it,contextptr)); + } + return res; + } + static vecteur in_factors1(const vecteur & res,GIAC_CONTEXT){ + gen coeff(1); + vecteur v; + const_iterateur it=res.begin(),itend=res.end(); + for (;it!=itend;it+=2){ + if (lidnt(*it).empty()) + coeff=coeff*(pow(*it,*(it+1),contextptr)); + else + v.push_back(makevecteur(*it,*(it+1))); + } + return makevecteur(coeff,v); + } + vecteur factors(const gen & g,const gen & x,GIAC_CONTEXT){ + gen gf=factor(g,x,false,contextptr); + vecteur res=in_factors(gf,contextptr); + if (xcas_mode(contextptr)!=1) + return res; + return in_factors1(res,contextptr); + } + vecteur sqff_factors(const gen & g,GIAC_CONTEXT){ + gen gf=_sqrfree(g,contextptr); + return in_factors(gf,contextptr); + } + static const char _factors_s []="factors"; + gen _factors(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type==_VECT && args.subtype==_SEQ__VECT && args._VECTptr->size()>=2 && args._VECTptr->back()==at_matrix){ + gen g; + if (args._VECTptr->size()==2) + g=args._VECTptr->front(); + else + g=gen(vecteur(args._VECTptr->begin(),args._VECTptr->end()-1),_SEQ__VECT); + g=_factors(g,contextptr); + if (g.type!=_VECT || g._VECTptr->size()%2) + return g; + return _matrix(makesequence(g._VECTptr->size()/2,2,g),contextptr); + } + if (args.type==_VECT && args.subtype==_POLY1__VECT){ + gen x(identificateur("xfactors")); + gen res=_poly2symb(makesequence(args,x),contextptr); + res=_factors(res,contextptr); + if (res.type==_VECT && res._VECTptr->size()==2){ + vecteur v(*res._VECTptr); + for (size_t i=0;isize()==2){ + gen j=args._VECTptr->back(); + gen res=_factors(args._VECTptr->front()*j,contextptr); + if (res.type==_VECT && xcas_mode(contextptr)!=1) + res=in_factors1(*res._VECTptr,contextptr); + if (res.type==_VECT && res._VECTptr->size()==2){ + res._VECTptr->front()=recursive_normal(res._VECTptr->front()/j,contextptr); + if (xcas_mode(contextptr)!=1){ + if (is_one(res._VECTptr->front())) + res=res._VECTptr->back(); + else { + j=res._VECTptr->front(); + res=res._VECTptr->back(); + if (res.type==_VECT) + res=mergevecteur(makevecteur(j,1),*res._VECTptr); + } + vecteur v; + aplatir(*res._VECTptr,v,contextptr); + res=v; + } + } + return res; + } + if (args.type==_VECT) + return apply(args,_factors,contextptr); + return factors(args,vx_var,contextptr); + } + static define_unary_function_eval (__factors,&_factors,_factors_s); + define_unary_function_ptr5( at_factors ,alias_at_factors,&__factors,0,true); + + static gen ifactors2ifactor(const vecteur & l,bool quote){ + int s; + s=int(l.size()); + gen r; + vecteur v(s/2); + for (int j=0;jsize()==1 && is_integer(n._VECTptr->front())) + return ifactor(n,contextptr); + if (n.type==_VECT) + return apply(n,_ifactor,contextptr); + if (!is_integral(n)) + return gensizeerr(contextptr); + if (is_strictly_positive(-n,0)) + return -_ifactor(-n,contextptr); + if (n.type==_INT_ && n.val<=3) + return n; + return ifactor(n,contextptr); + } + static const char _ifactor_s []="ifactor"; + static define_unary_function_eval (__ifactor,&_ifactor,_ifactor_s); + define_unary_function_ptr5( at_ifactor ,alias_at_ifactor,&__ifactor,0,true); + + static const char _factoriser_entier_s []="factoriser_entier"; + static define_unary_function_eval (__factoriser_entier,&_ifactor,_factoriser_entier_s); + define_unary_function_ptr5( at_factoriser_entier ,alias_at_factoriser_entier,&__factoriser_entier,0,true); + + static vecteur divis(const vecteur & l3,GIAC_CONTEXT){ + vecteur l1(1); + gen d,e; + int s=int(l3.size()); + gen taille=1; + for (int k=0;kLIST_SIZE_LIMIT) + return vecteur(1,gendimerr(contextptr)); + l1.reserve(taille.val); + l1[0]=1;//l3.push_back(..); + for (int k=0;ksize()!=4) ) + return gensizeerr(contextptr); + vecteur a(2).type==_STRNG && args.subtype==-1{ + if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) ) + return gensizeerr(contextptr); + vecteur a(2))) return args){ + if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) ) + return gensizeerr(contextptr); + vecteur a(2); + if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) ) + return gensizeerr(contextptr); + vecteur a(2),b(2); + a[0]=args[0]; + a[1]=args[1]; + b[0]=args[2]; + b[1]=args[3]; + //gen a=args[0],p=args[1], b=args[2],q=args[3]; + return ichinreme(a,b); + } + static const char _ichinreme_s []="ichinreme"; + static define_unary_function_eval (__ichinreme,&_ichinreme,_ichinreme_s); + define_unary_function_ptr5( at_ichinreme ,alias_at_ichinreme,&__ichinreme,0,true); + */ + + gen euler(const gen & e,GIAC_CONTEXT){ + if (e==0) + return e; + vecteur v(ifactors(e,contextptr)); + if (!v.empty() && is_undef(v.front())) return v.front(); + const_iterateur it=v.begin(),itend=v.end(); + for (gen res(plus_one);;){ + if (it==itend) + return res; + gen p=*it; + ++it; + int n=it->val; + res = res * (p-plus_one)*pow(p,n-1); + ++it; + } + } + static const char _euler_s []="euler"; + gen _euler(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type==_VECT) + return apply(args,_euler,contextptr); + if ( is_integer(args) && is_positive(args,contextptr)) + return euler(args,contextptr); + return gentypeerr(contextptr); + } + static define_unary_function_eval (__euler,&_euler,_euler_s); + define_unary_function_ptr5( at_euler ,alias_at_euler,&__euler,0,true); + + gen pa2b2(const gen & p,GIAC_CONTEXT){ + if (p==2) + return makevecteur(1,1); + if (!is_integer(p) || (p%4)!=1 || is_greater(1,p,contextptr)) return gensizeerr(contextptr);// car p!=1 mod 4 + gen q=(p-1)/4; + gen a=2; + gen ra; + ra=powmod(a,q,p); + //on cherche ra^2=-1 mod p avec ra!=1 et ra !=p-1 + while ((a!=p-1) && ((ra==1)|| (ra==p-1))){ + a=a+1; + ra=powmod(a,q,p); + } + if ((ra==1)||(ra==p-1)) return gensizeerr(contextptr);//car p n'est pas premier + gen ux=1,uy=ra,vx=0,vy=p,wx,wy; + gen m=1; + while(m!=0){ + if (is_positive(vx*vx+vy*vy-ux*ux-uy*uy,0)){ + //on echange u et v + wx=vx; + wy=vy; + vx=ux; + vy=uy; + ux=wx; + uy=wy; + } + gen alpha=inv(2,contextptr)-(ux*vx+uy*vy)*inv(vx*vx+vy*vy,contextptr); + //m=partie entiere de alpha (-v.v/2<(u+mv).v<=v.v/2) + m=_floor(alpha,contextptr); + ux=ux+m*vx; + uy=uy+m*vy; + } + vecteur v(2); + //v repond a la question + v[0]=abs(vx,contextptr); // ok + v[1]=abs(vy,contextptr); // ok + if (vx*vx+vy*vy!=p) + return gensizeerr(contextptr); + return v; + } + gen _pa2b2(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (!is_integer(args)) + return gensizeerr(contextptr); + gen n=args; + return pa2b2(n,contextptr); + } + static const char _pa2b2_s []="pa2b2"; + static define_unary_function_eval (__pa2b2,&_pa2b2,_pa2b2_s); + define_unary_function_ptr5( at_pa2b2 ,alias_at_pa2b2,&__pa2b2,0,true); + + static gen ipropfrac(const gen & a,const gen & b,GIAC_CONTEXT){ + if (!is_integer(a) || !is_integer(b)) + return gensizeerr(contextptr); + gen r=a%b; + gen q=(a-r)/b; + gen d=gcd(r,b); + r=r/d; + gen b1=b/d; + if (r==0) + return q; + gen v; + v=symbolic(at_division,gen(makevecteur(r,b1),_SEQ__VECT)); + gen w; + w=symbolic(at_plus,gen(makevecteur(q,v),_SEQ__VECT)); + if (calc_mode(contextptr)==1) + return symbolic(at_quote,w); + return w; + } + gen _propfrac(const gen & arg,GIAC_CONTEXT){ + if ( arg.type==_STRNG && arg.subtype==-1) return arg; + gen args(arg); + vecteur v; + if (arg.type==_VECT && arg._VECTptr->size()==2){ + v=vecteur(1,arg._VECTptr->back()); + args=arg._VECTptr->front(); + lvar(args,v); + } + else + v=lvar(arg); + gen g=e2r(args,v,contextptr); + gen a,b; + fxnd(g,a,b); + if (v.empty()) + return ipropfrac(a,b,contextptr); + else { + gen d=r2e(b,v,contextptr); + g=_quorem(makesequence(r2e(a,v,contextptr),d,v.front()),contextptr); + if (is_undef(g)) return g; + vecteur &v=*g._VECTptr; + return v[0]+rdiv(v[1],d,contextptr); + } + } + static const char _propfrac_s []="propfrac"; + static define_unary_function_eval (__propfrac,&_propfrac,_propfrac_s); + define_unary_function_ptr5( at_propfrac ,alias_at_propfrac,&__propfrac,0,true); + + void step_egcd(int a,int b,GIAC_CONTEXT){ + gprintf("===============",vecteur(0),1,contextptr); + gprintf("Extended Euclide algorithm for a=%gen and b=%gen",makevecteur(a,b),1,contextptr); + gprintf("L%gen: 1*a+0*b=%gen",makevecteur(1,a),1,contextptr); + gprintf("L%gen: 0*a+1*b=%gen",makevecteur(2,b),1,contextptr); + int i=3; + int u0=1,v0=0,u1=0,v1=1,u2,v2; + for (;b;++i){ + int q=a/b; + u2=u0-q*u1; + v2=v0-q*v1; + int r=a-q*b; + gprintf("iquo(%gen,%gen)=%gen",makevecteur(a,b,q),1,contextptr); + gprintf("L%gen=L%gen-%gen*L%gen: %gen*a+%gen*b=%gen",makevecteur(i,i-2,q,i-1,u2,v2,r),1,contextptr); + u0=u1; + u1=u2; + v0=v1; + v1=v2; + a=b; + b=r; + } + gprintf("Bezout identity %gen*a+%gen*b=%gen",makevecteur(u0,v0,a),1,contextptr); + } + + gen iabcuv(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){ + gen d=gcd(a,b); + if (c%d!=0) return gensizeerr(gettext("No solution in ring")); + gen a1=a/d,b1=b/d,c1=c/d; + gen u,v,w; + if (a1.type==_INT_ && b1.type==_INT_ && step_infolevel(contextptr)) + step_egcd(a1.val,b1.val,contextptr); + egcd(a1,b1,u,v,w); + vecteur r(2); + r[0]=smod(u*c1,b); + r[1]=iquo(c-r[0]*a,b); + return r; + } + gen _iabcuv(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()!=3) ) + return gensizeerr(contextptr); + gen a=args[0],b=args[1],c=args[2]; + return iabcuv(a,b,c,contextptr); + } + static const char _iabcuv_s []="iabcuv"; + static define_unary_function_eval (__iabcuv,&_iabcuv,_iabcuv_s); + define_unary_function_ptr5( at_iabcuv ,alias_at_iabcuv,&__iabcuv,0,true); + + gen abcuv(const gen & a,const gen & b,const gen & c,const gen & x,GIAC_CONTEXT){ + gen g=_egcd(makesequence(a,b,x),contextptr); + if (is_undef(g)) return g; + vecteur & v=*g._VECTptr; + gen h=_quorem(makesequence(c,v[2],x),contextptr); + if (is_undef(h)) return h; + vecteur & w=*h._VECTptr; + if (!is_zero(w[1])) + return gensizeerr(gettext("No solution in ring")); + gen U=v[0]*w[0],V=v[1]*w[0]; + if (_degree(makesequence(c,x),contextptr).val<_degree(makesequence(a,x),contextptr).val+_degree(makesequence(b,x),contextptr).val ){ + U=_rem(makesequence(U,b,x),contextptr); + V=_rem(makesequence(V,a,x),contextptr); + } + return makevecteur(U,V); + } + gen _abcuv(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()<3) ) + return gensizeerr(contextptr); + vecteur & v =*args._VECTptr; + if (v.size()>3) + return abcuv(v[0],v[1],v[2],v[3],contextptr); + return abcuv(v[0],v[1],v[2],vx_var,contextptr); + } + static const char _abcuv_s []="abcuv"; + static define_unary_function_eval (__abcuv,&_abcuv,_abcuv_s); + define_unary_function_ptr5( at_abcuv ,alias_at_abcuv,&__abcuv,0,true); + + gen simp2(const gen & a,const gen & b,GIAC_CONTEXT){ + vecteur r(2); + gen d=gcd(a,b); + r[0]=normal(a/d,contextptr); + r[1]=normal(b/d,contextptr); + return r; + } + gen _simp2(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()!=2) ) + return gensizeerr(contextptr); + gen a=args[0],b=args[1]; + if ( (a.type==_VECT) || (b.type==_VECT) ) + return gensizeerr(contextptr); + return simp2(a,b,contextptr); + } + static const char _simp2_s []="simp2"; + static define_unary_function_eval (__simp2,&_simp2,_simp2_s); + define_unary_function_ptr5( at_simp2 ,alias_at_simp2,&__simp2,0,true); + + gen fxnd(const gen & a){ + vecteur v(lvar(a)); + gen g=e2r(a,v,context0); // ok + gen n,d; + fxnd(g,n,d); + return makevecteur(r2e(n,v,context0),r2e(d,v,context0)); // ok + } + gen _fxnd(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type==_VECT) + return apply(args,fxnd); + return fxnd(args); + } + static const char _fxnd_s []="fxnd"; + static define_unary_function_eval (__fxnd,&_fxnd,_fxnd_s); + define_unary_function_ptr5( at_fxnd ,alias_at_fxnd,&__fxnd,0,true); + + int generator(int p,const vecteur & v){ + vector w; + for (int i=0;i2 && i%2==0) || + (i>3 && i%3==0) || + (i>5 && i%5==0) || + (i>7 && i%7==0) ) + continue; + gen u; + if (i==2) + u=isqrt(q); + else if (i==4) + u=isqrt(isqrt(q)); + else { + double x=std::pow(d,1./i); + u=longlong(x); + } + if (pow(u,i,contextptr)==q){ + cyclic=2; + o=q*(1-inv(u,contextptr)); + break; + } + } + } + if (cyclic){ + if (cyclic==1 && p.type==_INT_) + return makemod(generator(p.val),p); + gen g=prime_factors(o,true,contextptr); + if (g.type!=_VECT) return undef; + vecteur & v=*g._VECTptr; + vecteur w; + for (int i=0;i currently, znprimroot(k) expects a prime<2^31"); + return makemod(generator(p.val),p); + } + static const char _znprimroot_s []="znprimroot"; + static define_unary_function_eval (__znprimroot,&_znprimroot,_znprimroot_s); + define_unary_function_ptr5( at_znprimroot ,alias_at_znprimroot,&__znprimroot,0,true); + + int znorder(int k,int p,int phi,const vecteur & v){ + int o=1; + for (int i=0;isize()!=2) + return gensizeerr(contextptr); + gen k=args._VECTptr->front(),p=args._VECTptr->back(); +#ifdef HAVE_LIBPARI + if (gcd(p,k)!=1) + return 0; + return _pari(makesequence(string2gen("znorder",false),makemod(k,p)),contextptr); +#endif + if (is_greater(1,p,contextptr)) + return undef; + if (k.type==_INT_ && p.val==_INT_ ) + return znorder(k.val,p.val); + return znorder(k,p); + } + static const char _znorder_s []="znorder"; + static define_unary_function_eval (__znorder,&_znorder,_znorder_s); + define_unary_function_ptr5( at_znorder ,alias_at_znorder,&__znorder,0,true); + + // b1 *= m mod p + // m += (m>>31) &p; + // int msurp=((1LL<<31)*m)/p+1; + inline int precond_mulmod31(int b1,int m,int p,int msurp){ + // b1 += (b1>>31) &p; + int t=longlong(b1)*m-((longlong(b1)*msurp)>>31)*p; + // t += (t>>31)&p; // t positive (or at least t-p is valid) + return t; + } + + // Harvey algorithm for Bernoulli numbers + // https://arxiv.org/pdf/0807.1347.pdf + // k must be even and p prime + // https://web.maths.unsw.edu.au/~davidharvey/code/bernmm/index.html + // bernmm lib + int bernoulli_mod(int k,int p){ +#ifdef HAVE_LIBBERNMM + return bernmm::bern_modp(p,k); +#endif + if (k>p-3){ + int m=k % (p-1); // now m11?znorder(2,p,p-1,v):0; + if (debug_infolevel) + CERR << CLOCK()*1e-6 << " end generator/znorder \n"; + if (N>4 && k%N){ + // faster summation is possible + int n=(N%2)?N:N/2; + int m=(p-1)/2/n; + // twokm1=2^(k-1), gi=g^i, gkm1i=(g^(k-1))^i + longlong S=0,twokm1=powmod(2,(k-1)%N,p),gi=1,gkm1i=1; + int msurp=((1LL<<31)*twokm1)/p+1; + for (int i=0;i>31)<<1))*pow2;// (2*(1+(gi2j>>31))-1)*pow2; + gi2j -= (gi2j>>31)*p; + pow2=precond_mulmod31(pow2,twokm1,p,msurp);// (pow2*twokm1)%p; +#else + gi2j <<= 1; + if (gi2j>=p){ + gi2j -= p; + // f=-1 + s -= pow2; + if (s<0) + s += p; + } + else { + // f=1 + s += pow2; + if (s>=p) + s -= p; + } + pow2=(pow2*twokm1)%p; +#endif + } + // update g^i for next i iteration + gi=(gi*g)%p; + // s*(g^(k-1))^i + s=((s%p)*gkm1i)%p; + S += s; + if (S>=p) + S -=p; + // update (g^(k-1))^i for next i iteration + gkm1i=(gkm1i*r)%p; + } + // final answer k/(2^(-(k-1))-2)*S + S=(S*k)%p; + S=(S*invmod(invmod(twokm1,p)-2,p))%p; + return S; + } + if (g%2) + u=(g-1)/2; + else + u=(longlong(g-1)*invmod(2,p))%p; + int S=0,X=1,Y=r; + for (int i=1;i<=p/2;i++){ + int q=(longlong(g)*X)/p; + S=(S+(longlong(u)-q)*Y) % p; + X=(longlong(g)*X) % p; + Y=(longlong(r)*Y) % p; + } + int res=(2*longlong(k)*S)%p; + res=(longlong(res)*invmod(1-powmod(g,k,p),p))%p; + return res; + } + +#ifndef USE_GMP_REPLACEMENTS + void ichinrem_inplace(int r,int m,gen & res,const gen & pim,int & proba,mpz_t & tmpz){ + if (pim.type==_ZINT && res.type==_ZINT){ + longlong amodm=mpz_fdiv_ui(*res._ZINTptr,m); + if (amodm!=r){ + gen u,v,d; longlong U; + egcd(pim,m,u,v,d); + if (u.type==_ZINT) + U=mpz_fdiv_ui(*u._ZINTptr,m); + else + U=u.val; + if (d==-1){ U=-U; v=-v; d=1; } + mpz_mul_si(tmpz,*pim._ZINTptr,(U*(r-amodm))%m); + mpz_add(*res._ZINTptr,*res._ZINTptr,tmpz); + proba=0; + } + else ++proba; + } + } +#endif + + const double m_ln2=0.69314718055994531; + // Inspired by David Harvey code (bernmm) + gen bernoulli_rat(int k){ + long bound1 = (long) std::ceil((k + 0.5) * std::log(double(k)) /m_ln2); + if (bound1<37) + bound1=37; + // Computes the denominator of B_k using Clausen/von Staudt. + // loop through factors of k + gen D=1; + for (int f=1; f*f<=k; f++){ + // if f divides k.... + if (k % f == 0){ + // ... then both f + 1 and k/f + 1 are candidates for primes + // dividing the denominator of B_k + if (is_probab_prime_p(f+1)) + D = (f+1)*D; + if (f*f != k){ + int tmp=k/f+1; + if (is_probab_prime_p(tmp)) + D = tmp*D; + } + } + } + double bits= (k+0.5)*std::log(double(k))/m_ln2 - 4.094*k + 2.470 + + std::log(evalf_double(D,1,context0)._DOUBLE_val)/m_ln2 ; + gen res(0.0),pip=1; + mpz_t tmpz; mpz_init(tmpz); + for (int p = 5; ; p = nextprime(p+1).val){ + if (k % (p-1) == 0) + continue; + if (debug_infolevel) + COUT << CLOCK()*1e-6 << " start bernoulli_mod " << p << '\n'; + int cur=bernoulli_mod(k,p); + if (debug_infolevel) + COUT << CLOCK()*1e-6 << " end bernoulli_mod " << p << '\n'; + if (res.type==_DOUBLE_) + res=cur; + else { +#ifndef USE_GMP_REPLACEMENTS + if (res.type==_ZINT && pip.type==_ZINT){ + int proba=0; // not used + ichinrem_inplace(cur,p,res,pip,proba,tmpz); + } else +#endif + res=ichinrem(gen(cur),res,gen(p),pip); + } + pip = p*pip; + bits -= std::log(double(p))/m_ln2; + if (bits<-1) + break; + } + mpz_clear(tmpz); + res=smod(res*D,pip); + int s=fastsign(res,context0); + if (k%4==2){ + if (s==-1) + res += pip; + } + else { + if (s==1) + res -= pip; + } + //COUT << _evalf(makesequence(res/pip,30),context0) << '\n'; + return res/D; + } + + gen _bernoulli_mod(const gen & args,GIAC_CONTEXT){ + if (args.type!=_VECT || args._VECTptr->size()!=2) + return gensizeerr(contextptr); + gen k=args._VECTptr->front(),p=args._VECTptr->back(); + if (k.type!=_INT_ || k.val<2 || k.val%2 || p.type!=_INT_ || !is_probab_prime_p(p) ) + return gentypeerr(contextptr); + return bernoulli_mod(k.val,p.val); + } + static const char _bernoulli_mod_s []="bernoulli_mod"; + static define_unary_function_eval (__bernoulli_mod,&_bernoulli_mod,_bernoulli_mod_s); + define_unary_function_ptr5( at_bernoulli_mod ,alias_at_bernoulli_mod,&__bernoulli_mod,0,true); + + inline void new_xab(int & x, int & a, int& b,const int N,const int n,const int alpha,const int beta) { + switch (x % 3) { + case 0: + x = longlong(x)*x % N; + a = longlong(a)*2 % n; + b = longlong(b)*2 % n; + break; + case 1: + x = longlong(x)*alpha % N; + a = (a+1) % n; + break; + case 2: + x = longlong(x)*beta % N; + b = (b+1) % n; + break; + } + } + + // N prime, solve alpha^e=beta mod N using Pollard-Rho + int baby64(int alpha,int beta,int N,int n){ + int x = 1, a = 0, b = 0; // x=alpha^a*beta^b + int X = x, A = a, B = b; // X=alpha^A*beta^B + for (int i = 1; i < n; ++i) { + new_xab(x,a,b,N,n,alpha,beta); + new_xab(X,A,B,N,n,alpha,beta); + new_xab(X,A,B,N,n,alpha,beta); + if (x==X){ + // alpha^a*beta^b=alpha^A*beta^B hence + // alpha^(A-a)=beta^(B-b) mod n, (B-b)*e=(A-a) mod n + int b1=B-b,a1=a-A; + int g=gcd(b1,n); + if (a1%g) + return -1; + // b1*e=a1+k*n1 <-> b2*e=a2+k*n2 + int b2=b1/g,a2=a1/g,n2=n/g; + longlong b3=invmod(b2,n2); // e=b3*a2 mod n2 + int e0=(b3*a2) % n2; + for (longlong k=0;k b2*e=a2+k*n2 + longlong b2=b1/g,a2=a1/g,n2=n/g; + int128_t b3=invmod(b2,n2); // e=b3*a2 mod n2 + if (b3<0) b3+=n2; + longlong e0=(b3*a2) % n2; + for (longlong k=0;k b2*e=a2+k*n2 + gen b2=b1/g,a2=a1/g,n2=n/g; + gen b3=invmod(b2,n2); // e=b3*a2 mod n2 + if (is_positive(-b3,context0)) + b3 += n2; + gen e0=(b3*a2) % n2; + for (gen k=0;is_greater(g,k,context0);k+=1){ + gen e=e0+k*n2; + gen chk=powmod(alpha,e,N); + if ((chk-beta)%N==0) + return e; + if ((chk+beta)%N==0) + return e+n/2; // works only if alpha^(n/2)=-1 + } + } + } + return -1; // means not found + } + + // solve g^x=h mod N, where g^(p^e)=1 mod N and g^(p^(e-1))!=1 mod N + // start from the fact that h^-1*g^0 is of order p^(e) mod N, x0=0 + // then for k>=0 find dk such that + // h^-1*g^(xk+dk*p^(k)) is of order p^(e-(k+1)) mod N + // where h^-1*g^xk of order p^(e-k) mod N + // (g^(-xk)*h)^-1*g^(dk*p^(k)) must be of order p^(e-(k+1)) mod N + // let hk:=(g^(-xk)*h)^(p^(e-1-k)) and gamma=g^(p^(e-1) + // Take power p^(e-1-k) -> hk^-1*gamma^dk of order 1 mod N + // gamma^dk=hk mod N + gen padic_logb(const gen & g,const gen & h,const gen & p,int e,const gen & N){ + if (h==1) return 0; + if (h==g) return 1; + gen xk=0; + gen pe1=pow(p,e-1),pe=pe1*p,invg=invmod(g,N); + if (is_positive(-invg,context0)) + invg+=N; + gen gamma=powmod(g,pe1,N); + gen pk=1; + for (int k=0;k factor or -1/0 + for (;;){ + if (is_greater(gstop,g,contextptr)) + return res; + if (is_probab_prime_p(g)){ + // leave the user compute a certificate for this prime factor... + res.push_back(g); + return res; + } + gen b=pollard(g,1,contextptr); + if (!is_greater(b,2,contextptr)){ + // _ecm_factor(n,contextptr) -> factor or undef + b=_ecm_factor(g,contextptr); + if (is_undef(b)) + return undef; // could not partial factor + } + gen c=_ifactors(b,contextptr); + if (c.type!=_VECT) + return undef; + vecteur & v=*c._VECTptr; + for (int i=0;i. + */ + +using namespace std; +#include "index.h" +#include +#include +#include +#ifdef DEBUG_SUPPORT +#include "giacintl.h" +#endif + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + +#ifdef NO_STDEXCEPT +#undef DEBUG_SUPPORT +#endif + +#ifdef DEBUG_SUPPORT + void setsizeerr(const std::string & s); +#endif + + int mygcd(int a,int b){ + if (b) + return mygcd(b,a%b); + else + return a<0?-a:a; + } + + void swapint(int & a,int & b){ + int tmp=a; + a=b; + b=tmp; + } + + void swapdouble(double & a,double & b){ + double tmp=a; + a=b; + b=tmp; + } + + void index_gcd(const index_t & a,const index_t & b,index_t & res){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + unsigned s=unsigned(itaend-ita); + res.resize(s); + index_t::iterator itres=res.begin(); +#ifdef DEBUG_SUPPORT + if (s!=b.size()) + setsizeerr(gettext("Error index.cc index_gcd")); +#endif // DEBUG_SUPPORT + for (;ita!=itaend;++itb,++itres,++ita) + *itres=giacmin(*ita,*itb); + } + + index_t index_gcd(const index_t & a,const index_t & b){ + index_t res; + index_gcd(a,b,res); + return res; + } + + index_t index_lcm(const index_t & a,const index_t & b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + unsigned s=unsigned(itaend-ita); + index_t res(s); + index_t::iterator itres=res.begin(); +#ifdef DEBUG_SUPPORT + if (s!=b.size()) + setsizeerr(gettext("index.cc index_lcm")); +#endif // DEBUG_SUPPORT + for (;ita!=itaend;++itb,++itres,++ita) + *itres=giacmax(*ita,*itb); + return res; + } + + void index_lcm(const index_m & a,const index_m & b,index_t & res){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + unsigned s=unsigned(itaend-ita); + res.resize(s); + index_t::iterator itres=res.begin(); + for (;ita!=itaend;++itb,++itres,++ita) + *itres=giacmax(*ita,*itb); + } + + // index and monomial ordering/operations implementation + void add(const index_t & a, const index_t & b,index_t & res){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + index_t::iterator itres=res.begin(); + for (;ita!=itaend;++itb,++itres,++ita) + *itres=(*ita)+(*itb); + } + + void add(const index_m & a, const index_m & b,index_t & res){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + index_t::iterator itres=res.begin(); + for (;ita!=itaend;++itb,++itres,++ita) + *itres=(*ita)+(*itb); + } + + bool equal(const index_t & a,const index_t &b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(); + index_t::const_iterator itb=b.begin(); + for (;ita!=itaend;++itb,++ita){ + if (*ita!=*itb) + return false; + } + return true; + } + + index_t operator + (const index_t & a, const index_t & b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + unsigned s=unsigned(itaend-ita); + index_t res(s); + index_t::iterator itres=res.begin(); +#ifdef DEBUG_SUPPORT + if (s!=b.size()) + setsizeerr(gettext("index.cc operator +")); +#endif // DEBUG_SUPPORT + for (;ita!=itaend;++itb,++itres,++ita) + *itres=(*ita)+(*itb); + return res; + } + + index_t operator - (const index_t & a, const index_t & b){ + index_t res; + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + unsigned s=unsigned(itaend-ita); +#ifdef DEBUG_SUPPORT + if (s!=b.size()) + setsizeerr(gettext("index.cc operator -")); +#endif // DEBUG_SUPPORT + res.reserve(s); + for (;ita!=itaend;++ita,++itb) + res.push_back((*ita)-(*itb)); + return res; + } + + index_t operator | (const index_t & a, const index_t & b){ + index_t res; + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); + unsigned s=unsigned(itaend-ita); +#ifdef DEBUG_SUPPORT + if (s!=b.size()) + setsizeerr(gettext("index.cc operator |")); +#endif // DEBUG_SUPPORT + res.reserve(s); + for (;ita!=itaend;++ita,++itb) + res.push_back((*ita) | (*itb)); + return res; + } + + index_t operator - (const index_t & a){ + index_t res; + index_t::const_iterator ita=a.begin(),itaend=a.end(); + int s=int(itaend-ita); + res.reserve(s); + for (;ita!=itaend;++ita) + res.push_back(-(*ita)); + return res; + } + + index_t operator * (const index_t & a, int fois){ + index_t res; + index_t::const_iterator ita=a.begin(),itaend=a.end(); + res.reserve(itaend-ita); + for (;ita!=itaend;++ita) + res.push_back((*ita)*fois); + return res; + } + + index_t operator / (const index_t & a, int divisepar){ + index_t res; + index_t::const_iterator ita=a.begin(),itaend=a.end(); + res.reserve(itaend-ita); + for (;ita!=itaend;++ita) + res.push_back((*ita)/divisepar); + return res; + } + + int operator / (const index_t & a, const index_t & b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(),itbend=b.end(); +#ifdef DEBUG_SUPPORT + if (itaend-ita!=signed(b.size())) + setsizeerr(gettext("index.cc operator /")); +#endif // DEBUG_SUPPORT + for (;ita!=itaend;++ita,++itb){ + if (*itb) + return *ita / *itb; + } + return 0; + } + + bool all_sup_equal (const index_t & a, const index_t & b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); +#ifdef DEBUG_SUPPORT + if (itaend-ita!=signed(b.size())) + setsizeerr(gettext("index.cc operator >=")); +#endif // DEBUG_SUPPORT + for (;ita!=itaend;++ita,++itb){ + if ((*ita)<(*itb)) + return false; + } + return true; + } + + bool all_inf_equal (const index_t & a, const index_t & b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(),itb=b.begin(); +#ifdef DEBUG_SUPPORT + if (itaend-ita!=signed(b.size())) + setsizeerr(gettext("index.cc operator <=")); +#endif // DEBUG_SUPPORT + for (;ita!=itaend;++ita,++itb){ + if ((*ita)>(*itb)) + return false; + } + return true; + } + +#ifdef TICE + void add_print_INT_(string & s,int i){ + char c[sizeof("-8388608")]; + boot_sprintf(c,"%d",i); + s += c; + } + + string print_INT_(int i){ + char c[sizeof("-8388608")]; + boot_sprintf(c, "%d", i); + return c; + } + + string hexa_print_INT_(int i){ + char c[sizeof("0xffffff")]; + boot_sprintf(c, "0x%x", i); + return c; + } + + string octal_print_INT_(int i){ + char c[sizeof("0o77777777")]; + boot_sprintf(c, "0o%o", i); + return c; + } + + string binary_print_INT_(int i){ + char c[sizeof("0b100010001000100010001000")]; + c[0] = '0'; + c[1] = 'b'; + mpz_t tmp; + mpz_init_set_ui(tmp, i); + mpz_get_str(&c[2], 2, tmp); + mpz_clear(tmp); + return c; + } + + string print_INT_(const vector & m) { + vector::const_iterator it=m.begin(),itend=m.end(); + if (it==itend) { + return ""; + } + string s("["); + char buf[sizeof("-8388608,")]; + for (;;) { + boot_sprintf(buf, "%d,", *it); + s += buf; + ++it; + if (it==itend){ + s.back() = ']'; + return s; + } + } + } + + string print_INT_(const vector & m){ + vector::const_iterator it=m.begin(),itend=m.end(); + if (it==itend) { + return ""; + } + string s("["); + char buf[sizeof("-8388608,")]; + for (;;) { + boot_sprintf(buf, "%d,", *it); + s += buf; + ++it; + if (it==itend){ + s.back() = ']'; + return s; + } + } + } + +#else // TICE + + void add_print_INT_(string & s,int i){ + char c[256]; + sprint_int(c,i);//my_sprintf(c,"%d",i); + s += c; + } + + string print_INT_(int i){ + char c[256]; + sprint_int(c,i);//my_sprintf(c,"%d",i); + return c; + } + + string hexa_print_INT_(int i){ + char c[256]; + my_sprintf(c,"%X",i); + return string("0x")+c; + } + + string octal_print_INT_(int i){ + char c[256]; + my_sprintf(c,"%o",i); + return string("0o")+c; + } + + string binary_print_INT_(int i){ + if (i==0) + return "0b0"; + char c[256]; +#if 1 + unsigned ii=i; + int j=sizeinbase2(ii); + c[j]=0; + for (--j;ii;--j,ii/=2){ + c[j]='0'+(ii%2); + } +#else + mpz_t tmp; + mpz_init_set_ui(tmp, i); + mpz_get_str(c, 2, tmp); + mpz_clear(tmp); +#endif + return string("0b")+c; + } + + /* + string print_INT_(int i){ + if (!i) + return string("0"); + if (i<0) + return string("-")+print_INT_(-i); + int length = (int) std::floor(std::log10((double) i)); + char s[length+2]; + s[length+1]=0; + for (;length>-1;--length,i/=10) + s[length]=i%10+'0'; + return s; + } + */ + + string print_INT_(const vector & m){ + vector::const_iterator it=m.begin(),itend=m.end(); + if (it==itend) + return ""; + string s("["); + for (;;){ + s += print_INT_(*it); + ++it; + if (it==itend){ + s +=']'; + return s; + } + else + s += ','; + } + } + + string print_INT_(const vector & m){ + vector::const_iterator it=m.begin(),itend=m.end(); + if (it==itend) + return ""; + string s("["); + for (;;){ + s += print_INT_(*it); + ++it; + if (it==itend) + return s+']'; + else + s += ','; + } + } +#endif // TICE + +#ifdef NSPIRE + template nio::ios_base & operator << (nio::ios_base & os, const index_t & m ){ + return os << ":index_t: " << print_INT_(m) << " " ; + } +#else + ostream & operator << (ostream & os, const index_t & m ){ + return os << ":index_t: " << print_INT_(m) << " " ; + } +#endif + + void dbgprint(const index_t & i){ + COUT << i << endl; + } + + index_t mergeindex(const index_t & i,const index_t & j){ + index_t res(i); + index_t::const_iterator it=j.begin(),itend=j.end(); + res.reserve(i.size()+(itend-it)); + for (;it!=itend;++it) + res.push_back(*it); + return res; + } + + // by convention 0 -> 0 for permutations beginning at index 1 + vector inverse(const vector & p){ + vector inv(p); + int n=int(p.size()); + for (int i=0;i transposition(int i,int j,int size){ + if (i>j) + return transposition(j,i,size); + vector t; + for (int k=0;ki,i2.riptr->i); + } + + int sum_degree_from(const index_m & v1,int start){ + index_t & i1=v1.riptr->i; + index_t::const_iterator it = i1.begin()+start,itend = i1.end(); + int i=0; + for (;it!=itend;++it) + i += *it; + return i; + } + +#else + index_t index_m::iref() const { + if ( (taille % 2)==0) + return riptr->i; + return index_t(direct,direct+taille/2); + } + + index_t::iterator index_m::begin() { + if ( (taille % 2)==0) + return riptr->i.begin(); + return index_t::iterator((giac::deg_t *) direct); + } + + index_t::iterator index_m::end() { + if ( (taille % 2)==0) + return riptr->i.end(); + return index_t::iterator((giac::deg_t *) direct + taille/2) ; + } + + index_t::const_iterator index_m::begin() const { + if ( (taille % 2)==0) + return riptr->i.begin(); + return index_t::const_iterator((giac::deg_t *) direct); + } + + index_t::const_iterator index_m::end() const { + if ( (taille % 2)==0) + return riptr->i.end(); + return index_t::const_iterator((giac::deg_t *) direct + taille/2 ); + } + + void index_m::clear() { + if ( (taille % 2)==0) + riptr->i.clear(); + else + taille=1; + } + + void index_m::reserve(size_t n) { + if (int(n)>POLY_VARS){ + if ( taille % 2) + // alloc a true vector with correct size, copy into + riptr = new ref_index_t(begin(),end()); + // taille=0; + riptr->i.reserve(n); + } + } + + void index_m::push_back(deg_t x){ + if ( taille % 2){ + int pos = taille /2 ; + taille += 2; + if (posi.push_back(x); + } + + size_t index_m::size() const { + if (taille % 2) + return taille/2; + else + return riptr->i.size(); + } + + index_m index_m::set_first_zero() const { + if ( (taille % 2) == 0){ + index_t i(riptr->i); + assert(i.size()); + i[0]=0; + return index_m(i); + } + index_m copie(*this); + copie.direct[0]=0; + return copie; + } + + bool operator == (const index_m & i1, const index_m & i2){ + if (((i1.taille % 2))==0){ + if (i1.riptr==i2.riptr) + return true; +#if 0 // def x86_64 + const index_t & i1t=i1.riptr->i; + const index_t & i2t=i2.riptr->i; + int n=i1t.size(); + if (n!=i2.size()) return false; + const ulonglong * ptr1=(const ulonglong *)&i1t.front(),* ptr1end=ptr1+n/4,*ptr2=(const ulonglong *)&i2t.front(); + for (;ptr1!=ptr1end;++ptr2,++ptr1){ + if (*ptr1!=*ptr2) + return false; + } + const deg_t * i1ptr=(const deg_t *) ptr1,*i1end=i1ptr+n%4,* i2ptr= (const deg_t *) ptr2; + for (;i1ptr!=i1end;++i2ptr,++i1ptr){ + if (*i1ptr!=*i2ptr) + return false; + } + return true; +#else + return equal(i1.riptr->i,i2.riptr->i); +#endif + } + if (i1.taille!=i2.taille) + return false; + const deg_t * i1ptr=i1.direct, *i1end=i1ptr+i1.taille/2,* i2ptr=i2.direct; + for (;i1ptr!=i1end;++i2ptr,++i1ptr){ + if (*i1ptr!=*i2ptr) + return false; + } + return true; + } + + int sum_degree_from(const index_m & v1,int start){ + index_t::const_iterator it,itend; + if ( (v1.taille % 2)==0){ + index_t & i=v1.riptr->i; + it = i.begin()+start; + itend = i.end(); + } + else { + it = index_t::const_iterator((giac::deg_t *) v1.direct); + itend = it + v1.taille/2; + it += start; + } + int i=0; + for (;it!=itend;++it) + i += *it; + return i; + } + +#endif // VISUALC + + bool index_m::is_zero() const { + index_t::const_iterator it=begin(),itend=end(); + for (;it!=itend;++it){ + if (*it) + return false; + } + return true; + } + + size_t index_m::total_degree() const { + size_t i=0; + for (index_t::const_iterator it=begin();it!=end();++it) + i=i+(*it); + return i; + } + + + index_m operator + (const index_m & a, const index_m & b){ + const deg_t * ita=&*a.begin(), * itb=&*b.begin(); + int s=int(a.size()); + const deg_t * itaend=ita+s; +#ifdef DEBUG_SUPPORT + if (s!=signed(b.size())) + setsizeerr(gettext("index.cc index_m operator +")); +#endif // DEBUG_SUPPORT + index_m res(s); + deg_t * it=(deg_t*)&*res.begin(); +#if 0 // def x86_64 + ulonglong * target=(ulonglong *) &*it; + const ulonglong * ptr1=(const ulonglong *) &*ita,* ptr1end=ptr1+s/(sizeof(ulonglong)/sizeof(deg_t)); + const ulonglong * ptr2=(const ulonglong *) &*itb; + for (;ptr1!=ptr1end;++target,++ptr2,++ptr1){ + *target=*ptr1+*ptr2; + } + ita=(const deg_t*)&*ptr1; + itb=(const deg_t*)&*ptr2; + it=(deg_t*)&*target; +#endif + for (;ita!=itaend;++it,++itb,++ita) + *it = (*ita)+(*itb); + return res; + } + + index_m operator - (const index_m & a, const index_m & b){ + index_t::const_iterator ita=a.begin(); + index_t::const_iterator itaend=a.end(); + index_t::const_iterator itb=b.begin(); + int s=int(itaend-ita); +#ifdef DEBUG_SUPPORT + if (s!=signed(b.size())) + setsizeerr(gettext("index.cc index_m operator -")); +#endif // DEBUG_SUPPORT + index_m res(s); + index_t::iterator it=res.begin(); + for (;ita!=itaend;++it,++itb,++ita) + *it = (*ita)-(*itb); + return res; + } + + index_m operator * (const index_m & a, int fois){ + index_t::const_iterator ita=a.begin(),itaend=a.end(); + index_m res(itaend-ita); + index_t::iterator it=res.begin(); + for (;ita!=itaend;++it,++ita) + *it = (*ita)*fois; + return res; + } + + index_m operator / (const index_m & a, int divisepar){ + index_t::const_iterator ita=a.begin(),itaend=a.end(); + index_m res(itaend-ita); + index_t::iterator it=res.begin(); + for (;ita!=itaend;++it,++ita) + *it = (*ita)/divisepar; + return res; + } + + bool operator != (const index_m & i1, const index_m & i2){ + return !(i1==i2); + } + + // >= and <= are *partial* ordering on index_t + // they return TRUE if and only if >= or <= is true for *all* coordinates + bool operator >= (const index_m & a, const index_m & b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(); + index_t::const_iterator itb=b.begin(); +#ifdef DEBUG_SUPPORT + if (itaend-ita!=signed(b.size())) + setsizeerr(gettext("index.cc index_m operator >=")); +#endif + for (;ita!=itaend;++ita,++itb){ + if ((*ita)<(*itb)) + return false; + } + return true; + } + + bool operator <= (const index_m & a, const index_m & b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(); + index_t::const_iterator itb=b.begin(); +#ifdef DEBUG_SUPPORT + if (itaend-ita!=signed(b.size())) + setsizeerr(gettext("index.cc index_m operator >=")); +#endif + for (;ita!=itaend;++ita,++itb){ + if ((*ita)>(*itb)) + return false; + } + return true; + } + + bool equal(const index_m & a,const index_t &b){ + index_t::const_iterator ita=a.begin(),itaend=a.end(); + index_t::const_iterator itb=b.begin(); + for (;ita!=itaend;++itb,++ita){ + if (*ita!=*itb) + return false; + } + return true; + } + + int sum_degree(const index_m & v1){ + int i=0; + index_t::const_iterator it=v1.begin(),itend=v1.end(); + for (;it!=itend;++it) + i += *it; + return i; + } + + bool i_lex_is_greater(const index_m & v1, const index_m & v2){ + index_t::const_iterator it1=v1.begin(); + index_t::const_iterator it2=v2.begin(); + index_t::const_iterator it1end=v1.end(); +#ifdef DEBUG_SUPPORT + if (it1end-it1!=signed(v2.size())) + setsizeerr(gettext("index.cc index_m i_lex_is_greater")); +#endif + for (;it1!=it1end;++it1){ + if ( (*it1)!=(*it2) ){ + if ( (*it1)>(*it2)) + return(true); + else + return(false); + } + ++it2; + } + return(true); + } + + bool lex_is_strictly_greater_deg_t(const std::vector & v1, const std::vector & v2){ + assert(v1.size()==v2.size()); + std::vector::const_iterator it1=v1.begin(),it1end=v1.end(); + std::vector::const_iterator it2=v2.begin(); + for (;it1!=it1end;++it2,++it1){ + if ( (*it1)!=(*it2) ){ + if ( (*it1)>(*it2)) + return true; + else + return false; + } + } + return false; + } + + bool i_lex_is_strictly_greater(const index_m & v1, const index_m & v2){ + index_t::const_iterator it1=v1.begin(); + index_t::const_iterator it2=v2.begin(); + index_t::const_iterator it1end=v1.end(); +#ifdef DEBUG_SUPPORT + if (it1end-it1!=signed(v2.size())) + setsizeerr(gettext("index.cc index_m i_lex_is_greater")); +#endif + for (;it1!=it1end;++it1){ + if ( (*it1)!=(*it2) ){ + if ( (*it1)>(*it2)) + return(true); + else + return(false); + } + ++it2; + } + return(false); + } + + /* + bool i_revlex_is_greater(const index_m & v1, const index_m & v2){ + return revlex_is_greater(*v1.iptr,*v2.iptr); + } + */ + + bool i_total_lex_is_greater(const index_m & v1, const index_m & v2){ + int d1=sum_degree(v1); + int d2=sum_degree(v2); + if (d1!=d2){ + if (d1>d2) + return(true); + else + return(false); + } + return(i_lex_is_greater(v1,v2)); + } + + bool i_total_lex_is_strictly_greater(const index_m & v1, const index_m & v2){ + return !i_total_lex_is_greater(v2,v1); + } + + bool i_total_revlex_is_greater(const index_m & v1, const index_m & v2){ + int d1=sum_degree(v1); + int d2=sum_degree(v2); + if (d1!=d2){ + if (d1>d2) + return(true); + else + return(false); + } + // find order with variables reversed then reverse order + // return !i_lex_is_strictly_greater(v1,v2); + index_t::const_iterator it1=v1.end()-1; + index_t::const_iterator it2=v2.end()-1; + index_t::const_iterator it1end=v1.begin()-1; +#ifdef DEBUG_SUPPORT + if (it1-it1end!=signed(v2.size())) + setsizeerr(gettext("index.cc index_m i_total_revlex_is_greater")); +#endif + for (;it1!=it1end;--it1){ + if ( *it1 != *it2 ) + return *it1<*it2; + --it2; + } + return true; + } + + // revlex on 1st 3 vars, then revlex on remaining vars + bool i_3var_is_greater(const index_m & v1, const index_m & v2){ + index_t::const_iterator it1=v1.begin(); + index_t::const_iterator it2=v2.begin(); + int d1=*it1+*(it1+1)+*(it1+2); + int d2=*it2+*(it2+1)+*(it2+2); + if (d1!=d2) + return d1>=d2; + if (*(it1+2)!=*(it2+2)) + return *(it1+2)<=*(it2+2); + if (*(it1+1)!=*(it2+1)) + return *(it1+1)<=*(it2+1); + if (*it1!=*it2) v1.dbgprint(); // instantiate + d1=sum_degree_from(v1,3); + d2=sum_degree_from(v2,3); + if (d1!=d2) + return d1>=d2; + index_t::const_iterator it1end=it1+2; + it1 = v1.end()-1; + it2 = v2.end()-1; + for (;it1!=it1end;--it1,--it2){ + if (*it1!=*it2) + return *it1<=*it2; + } + return true; + } + + // revlex on 1st 7 vars, then revlex on remaining vars + bool i_7var_is_greater(const index_m & v1, const index_m & v2){ + index_t::const_iterator it1=v1.begin(); + index_t::const_iterator it2=v2.begin(); + int d1=*it1+*(it1+1)+*(it1+2)+*(it1+3)+*(it1+4)+*(it1+5)+*(it1+6); + int d2=*it2+*(it2+1)+*(it2+2)+*(it2+3)+*(it2+4)+*(it2+5)+*(it2+6); + if (d1!=d2) + return d1>=d2; + if (*(it1+6)!=*(it2+6)) + return *(it1+6)<=*(it2+6); + if (*(it1+5)!=*(it2+5)) + return *(it1+5)<=*(it2+5); + if (*(it1+4)!=*(it2+4)) + return *(it1+4)<=*(it2+4); + if (*(it1+3)!=*(it2+3)) + return *(it1+3)<=*(it2+3); + if (*(it1+2)!=*(it2+2)) + return *(it1+2)<=*(it2+2); + if (*(it1+1)!=*(it2+1)) + return *(it1+1)<=*(it2+1); + d1=sum_degree_from(v1,7); + d2=sum_degree_from(v2,7); + if (d1!=d2) + return d1>=d2; + index_t::const_iterator it1end=it1+6; + it1 = v1.end()-1; + it2 = v2.end()-1; + for (;it1!=it1end;--it1,--it2){ + if (*it1!=*it2) + return *it1<=*it2; + } + return true; + } + + // revlex on 1st 11 vars, then revlex on remaining vars + bool i_11var_is_greater(const index_m & v1, const index_m & v2){ + index_t::const_iterator it1=v1.begin(); + index_t::const_iterator it2=v2.begin(); + int d1=*it1+*(it1+1)+*(it1+2)+ + *(it1+3)+*(it1+4)+*(it1+5)+*(it1+6)+ + *(it1+7)+*(it1+8)+*(it1+9)+*(it1+10); + int d2=*it2+*(it2+1)+*(it2+2)+ + *(it2+3)+*(it2+4)+*(it2+5)+*(it2+6)+ + *(it2+7)+*(it2+8)+*(it2+9)+*(it2+10); + if (d1!=d2) + return d1>=d2; + if (*(it1+10)!=*(it2+10)) + return *(it1+10)<=*(it2+10); + if (*(it1+9)!=*(it2+9)) + return *(it1+9)<=*(it2+9); + if (*(it1+8)!=*(it2+8)) + return *(it1+8)<=*(it2+8); + if (*(it1+7)!=*(it2+7)) + return *(it1+7)<=*(it2+7); + if (*(it1+6)!=*(it2+6)) + return *(it1+6)<=*(it2+6); + if (*(it1+5)!=*(it2+5)) + return *(it1+5)<=*(it2+5); + if (*(it1+4)!=*(it2+4)) + return *(it1+4)<=*(it2+4); + if (*(it1+3)!=*(it2+3)) + return *(it1+3)<=*(it2+3); + if (*(it1+2)!=*(it2+2)) + return *(it1+2)<=*(it2+2); + if (*(it1+1)!=*(it2+1)) + return *(it1+1)<=*(it2+1); + d1=sum_degree_from(v1,11); + d2=sum_degree_from(v2,11); + if (d1!=d2) + return d1>=d2; + index_t::const_iterator it1end=it1+10; + it1 = v1.end()-1; + it2 = v2.end()-1; + for (;it1!=it1end;--it1,--it2){ + if (*it1!=*it2) + return *it1<=*it2; + } + return true; + } + + int nvar_total_degree(const index_m & v1,int n){ + index_t::const_iterator it1=v1.begin(),it1l=it1+n; + int d1; + for (d1=0;it1=d2; + } + for (--it2,--it1;it1!=it1beg;--it2,--it1){ + if (*it1!=*it2) + return *it1<=*it2; + } + it1end=v1.end(); + for (d1=0,d2=0,it1+=n,it2+=n;it1!=it1end;++it2,++it1){ + d1 += *it1; + d2 += *it2; + } + if (d1!=d2) + return d1>=d2; + it1 = it1end-1; + it2 = v2.end()-1; + it1end=it1beg+n-1; + for (;it1!=it1end;--it2,--it1){ + if (*it1!=*it2) + return *it1<=*it2; + } + return true; + } + + // revlex on 1st 16 vars, then revlex on remaining vars + bool i_16var_is_greater(const index_m & v1, const index_m & v2){ + return i_nvar_is_greater(v1,v2,16,false); + } + + // revlex on 1st 32 vars, then revlex on remaining vars + bool i_32var_is_greater(const index_m & v1, const index_m & v2){ + return i_nvar_is_greater(v1,v2,32,false); + } + + // revlex on 1st 64 vars, then revlex on remaining vars + bool i_64var_is_greater(const index_m & v1, const index_m & v2){ + return i_nvar_is_greater(v1,v2,64,false); + } + + bool i_total_revlex_is_strictly_greater(const index_m & v1, const index_m & v2){ + return !i_total_revlex_is_greater(v2,v1); + } + + bool disjoint(const index_m & a,const index_m & b){ + index_t::const_iterator it=a.begin(),itend=a.end(),jt=b.begin(); + for (;it!=itend;++jt,++it){ + if (*it && *jt) + return false; + } + return true; + } + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/input_lexer.cc b/android/app/src/main/cpp/giac/src/giac/cpp/input_lexer.cc new file mode 100644 index 0000000..a1a558f --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/input_lexer.cc @@ -0,0 +1,6223 @@ +#line 2 "input_lexer.cc" + +#line 4 "input_lexer.cc" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define giac_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer giac_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define giac_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer giac_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define giac_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer giac_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define giac_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string giac_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define giac_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes giac_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define giac_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer giac_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define giac_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer giac_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define giac_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state giac_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define giac_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer giac_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define giac_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state giac_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define giac_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state giac_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define giac_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack giac_yyensure_buffer_stack +#endif + +#ifdef yylex +#define giac_yylex_ALREADY_DEFINED +#else +#define yylex giac_yylex +#endif + +#ifdef yyrestart +#define giac_yyrestart_ALREADY_DEFINED +#else +#define yyrestart giac_yyrestart +#endif + +#ifdef yylex_init +#define giac_yylex_init_ALREADY_DEFINED +#else +#define yylex_init giac_yylex_init +#endif + +#ifdef yylex_init_extra +#define giac_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra giac_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define giac_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy giac_yylex_destroy +#endif + +#ifdef yyget_debug +#define giac_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug giac_yyget_debug +#endif + +#ifdef yyset_debug +#define giac_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug giac_yyset_debug +#endif + +#ifdef yyget_extra +#define giac_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra giac_yyget_extra +#endif + +#ifdef yyset_extra +#define giac_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra giac_yyset_extra +#endif + +#ifdef yyget_in +#define giac_yyget_in_ALREADY_DEFINED +#else +#define yyget_in giac_yyget_in +#endif + +#ifdef yyset_in +#define giac_yyset_in_ALREADY_DEFINED +#else +#define yyset_in giac_yyset_in +#endif + +#ifdef yyget_out +#define giac_yyget_out_ALREADY_DEFINED +#else +#define yyget_out giac_yyget_out +#endif + +#ifdef yyset_out +#define giac_yyset_out_ALREADY_DEFINED +#else +#define yyset_out giac_yyset_out +#endif + +#ifdef yyget_leng +#define giac_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng giac_yyget_leng +#endif + +#ifdef yyget_text +#define giac_yyget_text_ALREADY_DEFINED +#else +#define yyget_text giac_yyget_text +#endif + +#ifdef yyget_lineno +#define giac_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno giac_yyget_lineno +#endif + +#ifdef yyset_lineno +#define giac_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno giac_yyset_lineno +#endif + +#ifdef yyget_column +#define giac_yyget_column_ALREADY_DEFINED +#else +#define yyget_column giac_yyget_column +#endif + +#ifdef yyset_column +#define giac_yyset_column_ALREADY_DEFINED +#else +#define yyset_column giac_yyset_column +#endif + +#ifdef yywrap +#define giac_yywrap_ALREADY_DEFINED +#else +#define yywrap giac_yywrap +#endif + +#ifdef yyget_lval +#define giac_yyget_lval_ALREADY_DEFINED +#else +#define yyget_lval giac_yyget_lval +#endif + +#ifdef yyset_lval +#define giac_yyset_lval_ALREADY_DEFINED +#else +#define yyset_lval giac_yyset_lval +#endif + +#ifdef yyalloc +#define giac_yyalloc_ALREADY_DEFINED +#else +#define yyalloc giac_yyalloc +#endif + +#ifdef yyrealloc +#define giac_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc giac_yyrealloc +#endif + +#ifdef yyfree +#define giac_yyfree_ALREADY_DEFINED +#else +#define yyfree giac_yyfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define giac_yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 453 +#define YY_END_OF_BUFFER 454 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[1428] = + { 0, + 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, + 454, 452, 1, 2, 208, 3, 450, 153, 266, 220, + 31, 99, 100, 241, 210, 97, 236, 245, 251, 423, + 423, 34, 32, 91, 150, 92, 29, 168, 448, 448, + 448, 317, 448, 448, 448, 448, 44, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 101, + 102, 274, 30, 16, 448, 448, 448, 448, 318, 448, + 448, 448, 38, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 120, 181, 121, 221, + 42, 448, 448, 448, 448, 448, 452, 448, 448, 23, + + 25, 24, 453, 451, 453, 15, 6, 5, 453, 18, + 17, 19, 1, 0, 0, 137, 0, 0, 0, 0, + 0, 0, 0, 0, 154, 267, 253, 151, 449, 104, + 105, 0, 46, 45, 449, 122, 123, 174, 246, 256, + 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 277, + 243, 211, 212, 98, 103, 216, 0, 131, 217, 130, + 248, 219, 238, 198, 263, 444, 278, 252, 22, 0, + 261, 119, 442, 423, 424, 0, 0, 0, 0, 0, + + 0, 36, 35, 157, 0, 0, 0, 128, 144, 139, + 164, 0, 165, 132, 163, 148, 129, 167, 169, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 389, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 335, 399, 448, 448, 448, 448, 186, 51, + 448, 448, 50, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 275, 258, 188, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 448, 448, 448, 448, 448, 307, 448, 448, + 448, 448, 448, 448, 448, 390, 448, 448, 448, 448, + + 448, 448, 448, 448, 448, 448, 448, 448, 448, 67, + 334, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 57, 359, 448, 48, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 118, 257, 182, 33, 448, 224, 225, 448, + 62, 196, 39, 37, 49, 448, 448, 448, 448, 448, + 448, 448, 0, 448, 448, 23, 24, 24, 26, 0, + 451, 15, 4, 14, 7, 8, 12, 13, 9, 11, + 10, 18, 199, 201, 0, 0, 434, 435, 433, 437, + + 436, 438, 268, 112, 113, 106, 107, 124, 125, 255, + 449, 110, 111, 47, 0, 0, 0, 0, 155, 269, + 0, 0, 249, 234, 239, 0, 264, 0, 145, 0, + 0, 152, 0, 147, 0, 172, 0, 279, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 214, 134, 200, 205, 445, 0, 254, 0, + 21, 442, 443, 0, 0, 0, 446, 0, 440, 439, + 441, 425, 0, 0, 0, 0, 260, 0, 133, 259, + 176, 209, 448, 448, 448, 412, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 329, 403, 448, 448, + + 448, 448, 448, 448, 448, 448, 448, 408, 448, 352, + 448, 448, 448, 448, 448, 448, 448, 448, 411, 448, + 378, 448, 448, 448, 448, 448, 193, 0, 0, 0, + 0, 0, 0, 340, 0, 0, 0, 0, 0, 0, + 185, 0, 0, 0, 0, 0, 0, 0, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 328, 448, 448, 448, 448, 448, 448, 56, + 448, 448, 203, 448, 448, 345, 448, 448, 271, 354, + 448, 351, 448, 448, 448, 448, 448, 448, 448, 448, + + 448, 276, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 189, 0, 448, 43, 233, 226, 227, 228, 229, 230, + 231, 319, 162, 197, 417, 422, 237, 222, 54, 223, + 177, 187, 195, 194, 418, 420, 419, 421, 242, 190, + 161, 160, 232, 41, 320, 448, 7, 8, 0, 0, + 0, 0, 0, 114, 115, 108, 109, 126, 127, 0, + 95, 93, 138, 270, 178, 206, 158, 142, 140, 135, + 149, 170, 0, 0, 339, 0, 0, 0, 0, 0, + + 358, 184, 0, 0, 0, 0, 183, 0, 0, 444, + 0, 443, 0, 0, 0, 442, 0, 0, 447, 0, + 426, 0, 20, 0, 0, 0, 0, 448, 313, 314, + 448, 448, 448, 448, 448, 448, 406, 448, 448, 401, + 409, 330, 448, 448, 448, 448, 448, 337, 344, 402, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 391, 448, 386, 448, 448, 180, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 273, 0, 356, 0, 0, + 0, 0, 0, 0, 0, 191, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 311, 448, 448, 448, 448, + + 448, 0, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 336, 448, + 448, 448, 448, 448, 64, 448, 448, 448, 448, 0, + 448, 448, 448, 448, 448, 448, 74, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 376, 448, 377, + 448, 65, 66, 448, 448, 448, 380, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 0, 448, + 40, 7, 0, 0, 116, 117, 0, 96, 94, 179, + 0, 0, 0, 0, 272, 355, 0, 0, 0, 192, + 0, 445, 0, 0, 0, 442, 0, 0, 443, 0, + + 0, 397, 396, 398, 166, 312, 405, 315, 448, 448, + 448, 448, 448, 324, 448, 448, 448, 448, 448, 448, + 367, 407, 393, 448, 448, 448, 448, 415, 448, 395, + 388, 404, 0, 0, 0, 0, 0, 0, 0, 146, + 0, 250, 235, 0, 0, 0, 0, 0, 0, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 0, 0, 0, 448, 321, 323, 322, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 448, 71, 68, + 83, 448, 448, 448, 0, 448, 448, 448, 362, 448, + + 448, 448, 448, 448, 448, 365, 448, 448, 448, 448, + 448, 448, 448, 87, 448, 448, 448, 448, 448, 448, + 448, 448, 204, 448, 448, 61, 448, 448, 448, 448, + 387, 0, 448, 27, 28, 0, 304, 338, 0, 0, + 0, 0, 0, 0, 443, 0, 0, 448, 287, 410, + 281, 448, 283, 448, 448, 448, 448, 414, 371, 374, + 448, 400, 448, 379, 0, 0, 136, 0, 171, 0, + 0, 350, 280, 207, 0, 0, 0, 383, 448, 448, + 448, 301, 305, 308, 448, 448, 448, 448, 347, 79, + 316, 448, 332, 331, 0, 448, 448, 448, 448, 448, + + 325, 326, 448, 448, 448, 448, 448, 70, 448, 448, + 448, 448, 448, 448, 448, 448, 448, 353, 294, 448, + 361, 448, 448, 77, 81, 448, 448, 448, 448, 448, + 369, 448, 448, 372, 448, 448, 346, 448, 448, 381, + 348, 448, 78, 448, 448, 448, 448, 448, 55, 89, + 90, 0, 0, 349, 0, 0, 382, 427, 448, 448, + 448, 282, 284, 448, 394, 448, 159, 265, 0, 0, + 0, 156, 0, 0, 448, 448, 448, 303, 306, 309, + 82, 448, 448, 448, 448, 0, 299, 448, 448, 448, + 448, 448, 360, 85, 75, 448, 448, 448, 448, 448, + + 448, 448, 73, 448, 357, 448, 448, 448, 448, 448, + 448, 448, 448, 370, 448, 448, 448, 448, 448, 288, + 448, 448, 448, 72, 385, 0, 0, 375, 0, 428, + 448, 392, 285, 448, 448, 173, 0, 143, 0, 141, + 448, 448, 448, 448, 448, 448, 448, 333, 448, 448, + 448, 448, 327, 76, 448, 341, 448, 53, 202, 448, + 448, 63, 448, 59, 448, 448, 302, 368, 88, 373, + 448, 448, 448, 448, 366, 448, 448, 0, 0, 0, + 0, 0, 413, 286, 416, 0, 240, 448, 448, 448, + 448, 310, 448, 448, 448, 448, 448, 448, 448, 80, + + 448, 448, 60, 448, 86, 448, 69, 448, 448, 448, + 448, 448, 175, 0, 0, 431, 0, 343, 448, 448, + 448, 448, 448, 448, 218, 448, 448, 448, 448, 448, + 448, 363, 448, 448, 448, 448, 448, 448, 342, 0, + 0, 429, 448, 448, 291, 213, 448, 448, 448, 448, + 448, 52, 448, 297, 448, 448, 448, 448, 448, 448, + 0, 0, 430, 448, 290, 295, 448, 448, 448, 448, + 448, 448, 448, 84, 448, 58, 448, 0, 432, 448, + 448, 448, 448, 448, 448, 300, 448, 448, 364, 0, + 448, 448, 262, 448, 448, 448, 448, 296, 0, 448, + + 448, 448, 448, 448, 448, 0, 448, 448, 448, 448, + 293, 448, 0, 448, 298, 448, 244, 289, 0, 292, + 448, 0, 215, 0, 0, 384, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 23, 23, 23, 23, 24, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 41, 48, 49, 50, 51, 52, 53, 54, 41, 41, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + + 65, 66, 67, 68, 69, 41, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 41, 85, 86, 87, 88, 1, 89, 90, 91, + 92, 93, 94, 95, 41, 96, 97, 98, 41, 41, + 41, 41, 99, 100, 41, 101, 41, 102, 41, 103, + 104, 41, 41, 105, 41, 41, 106, 107, 41, 108, + 109, 110, 41, 111, 112, 113, 114, 115, 116, 117, + 118, 41, 41, 41, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 41, 41, 41, + 132, 41, 41, 133, 134, 41, 41, 41, 41, 41, + + 41, 41, 41, 41, 41, 135, 136, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 137, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 138, 139, 140, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 1 + } ; + +static const YY_CHAR yy_meta[141] = + { 0, + 1, 1, 2, 1, 1, 3, 1, 4, 4, 1, + 1, 1, 1, 5, 1, 1, 1, 1, 4, 6, + 6, 6, 6, 6, 1, 1, 1, 4, 1, 6, + 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 4, 3, 4, 1, 7, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 4, 1, 4, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 7, 7 + } ; + +static const flex_int16_t yy_base[1445] = + { 0, + 0, 0, 138, 139, 140, 141, 142, 143, 144, 147, + 2092, 2093, 154, 2093, 146, 2093, 155, 2093, 175, 187, + 258, 2093, 2093, 143, 145, 143, 195, 276, 227, 285, + 331, 292, 2093, 134, 199, 137, 2093, 302, 122, 2043, + 296, 211, 148, 139, 2016, 328, 145, 0, 2049, 106, + 2042, 2039, 305, 304, 153, 168, 2054, 167, 2039, 2093, + 2093, 211, 320, 2093, 331, 181, 169, 196, 339, 308, + 197, 2023, 291, 2018, 112, 210, 355, 207, 362, 363, + 380, 385, 270, 318, 2014, 2007, 2061, 362, 2093, 2093, + 0, 347, 146, 338, 1990, 381, 1989, 1988, 1970, 0, + + 2093, 407, 2072, 2093, 2093, 0, 2093, 2068, 465, 0, + 2093, 2093, 448, 2055, 2067, 2093, 2056, 2053, 485, 534, + 552, 601, 460, 619, 2093, 524, 2041, 2093, 0, 2093, + 2093, 289, 0, 0, 1999, 2093, 2093, 2093, 2093, 2093, + 2093, 1995, 1987, 1986, 2036, 2052, 377, 2052, 2050, 2049, + 2048, 2040, 2046, 2028, 462, 416, 447, 281, 2044, 374, + 390, 398, 1980, 426, 1988, 1968, 1978, 1976, 1963, 2020, + 2093, 2093, 2093, 2093, 2093, 2093, 2030, 2093, 2093, 2093, + 2093, 2093, 2093, 492, 2093, 666, 2093, 2018, 2093, 2042, + 2093, 2093, 671, 688, 458, 478, 355, 540, 693, 1924, + + 2024, 2093, 2093, 2093, 1962, 1964, 1960, 2011, 2093, 2093, + 2093, 1967, 2093, 2009, 2093, 2093, 2008, 570, 2093, 0, + 2000, 1956, 1997, 1983, 1986, 1959, 1966, 380, 1990, 0, + 463, 1953, 1978, 1956, 1976, 1946, 1943, 334, 1947, 1951, + 1945, 1957, 1967, 0, 1973, 1944, 1940, 1963, 0, 1969, + 1963, 1930, 0, 1934, 263, 436, 1926, 1969, 1956, 1922, + 1925, 1955, 1962, 1932, 1952, 2093, 2093, 2093, 438, 1930, + 1922, 462, 466, 1932, 460, 1922, 1918, 506, 1933, 448, + 1920, 1918, 1920, 1923, 1914, 1925, 1909, 0, 1919, 1922, + 1910, 181, 1906, 1905, 1909, 0, 1916, 1901, 1898, 542, + + 1898, 1905, 1900, 1905, 1893, 530, 1910, 1897, 1899, 2093, + 503, 565, 1904, 532, 1901, 1888, 1893, 1901, 1897, 322, + 1892, 0, 547, 1888, 0, 594, 1882, 576, 1886, 1882, + 1885, 571, 1895, 1882, 1882, 1882, 1884, 551, 1879, 1874, + 1885, 1887, 1875, 1870, 1877, 1870, 659, 1879, 1880, 1865, + 1872, 1863, 2093, 2093, 2093, 0, 1935, 0, 0, 1805, + 0, 0, 0, 0, 0, 617, 1818, 1835, 661, 549, + 544, 546, 1842, 433, 1834, 0, 564, 659, 2093, 1930, + 2093, 0, 2093, 2093, 760, 765, 2093, 2093, 2093, 2093, + 2093, 0, 2093, 2093, 1917, 1914, 770, 2093, 2093, 790, + + 677, 839, 760, 2093, 2093, 2093, 2093, 2093, 2093, 2093, + 0, 2093, 2093, 0, 1855, 1903, 1902, 1916, 2093, 2093, + 1915, 1914, 2093, 2093, 2093, 1913, 2093, 1912, 2093, 1911, + 1910, 2093, 1909, 2093, 1908, 2093, 1907, 2093, 1853, 1849, + 668, 1836, 1841, 1849, 1833, 1900, 1899, 1830, 1836, 1838, + 1829, 1894, 2093, 2093, 2093, 2093, 667, 862, 2093, 1901, + 2093, 886, 668, 897, 908, 775, 819, 872, 650, 844, + 932, 914, 1900, 1829, 1834, 1827, 2093, 1820, 2093, 2093, + 0, 0, 1866, 1861, 1846, 0, 1824, 1843, 1843, 1852, + 1820, 1821, 1814, 1813, 1841, 1807, 0, 0, 1811, 1834, + + 1816, 1810, 1814, 1803, 1806, 1842, 1834, 0, 1801, 0, + 1835, 1836, 1795, 1792, 1835, 1819, 1789, 1788, 0, 1823, + 1807, 1786, 1793, 1814, 1819, 1790, 0, 1796, 1781, 1777, + 1777, 1782, 1790, 2093, 1775, 656, 1780, 1788, 1780, 1771, + 2093, 1769, 1766, 1774, 1770, 1783, 696, 1767, 1784, 1771, + 1764, 685, 1760, 1767, 1768, 1774, 1761, 1696, 1753, 1764, + 1763, 1827, 1761, 1768, 1750, 1753, 1767, 1760, 661, 1746, + 1754, 1758, 0, 769, 1741, 1754, 1756, 1753, 1740, 1747, + 1750, 1739, 0, 1748, 1733, 1737, 1733, 1729, 0, 0, + 1736, 1803, 1747, 1728, 1735, 1738, 1723, 1723, 1745, 1726, + + 1714, 0, 1735, 1729, 1731, 1723, 1728, 817, 1731, 1712, + 1731, 1724, 1723, 1732, 1731, 1646, 1719, 1708, 1704, 1642, + 1715, 1714, 1707, 1699, 1711, 1706, 1697, 1694, 1705, 1700, + 0, 1633, 1656, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2093, 0, 0, 1658, 919, 925, 1752, 1751, + 1748, 1747, 737, 2093, 2093, 2093, 2093, 2093, 2093, 1737, + 1734, 1733, 2093, 2093, 2093, 2093, 2093, 2093, 2093, 2093, + 2093, 2093, 1749, 1681, 2093, 1693, 1692, 1676, 1744, 1743, + + 2093, 2093, 1673, 1680, 1677, 1739, 2093, 955, 937, 960, + 984, 735, 994, 1004, 965, 1011, 1021, 1026, 1031, 1041, + 1050, 1746, 2093, 1685, 1675, 1683, 1719, 1702, 0, 0, + 1678, 1704, 1709, 1690, 1665, 1659, 0, 1702, 1688, 0, + 0, 0, 1664, 1659, 1664, 1660, 1664, 0, 0, 0, + 1681, 1693, 1663, 1652, 1694, 1677, 1659, 1646, 1690, 1681, + 0, 1655, 0, 1683, 1653, 2093, 1648, 1647, 1654, 1641, + 1635, 1647, 1635, 1632, 1629, 2093, 1629, 2093, 1629, 1641, + 1638, 1637, 1624, 1626, 1627, 2093, 1621, 1634, 1624, 1623, + 1627, 1634, 1622, 1628, 1616, 0, 1620, 1601, 1624, 1607, + + 1614, 1011, 1615, 1614, 1619, 1606, 744, 1605, 1608, 1603, + 1600, 1607, 1612, 1603, 1610, 1599, 1602, 1593, 0, 1606, + 1597, 1592, 1609, 1612, 1611, 1610, 1595, 1585, 1601, 1592, + 1586, 1598, 1584, 1591, 1590, 1596, 2093, 1575, 753, 1592, + 1587, 1003, 1573, 598, 1570, 1572, 1593, 0, 1581, 0, + 1573, 2093, 2093, 1556, 1583, 1584, 1568, 1552, 1579, 1562, + 1573, 1559, 1570, 1568, 1575, 1559, 1552, 1566, 1534, 1496, + 0, 1067, 813, 812, 2093, 2093, 1618, 2093, 2093, 2093, + 1616, 1615, 1548, 1546, 2093, 2093, 1546, 1557, 1537, 2093, + 1072, 1077, 1087, 1097, 1102, 1107, 1117, 1122, 1127, 1137, + + 1513, 2093, 2093, 2093, 2093, 0, 0, 0, 1539, 1518, + 1499, 1483, 1476, 0, 1480, 1471, 1458, 1475, 1421, 1450, + 0, 0, 0, 1449, 1453, 1419, 1423, 1452, 1449, 0, + 0, 0, 1426, 1428, 1420, 1427, 1410, 1411, 1407, 2093, + 1408, 2093, 2093, 1408, 104, 140, 227, 257, 359, 377, + 437, 443, 467, 533, 556, 584, 632, 639, 675, 673, + 746, 765, 757, 772, 782, 772, 783, 0, 0, 0, + 799, 798, 790, 819, 816, 802, 811, 819, 822, 832, + 850, 860, 855, 852, 889, 894, 890, 913, 2093, 2093, + 2093, 907, 933, 929, 929, 930, 931, 939, 0, 933, + + 953, 968, 974, 973, 980, 0, 983, 995, 1001, 988, + 1003, 1000, 1005, 2093, 999, 1003, 989, 1020, 1016, 1028, + 1011, 1042, 0, 1058, 1046, 0, 1043, 1061, 1059, 1082, + 0, 1048, 1071, 1141, 1148, 1105, 2093, 2093, 1089, 1157, + 1096, 1091, 1160, 1152, 1157, 1168, 1060, 1144, 0, 0, + 0, 1104, 0, 1128, 1116, 1116, 1135, 0, 0, 0, + 1118, 0, 1158, 0, 1126, 1135, 2093, 1140, 2093, 1124, + 1142, 2093, 2093, 2093, 1131, 1144, 1145, 2093, 1138, 1131, + 1150, 1142, 1143, 1144, 1158, 1135, 1141, 1133, 0, 2093, + 0, 1152, 2093, 2093, 1144, 1146, 1139, 1156, 1151, 1156, + + 0, 0, 1155, 1160, 1171, 1172, 1149, 2093, 1156, 1153, + 1153, 1153, 1172, 1163, 1180, 1167, 1171, 2093, 0, 1164, + 0, 1166, 1167, 2093, 2093, 1164, 1177, 1166, 1179, 1166, + 0, 1169, 1174, 0, 1175, 1180, 0, 1172, 1178, 0, + 0, 1174, 2093, 1186, 1189, 1180, 1201, 1192, 2093, 0, + 0, 1186, 1194, 2093, 1249, 1184, 2093, 1242, 1218, 1195, + 1186, 0, 0, 1203, 0, 1222, 2093, 2093, 1193, 1208, + 1203, 2093, 1212, 1205, 1210, 1217, 1207, 0, 0, 0, + 2093, 1215, 1202, 1223, 1224, 1221, 0, 1216, 1205, 1208, + 1227, 1227, 0, 2093, 2093, 1235, 1226, 1214, 1224, 1210, + + 1224, 1229, 2093, 1224, 0, 1221, 1236, 1234, 1236, 1227, + 1231, 1240, 1250, 0, 1241, 1244, 1242, 1241, 1244, 0, + 1238, 1248, 1248, 2093, 0, 1239, 1252, 2093, 1247, 1299, + 1268, 0, 0, 1259, 1275, 2093, 1263, 2093, 1248, 2093, + 1269, 1265, 1256, 1272, 1267, 1261, 1270, 2093, 1257, 1271, + 1268, 1266, 0, 2093, 1284, 0, 1267, 0, 0, 1276, + 1277, 0, 1322, 0, 1290, 1268, 0, 0, 2093, 0, + 1292, 1279, 1284, 1276, 0, 1292, 1275, 1327, 1275, 1292, + 1336, 1272, 0, 0, 0, 1283, 2093, 1285, 1295, 1301, + 1302, 0, 1293, 1307, 1304, 1305, 1312, 1297, 1301, 2093, + + 1307, 1292, 0, 1312, 2093, 1308, 2093, 1315, 1314, 1309, + 1312, 1321, 2093, 1372, 1325, 1365, 1267, 2093, 1317, 1331, + 1328, 1329, 1331, 1319, 0, 1338, 1323, 1328, 1339, 1342, + 1323, 0, 1332, 1345, 1326, 1341, 1334, 1329, 2093, 1345, + 1321, 1391, 1345, 1344, 0, 0, 1353, 1350, 1345, 1341, + 1353, 0, 1348, 0, 1350, 1359, 1371, 1346, 1362, 1355, + 1361, 1308, 1417, 1352, 0, 0, 1372, 1373, 1366, 1377, + 1369, 1371, 1371, 2093, 1381, 0, 1370, 1382, 2093, 1370, + 1388, 1374, 1374, 1394, 1372, 0, 1378, 1385, 0, 1391, + 1389, 1388, 0, 1382, 1386, 1397, 1391, 0, 1399, 1391, + + 1401, 1406, 1407, 1392, 1409, 1394, 1399, 1395, 1401, 1398, + 0, 1397, 1412, 1400, 0, 1416, 0, 0, 1407, 0, + 1416, 1419, 0, 1418, 1473, 2093, 2093, 1502, 1510, 1518, + 1526, 1531, 1533, 1540, 1548, 1556, 1564, 1572, 1580, 1582, + 1589, 1597, 1605, 1613 + } ; + +static const flex_int16_t yy_def[1445] = + { 0, + 1427, 1, 1428, 1428, 1429, 1429, 1430, 1430, 1431, 1431, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1432, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, + 1427, 1427, 1427, 1427, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1427, 1427, 1427, + 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, 1433, 1434, + + 1427, 1435, 1436, 1427, 1427, 1437, 1427, 1427, 1438, 1439, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1440, 1427, + 1427, 1427, 1440, 1440, 1440, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1441, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1427, 1427, 1427, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1427, 1433, 1433, 1434, 1435, 1435, 1427, 1436, + 1427, 1437, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1439, 1427, 1427, 1442, 1443, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1440, 1427, 1427, 1440, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1441, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1444, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1427, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1427, 1433, 1433, 1433, 1427, 1427, 1442, 1442, + 1443, 1443, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1444, 1427, 1427, 1427, 1427, 1427, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + + 1433, 1427, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, + 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1427, 1427, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, + 1433, 1427, 1442, 1443, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1427, 1427, 1427, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1427, + 1427, 1433, 1433, 1433, 1427, 1433, 1433, 1433, 1433, 1433, + + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1427, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1427, 1433, 1442, 1443, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, + 1433, 1433, 1427, 1427, 1427, 1433, 1433, 1433, 1433, 1433, + + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, 1433, + 1433, 1433, 1433, 1427, 1427, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1427, 1433, 1433, 1433, 1433, 1433, 1427, 1433, + 1433, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1433, 1433, 1433, 1433, 1433, 1433, + 1427, 1433, 1433, 1433, 1433, 1427, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1427, 1427, 1433, 1433, 1433, 1433, 1433, + + 1433, 1433, 1427, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1427, 1433, 1427, 1427, 1427, 1427, 1427, + 1433, 1433, 1433, 1433, 1433, 1427, 1427, 1427, 1427, 1427, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, 1433, + 1433, 1433, 1433, 1427, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1427, 1427, + 1427, 1427, 1433, 1433, 1433, 1427, 1427, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, + + 1433, 1433, 1433, 1433, 1427, 1433, 1427, 1433, 1433, 1433, + 1433, 1433, 1427, 1427, 1427, 1427, 1427, 1427, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1427, + 1427, 1427, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1427, 1427, 1427, 1433, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1427, 1433, 1433, 1433, 1427, 1427, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, + 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1427, 1433, + + 1433, 1433, 1433, 1433, 1433, 1427, 1433, 1433, 1433, 1433, + 1433, 1433, 1427, 1433, 1433, 1433, 1433, 1433, 1427, 1433, + 1433, 1427, 1433, 1427, 1427, 1427, 0, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427 + } ; + +static const flex_int16_t yy_nxt[2234] = + { 0, + 12, 13, 14, 13, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 48, 51, 52, 53, 54, 55, 56, + 48, 57, 58, 59, 60, 13, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 48, 80, 81, 82, 83, + 84, 85, 86, 48, 87, 88, 89, 90, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + + 48, 48, 48, 48, 48, 48, 48, 48, 91, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 92, 93, 94, 95, 96, 97, 98, 99, + 101, 101, 104, 104, 107, 107, 111, 108, 108, 111, + 114, 102, 102, 105, 105, 113, 170, 113, 174, 172, + 208, 209, 210, 115, 216, 217, 221, 246, 1074, 117, + 171, 118, 173, 116, 119, 119, 120, 120, 121, 247, + 314, 243, 125, 126, 235, 315, 121, 121, 121, 121, + 121, 121, 258, 127, 222, 233, 138, 109, 109, 175, + + 139, 259, 128, 112, 1075, 263, 112, 211, 212, 113, + 244, 176, 236, 177, 140, 121, 122, 121, 121, 121, + 121, 178, 179, 180, 266, 213, 214, 215, 123, 130, + 234, 131, 260, 132, 264, 188, 261, 124, 267, 133, + 189, 290, 292, 134, 141, 190, 228, 142, 293, 135, + 229, 291, 557, 143, 191, 360, 230, 144, 558, 136, + 294, 137, 145, 307, 295, 146, 147, 148, 268, 296, + 316, 149, 150, 308, 151, 152, 153, 361, 317, 231, + 322, 323, 154, 318, 155, 156, 157, 232, 158, 181, + 182, 436, 183, 184, 185, 186, 186, 186, 186, 186, + + 412, 413, 193, 1076, 194, 194, 194, 194, 194, 515, + 201, 437, 516, 192, 195, 159, 202, 203, 160, 204, + 196, 218, 218, 218, 218, 218, 161, 224, 205, 162, + 163, 164, 219, 187, 165, 166, 1077, 167, 206, 255, + 168, 225, 347, 169, 250, 310, 197, 348, 193, 196, + 194, 194, 194, 194, 194, 251, 311, 207, 198, 238, + 195, 239, 240, 312, 241, 252, 196, 199, 256, 226, + 242, 304, 305, 253, 469, 469, 500, 257, 254, 227, + 269, 306, 349, 270, 271, 272, 350, 420, 273, 354, + 274, 275, 276, 277, 278, 196, 279, 280, 591, 281, + + 592, 283, 282, 284, 421, 285, 501, 286, 287, 288, + 289, 297, 488, 298, 299, 300, 301, 200, 302, 319, + 378, 303, 489, 331, 324, 379, 432, 332, 320, 333, + 325, 1078, 326, 321, 327, 328, 334, 335, 329, 362, + 336, 330, 337, 433, 338, 343, 439, 355, 339, 113, + 440, 113, 344, 1079, 340, 441, 363, 434, 341, 342, + 356, 345, 442, 200, 346, 364, 443, 357, 358, 359, + 366, 444, 429, 367, 435, 368, 369, 370, 371, 401, + 401, 401, 401, 372, 385, 385, 385, 385, 386, 430, + 431, 446, 466, 465, 466, 1080, 455, 467, 467, 467, + + 467, 467, 447, 113, 119, 119, 120, 120, 121, 456, + 528, 517, 545, 468, 518, 529, 121, 121, 121, 121, + 121, 121, 465, 491, 532, 1081, 387, 546, 537, 492, + 388, 534, 403, 538, 533, 404, 405, 389, 535, 539, + 493, 390, 468, 391, 1082, 121, 397, 121, 121, 121, + 121, 664, 398, 120, 120, 120, 120, 121, 399, 470, + 470, 470, 470, 577, 665, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 542, 1427, 406, 543, + 407, 578, 1427, 121, 121, 121, 121, 121, 121, 218, + 218, 218, 218, 218, 121, 121, 121, 121, 121, 121, + + 572, 398, 565, 583, 584, 1083, 573, 399, 408, 585, + 409, 594, 121, 121, 121, 121, 121, 121, 566, 398, + 400, 400, 121, 121, 121, 595, 614, 579, 1084, 615, + 580, 606, 121, 121, 121, 121, 121, 121, 402, 402, + 402, 402, 402, 581, 600, 607, 601, 659, 1085, 608, + 402, 402, 402, 402, 402, 402, 656, 602, 1010, 657, + 658, 121, 121, 121, 121, 121, 121, 597, 398, 469, + 469, 661, 378, 598, 660, 662, 1011, 379, 695, 402, + 402, 402, 402, 402, 402, 186, 186, 186, 186, 186, + 462, 462, 462, 462, 462, 457, 401, 401, 401, 401, + + 463, 458, 708, 714, 1086, 193, 464, 194, 194, 194, + 194, 194, 471, 471, 471, 471, 471, 195, 1087, 624, + 773, 809, 625, 196, 471, 471, 471, 471, 471, 471, + 458, 708, 714, 774, 810, 464, 626, 634, 635, 1088, + 636, 637, 638, 639, 640, 641, 696, 790, 875, 876, + 644, 645, 196, 471, 471, 471, 471, 471, 471, 646, + 784, 647, 791, 792, 785, 648, 1089, 649, 673, 650, + 894, 674, 675, 1003, 651, 652, 653, 654, 655, 667, + 667, 667, 667, 668, 668, 668, 668, 668, 668, 121, + 121, 121, 121, 121, 467, 467, 467, 467, 467, 894, + + 1090, 121, 121, 121, 121, 121, 121, 971, 972, 400, + 400, 121, 121, 121, 676, 973, 677, 1004, 1035, 1034, + 200, 121, 121, 121, 121, 121, 121, 873, 874, 1091, + 121, 121, 121, 121, 121, 121, 1092, 398, 467, 467, + 467, 467, 467, 814, 678, 1093, 679, 1094, 1095, 815, + 121, 121, 121, 121, 121, 121, 1096, 398, 402, 402, + 402, 402, 402, 470, 470, 470, 470, 1097, 1098, 1099, + 402, 402, 402, 402, 402, 402, 709, 1100, 709, 1101, + 1102, 710, 710, 710, 710, 710, 466, 1103, 466, 1104, + 845, 467, 467, 467, 467, 467, 846, 711, 1105, 402, + + 402, 402, 402, 402, 402, 462, 462, 462, 462, 462, + 1106, 715, 1107, 715, 1108, 712, 716, 716, 716, 716, + 716, 713, 718, 1109, 718, 1110, 711, 719, 719, 719, + 719, 719, 717, 721, 721, 721, 721, 721, 872, 872, + 872, 872, 668, 720, 668, 668, 668, 668, 668, 1111, + 713, 471, 471, 471, 471, 471, 710, 710, 710, 710, + 710, 717, 1112, 471, 471, 471, 471, 471, 471, 891, + 1113, 891, 720, 1114, 892, 892, 892, 892, 892, 710, + 710, 710, 710, 710, 716, 716, 716, 716, 716, 1115, + 893, 1116, 471, 471, 471, 471, 471, 471, 709, 1117, + + 709, 1118, 1119, 710, 710, 710, 710, 710, 895, 1120, + 895, 1121, 1122, 896, 896, 896, 896, 896, 898, 893, + 898, 1123, 1124, 899, 899, 899, 899, 899, 1125, 897, + 716, 716, 716, 716, 716, 715, 1126, 715, 1127, 900, + 716, 716, 716, 716, 716, 719, 719, 719, 719, 719, + 719, 719, 719, 719, 719, 718, 1128, 718, 897, 1129, + 719, 719, 719, 719, 719, 1130, 1131, 1132, 900, 721, + 721, 721, 721, 721, 964, 1007, 1133, 1134, 1135, 965, + 1008, 1136, 1137, 1138, 1139, 966, 668, 668, 668, 668, + 668, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 891, 1140, 891, 1141, 1142, 892, 892, 892, 892, + 892, 1044, 1143, 1044, 1144, 1145, 1045, 1045, 1045, 1045, + 1045, 896, 896, 896, 896, 896, 896, 896, 896, 896, + 896, 895, 1046, 895, 1146, 1147, 896, 896, 896, 896, + 896, 899, 899, 899, 899, 899, 899, 899, 899, 899, + 899, 898, 1148, 898, 1149, 670, 899, 899, 899, 899, + 899, 1046, 1150, 1151, 672, 1152, 1153, 1154, 1155, 1156, + 1157, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, + 1045, 1158, 1044, 1159, 1044, 1160, 901, 1045, 1045, 1045, + 1045, 1045, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, + + 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, + 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, + 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, + 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, + 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, + 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, + 1229, 1230, 1230, 1230, 1230, 1230, 1231, 1232, 1233, 1234, + 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, + 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, + 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, + + 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, + 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1283, 1230, 1230, + 1230, 1230, 1230, 1284, 1285, 1286, 1287, 1288, 1289, 1290, + 1291, 1292, 1293, 1295, 1296, 1297, 1298, 1299, 1300, 1301, + 1302, 1294, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, + 1311, 1312, 1313, 1314, 1315, 1316, 1316, 1316, 1316, 1316, + 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, + 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, + 1337, 1338, 1339, 1340, 1316, 1316, 1316, 1316, 1316, 1342, + 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, + + 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, + 1363, 1363, 1363, 1363, 1363, 1364, 1365, 1366, 1367, 1368, + 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, + 1379, 1380, 1381, 1382, 1383, 1282, 1363, 1363, 1363, 1363, + 1363, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, + 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, + 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, + 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, + 1423, 1424, 1425, 1426, 1073, 1072, 1071, 1070, 1069, 1068, + 1067, 1066, 1065, 1064, 1063, 1062, 1061, 1060, 1059, 1058, + + 1057, 1341, 100, 100, 100, 100, 100, 100, 100, 100, + 103, 103, 103, 103, 103, 103, 103, 103, 106, 106, + 106, 106, 106, 106, 106, 106, 110, 110, 110, 110, + 110, 110, 110, 110, 129, 1056, 1055, 129, 220, 220, + 376, 1054, 376, 376, 1053, 376, 376, 376, 377, 1052, + 377, 377, 377, 377, 377, 377, 380, 380, 380, 380, + 1051, 380, 380, 380, 382, 1050, 1049, 382, 382, 382, + 382, 382, 384, 384, 384, 384, 384, 384, 384, 384, + 392, 1048, 392, 392, 392, 392, 392, 411, 411, 460, + 460, 460, 460, 460, 460, 460, 460, 669, 669, 669, + + 669, 1047, 669, 669, 669, 671, 671, 671, 671, 1043, + 671, 671, 671, 722, 722, 722, 722, 722, 722, 722, + 722, 1042, 1041, 1040, 1039, 1038, 1037, 1036, 1033, 1032, + 1031, 1030, 1029, 1028, 1027, 1026, 1025, 1024, 1023, 1022, + 1021, 1020, 1019, 1018, 1017, 1016, 1015, 1014, 1013, 1012, + 1009, 1006, 1005, 1002, 1001, 1000, 999, 998, 997, 996, + 995, 994, 993, 992, 991, 990, 989, 988, 987, 986, + 985, 984, 983, 982, 981, 980, 979, 978, 977, 976, + 975, 974, 970, 969, 968, 967, 963, 962, 961, 960, + 959, 958, 957, 956, 955, 954, 953, 952, 951, 950, + + 949, 948, 947, 946, 945, 944, 943, 942, 941, 940, + 939, 938, 937, 936, 935, 934, 933, 932, 931, 930, + 929, 928, 927, 926, 925, 924, 923, 922, 921, 920, + 919, 918, 917, 916, 915, 914, 913, 912, 911, 910, + 909, 908, 907, 906, 905, 904, 903, 902, 723, 890, + 889, 888, 887, 886, 885, 884, 883, 882, 881, 880, + 879, 878, 877, 874, 672, 873, 670, 871, 870, 869, + 868, 867, 866, 865, 864, 863, 862, 861, 860, 859, + 858, 857, 856, 855, 854, 853, 852, 851, 850, 849, + 848, 847, 844, 843, 842, 841, 840, 839, 838, 837, + + 836, 835, 834, 833, 832, 831, 830, 829, 828, 827, + 826, 825, 824, 823, 822, 821, 820, 819, 818, 817, + 816, 813, 812, 811, 808, 807, 806, 805, 804, 803, + 802, 801, 800, 799, 798, 797, 796, 795, 794, 793, + 789, 788, 787, 786, 783, 782, 781, 780, 779, 778, + 777, 776, 775, 772, 771, 770, 769, 768, 767, 766, + 765, 764, 763, 762, 761, 760, 759, 758, 757, 756, + 755, 754, 753, 752, 751, 750, 749, 748, 747, 746, + 745, 744, 743, 742, 741, 740, 739, 738, 737, 736, + 735, 734, 733, 732, 731, 730, 729, 728, 727, 726, + + 725, 724, 723, 461, 707, 706, 705, 704, 703, 702, + 701, 700, 699, 698, 697, 694, 693, 692, 691, 690, + 689, 688, 687, 686, 685, 684, 683, 682, 681, 680, + 672, 670, 381, 666, 663, 643, 642, 633, 632, 631, + 630, 629, 628, 627, 623, 622, 621, 620, 619, 618, + 617, 616, 613, 612, 611, 610, 609, 605, 604, 603, + 599, 596, 593, 590, 589, 588, 587, 586, 582, 576, + 575, 574, 571, 570, 569, 568, 567, 564, 563, 562, + 561, 560, 559, 556, 555, 554, 553, 552, 551, 550, + 549, 548, 547, 544, 541, 540, 536, 531, 530, 527, + + 526, 525, 524, 523, 522, 521, 520, 519, 514, 513, + 512, 511, 510, 509, 508, 507, 506, 505, 504, 503, + 502, 499, 498, 497, 496, 495, 494, 490, 487, 486, + 485, 484, 483, 482, 481, 480, 479, 478, 477, 476, + 475, 474, 473, 472, 461, 459, 454, 453, 452, 451, + 450, 449, 448, 445, 438, 428, 427, 426, 425, 424, + 423, 422, 419, 418, 417, 416, 415, 414, 410, 396, + 395, 394, 393, 383, 381, 375, 374, 373, 365, 353, + 352, 351, 313, 309, 265, 262, 249, 248, 245, 237, + 223, 1427, 11, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427 + } ; + +static const flex_int16_t yy_chk[2234] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 4, 5, 6, 7, 8, 9, 7, 8, 10, + 15, 3, 4, 5, 6, 13, 24, 13, 26, 25, + 34, 34, 34, 15, 36, 36, 39, 50, 945, 17, + 24, 17, 25, 15, 17, 17, 17, 17, 17, 50, + 75, 47, 19, 19, 44, 75, 17, 17, 17, 17, + 17, 17, 55, 19, 39, 43, 20, 7, 8, 26, + + 20, 55, 19, 9, 946, 58, 10, 35, 35, 13, + 47, 27, 44, 27, 20, 17, 17, 17, 17, 17, + 17, 27, 27, 27, 62, 35, 35, 35, 17, 19, + 43, 19, 56, 19, 58, 29, 56, 17, 62, 19, + 29, 66, 67, 19, 20, 29, 42, 20, 67, 19, + 42, 66, 292, 20, 29, 93, 42, 20, 292, 19, + 68, 19, 21, 71, 68, 21, 21, 21, 62, 68, + 76, 21, 21, 71, 21, 21, 21, 93, 76, 42, + 78, 78, 21, 76, 21, 21, 21, 42, 21, 28, + 28, 158, 28, 28, 28, 28, 28, 28, 28, 28, + + 132, 132, 30, 947, 30, 30, 30, 30, 30, 255, + 32, 158, 255, 29, 30, 21, 32, 32, 21, 32, + 30, 38, 38, 38, 38, 38, 21, 41, 32, 21, + 21, 21, 38, 28, 21, 21, 948, 21, 32, 54, + 21, 41, 83, 21, 53, 73, 30, 83, 31, 30, + 31, 31, 31, 31, 31, 53, 73, 32, 30, 46, + 31, 46, 46, 73, 46, 53, 31, 30, 54, 41, + 46, 70, 70, 53, 197, 197, 238, 54, 53, 41, + 63, 70, 84, 63, 63, 63, 84, 147, 63, 88, + 63, 63, 63, 63, 63, 31, 63, 63, 320, 63, + + 320, 65, 63, 65, 147, 65, 238, 65, 65, 65, + 65, 69, 228, 69, 69, 69, 69, 30, 69, 77, + 102, 69, 228, 80, 79, 102, 156, 80, 77, 80, + 79, 949, 79, 77, 79, 79, 80, 80, 79, 94, + 81, 79, 81, 156, 81, 82, 160, 88, 81, 113, + 160, 113, 82, 950, 81, 161, 94, 157, 81, 81, + 92, 82, 161, 31, 82, 94, 162, 92, 92, 92, + 96, 162, 155, 96, 157, 96, 96, 96, 96, 123, + 123, 123, 123, 96, 109, 109, 109, 109, 109, 155, + 155, 164, 196, 195, 196, 951, 184, 196, 196, 196, + + 196, 196, 164, 113, 119, 119, 119, 119, 119, 184, + 269, 256, 280, 196, 256, 269, 119, 119, 119, 119, + 119, 119, 195, 231, 272, 952, 109, 280, 275, 231, + 109, 273, 126, 275, 272, 126, 126, 109, 273, 275, + 231, 109, 196, 109, 953, 119, 119, 119, 119, 119, + 119, 374, 119, 120, 120, 120, 120, 120, 119, 198, + 198, 198, 198, 311, 374, 120, 120, 120, 120, 120, + 120, 121, 121, 121, 121, 121, 278, 377, 126, 278, + 126, 311, 377, 121, 121, 121, 121, 121, 121, 218, + 218, 218, 218, 218, 120, 120, 120, 120, 120, 120, + + 306, 120, 300, 314, 314, 954, 306, 120, 126, 314, + 126, 323, 121, 121, 121, 121, 121, 121, 300, 121, + 122, 122, 122, 122, 122, 323, 338, 312, 955, 338, + 312, 332, 122, 122, 122, 122, 122, 122, 124, 124, + 124, 124, 124, 312, 328, 332, 328, 371, 956, 332, + 124, 124, 124, 124, 124, 124, 370, 328, 844, 370, + 370, 122, 122, 122, 122, 122, 122, 326, 122, 469, + 469, 372, 378, 326, 371, 372, 844, 378, 441, 124, + 124, 124, 124, 124, 124, 186, 186, 186, 186, 186, + 193, 193, 193, 193, 193, 186, 401, 401, 401, 401, + + 193, 186, 457, 463, 957, 194, 193, 194, 194, 194, + 194, 194, 199, 199, 199, 199, 199, 194, 958, 347, + 536, 569, 347, 194, 199, 199, 199, 199, 199, 199, + 186, 457, 463, 536, 569, 193, 347, 366, 366, 959, + 366, 366, 366, 366, 366, 366, 441, 552, 673, 673, + 369, 369, 194, 199, 199, 199, 199, 199, 199, 369, + 547, 369, 552, 552, 547, 369, 960, 369, 403, 369, + 712, 403, 403, 839, 369, 369, 369, 369, 369, 385, + 385, 385, 385, 385, 386, 386, 386, 386, 386, 397, + 397, 397, 397, 397, 466, 466, 466, 466, 466, 712, + + 961, 397, 397, 397, 397, 397, 397, 807, 807, 400, + 400, 400, 400, 400, 403, 807, 403, 839, 874, 873, + 194, 400, 400, 400, 400, 400, 400, 873, 874, 962, + 397, 397, 397, 397, 397, 397, 963, 397, 467, 467, + 467, 467, 467, 574, 403, 964, 403, 965, 966, 574, + 400, 400, 400, 400, 400, 400, 967, 400, 402, 402, + 402, 402, 402, 470, 470, 470, 470, 971, 972, 973, + 402, 402, 402, 402, 402, 402, 458, 974, 458, 975, + 976, 458, 458, 458, 458, 458, 468, 977, 468, 978, + 608, 468, 468, 468, 468, 468, 608, 458, 979, 402, + + 402, 402, 402, 402, 402, 462, 462, 462, 462, 462, + 980, 464, 981, 464, 982, 462, 464, 464, 464, 464, + 464, 462, 465, 983, 465, 984, 458, 465, 465, 465, + 465, 465, 464, 472, 472, 472, 472, 472, 667, 667, + 667, 667, 667, 465, 668, 668, 668, 668, 668, 985, + 462, 471, 471, 471, 471, 471, 709, 709, 709, 709, + 709, 464, 986, 471, 471, 471, 471, 471, 471, 708, + 987, 708, 465, 988, 708, 708, 708, 708, 708, 710, + 710, 710, 710, 710, 715, 715, 715, 715, 715, 992, + 708, 993, 471, 471, 471, 471, 471, 471, 711, 994, + + 711, 995, 996, 711, 711, 711, 711, 711, 713, 997, + 713, 998, 1000, 713, 713, 713, 713, 713, 714, 708, + 714, 1001, 1002, 714, 714, 714, 714, 714, 1003, 713, + 716, 716, 716, 716, 716, 717, 1004, 717, 1005, 714, + 717, 717, 717, 717, 717, 718, 718, 718, 718, 718, + 719, 719, 719, 719, 719, 720, 1007, 720, 713, 1008, + 720, 720, 720, 720, 720, 1009, 1010, 1011, 714, 721, + 721, 721, 721, 721, 802, 842, 1012, 1013, 1015, 802, + 842, 1016, 1017, 1018, 1019, 802, 872, 872, 872, 872, + 872, 891, 891, 891, 891, 891, 892, 892, 892, 892, + + 892, 893, 1020, 893, 1021, 1022, 893, 893, 893, 893, + 893, 894, 1024, 894, 1025, 1027, 894, 894, 894, 894, + 894, 895, 895, 895, 895, 895, 896, 896, 896, 896, + 896, 897, 894, 897, 1028, 1029, 897, 897, 897, 897, + 897, 898, 898, 898, 898, 898, 899, 899, 899, 899, + 899, 900, 1030, 900, 1032, 1034, 900, 900, 900, 900, + 900, 894, 1033, 1033, 1035, 1036, 1039, 1040, 1041, 1042, + 1043, 1044, 1044, 1044, 1044, 1044, 1045, 1045, 1045, 1045, + 1045, 1047, 1046, 1048, 1046, 1052, 721, 1046, 1046, 1046, + 1046, 1046, 1054, 1055, 1056, 1057, 1061, 1063, 1065, 1066, + + 1068, 1070, 1071, 1075, 1076, 1077, 1079, 1080, 1081, 1082, + 1083, 1084, 1085, 1086, 1087, 1088, 1092, 1095, 1096, 1097, + 1098, 1099, 1100, 1103, 1104, 1105, 1106, 1107, 1109, 1110, + 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1120, 1122, 1123, + 1126, 1127, 1128, 1129, 1130, 1132, 1133, 1135, 1136, 1138, + 1139, 1142, 1144, 1145, 1146, 1147, 1148, 1152, 1153, 1155, + 1156, 1158, 1158, 1158, 1158, 1158, 1159, 1160, 1161, 1164, + 1166, 1169, 1170, 1171, 1173, 1174, 1175, 1176, 1177, 1182, + 1183, 1184, 1185, 1186, 1188, 1189, 1190, 1191, 1192, 1196, + 1197, 1198, 1199, 1200, 1201, 1202, 1204, 1206, 1207, 1208, + + 1209, 1210, 1211, 1212, 1213, 1215, 1216, 1217, 1218, 1219, + 1221, 1222, 1223, 1226, 1227, 1229, 1230, 1231, 1230, 1230, + 1230, 1230, 1230, 1234, 1235, 1237, 1239, 1241, 1242, 1243, + 1244, 1245, 1246, 1247, 1249, 1250, 1251, 1252, 1255, 1257, + 1260, 1246, 1261, 1263, 1265, 1266, 1271, 1272, 1273, 1274, + 1276, 1277, 1278, 1279, 1280, 1281, 1281, 1281, 1281, 1281, + 1282, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1295, 1296, + 1297, 1298, 1299, 1301, 1302, 1304, 1306, 1308, 1309, 1310, + 1311, 1312, 1314, 1315, 1316, 1316, 1316, 1316, 1316, 1317, + 1319, 1320, 1321, 1322, 1323, 1324, 1326, 1327, 1328, 1329, + + 1330, 1331, 1333, 1334, 1335, 1336, 1337, 1338, 1340, 1341, + 1342, 1342, 1342, 1342, 1342, 1343, 1344, 1347, 1348, 1349, + 1350, 1351, 1353, 1355, 1356, 1357, 1358, 1359, 1360, 1361, + 1362, 1364, 1367, 1368, 1369, 1230, 1363, 1363, 1363, 1363, + 1363, 1370, 1371, 1372, 1373, 1375, 1377, 1378, 1380, 1381, + 1382, 1383, 1384, 1385, 1387, 1388, 1390, 1391, 1392, 1394, + 1395, 1396, 1397, 1399, 1400, 1401, 1402, 1403, 1404, 1405, + 1406, 1407, 1408, 1409, 1410, 1412, 1413, 1414, 1416, 1419, + 1421, 1422, 1424, 1425, 944, 941, 939, 938, 937, 936, + 935, 934, 933, 929, 928, 927, 926, 925, 924, 920, + + 919, 1316, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, + 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1430, 1430, + 1430, 1430, 1430, 1430, 1430, 1430, 1431, 1431, 1431, 1431, + 1431, 1431, 1431, 1431, 1432, 918, 917, 1432, 1433, 1433, + 1434, 916, 1434, 1434, 915, 1434, 1434, 1434, 1435, 913, + 1435, 1435, 1435, 1435, 1435, 1435, 1436, 1436, 1436, 1436, + 912, 1436, 1436, 1436, 1437, 911, 910, 1437, 1437, 1437, + 1437, 1437, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, + 1439, 909, 1439, 1439, 1439, 1439, 1439, 1440, 1440, 1441, + 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1442, 1442, 1442, + + 1442, 901, 1442, 1442, 1442, 1443, 1443, 1443, 1443, 889, + 1443, 1443, 1443, 1444, 1444, 1444, 1444, 1444, 1444, 1444, + 1444, 888, 887, 884, 883, 882, 881, 877, 870, 869, + 868, 867, 866, 865, 864, 863, 862, 861, 860, 859, + 858, 857, 856, 855, 854, 851, 849, 847, 846, 845, + 843, 841, 840, 838, 836, 835, 834, 833, 832, 831, + 830, 829, 828, 827, 826, 825, 824, 823, 822, 821, + 820, 818, 817, 816, 815, 814, 813, 812, 811, 810, + 809, 808, 806, 805, 804, 803, 801, 800, 799, 798, + 797, 795, 794, 793, 792, 791, 790, 789, 788, 787, + + 785, 784, 783, 782, 781, 780, 779, 777, 775, 774, + 773, 772, 771, 770, 769, 768, 767, 765, 764, 762, + 760, 759, 758, 757, 756, 755, 754, 753, 752, 751, + 747, 746, 745, 744, 743, 739, 738, 736, 735, 734, + 733, 732, 731, 728, 727, 726, 725, 724, 722, 706, + 705, 704, 703, 700, 699, 698, 697, 696, 694, 693, + 682, 681, 680, 672, 671, 670, 669, 666, 633, 632, + 630, 629, 628, 627, 626, 625, 624, 623, 622, 621, + 620, 619, 618, 617, 616, 615, 614, 613, 612, 611, + 610, 609, 607, 606, 605, 604, 603, 601, 600, 599, + + 598, 597, 596, 595, 594, 593, 592, 591, 588, 587, + 586, 585, 584, 582, 581, 580, 579, 578, 577, 576, + 575, 572, 571, 570, 568, 567, 566, 565, 564, 563, + 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, + 551, 550, 549, 548, 546, 545, 544, 543, 542, 540, + 539, 538, 537, 535, 533, 532, 531, 530, 529, 528, + 526, 525, 524, 523, 522, 521, 520, 518, 517, 516, + 515, 514, 513, 512, 511, 509, 507, 506, 505, 504, + 503, 502, 501, 500, 499, 496, 495, 494, 493, 492, + 491, 490, 489, 488, 487, 485, 484, 483, 478, 476, + + 475, 474, 473, 460, 452, 451, 450, 449, 448, 447, + 446, 445, 444, 443, 442, 440, 439, 437, 435, 433, + 431, 430, 428, 426, 422, 421, 418, 417, 416, 415, + 396, 395, 380, 375, 373, 368, 367, 360, 357, 352, + 351, 350, 349, 348, 346, 345, 344, 343, 342, 341, + 340, 339, 337, 336, 335, 334, 333, 331, 330, 329, + 327, 324, 321, 319, 318, 317, 316, 315, 313, 309, + 308, 307, 305, 304, 303, 302, 301, 299, 298, 297, + 295, 294, 293, 291, 290, 289, 287, 286, 285, 284, + 283, 282, 281, 279, 277, 276, 274, 271, 270, 265, + + 264, 263, 262, 261, 260, 259, 258, 257, 254, 252, + 251, 250, 248, 247, 246, 245, 243, 242, 241, 240, + 239, 237, 236, 235, 234, 233, 232, 229, 227, 226, + 225, 224, 223, 222, 221, 217, 214, 212, 208, 207, + 206, 205, 201, 200, 190, 188, 177, 170, 169, 168, + 167, 166, 165, 163, 159, 154, 153, 152, 151, 150, + 149, 148, 146, 145, 144, 143, 142, 135, 127, 118, + 117, 115, 114, 108, 103, 99, 98, 97, 95, 87, + 86, 85, 74, 72, 59, 57, 52, 51, 49, 45, + 40, 11, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, + 1427, 1427, 1427 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "input_lexer.ll" +#line 2 "input_lexer.ll" + /* -*- mode: C++; compile-command: "flex input_lexer.ll && make input_lexer.o " -*- */ +/* Note: for the nspire port, after flex, move from #ifdef HAVE_CONFIG_H + to #include "first.h" before #include + and map "log" to log10 instead of ln +*/ +/** @file input_lexer.ll + * + * Lexical analyzer definition for reading expressions. + * Note Maple input should be processed replacing # with // and { } for set + * This file must be processed with flex. */ +/* + * Copyright (C) 2001,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * The very first version was inspired by GiNaC lexer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* + * The lexer will first check for static patterns and strings (defined below) + * If a match is not found, it calls find_or_make_symbol + * This function looks first if the string should be translated + * (e.g. add a prefix from the export table) + * then look in lexer_functions for a match, then look in sym_tab + * if not found in sym_tab, a new identificateur is created & added in sym_tab + * Functions in lexer_functions are added during the construction + * of the corresponding unary_functions using lexer_functions_register + */ +/* + * Definitions + */ +#ifdef NUMWORKS +#define at_log at_logb +#else +#define at_log at_ln +#endif +#include "giacPCH.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#if !defined RTOS_THREADX && !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 +#include +#endif + +#include "gen.h" +#include "input_lexer.h" +#include "help.h" +#include "identificateur.h" +#include "usual.h" +#include "derive.h" +#include "series.h" +#include "intg.h" +#include "sym2poly.h" +#include "moyal.h" +#include "subst.h" +#include "vecteur.h" +#include "modpoly.h" +#include "lin.h" +#include "solve.h" +#include "ifactor.h" +#include "alg_ext.h" +#include "gauss.h" +#include "isom.h" +#include "plot.h" +#include "ti89.h" + +#include "prog.h" +#include "rpn.h" +#include "ezgcd.h" +#include "tex.h" +#include "risch.h" +#include "permu.h" +#include "input_parser.h" + +#if defined(RTOS_THREADX) || (defined(__MINGW_H) && !defined(KHICAS)) || defined NSPIRE || defined MS_SMART || defined(FREERTOS) + extern "C" int isatty (int ){ return 0; } +#endif + +#if defined BESTA_OS || defined(FREERTOS) +#define EINTR 4 +#endif + +#ifdef NSPIRE + // after flex, move #include "config.h" and first.h before all includes + // include "static.h" then giacPCH.h + // then edit input_lexer.cc and search for isatty, replace by 0 for interactive + void clearerr(FILE *){} +#endif + + using namespace std; + using namespace giac; + void giac_yyset_column (int column_no , yyscan_t yyscanner); + int giac_yyget_column (yyscan_t yyscanner); +#define YY_USER_ACTION giac_yyset_column(giac_yyget_column(yyscanner)+yyleng,yyscanner); +#define YY_USER_INIT giac_yyset_column(1,yyscanner); + +#ifndef NO_NAMESPACE_GIAC + namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + void increment_lexer_line_number_setcol(yyscan_t yyscanner,GIAC_CONTEXT){ + giac_yyset_column(1,yyscanner); + increment_lexer_line_number(contextptr); + } + bool doing_insmod = false; + +#ifdef HAVE_LIBPTHREAD + static pthread_mutex_t * syms_mutex_ptr = 0; + + int lock_syms_mutex(){ + if (!syms_mutex_ptr){ + pthread_mutex_t tmp=PTHREAD_MUTEX_INITIALIZER; + syms_mutex_ptr=new pthread_mutex_t(tmp); + } + return pthread_mutex_lock(syms_mutex_ptr); + } + + void unlock_syms_mutex(){ + if (syms_mutex_ptr) + pthread_mutex_unlock(syms_mutex_ptr); + } + +#else + int lock_syms_mutex(){ return 0; } + void unlock_syms_mutex(){} +#endif + + sym_string_tab & syms(){ + static sym_string_tab * ans=0; + if (!ans) ans=new sym_string_tab; + return * ans; + } + + + std::vector & lexer_localization_vector(){ + static std::vector * ans=0; + if (!ans) ans=new std::vector; + return *ans; + } + +#ifdef USTL + ustl::map & lexer_localization_map(){ + static ustl::map * ans = 0; + if (!ans) ans=new ustl::map; + return * ans; + } + ustl::multimap & back_lexer_localization_map(){ + static ustl::multimap * ans= 0; + if (!ans) ans=new ustl::multimap; + return * ans; + } + + // lexer_localization_vector() is the list of languages currently translated + // lexer_localization_map translates keywords from the locale to giac + // back_lexer_localization_map() lists for a giac keyword the translations + + ustl::map > & lexer_translator (){ + static ustl::map > * ans = 0; + if (!ans) ans=new ustl::map >; + return * ans; + } + // lexer_translator will be updated when export/with is called + // To each string (w/o ::) in a given library, + // If it exists, we push_back the full string (with ::) + // If not we create a vector with the full string + // If a library is unexported we remove the corresponding entry in the + // vector and remove the entry if the vector is empty + ustl::map > & library_functions (){ + static ustl::map > * ans=0; + if (!ans) ans=new ustl::map >; + return *ans; + } + +#else + std::map & lexer_localization_map(){ + static std::map * ans = 0; + if (!ans) ans=new std::map; + return * ans; + } + std::multimap & back_lexer_localization_map(){ + static std::multimap * ans= 0; + if (!ans) ans=new std::multimap; + return * ans; + } + // lexer_localization_vector() is the list of languages currently translated + // lexer_localization_map translates keywords from the locale to giac + // back_lexer_localization_map() lists for a giac keyword the translations + + std::map > & lexer_translator (){ + static std::map > * ans = 0; + if (!ans) ans=new std::map >; + return * ans; + } + // lexer_translator will be updated when export/with is called + // To each string (w/o ::) in a given library, + // If it exists, we push_back the full string (with ::) + // If not we create a vector with the full string + // If a library is unexported we remove the corresponding entry in the + // vector and remove the entry if the vector is empty + std::map > & library_functions (){ + static std::map > * ans=0; + if (!ans) ans=new std::map >; + return *ans; + } + +#endif + + // First string is the library name, second is the vector of function names + // User defined relations + vector & registered_lexer_functions(){ + static vector * ans = 0; + if (!ans){ + ans = new vector; + // ans->reserve(50); + } + return * ans; + } + + bool tri1(const lexer_tab_int_type & a,const lexer_tab_int_type & b){ + int res= strcmp(a.keyword,b.keyword); + return res<0; + } + + bool tri2(const char * a,const char * b){ + return strcmp(a,b)<0; + } + + const lexer_tab_int_type lexer_tab_int_values []={ +#ifdef GIAC_HAS_STO_38 +#include "lexer_tab38_int.h" +#else +#include "lexer_tab_int.h" +#endif + }; + + const lexer_tab_int_type * const lexer_tab_int_values_begin = lexer_tab_int_values; + const unsigned lexer_tab_int_values_n=sizeof(lexer_tab_int_values)/sizeof(lexer_tab_int_type); + const lexer_tab_int_type * const lexer_tab_int_values_end = lexer_tab_int_values+lexer_tab_int_values_n; +#ifndef NO_NAMESPACE_GIAC + } // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + +#line 1874 "input_lexer.cc" +#line 270 "input_lexer.ll" + /* Abbreviations */ + /* If changed, modify isalphan in help.cc FIXME is . allowed inside alphanumeric ? answer NO */ + + + + +/* + * Lexical rules + */ +#line 1885 "input_lexer.cc" + +#define INITIAL 0 +#define comment 1 +#define comment_hash 2 +#define str 3 +#define backquote 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 284 "input_lexer.ll" + + +#line 2166 "input_lexer.cc" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1428 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 2093 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 286 "input_lexer.ll" +/* skip whitespace */ + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 287 "input_lexer.ll" +increment_lexer_line_number_setcol(yyscanner,yyextra); //CERR << "Scanning line " << lexer_line_number(yyextra) << '\n'; + YY_BREAK +/* Strings */ +/* \"[^\"]*\" yylval = string2gen( giac_yytext); return T_STRING; */ +case 3: +YY_RULE_SETUP +#line 290 "input_lexer.ll" +BEGIN(str); comment_s("",yyextra); + YY_BREAK +case 4: +YY_RULE_SETUP +#line 291 "input_lexer.ll" +increment_comment_s('"',yyextra); + YY_BREAK +case 5: +YY_RULE_SETUP +#line 292 "input_lexer.ll" +{ index_status(yyextra)=1; BEGIN(INITIAL); + (*yylval)=string2gen(comment_s(yyextra),false); + return T_STRING; } + YY_BREAK +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 295 "input_lexer.ll" +increment_comment_s('\n',yyextra); increment_lexer_line_number_setcol(yyscanner,yyextra); + YY_BREAK +case 7: +YY_RULE_SETUP +#line 296 "input_lexer.ll" +{ + /* octal escape sequence */ + int result=0; + (void) sscanf( yytext + 1, "%o", &result ); // not supported on FXCG + increment_comment_s(char(result & 0xff),yyextra); + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 302 "input_lexer.ll" +{ + /* generate error - bad escape sequence; something + * like '\48' or '\0777777' + */ + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 307 "input_lexer.ll" +increment_comment_s('\n',yyextra); + YY_BREAK +case 10: +YY_RULE_SETUP +#line 308 "input_lexer.ll" +increment_comment_s('\t',yyextra); + YY_BREAK +case 11: +YY_RULE_SETUP +#line 309 "input_lexer.ll" +increment_comment_s('\r',yyextra); + YY_BREAK +case 12: +YY_RULE_SETUP +#line 310 "input_lexer.ll" +increment_comment_s('\b',yyextra); + YY_BREAK +case 13: +YY_RULE_SETUP +#line 311 "input_lexer.ll" +increment_comment_s('\f',yyextra); + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 312 "input_lexer.ll" +increment_comment_s(yytext[1],yyextra); + YY_BREAK +case 15: +YY_RULE_SETUP +#line 313 "input_lexer.ll" +increment_comment_s(yytext,yyextra); + YY_BREAK +case 16: +YY_RULE_SETUP +#line 314 "input_lexer.ll" +if (rpn_mode(yyextra)){ index_status(yyextra)=0; return T_ACCENTGRAVE; } else { BEGIN(backquote); comment_s("",yyextra); } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 315 "input_lexer.ll" +increment_comment_s('\n',yyextra); increment_lexer_line_number_setcol(yyscanner,yyextra); + YY_BREAK +case 18: +YY_RULE_SETUP +#line 316 "input_lexer.ll" +increment_comment_s(yytext,yyextra); + YY_BREAK +case 19: +YY_RULE_SETUP +#line 317 "input_lexer.ll" +{ index_status(yyextra)=1; BEGIN(INITIAL); + return find_or_make_symbol(comment_s(yyextra),(*yylval),yyscanner,true,yyextra); } + YY_BREAK +case 20: +/* rule 20 can match eol */ +YY_RULE_SETUP +#line 320 "input_lexer.ll" +index_status(yyextra)=0; increment_lexer_line_number_setcol(yyscanner,yyextra); + YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +#line 321 "input_lexer.ll" +index_status(yyextra)=0; increment_lexer_line_number_setcol(yyscanner,yyextra);/* (*yylval) = string2gen('"'+string(giac_yytext).substr(2,string(giac_yytext).size()-3)+'"'); return T_COMMENT; */ + YY_BREAK +case 22: +YY_RULE_SETUP +#line 322 "input_lexer.ll" +BEGIN(comment); comment_s(yyextra)=""; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 324 "input_lexer.ll" +comment_s(yyextra)+=yytext; /* eat anything that's not a '*' */ + YY_BREAK +case 24: +YY_RULE_SETUP +#line 325 "input_lexer.ll" +comment_s(yyextra)+=yytext; /* eat up '*'s not followed by '/'s */ + YY_BREAK +case 25: +/* rule 25 can match eol */ +YY_RULE_SETUP +#line 326 "input_lexer.ll" +comment_s(yyextra) += '\n'; increment_lexer_line_number_setcol(yyscanner,yyextra); CERR << "(Comment) scanning line " << lexer_line_number(yyextra) << '\n'; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 327 "input_lexer.ll" +BEGIN(INITIAL); index_status(yyextra)=0; /* (*yylval) = string2gen(comment_s(yyextra),false); return T_COMMENT; */ + YY_BREAK +case 27: +/* rule 27 can match eol */ +YY_RULE_SETUP +#line 328 "input_lexer.ll" +index_status(yyextra)=0; /* (*yylval) = string2gen('"'+string(yytext).substr(3,string(yytext).size()-6)+'"'); return T_COMMENT; */ + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +#line 329 "input_lexer.ll" +index_status(yyextra)=0; /* (*yylval) = string2gen('"'+string(yytext).substr(3,string(yytext).size()-6)+'"'); return T_COMMENT; */ + YY_BREAK +case 29: +YY_RULE_SETUP +#line 331 "input_lexer.ll" +if (index_status(yyextra)) return T_INTERROGATION; if (calc_mode(yyextra)==1){ *yylval=undef; return T_SYMBOL;} return T_HELP; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 332 "input_lexer.ll" +opened_quote(yyextra) |= 2; return T_UNIT; + YY_BREAK +case 31: +YY_RULE_SETUP +#line 333 "input_lexer.ll" +if (opened_quote(yyextra) & 1) { opened_quote(yyextra) &= 0x7ffffffe; return T_QUOTE; } if (index_status(yyextra) && !in_rpn(yyextra) && xcas_mode(yyextra)!= 1) return T_PRIME; opened_quote(yyextra) |= 1; return T_QUOTE; + YY_BREAK +case 32: +YY_RULE_SETUP +#line 334 "input_lexer.ll" +index_status(yyextra)=0; if (xcas_mode(yyextra)==3) return TI_SEMI; (*yylval)=0; return T_SEMI; + YY_BREAK +/* commented otherwise for(;;) will not work ";;" index_status(yyextra)=0; if (xcas_mode(yyextra)==3) return TI_SEMI; (*yylval)=0; return T_SEMI; */ +case 33: +YY_RULE_SETUP +#line 336 "input_lexer.ll" +index_status(yyextra)=0; if (xcas_mode(yyextra)==3) return T_SEMI; return TI_SEMI; + YY_BREAK +case 34: +YY_RULE_SETUP +#line 337 "input_lexer.ll" +if (spread_formula(yyextra)) return T_DEUXPOINTS; if ( xcas_mode(yyextra)==3 ) { index_status(yyextra)=0; return TI_DEUXPOINTS; } index_status(yyextra)=0; if (xcas_mode(yyextra)>0) { (*yylval)=1; return T_SEMI; } else return T_DEUXPOINTS; + YY_BREAK +case 35: +YY_RULE_SETUP +#line 338 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=1; return T_SEMI; + YY_BREAK +case 36: +YY_RULE_SETUP +#line 339 "input_lexer.ll" +index_status(yyextra)=0;return T_DOUBLE_DEUX_POINTS; + YY_BREAK +/* special values */ +case 37: +YY_RULE_SETUP +#line 343 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=theta__IDNT_e; return T_SYMBOL; + YY_BREAK +case 38: +YY_RULE_SETUP +#line 344 "input_lexer.ll" +index_status(yyextra)=1; if (xcas_mode(yyextra) > 0 || !i_sqrt_minus1(yyextra)) { (*yylval)=i__IDNT_e; return T_SYMBOL; } else { (*yylval) = cst_i; return T_LITERAL;}; + YY_BREAK +case 39: +YY_RULE_SETUP +#line 345 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_i; return T_LITERAL; + YY_BREAK +case 40: +YY_RULE_SETUP +#line 346 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_i; return T_LITERAL; + YY_BREAK +case 41: +YY_RULE_SETUP +#line 347 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_i; return T_LITERAL; + YY_BREAK +case 42: +YY_RULE_SETUP +#line 348 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_i; return T_LITERAL; + YY_BREAK +/* \xef\xbd\x89 index_status(yyextra)=1; (*yylval) = cst_i; return T_LITERAL; */ +case 43: +YY_RULE_SETUP +#line 350 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_i; return T_LITERAL; + YY_BREAK +case 44: +YY_RULE_SETUP +#line 351 "input_lexer.ll" +index_status(yyextra)=1; if (python_compat(yyextra)>=0 && (xcas_mode(yyextra)==0 || xcas_mode(yyextra)==3 || rpn_mode(yyextra)) ) { return find_or_make_symbol(yytext,(*yylval),yyscanner,true,yyextra); } else { (*yylval) = cst_i; return T_LITERAL; }; + YY_BREAK +case 45: +YY_RULE_SETUP +#line 352 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_i; return T_LITERAL; + YY_BREAK +case 46: +YY_RULE_SETUP +#line 353 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = symbolic(at_exp,1); return T_LITERAL; + YY_BREAK +case 47: +YY_RULE_SETUP +#line 354 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_pi; return T_LITERAL; + YY_BREAK +case 48: +YY_RULE_SETUP +#line 355 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_pi; return T_LITERAL; + YY_BREAK +case 49: +YY_RULE_SETUP +#line 356 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_pi; return T_LITERAL; + YY_BREAK +case 50: +YY_RULE_SETUP +#line 357 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_pi; return T_LITERAL; + YY_BREAK +case 51: +YY_RULE_SETUP +#line 358 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_pi; return T_LITERAL; + YY_BREAK +case 52: +YY_RULE_SETUP +#line 359 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = cst_euler_gamma; return T_LITERAL; + YY_BREAK +case 53: +YY_RULE_SETUP +#line 360 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = unsigned_inf; return T_LITERAL; + YY_BREAK +case 54: +YY_RULE_SETUP +#line 361 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = plus_inf; return T_LITERAL; + YY_BREAK +case 55: +YY_RULE_SETUP +#line 362 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = unsigned_inf; return T_LITERAL; + YY_BREAK +case 56: +YY_RULE_SETUP +#line 363 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = plus_inf; return T_LITERAL; + YY_BREAK +case 57: +YY_RULE_SETUP +#line 364 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = plus_inf; return T_LITERAL; + YY_BREAK +case 58: +YY_RULE_SETUP +#line 365 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = unsigned_inf; return T_LITERAL; + YY_BREAK +case 59: +YY_RULE_SETUP +#line 366 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = plus_inf; return T_LITERAL; + YY_BREAK +case 60: +YY_RULE_SETUP +#line 367 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = minus_inf; return T_LITERAL; + YY_BREAK +case 61: +YY_RULE_SETUP +#line 368 "input_lexer.ll" +index_status(yyextra)=1; (*yylval) = undef; return T_LITERAL; + YY_BREAK +case 62: +YY_RULE_SETUP +#line 369 "input_lexer.ll" +return T_END_INPUT; + YY_BREAK +/* integer values */ +case 63: +YY_RULE_SETUP +#line 372 "input_lexer.ll" +if (xcas_mode(yyextra)==2){ (*yylval) = gen(at_user_operator,6); index_status(yyextra)=0; return T_UNARY_OP; } index_status(yyextra)=0; (*yylval) = _FUNC; (*yylval).subtype=_INT_TYPE; return T_TYPE_ID; + YY_BREAK +case 64: +YY_RULE_SETUP +#line 373 "input_lexer.ll" +if (python_compat(yyextra)){ *yylval=at_python_list; return T_UNARY_OP; } if (xcas_mode(yyextra)==3) { index_status(yyextra)=1; return find_or_make_symbol(yytext,(*yylval),yyscanner,true,yyextra); } index_status(yyextra)=0; (*yylval) = _MAPLE_LIST ; (*yylval).subtype=_INT_MAPLECONVERSION ;return T_TYPE_ID; + YY_BREAK +/* vector/polynom/matrice delimiters */ +case 65: +YY_RULE_SETUP +#line 377 "input_lexer.ll" +(*yylval) = _SEQ__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 66: +YY_RULE_SETUP +#line 378 "input_lexer.ll" +(*yylval) = _SET__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 67: +YY_RULE_SETUP +#line 379 "input_lexer.ll" +(*yylval) = _INTERVAL__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 68: +YY_RULE_SETUP +#line 380 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _LIST__VECT; return T_VECT_DISPATCH; + YY_BREAK +/* "list(" index_status(yyextra)=0; (*yylval) = _LIST__VECT; return T_BEGIN_PAR; */ +case 69: +YY_RULE_SETUP +#line 382 "input_lexer.ll" +(*yylval) = _RPN_FUNC__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 70: +YY_RULE_SETUP +#line 383 "input_lexer.ll" +(*yylval) = _GROUP__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 71: +YY_RULE_SETUP +#line 384 "input_lexer.ll" +(*yylval) = _LINE__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 72: +YY_RULE_SETUP +#line 385 "input_lexer.ll" +(*yylval) = _VECTOR__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 73: +YY_RULE_SETUP +#line 386 "input_lexer.ll" +(*yylval) = _MATRIX__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 74: +YY_RULE_SETUP +#line 387 "input_lexer.ll" +(*yylval) = _PNT__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 75: +YY_RULE_SETUP +#line 388 "input_lexer.ll" +(*yylval) = _GGB__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 76: +YY_RULE_SETUP +#line 389 "input_lexer.ll" +(*yylval) = _GGBVECT; return T_VECT_DISPATCH; + YY_BREAK +case 77: +YY_RULE_SETUP +#line 390 "input_lexer.ll" +(*yylval) = _POINT__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 78: +YY_RULE_SETUP +#line 391 "input_lexer.ll" +(*yylval) = _TUPLE__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 79: +YY_RULE_SETUP +#line 392 "input_lexer.ll" +(*yylval) = _CURVE__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 80: +YY_RULE_SETUP +#line 393 "input_lexer.ll" +(*yylval) = _HALFLINE__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 81: +YY_RULE_SETUP +#line 394 "input_lexer.ll" +(*yylval) = _POLY1__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 82: +YY_RULE_SETUP +#line 395 "input_lexer.ll" +(*yylval) = _ASSUME__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 83: +YY_RULE_SETUP +#line 396 "input_lexer.ll" +(*yylval) = _LOGO__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 84: +YY_RULE_SETUP +#line 397 "input_lexer.ll" +(*yylval) = _SPREAD__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 85: +YY_RULE_SETUP +#line 398 "input_lexer.ll" +(*yylval) = _FOLDER__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 86: +YY_RULE_SETUP +#line 399 "input_lexer.ll" +(*yylval) = _POLYEDRE__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 87: +YY_RULE_SETUP +#line 400 "input_lexer.ll" +(*yylval) = _RGBA__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 88: +YY_RULE_SETUP +#line 401 "input_lexer.ll" +(*yylval) = _REALSET__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 89: +YY_RULE_SETUP +#line 402 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _LIST__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 90: +YY_RULE_SETUP +#line 403 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 91: +YY_RULE_SETUP +#line 404 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_strict,2); return T_TEST_EQUAL; + YY_BREAK +case 92: +YY_RULE_SETUP +#line 405 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_superieur_strict,2); return T_TEST_EQUAL; + YY_BREAK +case 93: +YY_RULE_SETUP +#line 406 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_strict,2); return T_TEST_EQUAL; + YY_BREAK +case 94: +YY_RULE_SETUP +#line 407 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_egal,2); return T_TEST_EQUAL; + YY_BREAK +case 95: +YY_RULE_SETUP +#line 408 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_superieur_strict,2); return T_TEST_EQUAL; + YY_BREAK +case 96: +YY_RULE_SETUP +#line 409 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_superieur_egal,2); return T_TEST_EQUAL; + YY_BREAK +case 97: +YY_RULE_SETUP +#line 410 "input_lexer.ll" +index_status(yyextra)=0; return T_VIRGULE; + YY_BREAK +case 98: +YY_RULE_SETUP +#line 411 "input_lexer.ll" +index_status(yyextra)=0; return T_VIRGULE; + YY_BREAK +case 99: +YY_RULE_SETUP +#line 412 "input_lexer.ll" +index_status(yyextra)=0; *yylval = 0; return T_BEGIN_PAR; + YY_BREAK +case 100: +YY_RULE_SETUP +#line 413 "input_lexer.ll" +index_status(yyextra)=1; return T_END_PAR; + YY_BREAK +case 101: +YY_RULE_SETUP +#line 414 "input_lexer.ll" +if (index_status(yyextra)) { index_status(yyextra)=0; return T_INDEX_BEGIN; } else { (*yylval) = 0; return T_VECT_DISPATCH; } ; + YY_BREAK +case 102: +YY_RULE_SETUP +#line 415 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 103: +YY_RULE_SETUP +#line 416 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 104: +YY_RULE_SETUP +#line 417 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _POLY1__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 105: +YY_RULE_SETUP +#line 418 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 106: +YY_RULE_SETUP +#line 419 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _MATRIX__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 107: +YY_RULE_SETUP +#line 420 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 108: +YY_RULE_SETUP +#line 421 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _ASSUME__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 109: +YY_RULE_SETUP +#line 422 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +/* geometric delimiters */ +case 110: +YY_RULE_SETUP +#line 424 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _GROUP__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 111: +YY_RULE_SETUP +#line 425 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 112: +YY_RULE_SETUP +#line 426 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _LINE__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 113: +YY_RULE_SETUP +#line 427 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 114: +YY_RULE_SETUP +#line 428 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _VECTOR__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 115: +YY_RULE_SETUP +#line 429 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 116: +YY_RULE_SETUP +#line 430 "input_lexer.ll" +index_status(yyextra)=0; (*yylval) = _CURVE__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 117: +YY_RULE_SETUP +#line 431 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +/* gen delimiters */ +case 118: +YY_RULE_SETUP +#line 433 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=_TABLE__VECT;return T_VECT_DISPATCH; + YY_BREAK +case 119: +YY_RULE_SETUP +#line 434 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 120: +YY_RULE_SETUP +#line 435 "input_lexer.ll" +index_status(yyextra)=0; if (rpn_mode(yyextra)||calc_mode(yyextra)==1) { (*yylval)=0; return T_VECT_DISPATCH; } if (xcas_mode(yyextra)==3 || abs_calc_mode(yyextra)==38){ (*yylval) = _LIST__VECT; return T_VECT_DISPATCH; } if (xcas_mode(yyextra) > 0 ){ (*yylval)=_SET__VECT; return T_VECT_DISPATCH; } else return T_BLOC_BEGIN; + YY_BREAK +case 121: +YY_RULE_SETUP +#line 436 "input_lexer.ll" +index_status(yyextra)=1; if (rpn_mode(yyextra) || calc_mode(yyextra)==1 || python_compat(yyextra)) return T_VECT_END; if (xcas_mode(yyextra)==3 || abs_calc_mode(yyextra)==38) return T_VECT_END; if (xcas_mode(yyextra) > 0) return T_VECT_END; else return T_BLOC_END; + YY_BREAK +case 122: +YY_RULE_SETUP +#line 437 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=_SET__VECT; return T_VECT_DISPATCH; + YY_BREAK +case 123: +YY_RULE_SETUP +#line 438 "input_lexer.ll" +index_status(yyextra)=1; return T_VECT_END; + YY_BREAK +case 124: +YY_RULE_SETUP +#line 439 "input_lexer.ll" +index_status(yyextra)=0; return T_ROOTOF_BEGIN; + YY_BREAK +case 125: +YY_RULE_SETUP +#line 440 "input_lexer.ll" +index_status(yyextra)=1; return T_ROOTOF_END; + YY_BREAK +case 126: +YY_RULE_SETUP +#line 441 "input_lexer.ll" +index_status(yyextra)=0; return T_SPOLY1_BEGIN; + YY_BREAK +case 127: +YY_RULE_SETUP +#line 442 "input_lexer.ll" +index_status(yyextra)=1; return T_SPOLY1_END; + YY_BREAK +case 128: +YY_RULE_SETUP +#line 443 "input_lexer.ll" +index_status(yyextra)=0; if (abs_calc_mode(yyextra)!=38){ (*yylval)=gen(at_rotate,2); return T_UNION; } ++in_rpn(yyextra); return T_RPN_BEGIN; + YY_BREAK +case 129: +YY_RULE_SETUP +#line 444 "input_lexer.ll" +index_status(yyextra)=0; if (abs_calc_mode(yyextra)!=38){ (*yylval)=gen(at_shift,2); return T_UNION; } --in_rpn(yyextra); return T_RPN_END; + YY_BREAK +/* binary operators */ +case 130: +YY_RULE_SETUP +#line 447 "input_lexer.ll" +index_status(yyextra)=0; return T_MAPSTO; + YY_BREAK +case 131: +YY_RULE_SETUP +#line 448 "input_lexer.ll" +(*yylval) = gen(at_couleur,2); index_status(yyextra)=0; return T_INTERVAL; + YY_BREAK +case 132: +YY_RULE_SETUP +#line 449 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_same,2); return T_TEST_EQUAL; + YY_BREAK +case 133: +YY_RULE_SETUP +#line 450 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_equal,2); return T_EQUAL; + YY_BREAK +case 134: +YY_RULE_SETUP +#line 451 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_deuxpoints,2); return T_DEUXPOINTS; + YY_BREAK +case 135: +YY_RULE_SETUP +#line 452 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_same,2); return T_QUOTED_BINARY; + YY_BREAK +case 136: +YY_RULE_SETUP +#line 453 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_same,2); return T_QUOTED_BINARY; + YY_BREAK +case 137: +YY_RULE_SETUP +#line 454 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_different,2); return T_TEST_EQUAL; + YY_BREAK +case 138: +YY_RULE_SETUP +#line 455 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_different,2); return T_QUOTED_BINARY; + YY_BREAK +case 139: +YY_RULE_SETUP +#line 456 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_different,2); return T_TEST_EQUAL; + YY_BREAK +case 140: +YY_RULE_SETUP +#line 457 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_different,2); return T_QUOTED_BINARY; + YY_BREAK +case 141: +YY_RULE_SETUP +#line 458 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_different,2); return T_QUOTED_BINARY; + YY_BREAK +case 142: +YY_RULE_SETUP +#line 459 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_egal,2); return T_QUOTED_BINARY; + YY_BREAK +case 143: +YY_RULE_SETUP +#line 460 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_egal,2); return T_QUOTED_BINARY; + YY_BREAK +case 144: +YY_RULE_SETUP +#line 461 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_egal,2); return T_TEST_EQUAL; + YY_BREAK +case 145: +YY_RULE_SETUP +#line 462 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_strict,2); return T_QUOTED_BINARY; + YY_BREAK +case 146: +YY_RULE_SETUP +#line 463 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_strict,2); return T_QUOTED_BINARY; + YY_BREAK +case 147: +YY_RULE_SETUP +#line 464 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_superieur_strict,2); return T_QUOTED_BINARY; + YY_BREAK +case 148: +YY_RULE_SETUP +#line 465 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_superieur_egal,2); return T_TEST_EQUAL; + YY_BREAK +case 149: +YY_RULE_SETUP +#line 466 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_superieur_egal,2); return T_QUOTED_BINARY; + YY_BREAK +case 150: +YY_RULE_SETUP +#line 467 "input_lexer.ll" +spread_formula(yyextra)=!index_status(yyextra); index_status(yyextra)=0; (*yylval)=gen(at_equal,2); return T_EQUAL; + YY_BREAK +case 151: +YY_RULE_SETUP +#line 468 "input_lexer.ll" +spread_formula(yyextra)=!index_status(yyextra); index_status(yyextra)=0; (*yylval)=gen(at_equal2,2); return T_EQUAL; + YY_BREAK +case 152: +YY_RULE_SETUP +#line 469 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_equal,2); return T_QUOTED_BINARY; + YY_BREAK +case 153: +YY_RULE_SETUP +#line 470 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_dollar,2); if (xcas_mode(yyextra)>0) return T_DOLLAR_MAPLE; else return T_DOLLAR; + YY_BREAK +case 154: +YY_RULE_SETUP +#line 471 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_dollar,2); return T_DOLLAR_MAPLE; + YY_BREAK +case 155: +YY_RULE_SETUP +#line 472 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_dollar,2); return T_QUOTED_BINARY; + YY_BREAK +case 156: +YY_RULE_SETUP +#line 473 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_dollar,2); return T_QUOTED_BINARY; + YY_BREAK +case 157: +YY_RULE_SETUP +#line 474 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sto,2); return T_AFFECT; + YY_BREAK +case 158: +YY_RULE_SETUP +#line 475 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sto,2); return T_QUOTED_BINARY; + YY_BREAK +case 159: +YY_RULE_SETUP +#line 476 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sto,2); return T_QUOTED_BINARY; + YY_BREAK +case 160: +YY_RULE_SETUP +#line 477 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sto,2); return TI_STO; + YY_BREAK +case 161: +YY_RULE_SETUP +#line 478 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sto,2); return TI_STO; + YY_BREAK +case 162: +YY_RULE_SETUP +#line 479 "input_lexer.ll" +index_status(yyextra)=0; if (xcas_mode(yyextra)==3){ (*yylval)=gen(at_sto,2); return TI_STO; } else return T_MAPSTO; + YY_BREAK +case 163: +YY_RULE_SETUP +#line 480 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sto,2); if (python_compat(yyextra)<0) return T_MAPSTO; return TI_STO; + YY_BREAK +case 164: +YY_RULE_SETUP +#line 481 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sto,2); return TI_STO; + YY_BREAK +case 165: +YY_RULE_SETUP +#line 482 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_array_sto,2); return T_AFFECT; + YY_BREAK +case 166: +YY_RULE_SETUP +#line 483 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_array_sto,2); return T_AFFECT; + YY_BREAK +case 167: +YY_RULE_SETUP +#line 484 "input_lexer.ll" +index_status(yyextra)=1; yytext[0]='0'; (*yylval) = symb_double_deux_points(makevecteur(_IDNT_id_at,chartab2gen(yytext,yyextra))); return T_SYMBOL; + YY_BREAK +case 168: +YY_RULE_SETUP +#line 485 "input_lexer.ll" +if (xcas_mode(yyextra)!=3) {index_status(yyextra)=0; (*yylval)=gen(at_compose,2); return T_COMPOSE; } BEGIN(comment_hash); + YY_BREAK +case 169: +YY_RULE_SETUP +#line 486 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_composepow,2); return T_POW; + YY_BREAK +case 170: +YY_RULE_SETUP +#line 487 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_composepow,2); return T_QUOTED_BINARY; + YY_BREAK +case 171: +YY_RULE_SETUP +#line 488 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_composepow,2); return T_QUOTED_BINARY; + YY_BREAK +case 172: +YY_RULE_SETUP +#line 489 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_compose,2); return T_QUOTED_BINARY; + YY_BREAK +case 173: +YY_RULE_SETUP +#line 490 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_compose,2); return T_QUOTED_BINARY; + YY_BREAK +case 174: +YY_RULE_SETUP +#line 491 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_and,2); return T_AND_OP; + YY_BREAK +case 175: +YY_RULE_SETUP +#line 492 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_and,2); return T_AND_OP; + YY_BREAK +case 176: +YY_RULE_SETUP +#line 493 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_and,2); return T_AND_OP; + YY_BREAK +case 177: +YY_RULE_SETUP +#line 494 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_and,2); return T_AND_OP; + YY_BREAK +case 178: +YY_RULE_SETUP +#line 495 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_and,2); return T_QUOTED_BINARY; + YY_BREAK +case 179: +YY_RULE_SETUP +#line 496 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_and,2); return T_QUOTED_BINARY; + YY_BREAK +case 180: +YY_RULE_SETUP +#line 497 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_and,2); return T_QUOTED_BINARY; + YY_BREAK +case 181: +YY_RULE_SETUP +#line 498 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_tilocal,2); return T_PIPE; + YY_BREAK +case 182: +YY_RULE_SETUP +#line 499 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ou,2); return T_AND_OP; + YY_BREAK +case 183: +YY_RULE_SETUP +#line 500 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ou,2); return T_QUOTED_BINARY; + YY_BREAK +case 184: +YY_RULE_SETUP +#line 501 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ou,2); return T_QUOTED_BINARY; + YY_BREAK +case 185: +YY_RULE_SETUP +#line 502 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ou,2); return T_QUOTED_BINARY; + YY_BREAK +case 186: +YY_RULE_SETUP +#line 503 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ou,2); return T_AND_OP; + YY_BREAK +case 187: +YY_RULE_SETUP +#line 504 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ou,2); return T_AND_OP; + YY_BREAK +case 188: +YY_RULE_SETUP +#line 505 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_bitxor,2); return T_AND_OP; + YY_BREAK +case 189: +YY_RULE_SETUP +#line 506 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_xor,2); return T_AND_OP; + YY_BREAK +case 190: +YY_RULE_SETUP +#line 507 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_xor,2); return T_AND_OP; + YY_BREAK +case 191: +YY_RULE_SETUP +#line 508 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_xor,2); return T_QUOTED_BINARY; + YY_BREAK +case 192: +YY_RULE_SETUP +#line 509 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_xor,2); return T_QUOTED_BINARY; + YY_BREAK +case 193: +YY_RULE_SETUP +#line 510 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_xor,2); return T_AND_OP; + YY_BREAK +case 194: +YY_RULE_SETUP +#line 511 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_union,2); return T_AND_OP; + YY_BREAK +case 195: +YY_RULE_SETUP +#line 512 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_intersect,2); return T_AND_OP; + YY_BREAK +case 196: +YY_RULE_SETUP +#line 513 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_symmetric_difference,2); return T_AND_OP; + YY_BREAK +case 197: +YY_RULE_SETUP +#line 514 "input_lexer.ll" +if (index_status(yyextra)) { (*yylval)=gen(at_complement); return T_FACTORIAL; } else { index_status(yyextra)=0; (*yylval)=gen(at_complement,1); return T_NOT; } + YY_BREAK +case 198: +YY_RULE_SETUP +#line 515 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_interval,2); return T_INTERVAL; + YY_BREAK +case 199: +YY_RULE_SETUP +#line 516 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_leftopen_interval,2); return T_INTERVAL; + YY_BREAK +case 200: +YY_RULE_SETUP +#line 517 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_rightopen_interval,2); return T_INTERVAL; + YY_BREAK +case 201: +YY_RULE_SETUP +#line 518 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_leftrightopen_interval,2); return T_INTERVAL; + YY_BREAK +case 202: +YY_RULE_SETUP +#line 519 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_interval,2); return T_UNARY_OP; + YY_BREAK +case 203: +YY_RULE_SETUP +#line 520 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_limit,1); return T_UNARY_OP; + YY_BREAK +case 204: +YY_RULE_SETUP +#line 521 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sort,1); return T_UNARY_OP; + YY_BREAK +case 205: +YY_RULE_SETUP +#line 522 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_interval,2); return T_INTERVAL; + YY_BREAK +case 206: +YY_RULE_SETUP +#line 523 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_interval,2); return T_QUOTED_BINARY; + YY_BREAK +case 207: +YY_RULE_SETUP +#line 524 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_interval,2); return T_QUOTED_BINARY; + YY_BREAK +case 208: +YY_RULE_SETUP +#line 525 "input_lexer.ll" +if (xcas_mode(yyextra) || index_status(yyextra)) { (*yylval)=gen(at_factorial); return T_FACTORIAL; } else { index_status(yyextra)=0; (*yylval)=gen(at_not,1); return T_NOT; } + YY_BREAK +/* standard functions */ +case 209: +YY_RULE_SETUP +#line 528 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=symbolic(at_Ans,0); return T_LITERAL; + YY_BREAK +case 210: +YY_RULE_SETUP +#line 529 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_plus,2); return T_PLUS; + YY_BREAK +case 211: +YY_RULE_SETUP +#line 530 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_increment,1); return T_FACTORIAL; + YY_BREAK +case 212: +YY_RULE_SETUP +#line 531 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_increment,1); return T_UNION; + YY_BREAK +case 213: +YY_RULE_SETUP +#line 532 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_increment,1); return T_UNION; + YY_BREAK +case 214: +YY_RULE_SETUP +#line 533 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_powsto,1); return T_UNION; + YY_BREAK +case 215: +YY_RULE_SETUP +#line 534 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_powsto,1); return T_UNION; + YY_BREAK +case 216: +YY_RULE_SETUP +#line 535 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_decrement,1); return T_FACTORIAL; + YY_BREAK +case 217: +YY_RULE_SETUP +#line 536 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_decrement,1); return T_UNION; + YY_BREAK +case 218: +YY_RULE_SETUP +#line 537 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_decrement,1); return T_UNION; + YY_BREAK +case 219: +YY_RULE_SETUP +#line 538 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pointplus,2); return T_PLUS; + YY_BREAK +case 220: +YY_RULE_SETUP +#line 539 "input_lexer.ll" +index_status(yyextra)=0; if (python_compat(yyextra)) { (*yylval)=gen(at_bitand,2); return T_AND_OP; } else { *yylval=gen(at_plus,2); return T_PLUS; } + YY_BREAK +case 221: +YY_RULE_SETUP +#line 540 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_bitnot,1); return T_NOT; + YY_BREAK +case 222: +YY_RULE_SETUP +#line 541 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_sqrt,2); return T_NOT; + YY_BREAK +case 223: +YY_RULE_SETUP +#line 542 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_polar_complex,2); return T_MOD; + YY_BREAK +case 224: +YY_RULE_SETUP +#line 543 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=2; return T_SQ; + YY_BREAK +case 225: +YY_RULE_SETUP +#line 544 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=3; return T_SQ; + YY_BREAK +case 226: +YY_RULE_SETUP +#line 545 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=4; return T_SQ; + YY_BREAK +case 227: +YY_RULE_SETUP +#line 546 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=5; return T_SQ; + YY_BREAK +case 228: +YY_RULE_SETUP +#line 547 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=6; return T_SQ; + YY_BREAK +case 229: +YY_RULE_SETUP +#line 548 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=7; return T_SQ; + YY_BREAK +case 230: +YY_RULE_SETUP +#line 549 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=8; return T_SQ; + YY_BREAK +case 231: +YY_RULE_SETUP +#line 550 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=9; return T_SQ; + YY_BREAK +case 232: +YY_RULE_SETUP +#line 551 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=-1; return T_SQ; + YY_BREAK +case 233: +YY_RULE_SETUP +#line 552 "input_lexer.ll" +index_status(yyextra)=1; (*yylval)=-1; return T_SQ; + YY_BREAK +/* "','" index_status(yyextra)=0; (*yylval)=gen(at_makevector,2); return T_QUOTED_BINARY; commented because of f('a','b') */ +case 234: +YY_RULE_SETUP +#line 554 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_plus,2); return T_QUOTED_BINARY; + YY_BREAK +case 235: +YY_RULE_SETUP +#line 555 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_plus,2); return T_QUOTED_BINARY; + YY_BREAK +case 236: +YY_RULE_SETUP +#line 556 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_binary_minus,2); return T_MOINS; // return (calc_mode(yyextra)==38)?T_MOINS38:T_MOINS; + YY_BREAK +case 237: +YY_RULE_SETUP +#line 557 "input_lexer.ll" +index_status(yyextra)=0; if (calc_mode(yyextra)==38){ (*yylval)=gen(at_neg,2); return T_NEG38; } else { CERR << 1 << '\n'; (*yylval)=gen(at_binary_minus,2); return T_MOINS;} + YY_BREAK +case 238: +YY_RULE_SETUP +#line 558 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pointminus,2); return T_PLUS; + YY_BREAK +case 239: +YY_RULE_SETUP +#line 559 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_binary_minus,2); return T_QUOTED_BINARY; + YY_BREAK +case 240: +YY_RULE_SETUP +#line 560 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_binary_minus,2); return T_QUOTED_BINARY; + YY_BREAK +/* "ร—" index_status(yyextra)=0; (*yylval)=gen(at_prod,2); return T_FOIS; */ +/* "ยท" index_status(yyextra)=0; (*yylval)=gen(at_prod,2); return T_FOIS; */ +case 241: +YY_RULE_SETUP +#line 563 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_prod,2); return T_FOIS; + YY_BREAK +case 242: +YY_RULE_SETUP +#line 564 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_cross,2); return T_FOIS; + YY_BREAK +case 243: +YY_RULE_SETUP +#line 565 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_multcrement,1); return T_UNION; + YY_BREAK +case 244: +YY_RULE_SETUP +#line 566 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_multcrement,1); return T_UNION; + YY_BREAK +case 245: +YY_RULE_SETUP +#line 567 "input_lexer.ll" +index_status(yyextra)=0; if (abs_calc_mode(yyextra)==38){return T_DOUBLE_DEUX_POINTS; } else {(*yylval)=gen(at_struct_dot,2); return T_COMPOSE;} + YY_BREAK +case 246: +YY_RULE_SETUP +#line 568 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ampersand_times,2); return T_FOIS; + YY_BREAK +case 247: +YY_RULE_SETUP +#line 569 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_quote_pow,2); return T_POW; + YY_BREAK +case 248: +YY_RULE_SETUP +#line 570 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pointprod,2); return T_FOIS; + YY_BREAK +case 249: +YY_RULE_SETUP +#line 571 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_prod,2); return T_QUOTED_BINARY; + YY_BREAK +case 250: +YY_RULE_SETUP +#line 572 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_prod,2); return T_QUOTED_BINARY; + YY_BREAK +case 251: +YY_RULE_SETUP +#line 573 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_division,2); return T_DIV; + YY_BREAK +/* "รท" index_status(yyextra)=0; (*yylval)=gen(at_division,2); return T_DIV; */ +case 252: +YY_RULE_SETUP +#line 575 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_iquo,2); return T_DIV; + YY_BREAK +case 253: +YY_RULE_SETUP +#line 576 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_irem,2); return T_DIV; + YY_BREAK +case 254: +YY_RULE_SETUP +#line 577 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_iquosto,2); return T_UNION; + YY_BREAK +case 255: +YY_RULE_SETUP +#line 578 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_iremsto,2); return T_UNION; + YY_BREAK +case 256: +YY_RULE_SETUP +#line 579 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_andsto,2); return T_UNION; + YY_BREAK +case 257: +YY_RULE_SETUP +#line 580 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_orsto,2); return T_UNION; + YY_BREAK +case 258: +YY_RULE_SETUP +#line 581 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_xorsto,2); return T_UNION; + YY_BREAK +case 259: +YY_RULE_SETUP +#line 582 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_shiftsto,2); return T_UNION; + YY_BREAK +case 260: +YY_RULE_SETUP +#line 583 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_rotatesto,2); return T_UNION; + YY_BREAK +case 261: +YY_RULE_SETUP +#line 584 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_divcrement,1); return T_DIV; + YY_BREAK +case 262: +YY_RULE_SETUP +#line 585 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_divcrement,1); return T_UNION; + YY_BREAK +case 263: +YY_RULE_SETUP +#line 586 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pointdivision,2); return T_DIV; + YY_BREAK +case 264: +YY_RULE_SETUP +#line 587 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_division,2); return T_QUOTED_BINARY; + YY_BREAK +case 265: +YY_RULE_SETUP +#line 588 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_division,2); return T_QUOTED_BINARY; + YY_BREAK +case 266: +YY_RULE_SETUP +#line 589 "input_lexer.ll" +index_status(yyextra)=0; if (abs_calc_mode(yyextra)==38){ (*yylval)=gen(at_PERCENT); return T_UNARY_OP_38; } if (xcas_mode(yyextra)==3 || calc_mode(yyextra)==1) { (*yylval)=gen(at_pourcent); return T_FACTORIAL; } if (xcas_mode(yyextra)==1) { (*yylval)=symbolic(at_ans,vecteur(0)); return T_NUMBER; } if (xcas_mode(yyextra) || python_compat(yyextra)) (*yylval)=gen(at_irem,2); else (*yylval)=0; return T_MOD; + YY_BREAK +case 267: +YY_RULE_SETUP +#line 590 "input_lexer.ll" +index_status(yyextra)=0; if (xcas_mode(yyextra)==0){ (*yylval)=gen(at_iquorem,2); return T_MOD;} (*yylval)=symbolic(at_ans,-2); return T_NUMBER; + YY_BREAK +/* \xe2\x88\xa1 index_status(yyextra)=0; (*yylval)=gen(at_polar_complex,2); return T_MOD; */ +case 268: +YY_RULE_SETUP +#line 592 "input_lexer.ll" +if (xcas_mode(yyextra)==0){ (*yylval)=gen(at_quorem,2); return T_MOD;} index_status(yyextra)=0; (*yylval)=symbolic(at_ans,-3); return T_NUMBER; + YY_BREAK +case 269: +YY_RULE_SETUP +#line 593 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_irem,2); return T_QUOTED_BINARY; + YY_BREAK +case 270: +YY_RULE_SETUP +#line 594 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_equal2,2); return T_QUOTED_BINARY; + YY_BREAK +case 271: +YY_RULE_SETUP +#line 595 "input_lexer.ll" +index_status(yyextra)=0; if (xcas_mode(yyextra)==3) { (*yylval)=gen(at_irem,2); return T_UNARY_OP; } else { if (xcas_mode(yyextra)) (*yylval)=gen(at_irem,2); else (*yylval)=0; return T_MOD; } + YY_BREAK +case 272: +YY_RULE_SETUP +#line 596 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_irem,2); return T_QUOTED_BINARY; + YY_BREAK +case 273: +YY_RULE_SETUP +#line 597 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_irem,2); return T_QUOTED_BINARY; + YY_BREAK +/* "MOD" index_status(yyextra)=0; return T_MOD; */ +case 274: +YY_RULE_SETUP +#line 599 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(python_compat(yyextra)==2?at_bitxor:at_pow,2); return T_POW; + YY_BREAK +case 275: +YY_RULE_SETUP +#line 600 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_trn,1); return T_FACTORIAL; + YY_BREAK +case 276: +YY_RULE_SETUP +#line 601 "input_lexer.ll" +(*yylval) = gen(at_pow,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 277: +YY_RULE_SETUP +#line 602 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pow,2); return T_POW; + YY_BREAK +case 278: +YY_RULE_SETUP +#line 603 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pointpow,2); return T_POW; + YY_BREAK +case 279: +YY_RULE_SETUP +#line 604 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pow,2); return T_QUOTED_BINARY; + YY_BREAK +case 280: +YY_RULE_SETUP +#line 605 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_pow,2); return T_QUOTED_BINARY; + YY_BREAK +case 281: +YY_RULE_SETUP +#line 606 "input_lexer.ll" +(*yylval) = gen(at_Digits,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 282: +YY_RULE_SETUP +#line 607 "input_lexer.ll" +(*yylval) = gen(at_HDigits,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 283: +YY_RULE_SETUP +#line 608 "input_lexer.ll" +(*yylval) = gen(at_HAngle,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 284: +YY_RULE_SETUP +#line 609 "input_lexer.ll" +(*yylval) = gen(at_HFormat,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 285: +YY_RULE_SETUP +#line 610 "input_lexer.ll" +(*yylval) = gen(at_HComplex,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 286: +YY_RULE_SETUP +#line 611 "input_lexer.ll" +(*yylval) = gen(at_HLanguage,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 287: +YY_RULE_SETUP +#line 612 "input_lexer.ll" +(*yylval) = gen(at_Digits,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 288: +YY_RULE_SETUP +#line 613 "input_lexer.ll" +(*yylval) = gen(at_threads,0) ; index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 289: +YY_RULE_SETUP +#line 614 "input_lexer.ll" +(*yylval) = gen(at_scientific_format,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 290: +YY_RULE_SETUP +#line 615 "input_lexer.ll" +(*yylval) = gen(at_angle_radian,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 291: +YY_RULE_SETUP +#line 616 "input_lexer.ll" +(*yylval) = gen(at_approx_mode,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 292: +YY_RULE_SETUP +#line 617 "input_lexer.ll" +(*yylval) = gen(at_all_trig_solutions,1); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 293: +YY_RULE_SETUP +#line 618 "input_lexer.ll" +(*yylval) = gen(at_increasing_power,1); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 294: +YY_RULE_SETUP +#line 619 "input_lexer.ll" +(*yylval) = gen(at_ntl_on,1); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 295: +YY_RULE_SETUP +#line 620 "input_lexer.ll" +(*yylval) = gen(at_complex_mode,1); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 296: +YY_RULE_SETUP +#line 621 "input_lexer.ll" +(*yylval) = gen(at_step_infolevel,1); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 297: +YY_RULE_SETUP +#line 622 "input_lexer.ll" +(*yylval) = gen(at_keep_algext,1); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 298: +YY_RULE_SETUP +#line 623 "input_lexer.ll" +(*yylval) = gen(at_complex_variables,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 299: +YY_RULE_SETUP +#line 624 "input_lexer.ll" +(*yylval) = gen(at_epsilon,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 300: +YY_RULE_SETUP +#line 625 "input_lexer.ll" +(*yylval) = gen(at_proba_epsilon,0); index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 301: +YY_RULE_SETUP +#line 627 "input_lexer.ll" +(*yylval) = gen(at_acos,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 302: +YY_RULE_SETUP +#line 628 "input_lexer.ll" +(*yylval) = gen(at_randNorm,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 303: +YY_RULE_SETUP +#line 629 "input_lexer.ll" +(*yylval) = gen(at_acosh,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 304: +YY_RULE_SETUP +#line 630 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_args,0); return T_QUOTED_BINARY; + YY_BREAK +case 305: +YY_RULE_SETUP +#line 631 "input_lexer.ll" +(*yylval) = gen(at_asin,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 306: +YY_RULE_SETUP +#line 632 "input_lexer.ll" +(*yylval) = gen(at_asinh,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 307: +YY_RULE_SETUP +#line 633 "input_lexer.ll" +(*yylval) = gen(at_at,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 308: +YY_RULE_SETUP +#line 634 "input_lexer.ll" +(*yylval) = gen(at_atan,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 309: +YY_RULE_SETUP +#line 635 "input_lexer.ll" +(*yylval) = gen(at_atanh,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 310: +YY_RULE_SETUP +#line 636 "input_lexer.ll" +(*yylval) = gen(at_backquote,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 311: +YY_RULE_SETUP +#line 637 "input_lexer.ll" +(*yylval) = gen(at_bloc,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 312: +YY_RULE_SETUP +#line 638 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_break,0); return T_BREAK; + YY_BREAK +case 313: +YY_RULE_SETUP +#line 639 "input_lexer.ll" +index_status(yyextra)=0; if (abs_calc_mode(yyextra)==38) return T_CASE38; else return T_CASE; + YY_BREAK +case 314: +YY_RULE_SETUP +#line 640 "input_lexer.ll" +(*yylval) = gen(at_cont,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 315: +YY_RULE_SETUP +#line 641 "input_lexer.ll" +(*yylval) = gen(at_debug,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 316: +YY_RULE_SETUP +#line 642 "input_lexer.ll" +(*yylval) = gen(at_derive,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 317: +YY_RULE_SETUP +#line 643 "input_lexer.ll" +if (xcas_mode(yyextra)==1 || xcas_mode(yyextra)==2) { (*yylval) = gen(at_function_diff,1); index_status(yyextra)=1; return T_UNARY_OP;} else { index_status(yyextra)=1; return find_or_make_symbol(yytext,(*yylval),yyscanner,true,yyextra); } + YY_BREAK +case 318: +YY_RULE_SETUP +#line 644 "input_lexer.ll" +if (xcas_mode(yyextra)==1 || xcas_mode(yyextra)==2 || parse_e(yyextra)) { (*yylval)=e__IDNT_e; }else (*yylval)=symbolic(at_exp,1); index_status(yyextra)=1; return T_NUMBER; + YY_BREAK +case 319: +YY_RULE_SETUP +#line 645 "input_lexer.ll" +(*yylval)=symbolic(at_exp,1); index_status(yyextra)=1; return T_NUMBER; + YY_BREAK +case 320: +YY_RULE_SETUP +#line 646 "input_lexer.ll" +(*yylval)=symbolic(at_exp,1); index_status(yyextra)=1; return T_NUMBER; + YY_BREAK +case 321: +YY_RULE_SETUP +#line 647 "input_lexer.ll" +(*yylval) = gen(at_equal,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 322: +YY_RULE_SETUP +#line 648 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_throw,1); return T_RETURN; + YY_BREAK +case 323: +YY_RULE_SETUP +#line 649 "input_lexer.ll" +(*yylval) = gen(at_erase,0); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 324: +YY_RULE_SETUP +#line 650 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_throw,1); return T_RETURN; + YY_BREAK +case 325: +YY_RULE_SETUP +#line 651 "input_lexer.ll" +if (xcas_mode(yyextra)==3) (*yylval)=gen(at_partfrac); else (*yylval) = gen(at_expand,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 326: +YY_RULE_SETUP +#line 652 "input_lexer.ll" +(*yylval) = gen(at_insmod,1); index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 327: +YY_RULE_SETUP +#line 653 "input_lexer.ll" +(*yylval) = gen(at_expand,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 328: +YY_RULE_SETUP +#line 654 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,4); return T_FOR; + YY_BREAK +case 329: +YY_RULE_SETUP +#line 655 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,4); return T_FOR; + YY_BREAK +case 330: +YY_RULE_SETUP +#line 656 "input_lexer.ll" +(*yylval) = gen(at_halt,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 331: +YY_RULE_SETUP +#line 657 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=4; return T_BLOC_END; + YY_BREAK +case 332: +YY_RULE_SETUP +#line 658 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=9; return T_BLOC_END; + YY_BREAK +case 333: +YY_RULE_SETUP +#line 659 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=3; return T_BLOC_END; + YY_BREAK +case 334: +YY_RULE_SETUP +#line 660 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ifte,3); return T_IF; + YY_BREAK +case 335: +YY_RULE_SETUP +#line 661 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ifte,3); if (rpn_mode(yyextra)) return T_RPN_IF; return T_IF; + YY_BREAK +case 336: +YY_RULE_SETUP +#line 662 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ifte,3); return T_IFTE; + YY_BREAK +case 337: +YY_RULE_SETUP +#line 663 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_when,3); return T_IFTE; + YY_BREAK +case 338: +YY_RULE_SETUP +#line 664 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ifte,3); return T_QUOTED_BINARY; + YY_BREAK +case 339: +YY_RULE_SETUP +#line 665 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ifte,3); return T_QUOTED_BINARY; + YY_BREAK +case 340: +YY_RULE_SETUP +#line 666 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ifte,3); return T_QUOTED_BINARY; + YY_BREAK +case 341: +YY_RULE_SETUP +#line 667 "input_lexer.ll" +if (xcas_mode(yyextra)==1) (*yylval) = gen(at_maple_ifactors); else (*yylval) = gen(at_ifactors,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 342: +YY_RULE_SETUP +#line 668 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_intersect,2); return T_QUOTED_BINARY; + YY_BREAK +case 343: +YY_RULE_SETUP +#line 669 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_intersect,2); return T_QUOTED_BINARY; + YY_BREAK +case 344: +YY_RULE_SETUP +#line 670 "input_lexer.ll" +(*yylval) = gen(at_kill,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 345: +YY_RULE_SETUP +#line 671 "input_lexer.ll" +(*yylval) = gen(at_log,1); index_status(yyextra)=1; return T_UNARY_OP; /* index_status(yyextra)=1 to accept log[] for a basis log */ + YY_BREAK +case 346: +YY_RULE_SETUP +#line 672 "input_lexer.ll" +(*yylval) = gen(at_asin,1); index_status(yyextra)=1; return T_UNARY_OP; + YY_BREAK +case 347: +YY_RULE_SETUP +#line 673 "input_lexer.ll" +(*yylval) = gen(at_acos,1); index_status(yyextra)=1; return T_UNARY_OP; + YY_BREAK +case 348: +YY_RULE_SETUP +#line 674 "input_lexer.ll" +(*yylval) = gen(at_atan,1); index_status(yyextra)=1; return T_UNARY_OP; + YY_BREAK +case 349: +YY_RULE_SETUP +#line 675 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_minus,2); return T_QUOTED_BINARY; + YY_BREAK +case 350: +YY_RULE_SETUP +#line 676 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_minus,2); return T_QUOTED_BINARY; + YY_BREAK +case 351: +YY_RULE_SETUP +#line 677 "input_lexer.ll" +(*yylval) = gen(at_not,1); if (xcas_mode(yyextra) || python_compat(yyextra)) return T_NOT; index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 352: +YY_RULE_SETUP +#line 678 "input_lexer.ll" +(*yylval) = gen(at_not,1); return T_NOT; + YY_BREAK +case 353: +YY_RULE_SETUP +#line 679 "input_lexer.ll" +(*yylval) = gen(at_not,1); return T_IN; + YY_BREAK +case 354: +YY_RULE_SETUP +#line 680 "input_lexer.ll" +(*yylval) = gen(at_neg,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 355: +YY_RULE_SETUP +#line 681 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_not,1); return T_QUOTED_BINARY; + YY_BREAK +case 356: +YY_RULE_SETUP +#line 682 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_not,1); return T_QUOTED_BINARY; + YY_BREAK +case 357: +YY_RULE_SETUP +#line 683 "input_lexer.ll" +(*yylval) = gen(at_greduce,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 358: +YY_RULE_SETUP +#line 684 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_of,2); return T_QUOTED_BINARY; + YY_BREAK +case 359: +YY_RULE_SETUP +#line 685 "input_lexer.ll" +if (xcas_mode(yyextra)==1) (*yylval) = gen(at_maple_op,1); else (*yylval) = gen(at_feuille,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 360: +YY_RULE_SETUP +#line 686 "input_lexer.ll" +(*yylval) = gen(at_feuille,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 361: +YY_RULE_SETUP +#line 687 "input_lexer.ll" +(*yylval)=2; index_status(yyextra)=0; return T_LOCAL; + YY_BREAK +case 362: +YY_RULE_SETUP +#line 688 "input_lexer.ll" +(*yylval) = gen(at_pcoeff,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 363: +YY_RULE_SETUP +#line 689 "input_lexer.ll" +(*yylval) = gen(at_funcplot,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 364: +YY_RULE_SETUP +#line 690 "input_lexer.ll" +(*yylval) = gen(at_user_operator,6); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 365: +YY_RULE_SETUP +#line 691 "input_lexer.ll" +if (rpn_mode(yyextra)) {(*yylval)=gen(at_purge,0); index_status(yyextra)=0; return T_RPN_OP;} else {(*yylval) = gen(at_purge,1); index_status(yyextra)=0; return T_UNARY_OP;}; + YY_BREAK +case 366: +YY_RULE_SETUP +#line 692 "input_lexer.ll" +if (rpn_mode(yyextra)) {(*yylval)=gen(at_purge,0); index_status(yyextra)=0; return T_RPN_OP;} else {(*yylval) = gen(at_purge,1); index_status(yyextra)=0; return T_UNARY_OP;}; + YY_BREAK +case 367: +YY_RULE_SETUP +#line 693 "input_lexer.ll" +if (rpn_mode(yyextra)) {(*yylval)=gen(at_purge,0); index_status(yyextra)=0; return T_RPN_OP;} else {(*yylval) = gen(at_purge,1); index_status(yyextra)=0; return T_UNARY_OP;}; + YY_BREAK +case 368: +YY_RULE_SETUP +#line 694 "input_lexer.ll" +(*yylval) = gen(at_srand,1); index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 369: +YY_RULE_SETUP +#line 695 "input_lexer.ll" +(*yylval) = gen(at_for,1) ; index_status(yyextra)=0; return T_REPEAT; + YY_BREAK +case 370: +YY_RULE_SETUP +#line 696 "input_lexer.ll" +(*yylval) = gen(at_for,1) ; index_status(yyextra)=0; return T_REPEAT; + YY_BREAK +case 371: +YY_RULE_SETUP +#line 697 "input_lexer.ll" +(*yylval) = gen(at_for,1) ;index_status(yyextra)=0; return T_REPEAT; + YY_BREAK +case 372: +YY_RULE_SETUP +#line 698 "input_lexer.ll" +(*yylval) = gen(at_return,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 373: +YY_RULE_SETUP +#line 699 "input_lexer.ll" +(*yylval) = gen(at_return,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 374: +YY_RULE_SETUP +#line 700 "input_lexer.ll" +(*yylval) = gen(at_return,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 375: +YY_RULE_SETUP +#line 701 "input_lexer.ll" +(*yylval) = gen(at_return,1) ; index_status(yyextra)=0; return T_QUOTED_BINARY; + YY_BREAK +case 376: +YY_RULE_SETUP +#line 702 "input_lexer.ll" +(*yylval) = gen(at_maple_root,1); index_status(yyextra)=1; return T_UNARY_OP; + YY_BREAK +case 377: +YY_RULE_SETUP +#line 703 "input_lexer.ll" +(*yylval) = gen(at_same,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 378: +YY_RULE_SETUP +#line 704 "input_lexer.ll" +(*yylval) = gen(at_sst,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 379: +YY_RULE_SETUP +#line 705 "input_lexer.ll" +(*yylval) = gen(at_sst_in,1); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 380: +YY_RULE_SETUP +#line 706 "input_lexer.ll" +if (xcas_mode(yyextra)==1) (*yylval) = gen(at_maple_subs,2); else (*yylval) = gen(at_subs,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 381: +YY_RULE_SETUP +#line 707 "input_lexer.ll" +if (xcas_mode(yyextra)==1) (*yylval) = gen(at_maple_subsop,2); else (*yylval) = gen(at_subsop,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 382: +YY_RULE_SETUP +#line 708 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_union,2); return T_QUOTED_BINARY; + YY_BREAK +case 383: +YY_RULE_SETUP +#line 709 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_union,2); return T_QUOTED_BINARY; + YY_BREAK +case 384: +YY_RULE_SETUP +#line 710 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_symmetric_difference,2); return T_QUOTED_BINARY; + YY_BREAK +case 385: +YY_RULE_SETUP +#line 711 "input_lexer.ll" +(*yylval) = gen(at_virgule,2); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 386: +YY_RULE_SETUP +#line 712 "input_lexer.ll" +(*yylval) = gen(at_VARS,0); index_status(yyextra)=0; return T_UNARY_OP; + YY_BREAK +case 387: +YY_RULE_SETUP +#line 713 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,4); if (xcas_mode(yyextra)==3) return TI_WHILE; if (xcas_mode(yyextra)!=0) return T_MUPMAP_WHILE; return T_WHILE; + YY_BREAK +case 388: +YY_RULE_SETUP +#line 714 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,4); return T_MUPMAP_WHILE; /* return T_RPN_WHILE; */ + YY_BREAK +case 389: +YY_RULE_SETUP +#line 715 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,4); return T_DO; /* must be here for DO ... END loop */ + YY_BREAK +case 390: +YY_RULE_SETUP +#line 716 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,4); return T_DO; /* must be here for DO ... END loop */ + YY_BREAK +case 391: +YY_RULE_SETUP +#line 717 "input_lexer.ll" +(*yylval) = gen(at_Text,1); index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 392: +YY_RULE_SETUP +#line 718 "input_lexer.ll" +(*yylval) = gen(at_DropDown,1); index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 393: +YY_RULE_SETUP +#line 719 "input_lexer.ll" +(*yylval) = gen(at_Popup,1); index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 394: +YY_RULE_SETUP +#line 720 "input_lexer.ll" +(*yylval) = gen(at_Request,1); index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 395: +YY_RULE_SETUP +#line 721 "input_lexer.ll" +(*yylval) = gen(at_Title,1); index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 396: +YY_RULE_SETUP +#line 722 "input_lexer.ll" +(*yylval)=0; index_status(yyextra)=0; return TI_PRGM; + YY_BREAK +case 397: +YY_RULE_SETUP +#line 723 "input_lexer.ll" +(*yylval)=0; index_status(yyextra)=0; return TI_PRGM; + YY_BREAK +case 398: +YY_RULE_SETUP +#line 724 "input_lexer.ll" +(*yylval)=0; index_status(yyextra)=0; return TI_PRGM; + YY_BREAK +case 399: +YY_RULE_SETUP +#line 725 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_ifte,3); return T_IF; + YY_BREAK +case 400: +YY_RULE_SETUP +#line 726 "input_lexer.ll" +(*yylval) = gen(at_return,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 401: +YY_RULE_SETUP +#line 727 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_breakpoint,0); return T_BREAK; + YY_BREAK +case 402: +YY_RULE_SETUP +#line 728 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,0); return TI_LOOP; + YY_BREAK +case 403: +YY_RULE_SETUP +#line 729 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,0); return TI_FOR; + YY_BREAK +case 404: +YY_RULE_SETUP +#line 730 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,0); return TI_WHILE; + YY_BREAK +case 405: +YY_RULE_SETUP +#line 731 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_for,0); return T_CONTINUE; + YY_BREAK +case 406: +YY_RULE_SETUP +#line 732 "input_lexer.ll" +(*yylval) = gen(at_print,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 407: +YY_RULE_SETUP +#line 733 "input_lexer.ll" +(*yylval) = gen(at_Pause,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 408: +YY_RULE_SETUP +#line 734 "input_lexer.ll" +(*yylval) = gen(at_label,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 409: +YY_RULE_SETUP +#line 735 "input_lexer.ll" +(*yylval) = gen(at_goto,1) ; index_status(yyextra)=0; return T_RETURN; + YY_BREAK +case 410: +YY_RULE_SETUP +#line 736 "input_lexer.ll" +(*yylval) = gen(at_Dialog,1) ; index_status(yyextra)=0; return TI_DIALOG; + YY_BREAK +case 411: +YY_RULE_SETUP +#line 737 "input_lexer.ll" +(*yylval) = gen(at_Row,0) ; index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 412: +YY_RULE_SETUP +#line 738 "input_lexer.ll" +(*yylval) = gen(at_Col,0) ; index_status(yyextra)=0; return T_DIGITS; + YY_BREAK +case 413: +YY_RULE_SETUP +#line 740 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_DELTALIST); return T_UNARY_OP_38; + YY_BREAK +case 414: +YY_RULE_SETUP +#line 741 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_PILIST); return T_UNARY_OP_38; + YY_BREAK +case 415: +YY_RULE_SETUP +#line 742 "input_lexer.ll" +index_status(yyextra)=0;(*yylval)=gen(at_HPSUM); return T_UNARY_OP_38; + YY_BREAK +case 416: +YY_RULE_SETUP +#line 743 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_SIGMALIST); return T_UNARY_OP_38; + YY_BREAK +case 417: +YY_RULE_SETUP +#line 744 "input_lexer.ll" +index_status(yyextra)=0;(*yylval)=gen(at_HPDIFF); return T_UNARY_OP_38; + YY_BREAK +case 418: +YY_RULE_SETUP +#line 745 "input_lexer.ll" +index_status(yyextra)=0;(*yylval)=gen(at_HPINT); return T_UNARY_OP_38; + YY_BREAK +case 419: +YY_RULE_SETUP +#line 746 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_inferieur_egal,2); return T_TEST_EQUAL; + YY_BREAK +case 420: +YY_RULE_SETUP +#line 747 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_different,2); return T_TEST_EQUAL; + YY_BREAK +case 421: +YY_RULE_SETUP +#line 748 "input_lexer.ll" +index_status(yyextra)=0; (*yylval)=gen(at_superieur_egal,2); return T_TEST_EQUAL; + YY_BREAK +case 422: +YY_RULE_SETUP +#line 749 "input_lexer.ll" +index_status(yyextra)=0;(*yylval)=gen(at_product); return T_UNARY_OP; + YY_BREAK +/* old format for physical constants +"_hbar_" (*yylval) = symbolic(at_unit,makevecteur(1.05457266e-34,_J_unit*_s_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_c_" (*yylval) = symbolic(at_unit,makevecteur(299792458,_m_unit/_s_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_g_" (*yylval) = symbolic(at_unit,makevecteur(9.80665,_m_unit*unitpow(_s_unit,-2))); index_status(yyextra)=0; return T_SYMBOL; +"_IO_" (*yylval) = symbolic(at_unit,makevecteur(1e-12,_W_unit*unitpow(_m_unit,-2))); index_status(yyextra)=0; return T_SYMBOL; +"_epsilonox_" (*yylval) = 3.9; index_status(yyextra)=0; return T_SYMBOL; +"_epsilonsi_" (*yylval) = 11.9; index_status(yyextra)=0; return T_SYMBOL; +"_qepsilon0_" (*yylval) = symbolic(at_unit,makevecteur(1.4185979e-30,_F_unit*_C_unit/_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_epsilon0q_" (*yylval) = symbolic(at_unit,makevecteur(55263469.6,_F_unit/(_m_unit*_C_unit))); index_status(yyextra)=0; return T_SYMBOL; +"_kq_" (*yylval) = symbolic(at_unit,makevecteur(8.617386e-5,_J_unit/(_K_unit*_C_unit))); index_status(yyextra)=0; return T_SYMBOL; +"_c3_" (*yylval) = symbolic(at_unit,makevecteur(.002897756,_m_unit*_K_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_lambdac_" (*yylval) = symbolic(at_unit,makevecteur( 0.00242631058e-9,_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_f0_" (*yylval) = symbolic(at_unit,makevecteur(2.4179883e14,_Hz_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_lambda0_" (*yylval) = symbolic(at_unit,makevecteur(1239.8425e-9,_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_muN_" (*yylval) = symbolic(at_unit,makevecteur(5.0507866e-27,_J_unit/_T_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_muB_" (*yylval) = symbolic(at_unit,makevecteur( 9.2740154e-24,_J_unit/_T_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_a0_" (*yylval) = symbolic(at_unit,makevecteur(.0529177249e-9,_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_Rinfinity_" (*yylval) = symbolic(at_unit,makevecteur(10973731.534,unitpow(_m_unit,-1))); index_status(yyextra)=0; return T_SYMBOL; +"_Faraday_" (*yylval) = symbolic(at_unit,makevecteur(96485.309,_C_unit/_mol_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_phi_" (*yylval) = symbolic(at_unit,makevecteur(2.06783461e-15,_Wb_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_alpha_" (*yylval) = 7.29735308e-3; index_status(yyextra)=0; return T_SYMBOL; +"_mpme_" (*yylval) = 1836.152701; index_status(yyextra)=0; return T_SYMBOL; +"_mp_" (*yylval) = symbolic(at_unit,makevecteur(1.6726231e-27,_kg_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_qme_" (*yylval) = symbolic(at_unit,makevecteur(1.75881962e11,_C_unit/_kg_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_me_" (*yylval) = symbolic(at_unit,makevecteur(9.1093897e-31,_kg_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_qe_" (*yylval) = symbolic(at_unit,makevecteur(1.60217733e-19,_C_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_h_" (*yylval) = symbolic(at_unit,makevecteur(6.6260755e-34,_J_unit*_s_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_G_" (*yylval) = symbolic(at_unit,makevecteur(6.67408e-11,unitpow(_m_unit,3)*unitpow(_s_unit,-2)*unitpow(_kg_unit,-1))); index_status(yyextra)=0; return T_SYMBOL; +"_mu0_" (*yylval) = symbolic(at_unit,makevecteur(1.25663706144e-6,_H_unit/_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_epsilon0_" (*yylval) = symbolic(at_unit,makevecteur(8.85418781761e-12,_F_unit/_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_sigma_" (*yylval) = symbolic(at_unit,makevecteur( 5.67051e-8,_W_unit*unitpow(_m_unit,-2)*unitpow(_K_unit,-4))); index_status(yyextra)=0; return T_SYMBOL; +"_StdP_" (*yylval) = symbolic(at_unit,makevecteur(101325.0,_Pa_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_StdT_" (*yylval) = symbolic(at_unit,makevecteur(273.15,_K_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_R_" (*yylval) = symbolic(at_unit,makevecteur(8.31451,_J_unit/_molK_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_Vm_" (*yylval) = symbolic(at_unit,makevecteur(22.4141,_l_unit/_mol_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_k_" (*yylval) = symbolic(at_unit,makevecteur(1.380658e-23,_J_unit/_K_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_NA_" (*yylval) = symbolic(at_unit,makevecteur(6.0221367e23,unitpow(_mol_unit,-1))); index_status(yyextra)=0; return T_SYMBOL; +"_mSun_" (*yylval) = symbolic(at_unit,makevecteur(1.989e30,_kg_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_RSun_" (*yylval) = symbolic(at_unit,makevecteur(6.955e8,_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_PSun_" (*yylval) = symbolic(at_unit,makevecteur(3.846e26,_W_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_mEarth_" (*yylval) = symbolic(at_unit,makevecteur(5.9736e24,_kg_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_REarth_" (*yylval) = symbolic(at_unit,makevecteur(6.371e6,_m_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_sd_" (*yylval) = symbolic(at_unit,makevecteur(8.61640905e4,_s_unit)); index_status(yyextra)=0; return T_SYMBOL; +"_syr_" (*yylval) = symbolic(at_unit,makevecteur(3.15581498e7,_s_unit)); index_status(yyextra)=0; return T_SYMBOL; + */ +/* numbers, also accept DMS e.g 1ยฐ15โ€ฒ27โ€ณ13 */ +case 423: +#line 797 "input_lexer.ll" +case 424: +#line 798 "input_lexer.ll" +case 425: +#line 799 "input_lexer.ll" +case 426: +#line 800 "input_lexer.ll" +case 427: +#line 801 "input_lexer.ll" +case 428: +#line 802 "input_lexer.ll" +case 429: +#line 803 "input_lexer.ll" +case 430: +#line 804 "input_lexer.ll" +case 431: +#line 805 "input_lexer.ll" +case 432: +#line 806 "input_lexer.ll" +case 433: +#line 807 "input_lexer.ll" +case 434: +#line 808 "input_lexer.ll" +case 435: +#line 809 "input_lexer.ll" +case 436: +#line 810 "input_lexer.ll" +case 437: +#line 811 "input_lexer.ll" +case 438: +#line 812 "input_lexer.ll" +case 439: +#line 813 "input_lexer.ll" +case 440: +#line 814 "input_lexer.ll" +case 441: +#line 815 "input_lexer.ll" +case 442: +#line 816 "input_lexer.ll" +case 443: +#line 817 "input_lexer.ll" +case 444: +#line 818 "input_lexer.ll" +case 445: +#line 819 "input_lexer.ll" +case 446: +#line 820 "input_lexer.ll" +case 447: +YY_RULE_SETUP +#line 820 "input_lexer.ll" +{ + index_status(yyextra)=1; + int l=strlen(yytext); + int interv=0; // set to non-zero if ? in the number + int dot=-1; + for (int i=0;i=0 && interv>1){ + --interv; // interv is the relative precision of the interval + if (interv && dot>=1 && yytext[dot-1]=='0') + --interv; + ++dot; + while (interv && dot2 && yytext[1]!='x' && (yytext[l-1]=='o' || yytext[l-1]=='b' || yytext[l-1]=='h') ){ + char base=yytext[l-1]; + for (int i=l-1;i>1;--i){ + yytext[i]=yytext[i-1]; + } + if (base=='h') + base='x'; + yytext[1]=base; + } + else { + for (l=0;(ch=*(yytext+l));++l){ + if (ch=='x') + break; + if (ch=='e' || ch=='E'){ + if ( (ch2=*(yytext+l+1)) && (ch2=='e' || ch2=='E')){ + ++l; + for (;(ch=*(yytext+l));++l) + *(yytext+l-1)=ch; + *(yytext+l-1)=0; + --l; + } + } +#ifndef BCD + if ( (ch==-30 && *(yytext+l+1)==-128) || (ch==-62 && *(yytext+l+1)==-80) ){ + *yylval=0; return T_NUMBER; + } +#endif + if (ch==-30 && *(yytext+l+1)==-120 && *(yytext+l+2)==-110){ + l += 3; + for (;(ch=*(yytext+l));++l) + *(yytext+l-2)=ch; + *(yytext+l-2)=0; + l -= 3; + *(yytext+l)='-'; + } + } + } + (*yylval) = chartab2gen(yytext,yyextra); + if (interv){ + double d=evalf_double(*yylval,1,context0)._DOUBLE_val; + if (d<0 && interv>1) + --interv; + double tmp=std::floor(std::log(absdouble(d))/std::log(10.0)); + tmp=(std::pow(10.,1+tmp-interv)); + *yylval=eval(gen(makevecteur(d-tmp,d+tmp),_INTERVAL__VECT),1,context0); + } + return T_NUMBER; +} + YY_BREAK +/* UNITS +"_"{A}{AN}* { + std::pair pp=equal_range(unitname_tab,unitname_tab_end,yytext,tri2); + if (pp.first!=pp.second && pp.second!=unitname_tab_end){ + gen tmp=mksa_register_unit(*pp.first,unitptr_tab[pp.first-unitname_tab]); + (*yylval)=tmp; + index_status(yyextra)=0; + return T_SYMBOL; + } + int res=find_or_make_symbol(yytext+1,(*yylval),yyscanner,false,yyextra); + (*yylval)=symb_unit(1,(*yylval),yyextra); + return res; +} + */ +/* symbols */ +case 448: +#line 913 "input_lexer.ll" +case 449: +YY_RULE_SETUP +#line 913 "input_lexer.ll" +{ + index_status(yyextra)=1; + int res=find_or_make_symbol(yytext,(*yylval),yyscanner,true,yyextra); + if (res==T_NUMBER) + *yylval=(*yylval)(string2gen(unlocalize(yytext),false),yyextra); + return res; +} + YY_BREAK +case 450: +YY_RULE_SETUP +#line 920 "input_lexer.ll" +if (!xcas_mode(yyextra) || xcas_mode(yyextra)==3) { + // CERR << "hash" << '\n'; + (*yylval)=gen(at_hash,1); return TI_HASH; +} else BEGIN(comment_hash); + YY_BREAK +case 451: +/* rule 451 can match eol */ +YY_RULE_SETUP +#line 924 "input_lexer.ll" +BEGIN(INITIAL); index_status(yyextra)=0; increment_lexer_line_number_setcol(yyscanner,yyextra); /* comment_s(yyextra)=string(yytext); (*yylval)=string2gen(comment_s(yyextra).substr(0,comment_s(yyextra).size()-1),false); return T_COMMENT; */ + YY_BREAK +/* everything else */ +case 452: +YY_RULE_SETUP +#line 926 "input_lexer.ll" +(*yylval)=string2gen(string(yytext),false); return T_STRING; + YY_BREAK +case 453: +YY_RULE_SETUP +#line 928 "input_lexer.ll" +ECHO; + YY_BREAK +#line 4599 "input_lexer.cc" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(comment): +case YY_STATE_EOF(comment_hash): +case YY_STATE_EOF(str): +case YY_STATE_EOF(backquote): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1428 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1428 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 1427); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) +{ + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = yyg->yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 928 "input_lexer.ll" + + +/* + * Routines + */ +#ifndef NO_NAMESPACE_GIAC + namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + bool tri (const std::pair & a ,const std::pair & b){ + return strcmp(a.first, b.first) < 0; + } + + // Set the input string + // export GIAC_DEBUG=-2 to renew static_lexer.h/static_extern.h + YY_BUFFER_STATE set_lexer_string(const std::string &s_orig,yyscan_t & scanner,GIAC_CONTEXT){ +#if 0 +#ifdef NSPIRE + FILE * f= fopen("/documents/log.tns","w"); // ends up in My Documents + fprintf(f,"%s",s_orig.c_str()); + fclose(f); +#else + ofstream of("log"); // ends up in fir/windows/log + of << s_orig<< '\n'; +#endif +#endif + if (abs_calc_mode(contextptr)==38 && s_orig==string(s_orig.size(),' ')) + giac_yyerror(scanner,"Void string"); +#if !defined RTOS_THREADX && !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 && !defined NSPIRE_NEWLIB // && !defined NUMWORKS + if (!builtin_lexer_functions_sorted){ +#ifndef STATIC_BUILTIN_LEXER_FUNCTIONS + sort(builtin_lexer_functions_begin(),builtin_lexer_functions_end(),tri); +#endif + builtin_lexer_functions_sorted=true; + int nfunc=builtin_lexer_functions_number; + if (debug_infolevel==-2 || debug_infolevel==-4 || debug_infolevel==-5){ + CERR << "Writing " << nfunc << " in static_lexer.h and static_extern.h "<< '\n'; + CERR << "Check at_FP->at_FRAC, at_IP->at_INT, at_lgamma->at_lower_incomplete_gamma, at_is_inside->at_est_dans, at_regroup->at_regrouper, at_ugamma->at_upper_incomplete_gamma, at_โˆก -> at_polar_complex, at_LINEAR? -> at_IS_LINEAR" << '\n'; + /* + ofstream static_add_ll("static_add.ll"); + for (int i=0;iquoted()) + static_lexer << "| 1"; + static_lexer << "}" ; + if (i!=nfunc-1) + static_lexer << ","; + static_lexer << '\n'; + } + static_lexer.close(); + if (debug_infolevel==-4){ + ofstream static_lexer_("static_lexer_.h"); + for (int i=0;ipush_back(*(size_t *)at_" << translate_at(builtin_lexer_functions_begin()[i].first) <<")"; + if (i!=nfunc-1) + static_lexer_ << ","; + static_lexer_ << '\n'; + } + static_lexer_.close(); + } + ofstream static_extern("static_extern.h"); + static_extern << "#ifndef STATIC_EXTERN" << '\n'; + static_extern << "#define STATIC_EXTERN" << '\n'; + static_extern << "namespace giac{" << '\n'; + static_extern << "struct unary_function_ptr;" << '\n'; + for (int i=0;i=sizeof(lexer_string)-100) + s="Parse_string_too_large"; +#endif + // change for Numworks built-in calculation app replacement + for (size_t i=0;i2 && s[i-2]=='\'' && s[i-1]=='='){ + s.insert(s.begin()+i-1,' '); + ++l; + } + } + if (!instring && i && s[i]=='/' && s[i-1]=='/'){ + // skip comment until end of line + for (;i=2 && ( (s[i-2]=='-' && s[i-1]=='-') || (s[i-2]=='+' && s[i-1]=='+') ) && (s[i]=='.'|| (s[i]>='0' && s[i]<='9')) ){ + s[i-2]='+'; + s[i-1]=' '; + } + if (!instring && i && s[i]=='*' && s[i-1]=='/'){ + // skip comment + for (;i=l) + break; + } + if (instring){ + if (s[i]=='"'&& (i==0 || s[i-1]!='\\')) + instring=false; + } + else { + switch (s[i]){ + case '"': + instring=i==0 || s[i-1]!='\\'; + break; + case '(': + ++np; + break; + case ')': + --np; + break; + case '[': + ++nb; + break; + case ']': + --nb; + break; + } + } + } + if (nb<0) + *logptr(contextptr) << "Too many ]" << '\n'; + if (np<0) + *logptr(contextptr) << "Too many )" << '\n'; + while (np<0 && i>=0 && s[i-1]==')'){ + --i; + ++np; + } + while (nb<0 && i>=0 && s[i-1]==']'){ + --i; + ++nb; + } + s=s.substr(0,i); + if (nb>0){ + *logptr(contextptr) << "Warning adding " << nb << " ] at end of input" << '\n'; + s += string(nb,']'); + } + if (np>0){ + *logptr(contextptr) << "Warning adding " << np << " ) at end of input" << '\n'; + s += string(np,')'); + } + } + index_status(contextptr)=0; + opened_quote(contextptr)=0; + in_rpn(contextptr)=0; + lexer_line_number(contextptr)=1; + first_error_line(contextptr)=0; + spread_formula(contextptr)=0; + l=s.size(); + for (;l;l--){ + if (s[l-1]!=' ') + break; + } + // strings ending with :; + while (l>=4 && s[l-1]==';' && s[l-2]==':'){ + // skip spaces before :; + int m; + for (m=l-3;m>0;--m){ + if (s[m]!=' ') + break; + } + if (m<=1 || s[m]!=';') + break; + if (s[m-1]==':') + l = m+1; + else { + s[m]=':'; + s[m+1]=';'; + l=m+2; + } + } + s=s.substr(0,l); + /* if (l && ( (s[l-1]==';') || (s[l-1]==':'))) + l--; */ + string ss; + ss.reserve(s.size()*1.1); + for (int i=0;i0 && s[i-1]=='^' && i='0' && s[i+1]<='9' && s[i+2]==')'){ // suppress () for things like 2x^(2) (sent from TI nspire lua UI) + ss += s[i+1]; + i+=2; + continue; + } +#endif + if (s[i]=='\\' && s[i+1]=='\n'){ + ++i; + continue; + } + if ((unsigned char)s[i]==0xc2 && (unsigned char)s[i+1]!=0xb5) // ยต + ss += "micro"; + if (i && (unsigned char)s[i]==0xc2 && (unsigned char)s[i+1]!=0xb0) + ss += ' '; + if ( (unsigned char)s[i]==0xef && i1 && (s[i-1]=='e' || s[i-1]=='E')){ + ss +='-'; + i +=2; + continue; + } + if (i>2 && (s[i-1]==' ' && (s[i-2]=='e' || s[i-2]=='E')) ){ + ss[ss.size()-1] = '-'; + i += 3; + continue; + } + ss += ' '; + ss += s[i]; + ++i; + ss += s[i]; + ++i; + ss += s[i]; + ss += ' '; + continue; + } // 0xe2 0x88 + if ((unsigned char)s[i+1]==0x96 && ((unsigned char)s[i+2]==0xba || (unsigned char)s[i+2]==182 )){ + // sto + ss += s[i]; + ++i; + ss += s[i]; + ++i; + ss += s[i]; + ss += ' '; + continue; + } // 0xe2 0x96 + if ((unsigned char)s[i+1]==0x86 && (unsigned char)s[i+2]==0x92){ + // sto + ss += s[i]; + ++i; + ss += s[i]; + ++i; + ss += s[i]; + ss += ' '; + continue; + } // 0xe2 0x96 + } //end if s[i]=0xe2 + if (s[i]=='.'){ + if ( i && (i 0 && xcas_mode(contextptr) !=3){ + if (s[i]=='#') + ss += "//"; + else + ss += s[i]; + } + else + ss+=s[i]; + } + } + // ofstream of("log"); of << s << '\n' << ss << '\n'; of.close(); + if (debug_infolevel>2) + CERR << "lexer " << ss << '\n'; + s.clear(); +#ifdef NUMWORKS + ss += " \n รฟ"; + if (ss.size()>sizeof(lexer_string)-1) + ss = "Parse_string_too_large"; + strcpy(lexer_string,ss.c_str()); +#else + lexer_string = ss; + lexer_string += " \n รฟ"; +#endif + } + yylex_init(&scanner); + yyset_extra(contextptr, scanner); +#ifdef NUMWORKS + currently_scanned(contextptr)=lexer_string; + YY_BUFFER_STATE state=yy_scan_string(lexer_string,scanner); +#else + currently_scanned(contextptr)=lexer_string.c_str(); + YY_BUFFER_STATE state=yy_scan_string(lexer_string.c_str(),scanner); +#endif + return state; + } + + int delete_lexer_string(YY_BUFFER_STATE & state,yyscan_t & scanner){ + yy_delete_buffer(state,scanner); + yylex_destroy(scanner); + return 1; + } +#ifdef STATIC_BUILTIN_LEXER_FUNCTIONS + bool CasIsBuildInFunction(char const *s, gen &g){ + // binary search in builtin_lexer_functions + int i=0, j=builtin_lexer_functions_number-1; + int cmp; + cmp= strcmp(s,builtin_lexer_functions[i].s); + if (cmp==0) goto found; if (cmp<0) return false; + cmp= strcmp(s,builtin_lexer_functions[j].s); + if (cmp==0) { i=j; goto found; } if (cmp>0) return false; + while (1){ + if (i+1>=j) return false; + int mid= (i+j)/2; + cmp= strcmp(s,builtin_lexer_functions[mid].s); + if (cmp==0) { i=mid; goto found; } + if (cmp>0) i= mid; else j=mid; + } + found: +#if defined NSPIRE + g= gen(int((*builtin_lexer_functions_())[i]+builtin_lexer_functions[i]._FUNC_)); +#else + g= gen(int(builtin_lexer_functions_[i]+builtin_lexer_functions[i]._FUNC_)); +#endif + g= gen(*g._FUNCptr); + return true; + } +#endif + +#ifndef NO_NAMESPACE_GIAC + } // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + + diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/input_parser.cc b/android/app/src/main/cpp/giac/src/giac/cpp/input_parser.cc new file mode 100644 index 0000000..450efe7 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/input_parser.cc @@ -0,0 +1,6949 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse giac_yyparse +#define yylex giac_yylex +#define yyerror giac_yyerror +#define yydebug giac_yydebug +#define yynerrs giac_yynerrs + + +/* Copy the first part of user declarations. */ +#line 24 "input_parser.yy" /* yacc.c:339 */ + + #define YYPARSE_PARAM scanner + #define YYLEX_PARAM scanner + +#line 33 "input_parser.yy" /* yacc.c:339 */ + +#include "giacPCH.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "first.h" +#include +#include +#include "giacPCH.h" +#include "index.h" +#include "gen.h" +#define YYSTYPE giac::gen +#define YY_EXTRA_TYPE const giac::context * +#include "lexer.h" +#include "input_lexer.h" +#include "usual.h" +#include "derive.h" +#include "sym2poly.h" +#include "vecteur.h" +#include "modpoly.h" +#include "alg_ext.h" +#include "prog.h" +#include "rpn.h" +#include "intg.h" +#include "plot.h" +#include "maple.h" +using namespace std; + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + +// It seems there is a bison bug when it reallocates space for the stack +// therefore I redefine YYINITDEPTH to 4000 (max size is YYMAXDEPTH) +// instead of 200 +// Feel free to change if you need but then readjust YYMAXDEPTH +#if defined RTOS_THREADX || defined NSPIRE || defined NSPIRE_NEWLIB || defined NUMWORKS +#ifdef RTOS_THREADX +#define YYINITDEPTH 100 +#define YYMAXDEPTH 101 +#else +#define YYINITDEPTH 200 +#define YYMAXDEPTH 201 +#endif +#else // RTOS_THREADX +// Note that the compilation by bison with -v option generates a file y.output +// to debug the grammar, compile input_parser.yy with bison +// then add yydebug=1 in input_parser.cc at the beginning of yyparse ( +#define YYDEBUG 1 +#ifdef GNUWINCE +#define YYINITDEPTH 1000 +#else +#define YYINITDEPTH 4000 +#define YYMAXDEPTH 20000 +#define YYERROR_VERBOSE 1 +#endif // GNUWINCE +#endif // RTOS_THREADX + +#if 0 +#define YYSTACK_USE_ALLOCA 1 +#endif + + +gen polynome_or_sparse_poly1(const gen & coeff, const gen & index){ + if (index.type==_VECT){ + index_t i; + const_iterateur it=index._VECTptr->begin(),itend=index._VECTptr->end(); + i.reserve(itend-it); + for (;it!=itend;++it){ + if (it->type!=_INT_) + return gentypeerr(); + i.push_back(it->val); + } + monomial m(coeff,i); + return polynome(m); + } + else { + sparse_poly1 res; + res.push_back(monome(coeff,index)); + return res; + } +} + +#line 161 "y.tab.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_GIAC_YY_Y_TAB_H_INCLUDED +# define YY_GIAC_YY_Y_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int giac_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + T_NUMBER = 258, + T_SYMBOL = 259, + T_LITERAL = 260, + T_DIGITS = 261, + T_STRING = 262, + T_END_INPUT = 263, + T_EXPRESSION = 264, + T_UNARY_OP = 265, + T_OF = 266, + T_NOT = 267, + T_TYPE_ID = 268, + T_VIRGULE = 269, + T_AFFECT = 270, + T_MAPSTO = 271, + T_BEGIN_PAR = 272, + T_END_PAR = 273, + T_PLUS = 274, + T_MOINS = 275, + T_FOIS = 276, + T_DIV = 277, + T_MOD = 278, + T_POW = 279, + T_QUOTED_BINARY = 280, + T_QUOTE = 281, + T_PRIME = 282, + T_TEST_EQUAL = 283, + T_EQUAL = 284, + T_INTERVAL = 285, + T_UNION = 286, + T_INTERSECT = 287, + T_MINUS = 288, + T_AND_OP = 289, + T_COMPOSE = 290, + T_DOLLAR = 291, + T_DOLLAR_MAPLE = 292, + T_INDEX_BEGIN = 293, + T_VECT_BEGIN = 294, + T_VECT_DISPATCH = 295, + T_VECT_END = 296, + T_SET_BEGIN = 297, + T_SET_END = 298, + T_SEMI = 299, + T_DEUXPOINTS = 300, + T_DOUBLE_DEUX_POINTS = 301, + T_IF = 302, + T_RPN_IF = 303, + T_ELIF = 304, + T_THEN = 305, + T_ELSE = 306, + T_IFTE = 307, + T_SWITCH = 308, + T_CASE = 309, + T_DEFAULT = 310, + T_ENDCASE = 311, + T_FOR = 312, + T_FROM = 313, + T_TO = 314, + T_DO = 315, + T_BY = 316, + T_WHILE = 317, + T_MUPMAP_WHILE = 318, + T_RPN_WHILE = 319, + T_REPEAT = 320, + T_UNTIL = 321, + T_IN = 322, + T_START = 323, + T_BREAK = 324, + T_CONTINUE = 325, + T_TRY = 326, + T_CATCH = 327, + T_TRY_CATCH = 328, + T_PROC = 329, + T_BLOC = 330, + T_BLOC_BEGIN = 331, + T_BLOC_END = 332, + T_RETURN = 333, + T_LOCAL = 334, + T_LOCALBLOC = 335, + T_NAME = 336, + T_PROGRAM = 337, + T_NULL = 338, + T_ARGS = 339, + T_FACTORIAL = 340, + T_RPN_OP = 341, + T_RPN_BEGIN = 342, + T_RPN_END = 343, + T_STACK = 344, + T_GROUPE_BEGIN = 345, + T_GROUPE_END = 346, + T_LINE_BEGIN = 347, + T_LINE_END = 348, + T_VECTOR_BEGIN = 349, + T_VECTOR_END = 350, + T_CURVE_BEGIN = 351, + T_CURVE_END = 352, + T_ROOTOF_BEGIN = 353, + T_ROOTOF_END = 354, + T_SPOLY1_BEGIN = 355, + T_SPOLY1_END = 356, + T_POLY1_BEGIN = 357, + T_POLY1_END = 358, + T_MATRICE_BEGIN = 359, + T_MATRICE_END = 360, + T_ASSUME_BEGIN = 361, + T_ASSUME_END = 362, + T_HELP = 363, + TI_DEUXPOINTS = 364, + TI_LOCAL = 365, + TI_LOOP = 366, + TI_FOR = 367, + TI_WHILE = 368, + TI_STO = 369, + TI_TRY = 370, + TI_DIALOG = 371, + T_PIPE = 372, + TI_DEFINE = 373, + TI_PRGM = 374, + TI_SEMI = 375, + TI_HASH = 376, + T_ACCENTGRAVE = 377, + T_MAPLELIB = 378, + T_INTERROGATION = 379, + T_UNIT = 380, + T_BIDON = 381, + T_LOGO = 382, + T_SQ = 383, + T_CASE38 = 384, + T_IFERR = 385, + T_MOINS38 = 386, + T_NEG38 = 387, + T_UNARY_OP_38 = 388, + T_FUNCTION = 389, + T_IMPMULT = 390 + }; +#endif +/* Tokens. */ +#define T_NUMBER 258 +#define T_SYMBOL 259 +#define T_LITERAL 260 +#define T_DIGITS 261 +#define T_STRING 262 +#define T_END_INPUT 263 +#define T_EXPRESSION 264 +#define T_UNARY_OP 265 +#define T_OF 266 +#define T_NOT 267 +#define T_TYPE_ID 268 +#define T_VIRGULE 269 +#define T_AFFECT 270 +#define T_MAPSTO 271 +#define T_BEGIN_PAR 272 +#define T_END_PAR 273 +#define T_PLUS 274 +#define T_MOINS 275 +#define T_FOIS 276 +#define T_DIV 277 +#define T_MOD 278 +#define T_POW 279 +#define T_QUOTED_BINARY 280 +#define T_QUOTE 281 +#define T_PRIME 282 +#define T_TEST_EQUAL 283 +#define T_EQUAL 284 +#define T_INTERVAL 285 +#define T_UNION 286 +#define T_INTERSECT 287 +#define T_MINUS 288 +#define T_AND_OP 289 +#define T_COMPOSE 290 +#define T_DOLLAR 291 +#define T_DOLLAR_MAPLE 292 +#define T_INDEX_BEGIN 293 +#define T_VECT_BEGIN 294 +#define T_VECT_DISPATCH 295 +#define T_VECT_END 296 +#define T_SET_BEGIN 297 +#define T_SET_END 298 +#define T_SEMI 299 +#define T_DEUXPOINTS 300 +#define T_DOUBLE_DEUX_POINTS 301 +#define T_IF 302 +#define T_RPN_IF 303 +#define T_ELIF 304 +#define T_THEN 305 +#define T_ELSE 306 +#define T_IFTE 307 +#define T_SWITCH 308 +#define T_CASE 309 +#define T_DEFAULT 310 +#define T_ENDCASE 311 +#define T_FOR 312 +#define T_FROM 313 +#define T_TO 314 +#define T_DO 315 +#define T_BY 316 +#define T_WHILE 317 +#define T_MUPMAP_WHILE 318 +#define T_RPN_WHILE 319 +#define T_REPEAT 320 +#define T_UNTIL 321 +#define T_IN 322 +#define T_START 323 +#define T_BREAK 324 +#define T_CONTINUE 325 +#define T_TRY 326 +#define T_CATCH 327 +#define T_TRY_CATCH 328 +#define T_PROC 329 +#define T_BLOC 330 +#define T_BLOC_BEGIN 331 +#define T_BLOC_END 332 +#define T_RETURN 333 +#define T_LOCAL 334 +#define T_LOCALBLOC 335 +#define T_NAME 336 +#define T_PROGRAM 337 +#define T_NULL 338 +#define T_ARGS 339 +#define T_FACTORIAL 340 +#define T_RPN_OP 341 +#define T_RPN_BEGIN 342 +#define T_RPN_END 343 +#define T_STACK 344 +#define T_GROUPE_BEGIN 345 +#define T_GROUPE_END 346 +#define T_LINE_BEGIN 347 +#define T_LINE_END 348 +#define T_VECTOR_BEGIN 349 +#define T_VECTOR_END 350 +#define T_CURVE_BEGIN 351 +#define T_CURVE_END 352 +#define T_ROOTOF_BEGIN 353 +#define T_ROOTOF_END 354 +#define T_SPOLY1_BEGIN 355 +#define T_SPOLY1_END 356 +#define T_POLY1_BEGIN 357 +#define T_POLY1_END 358 +#define T_MATRICE_BEGIN 359 +#define T_MATRICE_END 360 +#define T_ASSUME_BEGIN 361 +#define T_ASSUME_END 362 +#define T_HELP 363 +#define TI_DEUXPOINTS 364 +#define TI_LOCAL 365 +#define TI_LOOP 366 +#define TI_FOR 367 +#define TI_WHILE 368 +#define TI_STO 369 +#define TI_TRY 370 +#define TI_DIALOG 371 +#define T_PIPE 372 +#define TI_DEFINE 373 +#define TI_PRGM 374 +#define TI_SEMI 375 +#define TI_HASH 376 +#define T_ACCENTGRAVE 377 +#define T_MAPLELIB 378 +#define T_INTERROGATION 379 +#define T_UNIT 380 +#define T_BIDON 381 +#define T_LOGO 382 +#define T_SQ 383 +#define T_CASE38 384 +#define T_IFERR 385 +#define T_MOINS38 386 +#define T_NEG38 387 +#define T_UNARY_OP_38 388 +#define T_FUNCTION 389 +#define T_IMPMULT 390 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int giac_yyparse (void * scanner); + +#endif /* !YY_GIAC_YY_Y_TAB_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 481 "y.tab.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 157 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 14302 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 136 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 30 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 261 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 609 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 390 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 199, 199, 207, 208, 209, 212, 213, 214, 215, + 216, 217, 218, 220, 221, 224, 225, 226, 227, 231, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 254, 255, + 261, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 275, 276, 277, 282, 287, 293, 294, 300, 301, + 302, 303, 304, 305, 306, 320, 325, 329, 336, 339, + 340, 342, 343, 344, 347, 348, 349, 350, 351, 355, + 362, 363, 365, 367, 368, 370, 371, 372, 397, 402, + 415, 428, 432, 436, 441, 446, 452, 456, 460, 461, + 465, 466, 467, 468, 469, 470, 471, 473, 474, 475, + 476, 477, 478, 481, 482, 487, 491, 495, 496, 522, + 531, 537, 538, 539, 540, 545, 549, 550, 559, 560, + 561, 562, 563, 567, 568, 571, 576, 577, 578, 579, + 584, 589, 594, 599, 604, 609, 614, 615, 616, 617, + 618, 619, 620, 621, 625, 628, 632, 636, 637, 638, + 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, + 649, 650, 651, 652, 656, 660, 664, 667, 668, 669, + 670, 671, 675, 676, 695, 707, 708, 709, 710, 713, + 714, 720, 721, 722, 723, 724, 725, 733, 739, 742, + 743, 746, 747, 748, 752, 753, 756, 759, 762, 763, + 770, 771, 772, 773, 774, 775, 776, 777, 785, 795, + 796, 799, 800, 803, 805, 810, 813, 814, 815, 818, + 888, 889, 892, 893, 894, 895, 898, 899, 902, 903, + 904, 908, 911, 918, 919, 923, 926, 931, 932, 935, + 936, 939, 940, 941, 944, 945, 946, 949, 950, 951, + 952, 955 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "T_NUMBER", "T_SYMBOL", "T_LITERAL", + "T_DIGITS", "T_STRING", "T_END_INPUT", "T_EXPRESSION", "T_UNARY_OP", + "T_OF", "T_NOT", "T_TYPE_ID", "T_VIRGULE", "T_AFFECT", "T_MAPSTO", + "T_BEGIN_PAR", "T_END_PAR", "T_PLUS", "T_MOINS", "T_FOIS", "T_DIV", + "T_MOD", "T_POW", "T_QUOTED_BINARY", "T_QUOTE", "T_PRIME", + "T_TEST_EQUAL", "T_EQUAL", "T_INTERVAL", "T_UNION", "T_INTERSECT", + "T_MINUS", "T_AND_OP", "T_COMPOSE", "T_DOLLAR", "T_DOLLAR_MAPLE", + "T_INDEX_BEGIN", "T_VECT_BEGIN", "T_VECT_DISPATCH", "T_VECT_END", + "T_SET_BEGIN", "T_SET_END", "T_SEMI", "T_DEUXPOINTS", + "T_DOUBLE_DEUX_POINTS", "T_IF", "T_RPN_IF", "T_ELIF", "T_THEN", "T_ELSE", + "T_IFTE", "T_SWITCH", "T_CASE", "T_DEFAULT", "T_ENDCASE", "T_FOR", + "T_FROM", "T_TO", "T_DO", "T_BY", "T_WHILE", "T_MUPMAP_WHILE", + "T_RPN_WHILE", "T_REPEAT", "T_UNTIL", "T_IN", "T_START", "T_BREAK", + "T_CONTINUE", "T_TRY", "T_CATCH", "T_TRY_CATCH", "T_PROC", "T_BLOC", + "T_BLOC_BEGIN", "T_BLOC_END", "T_RETURN", "T_LOCAL", "T_LOCALBLOC", + "T_NAME", "T_PROGRAM", "T_NULL", "T_ARGS", "T_FACTORIAL", "T_RPN_OP", + "T_RPN_BEGIN", "T_RPN_END", "T_STACK", "T_GROUPE_BEGIN", "T_GROUPE_END", + "T_LINE_BEGIN", "T_LINE_END", "T_VECTOR_BEGIN", "T_VECTOR_END", + "T_CURVE_BEGIN", "T_CURVE_END", "T_ROOTOF_BEGIN", "T_ROOTOF_END", + "T_SPOLY1_BEGIN", "T_SPOLY1_END", "T_POLY1_BEGIN", "T_POLY1_END", + "T_MATRICE_BEGIN", "T_MATRICE_END", "T_ASSUME_BEGIN", "T_ASSUME_END", + "T_HELP", "TI_DEUXPOINTS", "TI_LOCAL", "TI_LOOP", "TI_FOR", "TI_WHILE", + "TI_STO", "TI_TRY", "TI_DIALOG", "T_PIPE", "TI_DEFINE", "TI_PRGM", + "TI_SEMI", "TI_HASH", "T_ACCENTGRAVE", "T_MAPLELIB", "T_INTERROGATION", + "T_UNIT", "T_BIDON", "T_LOGO", "T_SQ", "T_CASE38", "T_IFERR", + "T_MOINS38", "T_NEG38", "T_UNARY_OP_38", "T_FUNCTION", "T_IMPMULT", + "$accept", "input", "correct_input", "exp", "symbol_for", "symbol", + "symbol_or_literal", "entete", "stack", "local", "nom", "suite_symbol", + "affectable_symbol", "exp_or_empty", "suite", "prg_suite", "rpn_suite", + "rpn_token", "step", "from", "loop38_do", "else", "bloc", "elif", + "ti_bloc_end", "ti_else", "switch", "case", "case38", "semi", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390 +}; +# endif + +#define YYPACT_NINF -523 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-523))) + +#define YYTABLE_NINF -259 + +#define yytable_value_is_error(Yytable_value) \ + (!!((Yytable_value) == (-259))) + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 8983, -523, 211, -26, -523, 135, -523, -523, 16, -523, + 8983, 39, 8983, 8983, 8983, -523, 9116, 8983, 6589, -523, + 62, 8983, 6722, 78, 9249, 90, 119, 9382, 22, 9515, + 8983, 8983, -523, -523, 63, 153, 88, 181, 1269, 188, + 193, -523, 19, -523, 143, -16, 8983, 8983, 8983, 8983, + 8983, 8983, 8983, 8983, 6855, 81, 8983, 143, 174, 8983, + 1402, 15, 8983, 8983, 207, 225, -523, 600, 210, -523, + -523, -523, 215, 229, -17, 24, 8983, 6988, 7121, 8983, + 14174, -523, 10640, 14174, 14174, 86, 1934, 10707, 13798, 8983, + 14053, -523, 718, 10766, 195, -523, 8983, 10345, 8983, 8983, + 9648, 10303, 192, 26, -523, 39, 7254, -523, 167, 46, + 8983, 10825, 10884, 13208, 2998, 3131, 170, 8983, 7387, 222, + 8983, 1535, 13208, 8983, 8983, 8983, 8983, -523, 156, 134, + 8983, -523, 10943, 13267, 13208, 13208, 234, 3264, 13208, 144, + 11002, 3397, 3264, -523, 237, 102, 133, 8983, 14147, 7520, + 13798, 8983, 8983, 179, 3530, 14174, 8983, -523, -523, 196, + 8983, 8983, 6855, 7387, 8983, 8983, 8983, 8983, 8983, 8983, + -523, 8983, 8983, 870, 8983, 8983, 8983, 8983, 8983, 8983, + 8983, 9781, 7653, 8983, 8983, -523, 266, 8983, 8983, 8983, + 8983, -523, 8983, 7387, 8983, -523, 105, -523, -523, -523, + -523, 8983, -523, 13444, -523, 11061, -523, 11120, 11179, 243, + -523, 1003, -523, 13680, 70, -523, 11238, 6855, 8983, 11297, + 11356, 35, 261, 8983, 209, 263, 11415, 227, 8983, 8983, + 8983, 8983, 136, 11474, 8983, 8983, -523, 8983, 13208, -523, + 8983, 7786, 197, 3663, 265, 11533, 268, 7387, 11592, 11651, + 11710, 11769, 11828, -523, 143, -523, 11887, -523, 8983, 7387, + -523, 7919, -523, 8983, 8983, 8052, 8185, -523, 7387, -523, + 11946, -523, 12005, 3796, -523, 8983, 12064, 8983, 13680, 13444, + 13857, -523, 271, 651, 651, 14078, 14095, 14122, 292, 14001, + 718, 14053, 10386, 13956, 14023, 13884, 102, 267, 718, 2, + 6722, 12123, -523, -523, 13798, 13926, -523, -523, -523, -523, + -523, -523, -523, 8983, 168, 13326, 13562, 13739, 14147, 651, + 272, 12182, -523, 280, 12249, -523, -523, -523, 7387, 192, + 100, 246, 39, 70, -523, 28, -523, 1668, 2067, 242, + 13208, -523, 219, -523, 236, 3929, -523, -523, -523, 7254, + 12308, 13208, 13208, 13208, 8983, 8983, 160, 1801, 4062, 4195, + 12367, 12426, 70, -523, 4328, 218, -523, 8983, -523, 197, + 281, -523, -523, -523, -523, -523, -523, -523, 13621, 283, + -523, 3264, 3264, 3264, -523, 8052, 286, -523, 8983, 2200, + -523, 13926, -523, 1136, 8983, 10463, -523, 14147, 7387, 9914, + -9, 274, 290, -523, 293, 8983, 8983, 8983, 8983, 296, + 70, 8983, 7387, 12485, -7, 8983, -523, 2333, -523, -523, + 8983, 63, 104, 8983, 13208, 273, 8983, 12559, 13208, 8983, + 8983, 8983, 12618, -523, -523, -523, -523, -523, 27, -523, + 12677, 4461, 2466, -523, -10, -523, -523, -523, 3264, -523, + 289, 4594, 8983, -523, 13926, 269, 301, 6722, 12736, 8318, + 197, 319, -523, -523, 13208, 13503, 13385, 13503, -523, -523, + 10522, 10640, -7, 282, -523, 6855, 12795, 8983, -523, 3264, + -523, 322, 291, 254, 2599, 8451, 2732, 53, 12854, 4727, + 12913, -523, -523, 63, 8983, 4860, 197, 7786, 4993, 10047, + -523, 8584, 152, 5126, -523, -523, 10581, -523, 200, 13444, + -523, 7786, -523, -523, 8983, -523, 12972, -523, 8983, 13031, + -523, 294, 63, -523, 261, -523, 316, 8983, -523, -523, + -523, 8983, 8983, -523, 8983, -523, 5259, -523, 7786, 5392, + -523, 8717, 2865, 10180, 718, 15, -523, -523, 299, 7786, + 5525, 13090, -523, 2067, 8983, 63, -523, 6855, 5658, 5791, + 5924, 6057, -523, 6190, -523, 8983, 6323, 8983, -523, 8850, + 3264, -523, -523, 6456, -523, -523, -523, 2067, 104, 13149, + -523, -523, -523, -523, -523, -523, 226, 8983, 233, 8983, + -523, -523, -523, -523, -523, 8983, 235, 8983, 238, 3264, + 8983, 3264, 8983, -523, 3264, -523, 3264, -523, -523 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 0, 127, 6, 189, 31, 32, 13, 14, 68, 58, + 0, 99, 0, 0, 0, 113, 0, 0, 0, 107, + 0, 0, 0, 0, 0, 75, 0, 0, 93, 0, + 0, 0, 85, 86, 0, 159, 0, 81, 0, 133, + 77, 121, 63, 164, 226, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 137, 0, + 0, 257, 0, 0, 0, 0, 2, 0, 30, 128, + 199, 200, 0, 0, 7, 0, 0, 0, 0, 0, + 60, 197, 0, 55, 53, 99, 0, 0, 39, 0, + 49, 105, 101, 222, 0, 195, 0, 0, 0, 0, + 0, 254, 0, 189, 187, 0, 0, 188, 0, 232, + 0, 0, 0, 223, 0, 0, 0, 0, 0, 0, + 0, 0, 82, 0, 0, 0, 0, 229, 0, 226, + 0, 205, 0, 0, 122, 179, 30, 0, 222, 0, + 0, 0, 0, 178, 0, 198, 0, 0, 124, 0, + 129, 0, 0, 0, 0, 54, 0, 1, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, + 0, 126, 0, 0, 0, 196, 0, 10, 192, 191, + 190, 0, 193, 33, 35, 0, 67, 0, 0, 118, + 100, 0, 114, 50, 0, 119, 0, 0, 0, 0, + 0, 189, 0, 0, 0, 0, 220, 0, 0, 0, + 0, 0, 230, 0, 0, 0, 261, 0, 224, 225, + 0, 0, 201, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 136, 226, 227, 0, 57, 0, 0, + 247, 0, 166, 0, 0, 0, 0, 177, 0, 163, + 0, 131, 0, 0, 98, 0, 0, 0, 120, 59, + 79, 78, 0, 40, 41, 43, 44, 46, 45, 37, + 38, 47, 108, 110, 111, 51, 106, 104, 103, 30, + 0, 0, 4, 5, 52, 149, 36, 21, 25, 22, + 23, 24, 26, 0, 20, 112, 172, 123, 125, 42, + 0, 0, 8, 0, 0, 34, 64, 66, 0, 218, + 189, 215, 217, 0, 210, 0, 208, 0, 0, 72, + 167, 74, 0, 161, 0, 0, 162, 186, 148, 0, + 0, 233, 234, 235, 0, 0, 0, 0, 0, 0, + 94, 0, 0, 202, 0, 203, 241, 0, 158, 201, + 0, 80, 132, 76, 61, 62, 228, 204, 120, 0, + 248, 0, 0, 0, 169, 0, 0, 138, 0, 0, + 65, 150, 29, 0, 0, 0, 115, 27, 0, 0, + 28, 11, 0, 194, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 238, 0, 249, 0, 73, 243, + 0, 0, 251, 0, 220, 0, 0, 230, 231, 0, + 0, 0, 0, 153, 155, 156, 95, 207, 0, 242, + 0, 0, 0, 56, 28, 183, 184, 168, 0, 171, + 0, 0, 0, 97, 102, 0, 0, 0, 0, 0, + 201, 0, 9, 117, 211, 212, 213, 216, 214, 209, + 0, 0, 238, 0, 134, 0, 0, 0, 250, 0, + 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 154, 206, 0, 0, 0, 201, 0, 0, 0, + 170, 0, 257, 0, 116, 17, 0, 18, 201, 16, + 15, 0, 12, 151, 0, 135, 0, 240, 0, 0, + 244, 0, 0, 160, 58, 256, 0, 0, 87, 236, + 237, 0, 0, 91, 0, 157, 0, 139, 0, 0, + 141, 0, 0, 0, 180, 257, 259, 96, 0, 0, + 0, 0, 239, 0, 0, 0, 252, 0, 0, 0, + 0, 0, 143, 0, 140, 0, 0, 0, 176, 0, + 0, 260, 19, 0, 144, 152, 245, 0, 251, 0, + 146, 88, 89, 90, 92, 142, 0, 0, 0, 0, + 182, 145, 246, 253, 147, 0, 0, 0, 0, 0, + 0, 0, 0, 175, 0, 174, 0, 173, 181 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -523, -523, 161, 0, -523, 186, -523, -234, -523, -523, + -523, -14, -322, -347, 82, 270, -126, 303, -76, -523, + -523, -119, -31, -522, -133, -369, -222, -123, -487, -523 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 65, 66, 113, 108, 68, 74, 241, 69, 363, + 242, 335, 336, 227, 94, 114, 128, 129, 356, 232, + 531, 474, 116, 418, 419, 420, 483, 224, 153, 239 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 67, 130, 425, 255, 262, 459, 459, 196, 365, 267, + 80, 409, 82, 83, 84, 546, 87, 88, 90, 193, + 75, 92, 93, 143, 97, 102, 103, 101, 198, 111, + 112, 576, 104, 78, 199, 105, 125, 200, 122, 106, + 225, 410, 410, 81, 416, 475, 132, 133, 134, 135, + 201, 138, 140, 343, 79, 592, 145, 126, 571, 148, + 150, 229, 151, 155, 460, 460, 91, 131, 23, 394, + 152, 492, 75, 329, 330, 230, 203, 205, 207, 208, + 331, 75, 95, 332, 102, 3, 122, 333, 469, 213, + 81, 102, 3, -185, 105, 411, 216, 529, 219, 220, + 82, 105, 473, 475, 231, 118, 226, 98, 322, 499, + 233, 197, 210, 530, 238, 405, 23, 245, 138, 163, + 248, 135, 323, 249, 250, 251, 252, 23, 376, 406, + 256, 281, 384, 139, 23, 441, 99, 238, 526, 115, + 181, 238, 238, 56, 127, 407, 75, 270, 254, 82, + 76, 272, 77, 127, 238, 107, 276, 202, 481, 482, + 278, 279, 280, 138, 283, 284, 285, 286, 287, 288, + 117, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 298, 301, 67, 304, 305, 398, 339, 315, 316, 317, + 318, 56, 319, 138, 321, 354, 545, 355, 120, 151, + 246, 324, 56, 102, 3, 123, 399, 152, 497, 56, + 124, 87, 147, 105, 109, 70, 71, 118, 340, 429, + 430, 72, 119, 431, 156, 157, 511, 193, 350, 351, + 352, 353, 194, 195, 228, 136, 215, 360, 73, 247, + 361, 144, 244, 238, 253, 282, 23, 138, 445, 446, + 447, 259, 449, 263, 268, 269, 274, 73, 378, 138, + 328, 135, 538, 277, 344, 346, 135, 347, 138, 102, + 3, 349, 306, 238, 549, 320, 307, 391, 240, 105, + 308, 240, 367, 402, 163, 309, 369, 310, 311, 392, + 400, 169, 408, 421, 170, 422, 423, 362, 461, 442, + 395, 444, 178, -259, 450, 181, 414, 136, 462, 163, + 504, 463, 23, 397, 468, 500, 169, 485, 501, 505, + 137, 56, 512, 141, 142, 521, 433, 178, 138, 370, + 181, 523, 154, 478, 557, 595, 522, 413, 238, 555, + 572, 379, 597, 303, 600, 238, 520, 602, 438, 424, + 386, 487, 185, 515, 427, 428, 593, 432, 238, 238, + 146, 525, 0, 0, 238, 0, 299, 440, 0, 0, + 0, 0, 314, 0, 0, 0, 0, 185, 0, 0, + 312, 238, 238, 238, 0, 243, 0, 56, 0, 238, + 480, 313, 0, 287, 454, 191, 0, 0, 138, 458, + 334, 0, 0, 0, 0, 464, 465, 466, 467, 568, + 404, 470, 471, 0, 0, 476, 0, 135, 0, 0, + 191, 0, 273, 0, 0, 0, 0, 0, 510, 488, + 0, 490, 0, 0, 0, 0, 0, 590, 0, 0, + 0, 0, 0, 0, 517, 0, 0, 136, 238, 0, + 0, 238, 136, 0, 0, 0, 0, 506, 0, 509, + 0, 0, 535, 0, 0, 0, 603, 0, 605, 0, + 0, 607, 0, 608, 0, 516, 0, 519, 0, 238, + 456, 0, 0, 0, 238, 424, 238, 338, 0, 238, + 0, 556, 0, 345, 404, 238, 0, 0, 238, 0, + 0, 544, 0, 238, 358, 359, 0, 0, 0, 0, + 0, 364, 0, 0, 551, 0, 0, 0, 0, 334, + 0, 0, 0, 0, 578, 0, 580, 0, 0, 0, + 0, 0, 0, 381, 382, 383, 238, 0, 0, 238, + 0, 135, 238, 0, 0, 389, 0, 0, 334, 0, + 238, 0, 0, 238, 0, 0, 0, 579, 238, 238, + 238, 238, 0, 238, 0, 138, 135, 138, 0, 135, + 238, 0, 0, 238, 0, 0, 0, 238, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 138, 0, 138, + 0, 0, 0, 0, 0, 0, 334, 0, 0, 238, + 0, 238, 0, 136, 238, 0, 238, 0, 158, 0, + 0, 0, 159, 0, 160, 161, 162, 163, 0, 164, + 165, 166, 167, 168, 169, 0, 0, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 0, + 0, 0, 0, 0, 182, 183, 0, 586, 0, 588, + 0, 0, 0, 0, 0, 448, 0, 0, 451, 0, + 0, 0, 0, 159, 0, 0, 0, 184, 163, 596, + 0, 598, 166, 167, 168, 169, 0, 0, 170, 0, + 0, 0, 0, 0, 0, 185, 178, 179, 0, 181, + 479, 0, 0, 484, 119, 0, 486, 0, 0, 0, + 489, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 495, 498, 0, 186, 0, 0, 187, 0, 0, + 188, 0, 503, 0, 189, 190, 0, 136, 191, 0, + 159, 192, 0, 0, 0, 163, 185, 164, 165, 166, + 167, 168, 169, 0, 0, 170, 171, 172, 173, 174, + 175, 176, 136, 178, 179, 136, 181, 0, 0, 0, + 0, 0, 0, 0, 536, 0, 0, 539, 0, 542, + 0, 0, 0, 0, 0, 0, 190, 0, 0, 191, + 0, 550, 0, 0, 0, 0, 0, 0, 553, 0, + 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, + 0, 559, 560, 185, 561, 0, 0, 0, 563, 0, + 0, 0, 0, 570, 0, 0, 0, 0, 0, 573, + 0, 0, 0, 0, 577, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 190, 0, 0, 191, 0, 0, 192, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 599, 0, 601, 0, 0, + 604, 1, 606, 2, 3, 4, 5, 6, -48, 7, + 8, 9, 10, 11, -48, -48, -48, 12, -48, 13, + 14, -48, -48, -48, -48, 15, 16, -48, -48, -48, + -48, -48, -48, -48, -48, 19, 20, -48, -48, 0, + 22, -48, 0, 0, -48, -48, 23, 24, 0, -48, + -48, -48, 25, 26, 27, -48, -48, -48, -48, -48, + -48, -48, 29, 30, 0, 31, -48, -48, 0, 32, + 33, 34, 0, 35, 36, 37, 0, -48, -48, 0, + 39, 0, 40, 41, 42, -48, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, -48, + 47, -48, 0, 0, 0, 0, 0, 0, 48, -48, + -48, 50, 51, 52, -48, 53, 54, -48, 55, 0, + -48, 56, 57, 58, -48, 59, 0, -48, -48, 61, + 62, -48, 63, 64, 1, 0, 2, 3, 4, 5, + 6, -84, 7, 8, 9, 10, 85, -84, -84, -84, + 12, -84, 13, 14, -84, -84, -84, -84, 15, 16, + -84, -84, 17, 18, -84, -84, -84, -84, 19, 20, + 21, -84, 0, 22, -84, 0, 0, -84, -84, 23, + 24, 0, -84, -84, -84, 25, 26, 27, -84, -84, + 28, -84, -84, -84, -84, 29, 30, 0, 31, -84, + -84, 0, 32, 33, 34, 0, 35, 36, 37, 0, + -84, 86, 0, 39, 0, 40, 41, 42, -84, 43, + 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 46, -84, 47, -84, 0, 0, 0, 0, 0, + 0, 48, 49, -84, 50, 51, 52, -84, 53, 54, + -84, 55, 0, -84, 56, 57, 58, -84, 59, 0, + 60, -84, 61, 62, -84, 63, 64, 1, 0, -109, + 3, 4, 5, 6, -109, 7, 8, 9, 10, 11, + -109, -109, -109, 12, -109, -109, -109, -109, -109, -109, + -109, 15, 16, -109, -109, -109, -109, -109, -109, -109, + -109, 19, 20, -109, -109, 0, 22, -109, 0, 0, + -109, -109, 23, 24, 0, -109, -109, -109, 25, 26, + 27, -109, -109, -109, -109, -109, -109, -109, 29, 30, + 0, 31, -109, -109, 0, 32, 33, 34, 0, 35, + 36, 37, 0, -109, -109, 0, 39, 0, 40, 41, + 42, -109, 43, 44, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 46, -109, 47, -109, 0, 0, + 0, 0, 0, 0, 48, -109, -109, 50, 51, 52, + -109, 53, 54, -109, 55, 0, -109, 56, 57, 58, + -109, 59, 0, -109, -109, 61, 62, -109, 63, 64, + 1, 0, 2, 3, 4, 5, 6, -83, 7, 8, + 9, 10, 11, -83, -83, -83, 12, -83, 13, 14, + -83, -83, -83, -83, 15, 16, -83, -83, 17, 18, + -83, -83, -83, -83, 19, 20, 21, -83, 0, 22, + -83, 0, 0, -83, -83, 23, 24, 0, -83, -83, + -83, 25, 26, 27, -83, -83, 28, -83, -83, -83, + -83, 29, 30, 0, 31, -83, -83, 0, 32, 33, + 34, 0, 35, 36, 37, 0, -83, 0, 0, 39, + 0, 40, 41, 42, -83, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 46, -83, 47, + -83, 0, 0, 0, 0, 0, 0, 48, -83, -83, + 50, 51, 52, -83, 53, 54, -83, 55, 0, -83, + 56, 57, 58, -83, 59, 0, 60, -83, 61, 62, + -83, 63, 64, 1, 0, 2, 3, 4, 5, 6, + -130, 7, 8, 9, 10, 11, -130, -130, -130, 149, + -130, 13, 14, -130, -130, -130, -130, 15, 16, -130, + -130, 17, 18, -130, -130, -130, -130, 19, 20, 21, + -130, 0, 22, -130, 0, 0, -130, -130, 23, 24, + 0, -130, -130, -130, 25, 26, 27, -130, -130, -130, + -130, -130, -130, -130, 29, 30, 0, 31, -130, -130, + 0, 32, 33, 34, 0, 35, 36, 37, 0, -130, + -130, 0, 39, 0, 40, 41, 42, -130, 43, 44, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 46, -130, 47, -130, 0, 0, 0, 0, 0, 0, + 48, -130, -130, 50, 51, 52, -130, 53, 54, -130, + 55, 0, -130, 56, 57, 58, -130, 59, 0, 0, + -130, 61, 62, -130, 63, 64, 1, 0, 2, 3, + 4, 5, 6, -165, 7, 8, 9, 10, 11, -165, + -165, -165, 12, -165, 13, 14, -165, -165, -165, -165, + 15, 16, -165, -165, 17, 18, -165, -165, -165, -165, + 19, 20, 21, -165, 0, 22, -165, 0, 0, -165, + -165, 23, 24, 0, -165, -165, -165, 25, 26, 27, + -165, -165, 28, -165, -165, -165, -165, 29, 30, 0, + 31, -165, -165, 0, 32, 33, 34, 0, 35, 36, + 37, 0, -165, 38, 0, 39, 0, 40, 41, 42, + -165, 43, 44, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 46, -165, 47, -165, 0, 0, 0, + 0, 0, 0, 48, 0, -165, 50, 51, 52, -165, + 53, 54, -165, 55, 0, -165, 56, 57, 58, -165, + 59, 0, 60, -165, 61, 62, -165, 63, 64, 1, + 0, 2, 3, 4, 5, 6, 0, 7, 8, 9, + 10, 11, -118, -118, -118, 412, 0, 13, 14, -118, + -118, -118, -118, 15, 16, -118, -118, 17, 18, -118, + -118, -118, -118, 19, 20, 21, -118, 0, 22, 0, + 0, 0, 0, -118, 23, 24, 0, 0, -118, 0, + 25, 26, 27, 0, 0, 28, 0, 0, 0, 0, + 29, 30, 0, 31, 0, -118, 0, 32, 33, 34, + 0, 35, 36, 37, 115, 0, 38, 0, 39, 0, + 40, 41, 42, -118, 43, 44, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, -118, 53, 54, -118, 55, 0, -118, 56, + 57, 58, -118, 59, 0, 60, -118, 61, 62, -118, + 63, 64, 1, 0, 2, 3, 4, 5, 6, 0, + 7, 8, 9, 10, 11, -118, -118, -118, 412, 0, + 13, 14, -118, -118, -118, -118, 15, 16, -118, -118, + 17, 18, -118, -118, -118, -118, 19, 20, 21, -118, + 0, 22, 0, 0, 0, 0, -118, 23, 24, 0, + 0, 0, 0, 25, 26, 27, 0, 0, 28, 0, + 0, -118, 0, 29, 30, 0, 31, 0, -118, 0, + 32, 33, 34, 0, 35, 36, 37, 115, 0, 38, + 0, 39, 0, 40, 41, 42, -118, 43, 44, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 50, 51, 52, -118, 53, 54, -118, 55, + 0, -118, 56, 57, 58, -118, 59, 0, 60, -118, + 61, 62, -118, 63, 64, 1, 0, 2, 3, 4, + 5, 6, 0, 7, 8, 9, 10, 11, -83, -83, + -83, 12, 0, 13, 14, -83, -83, -83, -83, 15, + 211, -83, -83, 17, 18, -83, -83, -83, -83, 19, + 20, 21, -83, 0, 22, 0, 0, 0, 0, -83, + 23, 24, 0, 0, 0, 0, 25, 26, 27, 0, + 0, 28, 0, 0, 0, 0, 29, 30, 0, 31, + 0, -83, 0, 32, 33, 34, 0, 35, 36, 37, + 0, 0, 38, 0, 39, 0, 40, 41, 42, -83, + 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, + 0, 0, 48, 121, 0, 50, 51, 52, -83, 53, + 54, -83, 55, 0, -83, 56, 57, 58, -83, 59, + 0, 60, -83, 61, 62, -83, 63, 64, 1, 0, + 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, + 11, 0, 0, 0, 12, 0, 13, 14, 0, 0, + 0, 0, 15, 16, 0, 0, 17, 18, 0, 0, + 0, 0, 19, 20, 21, 0, 0, 22, 0, 0, + 0, 236, 0, 23, 24, 0, 415, 0, 416, 25, + 26, 27, 0, 0, 28, 0, 0, 0, 0, 29, + 30, 0, 31, 0, 0, 0, 32, 33, 34, 0, + 35, 36, 37, 0, 260, 38, 0, 39, 0, 40, + 41, 42, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 48, 417, 0, 50, 51, + 52, 0, 53, 54, 0, 55, 0, 0, 56, 57, + 58, 0, 59, 0, 60, 0, 61, 62, 0, 63, + 64, 1, 0, 2, 3, 4, 5, 6, 0, 7, + 8, 9, 10, 11, 0, 0, 0, 12, 0, 13, + 14, 0, 0, 0, 0, 15, 16, 0, 0, 17, + 18, 0, 0, 0, 0, 19, 20, 21, 0, 0, + 22, 0, 0, 0, 236, 0, 23, 24, 0, 0, + 0, 452, 25, 26, 27, 0, 0, 28, 0, 0, + 0, 0, 29, 30, 0, 31, 0, 0, 0, 32, + 33, 34, 0, 35, 36, 37, 0, 453, 38, 0, + 39, 0, 40, 41, 42, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 48, 49, + 0, 50, 51, 52, 0, 53, 54, 0, 55, 0, + 0, 56, 57, 58, 0, 59, 0, 60, 0, 61, + 62, 0, 63, 64, 1, 0, 2, 3, 4, 5, + 6, 0, 7, 8, 9, 10, 11, 0, 0, 0, + 12, 0, 13, 14, 0, 0, 0, 0, 15, 16, + 0, 0, 17, 18, 0, 0, 0, 0, 19, 20, + 21, 0, 0, 22, 0, 0, 0, 0, 0, 23, + 24, 0, 477, 0, 478, 25, 26, 27, 0, 0, + 28, 0, 0, 0, 0, 29, 30, 0, 31, 0, + 0, 0, 32, 33, 34, 0, 35, 36, 37, 0, + 380, 38, 0, 39, 0, 40, 41, 42, 0, 43, + 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, + 0, 48, 49, 0, 50, 51, 52, 0, 53, 54, + 0, 55, 0, 0, 56, 57, 58, 0, 59, 0, + 60, 0, 61, 62, 0, 63, 64, 1, 0, 2, + 3, 4, 5, 6, 0, 7, 8, 9, 10, 11, + 0, 0, 0, 12, 0, 13, 14, 0, 0, 0, + 0, 15, 16, 0, 0, 17, 18, 0, 0, 0, + 0, 19, 20, 21, 0, 0, 22, 0, 0, 0, + 0, 0, 23, 24, 0, 0, 0, 0, 25, 26, + 27, 0, 0, 28, 0, 0, 0, 0, 29, 30, + 0, 31, 0, 0, 0, 32, 33, 34, 0, 35, + 36, 37, 496, 0, 38, -201, 39, 240, 40, 41, + 42, 0, 43, 44, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, 47, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 0, 50, 51, 52, + 0, 53, 54, 0, 55, 0, 0, 56, 57, 58, + 0, 59, 0, 60, 0, 61, 62, 0, 63, 64, + 1, 0, 2, 3, 4, 5, 6, 0, 7, 8, + 524, 10, 11, 0, 0, 0, 12, 0, 13, 14, + 0, 0, 0, 0, 15, 16, 0, 0, 17, 18, + 0, 0, 0, 0, 19, 20, 21, 0, 0, 22, + 0, 0, 0, 236, 0, 23, 24, 0, 0, 0, + 0, 25, 26, 27, 223, -254, 28, 0, 0, 0, + 0, 29, 30, 0, 31, 0, 0, 0, 32, 33, + 34, 0, 35, 36, 37, 0, 0, 38, 0, 39, + 0, 40, 41, 42, 0, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 50, 51, 52, 0, 53, 54, 0, 55, 0, 0, + 56, 57, 58, 0, 59, 0, 60, 0, 61, 62, + 0, 63, 64, 1, 0, 2, 3, 4, 5, 6, + 0, 7, 8, 9, 10, 11, 0, 0, 0, 12, + 0, 13, 14, 0, 0, 0, 0, 15, 16, 0, + 0, 17, 18, 0, 0, 0, 0, 19, 20, 21, + 0, 0, 22, 0, 0, 0, 236, 0, 23, 24, + 0, 0, 0, 527, 25, 26, 27, 0, 0, 28, + 0, 0, 0, 0, 29, 30, 0, 31, 0, 0, + 0, 32, 33, 34, 0, 35, 36, 37, 0, 528, + 38, 0, 39, 0, 40, 41, 42, 0, 43, 44, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 0, 50, 51, 52, 0, 53, 54, 0, + 55, 0, 0, 56, 57, 58, 0, 59, 0, 60, + 0, 61, 62, 0, 63, 64, 1, 0, 2, 3, + 4, 5, 6, 0, 7, 8, 9, 10, 11, 0, + 0, 0, 12, 0, 13, 14, 0, 0, 0, 0, + 15, 16, 0, 0, 17, 18, 0, 0, 0, 0, + 19, 20, 21, 0, 0, 22, 0, 0, 0, 236, + 0, 23, 24, 0, 0, 0, 0, 25, 26, 27, + 0, 0, 28, 0, 0, 0, 0, 29, 30, 0, + 31, 0, 0, 0, 32, 33, 34, 0, 35, 36, + 37, 0, 260, 38, 0, 39, 0, 40, 41, 42, + 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 48, 566, 567, 50, 51, 52, 0, + 53, 54, 0, 55, 0, 0, 56, 57, 58, 0, + 59, 0, 60, 0, 61, 62, 0, 63, 64, 1, + 0, 2, 3, 4, 5, 6, 0, 7, 8, 9, + 10, 11, 0, 0, 0, 12, 0, 13, 14, 0, + 0, 0, 0, 15, 16, 0, 0, 17, 18, 0, + 0, 0, 0, 19, 20, 21, 0, 0, 22, 0, + 0, 0, 236, 0, 23, 24, 0, 0, 0, 0, + 25, 26, 27, 0, 0, 28, 0, 0, 0, 0, + 29, 30, 0, 31, 237, 0, 0, 32, 33, 34, + 0, 35, 36, 37, 0, 0, 38, 0, 39, 0, + 40, 41, 42, 0, 43, 44, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, 0, 53, 54, 0, 55, 0, 0, 56, + 57, 58, 0, 59, 0, 60, 0, 61, 62, 0, + 63, 64, 1, 0, 2, 3, 4, 5, 6, 0, + 7, 8, 9, 10, 11, 0, 0, 0, 12, 0, + 13, 14, 0, 0, 0, 0, 15, 16, 0, 0, + 17, 18, 0, 0, 0, 0, 19, 20, 21, 0, + 0, 22, 0, 0, 0, 0, 0, 23, 24, 0, + 0, 0, 0, 25, 26, 27, 0, 0, 28, 0, + 0, 0, 0, 29, 30, 0, 31, 0, 0, 0, + 32, 33, 34, 0, 35, 36, 37, 0, 0, 38, + -201, 39, 240, 40, 41, 42, 0, 43, 44, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 50, 51, 52, 0, 53, 54, 0, 55, + 0, 0, 56, 57, 58, 0, 59, 0, 60, 0, + 61, 62, 0, 63, 64, 1, 0, 2, 3, 4, + 5, 6, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 12, 0, 13, 14, 0, 0, 0, 0, 15, + 16, 0, 0, 17, 18, 0, 0, 0, 0, 19, + 20, 21, 0, 0, 22, 0, 0, 0, 236, 0, + 23, 24, 0, 0, 0, 0, 25, 26, 27, 0, + 0, 28, 0, 0, 0, 0, 29, 30, 0, 31, + 0, 0, 0, 32, 33, 34, 0, 35, 36, 37, + 0, 260, 38, 0, 39, 0, 40, 41, 42, 0, + 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, + 0, 0, 48, 261, 0, 50, 51, 52, 0, 53, + 54, 0, 55, 0, 0, 56, 57, 58, 0, 59, + 0, 60, 0, 61, 62, 0, 63, 64, 1, 0, + 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, + 11, 0, 0, 0, 12, 0, 13, 14, 0, 0, + 0, 0, 15, 16, 0, 0, 17, 18, 0, 0, + 0, 0, 19, 20, 21, 0, 0, 22, 0, 0, + 0, 236, 0, 23, 24, 0, 0, 0, 265, 25, + 26, 27, 0, 0, 28, 0, 0, 0, 0, 29, + 30, 0, 31, 0, 0, 0, 32, 33, 34, 0, + 35, 36, 37, 0, 0, 38, 0, 39, 0, 40, + 41, 42, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 48, 266, 0, 50, 51, + 52, 0, 53, 54, 0, 55, 0, 0, 56, 57, + 58, 0, 59, 0, 60, 0, 61, 62, 0, 63, + 64, 1, 0, 2, 3, 4, 5, 6, 0, 7, + 8, 9, 10, 11, 0, 0, 0, 12, 0, 13, + 14, 0, 0, 0, 0, 15, 16, 0, 0, 17, + 18, 0, 0, 0, 0, 19, 20, 21, 0, 0, + 22, 0, 0, 0, 236, 0, 23, 24, 0, 0, + 275, 0, 25, 26, 27, 0, 0, 28, 0, 0, + 0, 0, 29, 30, 0, 31, 0, 0, 0, 32, + 33, 34, 0, 35, 36, 37, 0, 0, 38, 0, + 39, 0, 40, 41, 42, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 48, 49, + 0, 50, 51, 52, 0, 53, 54, 0, 55, 0, + 0, 56, 57, 58, 0, 59, 0, 60, 0, 61, + 62, 0, 63, 64, 1, 0, 2, 3, 4, 5, + 6, 0, 7, 8, 9, 10, 11, 0, 0, 0, + 12, 0, 13, 14, 0, 0, 0, 0, 15, 16, + 0, 0, 17, 18, 0, 0, 0, 0, 19, 20, + 21, 0, 0, 22, 0, 0, 0, 236, 0, 23, + 24, 0, 0, 0, 0, 25, 26, 27, 0, 0, + 28, 0, 0, 0, 0, 29, 30, 0, 31, 0, + 0, 0, 32, 33, 34, 0, 35, 36, 37, 0, + 366, 38, 0, 39, 0, 40, 41, 42, 0, 43, + 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, + 0, 48, 49, 0, 50, 51, 52, 0, 53, 54, + 0, 55, 0, 0, 56, 57, 58, 0, 59, 0, + 60, 0, 61, 62, 0, 63, 64, 1, 0, 2, + 3, 4, 5, 6, 0, 7, 8, 9, 10, 11, + 0, 0, 0, 12, 0, 13, 14, 0, 0, 0, + 0, 15, 16, 0, 0, 17, 18, 0, 0, 0, + 0, 19, 20, 21, 0, 0, 22, 0, 0, 0, + 236, 0, 23, 24, 0, 0, 0, 0, 25, 26, + 27, 0, 0, 28, 0, 0, 0, 0, 29, 30, + 0, 31, 0, 0, 0, 32, 33, 34, 0, 35, + 36, 37, 0, -258, 38, 0, 39, 0, 40, 41, + 42, 0, 43, 44, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, 47, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 0, 50, 51, 52, + 0, 53, 54, 0, 55, 0, 0, 56, 57, 58, + 0, 59, 0, 60, 0, 61, 62, 0, 63, 64, + 1, 0, 2, 3, 4, 5, 6, 0, 7, 8, + 9, 10, 11, 0, 0, 0, 12, 0, 13, 14, + 0, 0, 0, 0, 15, 16, 0, 0, 17, 18, + 0, 0, 0, 0, 19, 20, 21, 0, 0, 22, + 0, 0, 0, 236, 0, 23, 24, 0, 0, 0, + 0, 25, 26, 27, 0, -255, 28, 0, 0, 0, + 0, 29, 30, 0, 31, 0, 0, 0, 32, 33, + 34, 0, 35, 36, 37, 0, 0, 38, 0, 39, + 0, 40, 41, 42, 0, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 50, 51, 52, 0, 53, 54, 0, 55, 0, 0, + 56, 57, 58, 0, 59, 0, 60, 0, 61, 62, + 0, 63, 64, 1, 0, 2, 3, 4, 5, 6, + 0, 7, 8, 9, 10, 11, 0, 0, 0, 12, + 0, 13, 14, 0, 0, 0, 0, 15, 16, 0, + 0, 17, 18, 0, 0, 0, 0, 19, 20, 21, + 0, 0, 22, 0, 0, 0, 236, 0, 23, 24, + 0, 0, 0, 0, 25, 26, 27, 0, 0, 28, + 0, 0, 0, 0, 29, 30, 0, 31, 0, 0, + 0, 32, 33, 34, 0, 35, 36, 37, 0, 434, + 38, 0, 39, 0, 40, 41, 42, 0, 43, 44, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 0, 50, 51, 52, 0, 53, 54, 0, + 55, 0, 0, 56, 57, 58, 0, 59, 0, 60, + 0, 61, 62, 0, 63, 64, 1, 0, 2, 3, + 4, 5, 6, 0, 7, 8, 9, 10, 11, 0, + 0, 0, 12, 0, 13, 14, 0, 0, 0, 0, + 15, 16, 0, 0, 17, 18, 0, 0, 0, 0, + 19, 20, 21, 0, 0, 22, 0, 0, 0, 236, + 0, 23, 24, 0, 0, 0, 0, 25, 26, 27, + 0, 0, 28, 0, 0, 0, 0, 29, 30, 0, + 31, 0, 0, 0, 32, 33, 34, 0, 35, 36, + 37, 0, 435, 38, 0, 39, 0, 40, 41, 42, + 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 48, 49, 0, 50, 51, 52, 0, + 53, 54, 0, 55, 0, 0, 56, 57, 58, 0, + 59, 0, 60, 0, 61, 62, 0, 63, 64, 1, + 0, 2, 3, 4, 5, 6, 0, 7, 8, 9, + 10, 11, 0, 0, 0, 12, 0, 13, 14, 0, + 0, 0, 0, 15, 16, 0, 0, 17, 18, 0, + 0, 0, 0, 19, 20, 21, 0, 0, 22, 0, + 0, 0, 236, 0, 23, 24, 0, 0, 0, 0, + 25, 26, 27, 0, 0, 28, 0, 0, 0, 0, + 29, 30, 0, 31, 0, 0, 0, 32, 33, 34, + 0, 35, 36, 37, 0, 439, 38, 0, 39, 0, + 40, 41, 42, 0, 43, 44, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, 0, 53, 54, 0, 55, 0, 0, 56, + 57, 58, 0, 59, 0, 60, 0, 61, 62, 0, + 63, 64, 1, 0, 2, 3, 4, 5, 6, 0, + 7, 8, 9, 10, 11, 0, 0, 0, 12, 0, + 13, 14, 0, 0, 0, 0, 15, 16, 0, 0, + 17, 18, 0, 0, 0, 0, 19, 20, 21, 0, + 0, 22, 0, 0, 0, 0, 0, 23, 24, 0, + 0, 0, 0, 25, 26, 27, 0, 0, 28, 0, + 0, 0, 0, 29, 30, 0, 31, 0, 0, 0, + 32, 33, 34, 0, 35, 36, 37, 494, 0, 38, + 362, 39, 0, 40, 41, 42, 0, 43, 44, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 50, 51, 52, 0, 53, 54, 0, 55, + 0, 0, 56, 57, 58, 0, 59, 0, 60, 0, + 61, 62, 0, 63, 64, 1, 0, 2, 3, 4, + 5, 6, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 12, 0, 13, 14, 0, 0, 0, 0, 15, + 16, 0, 0, 17, 18, 0, 0, 0, 0, 19, + 20, 21, 0, 0, 22, 0, 0, 0, 236, 0, + 23, 24, 0, 0, 0, 0, 25, 26, 27, 0, + 0, 28, 0, 0, 0, 0, 29, 30, 0, 31, + 0, 0, 0, 32, 33, 34, 0, 35, 36, 37, + 0, 502, 38, 0, 39, 0, 40, 41, 42, 0, + 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, + 0, 0, 48, 49, 0, 50, 51, 52, 0, 53, + 54, 0, 55, 0, 0, 56, 57, 58, 0, 59, + 0, 60, 0, 61, 62, 0, 63, 64, 1, 0, + 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, + 11, 0, 0, 0, 12, 0, 13, 14, 0, 0, + 0, 0, 15, 16, 0, 0, 17, 18, 0, 0, + 0, 0, 19, 20, 21, 0, 0, 22, 0, 0, + 0, 236, 0, 23, 24, 0, 0, 0, 0, 25, + 26, 27, 0, 0, 28, 0, 0, 0, 0, 29, + 30, 0, 31, 0, 0, 0, 32, 33, 34, 0, + 35, 36, 37, 0, 533, 38, 0, 39, 0, 40, + 41, 42, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 48, 49, 0, 50, 51, + 52, 0, 53, 54, 0, 55, 0, 0, 56, 57, + 58, 0, 59, 0, 60, 0, 61, 62, 0, 63, + 64, 1, 0, 2, 3, 4, 5, 6, 0, 7, + 8, 9, 10, 11, 0, 0, 0, 12, 0, 13, + 14, 0, 0, 0, 0, 15, 16, 0, 0, 17, + 18, 0, 0, 0, 0, 19, 20, 21, 0, 0, + 22, 0, 0, 0, 236, 0, 23, 24, 0, 0, + 0, 0, 25, 26, 27, 0, 0, 28, 0, 0, + 0, 0, 29, 30, 0, 31, 0, 0, 0, 32, + 33, 34, 0, 35, 36, 37, 0, 537, 38, 0, + 39, 0, 40, 41, 42, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 48, 49, + 0, 50, 51, 52, 0, 53, 54, 0, 55, 0, + 0, 56, 57, 58, 0, 59, 0, 60, 0, 61, + 62, 0, 63, 64, 1, 0, 2, 3, 4, 5, + 6, 0, 7, 8, 9, 10, 11, 0, 0, 0, + 12, 0, 13, 14, 0, 0, 0, 0, 15, 16, + 0, 0, 17, 18, 0, 0, 0, 0, 19, 20, + 21, 0, 0, 22, 0, 0, 0, 236, 0, 23, + 24, 0, 0, 0, 0, 25, 26, 27, 0, 0, + 28, 0, 0, 0, 0, 29, 30, 0, 31, 0, + 0, 0, 32, 33, 34, 0, 35, 36, 37, 0, + 540, 38, 0, 39, 0, 40, 41, 42, 0, 43, + 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, + 0, 48, 49, 0, 50, 51, 52, 0, 53, 54, + 0, 55, 0, 0, 56, 57, 58, 0, 59, 0, + 60, 0, 61, 62, 0, 63, 64, 1, 0, 2, + 3, 4, 5, 6, 0, 7, 8, 9, 10, 11, + 0, 0, 0, 12, 0, 13, 14, 0, 0, 0, + 0, 15, 16, 0, 0, 17, 18, 0, 0, 0, + 0, 19, 20, 21, 0, 0, 22, 0, 0, 0, + 236, 0, 23, 24, 0, 0, 0, 0, 25, 26, + 27, 0, 0, 28, 0, 0, 0, 0, 29, 30, + 0, 31, 0, 0, 0, 32, 33, 34, 0, 35, + 36, 37, 0, 547, 38, 0, 39, 0, 40, 41, + 42, 0, 43, 44, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, 47, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 0, 50, 51, 52, + 0, 53, 54, 0, 55, 0, 0, 56, 57, 58, + 0, 59, 0, 60, 0, 61, 62, 0, 63, 64, + 1, 0, 2, 3, 4, 5, 6, 0, 7, 8, + 9, 10, 11, 0, 0, 0, 12, 0, 13, 14, + 0, 0, 0, 0, 15, 16, 0, 0, 17, 18, + 0, 0, 0, 0, 19, 20, 21, 0, 0, 22, + 0, 0, 0, 236, 0, 23, 24, 0, 0, 0, + 0, 25, 26, 27, 0, 0, 28, 0, 0, 0, + 0, 29, 30, 0, 31, 0, 0, 0, 32, 33, + 34, 0, 35, 36, 37, 0, 562, 38, 0, 39, + 0, 40, 41, 42, 0, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 50, 51, 52, 0, 53, 54, 0, 55, 0, 0, + 56, 57, 58, 0, 59, 0, 60, 0, 61, 62, + 0, 63, 64, 1, 0, 2, 3, 4, 5, 6, + 0, 7, 8, 9, 10, 11, 0, 0, 0, 12, + 0, 13, 14, 0, 0, 0, 0, 15, 16, 0, + 0, 17, 18, 0, 0, 0, 0, 19, 20, 21, + 0, 0, 22, 0, 0, 0, 236, 0, 23, 24, + 0, 0, 0, 0, 25, 26, 27, 0, 0, 28, + 0, 0, 0, 0, 29, 30, 0, 31, 0, 0, + 0, 32, 33, 34, 0, 35, 36, 37, 0, 564, + 38, 0, 39, 0, 40, 41, 42, 0, 43, 44, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 0, 50, 51, 52, 0, 53, 54, 0, + 55, 0, 0, 56, 57, 58, 0, 59, 0, 60, + 0, 61, 62, 0, 63, 64, 1, 0, 2, 3, + 4, 5, 6, 0, 7, 8, 9, 10, 11, 0, + 0, 0, 12, 0, 13, 14, 0, 0, 0, 0, + 15, 16, 0, 0, 17, 18, 0, 0, 0, 0, + 19, 20, 21, 0, 0, 22, 0, 0, 0, 236, + 0, 23, 24, 0, 0, 0, 0, 25, 26, 27, + 0, 0, 28, 0, 0, 0, 0, 29, 30, 0, + 31, 0, 0, 0, 32, 33, 34, 0, 35, 36, + 37, 0, 574, 38, 0, 39, 0, 40, 41, 42, + 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 48, 49, 0, 50, 51, 52, 0, + 53, 54, 0, 55, 0, 0, 56, 57, 58, 0, + 59, 0, 60, 0, 61, 62, 0, 63, 64, 1, + 0, 2, 3, 4, 5, 6, 0, 7, 8, 9, + 10, 11, 0, 0, 0, 12, 0, 13, 14, 0, + 0, 0, 0, 15, 16, 0, 0, 17, 18, 0, + 0, 0, 0, 19, 20, 21, 0, 0, 22, 0, + 0, 0, 236, 0, 23, 24, 0, 0, 0, 0, + 25, 26, 27, 0, 0, 28, 0, 0, 0, 0, + 29, 30, 0, 31, 0, 0, 0, 32, 33, 34, + 0, 35, 36, 37, 0, 581, 38, 0, 39, 0, + 40, 41, 42, 0, 43, 44, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, 0, 53, 54, 0, 55, 0, 0, 56, + 57, 58, 0, 59, 0, 60, 0, 61, 62, 0, + 63, 64, 1, 0, 2, 3, 4, 5, 6, 0, + 7, 8, 9, 10, 11, 0, 0, 0, 12, 0, + 13, 14, 0, 0, 0, 0, 15, 16, 0, 0, + 17, 18, 0, 0, 0, 0, 19, 20, 21, 0, + 0, 22, 0, 0, 0, 236, 0, 23, 24, 0, + 0, 0, 0, 25, 26, 27, 0, 0, 28, 0, + 0, 0, 0, 29, 30, 0, 31, 0, 0, 0, + 32, 33, 34, 0, 35, 36, 37, 0, 582, 38, + 0, 39, 0, 40, 41, 42, 0, 43, 44, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 50, 51, 52, 0, 53, 54, 0, 55, + 0, 0, 56, 57, 58, 0, 59, 0, 60, 0, + 61, 62, 0, 63, 64, 1, 0, 2, 3, 4, + 5, 6, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 12, 0, 13, 14, 0, 0, 0, 0, 15, + 16, 0, 0, 17, 18, 0, 0, 0, 0, 19, + 20, 21, 0, 0, 22, 0, 0, 0, 236, 0, + 23, 24, 0, 0, 0, 0, 25, 26, 27, 0, + 0, 28, 0, 0, 0, 0, 29, 30, 0, 31, + 0, 0, 0, 32, 33, 34, 0, 35, 36, 37, + 0, 583, 38, 0, 39, 0, 40, 41, 42, 0, + 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, + 0, 0, 48, 49, 0, 50, 51, 52, 0, 53, + 54, 0, 55, 0, 0, 56, 57, 58, 0, 59, + 0, 60, 0, 61, 62, 0, 63, 64, 1, 0, + 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, + 11, 0, 0, 0, 12, 0, 13, 14, 0, 0, + 0, 0, 15, 16, 0, 0, 17, 18, 0, 0, + 0, 0, 19, 20, 21, 0, 0, 22, 0, 0, + 0, 236, 0, 23, 24, 0, 0, 0, 0, 25, + 26, 27, 0, 0, 28, 0, 0, 0, 0, 29, + 30, 0, 31, 0, 0, 0, 32, 33, 34, 0, + 35, 36, 37, 0, 584, 38, 0, 39, 0, 40, + 41, 42, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 48, 49, 0, 50, 51, + 52, 0, 53, 54, 0, 55, 0, 0, 56, 57, + 58, 0, 59, 0, 60, 0, 61, 62, 0, 63, + 64, 1, 0, 2, 3, 4, 5, 6, 0, 7, + 8, 9, 10, 11, 0, 0, 0, 12, 0, 13, + 14, 0, 0, 0, 0, 15, 16, 0, 0, 17, + 18, 0, 0, 0, 0, 19, 20, 21, 0, 0, + 22, 0, 0, 0, 236, 0, 23, 24, 0, 0, + 0, 0, 25, 26, 27, 0, 0, 28, 0, 0, + 0, 0, 29, 30, 0, 31, 0, 0, 0, 32, + 33, 34, 0, 35, 36, 37, 0, 585, 38, 0, + 39, 0, 40, 41, 42, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 48, 49, + 0, 50, 51, 52, 0, 53, 54, 0, 55, 0, + 0, 56, 57, 58, 0, 59, 0, 60, 0, 61, + 62, 0, 63, 64, 1, 0, 2, 3, 4, 5, + 6, 0, 7, 8, 9, 10, 11, 0, 0, 0, + 12, 0, 13, 14, 0, 0, 0, 0, 15, 16, + 0, 0, 17, 18, 0, 0, 0, 0, 19, 20, + 21, 0, 0, 22, 0, 0, 0, 0, 0, 23, + 24, 0, 0, 0, 0, 25, 26, 27, 0, 0, + 28, 0, 0, 0, 0, 29, 30, 0, 31, 0, + 0, 0, 32, 33, 34, 0, 35, 36, 37, 0, + 380, 38, 0, 39, 0, 40, 41, 42, 0, 43, + 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, + 0, 48, 49, 587, 50, 51, 52, 0, 53, 54, + 0, 55, 0, 0, 56, 57, 58, 0, 59, 0, + 60, 0, 61, 62, 0, 63, 64, 1, 0, 2, + 3, 4, 5, 6, 0, 7, 8, 9, 10, 11, + 0, 0, 0, 12, 0, 13, 14, 0, 0, 0, + 0, 15, 16, 0, 0, 17, 18, 0, 0, 0, + 0, 19, 20, 21, 0, 0, 22, 0, 0, 0, + 236, 0, 23, 24, 0, 0, 0, 0, 25, 26, + 27, 0, 0, 28, 0, 0, 0, 0, 29, 30, + 0, 31, 0, 0, 0, 32, 33, 34, 0, 35, + 36, 37, 0, 591, 38, 0, 39, 0, 40, 41, + 42, 0, 43, 44, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, 47, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 0, 50, 51, 52, + 0, 53, 54, 0, 55, 0, 0, 56, 57, 58, + 0, 59, 0, 60, 0, 61, 62, 0, 63, 64, + 1, 0, 2, 3, 4, 5, 6, 0, 7, 8, + 9, 10, 11, 89, 0, 0, 12, 0, 13, 14, + 0, 0, 0, 0, 15, 16, 0, 0, 17, 18, + 0, 0, 0, 0, 19, 20, 21, 0, 0, 22, + 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, + 0, 25, 26, 27, 0, 0, 28, 0, 0, 0, + 0, 29, 30, 0, 31, 0, 0, 0, 32, 33, + 34, 0, 35, 36, 37, 0, 0, 38, 0, 39, + 0, 40, 41, 42, 0, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 50, 51, 52, 0, 53, 54, 0, 55, 0, 0, + 56, 57, 58, 0, 59, 0, 60, 0, 61, 62, + 0, 63, 64, 1, 0, 2, 3, 4, 5, 6, + 0, 7, 8, 9, 10, 11, 0, 0, 0, 12, + 0, 13, 14, 0, 0, 0, 0, 15, 16, 0, + 0, 17, 18, 0, 0, 0, 0, 19, 20, 21, + 0, 0, 22, -221, 0, 0, 0, 0, 23, 24, + 0, 0, 0, 0, 25, 26, 27, 0, 0, 28, + 0, 0, 0, 0, 29, 30, 0, 31, 0, 0, + 0, 32, 33, 34, 0, 35, 36, 37, 0, 0, + 38, 0, 39, 0, 40, 41, 42, 0, 43, 44, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 0, 50, 51, 52, 0, 53, 54, 0, + 55, 0, 0, 56, 57, 58, 0, 59, 0, 60, + 0, 61, 62, 0, 63, 64, 1, 0, 2, 3, + 4, 5, 6, 0, 7, 8, 9, 10, 11, 0, + 0, 0, 12, 0, 13, 14, 0, 0, 0, 0, + 15, 16, 0, 0, 17, 18, 0, 0, 0, 0, + 19, 20, 21, 0, 0, 22, 0, 0, 0, 0, + 0, 23, 24, 0, 0, 0, 0, 25, 26, 27, + 0, 0, 28, 0, 0, 0, 0, 29, 30, 0, + 31, 0, 0, 0, 32, 33, 34, 0, 35, 36, + 37, 115, 0, 38, 0, 39, 0, 40, 41, 42, + 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 48, 49, 0, 50, 51, 52, 0, + 53, 54, 0, 55, 0, 0, 56, 57, 58, 0, + 59, 0, 60, 0, 61, 62, 0, 63, 64, 1, + 0, 2, 3, 4, 5, 6, 0, 7, 8, 9, + 10, 11, 0, 0, 0, 12, 204, 13, 14, 0, + 0, 0, 0, 15, 16, 0, 0, 17, 18, 0, + 0, 0, 0, 19, 20, 21, 0, 0, 22, 0, + 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, + 25, 26, 27, 0, 0, 28, 0, 0, 0, 0, + 29, 30, 0, 31, 0, 0, 0, 32, 33, 34, + 0, 35, 36, 37, 0, 0, 38, 0, 39, 0, + 40, 41, 42, 0, 43, 44, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, 0, 53, 54, 0, 55, 0, 0, 56, + 57, 58, 0, 59, 0, 60, 0, 61, 62, 0, + 63, 64, 1, 0, 2, 3, 4, 5, 6, 0, + 7, 8, 9, 10, 11, 0, 0, 0, 12, 206, + 13, 14, 0, 0, 0, 0, 15, 16, 0, 0, + 17, 18, 0, 0, 0, 0, 19, 20, 21, 0, + 0, 22, 0, 0, 0, 0, 0, 23, 24, 0, + 0, 0, 0, 25, 26, 27, 0, 0, 28, 0, + 0, 0, 0, 29, 30, 0, 31, 0, 0, 0, + 32, 33, 34, 0, 35, 36, 37, 0, 0, 38, + 0, 39, 0, 40, 41, 42, 0, 43, 44, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 50, 51, 52, 0, 53, 54, 0, 55, + 0, 0, 56, 57, 58, 0, 59, 0, 60, 0, + 61, 62, 0, 63, 64, 1, 0, 2, 3, 4, + 5, 6, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 12, 0, 13, 14, 0, 0, 0, 0, 15, + 16, 0, 0, 17, 18, 0, 0, 0, 0, 19, + 20, 21, 0, 0, 22, 0, 0, 0, -219, 0, + 23, 24, 0, 0, 0, 0, 25, 26, 27, 0, + 0, 28, 0, 0, 0, 0, 29, 30, 0, 31, + 0, 0, 0, 32, 33, 34, 0, 35, 36, 37, + 0, 0, 38, 0, 39, 0, 40, 41, 42, 0, + 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, + 0, 0, 48, 49, 0, 50, 51, 52, 0, 53, + 54, 0, 55, 0, 0, 56, 57, 58, 0, 59, + 0, 60, 0, 61, 62, 0, 63, 64, 1, 0, + 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, + 11, 0, 0, 0, 12, -221, 13, 14, 0, 0, + 0, 0, 15, 16, 0, 0, 17, 18, 0, 0, + 0, 0, 19, 20, 21, 0, 0, 22, 0, 0, + 0, 0, 0, 23, 24, 0, 0, 0, 0, 25, + 26, 27, 0, 0, 28, 0, 0, 0, 0, 29, + 30, 0, 31, 0, 0, 0, 32, 33, 34, 0, + 35, 36, 37, 0, 0, 38, 0, 39, 0, 40, + 41, 42, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 48, 49, 0, 50, 51, + 52, 0, 53, 54, 0, 55, 0, 0, 56, 57, + 58, 0, 59, 0, 60, 0, 61, 62, 0, 63, + 64, 1, 0, 2, 3, 4, 5, 6, 0, 7, + 8, 9, 10, 11, 0, 0, 0, 12, 271, 13, + 14, 0, 0, 0, 0, 15, 16, 0, 0, 17, + 18, 0, 0, 0, 0, 19, 20, 21, 0, 0, + 22, 0, 0, 0, 0, 0, 23, 24, 0, 0, + 0, 0, 25, 26, 27, 0, 0, 28, 0, 0, + 0, 0, 29, 30, 0, 31, 0, 0, 0, 32, + 33, 34, 0, 35, 36, 37, 0, 0, 38, 0, + 39, 0, 40, 41, 42, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 48, 49, + 0, 50, 51, 52, 0, 53, 54, 0, 55, 0, + 0, 56, 57, 58, 0, 59, 0, 60, 0, 61, + 62, 0, 63, 64, 1, 0, 2, 3, 4, 5, + 6, 302, 7, 8, 9, 10, 11, 0, 0, 0, + 12, 0, 13, 14, 0, 0, 0, 0, 15, 16, + 0, 0, 17, 18, 0, 0, 0, 0, 19, 20, + 21, 0, 0, 22, 0, 0, 0, 0, 0, 23, + 24, 0, 0, 0, 0, 25, 26, 27, 0, 0, + 28, 0, 0, 0, 0, 29, 30, 0, 31, 0, + 0, 0, 32, 33, 34, 0, 35, 36, 37, 0, + 0, 38, 0, 39, 0, 40, 41, 42, 0, 43, + 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, + 0, 48, 49, 0, 50, 51, 52, 0, 53, 54, + 0, 55, 0, 0, 56, 57, 58, 0, 59, 0, + 60, 0, 61, 62, 0, 63, 64, 1, 0, 2, + 3, 4, 5, 6, 0, 7, 8, 9, 10, 11, + 0, 0, 0, 12, 0, 13, 14, 0, 0, 0, + 0, 15, 16, 0, 0, 17, 18, 0, 0, 0, + 0, 19, 20, 21, 0, 0, 22, 0, 0, 0, + 0, 0, 23, 24, 0, 0, 0, 0, 25, 26, + 27, 0, 0, 28, 0, 0, 0, 0, 29, 30, + 0, 31, 0, 0, 0, 32, 33, 34, 0, 35, + 36, 37, 0, 0, 38, 362, 39, 0, 40, 41, + 42, 0, 43, 44, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, 47, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 0, 50, 51, 52, + 0, 53, 54, 0, 55, 0, 0, 56, 57, 58, + 0, 59, 0, 60, 0, 61, 62, 0, 63, 64, + 1, 0, 2, 3, 4, 5, 6, 0, 7, 8, + 9, 10, 11, 0, 0, 0, 12, 0, 13, 14, + 0, 0, 0, 0, 15, 16, 0, 0, 17, 18, + 0, 0, 0, 0, 19, 20, 21, 0, 0, 22, + 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, + 0, 25, 26, 27, 0, 0, 28, 0, 0, 0, + 0, 29, 30, 0, 31, 0, 0, 0, 32, 33, + 34, 0, 35, 36, 37, 0, 380, 38, 0, 39, + 0, 40, 41, 42, 0, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 50, 51, 52, 0, 53, 54, 0, 55, 0, 0, + 56, 57, 58, 0, 59, 0, 60, 0, 61, 62, + 0, 63, 64, 1, 0, 2, 3, 4, 5, 6, + 0, 7, 8, 9, 10, 11, 0, 0, 0, 12, + 0, 13, 14, 0, 0, 0, 0, 15, 16, 0, + 0, 17, 18, 0, 0, 0, 0, 19, 20, 21, + 0, 0, 22, 0, 0, 0, 0, 0, 23, 24, + 0, 0, 0, 0, 25, 26, 27, 0, 0, 28, + 0, 0, 0, 0, 29, 30, 0, 31, 0, 0, + 0, 32, 33, 34, 0, 35, 36, 37, 0, 260, + 38, 0, 39, 0, 40, 41, 42, 0, 43, 44, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, + 48, 261, 0, 50, 51, 52, 0, 53, 54, 0, + 55, 0, 0, 56, 57, 58, 0, 59, 0, 60, + 0, 61, 62, 0, 63, 64, 1, 0, 2, 3, + 4, 5, 6, 0, 7, 8, 9, 10, 11, 0, + 0, 0, 12, 0, 13, 14, 0, 0, 0, 0, + 15, 16, 0, 0, 17, 18, 0, 0, 0, 0, + 19, 20, 21, 0, 0, 22, 0, 0, 0, 0, + 0, 23, 24, 0, 0, 0, 385, 25, 26, 27, + 0, 0, 28, 0, 0, 0, 0, 29, 30, 0, + 31, 0, 0, 0, 32, 33, 34, 0, 35, 36, + 37, 0, 0, 38, 0, 39, 0, 40, 41, 42, + 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 48, 49, 0, 50, 51, 52, 0, + 53, 54, 0, 55, 0, 0, 56, 57, 58, 0, + 59, 0, 60, 0, 61, 62, 0, 63, 64, 1, + 0, 2, 3, 4, 5, 6, 0, 7, 8, 9, + 10, 11, 0, 0, 0, 12, 0, 13, 14, 0, + 0, 0, 0, 15, 16, 0, 0, 17, 18, 0, + 0, 0, 0, 19, 20, 21, 0, 0, 22, 0, + 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, + 25, 26, 27, 0, 0, 28, 0, 0, 0, 0, + 29, 30, 0, 31, 0, 0, 0, 32, 33, 34, + 0, 35, 508, 37, 115, 0, 38, 0, 39, 0, + 40, 41, 42, 0, 43, 44, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, 0, 53, 54, 0, 55, 0, 0, 56, + 57, 58, 0, 59, 0, 60, 0, 61, 62, 0, + 63, 64, 1, 0, 2, 3, 4, 5, 6, 0, + 7, 8, 9, 10, 11, 0, 0, 0, 12, -219, + 13, 14, 0, 0, 0, 0, 15, 16, 0, 0, + 17, 18, 0, 0, 0, 0, 19, 20, 21, 0, + 0, 22, 0, 0, 0, 0, 0, 23, 24, 0, + 0, 0, 0, 25, 26, 27, 0, 0, 28, 0, + 0, 0, 0, 29, 30, 0, 31, 0, 0, 0, + 32, 33, 34, 0, 35, 36, 37, 0, 0, 38, + 0, 39, 0, 40, 41, 42, 0, 43, 44, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 50, 51, 52, 0, 53, 54, 0, 55, + 0, 0, 56, 57, 58, 0, 59, 0, 60, 0, + 61, 62, 0, 63, 64, 1, 0, 2, 3, 4, + 5, 6, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 12, 0, 13, 14, 0, 0, 0, 0, 15, + 16, 0, 0, 17, 18, 0, 0, 0, 0, 19, + 20, 21, 0, 0, 22, 0, 0, 0, 0, 0, + 23, 24, 0, 0, 0, 0, 25, 26, 27, 0, + 0, 28, 0, 0, 0, 0, 29, 30, 0, 31, + 0, 0, 0, 32, 33, 34, 0, 35, 36, 37, + 0, 0, 38, 0, 39, 0, 40, 41, 42, 0, + 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, + 0, 0, 48, 49, 0, 50, 51, 52, 0, 53, + 54, 0, 55, 543, 0, 56, 57, 58, 0, 59, + 0, 60, 0, 61, 62, 0, 63, 64, 1, 0, + 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, + 11, 0, 0, 0, 12, 0, 13, 14, 0, 0, + 0, 0, 15, 16, 0, 0, 17, 18, 0, 0, + 0, 0, 19, 20, 21, 0, 0, 22, 0, 0, + 0, 0, 0, 23, 24, 0, 0, 0, 0, 25, + 26, 27, 0, 0, 28, 0, 0, 0, 0, 29, + 30, 0, 31, 0, 0, 0, 32, 33, 34, 0, + 35, 36, 37, 0, 0, 38, 0, 39, 0, 40, + 41, 42, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 48, 49, 565, 50, 51, + 52, 0, 53, 54, 0, 55, 0, 0, 56, 57, + 58, 0, 59, 0, 60, 0, 61, 62, 0, 63, + 64, 1, 0, 2, 3, 4, 5, 6, 0, 7, + 8, 9, 10, 11, 0, 0, 0, 12, 0, 13, + 14, 0, 0, 0, 0, 15, 16, 0, 0, 17, + 18, 0, 0, 0, 0, 19, 20, 21, 0, 0, + 22, 0, 0, 0, 0, 0, 23, 24, 0, 0, + 0, 0, 25, 26, 27, 0, 0, 28, 0, 0, + 0, 0, 29, 30, 0, 31, 0, 0, 0, 32, + 33, 34, 0, 35, 36, 37, 0, 0, 38, 0, + 39, 0, 40, 41, 42, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 48, 49, + 589, 50, 51, 52, 0, 53, 54, 0, 55, 0, + 0, 56, 57, 58, 0, 59, 0, 60, 0, 61, + 62, 0, 63, 64, 1, 0, 2, 3, 4, 5, + 6, 0, 7, 8, 9, 10, 11, 0, 0, 0, + 12, 0, 13, 14, 0, 0, 0, 0, 15, 16, + 0, 0, 17, 18, 0, 0, 0, 0, 19, 20, + 21, 0, 0, 22, 0, 0, 0, 0, 0, 23, + 24, 0, 0, 0, 0, 25, 26, 27, 0, 0, + 28, 0, 0, 0, 0, 29, 30, 0, 31, 0, + 0, 0, 32, 33, 34, 0, 35, 36, 37, 0, + 0, 38, 0, 39, 0, 40, 41, 42, 0, 43, + 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 47, 0, 0, 0, 0, 0, 0, + 0, 48, 49, 0, 50, 51, 52, 0, 53, 54, + 0, 55, 0, 0, 56, 57, 58, 0, 59, 0, + 60, 0, 61, 62, 0, 63, 64, 1, 0, 2, + 3, 4, 5, 6, 0, 7, 8, 9, 10, 85, + 0, 0, 0, 12, 0, 13, 14, 0, 0, 0, + 0, 15, 16, 0, 0, 17, 18, 0, 0, 0, + 0, 19, 20, 21, 0, 0, 22, 0, 0, 0, + 0, 0, 23, 24, 0, 0, 0, 0, 25, 26, + 27, 0, 0, 28, 0, 0, 0, 0, 29, 30, + 0, 31, 0, 0, 0, 32, 33, 34, 0, 35, + 36, 37, 0, 0, 86, 0, 39, 0, 40, 41, + 42, 0, 43, 44, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, 47, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 0, 50, 51, 52, + 0, 53, 54, 0, 55, 0, 0, 56, 57, 58, + 0, 59, 0, 60, 0, 61, 62, 0, 63, 64, + 1, 0, 2, 3, 4, 5, 6, 0, 7, 8, + 9, 10, 11, 0, 0, 0, 96, 0, 13, 14, + 0, 0, 0, 0, 15, 16, 0, 0, 17, 18, + 0, 0, 0, 0, 19, 20, 21, 0, 0, 22, + 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, + 0, 25, 26, 27, 0, 0, 28, 0, 0, 0, + 0, 29, 30, 0, 31, 0, 0, 0, 32, 33, + 34, 0, 35, 36, 37, 0, 0, 38, 0, 39, + 0, 40, 41, 42, 0, 43, 44, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, + 0, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 50, 51, 52, 0, 53, 54, 0, 55, 0, 0, + 56, 57, 58, 0, 59, 0, 60, 0, 61, 62, + 0, 63, 64, 1, 0, 2, 3, 4, 5, 6, + 0, 7, 8, 9, 10, 11, 0, 0, 0, 100, + 0, 13, 14, 0, 0, 0, 0, 15, 16, 0, + 0, 17, 18, 0, 0, 0, 0, 19, 20, 21, + 0, 0, 22, 0, 0, 0, 0, 0, 23, 24, + 0, 0, 0, 0, 25, 26, 27, 0, 0, 28, + 0, 0, 0, 0, 29, 30, 0, 31, 0, 0, + 0, 32, 33, 34, 0, 35, 36, 37, 0, 0, + 38, 0, 39, 0, 40, 41, 42, 0, 43, 44, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 47, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 0, 50, 51, 52, 0, 53, 54, 0, + 55, 0, 0, 56, 57, 58, 0, 59, 0, 60, + 0, 61, 62, 0, 63, 64, 1, 0, 2, 3, + 4, 5, 6, 0, 7, 8, 9, 10, 11, 0, + 0, 0, 110, 0, 13, 14, 0, 0, 0, 0, + 15, 16, 0, 0, 17, 18, 0, 0, 0, 0, + 19, 20, 21, 0, 0, 22, 0, 0, 0, 0, + 0, 23, 24, 0, 0, 0, 0, 25, 26, 27, + 0, 0, 28, 0, 0, 0, 0, 29, 30, 0, + 31, 0, 0, 0, 32, 33, 34, 0, 35, 36, + 37, 0, 0, 38, 0, 39, 0, 40, 41, 42, + 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 48, 49, 0, 50, 51, 52, 0, + 53, 54, 0, 55, 0, 0, 56, 57, 58, 0, + 59, 0, 60, 0, 61, 62, 0, 63, 64, 1, + 0, 2, 221, 4, 5, 6, 0, 7, 8, 9, + 10, 11, 0, 0, 0, 12, 0, 13, 14, 0, + 0, 0, 0, 15, 16, 0, 0, 17, 18, 0, + 0, 0, 0, 19, 20, 21, 0, 0, 22, 0, + 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, + 25, 26, 27, 0, 0, 28, 0, 0, 0, 0, + 29, 30, 0, 31, 0, 0, 0, 32, 33, 34, + 0, 35, 36, 37, 0, 0, 38, 0, 39, 0, + 40, 41, 42, 0, 43, 44, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, 0, 53, 54, 0, 55, 0, 0, 56, + 57, 58, 0, 59, 0, 60, 0, 61, 62, 0, + 63, 64, 1, 0, 2, 3, 4, 5, 6, 0, + 7, 8, 9, 10, 11, 0, 0, 0, 12, 0, + 13, 14, 0, 0, 0, 0, 15, 16, 0, 0, + 17, 18, 0, 0, 0, 0, 19, 20, 21, 0, + 0, 300, 0, 0, 0, 0, 0, 23, 24, 0, + 0, 0, 0, 25, 26, 27, 0, 0, 28, 0, + 0, 0, 0, 29, 30, 0, 31, 0, 0, 0, + 32, 33, 34, 0, 35, 36, 37, 0, 0, 38, + 0, 39, 0, 40, 41, 42, 0, 43, 44, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 48, + 49, 0, 50, 51, 52, 0, 53, 54, 0, 55, + 0, 0, 56, 57, 58, 0, 59, 0, 60, 0, + 61, 62, 0, 63, 64, 1, 0, 2, 3, 4, + 5, 6, 0, 7, 8, 9, 10, 11, 0, 0, + 0, 12, 0, 13, 14, 0, 0, 0, 0, 15, + 16, 0, 0, 17, 18, 0, 0, 0, 0, 19, + 20, 21, 0, 0, 457, 0, 0, 0, 0, 0, + 23, 24, 0, 0, 0, 0, 25, 26, 27, 0, + 0, 28, 0, 0, 0, 0, 29, 30, 0, 31, + 0, 0, 0, 32, 33, 34, 0, 35, 36, 37, + 0, 0, 38, 0, 39, 0, 40, 41, 42, 0, + 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 47, 0, 0, 0, 0, 0, + 0, 0, 48, 49, 0, 50, 51, 52, 0, 53, + 54, 0, 55, 0, 0, 56, 57, 58, 0, 59, + 0, 60, 0, 61, 62, 0, 63, 64, 1, 0, + 2, 3, 4, 5, 6, 0, 7, 8, 9, 10, + 11, 0, 0, 0, 12, 0, 13, 14, 0, 0, + 0, 0, 15, 16, 0, 0, 17, 18, 0, 0, + 0, 0, 19, 20, 21, 0, 0, 22, 0, 0, + 0, 0, 0, 23, 24, 0, 0, 0, 0, 25, + 26, 27, 0, 0, 28, 0, 0, 0, 0, 29, + 30, 0, 31, 0, 0, 0, 32, 33, 34, 0, + 35, 36, 37, 0, 0, 38, 0, 39, 0, 40, + 41, 42, 0, 43, 44, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 48, 541, 0, 50, 51, + 52, 0, 53, 54, 0, 55, 0, 0, 56, 57, + 58, 0, 59, 0, 60, 0, 61, 62, 0, 63, + 64, 1, 0, 2, 3, 4, 5, 6, 0, 7, + 8, 9, 10, 11, 0, 0, 0, 12, 0, 13, + 14, 0, 0, 0, 0, 15, 16, 0, 0, 17, + 18, 0, 0, 0, 0, 19, 20, 21, 0, 0, + 22, 0, 0, 0, 0, 0, 23, 24, 0, 0, + 0, 0, 25, 26, 27, 0, 0, 28, 0, 0, + 0, 0, 29, 30, 0, 31, 0, 0, 0, 32, + 33, 34, 0, 35, 36, 37, 0, 0, 38, 0, + 39, 0, 40, 41, 42, 0, 43, 44, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 48, 569, + 0, 50, 51, 52, 0, 53, 54, 0, 55, 0, + 0, 56, 57, 58, 0, 59, 0, 60, 0, 61, + 62, 0, 63, 64, 222, 159, 0, 160, 161, 162, + 163, 0, 164, 165, 166, 167, 168, 169, 0, 0, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 0, 0, 0, 0, 0, 0, 183, 0, + 0, 0, 0, 0, 0, 0, 0, 159, 223, 160, + 161, 162, 163, 0, 164, 165, 166, 167, 168, 169, + 184, 0, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 0, 0, 0, 0, 185, 0, + 183, 0, 0, 0, 0, 217, 0, 0, 159, 0, + 0, 0, 0, 163, 0, 164, 165, 166, 167, 393, + 169, 0, 184, 170, 0, 0, 173, 186, 175, 176, + 187, 178, 179, 188, 181, 0, 0, 189, 190, 0, + 185, 191, 0, 0, 192, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 218, 0, 0, 0, 0, 186, + 0, 0, 187, 0, 0, 188, 0, 0, 0, 189, + 190, 185, 0, 191, 0, 159, 192, 160, 161, 162, + 163, 0, 164, 165, 166, 167, 168, 169, 0, 0, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 0, 0, 455, 0, 0, 0, 183, 0, + 0, 190, 0, 0, 191, 0, 0, 192, 0, 0, + 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 184, 0, 0, 0, 159, 0, 160, 161, 162, 163, + 0, 164, 165, 166, 167, 168, 169, 0, 185, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 0, 0, 513, 0, 0, 0, 183, 0, 514, + 0, 0, 0, 0, 0, 0, 0, 186, 0, 0, + 187, 0, 0, 188, 0, 0, 0, 189, 190, 184, + 0, 191, 0, 159, 192, 160, 161, 162, 163, 0, + 164, 165, 166, 167, 168, 169, 0, 185, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 0, 0, 548, 0, 0, 0, 183, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 186, 0, 214, 187, + 0, 0, 188, 0, 0, 0, 189, 190, 184, 0, + 191, 0, 159, 192, 160, 161, 162, 163, 209, 164, + 165, 166, 167, 168, 169, 0, 185, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 0, + 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 186, 0, 0, 187, 0, + 0, 188, 0, 0, 0, 189, 190, 184, 0, 191, + 0, 0, 192, 0, 0, 0, 0, 0, 0, 159, + 0, 160, 161, 162, 163, 185, 164, 165, 166, 167, + 168, 169, 0, 212, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 0, 0, 0, 0, + 0, 0, 183, 0, 186, 0, 0, 187, 0, 0, + 188, 0, 0, 0, 189, 190, 0, 0, 191, 0, + 0, 192, 0, 0, 184, 0, 0, 0, 159, 0, + 160, 161, 162, 163, 0, 164, 165, 166, 167, 168, + 169, 0, 185, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 0, 0, 0, 0, 0, + 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 186, 0, 214, 187, 0, 0, 188, 0, 0, + 0, 189, 190, 184, 0, 191, 0, 159, 192, 160, + 161, 162, 163, 0, 164, 165, 166, 167, 168, 169, + 0, 185, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 0, 0, 0, 0, 0, 0, + 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 186, 0, 0, 187, 0, 234, 188, 0, 0, 0, + 189, 190, 184, 0, 191, 0, 159, 192, 160, 161, + 162, 163, 0, 164, 165, 166, 167, 168, 169, 0, + 185, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 0, 0, 0, 0, 0, 0, 183, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, + 0, 0, 187, 0, 235, 188, 0, 0, 0, 189, + 190, 184, 0, 191, 0, 159, 192, 160, 161, 162, + 163, 0, 164, 165, 166, 167, 168, 169, 0, 185, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 0, 0, 0, 0, 0, 0, 183, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 186, 0, + 0, 187, 0, 0, 188, 0, 0, 0, 189, 190, + 184, 0, 191, 0, 159, 192, 160, 161, 162, 163, + 0, 164, 165, 166, 167, 168, 169, 0, 185, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 0, 257, 0, 0, 0, 0, 183, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 186, 0, 0, + 187, 0, 0, 188, 0, 0, 0, 189, 190, 184, + 0, 191, 0, 159, 192, 160, 161, 162, 163, 325, + 164, 165, 166, 167, 168, 169, 0, 185, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, + 0, 264, 0, 0, 0, 0, 186, 0, 0, 187, + 0, 0, 188, 0, 0, 0, 189, 190, 184, 0, + 191, 0, 159, 192, 160, 161, 162, 163, 326, 164, + 165, 166, 167, 168, 169, 0, 185, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 0, + 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 186, 0, 0, 187, 0, + 0, 188, 0, 0, 0, 189, 190, 184, 0, 191, + 0, 159, 192, 160, 161, 162, 163, 0, 164, 165, + 166, 167, 168, 169, 0, 185, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 0, 0, + 327, 0, 0, 0, 183, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 186, 0, 0, 187, 0, 0, + 188, 0, 0, 0, 189, 190, 184, 0, 191, 0, + 159, 192, 160, 161, 162, 163, 337, 164, 165, 166, + 167, 168, 169, 0, 185, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 0, 0, 0, + 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 186, 0, 0, 187, 0, 0, 188, + 0, 0, 0, 189, 190, 184, 0, 191, 0, 159, + 192, 160, 161, 162, 163, 341, 164, 165, 166, 167, + 168, 169, 0, 185, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 0, 0, 0, 0, + 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 186, 0, 0, 187, 0, 0, 188, 0, + 0, 0, 189, 190, 184, 0, 191, 0, 159, 192, + 160, 161, 162, 163, 342, 164, 165, 166, 167, 168, + 169, 0, 185, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 0, 0, 0, 0, 0, + 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 186, 0, 0, 187, 0, 0, 188, 0, 0, + 0, 189, 190, 184, 0, 191, 0, 159, 192, 160, + 161, 162, 163, 348, 164, 165, 166, 167, 168, 169, + 0, 185, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 0, 0, 0, 0, 0, 0, + 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 186, 0, 0, 187, 0, 0, 188, 0, 0, 0, + 189, 190, 184, 0, 191, 0, 159, 192, 160, 161, + 162, 163, 357, 164, 165, 166, 167, 168, 169, 0, + 185, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 0, 0, 0, 0, 0, 0, 183, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, + 0, 0, 187, 0, 0, 188, 0, 0, 0, 189, + 190, 184, 0, 191, 0, 159, 192, 160, 161, 162, + 163, 368, 164, 165, 166, 167, 168, 169, 0, 185, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 0, 0, 0, 0, 0, 0, 183, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 186, 0, + 0, 187, 0, 0, 188, 0, 0, 0, 189, 190, + 184, 0, 191, 0, 159, 192, 160, 161, 162, 163, + 371, 164, 165, 166, 167, 168, 169, 0, 185, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 0, 0, 0, 0, 0, 0, 183, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 186, 0, 0, + 187, 0, 0, 188, 0, 0, 0, 189, 190, 184, + 0, 191, 0, 159, 192, 160, 161, 162, 163, 372, + 164, 165, 166, 167, 168, 169, 0, 185, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 186, 0, 0, 187, + 0, 0, 188, 0, 0, 0, 189, 190, 184, 0, + 191, 0, 159, 192, 160, 161, 162, 163, 373, 164, + 165, 166, 167, 168, 169, 0, 185, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 0, + 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 186, 0, 0, 187, 0, + 0, 188, 0, 0, 0, 189, 190, 184, 0, 191, + 0, 159, 192, 160, 161, 162, 163, 374, 164, 165, + 166, 167, 168, 169, 0, 185, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 0, 0, + 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 186, 0, 0, 187, 0, 0, + 188, 0, 0, 0, 189, 190, 184, 0, 191, 0, + 159, 192, 160, 161, 162, 163, 0, 164, 165, 166, + 167, 168, 169, 0, 185, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 0, 0, 375, + 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 186, 0, 0, 187, 0, 0, 188, + 0, 0, 0, 189, 190, 184, 0, 191, 0, 159, + 192, 160, 161, 162, 163, 377, 164, 165, 166, 167, + 168, 169, 0, 185, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 0, 0, 0, 0, + 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 186, 0, 0, 187, 0, 0, 188, 0, + 0, 0, 189, 190, 184, 0, 191, 0, 159, 192, + 160, 161, 162, 163, 0, 164, 165, 166, 167, 168, + 169, 0, 185, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 0, 0, 387, 0, 0, + 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 186, 0, 0, 187, 0, 0, 188, 0, 0, + 0, 189, 190, 184, 0, 191, 0, 159, 192, 160, + 161, 162, 163, 0, 164, 165, 166, 167, 168, 169, + 0, 185, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 0, 0, 0, 0, 0, 0, + 183, 0, 0, 0, 0, 388, 0, 0, 0, 0, + 186, 0, 0, 187, 0, 0, 188, 0, 0, 0, + 189, 190, 184, 0, 191, 0, 159, 192, 160, 161, + 162, 163, 390, 164, 165, 166, 167, 168, 169, 0, + 185, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 0, 0, 0, 0, 0, 0, 183, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, + 0, 0, 187, 0, 0, 188, 0, 0, 0, 189, + 190, 184, 0, 191, 0, 159, 192, 160, 161, 162, + 163, 0, 164, 165, 166, 167, 168, 169, 0, 185, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 0, 0, 396, 0, 0, 0, 183, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 186, 0, + 0, 187, 0, 0, 188, 0, 0, 0, 189, 190, + 184, 0, 191, 0, 159, 192, 160, 161, 162, 163, + 401, 164, 165, 166, 167, 168, 169, 0, 185, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 0, 0, 0, 0, 0, 0, 183, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 186, 0, 0, + 187, 0, 0, 188, 0, 0, 0, 189, 190, 184, + 0, 191, 0, 0, 192, 0, 0, 0, 0, 0, + 0, 159, 0, 160, 161, 162, 163, 185, 164, 165, + 166, 167, 168, 169, 0, 403, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 0, 0, + 0, 0, 0, 0, 183, 0, 186, 0, 0, 187, + 0, 0, 188, 0, 0, 0, 189, 190, 0, 0, + 191, 0, 0, 192, 0, 0, 184, 0, 0, 0, + 159, 0, 160, 161, 162, 163, 0, 164, 165, 166, + 167, 168, 169, 0, 185, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 0, 0, 0, + 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 186, 0, 0, 187, 0, 426, 188, + 0, 0, 0, 189, 190, 184, 0, 191, 0, 159, + 192, 160, 161, 162, 163, 0, 164, 165, 166, 167, + 168, 169, 0, 185, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 0, 0, 0, 0, + 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 186, 0, 0, 187, 0, 0, 188, 0, + 0, 0, 189, 190, 184, 0, 191, 0, 159, 192, + 160, 161, 162, 163, 436, 164, 165, 166, 167, 168, + 169, 0, 185, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 0, 0, 0, 0, 0, + 437, 183, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 186, 0, 0, 187, 0, 0, 188, 0, 0, + 0, 189, 190, 184, 0, 191, 0, 159, 192, 160, + 161, 162, 163, 0, 164, 165, 166, 167, 168, 169, + 0, 185, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 0, 0, 0, 0, 0, 472, + 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 186, 0, 0, 187, 0, 0, 188, 0, 0, 0, + 189, 190, 184, 0, 191, 0, 0, 192, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 185, 159, 0, 160, 161, 162, 163, 0, 164, 165, + 166, 167, 168, 169, 0, 0, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 0, 186, + 0, 0, 187, 0, 183, 188, 0, 0, 0, 189, + 190, 0, 0, 191, 0, 0, 192, 0, 0, 0, + 355, 0, 0, 0, 0, 0, 184, 0, 0, 0, + 159, 0, 160, 161, 162, 163, 0, 164, 165, 166, + 167, 168, 169, 0, 185, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 0, 0, 0, + 0, 0, 491, 183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 186, 0, 0, 187, 0, 0, 188, + 0, 0, 0, 189, 190, 184, 0, 191, 0, 159, + 192, 160, 161, 162, 163, 493, 164, 165, 166, 167, + 168, 169, 0, 185, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 0, 0, 0, 0, + 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 186, 0, 0, 187, 0, 0, 188, 0, + 0, 0, 189, 190, 184, 0, 191, 0, 159, 192, + 160, 161, 162, 163, 0, 164, 165, 166, 167, 168, + 169, 0, 185, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 0, 0, 507, 0, 0, + 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 186, 0, 0, 187, 0, 0, 188, 0, 0, + 0, 189, 190, 184, 0, 191, 0, 159, 192, 160, + 161, 162, 163, 0, 164, 165, 166, 167, 168, 169, + 0, 185, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 0, 0, 0, 0, 0, 0, + 183, 0, 0, 0, 0, 518, 0, 0, 0, 0, + 186, 0, 0, 187, 0, 0, 188, 0, 0, 0, + 189, 190, 184, 0, 191, 0, 159, 192, 160, 161, + 162, 163, 0, 164, 165, 166, 167, 168, 169, 0, + 185, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 0, 0, 0, 0, 0, 0, 183, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, + 0, 0, 187, 0, 532, 188, 0, 0, 0, 189, + 190, 184, 0, 191, 0, 159, 192, 160, 161, 162, + 163, 0, 164, 165, 166, 167, 168, 169, 0, 185, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 0, 0, 0, 0, 0, 0, 183, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 186, 0, + 0, 187, 0, 534, 188, 0, 0, 0, 189, 190, + 184, 0, 191, 0, 159, 192, 160, 161, 162, 163, + 0, 164, 165, 166, 167, 168, 169, 0, 185, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 0, 0, 0, 0, 0, 552, 183, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 186, 0, 0, + 187, 0, 0, 188, 0, 0, 0, 189, 190, 184, + 0, 191, 0, 159, 192, 160, 161, 162, 163, 0, + 164, 165, 166, 167, 168, 169, 0, 185, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, + 0, 554, 0, 0, 0, 0, 186, 0, 0, 187, + 0, 0, 188, 0, 0, 0, 189, 190, 184, 0, + 191, 0, 159, 192, 160, 161, 162, 163, 0, 164, + 165, 166, 167, 168, 169, 0, 185, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 0, + 0, 575, 0, 0, 0, 183, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 186, 0, 0, 187, 0, + 0, 188, 0, 0, 0, 189, 190, 184, 0, 191, + 0, 159, 192, 160, 161, 162, 163, 0, 164, 165, + 166, 167, 168, 169, 0, 185, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 0, 0, + 0, 0, 0, 594, 183, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 186, 0, 0, 187, 0, 0, + 188, 0, 0, 0, 189, 190, 184, 0, 191, 0, + 159, 192, 160, 161, 162, 163, 0, 164, 165, 166, + 167, 168, 169, 0, 185, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 0, 0, 0, + 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 186, 0, 0, 187, 0, 0, 188, + 0, 0, 0, 189, 190, 184, 0, 191, 0, 159, + 192, 258, 161, 162, 163, 0, 164, 165, 166, 167, + 168, 169, 0, 185, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 0, 0, 0, 0, + 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 186, 0, 0, 187, 0, 0, 188, 0, + 0, 0, 189, 190, 184, 0, 191, 0, 159, 192, + 160, 161, 162, 163, 0, 164, 165, 166, 167, 168, + 169, 0, 185, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 0, 0, 0, 0, 0, + 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 186, 0, 0, 187, 0, 0, 188, 0, 0, + 0, 189, 190, 184, 0, 191, 0, 159, 192, 0, + 161, 162, 163, 0, 164, 165, 166, 167, 168, 169, + 0, 185, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 0, 0, 0, 0, 0, 0, + 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -259, 0, 0, 188, 0, 0, 0, + 189, 190, 184, 0, 191, 0, 159, 192, 160, 161, + 162, 163, 0, 164, 165, 166, 167, 168, 169, 0, + 185, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 0, 0, 0, 0, 0, 0, 183, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, + 0, 0, 187, 0, 0, 188, 0, 0, 0, 189, + 190, 184, 0, 191, 0, 159, 192, 0, 161, 162, + 163, 0, 164, 165, 166, 167, 168, 169, 0, 185, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 0, 0, 0, 0, 0, 0, 183, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 188, 0, 0, 0, 189, 190, + 0, 0, 191, 0, 159, 192, 160, 0, 162, 163, + 0, 164, 165, 166, 167, 168, 169, 0, 185, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 0, 0, 0, 0, 0, 0, 183, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 186, 0, 0, + 187, 0, 0, 188, 0, 0, 0, 189, 190, 184, + 0, 191, 0, 159, 192, 0, 0, 162, 163, 0, + 164, 165, 166, 167, 168, 169, 0, 185, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 189, 190, 184, 0, + 191, 0, 159, 192, 0, 0, 162, 163, 0, 164, + 165, 166, 167, 168, 169, 0, 185, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 0, + 0, 0, 443, 0, 0, 183, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 189, 190, 184, 0, 191, + 0, 159, 192, 0, 0, 162, 163, 0, 164, 165, + 166, 167, 168, 169, 0, 185, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 0, 0, + 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 189, 190, 184, 0, 191, 0, + 159, 192, 0, 0, 162, 163, 0, 164, 165, 166, + 167, 168, 169, 0, 185, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 0, 0, 0, + 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -259, 190, 184, 0, 191, 0, 159, + 192, 0, 0, -259, 163, 0, 164, 165, 166, 167, + 168, 169, 0, 185, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 159, 0, 0, 0, + 0, 163, 0, 164, 165, 166, 167, 168, 169, 0, + 0, 170, 171, 172, 173, 174, 175, 176, 0, 178, + 179, 180, 181, 190, 184, 0, 191, 0, 0, 192, + 0, 0, 0, 0, 0, 0, 0, 0, 159, 0, + 0, 0, 185, 163, 0, 164, 165, 166, 167, 168, + 169, 184, 0, 170, 171, 172, 173, 174, 175, 176, + 0, 178, 179, 180, 181, 0, 0, 0, 159, 185, + 0, 0, 0, 163, 0, 164, 165, 166, 167, 168, + 169, 0, 190, 170, 0, 191, 173, 0, 192, 0, + 0, 178, 179, -259, 181, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, + 0, 185, 191, 159, 0, 192, 0, 0, 163, 0, + 164, 165, 166, 167, 168, 169, 0, 0, 170, 0, + 0, 173, 174, 175, 176, 159, 178, 179, 0, 181, + 163, 185, 164, 165, 166, 167, 168, 169, 0, 0, + 170, 190, 0, 173, 191, 175, -259, 192, 178, 179, + 0, 181, 0, 0, 0, 159, 0, 0, 0, 0, + 163, 0, 164, 165, 166, 167, 168, 169, 0, 0, + 170, 190, 0, 0, 191, 0, 185, 192, 178, 179, + 159, 181, 0, 0, 0, 163, 0, 0, 0, 0, + 167, 168, 169, 0, 0, 170, 0, 159, 185, 0, + 0, 0, 163, 178, 179, 0, 181, 0, 168, 169, + 0, 0, 170, 0, 0, 0, 190, 0, 0, 191, + 178, 179, 192, 181, 159, 0, 0, 0, 185, 163, + 0, 0, 0, 0, 0, -259, 169, 0, 190, 170, + 0, 191, 0, 0, 192, 0, 0, 178, 179, 159, + 181, 0, 0, 185, 163, 0, 0, 0, 0, 0, + 0, 169, 0, 0, 170, 0, 0, 0, 190, 0, + 185, 191, 178, 179, 192, 181, -259, 0, 0, 0, + 0, 163, 0, 0, 0, 0, 0, 0, 169, 0, + 0, 170, 0, 190, 0, 0, 191, 185, 0, 178, + 179, 0, 181, 0, 0, 0, 0, 0, 0, 0, + 190, 0, 0, 191, 0, 0, 0, 0, 0, 0, + 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, + 191, 0, 0, 0, 0, 0, 0, 0, 0, 185, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -259, 0, 0, 191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 191 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 17, 349, 129, 137, 15, 15, 24, 242, 142, + 10, 333, 12, 13, 14, 502, 16, 17, 18, 17, + 46, 21, 22, 54, 24, 3, 4, 27, 4, 29, + 30, 553, 10, 17, 10, 13, 17, 13, 38, 17, + 14, 14, 14, 4, 51, 414, 46, 47, 48, 49, + 26, 51, 52, 18, 38, 577, 56, 38, 545, 59, + 60, 15, 47, 63, 74, 74, 4, 83, 46, 67, + 55, 44, 46, 3, 4, 29, 76, 77, 78, 79, + 10, 46, 4, 13, 3, 4, 86, 17, 410, 89, + 4, 3, 4, 67, 13, 67, 96, 44, 98, 99, + 100, 13, 109, 472, 58, 17, 106, 17, 3, 119, + 110, 128, 26, 60, 114, 15, 46, 117, 118, 17, + 120, 121, 17, 123, 124, 125, 126, 46, 254, 29, + 130, 162, 265, 51, 46, 369, 17, 137, 485, 76, + 38, 141, 142, 121, 10, 45, 46, 147, 14, 149, + 15, 151, 17, 10, 154, 133, 156, 133, 54, 55, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 17, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 17, 217, 187, 188, 189, + 190, 121, 192, 193, 194, 59, 44, 61, 17, 47, + 118, 201, 121, 3, 4, 17, 38, 55, 442, 121, + 17, 211, 38, 13, 28, 4, 5, 17, 218, 59, + 60, 10, 36, 63, 17, 0, 460, 17, 228, 229, + 230, 231, 17, 4, 67, 49, 41, 237, 46, 17, + 240, 55, 72, 243, 88, 163, 46, 247, 381, 382, + 383, 17, 385, 109, 17, 122, 77, 46, 258, 259, + 17, 261, 496, 67, 3, 56, 266, 4, 268, 3, + 4, 44, 6, 273, 508, 193, 10, 277, 81, 13, + 14, 81, 17, 3, 17, 19, 18, 21, 22, 18, + 18, 24, 46, 51, 27, 76, 60, 79, 24, 18, + 300, 18, 35, 36, 18, 38, 337, 121, 18, 17, + 41, 18, 46, 313, 18, 448, 24, 44, 29, 18, + 50, 121, 3, 53, 54, 3, 357, 35, 328, 247, + 38, 77, 62, 51, 18, 109, 45, 337, 338, 45, + 41, 259, 109, 182, 109, 345, 479, 109, 362, 349, + 268, 427, 85, 472, 354, 355, 578, 357, 358, 359, + 57, 484, -1, -1, 364, -1, 180, 367, -1, -1, + -1, -1, 186, -1, -1, -1, -1, 85, -1, -1, + 114, 381, 382, 383, -1, 115, -1, 121, -1, 389, + 421, 125, -1, 393, 394, 128, -1, -1, 398, 399, + 214, -1, -1, -1, -1, 405, 406, 407, 408, 542, + 328, 411, 412, -1, -1, 415, -1, 417, -1, -1, + 128, -1, 152, -1, -1, -1, -1, -1, 459, 429, + -1, 431, -1, -1, -1, -1, -1, 570, -1, -1, + -1, -1, -1, -1, 475, -1, -1, 261, 448, -1, + -1, 451, 266, -1, -1, -1, -1, 457, -1, 459, + -1, -1, 493, -1, -1, -1, 599, -1, 601, -1, + -1, 604, -1, 606, -1, 475, -1, 477, -1, 479, + 398, -1, -1, -1, 484, 485, 486, 217, -1, 489, + -1, 522, -1, 223, 412, 495, -1, -1, 498, -1, + -1, 501, -1, 503, 234, 235, -1, -1, -1, -1, + -1, 241, -1, -1, 514, -1, -1, -1, -1, 333, + -1, -1, -1, -1, 555, -1, 557, -1, -1, -1, + -1, -1, -1, 263, 264, 265, 536, -1, -1, 539, + -1, 541, 542, -1, -1, 275, -1, -1, 362, -1, + 550, -1, -1, 553, -1, -1, -1, 557, 558, 559, + 560, 561, -1, 563, -1, 565, 566, 567, -1, 569, + 570, -1, -1, 573, -1, -1, -1, 577, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 587, -1, 589, + -1, -1, -1, -1, -1, -1, 410, -1, -1, 599, + -1, 601, -1, 417, 604, -1, 606, -1, 8, -1, + -1, -1, 12, -1, 14, 15, 16, 17, -1, 19, + 20, 21, 22, 23, 24, -1, -1, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, + -1, -1, -1, -1, 44, 45, -1, 565, -1, 567, + -1, -1, -1, -1, -1, 385, -1, -1, 388, -1, + -1, -1, -1, 12, -1, -1, -1, 67, 17, 587, + -1, 589, 21, 22, 23, 24, -1, -1, 27, -1, + -1, -1, -1, -1, -1, 85, 35, 36, -1, 38, + 420, -1, -1, 423, 508, -1, 426, -1, -1, -1, + 430, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 441, 442, -1, 114, -1, -1, 117, -1, -1, + 120, -1, 452, -1, 124, 125, -1, 541, 128, -1, + 12, 131, -1, -1, -1, 17, 85, 19, 20, 21, + 22, 23, 24, -1, -1, 27, 28, 29, 30, 31, + 32, 33, 566, 35, 36, 569, 38, -1, -1, -1, + -1, -1, -1, -1, 494, -1, -1, 497, -1, 499, + -1, -1, -1, -1, -1, -1, 125, -1, -1, 128, + -1, 511, -1, -1, -1, -1, -1, -1, 518, -1, + -1, -1, -1, -1, -1, -1, -1, 527, -1, -1, + -1, 531, 532, 85, 534, -1, -1, -1, 538, -1, + -1, -1, -1, 543, -1, -1, -1, -1, -1, 549, + -1, -1, -1, -1, 554, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 125, -1, -1, 128, -1, -1, 131, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 595, -1, 597, -1, -1, + 600, 1, 602, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, + 40, 41, -1, -1, 44, 45, 46, 47, -1, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, -1, 65, 66, 67, -1, 69, + 70, 71, -1, 73, 74, 75, -1, 77, 78, -1, + 80, -1, 82, 83, 84, 85, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, 99, + 100, 101, -1, -1, -1, -1, -1, -1, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, + 120, 121, 122, 123, 124, 125, -1, 127, 128, 129, + 130, 131, 132, 133, 1, -1, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, 40, 41, -1, -1, 44, 45, 46, + 47, -1, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, -1, 65, 66, + 67, -1, 69, 70, 71, -1, 73, 74, 75, -1, + 77, 78, -1, 80, -1, 82, 83, 84, 85, 86, + 87, -1, 89, -1, -1, -1, -1, -1, -1, -1, + -1, 98, 99, 100, 101, -1, -1, -1, -1, -1, + -1, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, + 127, 128, 129, 130, 131, 132, 133, 1, -1, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, 40, 41, -1, -1, + 44, 45, 46, 47, -1, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + -1, 65, 66, 67, -1, 69, 70, 71, -1, 73, + 74, 75, -1, 77, 78, -1, 80, -1, 82, 83, + 84, 85, 86, 87, -1, 89, -1, -1, -1, -1, + -1, -1, -1, -1, 98, 99, 100, 101, -1, -1, + -1, -1, -1, -1, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, 127, 128, 129, 130, 131, 132, 133, + 1, -1, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, -1, 40, + 41, -1, -1, 44, 45, 46, 47, -1, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, -1, 65, 66, 67, -1, 69, 70, + 71, -1, 73, 74, 75, -1, 77, -1, -1, 80, + -1, 82, 83, 84, 85, 86, 87, -1, 89, -1, + -1, -1, -1, -1, -1, -1, -1, 98, 99, 100, + 101, -1, -1, -1, -1, -1, -1, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, + 121, 122, 123, 124, 125, -1, 127, 128, 129, 130, + 131, 132, 133, 1, -1, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, -1, 40, 41, -1, -1, 44, 45, 46, 47, + -1, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, -1, 65, 66, 67, + -1, 69, 70, 71, -1, 73, 74, 75, -1, 77, + 78, -1, 80, -1, 82, 83, 84, 85, 86, 87, + -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, + 98, 99, 100, 101, -1, -1, -1, -1, -1, -1, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, 132, 133, 1, -1, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, 40, 41, -1, -1, 44, + 45, 46, 47, -1, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, + 65, 66, 67, -1, 69, 70, 71, -1, 73, 74, + 75, -1, 77, 78, -1, 80, -1, 82, 83, 84, + 85, 86, 87, -1, 89, -1, -1, -1, -1, -1, + -1, -1, -1, 98, 99, 100, 101, -1, -1, -1, + -1, -1, -1, 108, -1, 110, 111, 112, 113, 114, + 115, 116, 117, 118, -1, 120, 121, 122, 123, 124, + 125, -1, 127, 128, 129, 130, 131, 132, 133, 1, + -1, 3, 4, 5, 6, 7, -1, 9, 10, 11, + 12, 13, 14, 15, 16, 17, -1, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, -1, 40, -1, + -1, -1, -1, 45, 46, 47, -1, -1, 50, -1, + 52, 53, 54, -1, -1, 57, -1, -1, -1, -1, + 62, 63, -1, 65, -1, 67, -1, 69, 70, 71, + -1, 73, 74, 75, 76, -1, 78, -1, 80, -1, + 82, 83, 84, 85, 86, 87, -1, 89, -1, -1, + -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 108, 109, -1, 111, + 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, + 122, 123, 124, 125, -1, 127, 128, 129, 130, 131, + 132, 133, 1, -1, 3, 4, 5, 6, 7, -1, + 9, 10, 11, 12, 13, 14, 15, 16, 17, -1, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + -1, 40, -1, -1, -1, -1, 45, 46, 47, -1, + -1, -1, -1, 52, 53, 54, -1, -1, 57, -1, + -1, 60, -1, 62, 63, -1, 65, -1, 67, -1, + 69, 70, 71, -1, 73, 74, 75, 76, -1, 78, + -1, 80, -1, 82, 83, 84, 85, 86, 87, -1, + 89, -1, -1, -1, -1, -1, -1, -1, -1, 98, + -1, 100, -1, -1, -1, -1, -1, -1, -1, 108, + 109, -1, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, 127, 128, + 129, 130, 131, 132, 133, 1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 11, 12, 13, 14, 15, + 16, 17, -1, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, -1, 40, -1, -1, -1, -1, 45, + 46, 47, -1, -1, -1, -1, 52, 53, 54, -1, + -1, 57, -1, -1, -1, -1, 62, 63, -1, 65, + -1, 67, -1, 69, 70, 71, -1, 73, 74, 75, + -1, -1, 78, -1, 80, -1, 82, 83, 84, 85, + 86, 87, -1, 89, -1, -1, -1, -1, -1, -1, + -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, + -1, -1, 108, 109, -1, 111, 112, 113, 114, 115, + 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, + -1, 127, 128, 129, 130, 131, 132, 133, 1, -1, + 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, + 13, -1, -1, -1, 17, -1, 19, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 29, 30, -1, -1, + -1, -1, 35, 36, 37, -1, -1, 40, -1, -1, + -1, 44, -1, 46, 47, -1, 49, -1, 51, 52, + 53, 54, -1, -1, 57, -1, -1, -1, -1, 62, + 63, -1, 65, -1, -1, -1, 69, 70, 71, -1, + 73, 74, 75, -1, 77, 78, -1, 80, -1, 82, + 83, 84, -1, 86, 87, -1, 89, -1, -1, -1, + -1, -1, -1, -1, -1, 98, -1, 100, -1, -1, + -1, -1, -1, -1, -1, 108, 109, -1, 111, 112, + 113, -1, 115, 116, -1, 118, -1, -1, 121, 122, + 123, -1, 125, -1, 127, -1, 129, 130, -1, 132, + 133, 1, -1, 3, 4, 5, 6, 7, -1, 9, + 10, 11, 12, 13, -1, -1, -1, 17, -1, 19, + 20, -1, -1, -1, -1, 25, 26, -1, -1, 29, + 30, -1, -1, -1, -1, 35, 36, 37, -1, -1, + 40, -1, -1, -1, 44, -1, 46, 47, -1, -1, + -1, 51, 52, 53, 54, -1, -1, 57, -1, -1, + -1, -1, 62, 63, -1, 65, -1, -1, -1, 69, + 70, 71, -1, 73, 74, 75, -1, 77, 78, -1, + 80, -1, 82, 83, 84, -1, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, -1, -1, -1, -1, 108, 109, + -1, 111, 112, 113, -1, 115, 116, -1, 118, -1, + -1, 121, 122, 123, -1, 125, -1, 127, -1, 129, + 130, -1, 132, 133, 1, -1, 3, 4, 5, 6, + 7, -1, 9, 10, 11, 12, 13, -1, -1, -1, + 17, -1, 19, 20, -1, -1, -1, -1, 25, 26, + -1, -1, 29, 30, -1, -1, -1, -1, 35, 36, + 37, -1, -1, 40, -1, -1, -1, -1, -1, 46, + 47, -1, 49, -1, 51, 52, 53, 54, -1, -1, + 57, -1, -1, -1, -1, 62, 63, -1, 65, -1, + -1, -1, 69, 70, 71, -1, 73, 74, 75, -1, + 77, 78, -1, 80, -1, 82, 83, 84, -1, 86, + 87, -1, 89, -1, -1, -1, -1, -1, -1, -1, + -1, 98, -1, 100, -1, -1, -1, -1, -1, -1, + -1, 108, 109, -1, 111, 112, 113, -1, 115, 116, + -1, 118, -1, -1, 121, 122, 123, -1, 125, -1, + 127, -1, 129, 130, -1, 132, 133, 1, -1, 3, + 4, 5, 6, 7, -1, 9, 10, 11, 12, 13, + -1, -1, -1, 17, -1, 19, 20, -1, -1, -1, + -1, 25, 26, -1, -1, 29, 30, -1, -1, -1, + -1, 35, 36, 37, -1, -1, 40, -1, -1, -1, + -1, -1, 46, 47, -1, -1, -1, -1, 52, 53, + 54, -1, -1, 57, -1, -1, -1, -1, 62, 63, + -1, 65, -1, -1, -1, 69, 70, 71, -1, 73, + 74, 75, 76, -1, 78, 79, 80, 81, 82, 83, + 84, -1, 86, 87, -1, 89, -1, -1, -1, -1, + -1, -1, -1, -1, 98, -1, 100, -1, -1, -1, + -1, -1, -1, -1, 108, 109, -1, 111, 112, 113, + -1, 115, 116, -1, 118, -1, -1, 121, 122, 123, + -1, 125, -1, 127, -1, 129, 130, -1, 132, 133, + 1, -1, 3, 4, 5, 6, 7, -1, 9, 10, + 11, 12, 13, -1, -1, -1, 17, -1, 19, 20, + -1, -1, -1, -1, 25, 26, -1, -1, 29, 30, + -1, -1, -1, -1, 35, 36, 37, -1, -1, 40, + -1, -1, -1, 44, -1, 46, 47, -1, -1, -1, + -1, 52, 53, 54, 55, 56, 57, -1, -1, -1, + -1, 62, 63, -1, 65, -1, -1, -1, 69, 70, + 71, -1, 73, 74, 75, -1, -1, 78, -1, 80, + -1, 82, 83, 84, -1, 86, 87, -1, 89, -1, + -1, -1, -1, -1, -1, -1, -1, 98, -1, 100, + -1, -1, -1, -1, -1, -1, -1, 108, 109, -1, + 111, 112, 113, -1, 115, 116, -1, 118, -1, -1, + 121, 122, 123, -1, 125, -1, 127, -1, 129, 130, + -1, 132, 133, 1, -1, 3, 4, 5, 6, 7, + -1, 9, 10, 11, 12, 13, -1, -1, -1, 17, + -1, 19, 20, -1, -1, -1, -1, 25, 26, -1, + -1, 29, 30, -1, -1, -1, -1, 35, 36, 37, + -1, -1, 40, -1, -1, -1, 44, -1, 46, 47, + -1, -1, -1, 51, 52, 53, 54, -1, -1, 57, + -1, -1, -1, -1, 62, 63, -1, 65, -1, -1, + -1, 69, 70, 71, -1, 73, 74, 75, -1, 77, + 78, -1, 80, -1, 82, 83, 84, -1, 86, 87, + -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, + 98, -1, 100, -1, -1, -1, -1, -1, -1, -1, + 108, 109, -1, 111, 112, 113, -1, 115, 116, -1, + 118, -1, -1, 121, 122, 123, -1, 125, -1, 127, + -1, 129, 130, -1, 132, 133, 1, -1, 3, 4, + 5, 6, 7, -1, 9, 10, 11, 12, 13, -1, + -1, -1, 17, -1, 19, 20, -1, -1, -1, -1, + 25, 26, -1, -1, 29, 30, -1, -1, -1, -1, + 35, 36, 37, -1, -1, 40, -1, -1, -1, 44, + -1, 46, 47, -1, -1, -1, -1, 52, 53, 54, + -1, -1, 57, -1, -1, -1, -1, 62, 63, -1, + 65, -1, -1, -1, 69, 70, 71, -1, 73, 74, + 75, -1, 77, 78, -1, 80, -1, 82, 83, 84, + -1, 86, 87, -1, 89, -1, -1, -1, -1, -1, + -1, -1, -1, 98, -1, 100, -1, -1, -1, -1, + -1, -1, -1, 108, 109, 110, 111, 112, 113, -1, + 115, 116, -1, 118, -1, -1, 121, 122, 123, -1, + 125, -1, 127, -1, 129, 130, -1, 132, 133, 1, + -1, 3, 4, 5, 6, 7, -1, 9, 10, 11, + 12, 13, -1, -1, -1, 17, -1, 19, 20, -1, + -1, -1, -1, 25, 26, -1, -1, 29, 30, -1, + -1, -1, -1, 35, 36, 37, -1, -1, 40, -1, + -1, -1, 44, -1, 46, 47, -1, -1, -1, -1, + 52, 53, 54, -1, -1, 57, -1, -1, -1, -1, + 62, 63, -1, 65, 66, -1, -1, 69, 70, 71, + -1, 73, 74, 75, -1, -1, 78, -1, 80, -1, + 82, 83, 84, -1, 86, 87, -1, 89, -1, -1, + -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 108, 109, -1, 111, + 112, 113, -1, 115, 116, -1, 118, -1, -1, 121, + 122, 123, -1, 125, -1, 127, -1, 129, 130, -1, + 132, 133, 1, -1, 3, 4, 5, 6, 7, -1, + 9, 10, 11, 12, 13, -1, -1, -1, 17, -1, + 19, 20, -1, -1, -1, -1, 25, 26, -1, -1, + 29, 30, -1, -1, -1, -1, 35, 36, 37, -1, + -1, 40, -1, -1, -1, -1, -1, 46, 47, -1, + -1, -1, -1, 52, 53, 54, -1, -1, 57, -1, + -1, -1, -1, 62, 63, -1, 65, -1, -1, -1, + 69, 70, 71, -1, 73, 74, 75, -1, -1, 78, + 79, 80, 81, 82, 83, 84, -1, 86, 87, -1, + 89, -1, -1, -1, -1, -1, -1, -1, -1, 98, + -1, 100, -1, -1, -1, -1, -1, -1, -1, 108, + 109, -1, 111, 112, 113, -1, 115, 116, -1, 118, + -1, -1, 121, 122, 123, -1, 125, -1, 127, -1, + 129, 130, -1, 132, 133, 1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 11, 12, 13, -1, -1, + -1, 17, -1, 19, 20, -1, -1, -1, -1, 25, + 26, -1, -1, 29, 30, -1, -1, -1, -1, 35, + 36, 37, -1, -1, 40, -1, -1, -1, 44, -1, + 46, 47, -1, -1, -1, -1, 52, 53, 54, -1, + -1, 57, -1, -1, -1, -1, 62, 63, -1, 65, + -1, -1, -1, 69, 70, 71, -1, 73, 74, 75, + -1, 77, 78, -1, 80, -1, 82, 83, 84, -1, + 86, 87, -1, 89, -1, -1, -1, -1, -1, -1, + -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, + -1, -1, 108, 109, -1, 111, 112, 113, -1, 115, + 116, -1, 118, -1, -1, 121, 122, 123, -1, 125, + -1, 127, -1, 129, 130, -1, 132, 133, 1, -1, + 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, + 13, -1, -1, -1, 17, -1, 19, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 29, 30, -1, -1, + -1, -1, 35, 36, 37, -1, -1, 40, -1, -1, + -1, 44, -1, 46, 47, -1, -1, -1, 51, 52, + 53, 54, -1, -1, 57, -1, -1, -1, -1, 62, + 63, -1, 65, -1, -1, -1, 69, 70, 71, -1, + 73, 74, 75, -1, -1, 78, -1, 80, -1, 82, + 83, 84, -1, 86, 87, -1, 89, -1, -1, -1, + -1, -1, -1, -1, -1, 98, -1, 100, -1, -1, + -1, -1, -1, -1, -1, 108, 109, -1, 111, 112, + 113, -1, 115, 116, -1, 118, -1, -1, 121, 122, + 123, -1, 125, -1, 127, -1, 129, 130, -1, 132, + 133, 1, -1, 3, 4, 5, 6, 7, -1, 9, + 10, 11, 12, 13, -1, -1, -1, 17, -1, 19, + 20, -1, -1, -1, -1, 25, 26, -1, -1, 29, + 30, -1, -1, -1, -1, 35, 36, 37, -1, -1, + 40, -1, -1, -1, 44, -1, 46, 47, -1, -1, + 50, -1, 52, 53, 54, -1, -1, 57, -1, -1, + -1, -1, 62, 63, -1, 65, -1, -1, -1, 69, + 70, 71, -1, 73, 74, 75, -1, -1, 78, -1, + 80, -1, 82, 83, 84, -1, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, -1, -1, -1, -1, 108, 109, + -1, 111, 112, 113, -1, 115, 116, -1, 118, -1, + -1, 121, 122, 123, -1, 125, -1, 127, -1, 129, + 130, -1, 132, 133, 1, -1, 3, 4, 5, 6, + 7, -1, 9, 10, 11, 12, 13, -1, -1, -1, + 17, -1, 19, 20, -1, -1, -1, -1, 25, 26, + -1, -1, 29, 30, -1, -1, -1, -1, 35, 36, + 37, -1, -1, 40, -1, -1, -1, 44, -1, 46, + 47, -1, -1, -1, -1, 52, 53, 54, -1, -1, + 57, -1, -1, -1, -1, 62, 63, -1, 65, -1, + -1, -1, 69, 70, 71, -1, 73, 74, 75, -1, + 77, 78, -1, 80, -1, 82, 83, 84, -1, 86, + 87, -1, 89, -1, -1, -1, -1, -1, -1, -1, + -1, 98, -1, 100, -1, -1, -1, -1, -1, -1, + -1, 108, 109, -1, 111, 112, 113, -1, 115, 116, + -1, 118, -1, -1, 121, 122, 123, -1, 125, -1, + 127, -1, 129, 130, -1, 132, 133, 1, -1, 3, + 4, 5, 6, 7, -1, 9, 10, 11, 12, 13, + -1, -1, -1, 17, -1, 19, 20, -1, -1, -1, + -1, 25, 26, -1, -1, 29, 30, -1, -1, -1, + -1, 35, 36, 37, -1, -1, 40, -1, -1, -1, + 44, -1, 46, 47, -1, -1, -1, -1, 52, 53, + 54, -1, -1, 57, -1, -1, -1, -1, 62, 63, + -1, 65, -1, -1, -1, 69, 70, 71, -1, 73, + 74, 75, -1, 77, 78, -1, 80, -1, 82, 83, + 84, -1, 86, 87, -1, 89, -1, -1, -1, -1, + -1, -1, -1, -1, 98, -1, 100, -1, -1, -1, + -1, -1, -1, -1, 108, 109, -1, 111, 112, 113, + -1, 115, 116, -1, 118, -1, -1, 121, 122, 123, + -1, 125, -1, 127, -1, 129, 130, -1, 132, 133, + 1, -1, 3, 4, 5, 6, 7, -1, 9, 10, + 11, 12, 13, -1, -1, -1, 17, -1, 19, 20, + -1, -1, -1, -1, 25, 26, -1, -1, 29, 30, + -1, -1, -1, -1, 35, 36, 37, -1, -1, 40, + -1, -1, -1, 44, -1, 46, 47, -1, -1, -1, + -1, 52, 53, 54, -1, 56, 57, -1, -1, -1, + -1, 62, 63, -1, 65, -1, -1, -1, 69, 70, + 71, -1, 73, 74, 75, -1, -1, 78, -1, 80, + -1, 82, 83, 84, -1, 86, 87, -1, 89, -1, + -1, -1, -1, -1, -1, -1, -1, 98, -1, 100, + -1, -1, -1, -1, -1, -1, -1, 108, 109, -1, + 111, 112, 113, -1, 115, 116, -1, 118, -1, -1, + 121, 122, 123, -1, 125, -1, 127, -1, 129, 130, + -1, 132, 133, 1, -1, 3, 4, 5, 6, 7, + -1, 9, 10, 11, 12, 13, -1, -1, -1, 17, + -1, 19, 20, -1, -1, -1, -1, 25, 26, -1, + -1, 29, 30, -1, -1, -1, -1, 35, 36, 37, + -1, -1, 40, -1, -1, -1, 44, -1, 46, 47, + -1, -1, -1, -1, 52, 53, 54, -1, -1, 57, + -1, -1, -1, -1, 62, 63, -1, 65, -1, -1, + -1, 69, 70, 71, -1, 73, 74, 75, -1, 77, + 78, -1, 80, -1, 82, 83, 84, -1, 86, 87, + -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, + 98, -1, 100, -1, -1, -1, -1, -1, -1, -1, + 108, 109, -1, 111, 112, 113, -1, 115, 116, -1, + 118, -1, -1, 121, 122, 123, -1, 125, -1, 127, + -1, 129, 130, -1, 132, 133, 1, -1, 3, 4, + 5, 6, 7, -1, 9, 10, 11, 12, 13, -1, + -1, -1, 17, -1, 19, 20, -1, -1, -1, -1, + 25, 26, -1, -1, 29, 30, -1, -1, -1, -1, + 35, 36, 37, -1, -1, 40, -1, -1, -1, 44, + -1, 46, 47, -1, -1, -1, -1, 52, 53, 54, + -1, -1, 57, -1, -1, -1, -1, 62, 63, -1, + 65, -1, -1, -1, 69, 70, 71, -1, 73, 74, + 75, -1, 77, 78, -1, 80, -1, 82, 83, 84, + -1, 86, 87, -1, 89, -1, -1, -1, -1, -1, + -1, -1, -1, 98, -1, 100, -1, -1, -1, -1, + -1, -1, -1, 108, 109, -1, 111, 112, 113, -1, + 115, 116, -1, 118, -1, -1, 121, 122, 123, -1, + 125, -1, 127, -1, 129, 130, -1, 132, 133, 1, + -1, 3, 4, 5, 6, 7, -1, 9, 10, 11, + 12, 13, -1, -1, -1, 17, -1, 19, 20, -1, + -1, -1, -1, 25, 26, -1, -1, 29, 30, -1, + -1, -1, -1, 35, 36, 37, -1, -1, 40, -1, + -1, -1, 44, -1, 46, 47, -1, -1, -1, -1, + 52, 53, 54, -1, -1, 57, -1, -1, -1, -1, + 62, 63, -1, 65, -1, -1, -1, 69, 70, 71, + -1, 73, 74, 75, -1, 77, 78, -1, 80, -1, + 82, 83, 84, -1, 86, 87, -1, 89, -1, -1, + -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 108, 109, -1, 111, + 112, 113, -1, 115, 116, -1, 118, -1, -1, 121, + 122, 123, -1, 125, -1, 127, -1, 129, 130, -1, + 132, 133, 1, -1, 3, 4, 5, 6, 7, -1, + 9, 10, 11, 12, 13, -1, -1, -1, 17, -1, + 19, 20, -1, -1, -1, -1, 25, 26, -1, -1, + 29, 30, -1, -1, -1, -1, 35, 36, 37, -1, + -1, 40, -1, -1, -1, -1, -1, 46, 47, -1, + -1, -1, -1, 52, 53, 54, -1, -1, 57, -1, + -1, -1, -1, 62, 63, -1, 65, -1, -1, -1, + 69, 70, 71, -1, 73, 74, 75, 76, -1, 78, + 79, 80, -1, 82, 83, 84, -1, 86, 87, -1, + 89, -1, -1, -1, -1, -1, -1, -1, -1, 98, + -1, 100, -1, -1, -1, -1, -1, -1, -1, 108, + 109, -1, 111, 112, 113, -1, 115, 116, -1, 118, + -1, -1, 121, 122, 123, -1, 125, -1, 127, -1, + 129, 130, -1, 132, 133, 1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 11, 12, 13, -1, -1, + -1, 17, -1, 19, 20, -1, -1, -1, -1, 25, + 26, -1, -1, 29, 30, -1, -1, -1, -1, 35, + 36, 37, -1, -1, 40, -1, -1, -1, 44, -1, + 46, 47, -1, -1, -1, -1, 52, 53, 54, -1, + -1, 57, -1, -1, -1, -1, 62, 63, -1, 65, + -1, -1, -1, 69, 70, 71, -1, 73, 74, 75, + -1, 77, 78, -1, 80, -1, 82, 83, 84, -1, + 86, 87, -1, 89, -1, -1, -1, -1, -1, -1, + -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, + -1, -1, 108, 109, -1, 111, 112, 113, -1, 115, + 116, -1, 118, -1, -1, 121, 122, 123, -1, 125, + -1, 127, -1, 129, 130, -1, 132, 133, 1, -1, + 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, + 13, -1, -1, -1, 17, -1, 19, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 29, 30, -1, -1, + -1, -1, 35, 36, 37, -1, -1, 40, -1, -1, + -1, 44, -1, 46, 47, -1, -1, -1, -1, 52, + 53, 54, -1, -1, 57, -1, -1, -1, -1, 62, + 63, -1, 65, -1, -1, -1, 69, 70, 71, -1, + 73, 74, 75, -1, 77, 78, -1, 80, -1, 82, + 83, 84, -1, 86, 87, -1, 89, -1, -1, -1, + -1, -1, -1, -1, -1, 98, -1, 100, -1, -1, + -1, -1, -1, -1, -1, 108, 109, -1, 111, 112, + 113, -1, 115, 116, -1, 118, -1, -1, 121, 122, + 123, -1, 125, -1, 127, -1, 129, 130, -1, 132, + 133, 1, -1, 3, 4, 5, 6, 7, -1, 9, + 10, 11, 12, 13, -1, -1, -1, 17, -1, 19, + 20, -1, -1, -1, -1, 25, 26, -1, -1, 29, + 30, -1, -1, -1, -1, 35, 36, 37, -1, -1, + 40, -1, -1, -1, 44, -1, 46, 47, -1, -1, + -1, -1, 52, 53, 54, -1, -1, 57, -1, -1, + -1, -1, 62, 63, -1, 65, -1, -1, -1, 69, + 70, 71, -1, 73, 74, 75, -1, 77, 78, -1, + 80, -1, 82, 83, 84, -1, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, -1, -1, -1, -1, 108, 109, + -1, 111, 112, 113, -1, 115, 116, -1, 118, -1, + -1, 121, 122, 123, -1, 125, -1, 127, -1, 129, + 130, -1, 132, 133, 1, -1, 3, 4, 5, 6, + 7, -1, 9, 10, 11, 12, 13, -1, -1, -1, + 17, -1, 19, 20, -1, -1, -1, -1, 25, 26, + -1, -1, 29, 30, -1, -1, -1, -1, 35, 36, + 37, -1, -1, 40, -1, -1, -1, 44, -1, 46, + 47, -1, -1, -1, -1, 52, 53, 54, -1, -1, + 57, -1, -1, -1, -1, 62, 63, -1, 65, -1, + -1, -1, 69, 70, 71, -1, 73, 74, 75, -1, + 77, 78, -1, 80, -1, 82, 83, 84, -1, 86, + 87, -1, 89, -1, -1, -1, -1, -1, -1, -1, + -1, 98, -1, 100, -1, -1, -1, -1, -1, -1, + -1, 108, 109, -1, 111, 112, 113, -1, 115, 116, + -1, 118, -1, -1, 121, 122, 123, -1, 125, -1, + 127, -1, 129, 130, -1, 132, 133, 1, -1, 3, + 4, 5, 6, 7, -1, 9, 10, 11, 12, 13, + -1, -1, -1, 17, -1, 19, 20, -1, -1, -1, + -1, 25, 26, -1, -1, 29, 30, -1, -1, -1, + -1, 35, 36, 37, -1, -1, 40, -1, -1, -1, + 44, -1, 46, 47, -1, -1, -1, -1, 52, 53, + 54, -1, -1, 57, -1, -1, -1, -1, 62, 63, + -1, 65, -1, -1, -1, 69, 70, 71, -1, 73, + 74, 75, -1, 77, 78, -1, 80, -1, 82, 83, + 84, -1, 86, 87, -1, 89, -1, -1, -1, -1, + -1, -1, -1, -1, 98, -1, 100, -1, -1, -1, + -1, -1, -1, -1, 108, 109, -1, 111, 112, 113, + -1, 115, 116, -1, 118, -1, -1, 121, 122, 123, + -1, 125, -1, 127, -1, 129, 130, -1, 132, 133, + 1, -1, 3, 4, 5, 6, 7, -1, 9, 10, + 11, 12, 13, -1, -1, -1, 17, -1, 19, 20, + -1, -1, -1, -1, 25, 26, -1, -1, 29, 30, + -1, -1, -1, -1, 35, 36, 37, -1, -1, 40, + -1, -1, -1, 44, -1, 46, 47, -1, -1, -1, + -1, 52, 53, 54, -1, -1, 57, -1, -1, -1, + -1, 62, 63, -1, 65, -1, -1, -1, 69, 70, + 71, -1, 73, 74, 75, -1, 77, 78, -1, 80, + -1, 82, 83, 84, -1, 86, 87, -1, 89, -1, + -1, -1, -1, -1, -1, -1, -1, 98, -1, 100, + -1, -1, -1, -1, -1, -1, -1, 108, 109, -1, + 111, 112, 113, -1, 115, 116, -1, 118, -1, -1, + 121, 122, 123, -1, 125, -1, 127, -1, 129, 130, + -1, 132, 133, 1, -1, 3, 4, 5, 6, 7, + -1, 9, 10, 11, 12, 13, -1, -1, -1, 17, + -1, 19, 20, -1, -1, -1, -1, 25, 26, -1, + -1, 29, 30, -1, -1, -1, -1, 35, 36, 37, + -1, -1, 40, -1, -1, -1, 44, -1, 46, 47, + -1, -1, -1, -1, 52, 53, 54, -1, -1, 57, + -1, -1, -1, -1, 62, 63, -1, 65, -1, -1, + -1, 69, 70, 71, -1, 73, 74, 75, -1, 77, + 78, -1, 80, -1, 82, 83, 84, -1, 86, 87, + -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, + 98, -1, 100, -1, -1, -1, -1, -1, -1, -1, + 108, 109, -1, 111, 112, 113, -1, 115, 116, -1, + 118, -1, -1, 121, 122, 123, -1, 125, -1, 127, + -1, 129, 130, -1, 132, 133, 1, -1, 3, 4, + 5, 6, 7, -1, 9, 10, 11, 12, 13, -1, + -1, -1, 17, -1, 19, 20, -1, -1, -1, -1, + 25, 26, -1, -1, 29, 30, -1, -1, -1, -1, + 35, 36, 37, -1, -1, 40, -1, -1, -1, 44, + -1, 46, 47, -1, -1, -1, -1, 52, 53, 54, + -1, -1, 57, -1, -1, -1, -1, 62, 63, -1, + 65, -1, -1, -1, 69, 70, 71, -1, 73, 74, + 75, -1, 77, 78, -1, 80, -1, 82, 83, 84, + -1, 86, 87, -1, 89, -1, -1, -1, -1, -1, + -1, -1, -1, 98, -1, 100, -1, -1, -1, -1, + -1, -1, -1, 108, 109, -1, 111, 112, 113, -1, + 115, 116, -1, 118, -1, -1, 121, 122, 123, -1, + 125, -1, 127, -1, 129, 130, -1, 132, 133, 1, + -1, 3, 4, 5, 6, 7, -1, 9, 10, 11, + 12, 13, -1, -1, -1, 17, -1, 19, 20, -1, + -1, -1, -1, 25, 26, -1, -1, 29, 30, -1, + -1, -1, -1, 35, 36, 37, -1, -1, 40, -1, + -1, -1, 44, -1, 46, 47, -1, -1, -1, -1, + 52, 53, 54, -1, -1, 57, -1, -1, -1, -1, + 62, 63, -1, 65, -1, -1, -1, 69, 70, 71, + -1, 73, 74, 75, -1, 77, 78, -1, 80, -1, + 82, 83, 84, -1, 86, 87, -1, 89, -1, -1, + -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 108, 109, -1, 111, + 112, 113, -1, 115, 116, -1, 118, -1, -1, 121, + 122, 123, -1, 125, -1, 127, -1, 129, 130, -1, + 132, 133, 1, -1, 3, 4, 5, 6, 7, -1, + 9, 10, 11, 12, 13, -1, -1, -1, 17, -1, + 19, 20, -1, -1, -1, -1, 25, 26, -1, -1, + 29, 30, -1, -1, -1, -1, 35, 36, 37, -1, + -1, 40, -1, -1, -1, 44, -1, 46, 47, -1, + -1, -1, -1, 52, 53, 54, -1, -1, 57, -1, + -1, -1, -1, 62, 63, -1, 65, -1, -1, -1, + 69, 70, 71, -1, 73, 74, 75, -1, 77, 78, + -1, 80, -1, 82, 83, 84, -1, 86, 87, -1, + 89, -1, -1, -1, -1, -1, -1, -1, -1, 98, + -1, 100, -1, -1, -1, -1, -1, -1, -1, 108, + 109, -1, 111, 112, 113, -1, 115, 116, -1, 118, + -1, -1, 121, 122, 123, -1, 125, -1, 127, -1, + 129, 130, -1, 132, 133, 1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 11, 12, 13, -1, -1, + -1, 17, -1, 19, 20, -1, -1, -1, -1, 25, + 26, -1, -1, 29, 30, -1, -1, -1, -1, 35, + 36, 37, -1, -1, 40, -1, -1, -1, 44, -1, + 46, 47, -1, -1, -1, -1, 52, 53, 54, -1, + -1, 57, -1, -1, -1, -1, 62, 63, -1, 65, + -1, -1, -1, 69, 70, 71, -1, 73, 74, 75, + -1, 77, 78, -1, 80, -1, 82, 83, 84, -1, + 86, 87, -1, 89, -1, -1, -1, -1, -1, -1, + -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, + -1, -1, 108, 109, -1, 111, 112, 113, -1, 115, + 116, -1, 118, -1, -1, 121, 122, 123, -1, 125, + -1, 127, -1, 129, 130, -1, 132, 133, 1, -1, + 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, + 13, -1, -1, -1, 17, -1, 19, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 29, 30, -1, -1, + -1, -1, 35, 36, 37, -1, -1, 40, -1, -1, + -1, 44, -1, 46, 47, -1, -1, -1, -1, 52, + 53, 54, -1, -1, 57, -1, -1, -1, -1, 62, + 63, -1, 65, -1, -1, -1, 69, 70, 71, -1, + 73, 74, 75, -1, 77, 78, -1, 80, -1, 82, + 83, 84, -1, 86, 87, -1, 89, -1, -1, -1, + -1, -1, -1, -1, -1, 98, -1, 100, -1, -1, + -1, -1, -1, -1, -1, 108, 109, -1, 111, 112, + 113, -1, 115, 116, -1, 118, -1, -1, 121, 122, + 123, -1, 125, -1, 127, -1, 129, 130, -1, 132, + 133, 1, -1, 3, 4, 5, 6, 7, -1, 9, + 10, 11, 12, 13, -1, -1, -1, 17, -1, 19, + 20, -1, -1, -1, -1, 25, 26, -1, -1, 29, + 30, -1, -1, -1, -1, 35, 36, 37, -1, -1, + 40, -1, -1, -1, 44, -1, 46, 47, -1, -1, + -1, -1, 52, 53, 54, -1, -1, 57, -1, -1, + -1, -1, 62, 63, -1, 65, -1, -1, -1, 69, + 70, 71, -1, 73, 74, 75, -1, 77, 78, -1, + 80, -1, 82, 83, 84, -1, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, -1, -1, -1, -1, 108, 109, + -1, 111, 112, 113, -1, 115, 116, -1, 118, -1, + -1, 121, 122, 123, -1, 125, -1, 127, -1, 129, + 130, -1, 132, 133, 1, -1, 3, 4, 5, 6, + 7, -1, 9, 10, 11, 12, 13, -1, -1, -1, + 17, -1, 19, 20, -1, -1, -1, -1, 25, 26, + -1, -1, 29, 30, -1, -1, -1, -1, 35, 36, + 37, -1, -1, 40, -1, -1, -1, -1, -1, 46, + 47, -1, -1, -1, -1, 52, 53, 54, -1, -1, + 57, -1, -1, -1, -1, 62, 63, -1, 65, -1, + -1, -1, 69, 70, 71, -1, 73, 74, 75, -1, + 77, 78, -1, 80, -1, 82, 83, 84, -1, 86, + 87, -1, 89, -1, -1, -1, -1, -1, -1, -1, + -1, 98, -1, 100, -1, -1, -1, -1, -1, -1, + -1, 108, 109, 110, 111, 112, 113, -1, 115, 116, + -1, 118, -1, -1, 121, 122, 123, -1, 125, -1, + 127, -1, 129, 130, -1, 132, 133, 1, -1, 3, + 4, 5, 6, 7, -1, 9, 10, 11, 12, 13, + -1, -1, -1, 17, -1, 19, 20, -1, -1, -1, + -1, 25, 26, -1, -1, 29, 30, -1, -1, -1, + -1, 35, 36, 37, -1, -1, 40, -1, -1, -1, + 44, -1, 46, 47, -1, -1, -1, -1, 52, 53, + 54, -1, -1, 57, -1, -1, -1, -1, 62, 63, + -1, 65, -1, -1, -1, 69, 70, 71, -1, 73, + 74, 75, -1, 77, 78, -1, 80, -1, 82, 83, + 84, -1, 86, 87, -1, 89, -1, -1, -1, -1, + -1, -1, -1, -1, 98, -1, 100, -1, -1, -1, + -1, -1, -1, -1, 108, 109, -1, 111, 112, 113, + -1, 115, 116, -1, 118, -1, -1, 121, 122, 123, + -1, 125, -1, 127, -1, 129, 130, -1, 132, 133, + 1, -1, 3, 4, 5, 6, 7, -1, 9, 10, + 11, 12, 13, 14, -1, -1, 17, -1, 19, 20, + -1, -1, -1, -1, 25, 26, -1, -1, 29, 30, + -1, -1, -1, -1, 35, 36, 37, -1, -1, 40, + -1, -1, -1, -1, -1, 46, 47, -1, -1, -1, + -1, 52, 53, 54, -1, -1, 57, -1, -1, -1, + -1, 62, 63, -1, 65, -1, -1, -1, 69, 70, + 71, -1, 73, 74, 75, -1, -1, 78, -1, 80, + -1, 82, 83, 84, -1, 86, 87, -1, 89, -1, + -1, -1, -1, -1, -1, -1, -1, 98, -1, 100, + -1, -1, -1, -1, -1, -1, -1, 108, 109, -1, + 111, 112, 113, -1, 115, 116, -1, 118, -1, -1, + 121, 122, 123, -1, 125, -1, 127, -1, 129, 130, + -1, 132, 133, 1, -1, 3, 4, 5, 6, 7, + -1, 9, 10, 11, 12, 13, -1, -1, -1, 17, + -1, 19, 20, -1, -1, -1, -1, 25, 26, -1, + -1, 29, 30, -1, -1, -1, -1, 35, 36, 37, + -1, -1, 40, 41, -1, -1, -1, -1, 46, 47, + -1, -1, -1, -1, 52, 53, 54, -1, -1, 57, + -1, -1, -1, -1, 62, 63, -1, 65, -1, -1, + -1, 69, 70, 71, -1, 73, 74, 75, -1, -1, + 78, -1, 80, -1, 82, 83, 84, -1, 86, 87, + -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, + 98, -1, 100, -1, -1, -1, -1, -1, -1, -1, + 108, 109, -1, 111, 112, 113, -1, 115, 116, -1, + 118, -1, -1, 121, 122, 123, -1, 125, -1, 127, + -1, 129, 130, -1, 132, 133, 1, -1, 3, 4, + 5, 6, 7, -1, 9, 10, 11, 12, 13, -1, + -1, -1, 17, -1, 19, 20, -1, -1, -1, -1, + 25, 26, -1, -1, 29, 30, -1, -1, -1, -1, + 35, 36, 37, -1, -1, 40, -1, -1, -1, -1, + -1, 46, 47, -1, -1, -1, -1, 52, 53, 54, + -1, -1, 57, -1, -1, -1, -1, 62, 63, -1, + 65, -1, -1, -1, 69, 70, 71, -1, 73, 74, + 75, 76, -1, 78, -1, 80, -1, 82, 83, 84, + -1, 86, 87, -1, 89, -1, -1, -1, -1, -1, + -1, -1, -1, 98, -1, 100, -1, -1, -1, -1, + -1, -1, -1, 108, 109, -1, 111, 112, 113, -1, + 115, 116, -1, 118, -1, -1, 121, 122, 123, -1, + 125, -1, 127, -1, 129, 130, -1, 132, 133, 1, + -1, 3, 4, 5, 6, 7, -1, 9, 10, 11, + 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, + -1, -1, -1, 25, 26, -1, -1, 29, 30, -1, + -1, -1, -1, 35, 36, 37, -1, -1, 40, -1, + -1, -1, -1, -1, 46, 47, -1, -1, -1, -1, + 52, 53, 54, -1, -1, 57, -1, -1, -1, -1, + 62, 63, -1, 65, -1, -1, -1, 69, 70, 71, + -1, 73, 74, 75, -1, -1, 78, -1, 80, -1, + 82, 83, 84, -1, 86, 87, -1, 89, -1, -1, + -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 108, 109, -1, 111, + 112, 113, -1, 115, 116, -1, 118, -1, -1, 121, + 122, 123, -1, 125, -1, 127, -1, 129, 130, -1, + 132, 133, 1, -1, 3, 4, 5, 6, 7, -1, + 9, 10, 11, 12, 13, -1, -1, -1, 17, 18, + 19, 20, -1, -1, -1, -1, 25, 26, -1, -1, + 29, 30, -1, -1, -1, -1, 35, 36, 37, -1, + -1, 40, -1, -1, -1, -1, -1, 46, 47, -1, + -1, -1, -1, 52, 53, 54, -1, -1, 57, -1, + -1, -1, -1, 62, 63, -1, 65, -1, -1, -1, + 69, 70, 71, -1, 73, 74, 75, -1, -1, 78, + -1, 80, -1, 82, 83, 84, -1, 86, 87, -1, + 89, -1, -1, -1, -1, -1, -1, -1, -1, 98, + -1, 100, -1, -1, -1, -1, -1, -1, -1, 108, + 109, -1, 111, 112, 113, -1, 115, 116, -1, 118, + -1, -1, 121, 122, 123, -1, 125, -1, 127, -1, + 129, 130, -1, 132, 133, 1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 11, 12, 13, -1, -1, + -1, 17, -1, 19, 20, -1, -1, -1, -1, 25, + 26, -1, -1, 29, 30, -1, -1, -1, -1, 35, + 36, 37, -1, -1, 40, -1, -1, -1, 44, -1, + 46, 47, -1, -1, -1, -1, 52, 53, 54, -1, + -1, 57, -1, -1, -1, -1, 62, 63, -1, 65, + -1, -1, -1, 69, 70, 71, -1, 73, 74, 75, + -1, -1, 78, -1, 80, -1, 82, 83, 84, -1, + 86, 87, -1, 89, -1, -1, -1, -1, -1, -1, + -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, + -1, -1, 108, 109, -1, 111, 112, 113, -1, 115, + 116, -1, 118, -1, -1, 121, 122, 123, -1, 125, + -1, 127, -1, 129, 130, -1, 132, 133, 1, -1, + 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, + 13, -1, -1, -1, 17, 18, 19, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 29, 30, -1, -1, + -1, -1, 35, 36, 37, -1, -1, 40, -1, -1, + -1, -1, -1, 46, 47, -1, -1, -1, -1, 52, + 53, 54, -1, -1, 57, -1, -1, -1, -1, 62, + 63, -1, 65, -1, -1, -1, 69, 70, 71, -1, + 73, 74, 75, -1, -1, 78, -1, 80, -1, 82, + 83, 84, -1, 86, 87, -1, 89, -1, -1, -1, + -1, -1, -1, -1, -1, 98, -1, 100, -1, -1, + -1, -1, -1, -1, -1, 108, 109, -1, 111, 112, + 113, -1, 115, 116, -1, 118, -1, -1, 121, 122, + 123, -1, 125, -1, 127, -1, 129, 130, -1, 132, + 133, 1, -1, 3, 4, 5, 6, 7, -1, 9, + 10, 11, 12, 13, -1, -1, -1, 17, 18, 19, + 20, -1, -1, -1, -1, 25, 26, -1, -1, 29, + 30, -1, -1, -1, -1, 35, 36, 37, -1, -1, + 40, -1, -1, -1, -1, -1, 46, 47, -1, -1, + -1, -1, 52, 53, 54, -1, -1, 57, -1, -1, + -1, -1, 62, 63, -1, 65, -1, -1, -1, 69, + 70, 71, -1, 73, 74, 75, -1, -1, 78, -1, + 80, -1, 82, 83, 84, -1, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, -1, -1, -1, -1, 108, 109, + -1, 111, 112, 113, -1, 115, 116, -1, 118, -1, + -1, 121, 122, 123, -1, 125, -1, 127, -1, 129, + 130, -1, 132, 133, 1, -1, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, -1, -1, -1, + 17, -1, 19, 20, -1, -1, -1, -1, 25, 26, + -1, -1, 29, 30, -1, -1, -1, -1, 35, 36, + 37, -1, -1, 40, -1, -1, -1, -1, -1, 46, + 47, -1, -1, -1, -1, 52, 53, 54, -1, -1, + 57, -1, -1, -1, -1, 62, 63, -1, 65, -1, + -1, -1, 69, 70, 71, -1, 73, 74, 75, -1, + -1, 78, -1, 80, -1, 82, 83, 84, -1, 86, + 87, -1, 89, -1, -1, -1, -1, -1, -1, -1, + -1, 98, -1, 100, -1, -1, -1, -1, -1, -1, + -1, 108, 109, -1, 111, 112, 113, -1, 115, 116, + -1, 118, -1, -1, 121, 122, 123, -1, 125, -1, + 127, -1, 129, 130, -1, 132, 133, 1, -1, 3, + 4, 5, 6, 7, -1, 9, 10, 11, 12, 13, + -1, -1, -1, 17, -1, 19, 20, -1, -1, -1, + -1, 25, 26, -1, -1, 29, 30, -1, -1, -1, + -1, 35, 36, 37, -1, -1, 40, -1, -1, -1, + -1, -1, 46, 47, -1, -1, -1, -1, 52, 53, + 54, -1, -1, 57, -1, -1, -1, -1, 62, 63, + -1, 65, -1, -1, -1, 69, 70, 71, -1, 73, + 74, 75, -1, -1, 78, 79, 80, -1, 82, 83, + 84, -1, 86, 87, -1, 89, -1, -1, -1, -1, + -1, -1, -1, -1, 98, -1, 100, -1, -1, -1, + -1, -1, -1, -1, 108, 109, -1, 111, 112, 113, + -1, 115, 116, -1, 118, -1, -1, 121, 122, 123, + -1, 125, -1, 127, -1, 129, 130, -1, 132, 133, + 1, -1, 3, 4, 5, 6, 7, -1, 9, 10, + 11, 12, 13, -1, -1, -1, 17, -1, 19, 20, + -1, -1, -1, -1, 25, 26, -1, -1, 29, 30, + -1, -1, -1, -1, 35, 36, 37, -1, -1, 40, + -1, -1, -1, -1, -1, 46, 47, -1, -1, -1, + -1, 52, 53, 54, -1, -1, 57, -1, -1, -1, + -1, 62, 63, -1, 65, -1, -1, -1, 69, 70, + 71, -1, 73, 74, 75, -1, 77, 78, -1, 80, + -1, 82, 83, 84, -1, 86, 87, -1, 89, -1, + -1, -1, -1, -1, -1, -1, -1, 98, -1, 100, + -1, -1, -1, -1, -1, -1, -1, 108, 109, -1, + 111, 112, 113, -1, 115, 116, -1, 118, -1, -1, + 121, 122, 123, -1, 125, -1, 127, -1, 129, 130, + -1, 132, 133, 1, -1, 3, 4, 5, 6, 7, + -1, 9, 10, 11, 12, 13, -1, -1, -1, 17, + -1, 19, 20, -1, -1, -1, -1, 25, 26, -1, + -1, 29, 30, -1, -1, -1, -1, 35, 36, 37, + -1, -1, 40, -1, -1, -1, -1, -1, 46, 47, + -1, -1, -1, -1, 52, 53, 54, -1, -1, 57, + -1, -1, -1, -1, 62, 63, -1, 65, -1, -1, + -1, 69, 70, 71, -1, 73, 74, 75, -1, 77, + 78, -1, 80, -1, 82, 83, 84, -1, 86, 87, + -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, + 98, -1, 100, -1, -1, -1, -1, -1, -1, -1, + 108, 109, -1, 111, 112, 113, -1, 115, 116, -1, + 118, -1, -1, 121, 122, 123, -1, 125, -1, 127, + -1, 129, 130, -1, 132, 133, 1, -1, 3, 4, + 5, 6, 7, -1, 9, 10, 11, 12, 13, -1, + -1, -1, 17, -1, 19, 20, -1, -1, -1, -1, + 25, 26, -1, -1, 29, 30, -1, -1, -1, -1, + 35, 36, 37, -1, -1, 40, -1, -1, -1, -1, + -1, 46, 47, -1, -1, -1, 51, 52, 53, 54, + -1, -1, 57, -1, -1, -1, -1, 62, 63, -1, + 65, -1, -1, -1, 69, 70, 71, -1, 73, 74, + 75, -1, -1, 78, -1, 80, -1, 82, 83, 84, + -1, 86, 87, -1, 89, -1, -1, -1, -1, -1, + -1, -1, -1, 98, -1, 100, -1, -1, -1, -1, + -1, -1, -1, 108, 109, -1, 111, 112, 113, -1, + 115, 116, -1, 118, -1, -1, 121, 122, 123, -1, + 125, -1, 127, -1, 129, 130, -1, 132, 133, 1, + -1, 3, 4, 5, 6, 7, -1, 9, 10, 11, + 12, 13, -1, -1, -1, 17, -1, 19, 20, -1, + -1, -1, -1, 25, 26, -1, -1, 29, 30, -1, + -1, -1, -1, 35, 36, 37, -1, -1, 40, -1, + -1, -1, -1, -1, 46, 47, -1, -1, -1, -1, + 52, 53, 54, -1, -1, 57, -1, -1, -1, -1, + 62, 63, -1, 65, -1, -1, -1, 69, 70, 71, + -1, 73, 74, 75, 76, -1, 78, -1, 80, -1, + 82, 83, 84, -1, 86, 87, -1, 89, -1, -1, + -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 108, 109, -1, 111, + 112, 113, -1, 115, 116, -1, 118, -1, -1, 121, + 122, 123, -1, 125, -1, 127, -1, 129, 130, -1, + 132, 133, 1, -1, 3, 4, 5, 6, 7, -1, + 9, 10, 11, 12, 13, -1, -1, -1, 17, 18, + 19, 20, -1, -1, -1, -1, 25, 26, -1, -1, + 29, 30, -1, -1, -1, -1, 35, 36, 37, -1, + -1, 40, -1, -1, -1, -1, -1, 46, 47, -1, + -1, -1, -1, 52, 53, 54, -1, -1, 57, -1, + -1, -1, -1, 62, 63, -1, 65, -1, -1, -1, + 69, 70, 71, -1, 73, 74, 75, -1, -1, 78, + -1, 80, -1, 82, 83, 84, -1, 86, 87, -1, + 89, -1, -1, -1, -1, -1, -1, -1, -1, 98, + -1, 100, -1, -1, -1, -1, -1, -1, -1, 108, + 109, -1, 111, 112, 113, -1, 115, 116, -1, 118, + -1, -1, 121, 122, 123, -1, 125, -1, 127, -1, + 129, 130, -1, 132, 133, 1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 11, 12, 13, -1, -1, + -1, 17, -1, 19, 20, -1, -1, -1, -1, 25, + 26, -1, -1, 29, 30, -1, -1, -1, -1, 35, + 36, 37, -1, -1, 40, -1, -1, -1, -1, -1, + 46, 47, -1, -1, -1, -1, 52, 53, 54, -1, + -1, 57, -1, -1, -1, -1, 62, 63, -1, 65, + -1, -1, -1, 69, 70, 71, -1, 73, 74, 75, + -1, -1, 78, -1, 80, -1, 82, 83, 84, -1, + 86, 87, -1, 89, -1, -1, -1, -1, -1, -1, + -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, + -1, -1, 108, 109, -1, 111, 112, 113, -1, 115, + 116, -1, 118, 119, -1, 121, 122, 123, -1, 125, + -1, 127, -1, 129, 130, -1, 132, 133, 1, -1, + 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, + 13, -1, -1, -1, 17, -1, 19, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 29, 30, -1, -1, + -1, -1, 35, 36, 37, -1, -1, 40, -1, -1, + -1, -1, -1, 46, 47, -1, -1, -1, -1, 52, + 53, 54, -1, -1, 57, -1, -1, -1, -1, 62, + 63, -1, 65, -1, -1, -1, 69, 70, 71, -1, + 73, 74, 75, -1, -1, 78, -1, 80, -1, 82, + 83, 84, -1, 86, 87, -1, 89, -1, -1, -1, + -1, -1, -1, -1, -1, 98, -1, 100, -1, -1, + -1, -1, -1, -1, -1, 108, 109, 110, 111, 112, + 113, -1, 115, 116, -1, 118, -1, -1, 121, 122, + 123, -1, 125, -1, 127, -1, 129, 130, -1, 132, + 133, 1, -1, 3, 4, 5, 6, 7, -1, 9, + 10, 11, 12, 13, -1, -1, -1, 17, -1, 19, + 20, -1, -1, -1, -1, 25, 26, -1, -1, 29, + 30, -1, -1, -1, -1, 35, 36, 37, -1, -1, + 40, -1, -1, -1, -1, -1, 46, 47, -1, -1, + -1, -1, 52, 53, 54, -1, -1, 57, -1, -1, + -1, -1, 62, 63, -1, 65, -1, -1, -1, 69, + 70, 71, -1, 73, 74, 75, -1, -1, 78, -1, + 80, -1, 82, 83, 84, -1, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, -1, -1, -1, -1, 108, 109, + 110, 111, 112, 113, -1, 115, 116, -1, 118, -1, + -1, 121, 122, 123, -1, 125, -1, 127, -1, 129, + 130, -1, 132, 133, 1, -1, 3, 4, 5, 6, + 7, -1, 9, 10, 11, 12, 13, -1, -1, -1, + 17, -1, 19, 20, -1, -1, -1, -1, 25, 26, + -1, -1, 29, 30, -1, -1, -1, -1, 35, 36, + 37, -1, -1, 40, -1, -1, -1, -1, -1, 46, + 47, -1, -1, -1, -1, 52, 53, 54, -1, -1, + 57, -1, -1, -1, -1, 62, 63, -1, 65, -1, + -1, -1, 69, 70, 71, -1, 73, 74, 75, -1, + -1, 78, -1, 80, -1, 82, 83, 84, -1, 86, + 87, -1, 89, -1, -1, -1, -1, -1, -1, -1, + -1, 98, -1, 100, -1, -1, -1, -1, -1, -1, + -1, 108, 109, -1, 111, 112, 113, -1, 115, 116, + -1, 118, -1, -1, 121, 122, 123, -1, 125, -1, + 127, -1, 129, 130, -1, 132, 133, 1, -1, 3, + 4, 5, 6, 7, -1, 9, 10, 11, 12, 13, + -1, -1, -1, 17, -1, 19, 20, -1, -1, -1, + -1, 25, 26, -1, -1, 29, 30, -1, -1, -1, + -1, 35, 36, 37, -1, -1, 40, -1, -1, -1, + -1, -1, 46, 47, -1, -1, -1, -1, 52, 53, + 54, -1, -1, 57, -1, -1, -1, -1, 62, 63, + -1, 65, -1, -1, -1, 69, 70, 71, -1, 73, + 74, 75, -1, -1, 78, -1, 80, -1, 82, 83, + 84, -1, 86, 87, -1, 89, -1, -1, -1, -1, + -1, -1, -1, -1, 98, -1, 100, -1, -1, -1, + -1, -1, -1, -1, 108, 109, -1, 111, 112, 113, + -1, 115, 116, -1, 118, -1, -1, 121, 122, 123, + -1, 125, -1, 127, -1, 129, 130, -1, 132, 133, + 1, -1, 3, 4, 5, 6, 7, -1, 9, 10, + 11, 12, 13, -1, -1, -1, 17, -1, 19, 20, + -1, -1, -1, -1, 25, 26, -1, -1, 29, 30, + -1, -1, -1, -1, 35, 36, 37, -1, -1, 40, + -1, -1, -1, -1, -1, 46, 47, -1, -1, -1, + -1, 52, 53, 54, -1, -1, 57, -1, -1, -1, + -1, 62, 63, -1, 65, -1, -1, -1, 69, 70, + 71, -1, 73, 74, 75, -1, -1, 78, -1, 80, + -1, 82, 83, 84, -1, 86, 87, -1, 89, -1, + -1, -1, -1, -1, -1, -1, -1, 98, -1, 100, + -1, -1, -1, -1, -1, -1, -1, 108, 109, -1, + 111, 112, 113, -1, 115, 116, -1, 118, -1, -1, + 121, 122, 123, -1, 125, -1, 127, -1, 129, 130, + -1, 132, 133, 1, -1, 3, 4, 5, 6, 7, + -1, 9, 10, 11, 12, 13, -1, -1, -1, 17, + -1, 19, 20, -1, -1, -1, -1, 25, 26, -1, + -1, 29, 30, -1, -1, -1, -1, 35, 36, 37, + -1, -1, 40, -1, -1, -1, -1, -1, 46, 47, + -1, -1, -1, -1, 52, 53, 54, -1, -1, 57, + -1, -1, -1, -1, 62, 63, -1, 65, -1, -1, + -1, 69, 70, 71, -1, 73, 74, 75, -1, -1, + 78, -1, 80, -1, 82, 83, 84, -1, 86, 87, + -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, + 98, -1, 100, -1, -1, -1, -1, -1, -1, -1, + 108, 109, -1, 111, 112, 113, -1, 115, 116, -1, + 118, -1, -1, 121, 122, 123, -1, 125, -1, 127, + -1, 129, 130, -1, 132, 133, 1, -1, 3, 4, + 5, 6, 7, -1, 9, 10, 11, 12, 13, -1, + -1, -1, 17, -1, 19, 20, -1, -1, -1, -1, + 25, 26, -1, -1, 29, 30, -1, -1, -1, -1, + 35, 36, 37, -1, -1, 40, -1, -1, -1, -1, + -1, 46, 47, -1, -1, -1, -1, 52, 53, 54, + -1, -1, 57, -1, -1, -1, -1, 62, 63, -1, + 65, -1, -1, -1, 69, 70, 71, -1, 73, 74, + 75, -1, -1, 78, -1, 80, -1, 82, 83, 84, + -1, 86, 87, -1, 89, -1, -1, -1, -1, -1, + -1, -1, -1, 98, -1, 100, -1, -1, -1, -1, + -1, -1, -1, 108, 109, -1, 111, 112, 113, -1, + 115, 116, -1, 118, -1, -1, 121, 122, 123, -1, + 125, -1, 127, -1, 129, 130, -1, 132, 133, 1, + -1, 3, 4, 5, 6, 7, -1, 9, 10, 11, + 12, 13, -1, -1, -1, 17, -1, 19, 20, -1, + -1, -1, -1, 25, 26, -1, -1, 29, 30, -1, + -1, -1, -1, 35, 36, 37, -1, -1, 40, -1, + -1, -1, -1, -1, 46, 47, -1, -1, -1, -1, + 52, 53, 54, -1, -1, 57, -1, -1, -1, -1, + 62, 63, -1, 65, -1, -1, -1, 69, 70, 71, + -1, 73, 74, 75, -1, -1, 78, -1, 80, -1, + 82, 83, 84, -1, 86, 87, -1, 89, -1, -1, + -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 108, 109, -1, 111, + 112, 113, -1, 115, 116, -1, 118, -1, -1, 121, + 122, 123, -1, 125, -1, 127, -1, 129, 130, -1, + 132, 133, 1, -1, 3, 4, 5, 6, 7, -1, + 9, 10, 11, 12, 13, -1, -1, -1, 17, -1, + 19, 20, -1, -1, -1, -1, 25, 26, -1, -1, + 29, 30, -1, -1, -1, -1, 35, 36, 37, -1, + -1, 40, -1, -1, -1, -1, -1, 46, 47, -1, + -1, -1, -1, 52, 53, 54, -1, -1, 57, -1, + -1, -1, -1, 62, 63, -1, 65, -1, -1, -1, + 69, 70, 71, -1, 73, 74, 75, -1, -1, 78, + -1, 80, -1, 82, 83, 84, -1, 86, 87, -1, + 89, -1, -1, -1, -1, -1, -1, -1, -1, 98, + -1, 100, -1, -1, -1, -1, -1, -1, -1, 108, + 109, -1, 111, 112, 113, -1, 115, 116, -1, 118, + -1, -1, 121, 122, 123, -1, 125, -1, 127, -1, + 129, 130, -1, 132, 133, 1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 11, 12, 13, -1, -1, + -1, 17, -1, 19, 20, -1, -1, -1, -1, 25, + 26, -1, -1, 29, 30, -1, -1, -1, -1, 35, + 36, 37, -1, -1, 40, -1, -1, -1, -1, -1, + 46, 47, -1, -1, -1, -1, 52, 53, 54, -1, + -1, 57, -1, -1, -1, -1, 62, 63, -1, 65, + -1, -1, -1, 69, 70, 71, -1, 73, 74, 75, + -1, -1, 78, -1, 80, -1, 82, 83, 84, -1, + 86, 87, -1, 89, -1, -1, -1, -1, -1, -1, + -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, + -1, -1, 108, 109, -1, 111, 112, 113, -1, 115, + 116, -1, 118, -1, -1, 121, 122, 123, -1, 125, + -1, 127, -1, 129, 130, -1, 132, 133, 1, -1, + 3, 4, 5, 6, 7, -1, 9, 10, 11, 12, + 13, -1, -1, -1, 17, -1, 19, 20, -1, -1, + -1, -1, 25, 26, -1, -1, 29, 30, -1, -1, + -1, -1, 35, 36, 37, -1, -1, 40, -1, -1, + -1, -1, -1, 46, 47, -1, -1, -1, -1, 52, + 53, 54, -1, -1, 57, -1, -1, -1, -1, 62, + 63, -1, 65, -1, -1, -1, 69, 70, 71, -1, + 73, 74, 75, -1, -1, 78, -1, 80, -1, 82, + 83, 84, -1, 86, 87, -1, 89, -1, -1, -1, + -1, -1, -1, -1, -1, 98, -1, 100, -1, -1, + -1, -1, -1, -1, -1, 108, 109, -1, 111, 112, + 113, -1, 115, 116, -1, 118, -1, -1, 121, 122, + 123, -1, 125, -1, 127, -1, 129, 130, -1, 132, + 133, 1, -1, 3, 4, 5, 6, 7, -1, 9, + 10, 11, 12, 13, -1, -1, -1, 17, -1, 19, + 20, -1, -1, -1, -1, 25, 26, -1, -1, 29, + 30, -1, -1, -1, -1, 35, 36, 37, -1, -1, + 40, -1, -1, -1, -1, -1, 46, 47, -1, -1, + -1, -1, 52, 53, 54, -1, -1, 57, -1, -1, + -1, -1, 62, 63, -1, 65, -1, -1, -1, 69, + 70, 71, -1, 73, 74, 75, -1, -1, 78, -1, + 80, -1, 82, 83, 84, -1, 86, 87, -1, 89, + -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, -1, -1, -1, -1, 108, 109, + -1, 111, 112, 113, -1, 115, 116, -1, 118, -1, + -1, 121, 122, 123, -1, 125, -1, 127, -1, 129, + 130, -1, 132, 133, 11, 12, -1, 14, 15, 16, + 17, -1, 19, 20, 21, 22, 23, 24, -1, -1, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, -1, -1, -1, -1, -1, 45, -1, + -1, -1, -1, -1, -1, -1, -1, 12, 55, 14, + 15, 16, 17, -1, 19, 20, 21, 22, 23, 24, + 67, -1, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, -1, -1, -1, 85, -1, + 45, -1, -1, -1, -1, 50, -1, -1, 12, -1, + -1, -1, -1, 17, -1, 19, 20, 21, 22, 23, + 24, -1, 67, 27, -1, -1, 30, 114, 32, 33, + 117, 35, 36, 120, 38, -1, -1, 124, 125, -1, + 85, 128, -1, -1, 131, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 109, -1, -1, -1, -1, 114, + -1, -1, 117, -1, -1, 120, -1, -1, -1, 124, + 125, 85, -1, 128, -1, 12, 131, 14, 15, 16, + 17, -1, 19, 20, 21, 22, 23, 24, -1, -1, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, -1, 41, -1, -1, -1, 45, -1, + -1, 125, -1, -1, 128, -1, -1, 131, -1, -1, + 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 67, -1, -1, -1, 12, -1, 14, 15, 16, 17, + -1, 19, 20, 21, 22, 23, 24, -1, 85, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, -1, -1, 41, -1, -1, -1, 45, -1, 47, + -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, + 117, -1, -1, 120, -1, -1, -1, 124, 125, 67, + -1, 128, -1, 12, 131, 14, 15, 16, 17, -1, + 19, 20, 21, 22, 23, 24, -1, 85, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + -1, -1, 41, -1, -1, -1, 45, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 114, -1, 57, 117, + -1, -1, 120, -1, -1, -1, 124, 125, 67, -1, + 128, -1, 12, 131, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, -1, 85, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 114, -1, -1, 117, -1, + -1, 120, -1, -1, -1, 124, 125, 67, -1, 128, + -1, -1, 131, -1, -1, -1, -1, -1, -1, 12, + -1, 14, 15, 16, 17, 85, 19, 20, 21, 22, + 23, 24, -1, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, -1, -1, -1, -1, + -1, -1, 45, -1, 114, -1, -1, 117, -1, -1, + 120, -1, -1, -1, 124, 125, -1, -1, 128, -1, + -1, 131, -1, -1, 67, -1, -1, -1, 12, -1, + 14, 15, 16, 17, -1, 19, 20, 21, 22, 23, + 24, -1, 85, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, -1, -1, -1, -1, + -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 114, -1, 57, 117, -1, -1, 120, -1, -1, + -1, 124, 125, 67, -1, 128, -1, 12, 131, 14, + 15, 16, 17, -1, 19, 20, 21, 22, 23, 24, + -1, 85, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 114, -1, -1, 117, -1, 60, 120, -1, -1, -1, + 124, 125, 67, -1, 128, -1, 12, 131, 14, 15, + 16, 17, -1, 19, 20, 21, 22, 23, 24, -1, + 85, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, -1, -1, -1, -1, -1, -1, 45, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, + -1, -1, 117, -1, 60, 120, -1, -1, -1, 124, + 125, 67, -1, 128, -1, 12, 131, 14, 15, 16, + 17, -1, 19, 20, 21, 22, 23, 24, -1, 85, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, -1, -1, -1, -1, -1, 45, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 114, -1, + -1, 117, -1, -1, 120, -1, -1, -1, 124, 125, + 67, -1, 128, -1, 12, 131, 14, 15, 16, 17, + -1, 19, 20, 21, 22, 23, 24, -1, 85, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, -1, 99, -1, -1, -1, -1, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, + 117, -1, -1, 120, -1, -1, -1, 124, 125, 67, + -1, 128, -1, 12, 131, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, -1, 85, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, + -1, 109, -1, -1, -1, -1, 114, -1, -1, 117, + -1, -1, 120, -1, -1, -1, 124, 125, 67, -1, + 128, -1, 12, 131, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, -1, 85, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 114, -1, -1, 117, -1, + -1, 120, -1, -1, -1, 124, 125, 67, -1, 128, + -1, 12, 131, 14, 15, 16, 17, -1, 19, 20, + 21, 22, 23, 24, -1, 85, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, + 41, -1, -1, -1, 45, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 114, -1, -1, 117, -1, -1, + 120, -1, -1, -1, 124, 125, 67, -1, 128, -1, + 12, 131, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, -1, 85, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, + -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 114, -1, -1, 117, -1, -1, 120, + -1, -1, -1, 124, 125, 67, -1, 128, -1, 12, + 131, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, -1, 85, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, -1, -1, -1, -1, + -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 114, -1, -1, 117, -1, -1, 120, -1, + -1, -1, 124, 125, 67, -1, 128, -1, 12, 131, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, -1, 85, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, -1, -1, -1, -1, + -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 114, -1, -1, 117, -1, -1, 120, -1, -1, + -1, 124, 125, 67, -1, 128, -1, 12, 131, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + -1, 85, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 114, -1, -1, 117, -1, -1, 120, -1, -1, -1, + 124, 125, 67, -1, 128, -1, 12, 131, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, + 85, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, -1, -1, -1, -1, -1, -1, 45, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, + -1, -1, 117, -1, -1, 120, -1, -1, -1, 124, + 125, 67, -1, 128, -1, 12, 131, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, -1, 85, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, -1, -1, -1, -1, -1, 45, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 114, -1, + -1, 117, -1, -1, 120, -1, -1, -1, 124, 125, + 67, -1, 128, -1, 12, 131, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, -1, 85, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, -1, -1, -1, -1, -1, -1, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, + 117, -1, -1, 120, -1, -1, -1, 124, 125, 67, + -1, 128, -1, 12, 131, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, -1, 85, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 114, -1, -1, 117, + -1, -1, 120, -1, -1, -1, 124, 125, 67, -1, + 128, -1, 12, 131, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, -1, 85, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, + -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 114, -1, -1, 117, -1, + -1, 120, -1, -1, -1, 124, 125, 67, -1, 128, + -1, 12, 131, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, -1, 85, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, + -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 114, -1, -1, 117, -1, -1, + 120, -1, -1, -1, 124, 125, 67, -1, 128, -1, + 12, 131, 14, 15, 16, 17, -1, 19, 20, 21, + 22, 23, 24, -1, 85, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, -1, -1, 41, + -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 114, -1, -1, 117, -1, -1, 120, + -1, -1, -1, 124, 125, 67, -1, 128, -1, 12, + 131, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, -1, 85, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, -1, -1, -1, -1, + -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 114, -1, -1, 117, -1, -1, 120, -1, + -1, -1, 124, 125, 67, -1, 128, -1, 12, 131, + 14, 15, 16, 17, -1, 19, 20, 21, 22, 23, + 24, -1, 85, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, -1, 41, -1, -1, + -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 114, -1, -1, 117, -1, -1, 120, -1, -1, + -1, 124, 125, 67, -1, 128, -1, 12, 131, 14, + 15, 16, 17, -1, 19, 20, 21, 22, 23, 24, + -1, 85, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, 50, -1, -1, -1, -1, + 114, -1, -1, 117, -1, -1, 120, -1, -1, -1, + 124, 125, 67, -1, 128, -1, 12, 131, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, + 85, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, -1, -1, -1, -1, -1, -1, 45, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, + -1, -1, 117, -1, -1, 120, -1, -1, -1, 124, + 125, 67, -1, 128, -1, 12, 131, 14, 15, 16, + 17, -1, 19, 20, 21, 22, 23, 24, -1, 85, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, -1, 41, -1, -1, -1, 45, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 114, -1, + -1, 117, -1, -1, 120, -1, -1, -1, 124, 125, + 67, -1, 128, -1, 12, 131, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, -1, 85, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, -1, -1, -1, -1, -1, -1, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, + 117, -1, -1, 120, -1, -1, -1, 124, 125, 67, + -1, 128, -1, -1, 131, -1, -1, -1, -1, -1, + -1, 12, -1, 14, 15, 16, 17, 85, 19, 20, + 21, 22, 23, 24, -1, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, + -1, -1, -1, -1, 45, -1, 114, -1, -1, 117, + -1, -1, 120, -1, -1, -1, 124, 125, -1, -1, + 128, -1, -1, 131, -1, -1, 67, -1, -1, -1, + 12, -1, 14, 15, 16, 17, -1, 19, 20, 21, + 22, 23, 24, -1, 85, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, + -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 114, -1, -1, 117, -1, 60, 120, + -1, -1, -1, 124, 125, 67, -1, 128, -1, 12, + 131, 14, 15, 16, 17, -1, 19, 20, 21, 22, + 23, 24, -1, 85, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, -1, -1, -1, -1, + -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 114, -1, -1, 117, -1, -1, 120, -1, + -1, -1, 124, 125, 67, -1, 128, -1, 12, 131, + 14, 15, 16, 17, 77, 19, 20, 21, 22, 23, + 24, -1, 85, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, -1, -1, -1, -1, + 44, 45, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 114, -1, -1, 117, -1, -1, 120, -1, -1, + -1, 124, 125, 67, -1, 128, -1, 12, 131, 14, + 15, 16, 17, -1, 19, 20, 21, 22, 23, 24, + -1, 85, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, -1, -1, -1, -1, 44, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 114, -1, -1, 117, -1, -1, 120, -1, -1, -1, + 124, 125, 67, -1, 128, -1, -1, 131, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 85, 12, -1, 14, 15, 16, 17, -1, 19, 20, + 21, 22, 23, 24, -1, -1, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, -1, 114, + -1, -1, 117, -1, 45, 120, -1, -1, -1, 124, + 125, -1, -1, 128, -1, -1, 131, -1, -1, -1, + 61, -1, -1, -1, -1, -1, 67, -1, -1, -1, + 12, -1, 14, 15, 16, 17, -1, 19, 20, 21, + 22, 23, 24, -1, 85, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, + -1, -1, 44, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 114, -1, -1, 117, -1, -1, 120, + -1, -1, -1, 124, 125, 67, -1, 128, -1, 12, + 131, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, -1, 85, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, -1, -1, -1, -1, + -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 114, -1, -1, 117, -1, -1, 120, -1, + -1, -1, 124, 125, 67, -1, 128, -1, 12, 131, + 14, 15, 16, 17, -1, 19, 20, 21, 22, 23, + 24, -1, 85, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, -1, 41, -1, -1, + -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 114, -1, -1, 117, -1, -1, 120, -1, -1, + -1, 124, 125, 67, -1, 128, -1, 12, 131, 14, + 15, 16, 17, -1, 19, 20, 21, 22, 23, 24, + -1, 85, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, 50, -1, -1, -1, -1, + 114, -1, -1, 117, -1, -1, 120, -1, -1, -1, + 124, 125, 67, -1, 128, -1, 12, 131, 14, 15, + 16, 17, -1, 19, 20, 21, 22, 23, 24, -1, + 85, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, -1, -1, -1, -1, -1, -1, 45, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, + -1, -1, 117, -1, 60, 120, -1, -1, -1, 124, + 125, 67, -1, 128, -1, 12, 131, 14, 15, 16, + 17, -1, 19, 20, 21, 22, 23, 24, -1, 85, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, -1, -1, -1, -1, -1, 45, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 114, -1, + -1, 117, -1, 60, 120, -1, -1, -1, 124, 125, + 67, -1, 128, -1, 12, 131, 14, 15, 16, 17, + -1, 19, 20, 21, 22, 23, 24, -1, 85, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, -1, -1, -1, -1, -1, 44, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, + 117, -1, -1, 120, -1, -1, -1, 124, 125, 67, + -1, 128, -1, 12, 131, 14, 15, 16, 17, -1, + 19, 20, 21, 22, 23, 24, -1, 85, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, + -1, 50, -1, -1, -1, -1, 114, -1, -1, 117, + -1, -1, 120, -1, -1, -1, 124, 125, 67, -1, + 128, -1, 12, 131, 14, 15, 16, 17, -1, 19, + 20, 21, 22, 23, 24, -1, 85, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, + -1, 41, -1, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 114, -1, -1, 117, -1, + -1, 120, -1, -1, -1, 124, 125, 67, -1, 128, + -1, 12, 131, 14, 15, 16, 17, -1, 19, 20, + 21, 22, 23, 24, -1, 85, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, + -1, -1, -1, 44, 45, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 114, -1, -1, 117, -1, -1, + 120, -1, -1, -1, 124, 125, 67, -1, 128, -1, + 12, 131, 14, 15, 16, 17, -1, 19, 20, 21, + 22, 23, 24, -1, 85, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, + -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 114, -1, -1, 117, -1, -1, 120, + -1, -1, -1, 124, 125, 67, -1, 128, -1, 12, + 131, 14, 15, 16, 17, -1, 19, 20, 21, 22, + 23, 24, -1, 85, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, -1, -1, -1, -1, + -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 114, -1, -1, 117, -1, -1, 120, -1, + -1, -1, 124, 125, 67, -1, 128, -1, 12, 131, + 14, 15, 16, 17, -1, 19, 20, 21, 22, 23, + 24, -1, 85, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, -1, -1, -1, -1, + -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 114, -1, -1, 117, -1, -1, 120, -1, -1, + -1, 124, 125, 67, -1, 128, -1, 12, 131, -1, + 15, 16, 17, -1, 19, 20, 21, 22, 23, 24, + -1, 85, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 117, -1, -1, 120, -1, -1, -1, + 124, 125, 67, -1, 128, -1, 12, 131, 14, 15, + 16, 17, -1, 19, 20, 21, 22, 23, 24, -1, + 85, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, -1, -1, -1, -1, -1, -1, 45, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, + -1, -1, 117, -1, -1, 120, -1, -1, -1, 124, + 125, 67, -1, 128, -1, 12, 131, -1, 15, 16, + 17, -1, 19, 20, 21, 22, 23, 24, -1, 85, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, -1, -1, -1, -1, -1, -1, 45, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 120, -1, -1, -1, 124, 125, + -1, -1, 128, -1, 12, 131, 14, -1, 16, 17, + -1, 19, 20, 21, 22, 23, 24, -1, 85, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, -1, -1, -1, -1, -1, -1, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, + 117, -1, -1, 120, -1, -1, -1, 124, 125, 67, + -1, 128, -1, 12, 131, -1, -1, 16, 17, -1, + 19, 20, 21, 22, 23, 24, -1, 85, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 124, 125, 67, -1, + 128, -1, 12, 131, -1, -1, 16, 17, -1, 19, + 20, 21, 22, 23, 24, -1, 85, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, + -1, -1, 101, -1, -1, 45, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 124, 125, 67, -1, 128, + -1, 12, 131, -1, -1, 16, 17, -1, 19, 20, + 21, 22, 23, 24, -1, 85, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, + -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 124, 125, 67, -1, 128, -1, + 12, 131, -1, -1, 16, 17, -1, 19, 20, 21, + 22, 23, 24, -1, 85, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, + -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 124, 125, 67, -1, 128, -1, 12, + 131, -1, -1, 16, 17, -1, 19, 20, 21, 22, + 23, 24, -1, 85, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 12, -1, -1, -1, + -1, 17, -1, 19, 20, 21, 22, 23, 24, -1, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + 36, 37, 38, 125, 67, -1, 128, -1, -1, 131, + -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, + -1, -1, 85, 17, -1, 19, 20, 21, 22, 23, + 24, 67, -1, 27, 28, 29, 30, 31, 32, 33, + -1, 35, 36, 37, 38, -1, -1, -1, 12, 85, + -1, -1, -1, 17, -1, 19, 20, 21, 22, 23, + 24, -1, 125, 27, -1, 128, 30, -1, 131, -1, + -1, 35, 36, 67, 38, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 125, + -1, 85, 128, 12, -1, 131, -1, -1, 17, -1, + 19, 20, 21, 22, 23, 24, -1, -1, 27, -1, + -1, 30, 31, 32, 33, 12, 35, 36, -1, 38, + 17, 85, 19, 20, 21, 22, 23, 24, -1, -1, + 27, 125, -1, 30, 128, 32, 33, 131, 35, 36, + -1, 38, -1, -1, -1, 12, -1, -1, -1, -1, + 17, -1, 19, 20, 21, 22, 23, 24, -1, -1, + 27, 125, -1, -1, 128, -1, 85, 131, 35, 36, + 12, 38, -1, -1, -1, 17, -1, -1, -1, -1, + 22, 23, 24, -1, -1, 27, -1, 12, 85, -1, + -1, -1, 17, 35, 36, -1, 38, -1, 23, 24, + -1, -1, 27, -1, -1, -1, 125, -1, -1, 128, + 35, 36, 131, 38, 12, -1, -1, -1, 85, 17, + -1, -1, -1, -1, -1, 23, 24, -1, 125, 27, + -1, 128, -1, -1, 131, -1, -1, 35, 36, 12, + 38, -1, -1, 85, 17, -1, -1, -1, -1, -1, + -1, 24, -1, -1, 27, -1, -1, -1, 125, -1, + 85, 128, 35, 36, 131, 38, 12, -1, -1, -1, + -1, 17, -1, -1, -1, -1, -1, -1, 24, -1, + -1, 27, -1, 125, -1, -1, 128, 85, -1, 35, + 36, -1, 38, -1, -1, -1, -1, -1, -1, -1, + 125, -1, -1, 128, -1, -1, -1, -1, -1, -1, + -1, -1, 85, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 125, -1, -1, + 128, -1, -1, -1, -1, -1, -1, -1, -1, 85, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 125, -1, -1, 128, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 128 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 1, 3, 4, 5, 6, 7, 9, 10, 11, + 12, 13, 17, 19, 20, 25, 26, 29, 30, 35, + 36, 37, 40, 46, 47, 52, 53, 54, 57, 62, + 63, 65, 69, 70, 71, 73, 74, 75, 78, 80, + 82, 83, 84, 86, 87, 89, 98, 100, 108, 109, + 111, 112, 113, 115, 116, 118, 121, 122, 123, 125, + 127, 129, 130, 132, 133, 137, 138, 139, 141, 144, + 4, 5, 10, 46, 142, 46, 15, 17, 17, 38, + 139, 4, 139, 139, 139, 13, 78, 139, 139, 14, + 139, 4, 139, 139, 150, 4, 17, 139, 17, 17, + 17, 139, 3, 4, 10, 13, 17, 133, 140, 141, + 17, 139, 139, 139, 151, 76, 158, 17, 17, 141, + 17, 109, 139, 17, 17, 17, 38, 10, 152, 153, + 17, 83, 139, 139, 139, 139, 141, 151, 139, 150, + 139, 151, 151, 158, 141, 139, 153, 38, 139, 17, + 139, 47, 55, 164, 151, 139, 17, 0, 8, 12, + 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 44, 45, 67, 85, 114, 117, 120, 124, + 125, 128, 131, 17, 17, 4, 24, 128, 4, 10, + 13, 26, 133, 139, 18, 139, 18, 139, 139, 18, + 26, 26, 26, 139, 57, 41, 139, 50, 109, 139, + 139, 4, 11, 55, 163, 14, 139, 149, 67, 15, + 29, 58, 155, 139, 60, 60, 44, 66, 139, 165, + 81, 143, 146, 151, 72, 139, 150, 17, 139, 139, + 139, 139, 139, 88, 14, 152, 139, 99, 14, 17, + 77, 109, 160, 109, 109, 51, 109, 160, 17, 122, + 139, 18, 139, 151, 77, 50, 139, 67, 139, 139, + 139, 158, 150, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 141, + 40, 139, 8, 138, 139, 139, 6, 10, 14, 19, + 21, 22, 114, 125, 141, 139, 139, 139, 139, 139, + 150, 139, 3, 17, 139, 18, 18, 41, 17, 3, + 4, 10, 13, 17, 141, 147, 148, 18, 151, 158, + 139, 18, 18, 18, 3, 151, 56, 4, 18, 44, + 139, 139, 139, 139, 59, 61, 154, 18, 151, 151, + 139, 139, 79, 145, 151, 143, 77, 17, 18, 18, + 150, 18, 18, 18, 18, 41, 152, 18, 139, 150, + 77, 151, 151, 151, 160, 51, 150, 41, 50, 151, + 18, 139, 18, 23, 67, 139, 41, 139, 17, 38, + 18, 18, 3, 26, 150, 15, 29, 45, 46, 148, + 14, 67, 17, 139, 158, 49, 51, 109, 159, 160, + 161, 51, 76, 60, 139, 149, 60, 139, 139, 59, + 60, 63, 139, 158, 77, 77, 77, 44, 147, 77, + 139, 143, 18, 101, 18, 160, 160, 160, 151, 160, + 18, 151, 51, 77, 139, 41, 150, 40, 139, 15, + 74, 24, 18, 18, 139, 139, 139, 139, 18, 148, + 139, 139, 44, 109, 157, 161, 139, 49, 51, 151, + 158, 54, 55, 162, 151, 44, 151, 154, 139, 151, + 139, 44, 44, 18, 76, 151, 76, 143, 151, 119, + 160, 29, 77, 151, 41, 18, 139, 41, 74, 139, + 158, 143, 3, 41, 47, 157, 139, 158, 50, 139, + 160, 3, 45, 77, 11, 163, 149, 51, 77, 44, + 60, 156, 60, 77, 60, 158, 151, 77, 143, 151, + 77, 109, 151, 119, 139, 44, 164, 77, 41, 143, + 151, 139, 44, 151, 50, 45, 158, 18, 151, 151, + 151, 151, 77, 151, 77, 110, 109, 110, 160, 109, + 151, 164, 41, 151, 77, 41, 159, 151, 158, 139, + 158, 77, 77, 77, 77, 77, 150, 110, 150, 110, + 160, 77, 159, 162, 44, 109, 150, 109, 150, 151, + 109, 151, 109, 160, 151, 160, 151, 160, 160 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 136, 137, 138, 138, 138, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 140, 140, 140, 140, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 142, + 142, 143, 143, 143, 144, 144, 145, 146, 147, 147, + 148, 148, 148, 148, 148, 148, 148, 148, 148, 149, + 149, 150, 150, 151, 151, 151, 152, 152, 152, 153, + 154, 154, 155, 155, 155, 155, 156, 156, 157, 157, + 157, 158, 158, 159, 159, 159, 159, 160, 160, 161, + 161, 162, 162, 162, 163, 163, 163, 164, 164, 164, + 164, 165 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 2, 3, 3, 1, 2, 4, 6, + 3, 5, 7, 1, 1, 6, 6, 6, 6, 8, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 1, 1, 1, 3, 4, 3, 3, 3, 3, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, + 3, 3, 3, 2, 2, 2, 5, 3, 1, 3, + 2, 4, 4, 1, 4, 4, 4, 3, 1, 2, + 2, 6, 4, 5, 4, 1, 4, 1, 3, 3, + 4, 1, 2, 1, 3, 1, 1, 7, 9, 9, + 9, 7, 9, 1, 4, 5, 7, 5, 3, 1, + 3, 2, 5, 3, 3, 2, 3, 1, 3, 4, + 3, 3, 3, 1, 3, 4, 6, 6, 3, 3, + 3, 1, 2, 3, 2, 3, 2, 1, 1, 2, + 1, 3, 4, 1, 6, 7, 3, 1, 4, 7, + 8, 7, 9, 8, 8, 9, 9, 10, 4, 3, + 4, 7, 9, 5, 6, 5, 5, 7, 4, 1, + 7, 4, 4, 3, 1, 2, 3, 4, 5, 4, + 6, 5, 3, 13, 12, 12, 8, 3, 2, 2, + 7, 13, 9, 5, 5, 1, 3, 1, 1, 1, + 3, 3, 3, 3, 5, 2, 3, 2, 2, 1, + 1, 0, 2, 2, 4, 2, 3, 3, 1, 3, + 1, 3, 3, 3, 3, 1, 3, 1, 1, 0, + 1, 0, 1, 1, 2, 2, 0, 2, 3, 1, + 0, 2, 0, 2, 2, 2, 1, 1, 0, 3, + 2, 3, 4, 1, 3, 5, 6, 1, 2, 1, + 2, 0, 3, 5, 0, 2, 5, 0, 2, 6, + 7, 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (scanner, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, scanner); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void * scanner) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (scanner); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void * scanner) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, void * scanner) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , scanner); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, scanner); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void * scanner) +{ + YYUSE (yyvaluep); + YYUSE (scanner); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void * scanner) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval,YYLEX_PARAM); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 199 "input_parser.yy" /* yacc.c:1646 */ + { const giac::context * contextptr = giac_yyget_extra(scanner); + if ((yyvsp[0])._VECTptr->size()==1) + parsed_gen((yyvsp[0])._VECTptr->front(),contextptr); + else + parsed_gen(gen(*(yyvsp[0])._VECTptr,_SEQ__VECT),contextptr); + } +#line 4735 "y.tab.c" /* yacc.c:1646 */ + break; + + case 3: +#line 207 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=vecteur(1,(yyvsp[-1])); } +#line 4741 "y.tab.c" /* yacc.c:1646 */ + break; + + case 4: +#line 208 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[-1]).val==1) (yyval)=vecteur(1,symbolic(at_nodisp,(yyvsp[-2]))); else (yyval)=vecteur(1,(yyvsp[-2])); } +#line 4747 "y.tab.c" /* yacc.c:1646 */ + break; + + case 5: +#line 209 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[-1]).val==1) (yyval)=mergevecteur(makevecteur(symbolic(at_nodisp,(yyvsp[-2]))),*(yyvsp[0])._VECTptr); else (yyval)=mergevecteur(makevecteur((yyvsp[-2])),*(yyvsp[0])._VECTptr); } +#line 4753 "y.tab.c" /* yacc.c:1646 */ + break; + + case 6: +#line 212 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = (yyvsp[0]);} +#line 4759 "y.tab.c" /* yacc.c:1646 */ + break; + + case 7: +#line 213 "input_parser.yy" /* yacc.c:1646 */ + {if (is_one((yyvsp[-1]))) (yyval)=(yyvsp[0]); else (yyval)=symbolic(at_prod,gen(makevecteur((yyvsp[-1]),(yyvsp[0])),_SEQ__VECT));} +#line 4765 "y.tab.c" /* yacc.c:1646 */ + break; + + case 8: +#line 214 "input_parser.yy" /* yacc.c:1646 */ + {if (is_one((yyvsp[-3]))) (yyval)=symb_pow((yyvsp[-2]),(yyvsp[0])); else (yyval)=symbolic(at_prod,gen(makevecteur((yyvsp[-3]),symb_pow((yyvsp[-2]),(yyvsp[0]))),_SEQ__VECT));} +#line 4771 "y.tab.c" /* yacc.c:1646 */ + break; + + case 9: +#line 215 "input_parser.yy" /* yacc.c:1646 */ + {if (is_one((yyvsp[-5]))) (yyval)=symb_pow((yyvsp[-4]),(yyvsp[-1])); else (yyval)=symbolic(at_prod,gen(makevecteur((yyvsp[-5]),symb_pow((yyvsp[-4]),(yyvsp[-1]))),_SEQ__VECT));} +#line 4777 "y.tab.c" /* yacc.c:1646 */ + break; + + case 10: +#line 216 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symbolic(at_prod,gen(makevecteur((yyvsp[-2]),symb_pow((yyvsp[-1]),(yyvsp[0]))) ,_SEQ__VECT));} +#line 4783 "y.tab.c" /* yacc.c:1646 */ + break; + + case 11: +#line 217 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) =(yyvsp[-4])*symbolic(*(yyvsp[-3])._FUNCptr,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround((yyvsp[-1]))):os_nary_workaround((yyvsp[-1]))); } +#line 4789 "y.tab.c" /* yacc.c:1646 */ + break; + + case 12: +#line 218 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) =(yyvsp[-6])*symb_pow(symbolic(*(yyvsp[-5])._FUNCptr,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround((yyvsp[-3]))):os_nary_workaround((yyvsp[-3]))),(yyvsp[0])); } +#line 4795 "y.tab.c" /* yacc.c:1646 */ + break; + + case 13: +#line 220 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 4801 "y.tab.c" /* yacc.c:1646 */ + break; + + case 14: +#line 221 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[0]).type==_FUNC) (yyval)=symbolic(*(yyvsp[0])._FUNCptr,gen(vecteur(0),_SEQ__VECT)); else (yyval)=(yyvsp[0]); } +#line 4807 "y.tab.c" /* yacc.c:1646 */ + break; + + case 15: +#line 224 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symb_program_sto((yyvsp[-3]),(yyvsp[-3])*gen_zero,(yyvsp[0]),(yyvsp[-5]),false,giac_yyget_extra(scanner));} +#line 4813 "y.tab.c" /* yacc.c:1646 */ + break; + + case 16: +#line 225 "input_parser.yy" /* yacc.c:1646 */ + {if (is_array_index((yyvsp[-5]),(yyvsp[-3]),giac_yyget_extra(scanner)) || (abs_calc_mode(giac_yyget_extra(scanner))==38 && (yyvsp[-5]).type==_IDNT && strlen((yyvsp[-5])._IDNTptr->id_name)==2 && check_vect_38((yyvsp[-5])._IDNTptr->id_name))) (yyval)=symbolic(at_sto,gen(makevecteur((yyvsp[0]),symbolic(at_of,gen(makevecteur((yyvsp[-5]),(yyvsp[-3])) ,_SEQ__VECT))) ,_SEQ__VECT)); else { (yyval) = symb_program_sto((yyvsp[-3]),(yyvsp[-3])*gen_zero,(yyvsp[0]),(yyvsp[-5]),true,giac_yyget_extra(scanner)); (yyval)._SYMBptr->feuille.subtype=_SORTED__VECT; } } +#line 4819 "y.tab.c" /* yacc.c:1646 */ + break; + + case 17: +#line 226 "input_parser.yy" /* yacc.c:1646 */ + {if (is_array_index((yyvsp[-3]),(yyvsp[-1]),giac_yyget_extra(scanner)) || (abs_calc_mode(giac_yyget_extra(scanner))==38 && (yyvsp[-3]).type==_IDNT && check_vect_38((yyvsp[-3])._IDNTptr->id_name))) (yyval)=symbolic(at_sto,gen(makevecteur((yyvsp[-5]),symbolic(at_of,gen(makevecteur((yyvsp[-3]),(yyvsp[-1])) ,_SEQ__VECT))) ,_SEQ__VECT)); else (yyval) = symb_program_sto((yyvsp[-1]),(yyvsp[-1])*gen_zero,(yyvsp[-5]),(yyvsp[-3]),false,giac_yyget_extra(scanner));} +#line 4825 "y.tab.c" /* yacc.c:1646 */ + break; + + case 18: +#line 227 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + gen g=symb_at((yyvsp[-3]),(yyvsp[-1]),contextptr); (yyval)=parser_symb_sto((yyvsp[-5]),g); + } +#line 4834 "y.tab.c" /* yacc.c:1646 */ + break; + + case 19: +#line 231 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + gen g=symbolic(at_of,gen(makevecteur((yyvsp[-5]),(yyvsp[-2])) ,_SEQ__VECT)); (yyval)=parser_symb_sto((yyvsp[-7]),g); + } +#line 4843 "y.tab.c" /* yacc.c:1646 */ + break; + + case 20: +#line 235 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[0]).type==_IDNT) { string s=(yyvsp[0]).print(context0); const char * ch=s.c_str(); if (ch[0]=='_' && unit_conversion_map().find(ch+1) != unit_conversion_map().end()) (yyval)=symbolic(at_convert,gen(makevecteur((yyvsp[-2]),symbolic(at_unit,makevecteur(1,(yyvsp[0])))) ,_SEQ__VECT)); else (yyval)=parser_symb_sto((yyvsp[-2]),(yyvsp[0])); } else (yyval)=parser_symb_sto((yyvsp[-2]),(yyvsp[0])); } +#line 4849 "y.tab.c" /* yacc.c:1646 */ + break; + + case 21: +#line 236 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_convert,gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 4855 "y.tab.c" /* yacc.c:1646 */ + break; + + case 22: +#line 237 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_convert,gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 4861 "y.tab.c" /* yacc.c:1646 */ + break; + + case 23: +#line 238 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_convert,gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 4867 "y.tab.c" /* yacc.c:1646 */ + break; + + case 24: +#line 239 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_convert,gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 4873 "y.tab.c" /* yacc.c:1646 */ + break; + + case 25: +#line 240 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_time,(yyvsp[-2]));} +#line 4879 "y.tab.c" /* yacc.c:1646 */ + break; + + case 26: +#line 241 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[-2])==16 || (yyvsp[-2])==10 || (yyvsp[-2])==8 || (yyvsp[-2])==2) (yyval)=symbolic(at_integer_format,(yyvsp[-2])); else (yyval)=symbolic(at_solve,symb_equal((yyvsp[-2]),0));} +#line 4885 "y.tab.c" /* yacc.c:1646 */ + break; + + case 27: +#line 242 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_convert,gen(makevecteur((yyvsp[-3]),symb_unit(gen(1),(yyvsp[0]),giac_yyget_extra(scanner))),_SEQ__VECT)); opened_quote(giac_yyget_extra(scanner)) &= 0x7ffffffd;} +#line 4891 "y.tab.c" /* yacc.c:1646 */ + break; + + case 28: +#line 243 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = check_symb_of((yyvsp[-3]),python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround((yyvsp[-1]))):os_nary_workaround((yyvsp[-1])),giac_yyget_extra(scanner));} +#line 4897 "y.tab.c" /* yacc.c:1646 */ + break; + + case 29: +#line 244 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = check_symb_of((yyvsp[-3]),python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround((yyvsp[-1]))):os_nary_workaround((yyvsp[-1])),giac_yyget_extra(scanner));} +#line 4903 "y.tab.c" /* yacc.c:1646 */ + break; + + case 30: +#line 245 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = (yyvsp[0]);} +#line 4909 "y.tab.c" /* yacc.c:1646 */ + break; + + case 31: +#line 246 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = (yyvsp[0]);} +#line 4915 "y.tab.c" /* yacc.c:1646 */ + break; + + case 32: +#line 247 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = (yyvsp[0]);} +#line 4921 "y.tab.c" /* yacc.c:1646 */ + break; + + case 33: +#line 248 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-2])._FUNCptr,(yyvsp[0]));} +#line 4927 "y.tab.c" /* yacc.c:1646 */ + break; + + case 34: +#line 249 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-3])._FUNCptr,(yyvsp[-1]));} +#line 4933 "y.tab.c" /* yacc.c:1646 */ + break; + + case 35: +#line 250 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-2])._FUNCptr,gen(vecteur(0),_SEQ__VECT));} +#line 4939 "y.tab.c" /* yacc.c:1646 */ + break; + + case 36: +#line 251 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[0])._FUNCptr,(yyvsp[-2]));} +#line 4945 "y.tab.c" /* yacc.c:1646 */ + break; + + case 37: +#line 252 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symb_test_equal((yyvsp[-2]),(yyvsp[-1]),(yyvsp[0]));} +#line 4951 "y.tab.c" /* yacc.c:1646 */ + break; + + case 38: +#line 254 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-1])._FUNCptr,makesequence((yyvsp[-2]),(yyvsp[0]))); } +#line 4957 "y.tab.c" /* yacc.c:1646 */ + break; + + case 39: +#line 255 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_SYMB) (yyval)=(yyvsp[0]); else (yyval)=symbolic(at_nop,(yyvsp[0])); + (yyval).change_subtype(_SPREAD__SYMB); + const giac::context * contextptr = giac_yyget_extra(scanner); + spread_formula(false,contextptr); + } +#line 4968 "y.tab.c" /* yacc.c:1646 */ + break; + + case 40: +#line 261 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[-2]).is_symb_of_sommet(at_plus) && (yyvsp[-2])._SYMBptr->feuille.type==_VECT){ (yyvsp[-2])._SYMBptr->feuille._VECTptr->push_back((yyvsp[0])); (yyval)=(yyvsp[-2]); } else + (yyval) =symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])),_SEQ__VECT));} +#line 4975 "y.tab.c" /* yacc.c:1646 */ + break; + + case 41: +#line 263 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symb_plus((yyvsp[-2]),(yyvsp[0]).type<_IDNT?-(yyvsp[0]):symbolic(at_neg,(yyvsp[0])));} +#line 4981 "y.tab.c" /* yacc.c:1646 */ + break; + + case 42: +#line 264 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symb_plus((yyvsp[-2]),(yyvsp[0]).type<_IDNT?-(yyvsp[0]):symbolic(at_neg,(yyvsp[0])));} +#line 4987 "y.tab.c" /* yacc.c:1646 */ + break; + + case 43: +#line 265 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) =symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])),_SEQ__VECT));} +#line 4993 "y.tab.c" /* yacc.c:1646 */ + break; + + case 44: +#line 266 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) =symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])),_SEQ__VECT));} +#line 4999 "y.tab.c" /* yacc.c:1646 */ + break; + + case 45: +#line 267 "input_parser.yy" /* yacc.c:1646 */ + {if ((yyvsp[-2])==symbolic(at_exp,1) && (yyvsp[-1])==at_pow) (yyval)=symbolic(at_exp,(yyvsp[0])); else (yyval) =symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])),_SEQ__VECT));} +#line 5005 "y.tab.c" /* yacc.c:1646 */ + break; + + case 46: +#line 268 "input_parser.yy" /* yacc.c:1646 */ + {if ((yyvsp[-1]).type==_FUNC) (yyval)=symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])),_SEQ__VECT)); else (yyval) = symbolic(at_normalmod,gen(makevecteur((yyvsp[-2]),(yyvsp[0])),_SEQ__VECT));} +#line 5011 "y.tab.c" /* yacc.c:1646 */ + break; + + case 47: +#line 269 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 5017 "y.tab.c" /* yacc.c:1646 */ + break; + + case 48: +#line 270 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[0])._FUNCptr,gen(makevecteur((yyvsp[-1]),RAND_MAX) ,_SEQ__VECT)); } +#line 5023 "y.tab.c" /* yacc.c:1646 */ + break; + + case 49: +#line 271 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur(0,(yyvsp[0])) ,_SEQ__VECT)); } +#line 5029 "y.tab.c" /* yacc.c:1646 */ + break; + + case 50: +#line 272 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = makesequence(symbolic(*(yyvsp[-2])._FUNCptr,gen(makevecteur(0,RAND_MAX) ,_SEQ__VECT)),(yyvsp[0])); } +#line 5035 "y.tab.c" /* yacc.c:1646 */ + break; + + case 51: +#line 275 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])),_SEQ__VECT));} +#line 5041 "y.tab.c" /* yacc.c:1646 */ + break; + + case 52: +#line 276 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)= symbolic(at_deuxpoints,gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT));} +#line 5047 "y.tab.c" /* yacc.c:1646 */ + break; + + case 53: +#line 277 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0])==unsigned_inf) + (yyval) = minus_inf; + else { if ((yyvsp[0]).type==_INT_) (yyval)=(-(yyvsp[0]).val); else { if ((yyvsp[0]).type==_DOUBLE_) (yyval)=(-(yyvsp[0])._DOUBLE_val); else (yyval)=symbolic(at_neg,(yyvsp[0])); } } + } +#line 5057 "y.tab.c" /* yacc.c:1646 */ + break; + + case 54: +#line 282 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0])==unsigned_inf) + (yyval) = minus_inf; + else { if ((yyvsp[0]).type==_INT_ || (yyvsp[0]).type==_DOUBLE_ || (yyvsp[0]).type==_FLOAT_) (yyval)=-(yyvsp[0]); else (yyval)=symbolic(at_neg,(yyvsp[0])); } + } +#line 5067 "y.tab.c" /* yacc.c:1646 */ + break; + + case 55: +#line 287 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0])==unsigned_inf) + (yyval) = plus_inf; + else + (yyval) = (yyvsp[0]); + } +#line 5078 "y.tab.c" /* yacc.c:1646 */ + break; + + case 56: +#line 293 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = polynome_or_sparse_poly1(eval((yyvsp[-3]),1, giac_yyget_extra(scanner)),(yyvsp[-1]));} +#line 5084 "y.tab.c" /* yacc.c:1646 */ + break; + + case 57: +#line 294 "input_parser.yy" /* yacc.c:1646 */ + { + if ( ((yyvsp[-1]).type==_SYMB) && ((yyvsp[-1])._SYMBptr->sommet==at_deuxpoints) ) + (yyval) = algebraic_EXTension((yyvsp[-1])._SYMBptr->feuille._VECTptr->front(),(yyvsp[-1])._SYMBptr->feuille._VECTptr->back()); + else (yyval)=(yyvsp[-1]); + } +#line 5094 "y.tab.c" /* yacc.c:1646 */ + break; + + case 58: +#line 300 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(at_of,2); } +#line 5100 "y.tab.c" /* yacc.c:1646 */ + break; + + case 59: +#line 301 "input_parser.yy" /* yacc.c:1646 */ + {if ((yyvsp[-2]).type==_FUNC) *logptr(giac_yyget_extra(scanner))<< ("Warning: "+(yyvsp[-2]).print(context0)+" is a reserved word")<<'\n'; if ((yyvsp[-2]).type==_INT_) (yyval)=symb_equal((yyvsp[-2]),(yyvsp[0])); else {(yyval) = parser_symb_sto((yyvsp[0]),(yyvsp[-2]),(yyvsp[-1])==at_array_sto); if ((yyvsp[0]).is_symb_of_sommet(at_program)) *logptr(giac_yyget_extra(scanner))<<"// End defining "<<(yyvsp[-2])<<'\n';}} +#line 5106 "y.tab.c" /* yacc.c:1646 */ + break; + + case 60: +#line 302 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symbolic(*(yyvsp[-1])._FUNCptr,(yyvsp[0]));} +#line 5112 "y.tab.c" /* yacc.c:1646 */ + break; + + case 61: +#line 303 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symb_args((yyvsp[-1]));} +#line 5118 "y.tab.c" /* yacc.c:1646 */ + break; + + case 62: +#line 304 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symb_args((yyvsp[-1]));} +#line 5124 "y.tab.c" /* yacc.c:1646 */ + break; + + case 63: +#line 305 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_args(vecteur(0)); } +#line 5130 "y.tab.c" /* yacc.c:1646 */ + break; + + case 64: +#line 306 "input_parser.yy" /* yacc.c:1646 */ + { + gen tmp=python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround((yyvsp[-1]))):os_nary_workaround((yyvsp[-1])); + // CERR << python_compat(giac_yyget_extra(scanner)) << tmp << '\n'; + (yyval) = symbolic(*(yyvsp[-3])._FUNCptr,tmp); + const giac::context * contextptr = giac_yyget_extra(scanner); + if ((yyvsp[-1]).type==_INT_ && (*(yyvsp[-3])._FUNCptr==at_maple_mode ||*(yyvsp[-3])._FUNCptr==at_xcas_mode )){ + xcas_mode(contextptr)=(yyvsp[-1]).val; + } + if ((yyvsp[-1]).type==_INT_ && *(yyvsp[-3])._FUNCptr==at_python_compat) + python_compat(contextptr)=(yyvsp[-1]).val; + if (*(yyvsp[-3])._FUNCptr==at_user_operator){ + user_operator((yyvsp[-1]),contextptr); + } + } +#line 5149 "y.tab.c" /* yacc.c:1646 */ + break; + + case 65: +#line 320 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[-1]).type==_VECT && (yyvsp[-1])._VECTptr->empty()) + giac_yyerror(scanner,"void argument"); + (yyval) = symbolic(*(yyvsp[-3])._FUNCptr,python_compat(giac_yyget_extra(scanner))?denest_sto(os_nary_workaround((yyvsp[-1]))):os_nary_workaround((yyvsp[-1]))); + } +#line 5159 "y.tab.c" /* yacc.c:1646 */ + break; + + case 66: +#line 325 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_at((yyvsp[-3]),(yyvsp[-1]),contextptr); + } +#line 5168 "y.tab.c" /* yacc.c:1646 */ + break; + + case 67: +#line 329 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval) = symbolic(*(yyvsp[-2])._FUNCptr,gen(vecteur(0),_SEQ__VECT)); + if (*(yyvsp[-2])._FUNCptr==at_rpn) + rpn_mode(giac_yyget_extra(scanner))=1; + if (*(yyvsp[-2])._FUNCptr==at_alg) + rpn_mode(giac_yyget_extra(scanner))=0; + } +#line 5180 "y.tab.c" /* yacc.c:1646 */ + break; + + case 68: +#line 336 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval) = (yyvsp[0]); + } +#line 5188 "y.tab.c" /* yacc.c:1646 */ + break; + + case 69: +#line 339 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(at_derive,(yyvsp[-1]));} +#line 5194 "y.tab.c" /* yacc.c:1646 */ + break; + + case 70: +#line 340 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(*(yyvsp[0])._FUNCptr,(yyvsp[-1])); } +#line 5200 "y.tab.c" /* yacc.c:1646 */ + break; + + case 71: +#line 342 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-5])._FUNCptr,makevecteur(equaltosame((yyvsp[-4])),symb_bloc((yyvsp[-2])),symb_bloc((yyvsp[0]))));} +#line 5206 "y.tab.c" /* yacc.c:1646 */ + break; + + case 72: +#line 343 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-3])._FUNCptr,makevecteur(equaltosame((yyvsp[-2])),(yyvsp[0]),0));} +#line 5212 "y.tab.c" /* yacc.c:1646 */ + break; + + case 73: +#line 344 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval) = symbolic(*(yyvsp[-4])._FUNCptr,makevecteur(equaltosame((yyvsp[-3])),symb_bloc((yyvsp[-1])),(yyvsp[0]))); + } +#line 5220 "y.tab.c" /* yacc.c:1646 */ + break; + + case 74: +#line 347 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-3])._FUNCptr,(yyvsp[-1]));} +#line 5226 "y.tab.c" /* yacc.c:1646 */ + break; + + case 75: +#line 348 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = (yyvsp[0]);} +#line 5232 "y.tab.c" /* yacc.c:1646 */ + break; + + case 76: +#line 349 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symb_program((yyvsp[-1]));} +#line 5238 "y.tab.c" /* yacc.c:1646 */ + break; + + case 77: +#line 350 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = gen(at_program,3);} +#line 5244 "y.tab.c" /* yacc.c:1646 */ + break; + + case 78: +#line 351 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval) = symb_program((yyvsp[-2]),gen_zero*(yyvsp[-2]),(yyvsp[0]),contextptr); + } +#line 5253 "y.tab.c" /* yacc.c:1646 */ + break; + + case 79: +#line 355 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + if ((yyvsp[0]).type==_VECT) + (yyval) = symb_program((yyvsp[-2]),gen_zero*(yyvsp[-2]),symb_bloc(makevecteur(at_nop,(yyvsp[0]))),contextptr); + else + (yyval) = symb_program((yyvsp[-2]),gen_zero*(yyvsp[-2]),(yyvsp[0]),contextptr); + } +#line 5265 "y.tab.c" /* yacc.c:1646 */ + break; + + case 80: +#line 362 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symb_bloc((yyvsp[-1]));} +#line 5271 "y.tab.c" /* yacc.c:1646 */ + break; + + case 81: +#line 363 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = at_bloc;} +#line 5277 "y.tab.c" /* yacc.c:1646 */ + break; + + case 82: +#line 365 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(*(yyvsp[-1])._FUNCptr,(yyvsp[0])); } +#line 5283 "y.tab.c" /* yacc.c:1646 */ + break; + + case 83: +#line 367 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = gen(*(yyvsp[0])._FUNCptr,0);} +#line 5289 "y.tab.c" /* yacc.c:1646 */ + break; + + case 84: +#line 368 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[-1]);} +#line 5295 "y.tab.c" /* yacc.c:1646 */ + break; + + case 85: +#line 370 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(at_break,gen_zero);} +#line 5301 "y.tab.c" /* yacc.c:1646 */ + break; + + case 86: +#line 371 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(at_continue,gen_zero);} +#line 5307 "y.tab.c" /* yacc.c:1646 */ + break; + + case 87: +#line 372 "input_parser.yy" /* yacc.c:1646 */ + { + /* + gen kk(identificateur("index")); + vecteur v(*$6._VECTptr); + const giac::context * contextptr = giac_yyget_extra(scanner); + v.insert(v.begin(),symb_sto(symb_at($4,kk,contextptr),$2)); + $$=symbolic(*$1._FUNCptr,makevecteur(symb_sto(xcas_mode(contextptr)!=0,kk),symb_inferieur_strict(kk,symb_size($4)+(xcas_mode(contextptr)!=0)),symb_sto(symb_plus(kk,gen(1)),kk),symb_bloc(v))); + */ + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=2 && (yyvsp[0]).val!=9) + giac_yyerror(scanner,"missing loop end delimiter"); + bool rg=(yyvsp[-3]).is_symb_of_sommet(at_range); + gen f=(yyvsp[-3]).type==_SYMB?(yyvsp[-3])._SYMBptr->feuille:0,inc=1; + if (rg){ + if (f.type!=_VECT) f=makesequence(0,f); + vecteur v=*f._VECTptr; + if (v.size()==3) inc=v[2]; + if (v.size()>=2) f=makesequence(v.front(),v[1]-inc); + } + if (inc.type==_INT_ && inc.val!=0 && f.type==_VECT && f._VECTptr->size()==2 && (rg || ((yyvsp[-3]).is_symb_of_sommet(at_interval) + // && f._VECTptr->front().type==_INT_ && f._VECTptr->back().type==_INT_ + ))) + (yyval)=symbolic(*(yyvsp[-6])._FUNCptr,makevecteur(symb_sto(f._VECTptr->front(),(yyvsp[-5])),inc.val>0?symb_inferieur_egal((yyvsp[-5]),f._VECTptr->back()):symb_superieur_egal((yyvsp[-5]),f._VECTptr->back()),symb_sto(symb_plus((yyvsp[-5]),inc),(yyvsp[-5])),symb_bloc((yyvsp[-1])))); + else + (yyval)=symbolic(*(yyvsp[-6])._FUNCptr,makevecteur(1,symbolic(*(yyvsp[-6])._FUNCptr,makevecteur((yyvsp[-5]),(yyvsp[-3]))),1,symb_bloc((yyvsp[-1])))); + } +#line 5337 "y.tab.c" /* yacc.c:1646 */ + break; + + case 88: +#line 397 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=2 && (yyvsp[0]).val!=9) + giac_yyerror(scanner,"missing loop end delimiter"); + (yyval)=symbolic(*(yyvsp[-8])._FUNCptr,makevecteur(1,symbolic(*(yyvsp[-8])._FUNCptr,makevecteur((yyvsp[-7]),(yyvsp[-5]),symb_bloc((yyvsp[-1])))),1,symb_bloc((yyvsp[-3])))); + } +#line 5347 "y.tab.c" /* yacc.c:1646 */ + break; + + case 89: +#line 402 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=2 && (yyvsp[0]).val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + gen tmp,st=(yyvsp[-3]); + if (st==1 && (yyvsp[-5])!=1) st=(yyvsp[-5]); + const giac::context * contextptr = giac_yyget_extra(scanner); + if (!lidnt(st).empty()) + *logptr(contextptr) << "Warning, step is not numeric " << st << '\n'; + bool b=has_evalf(st,tmp,1,context0); + if (!b || is_positive(tmp,context0)) + (yyval)=symbolic(*(yyvsp[-8])._FUNCptr,makevecteur(symb_sto((yyvsp[-6]),(yyvsp[-7])),symb_inferieur_egal((yyvsp[-7]),(yyvsp[-4])),symb_sto(symb_plus((yyvsp[-7]),b?abs(st,context0):symb_abs(st)),(yyvsp[-7])),symb_bloc((yyvsp[-1])))); + else + (yyval)=symbolic(*(yyvsp[-8])._FUNCptr,makevecteur(symb_sto((yyvsp[-6]),(yyvsp[-7])),symb_superieur_egal((yyvsp[-7]),(yyvsp[-4])),symb_sto(symb_plus((yyvsp[-7]),st),(yyvsp[-7])),symb_bloc((yyvsp[-1])))); + } +#line 5365 "y.tab.c" /* yacc.c:1646 */ + break; + + case 90: +#line 415 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=2 && (yyvsp[0]).val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + gen tmp,st=(yyvsp[-5]); + if (st==1 && (yyvsp[-4])!=1) st=(yyvsp[-4]); + const giac::context * contextptr = giac_yyget_extra(scanner); + if (!lidnt(st).empty()) + *logptr(contextptr) << "Warning, step is not numeric " << st << '\n'; + bool b=has_evalf(st,tmp,1,context0); + if (!b || is_positive(tmp,context0)) + (yyval)=symbolic(*(yyvsp[-8])._FUNCptr,makevecteur(symb_sto((yyvsp[-6]),(yyvsp[-7])),symb_inferieur_egal((yyvsp[-7]),(yyvsp[-3])),symb_sto(symb_plus((yyvsp[-7]),b?abs(st,context0):symb_abs(st)),(yyvsp[-7])),symb_bloc((yyvsp[-1])))); + else + (yyval)=symbolic(*(yyvsp[-8])._FUNCptr,makevecteur(symb_sto((yyvsp[-6]),(yyvsp[-7])),symb_superieur_egal((yyvsp[-7]),(yyvsp[-3])),symb_sto(symb_plus((yyvsp[-7]),st),(yyvsp[-7])),symb_bloc((yyvsp[-1])))); + } +#line 5383 "y.tab.c" /* yacc.c:1646 */ + break; + + case 91: +#line 428 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=2 && (yyvsp[0]).val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + (yyval)=symbolic(*(yyvsp[-6])._FUNCptr,makevecteur(symb_sto((yyvsp[-4]),(yyvsp[-5])),gen(1),symb_sto(symb_plus((yyvsp[-5]),(yyvsp[-3])),(yyvsp[-5])),symb_bloc((yyvsp[-1])))); + } +#line 5392 "y.tab.c" /* yacc.c:1646 */ + break; + + case 92: +#line 432 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=2 && (yyvsp[0]).val!=9 && (yyvsp[0]).val!=8) giac_yyerror(scanner,"missing loop end delimiter"); + (yyval)=symbolic(*(yyvsp[-8])._FUNCptr,makevecteur(symb_sto((yyvsp[-6]),(yyvsp[-7])),(yyvsp[-3]),symb_sto(symb_plus((yyvsp[-7]),(yyvsp[-5])),(yyvsp[-7])),symb_bloc((yyvsp[-1])))); + } +#line 5401 "y.tab.c" /* yacc.c:1646 */ + break; + + case 93: +#line 436 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = gen(*(yyvsp[0])._FUNCptr,4);} +#line 5407 "y.tab.c" /* yacc.c:1646 */ + break; + + case 94: +#line 441 "input_parser.yy" /* yacc.c:1646 */ + { + vecteur v=gen2vecteur((yyvsp[-2])); + v.push_back(symb_ifte(equaltosame((yyvsp[0])),symbolic(at_break,gen_zero),0)); + (yyval)=symbolic(*(yyvsp[-3])._FUNCptr,makevecteur(gen_zero,1,gen_zero,symb_bloc(v))); + } +#line 5417 "y.tab.c" /* yacc.c:1646 */ + break; + + case 95: +#line 446 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=2 && (yyvsp[0]).val!=9) giac_yyerror(scanner,"missing loop end delimiter"); + vecteur v=gen2vecteur((yyvsp[-3])); + v.push_back(symb_ifte(equaltosame((yyvsp[-1])),symbolic(at_break,gen_zero),0)); + (yyval)=symbolic(*(yyvsp[-4])._FUNCptr,makevecteur(gen_zero,1,gen_zero,symb_bloc(v))); + } +#line 5428 "y.tab.c" /* yacc.c:1646 */ + break; + + case 96: +#line 452 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=4) giac_yyerror(scanner,"missing iferr end delimiter"); + (yyval)=symbolic(at_try_catch,makevecteur(symb_bloc((yyvsp[-5])),0,symb_bloc((yyvsp[-3])),symb_bloc((yyvsp[-1])))); + } +#line 5437 "y.tab.c" /* yacc.c:1646 */ + break; + + case 97: +#line 456 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=4) giac_yyerror(scanner,"missing iferr end delimiter"); + (yyval)=symbolic(at_try_catch,makevecteur(symb_bloc((yyvsp[-3])),0,symb_bloc((yyvsp[-1])),symb_bloc(0))); + } +#line 5446 "y.tab.c" /* yacc.c:1646 */ + break; + + case 98: +#line 460 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symbolic(at_piecewise,(yyvsp[-1])); } +#line 5452 "y.tab.c" /* yacc.c:1646 */ + break; + + case 99: +#line 461 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval)=(yyvsp[0]); + // $$.subtype=1; + } +#line 5461 "y.tab.c" /* yacc.c:1646 */ + break; + + case 100: +#line 465 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[-1]); /* $$.subtype=1; */ } +#line 5467 "y.tab.c" /* yacc.c:1646 */ + break; + + case 101: +#line 466 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symb_dollar((yyvsp[0])); } +#line 5473 "y.tab.c" /* yacc.c:1646 */ + break; + + case 102: +#line 467 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symb_dollar(gen(makevecteur((yyvsp[-4]),(yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT));} +#line 5479 "y.tab.c" /* yacc.c:1646 */ + break; + + case 103: +#line 468 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symb_dollar(gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 5485 "y.tab.c" /* yacc.c:1646 */ + break; + + case 104: +#line 469 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symb_dollar(gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 5491 "y.tab.c" /* yacc.c:1646 */ + break; + + case 105: +#line 470 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_dollar((yyvsp[0])); } +#line 5497 "y.tab.c" /* yacc.c:1646 */ + break; + + case 106: +#line 471 "input_parser.yy" /* yacc.c:1646 */ + { //CERR << $1 << " compose " << $2 << $3 << '\n'; +(yyval) = symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),python_compat(giac_yyget_extra(scanner))?denest_sto((yyvsp[0])):(yyvsp[0])) ,_SEQ__VECT)); } +#line 5504 "y.tab.c" /* yacc.c:1646 */ + break; + + case 107: +#line 473 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symbolic(at_ans,-1);} +#line 5510 "y.tab.c" /* yacc.c:1646 */ + break; + + case 108: +#line 474 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symbolic(((yyvsp[-1]).type==_FUNC?*(yyvsp[-1])._FUNCptr:*at_union),gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 5516 "y.tab.c" /* yacc.c:1646 */ + break; + + case 109: +#line 475 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symbolic(((yyvsp[-2]).type==_FUNC?*(yyvsp[-2])._FUNCptr:*at_union),gen(makevecteur((yyvsp[-3]),(yyvsp[-3])*(yyvsp[-1])/100) ,_SEQ__VECT)); } +#line 5522 "y.tab.c" /* yacc.c:1646 */ + break; + + case 110: +#line 476 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symb_intersect(gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 5528 "y.tab.c" /* yacc.c:1646 */ + break; + + case 111: +#line 477 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symb_minus(gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); } +#line 5534 "y.tab.c" /* yacc.c:1646 */ + break; + + case 112: +#line 478 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval)=symbolic(*(yyvsp[-1])._FUNCptr,gen(makevecteur((yyvsp[-2]),(yyvsp[0])) ,_SEQ__VECT)); + } +#line 5542 "y.tab.c" /* yacc.c:1646 */ + break; + + case 113: +#line 481 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = (yyvsp[0]); } +#line 5548 "y.tab.c" /* yacc.c:1646 */ + break; + + case 114: +#line 482 "input_parser.yy" /* yacc.c:1646 */ + {if ((yyvsp[-1]).type==_FUNC) (yyval)=(yyvsp[-1]); else { + // const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_quote((yyvsp[-1])); + } + } +#line 5558 "y.tab.c" /* yacc.c:1646 */ + break; + + case 115: +#line 487 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval) = symb_at((yyvsp[-3]),(yyvsp[-1]),contextptr); + } +#line 5567 "y.tab.c" /* yacc.c:1646 */ + break; + + case 116: +#line 491 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval) = symbolic(at_of,gen(makevecteur((yyvsp[-5]),(yyvsp[-2])) ,_SEQ__VECT)); + } +#line 5576 "y.tab.c" /* yacc.c:1646 */ + break; + + case 117: +#line 495 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = check_symb_of((yyvsp[-4]),(yyvsp[-1]),giac_yyget_extra(scanner));} +#line 5582 "y.tab.c" /* yacc.c:1646 */ + break; + + case 118: +#line 496 "input_parser.yy" /* yacc.c:1646 */ + { + if ( ((yyvsp[-2])==_LIST__VECT && python_compat(giac_yyget_extra(scanner))) || + python_compat(giac_yyget_extra(scanner))==2){ + if (python_compat(giac_yyget_extra(scanner))==2) + (yyval)=change_subtype((yyvsp[-1]),_TUPLE__VECT); + else + (yyval)=symbolic(at_python_list,(yyvsp[-1])); + } + else { + if (abs_calc_mode(giac_yyget_extra(scanner))==38 && (yyvsp[-1]).type==_VECT && (yyvsp[-1]).subtype==_SEQ__VECT && (yyvsp[-1])._VECTptr->size()==2 && ((yyvsp[-1])._VECTptr->front().type<=_DOUBLE_ || (yyvsp[-1])._VECTptr->front().type==_FLOAT_) && ((yyvsp[-1])._VECTptr->back().type<=_DOUBLE_ || (yyvsp[-1])._VECTptr->back().type==_FLOAT_)){ + const giac::context * contextptr = giac_yyget_extra(scanner); + gen a=evalf((yyvsp[-1])._VECTptr->front(),1,contextptr), + b=evalf((yyvsp[-1])._VECTptr->back(),1,contextptr); + if ( (a.type==_DOUBLE_ || a.type==_FLOAT_) && + (b.type==_DOUBLE_ || b.type==_FLOAT_)) + (yyval)= a+b*cst_i; + else (yyval)=(yyvsp[-1]); + } else { + if (calc_mode(giac_yyget_extra(scanner))==1 && (yyvsp[-1]).type==_VECT && (yyvsp[-2])!=_LIST__VECT && + (yyvsp[-1]).subtype==_SEQ__VECT && ((yyvsp[-1])._VECTptr->size()==2 || (yyvsp[-1])._VECTptr->size()==3) ) + (yyval) = gen(*(yyvsp[-1])._VECTptr,_GGB__VECT); + else + (yyval)=(yyvsp[-1]); + } + } + } +#line 5613 "y.tab.c" /* yacc.c:1646 */ + break; + + case 119: +#line 522 "input_parser.yy" /* yacc.c:1646 */ + { + //cerr << $1 << " " << $2 << '\n'; + (yyval) = gen(*((yyvsp[-1])._VECTptr),(yyvsp[-2]).val); + if ((yyvsp[-1])._VECTptr->size()==1 && (yyvsp[-1])._VECTptr->front().is_symb_of_sommet(at_ti_semi) ) { + (yyval)=(yyvsp[-1])._VECTptr->front(); + } + // cerr << $$ << '\n'; + + } +#line 5627 "y.tab.c" /* yacc.c:1646 */ + break; + + case 120: +#line 531 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[-2]).type==_VECT && (yyvsp[-2]).subtype==_SEQ__VECT && !((yyvsp[0]).type==_VECT && (yyvsp[-1]).subtype==_SEQ__VECT)){ (yyval)=(yyvsp[-2]); (yyval)._VECTptr->push_back((yyvsp[0])); } + else + (yyval) = makesuite((yyvsp[-2]),(yyvsp[0])); + + } +#line 5638 "y.tab.c" /* yacc.c:1646 */ + break; + + case 121: +#line 537 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(vecteur(0),_SEQ__VECT); } +#line 5644 "y.tab.c" /* yacc.c:1646 */ + break; + + case 122: +#line 538 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symb_findhelp((yyvsp[0]));} +#line 5650 "y.tab.c" /* yacc.c:1646 */ + break; + + case 123: +#line 539 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_interrogation((yyvsp[-2]),(yyvsp[0])); } +#line 5656 "y.tab.c" /* yacc.c:1646 */ + break; + + case 124: +#line 540 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_unit(gen(1),(yyvsp[0]),contextptr); + opened_quote(giac_yyget_extra(scanner)) &= 0x7ffffffd; + } +#line 5666 "y.tab.c" /* yacc.c:1646 */ + break; + + case 125: +#line 545 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_unit((yyvsp[-2]),(yyvsp[0]),contextptr); + opened_quote(giac_yyget_extra(scanner)) &= 0x7ffffffd; } +#line 5675 "y.tab.c" /* yacc.c:1646 */ + break; + + case 126: +#line 549 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_pow((yyvsp[-1]),(yyvsp[0])); } +#line 5681 "y.tab.c" /* yacc.c:1646 */ + break; + + case 127: +#line 550 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); +#ifdef HAVE_SIGNAL_H_OLD + messages_to_print += parser_filename(contextptr) + parser_error(contextptr); + /* *logptr(giac_yyget_extra(scanner)) << messages_to_print; */ +#endif + (yyval)=undef; + spread_formula(false,contextptr); + } +#line 5695 "y.tab.c" /* yacc.c:1646 */ + break; + + case 128: +#line 559 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 5701 "y.tab.c" /* yacc.c:1646 */ + break; + + case 129: +#line 560 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(*(yyvsp[-1])._FUNCptr,(yyvsp[0])); } +#line 5707 "y.tab.c" /* yacc.c:1646 */ + break; + + case 130: +#line 561 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[0])._FUNCptr,gen(vecteur(0),_SEQ__VECT));} +#line 5713 "y.tab.c" /* yacc.c:1646 */ + break; + + case 131: +#line 562 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-2])._FUNCptr,gen(vecteur(0),_SEQ__VECT));} +#line 5719 "y.tab.c" /* yacc.c:1646 */ + break; + + case 132: +#line 563 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval) = symb_local((yyvsp[-1]),contextptr); + } +#line 5728 "y.tab.c" /* yacc.c:1646 */ + break; + + case 133: +#line 567 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = gen(at_local,2);} +#line 5734 "y.tab.c" /* yacc.c:1646 */ + break; + + case 134: +#line 568 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval) = symbolic(*(yyvsp[-5])._FUNCptr,makevecteur(equaltosame((yyvsp[-3])),symb_bloc((yyvsp[-1])),(yyvsp[0]))); + } +#line 5742 "y.tab.c" /* yacc.c:1646 */ + break; + + case 135: +#line 571 "input_parser.yy" /* yacc.c:1646 */ + { + vecteur v=makevecteur(equaltosame((yyvsp[-4])),(yyvsp[-2]),(yyvsp[0])); + // *logptr(giac_yyget_extra(scanner)) << v << '\n'; + (yyval) = symbolic(*(yyvsp[-6])._FUNCptr,v); + } +#line 5752 "y.tab.c" /* yacc.c:1646 */ + break; + + case 136: +#line 576 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_rpn_prog((yyvsp[-1])); } +#line 5758 "y.tab.c" /* yacc.c:1646 */ + break; + + case 137: +#line 577 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 5764 "y.tab.c" /* yacc.c:1646 */ + break; + + case 138: +#line 578 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_maple_lib,makevecteur((yyvsp[-3]),(yyvsp[-1]))); } +#line 5770 "y.tab.c" /* yacc.c:1646 */ + break; + + case 139: +#line 579 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program((yyvsp[-4]),gen_zero*(yyvsp[-4]),symb_local((yyvsp[-2]),(yyvsp[-1]),contextptr),contextptr); + } +#line 5780 "y.tab.c" /* yacc.c:1646 */ + break; + + case 140: +#line 584 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-4]),gen_zero*(yyvsp[-4]),symb_local((yyvsp[-2]),(yyvsp[-1]),contextptr),(yyvsp[-6]),false,contextptr); + } +#line 5790 "y.tab.c" /* yacc.c:1646 */ + break; + + case 141: +#line 589 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-3]),gen_zero*(yyvsp[-3]),symb_bloc((yyvsp[-1])),(yyvsp[-5]),false,contextptr); + } +#line 5800 "y.tab.c" /* yacc.c:1646 */ + break; + + case 142: +#line 594 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-5]),gen_zero*(yyvsp[-5]),symb_local((yyvsp[-2]),(yyvsp[-1]),contextptr),(yyvsp[-7]),false,contextptr); + } +#line 5810 "y.tab.c" /* yacc.c:1646 */ + break; + + case 143: +#line 599 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program((yyvsp[-5]),gen_zero*(yyvsp[-5]),symb_local((yyvsp[-3]),(yyvsp[-1]),contextptr),contextptr); + } +#line 5820 "y.tab.c" /* yacc.c:1646 */ + break; + + case 144: +#line 604 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-5]),gen_zero*(yyvsp[-5]),symb_local((yyvsp[-2]),(yyvsp[-1]),contextptr),(yyvsp[-7]),false,contextptr); + } +#line 5830 "y.tab.c" /* yacc.c:1646 */ + break; + + case 145: +#line 609 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=3) giac_yyerror(scanner,"missing func/prog/proc end delimiter"); + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-6]),gen_zero*(yyvsp[-6]),symb_local((yyvsp[-2]),(yyvsp[-1]),contextptr),(yyvsp[-8]),false,contextptr); + } +#line 5840 "y.tab.c" /* yacc.c:1646 */ + break; + + case 146: +#line 614 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-8])._FUNCptr,makevecteur((yyvsp[-6]),equaltosame((yyvsp[-4])),(yyvsp[-2]),symb_bloc((yyvsp[0]))));} +#line 5846 "y.tab.c" /* yacc.c:1646 */ + break; + + case 147: +#line 615 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-9])._FUNCptr,makevecteur((yyvsp[-7]),equaltosame((yyvsp[-5])),(yyvsp[-3]),(yyvsp[-1])));} +#line 5852 "y.tab.c" /* yacc.c:1646 */ + break; + + case 148: +#line 616 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-3])._FUNCptr,gen2vecteur((yyvsp[-1])));} +#line 5858 "y.tab.c" /* yacc.c:1646 */ + break; + + case 149: +#line 617 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symbolic(at_member,makesequence((yyvsp[-2]),(yyvsp[0]))); if ((yyvsp[-1])==at_not) (yyval)=symbolic(at_not,(yyval));} +#line 5864 "y.tab.c" /* yacc.c:1646 */ + break; + + case 150: +#line 618 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symbolic(at_not,symbolic(at_member,makesequence((yyvsp[-3]),(yyvsp[0]))));} +#line 5870 "y.tab.c" /* yacc.c:1646 */ + break; + + case 151: +#line 619 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_apply,makesequence(symbolic(at_program,makesequence((yyvsp[-3]),0*(yyvsp[-3]),vecteur(1,(yyvsp[-5])))),(yyvsp[-1]))); if ((yyvsp[-6])==_TABLE__VECT) (yyval)=symbolic(at_table,(yyval));} +#line 5876 "y.tab.c" /* yacc.c:1646 */ + break; + + case 152: +#line 620 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_apply,symbolic(at_program,makesequence((yyvsp[-5]),0*(yyvsp[-5]),vecteur(1,(yyvsp[-7])))),symbolic(at_select,makesequence(symbolic(at_program,makesequence((yyvsp[-5]),0*(yyvsp[-5]),(yyvsp[-1]))),(yyvsp[-3])))); if ((yyvsp[-8])==_TABLE__VECT) (yyval)=symbolic(at_table,(yyval));} +#line 5882 "y.tab.c" /* yacc.c:1646 */ + break; + + case 153: +#line 621 "input_parser.yy" /* yacc.c:1646 */ + { + vecteur v=makevecteur(gen_zero,equaltosame((yyvsp[-2])),gen_zero,symb_bloc((yyvsp[0]))); + (yyval)=symbolic(*(yyvsp[-4])._FUNCptr,v); + } +#line 5891 "y.tab.c" /* yacc.c:1646 */ + break; + + case 154: +#line 625 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval)=symbolic(*(yyvsp[-5])._FUNCptr,makevecteur(gen_zero,equaltosame((yyvsp[-3])),gen_zero,(yyvsp[-1]))); + } +#line 5899 "y.tab.c" /* yacc.c:1646 */ + break; + + case 155: +#line 628 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=9 && (yyvsp[0]).val!=8) giac_yyerror(scanner,"missing loop end delimiter"); + (yyval)=symbolic(*(yyvsp[-4])._FUNCptr,makevecteur(gen_zero,equaltosame((yyvsp[-3])),gen_zero,symb_bloc((yyvsp[-1])))); + } +#line 5908 "y.tab.c" /* yacc.c:1646 */ + break; + + case 156: +#line 632 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=9 && (yyvsp[0]).val!=8) giac_yyerror(scanner,"missing loop end delimiter"); + (yyval)=symbolic(*(yyvsp[-4])._FUNCptr,makevecteur(gen_zero,equaltosame((yyvsp[-3])),gen_zero,symb_bloc((yyvsp[-1])))); + } +#line 5917 "y.tab.c" /* yacc.c:1646 */ + break; + + case 157: +#line 636 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_try_catch(makevecteur(symb_bloc((yyvsp[-5])),(yyvsp[-2]),symb_bloc((yyvsp[0]))));} +#line 5923 "y.tab.c" /* yacc.c:1646 */ + break; + + case 158: +#line 637 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symb_try_catch(gen2vecteur((yyvsp[-1])));} +#line 5929 "y.tab.c" /* yacc.c:1646 */ + break; + + case 159: +#line 638 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=gen(at_try_catch,3);} +#line 5935 "y.tab.c" /* yacc.c:1646 */ + break; + + case 160: +#line 639 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_case((yyvsp[-4]),(yyvsp[-1])); } +#line 5941 "y.tab.c" /* yacc.c:1646 */ + break; + + case 161: +#line 640 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = symb_case((yyvsp[-1])); } +#line 5947 "y.tab.c" /* yacc.c:1646 */ + break; + + case 162: +#line 641 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_case((yyvsp[-2]),(yyvsp[-1])); } +#line 5953 "y.tab.c" /* yacc.c:1646 */ + break; + + case 163: +#line 642 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[-1]); } +#line 5959 "y.tab.c" /* yacc.c:1646 */ + break; + + case 164: +#line 643 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 5965 "y.tab.c" /* yacc.c:1646 */ + break; + + case 165: +#line 644 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = gen(*(yyvsp[-1])._FUNCptr,0);} +#line 5971 "y.tab.c" /* yacc.c:1646 */ + break; + + case 166: +#line 645 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(*(yyvsp[-2])._FUNCptr,makevecteur(gen_zero,gen(1),gen_zero,symb_bloc((yyvsp[-1])))); } +#line 5977 "y.tab.c" /* yacc.c:1646 */ + break; + + case 167: +#line 646 "input_parser.yy" /* yacc.c:1646 */ + {(yyval) = symbolic(*(yyvsp[-3])._FUNCptr,makevecteur(equaltosame((yyvsp[-2])),(yyvsp[0]),0));} +#line 5983 "y.tab.c" /* yacc.c:1646 */ + break; + + case 168: +#line 647 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_try_catch(makevecteur(symb_bloc((yyvsp[-3])),at_break,symb_bloc((yyvsp[-1])))); } +#line 5989 "y.tab.c" /* yacc.c:1646 */ + break; + + case 169: +#line 648 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_try_catch(makevecteur(symb_bloc((yyvsp[-2])),at_break,0)); } +#line 5995 "y.tab.c" /* yacc.c:1646 */ + break; + + case 170: +#line 649 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_try_catch(makevecteur(symb_bloc((yyvsp[-4])),at_break,symb_bloc((yyvsp[-1])))); } +#line 6001 "y.tab.c" /* yacc.c:1646 */ + break; + + case 171: +#line 650 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_try_catch(makevecteur(symb_bloc((yyvsp[-3])),at_break,0)); } +#line 6007 "y.tab.c" /* yacc.c:1646 */ + break; + + case 172: +#line 651 "input_parser.yy" /* yacc.c:1646 */ + { vecteur v1(gen2vecteur((yyvsp[-2]))),v3(gen2vecteur((yyvsp[0]))); (yyval)=symbolic(at_ti_semi,makevecteur(v1,v3)); } +#line 6013 "y.tab.c" /* yacc.c:1646 */ + break; + + case 173: +#line 652 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-9]),(yyvsp[-9])*gen_zero,symb_local((yyvsp[-3]),mergevecteur(*(yyvsp[-6])._VECTptr,*(yyvsp[-1])._VECTptr),contextptr),(yyvsp[-11]),false,contextptr); + } +#line 6022 "y.tab.c" /* yacc.c:1646 */ + break; + + case 174: +#line 656 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-8]),(yyvsp[-8])*gen_zero,symb_local((yyvsp[-3]),mergevecteur(*(yyvsp[-5])._VECTptr,*(yyvsp[-1])._VECTptr),contextptr),(yyvsp[-10]),false,contextptr); + } +#line 6031 "y.tab.c" /* yacc.c:1646 */ + break; + + case 175: +#line 660 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-8]),(yyvsp[-8])*gen_zero,symb_local((yyvsp[-3]),(yyvsp[-1]),contextptr),(yyvsp[-10]),false,contextptr); + } +#line 6040 "y.tab.c" /* yacc.c:1646 */ + break; + + case 176: +#line 664 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval)=symb_program_sto((yyvsp[-4]),(yyvsp[-4])*gen_zero,symb_bloc((yyvsp[-1])),(yyvsp[-6]),false,giac_yyget_extra(scanner)); + } +#line 6048 "y.tab.c" /* yacc.c:1646 */ + break; + + case 177: +#line 667 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(*(yyvsp[-2])._FUNCptr,(yyvsp[-1])); } +#line 6054 "y.tab.c" /* yacc.c:1646 */ + break; + + case 178: +#line 668 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(*(yyvsp[-1])._FUNCptr,(yyvsp[0])); } +#line 6060 "y.tab.c" /* yacc.c:1646 */ + break; + + case 179: +#line 669 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6066 "y.tab.c" /* yacc.c:1646 */ + break; + + case 180: +#line 670 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_program_sto((yyvsp[-3]),(yyvsp[-3])*gen_zero,(yyvsp[0]),(yyvsp[-5]),false,giac_yyget_extra(scanner));} +#line 6072 "y.tab.c" /* yacc.c:1646 */ + break; + + case 181: +#line 671 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=symb_program_sto((yyvsp[-9]),(yyvsp[-9])*gen_zero,symb_local((yyvsp[-3]),(yyvsp[-1]),contextptr),(yyvsp[-11]),false,contextptr); + } +#line 6081 "y.tab.c" /* yacc.c:1646 */ + break; + + case 182: +#line 675 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_program_sto((yyvsp[-5]),(yyvsp[-5])*gen_zero,symb_bloc((yyvsp[-1])),(yyvsp[-7]),false,giac_yyget_extra(scanner)); } +#line 6087 "y.tab.c" /* yacc.c:1646 */ + break; + + case 183: +#line 676 "input_parser.yy" /* yacc.c:1646 */ + { + vecteur & v=*(yyvsp[-3])._VECTptr; + if ( (v.size()<3) || v[0].type!=_IDNT){ + *logptr(giac_yyget_extra(scanner)) << "Syntax For name,begin,end[,step]" << '\n'; + (yyval)=undef; + } + else { + gen pas(gen(1)); + if (v.size()==4) + pas=v[3]; + gen condition; + if (is_positive(-pas,0)) + condition=symb_superieur_egal(v[0],v[2]); + else + condition=symb_inferieur_egal(v[0],v[2]); + vecteur w=makevecteur(symb_sto(v[1],v[0]),condition,symb_sto(symb_plus(v[0],pas),v[0]),symb_bloc((yyvsp[-1]))); + (yyval)=symbolic(*(yyvsp[-4])._FUNCptr,w); + } + } +#line 6111 "y.tab.c" /* yacc.c:1646 */ + break; + + case 184: +#line 695 "input_parser.yy" /* yacc.c:1646 */ + { + vecteur v=makevecteur(gen_zero,equaltosame((yyvsp[-3])),gen_zero,symb_bloc((yyvsp[-1]))); + (yyval)=symbolic(*(yyvsp[-4])._FUNCptr,v); + } +#line 6120 "y.tab.c" /* yacc.c:1646 */ + break; + + case 185: +#line 707 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6126 "y.tab.c" /* yacc.c:1646 */ + break; + + case 186: +#line 708 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=makesequence((yyvsp[-2]),(yyvsp[0]));} +#line 6132 "y.tab.c" /* yacc.c:1646 */ + break; + + case 187: +#line 709 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6138 "y.tab.c" /* yacc.c:1646 */ + break; + + case 188: +#line 710 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6144 "y.tab.c" /* yacc.c:1646 */ + break; + + case 189: +#line 713 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6150 "y.tab.c" /* yacc.c:1646 */ + break; + + case 190: +#line 714 "input_parser.yy" /* yacc.c:1646 */ + { + gen tmp((yyvsp[0])); + // tmp.subtype=1; + //$$=symb_check_type(makevecteur(tmp,$1),context0); + (yyval)=symbolic(at_deuxpoints,makesequence((yyvsp[-2]),(yyvsp[0]))); + } +#line 6161 "y.tab.c" /* yacc.c:1646 */ + break; + + case 191: +#line 720 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_double_deux_points(makevecteur((yyvsp[-2]),(yyvsp[0]))); } +#line 6167 "y.tab.c" /* yacc.c:1646 */ + break; + + case 192: +#line 721 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_double_deux_points(makevecteur((yyvsp[-2]),(yyvsp[0]))); } +#line 6173 "y.tab.c" /* yacc.c:1646 */ + break; + + case 193: +#line 722 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_double_deux_points(makevecteur((yyvsp[-2]),(yyvsp[0]))); } +#line 6179 "y.tab.c" /* yacc.c:1646 */ + break; + + case 194: +#line 723 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_double_deux_points(makevecteur((yyvsp[-4]),(yyvsp[-1]))); } +#line 6185 "y.tab.c" /* yacc.c:1646 */ + break; + + case 195: +#line 724 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_double_deux_points(makevecteur(0,(yyvsp[0]))); } +#line 6191 "y.tab.c" /* yacc.c:1646 */ + break; + + case 196: +#line 725 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_double_deux_points(makevecteur((yyvsp[-2]),(yyvsp[0]))); } +#line 6197 "y.tab.c" /* yacc.c:1646 */ + break; + + case 197: +#line 733 "input_parser.yy" /* yacc.c:1646 */ + { + gen tmp((yyvsp[-1])); + // tmp.subtype=1; + // $$=symb_check_type(makevecteur(tmp,$2),context0); + (yyval)=symbolic(at_deuxpoints,makesequence((yyvsp[0]),(yyvsp[-1]))); + } +#line 6208 "y.tab.c" /* yacc.c:1646 */ + break; + + case 198: +#line 739 "input_parser.yy" /* yacc.c:1646 */ + {(yyval)=symbolic(*(yyvsp[-1])._FUNCptr,(yyvsp[0])); } +#line 6214 "y.tab.c" /* yacc.c:1646 */ + break; + + case 199: +#line 742 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6220 "y.tab.c" /* yacc.c:1646 */ + break; + + case 200: +#line 743 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6226 "y.tab.c" /* yacc.c:1646 */ + break; + + case 201: +#line 746 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=makevecteur(vecteur(0),vecteur(0)); } +#line 6232 "y.tab.c" /* yacc.c:1646 */ + break; + + case 202: +#line 747 "input_parser.yy" /* yacc.c:1646 */ + { vecteur v1 =gen2vecteur((yyvsp[-1])); vecteur v2=gen2vecteur((yyvsp[0])); (yyval)=makevecteur(mergevecteur(gen2vecteur(v1[0]),gen2vecteur(v2[0])),mergevecteur(gen2vecteur(v1[1]),gen2vecteur(v2[1]))); } +#line 6238 "y.tab.c" /* yacc.c:1646 */ + break; + + case 203: +#line 748 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6244 "y.tab.c" /* yacc.c:1646 */ + break; + + case 204: +#line 752 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[-1]).type==_VECT) (yyval)=gen(*(yyvsp[-1])._VECTptr,_RPN_STACK__VECT); else (yyval)=gen(vecteur(1,(yyvsp[-1])),_RPN_STACK__VECT); } +#line 6250 "y.tab.c" /* yacc.c:1646 */ + break; + + case 205: +#line 753 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(vecteur(0),_RPN_STACK__VECT); } +#line 6256 "y.tab.c" /* yacc.c:1646 */ + break; + + case 206: +#line 756 "input_parser.yy" /* yacc.c:1646 */ + { if (!(yyvsp[-2]).val) (yyval)=makevecteur((yyvsp[-1]),vecteur(0)); else (yyval)=makevecteur(vecteur(0),(yyvsp[-1]));} +#line 6262 "y.tab.c" /* yacc.c:1646 */ + break; + + case 207: +#line 759 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[-1]); } +#line 6268 "y.tab.c" /* yacc.c:1646 */ + break; + + case 208: +#line 762 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(vecteur(1,(yyvsp[0])),_SEQ__VECT); } +#line 6274 "y.tab.c" /* yacc.c:1646 */ + break; + + case 209: +#line 763 "input_parser.yy" /* yacc.c:1646 */ + { + vecteur v=*(yyvsp[-2])._VECTptr; + v.push_back((yyvsp[0])); + (yyval)=gen(v,_SEQ__VECT); + } +#line 6284 "y.tab.c" /* yacc.c:1646 */ + break; + + case 210: +#line 770 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6290 "y.tab.c" /* yacc.c:1646 */ + break; + + case 211: +#line 771 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=parser_symb_sto((yyvsp[0]),(yyvsp[-2]),(yyvsp[-1])==at_array_sto); } +#line 6296 "y.tab.c" /* yacc.c:1646 */ + break; + + case 212: +#line 772 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_equal((yyvsp[-2]),(yyvsp[0])); } +#line 6302 "y.tab.c" /* yacc.c:1646 */ + break; + + case 213: +#line 773 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symbolic(at_deuxpoints,makesequence((yyvsp[-2]),(yyvsp[0]))); } +#line 6308 "y.tab.c" /* yacc.c:1646 */ + break; + + case 214: +#line 774 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[-1]); } +#line 6314 "y.tab.c" /* yacc.c:1646 */ + break; + + case 215: +#line 775 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); *logptr(giac_yyget_extra(scanner)) << "Error: reserved word "<< (yyvsp[0]) <<'\n';} +#line 6320 "y.tab.c" /* yacc.c:1646 */ + break; + + case 216: +#line 776 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_double_deux_points(makevecteur((yyvsp[-2]),(yyvsp[0]))); *logptr(giac_yyget_extra(scanner)) << "Error: reserved word "<< (yyvsp[-2]) <<'\n'; } +#line 6326 "y.tab.c" /* yacc.c:1646 */ + break; + + case 217: +#line 777 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=string2gen("_"+(yyvsp[0]).print(contextptr),false); + if (!giac::first_error_line(contextptr)){ + giac::first_error_line(giac::lexer_line_number(contextptr),contextptr); + giac:: error_token_name((yyvsp[0]).print(contextptr)+ " (reserved word)",contextptr); + } +} +#line 6339 "y.tab.c" /* yacc.c:1646 */ + break; + + case 218: +#line 785 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval)=string2gen("_"+(yyvsp[0]).print(contextptr),false); + if (!giac::first_error_line(contextptr)){ + giac::first_error_line(giac::lexer_line_number(contextptr),contextptr); + giac:: error_token_name((yyvsp[0]).print(contextptr)+ " reserved word",contextptr); + } +} +#line 6352 "y.tab.c" /* yacc.c:1646 */ + break; + + case 219: +#line 795 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(1);} +#line 6358 "y.tab.c" /* yacc.c:1646 */ + break; + + case 220: +#line 796 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6364 "y.tab.c" /* yacc.c:1646 */ + break; + + case 221: +#line 799 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(vecteur(0),_SEQ__VECT); } +#line 6370 "y.tab.c" /* yacc.c:1646 */ + break; + + case 222: +#line 800 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=makesuite((yyvsp[0])); } +#line 6376 "y.tab.c" /* yacc.c:1646 */ + break; + + case 223: +#line 803 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = gen(makevecteur((yyvsp[0])),_PRG__VECT); } +#line 6382 "y.tab.c" /* yacc.c:1646 */ + break; + + case 224: +#line 805 "input_parser.yy" /* yacc.c:1646 */ + { vecteur v(1,(yyvsp[-1])); + if ((yyvsp[-1]).type==_VECT) v=*((yyvsp[-1])._VECTptr); + v.push_back((yyvsp[0])); + (yyval) = gen(v,_PRG__VECT); + } +#line 6392 "y.tab.c" /* yacc.c:1646 */ + break; + + case 225: +#line 810 "input_parser.yy" /* yacc.c:1646 */ + { (yyval) = (yyvsp[-1]);} +#line 6398 "y.tab.c" /* yacc.c:1646 */ + break; + + case 226: +#line 813 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=vecteur(0); } +#line 6404 "y.tab.c" /* yacc.c:1646 */ + break; + + case 227: +#line 814 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=mergevecteur(vecteur(1,(yyvsp[-1])),*((yyvsp[0])._VECTptr));} +#line 6410 "y.tab.c" /* yacc.c:1646 */ + break; + + case 228: +#line 815 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=mergevecteur(vecteur(1,(yyvsp[-2])),*((yyvsp[0])._VECTptr));} +#line 6416 "y.tab.c" /* yacc.c:1646 */ + break; + + case 229: +#line 818 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6422 "y.tab.c" /* yacc.c:1646 */ + break; + + case 230: +#line 888 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(1); } +#line 6428 "y.tab.c" /* yacc.c:1646 */ + break; + + case 231: +#line 889 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6434 "y.tab.c" /* yacc.c:1646 */ + break; + + case 232: +#line 892 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(1); } +#line 6440 "y.tab.c" /* yacc.c:1646 */ + break; + + case 233: +#line 893 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6446 "y.tab.c" /* yacc.c:1646 */ + break; + + case 234: +#line 894 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6452 "y.tab.c" /* yacc.c:1646 */ + break; + + case 235: +#line 895 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6458 "y.tab.c" /* yacc.c:1646 */ + break; + + case 236: +#line 898 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=gen(1); } +#line 6464 "y.tab.c" /* yacc.c:1646 */ + break; + + case 237: +#line 899 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6470 "y.tab.c" /* yacc.c:1646 */ + break; + + case 238: +#line 902 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=0; } +#line 6476 "y.tab.c" /* yacc.c:1646 */ + break; + + case 239: +#line 903 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[-1]); } +#line 6482 "y.tab.c" /* yacc.c:1646 */ + break; + + case 240: +#line 904 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=symb_bloc((yyvsp[0])); } +#line 6488 "y.tab.c" /* yacc.c:1646 */ + break; + + case 241: +#line 908 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval) = (yyvsp[-1]); + } +#line 6496 "y.tab.c" /* yacc.c:1646 */ + break; + + case 242: +#line 911 "input_parser.yy" /* yacc.c:1646 */ + { + const giac::context * contextptr = giac_yyget_extra(scanner); + (yyval) = symb_local((yyvsp[-2]),(yyvsp[-1]),contextptr); + } +#line 6505 "y.tab.c" /* yacc.c:1646 */ + break; + + case 243: +#line 918 "input_parser.yy" /* yacc.c:1646 */ + { if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=4) giac_yyerror(scanner,"missing test end delimiter"); (yyval)=0; } +#line 6511 "y.tab.c" /* yacc.c:1646 */ + break; + + case 244: +#line 919 "input_parser.yy" /* yacc.c:1646 */ + { + if ((yyvsp[0]).type==_INT_ && (yyvsp[0]).val && (yyvsp[0]).val!=4) giac_yyerror(scanner,"missing test end delimiter"); + (yyval)=symb_bloc((yyvsp[-1])); + } +#line 6520 "y.tab.c" /* yacc.c:1646 */ + break; + + case 245: +#line 923 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval)=symb_ifte(equaltosame((yyvsp[-3])),symb_bloc((yyvsp[-1])),(yyvsp[0])); + } +#line 6528 "y.tab.c" /* yacc.c:1646 */ + break; + + case 246: +#line 926 "input_parser.yy" /* yacc.c:1646 */ + { + (yyval)=symb_ifte(equaltosame((yyvsp[-3])),symb_bloc((yyvsp[-1])),(yyvsp[0])); + } +#line 6536 "y.tab.c" /* yacc.c:1646 */ + break; + + case 247: +#line 931 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6542 "y.tab.c" /* yacc.c:1646 */ + break; + + case 248: +#line 932 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6548 "y.tab.c" /* yacc.c:1646 */ + break; + + case 249: +#line 935 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=0; } +#line 6554 "y.tab.c" /* yacc.c:1646 */ + break; + + case 250: +#line 936 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=0; } +#line 6560 "y.tab.c" /* yacc.c:1646 */ + break; + + case 251: +#line 939 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=vecteur(0); } +#line 6566 "y.tab.c" /* yacc.c:1646 */ + break; + + case 252: +#line 940 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=makevecteur(symb_bloc((yyvsp[0])));} +#line 6572 "y.tab.c" /* yacc.c:1646 */ + break; + + case 253: +#line 941 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=mergevecteur(makevecteur((yyvsp[-3]),symb_bloc((yyvsp[-1]))),*((yyvsp[0])._VECTptr));} +#line 6578 "y.tab.c" /* yacc.c:1646 */ + break; + + case 254: +#line 944 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=vecteur(0); } +#line 6584 "y.tab.c" /* yacc.c:1646 */ + break; + + case 255: +#line 945 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=vecteur(1,symb_bloc((yyvsp[0]))); } +#line 6590 "y.tab.c" /* yacc.c:1646 */ + break; + + case 256: +#line 946 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=mergevecteur(makevecteur((yyvsp[-3]),symb_bloc((yyvsp[-1]))),*((yyvsp[0])._VECTptr));} +#line 6596 "y.tab.c" /* yacc.c:1646 */ + break; + + case 257: +#line 949 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=vecteur(0); } +#line 6602 "y.tab.c" /* yacc.c:1646 */ + break; + + case 258: +#line 950 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=vecteur(1,symb_bloc((yyvsp[0]))); } +#line 6608 "y.tab.c" /* yacc.c:1646 */ + break; + + case 259: +#line 951 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=mergevecteur(makevecteur((yyvsp[-4]),symb_bloc((yyvsp[-2]))),gen2vecteur((yyvsp[0])));} +#line 6614 "y.tab.c" /* yacc.c:1646 */ + break; + + case 260: +#line 952 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=mergevecteur(makevecteur((yyvsp[-5]),symb_bloc((yyvsp[-3]))),gen2vecteur((yyvsp[0])));} +#line 6620 "y.tab.c" /* yacc.c:1646 */ + break; + + case 261: +#line 955 "input_parser.yy" /* yacc.c:1646 */ + { (yyval)=(yyvsp[0]); } +#line 6626 "y.tab.c" /* yacc.c:1646 */ + break; + + +#line 6630 "y.tab.c" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (scanner, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (scanner, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, scanner); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, scanner); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (scanner, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, scanner); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, scanner); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 962 "input_parser.yy" /* yacc.c:1906 */ + + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac + + +#endif // ndef NO_NAMESPACE_GIAC +int giac_yyget_column (yyscan_t yyscanner); + +// Error print routine (store error string in parser_error) +#if 1 +int giac_yyerror(yyscan_t scanner,const char *s) { + const giac::context * contextptr = giac_yyget_extra(scanner); + int col = giac_yyget_column(scanner); + int line = giac::lexer_line_number(contextptr); + const char * scanb=giac::currently_scanned(contextptr); + std::string curline; + if (scanb){ + for (int i=1;isuffix.size() && token_name.compare(token_name.size()-suffix.size(),suffix.size(),suffix)) { + if (col>=token_name.size()-suffix.size()) { + col -= token_name.size()-suffix.size(); + } + } else if (col>=token_name.size()) { + col -= token_name.size(); + } + giac::lexer_column_number(contextptr)=col; + string sy("syntax error "); + if (0 && strlen(s)){ + sy += ": "; + sy += s; + sy +=", "; + } + if (is_at_end) { + parser_error(":" + giac::print_INT_(line) + ": " +sy + " at end of input\n",contextptr); // string(s) replaced with syntax error + giac::parsed_gen(giac::undef,contextptr); + } else { + parser_error( ":" + giac::print_INT_(line) + ": " + sy + " line " + giac::print_INT_(line) + " col " + giac::print_INT_(col) + " at " + token_name +" in "+curline+" \n",contextptr); // string(s) replaced with syntax error + giac::parsed_gen(giac::string2gen(token_name,false),contextptr); + } + if (!giac::first_error_line(contextptr)) { + giac::first_error_line(line,contextptr); + if (is_at_end) { + token_name="end of input"; + } + giac:: error_token_name(token_name,contextptr); + } + return line; +} + +#else + +int giac_yyerror(yyscan_t scanner,const char *s) +{ + const giac::context * contextptr = giac_yyget_extra(scanner); + int col= giac_yyget_column(scanner); + giac::lexer_column_number(contextptr)=col; + if ( (*giac_yyget_text( scanner )) && (giac_yyget_text( scanner )[0]!=-61) && (giac_yyget_text( scanner )[1]!=-65)){ + std::string txt=giac_yyget_text( scanner ); + parser_error( ":" + giac::print_INT_(giac::lexer_line_number(contextptr)) + ": " + string(s) + " line " + giac::print_INT_(giac::lexer_line_number(contextptr)) + " col " + giac::print_INT_(col) + " at " + txt +"\n",contextptr); + giac::parsed_gen(giac::string2gen(txt,false),contextptr); + } + else { + parser_error(":" + giac::print_INT_(giac::lexer_line_number(contextptr)) + ": " +string(s) + " at end of input\n",contextptr); + giac::parsed_gen(giac::undef,contextptr); + } + if (!giac::first_error_line(contextptr)){ + giac::first_error_line(giac::lexer_line_number(contextptr),contextptr); + std::string s=string(giac_yyget_text( scanner )); + if (s.size()==2 && s[0]==-61 && s[1]==-65) + s="end of input"; + giac:: error_token_name(s,contextptr); + } + return giac::lexer_line_number(contextptr); +} +#endif diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/intg.cc b/android/app/src/main/cpp/giac/src/giac/cpp/intg.cc new file mode 100644 index 0000000..adfa9e9 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/intg.cc @@ -0,0 +1,7344 @@ +// -*- mode:C++ ; compile-command: "g++ -I.. -g -c intg.cc -fno-strict-aliasing -DGIAC_GENERIC_CONSTANTS -DHAVE_CONFIG_H -DIN_GIAC " -*- +#include "giacPCH.h" +// #define LOGINT + +/* + * Copyright (C) 2000,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using namespace std; +#include +#include "vector.h" +#include +#include +#include +#include "sym2poly.h" +#include "usual.h" +#include "intg.h" +#include "subst.h" +#include "derive.h" +#include "lin.h" +#include "vecteur.h" +#include "gausspol.h" +#include "plot.h" +#include "prog.h" +#include "modpoly.h" +#include "series.h" +#include "tex.h" +#include "ifactor.h" +#include "risch.h" +#include "solve.h" +#include "intgab.h" +#include "moyal.h" +#include "maple.h" +#include "rpn.h" +#include "modpoly.h" +#include "giacintl.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBGSL +#include +#include +#include +#include +#include +#include +#endif + +#if defined HAVE_LIBBERNMM && !defined BF2GMP_H +#include +#endif + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + // Left redimension p to degree n, i.e. size n+1 + void lrdm(modpoly & p,int n){ + int s=int(p.size()); + if (n+1>s) + p=mergevecteur(vecteur(n+1-s),p); + } + + struct pf1 { + vecteur num; + vecteur den; + vecteur fact; + int mult; // den=cste*fact^mult + pf1():num(0),den(makevecteur(1)),fact(makevecteur(1)),mult(1) {} + pf1(const pf1 & a) : num(a.num), den(a.den), fact(a.fact),mult(a.mult) {} + pf1(const vecteur &n, const vecteur & d, const vecteur & f,int m) : num(n), den(d), fact(f), mult(m) {}; + pf1(const polynome & n,const polynome & d,const polynome & f,int m): num(polynome2poly1(n,1)),den(polynome2poly1(d,1)),fact(polynome2poly1(f,1)),mult(m) {} + }; + + gen complex_subst(const gen & e,const vecteur & substin,const vecteur & substout,GIAC_CONTEXT){ + bool save_complex_mode=complex_mode(contextptr); + complex_mode(true,contextptr); + bool save_eval_abs=eval_abs(contextptr); + eval_abs(false,contextptr); + gen res=simplifier(eval(subst(e,substin,substout,false,contextptr),1,contextptr),contextptr); + // eval is used since after subst * are not flattened + complex_mode(save_complex_mode,contextptr); + eval_abs(save_eval_abs,contextptr); + return res; + } + + gen complex_subst(const gen & e,const gen & x,const gen & newx,GIAC_CONTEXT){ + bool save_complex_mode=complex_mode(contextptr); + complex_mode(true,contextptr); + bool save_eval_abs=eval_abs(contextptr); + eval_abs(false,contextptr); + gen res=subst(e,x,newx,false,contextptr); + eval_abs(save_eval_abs,contextptr); + // avoid rewrite of fractional powers + vecteur v=lop(newx,at_pow); + int i=0; + for (;ifeuille; + if (tmp.type==_VECT && tmp._VECTptr->size()==2){ + tmp=tmp._VECTptr->back(); + if (tmp.type==_FRAC && tmp._FRACptr->den.type==_INT_ ){ + tmp=tmp._FRACptr->den; + if (tmp.val % 2==1) + break; + } + } + } + } + complex_mode(save_complex_mode,contextptr); + if (i==v.size()) + res=eval(res,1,contextptr); + return res; + } + + static bool has_nop_var(const vecteur & v){ + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (contains(*it,at_nop)) + return true; + } + return false; + } + + static gen nop_inv(const gen & e,GIAC_CONTEXT){ + return symbolic(at_nop,gen(symbolic(at_inv,e))); + } + static gen nop_pow(const gen & e,GIAC_CONTEXT){ + if ( (e.type!=_VECT) || (e._VECTptr->size()!=2)) + return symbolic(at_pow,e); + if ( (e._VECTptr->back().type!=_INT_) || (e._VECTptr->back().val>=0) || ( (e._VECTptr->front().type==_SYMB) && (e._VECTptr->front()._SYMBptr->sommet==at_exp) ) ) + return symbolic(at_pow,change_subtype(e,_SEQ__VECT)); + return nop_inv(symbolic(at_pow,gen(makevecteur(e._VECTptr->front(),-e._VECTptr->back()),_SEQ__VECT)),contextptr); + } + + static gen sin_over_cos(const gen & e,GIAC_CONTEXT){ + return rdiv(symb_sin(e),symb_cos(e),contextptr); + } + const gen_op_context invpowtan2_tab[]={nop_inv,nop_pow,sin_over_cos,0}; + // remove nop if nop() does not contain x + gen remove_nop(const gen & g,const gen & x,GIAC_CONTEXT){ + if (g.type==_VECT){ + vecteur res(*g._VECTptr); + iterateur it=res.begin(),itend=res.end(); + for (;it!=itend;++it){ + *it=remove_nop(*it,x,contextptr); + } + return gen(res,g.subtype); + } + if (g.type!=_SYMB) + return g; + if (g._SYMBptr->sommet!=at_nop) + return symbolic(g._SYMBptr->sommet,remove_nop(g._SYMBptr->feuille,x,contextptr)); + if (is_zero(derive(g._SYMBptr->feuille,x,contextptr))) + return g._SYMBptr->feuille; + else + return g; + } + vecteur lvarxwithinv(const gen &e,const gen & x,GIAC_CONTEXT){ + gen ee=subst(e,invpowtan_tab,invpowtan2_tab,false,contextptr); + ee=remove_nop(ee,x,contextptr); + vecteur v(lvarx(ee,x)); + return v; // to remove nop do a return *(eval(v)._VECTptr); + } + + bool is_constant_wrt(const gen & e,const gen & x,GIAC_CONTEXT){ + if (e.type==_VECT){ + const_iterateur it=e._VECTptr->begin(),itend=e._VECTptr->end(); + for (;it!=itend;++it){ + if (!is_constant_wrt(*it,x,contextptr)) + return false; + } + return true; + } + if (e==x) + return false; + if (e.type!=_SYMB) + return true; + return is_exactly_zero(derive(e,x,contextptr)); + } + + // return true if e=a*x+b + bool is_linear_wrt(const gen & e,const gen &x,gen & a,gen & b,GIAC_CONTEXT){ + a=derive(e,x,contextptr); + if (is_undef(a) || !is_constant_wrt(a,x,contextptr)) + return false; + if (x*a==e) + b=0; + else + b=ratnormal(e-a*x,contextptr); + return lvarx(b,x).empty(); + } + + // return true if e=a*x+b + bool is_quadratic_wrt(const gen & e,const gen &x,gen & a,gen & b,gen & c,GIAC_CONTEXT){ + gen tmp=derive(e,x,contextptr); + if (is_undef(tmp) || !is_linear_wrt(tmp,x,a,b,contextptr)) + return false; + a=ratnormal(rdiv(a,plus_two,contextptr),contextptr); + c=ratnormal(e-a*x*x-b*x,contextptr); + return true; + } + + void decompose_plus(const vecteur & arg,const gen & x,vecteur & non_constant,gen & plus_constant,GIAC_CONTEXT){ + non_constant.clear(); + plus_constant=zero; + const_iterateur it=arg.begin(),itend=arg.end(); + for (;it!=itend;++it){ + if (is_constant_wrt(*it,x,contextptr)) + plus_constant=plus_constant+(*it); + else + non_constant.push_back(*it); + } + // if (contains(plus_constant,x)) plus_constant=ratnormal(plus_constant,contextptr); + } + + void decompose_prod(const vecteur & arg,const gen & x,vecteur & non_constant,gen & prod_constant,bool signcst,GIAC_CONTEXT){ + non_constant.clear(); + prod_constant=plus_one; + const_iterateur it=arg.begin(),itend=arg.end(); + for (;it!=itend;++it){ + gen tst=*it; + if (!signcst && it->is_symb_of_sommet(at_sign)) + tst=it->_SYMBptr->feuille; + if (is_constant_wrt(tst,x,contextptr)) + prod_constant=prod_constant*(*it); + else + non_constant.push_back(*it); + } + // if (contains(prod_constant,x)) prod_constant=ratnormal(prod_constant,contextptr); + } + + gen extract_cst(gen & u,const gen & x,GIAC_CONTEXT){ + if (!u.is_symb_of_sommet(at_prod) || u._SYMBptr->feuille.type!=_VECT) + return 1; + vecteur non_constant; gen prod_constant=1; + decompose_prod(*u._SYMBptr->feuille._VECTptr,x,non_constant,prod_constant,false,contextptr); + if (non_constant.size()==0) + u=1; + if (non_constant.size()==1) + u=non_constant.front(); + if (non_constant.size()>1) + u=symbolic(at_prod,gen(non_constant,_SEQ__VECT)); + return prod_constant; + } + + // applies linearity of f. + & neg are distributed as well as * with respect + // to terms that are constant w.r.t. x + // e is assumed to be a scalar + gen linear_apply(const gen & e,const gen & x,gen & remains, int intmode,GIAC_CONTEXT, gen (* f)(const gen &,const gen &,gen &,int,const context *)){ + if (is_constant_wrt(e,x,contextptr) || (e==x) ) + return f(e,x,remains,intmode,contextptr); + // e must be of type _SYMB + if (e.type==_VECT){ + vecteur v(*e._VECTptr); + vecteur r(v.size()); + for (unsigned i=0;isommet); + gen arg(e._SYMBptr->feuille); + gen res; + if (u==at_neg){ + res=-linear_apply(arg,x,remains,intmode,contextptr,f); + remains=-remains; + return res; + } // end at_neg + if (u==at_plus){ + if (arg.type!=_VECT) + return linear_apply(arg,x,remains,intmode,contextptr,f); + const_iterateur it=arg._VECTptr->begin(),itend=arg._VECTptr->end(); + for (gen tmp;it!=itend;++it){ + res = res + linear_apply(*it,x,tmp,intmode,contextptr,f); + remains =remains + tmp; + } + return res; + } // end at_plus + if (u==at_prod){ + if (arg.type!=_VECT) + return linear_apply(arg,x,remains,intmode,contextptr,f); + // find all constant terms in the product + vecteur non_constant; + gen prod_constant; + decompose_prod(*arg._VECTptr,x,non_constant,prod_constant,false,contextptr); + if (non_constant.empty()) return gensizeerr(gettext("in linear_apply 2")); // otherwise the product would be constant + if (non_constant.size()==1) + res = linear_apply(non_constant.front(),x,remains,intmode,contextptr,f); + else + res = f(symbolic(at_prod,gen(non_constant,_SEQ__VECT)),x,remains,intmode,contextptr); + remains = prod_constant * remains; + return prod_constant * res; + } // end at_prod + return f(e,x,remains,intmode,contextptr); + } + + gen lnabs(const gen & x,GIAC_CONTEXT){ + bool _lnabs=do_lnabs(contextptr); + if (!complex_mode(contextptr) && _lnabs && !has_i(x)) + return ln(abs(x,contextptr),contextptr); + else + return ln(x,contextptr); + } + + gen lnabs2(const gen & x,const gen & xvar,GIAC_CONTEXT){ + if (xvar.type!=_IDNT) + return lnabs(x,contextptr); + bool _lnabs=do_lnabs(contextptr); + if (!complex_mode(contextptr) && _lnabs && !has_i(x)){ + return symbolic(at_ln,symbolic(at_abs,x)); + } + else { + if (is_positive(-x,contextptr)) + return symbolic(at_ln,-x); + return symbolic(at_ln,x); + } + } + + static gen normal_norootof(const gen & g,GIAC_CONTEXT){ + gen res=normal(g,contextptr); + if (!lop(res,at_rootof).empty()) + res=ratnormal(normalize_sqrt(g,contextptr),contextptr); + return res; + } + + // eval N at X=e with e=x*exp(i*dephasage*pi/n) and returns N*ln(X-e)+conj + static gen substconj_(const gen & N,const gen & X,const gen & x,const gen & dephasage_,bool residue_only,GIAC_CONTEXT){ + int mode=angle_mode(contextptr); + gen pi=cst_pi; + gen dephasage(dephasage_); + if (mode==1){ + dephasage=ratnormal(gen(180)/cst_pi*dephasage,contextptr); + pi=180; + } + if (mode==2){ + dephasage=ratnormal(gen(200)/cst_pi*dephasage,contextptr); + pi=200; + } + gen c=cos(dephasage,contextptr); + gen s=sin(dephasage,contextptr); + if (c.is_symb_of_sommet(at_cos) && c._SYMBptr->feuille==dephasage){ + gen c2=cos(ratnormal(2*dephasage,contextptr),contextptr); + if (!c2.is_symb_of_sommet(at_cos)){ + c=sign(c,contextptr)*sqrt((1+c2)/2,contextptr); + s=sign(s,contextptr)*sqrt((1-c2)/2,contextptr); + } + } + gen e=x*(c+cst_i*s); + gen b=subst(N,X,e,false,contextptr),rb,ib; + reim(b,rb,ib,contextptr); + gen N2=normal_norootof(-2*ib,contextptr); // same + if (residue_only) + return N2*sign(s*x,contextptr); + gen res=normal_norootof(rb,contextptr)*symbolic(at_ln,pow(X,2)+ratnormal(-2*c*x,contextptr)*X+x.squarenorm(contextptr)); + gen atanterm=pi/cst_pi*symbolic(at_atan,(X-c*x)/(s*x)); + if (X.is_symb_of_sommet(at_tan)) + atanterm += pi*sign(s*x,contextptr)*symbolic(at_floor,X._SYMBptr->feuille/pi+plus_one_half); + res=res+N2*atanterm; + return res; + } + + static gen substconj(const gen & N,const gen & X,const gen & x,const gen & dephasage,bool residue_only,GIAC_CONTEXT){ + if (has_i(N)){ + gen Nr,Ni; + reim(N,Nr,Ni,contextptr); + return substconj_(Nr,X,x,dephasage,residue_only,contextptr)+cst_i*substconj_(Ni,X,x,dephasage,residue_only,contextptr); + } + return substconj_(N,X,x,dephasage,residue_only,contextptr); + } + + gen surd(const gen & c,int n,GIAC_CONTEXT){ + if (is_exactly_zero(c)) + return c; + if (n%2 && is_positive(-c,contextptr)){ + if (c.type==_FLOAT_) + return -exp(ln(-c,contextptr)/n,contextptr); + return -pow(-c,inv(n,contextptr),contextptr); + } + else { + if (c.type==_FLOAT_) + return exp(ln(c,contextptr)/n,contextptr); + return pow(c,inv(n,contextptr),contextptr); + } + } + + gen _surd(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT || args._VECTptr->size()!=2) + return gensizeerr(contextptr); + gen a=args._VECTptr->front(),aa,b=args._VECTptr->back(),c; + if (a.is_symb_of_sommet(at_abs) || a.is_symb_of_sommet(at_exp)) + return pow(a,inv(b,contextptr),contextptr); + if (is_equal(a)){ + gen a0=a._SYMBptr->feuille[0],a1=a._SYMBptr->feuille[1]; + return symbolic(at_equal,makesequence(_surd(makesequence(a0,b),contextptr),_surd(makesequence(a1,b),contextptr))); + } + if (is_undef(a)) return a; + if (is_undef(b)) return b; + if (is_inf(b)){ + if (is_inf(a) || is_zero(a)) + return undef; + return 1; + } + if (is_zero(b)) + return undef; + if (is_inf(a)){ + if (a==minus_inf && is_integral(b) && b.type==_INT_ && b.val%2) + return -pow(plus_inf,inv(b,contextptr),contextptr); + return pow(a,inv(b,contextptr),contextptr); + } + c=_floor(b,contextptr); + if (c.type==_FLOAT_) + c=get_int(c._FLOAT_val); + if (!has_evalf(a,aa,1,contextptr)){ + if (c.type==_INT_ && c==b && (c.val %2 ==0 || (a.is_symb_of_sommet(at_pow) && a._SYMBptr->feuille[1].type==_INT_ && a._SYMBptr->feuille[1].val % c.val==0)) ) + return pow(a,inv(c,contextptr),contextptr); + return symbolic(at_NTHROOT,gen(makevecteur(b,a),_SEQ__VECT)); + } + if (c.type==_INT_ && c==b) + return surd(a,c.val,contextptr); + else + return pow(a,inv(b,contextptr),contextptr); + } + static const char _surd_s []="surd"; + static define_unary_function_eval (__surd,&_surd,_surd_s); + define_unary_function_ptr5( at_surd ,alias_at_surd,&__surd,0,true); + + static gen makelnatan(const gen & N,const gen & X,const gen & c0,int n,bool residue_only,GIAC_CONTEXT){ + gen c(c0),res(0); + if (n%2){ + if (is_positive(-c,contextptr)) + c=-pow(-c,inv(n,contextptr),contextptr); + else + c=pow(c,inv(n,contextptr),contextptr); + if (!residue_only) + res += subst(N,X,c,false,contextptr)*lnabs(X-c,contextptr); + for (int i=1;i<=n/2;++i) + res += substconj(N,X,c,gen(2*i)/n*cst_pi,residue_only,contextptr); + return res; + } + if (is_positive(c,contextptr) ){ + if (n==2) + c=sqrt(c,contextptr); + else + c=pow(c,inv(n,contextptr),contextptr); + if (!residue_only) + res += normal_norootof(subst(N,X,c,false,contextptr),contextptr)*lnabs2(X-c,X,contextptr)+normal_norootof(subst(N,X,-c,false,contextptr),contextptr)*lnabs2(X+c,X,contextptr); + for (int i=1;ib.lexsorted_degree()) + return -ln2sumatan(b,a,l,contextptr); + polynome u,v,d; + egcd(a,b,u,v,d); + if (v.coord.empty()){ // a divides b + return symb_atan(a,b,l,contextptr); + } + gen tmp=-ln2sumatan(v,u,l,contextptr); + tmp += symb_atan(d,b*u-a*v,l,contextptr); + return tmp; + } + gen ln2sumatan(const gen & a,const gen & b,const vecteur & l,GIAC_CONTEXT){ + //return symb_atan(b/a); + gen A=e2r(a,l,contextptr),An,Ad; + gen B=e2r(b,l,contextptr),Bn,Bd; + fxnd(A,An,Ad); + fxnd(B,Bn,Bd); + An=Bd*An; + Bn=Ad*Bn; + if (An.type==_POLY && Bn.type==_POLY) + return ln2sumatan(*An._POLYptr,*Bn._POLYptr,l,contextptr); + if (Bn.type!=_POLY) + return -symb_atan(a/b); + return symb_atan(b/a); + } + + static bool integrate_rothstein_trager(const polynome & num,const vecteur & v,const vecteur & l,const gen & X,gen & res,int intmode,GIAC_CONTEXT){ + // Improve: csolve for resultant(num-t*v',v) + // Example a:=diff(atan((x^2-2x)/(x-1))); b:=int(a); + // v=[1,-4,5,-2,1], roots for resultant +/-i/2 + // sum t*ln(gcd(n-t*d',d)) + // if t is complex and v real + // t*ln()+conjugate=re(t)*ln(|gcd|^2)-im(t)*atan(im(gcd)/re(gcd)) + gen N=r2e(num,l,contextptr); + vecteur Nv(lvar(N)); + if (1 || Nv==vecteur(1,X)){ // [commented: do it for univariate only] + gen D=r2e(poly12polynome(v,1),l,contextptr),resadd; +#if 0 + gen Dprime=r2e(poly12polynome(derivative(v),1),l,contextptr); + gen Dc=1; +#else + gen Dc=_content(makesequence(D,X),contextptr); + D=_quo(makesequence(D,Dc,X),contextptr); + gen Dprime=derive(D,X,contextptr); +#endif + int Ddeg=v.size()-1; + gen tres(identificateur("tresultant")); + gen R=_resultant(makesequence(N-tres*Dprime,D,X),contextptr); + gen Rprime=derive(R,tres,contextptr); + R=_quo(makesequence(R,gcd(R,Rprime,contextptr),tres),contextptr); + gen Rdeg=_degree(makesequence(R,tres),contextptr); + if (Rdeg.type==_INT_ && Rdeg.val==Ddeg){ + // it's easier to extract the roots of D + gen racines=solve(D,X,1,contextptr); + if (!has_i(racines) && racines.type==_VECT && racines._VECTptr->size()==Ddeg){ + // apply sum_racines N/D'(racine)*log(x-racine) + gen ND=N/Dprime; + for (int i=0;isize()==Rdeg.val){ + vecteur w=*Rt._VECTptr; + bool reel=vect_is_real(v,contextptr); + if (!has_num_coeff(w)){ + for (size_t wi=0;wifront(); + gen a=r2e(v.front(),lprime,contextptr); + gen b=r2e(v.back(),lprime,contextptr); + // check for deno of type a*x^2n + A*x^n + b + // FIXME: improve some simplifications of sin/cos(asin()/k) and remove test d==2 + if (d==2 && 2*d==n){ + ++it; + for (;it!=itend;++it){ + if (!is_zero(*it)) + break; + } + if (it==itend){ // ok! + gen c=b; + b=r2e(v[d],lprime,contextptr); + gen delta=b*b-4*a*c; + if (is_zero(delta)) // if (is_positive(-delta,contextptr)) + return false; + if ( (intmode &2)==0) + gprintf(step_ratfrac,gettext("Integration of a rational fraction with denominator %gen\nroots are obtained by solving the 2nd order equation %gen=0 then extracting nth-roots"),makevecteur(a*symb_pow(vx_var,2*n)+b*symb_pow(vx_var,n)+c,a*symb_pow(vx_var,2)+b*vx_var+c),contextptr); + // int(num/(a*X^2d+b*X^d+c),X) = + // sum(x=rootof(deno),num*x/(+/-d*sqrt(delta))*ln(X-x)) + gen sqrtdelta=sqrt(delta,contextptr); + gen c1=(-b-sqrtdelta)/2/a; + gen c2=(-b+sqrtdelta)/2/a; + gen N=r2e(num,l,contextptr)*X/d/sqrtdelta; + if (is_zero(im(a,contextptr)) && is_zero(im(b,contextptr)) && is_zero(im(c,contextptr))){ + if (!is_positive(-delta,contextptr)){ + res += makelnatan(N/c2,X,c2,d,residue_only,contextptr); + res -= makelnatan(N/c1,X,c1,d,residue_only,contextptr); + return true; + } + else { + gen module=sqrt(c/a,contextptr); + gen argument=acos(normal(-b/a/2/module,contextptr),contextptr); + // roots are module^(1/d)*exp(i*argument/d)*exp(2*i*pi*k/d) + // for k=0..d-1 and conjugates + gen moduled=pow(c/a,inv(n,contextptr),contextptr); + for (int i=0;itype!=_INT_ && jt->type!=_POLY) + break; + } + deg=is_cyclotomic(w,epsilon(contextptr)); + if (!deg){ + w=w_copy; + c=pow(r2e(-*it/v.front(),lprime,contextptr),inv(d,contextptr),contextptr); + jt=w.begin()+1,jtend=w.end(); + for (int k=1;jt!=jtend;++jt,++k){ + *jt=normal(*jt * pow(c,-k),contextptr); + if (jt->type!=_INT_ && jt->type!=_POLY) + break; + } + deg=is_cyclotomic(w,epsilon(contextptr)); + } + if (!deg) + return residue_only?false:integrate_rothstein_trager(num,v,l,X,res,intmode,contextptr); + if ( (intmode &2)==0) + gprintf(step_cyclotomic,gettext("Integrate rational fraction with denominator a cyclotomic polynomial, roots are primitive roots of %gen=0"),makevecteur(a*symb_pow(vx_var,deg)+b),contextptr); + // int(num/(a*X^n+b),X)=sum(x=rootof(-b/a),num*x/(-n*b)*ln(X-x)) + vecteur vprime=derivative(v),V,Vprime,d; + egcd(v,vprime,0,V,Vprime,d); + if (d.size()!=1) + return residue_only?false:integrate_rothstein_trager(num,v,l,X,res,intmode,contextptr); + gen dd=d.front(); + // 1/vprime=Vprime/d + gen N=normal(_quorem(makesequence(r2e(num,l,contextptr)*horner(r2e(Vprime,lprime,contextptr),X),horner(r2e(v,lprime,contextptr),X),X),contextptr)[1]/r2e(dd,lprime,contextptr),contextptr); + if (complex_mode(contextptr) && !residue_only){ + for (int i=1;i0;n--){ + DivRem(w,powmod(test,n,0,0),0,q,r); + if (q.size()>1) + return 0; + w=r.empty()?r:vecteur(r.begin(),r.end()-1); + res.push_back(q.empty()?0:q.front()); + } + if (w.empty()) + res.push_back(0); // was return 0; + else + res.push_back(w.front()); + return rescoeff; + } + + // n/d(x) -> newn/newd(t) with x=a/t, + // if dx is true multiplies by dx/dt=-a/t^2 + static void xtoinvx(const gen & a,const modpoly & n,const modpoly & d,modpoly & newn, modpoly & newd,bool dx){ + int ns=int(n.size()); int nd=int(d.size()); + newn=vecteur(ns); newd=vecteur(nd); + gen ad(1); + for (int i=ns-1;i>=0;--i){ + newn[ns-1-i]=ad*n[i]; + ad = ad*a; + } + ad=1; + for (int i=nd-1;i>=0;--i){ + newd[nd-1-i]=ad*d[i]; + ad = ad*a; + } + if (dx){ + newn=operator_times(-a,newn,0); + ns+=2; + } + trim(newn,0); + trim(newd,0); + for (;ns>nd;--ns){ + newd.push_back(0); + } + for (;nd>ns;--nd){ + newn.push_back(0); + } + } + + static gen integrate_rational(const gen & e, const gen & x, gen & remains_to_integrate,gen & xvar,int intmode,GIAC_CONTEXT); + + static void solve_aPprime_plus_P(const gen & anum,const gen & aden,const vecteur & Q,vecteur & R,gen & Pden){ + // a P+P'=Q, a=anum/aden, on cherche P sous la forme R/Pden + // On a (k+1)p_(k+1)+ anum/aden*p_k=q_k + // Donc p_k=aden/anum*(q_k-(k+1)p_(k+1)) + // n=deg[Q], on a donc Pden=anum^(n+1), puis on cherche R=P*anum^(n+1) + // on multiplie donc Q par anum^(n+1) S=Q*anum^(n+1)/a + // on a aR+R'=aS + // on a donc par ordre decr. r_(n+1)=0 + // r_k= s_k - (k+1)*r_(k+1)/a + // avec des divisions sans creation de denominateurs + // par ex. P'+3P=x^2+5x+7 -> r_2=9, r_1=39, r_0=50, a=3, n=2, a^n=9 + R.clear(); + if (Q.empty()){ + Pden=plus_one; + return; + } + int n=int(Q.size())-1; + R.reserve(n+1); + Pden=pow(anum,n); + vecteur S; + multvecteur(Pden*aden,Q,S); + Pden=Pden*anum; + const_iterateur it=S.begin(),itend=S.end(); + R.push_back(*it); + ++it; + for (int k=n-1;it!=itend;++it,--k){ + R.push_back(*it-rdiv(gen(k+1)*R.back()*aden,anum,context0)); + } + // should simplify R with Pden + } + + static gen integrate_linearizable(const gen & e,const gen & gen_x,gen & remains_to_integrate,int intmode,bool do_risch,GIAC_CONTEXT){ + // exp linearization + vecteur vexp; + gen res; + const identificateur & id_x=*gen_x._IDNTptr; + lin(e,vexp,contextptr); // vexp = coeff, arg of exponential + if ( (intmode &2)==0 ){ + gen tmp=unlin(vexp,contextptr); + if (vexp.size()>2 || !is_zero(ratnormal(tmp-e,contextptr))) + gprintf(step_linearizable,gettext("Integrate linearizable expression %gen -> %gen"),makevecteur(e,tmp),contextptr); + } + const_iterateur it=vexp.begin(),itend=vexp.end(); + for (;it!=itend;){ + // trig linearization + vecteur vtrig; + gen coeff=*it; + ++it; // it -> on the arg of the exp that must be linear + gen rex2,rea,reb,reaxb=*it; + ++it; + if (!is_quadratic_wrt(reaxb,gen_x,rex2,rea,reb,contextptr)){ + // IMPROVE using int(exp(-x^a))=1/a*igamma(1/a,x^a) + vecteur lv=lvarxwithinv(makevecteur(reaxb,coeff),gen_x,contextptr); + if (lv.size()==1){ + gen C=_coeff(makesequence(reaxb,gen_x),contextptr); + if (C.type==_VECT && C._VECTptr->size()>2){ + vecteur Cv=*C._VECTptr; + int n=int(Cv.size())-1; + gen c=Cv[0]; + gen a=-Cv[1]/(n*c); + // must be c*(x-a)^n + if (C==_coeff(makesequence(c*pow(gen_x-a,n,contextptr),gen_x),contextptr) && ((n%2) || is_positive(-c,contextptr))){ + // c=surd(c,n,contextptr); + C=_coeff(makesequence(coeff,gen_x),contextptr); + C=_ptayl(makesequence(C,a,gen_x),contextptr); + if (C.type==_VECT){ + c=-c; + gen ca=surd(c,n,contextptr); + Cv=*C._VECTptr; + int m=int(Cv.size())-1; + gen ires=0; + // 1/n*igamma(1/n+b/n,c*x^n)'=x^b*exp(-c*x^n)*c^(b+1)/n + for (int b=0;b<=m;++b){ + ires += Cv[m-b]*_lower_incomplete_gamma(makesequence(gen(b+1)/gen(n),c*pow(gen_x-a,n)),contextptr)/pow(ca,b+1,contextptr); + } + if (n%2==0){ + ires=ires*abs(gen_x,contextptr)/gen_x; // sign(gen_x,contextptr); + } + ires=ires/n; + res += ires; + continue; + } + } + } + } + remains_to_integrate = remains_to_integrate + coeff*exp(reaxb,contextptr); + continue; + } + if (!is_zero(rex2)){ + if (1 + //&&is_zero(im(rex2,contextptr)) + //&& is_positive(-rex2,contextptr) + ){ + const vecteur & vx2=lvarxpow(coeff,gen_x); + if ( vx2.size()>1 || (!vx2.empty() && vx2.front()!=gen_x) ){ + remains_to_integrate = remains_to_integrate + coeff*exp(reaxb,contextptr); + continue; + } + // int(exp(rex2*x^2+rea*x+reb)*P(x),x) + gen decal=rea/rex2/2; + gen cst=normal(reb-rex2*decal*decal,contextptr); + // exp(cst)*int(exp(rex2*(x+decal)^2)*P(x),x) + coeff=quotesubst(coeff,gen_x,gen_x-decal,contextptr); + // exp(cst)*subst(int(exp(rex2*x^2)*coeff(x),x),x,x+decal) + vecteur les_var(1,gen_x); // insure x is the main var + lvar(makevecteur(coeff,rex2),les_var); + int les_vars=int(les_var.size()); + gen in_coeff,in_coeffnum,in_coeffden,ina; + in_coeff=e2r(coeff,les_var,contextptr); + ina=e2r(rex2,vecteur(les_var.begin()+1,les_var.end()),contextptr); + fxnd(in_coeff,in_coeffnum,in_coeffden); + vecteur in_coeffnumv; + if (in_coeffnum.type==_POLY) + in_coeffnumv=polynome2poly1(*in_coeffnum._POLYptr,1); + else + in_coeffnumv.push_back(in_coeffnum); + // now find int(exp(ina*x^2)*P(x)), coeffs of P are in in_coeffnumv + int vs=int(in_coeffnumv.size())-1; + vecteur vres(vs+1); + // integration by part to decrease vs + for (int i=vs;i>=1;--i){ + // i is the degree of the term to integrate + gen tmp=in_coeffnumv[vs-i]/ina/2; + vres[vs-(i-1)]=tmp; + if (i>1) + in_coeffnumv[vs-(i-2)] -= (i-1)*tmp; + } + gen vresden; + lcmdeno(vres,vresden,contextptr); // lcmdeno_converted? + gen ppart=subst(r2e(poly12polynome(vres,1,les_vars),les_var,contextptr),gen_x,gen_x+decal,false,contextptr)/r2e(vresden,vecteur(les_var.begin()+1,les_var.end()),contextptr)*exp(reaxb,contextptr); + // add erf part from the last coeff vres[vs] + gen a=-rex2; // r2e(-ina,les_var,contextptr); + gen sqrta=sqrt_noabs(a,contextptr); + gen erfpart=r2e(in_coeffnumv[vs],cdr_VECT(les_var),contextptr)*symbolic(at_sqrt,cst_pi)/sqrta*exp(cst,contextptr)/2*_erf(sqrta*(gen_x+decal),contextptr); + res += (ppart + erfpart)/r2e(in_coeffden,les_var,contextptr); + continue; + } + remains_to_integrate = remains_to_integrate + coeff*exp(reaxb,contextptr); + continue; + } + gen reai=im(rea,contextptr),rebi=im(reb,contextptr); + if (!is_zero(reai) || !is_zero(rebi)){ + gen reaxbi=reai*gen_x+rebi; + coeff=coeff*(cos(reaxbi,contextptr)+cst_i*sin(reaxbi,contextptr)); + rea=re(rea,contextptr); + reb=re(reb,contextptr); + reaxb=rea*gen_x+reb; + } + tlin(coeff,vtrig,contextptr); // vtrig = coeff , sin/cos(arg)/1 + if ( (intmode &2)==0 ){ + gen tmp=tunlin(vtrig,contextptr); + if (vtrig.size()>2 || !is_zero(ratnormal(tmp-coeff,contextptr))) + gprintf(step_triglinearizable,gettext("Integrate trigonometric linearizable expression %gen -> %gen"),makevecteur(coeff,tmp),contextptr); + } + const_iterateur jt=vtrig.begin(),jtend=vtrig.end(); + for (;jt!=jtend;){ + // now check that each arg is linear and coeff polynomial + coeff=*jt; + ++jt; + gen ima,imb,imaxb=*jt; + ++jt; + if (is_constant_wrt(imaxb,gen_x,contextptr)){ + coeff = coeff*imaxb; + imaxb=1; + } + int trig_type=0; // 0 for 1, 1 for sin, 2 for cos + if (imaxb.type==_SYMB){ + if (imaxb._SYMBptr->sommet==at_sin) + trig_type=1; + if (imaxb._SYMBptr->sommet==at_cos) + trig_type=2; + } + else + imaxb=0; + // check polynomial + const vecteur vx2=lvarxpow(coeff,gen_x); + bool coeffnotpoly=(vx2.size()>1) || ( (!vx2.empty()) && (vx2.front()!=gen_x)); + if (coeffnotpoly && imaxb==0 && rea!=0){ // detect ugamma + gen chkugamma; + if (vx2.size()==2 && vx2.front()==gen_x) + chkugamma=vx2.back(); + else if (vx2.size()==1) + chkugamma=vx2.front(); + if (chkugamma.is_symb_of_sommet(at_pow)){ + gen chkf=chkugamma._SYMBptr->feuille,chka,chkb; + if (chkf.type==_VECT && chkf._VECTptr->size()==2 && chkf._VECTptr->back().type!=_INT_ && is_constant_wrt(chkf._VECTptr->back(),gen_x,contextptr) && is_linear_wrt(chkf._VECTptr->front(),gen_x,chka,chkb,contextptr) && is_zero(chkb)){ + gen chkn=chkf._VECTptr->back(); + // chkugamm=(chka*gen_x)^chkn + vecteur chkv(makevecteur(chkugamma,gen_x)); + lvar(coeff,chkv); + gen num=sym2r(coeff,chkv,contextptr),deno=1; + // should allow a negative power of gen_x with a shift + if (num.type==_FRAC){ + deno=r2sym(num._FRACptr->den,chkv,contextptr); + num=num._FRACptr->num; + } + if (is_constant_wrt(deno,gen_x,contextptr) && num.type==_POLY){ + gen tmpres,b=-rea; + // expand polynomial with respect to first 2 variables + // for each monomial, exp(reb)*chka^(monomial_index[0]*chkn)*monomial_coeff*gen_x^n*exp(rea*gen_x) where n=chkn*monomial_index[0]+monomial_index[1] + // b=-rea + // -> exp(reb)*chka^n*monomial_coeff*igamma(n+1,b*gen_x)/b^(n+1) + vector< monomial >::const_iterator it=num._POLYptr->coord.begin(),itend=num._POLYptr->coord.end(); + for (;it!=itend;++it){ + polynome tmp(num._POLYptr->dim); + index_t index(it->index.iref()); + int i0(index[0]),i1(index[1]); + gen n=i0*chkn+i1; + index[0]=index[1]=0; + tmp.coord.push_back(monomial(it->value,index)); + gen tmpadd = r2sym(tmp,chkv,contextptr)*pow(chka,i0*chkn,contextptr)/pow(b,n+1,contextptr)*_lower_incomplete_gamma(makesequence(n+1,b*gen_x),contextptr); + tmpres += tmpadd; + } + res += exp(reb,contextptr)*tmpres; + continue; + } + } + } + } + gen imc; + bool quad=imaxb.type==_SYMB && is_quadratic_wrt(imaxb._SYMBptr->feuille,gen_x,ima,imb,imc,contextptr); + if (!coeffnotpoly && quad && !is_zero(ima) && angle_radian(contextptr)){ + imc=_trig2exp(coeff*exp(reaxb,contextptr)*imaxb,contextptr); + res += integrate_linearizable(imc,gen_x,remains_to_integrate,intmode,true,contextptr); + continue; + } + if ( coeffnotpoly || ( imaxb.type==_SYMB && !is_linear_wrt(imaxb._SYMBptr->feuille,gen_x,ima,imb,contextptr)) ) { + if (trig_type) imaxb=imaxb._SYMBptr->feuille; + gen tmp(plus_one); + if (trig_type==1) + tmp=sin(imaxb,contextptr); + if (trig_type==2) + tmp=cos(imaxb,contextptr); + remains_to_integrate = remains_to_integrate + coeff * exp(reaxb,contextptr) * tmp; + continue; + } + // everything OK coeff*exp(rea*x+reb)* 1/cos/sin(ima*x+imb) + if (trig_type) + imaxb=imaxb._SYMBptr->feuille; + else { + if (is_zero(rea)){ + gen tmprem,xvar(gen_x); + res= res + exp(reb,contextptr)*integrate_rational(coeff,gen_x,tmprem,xvar,intmode,contextptr); + remains_to_integrate = remains_to_integrate+exp(reb,contextptr)*tmprem; + continue; + } + } + bool coeff_is_real=false; + if (trig_type){ + gen imcoeff=im(coeff,contextptr); + rewrite_with_t_real(imcoeff,gen_x,contextptr); + if (is_zero(imcoeff) && is_zero(im(rea,contextptr)) && is_zero(im(ima,contextptr))) + coeff_is_real=true; + } + // find vars of coeff,rea,reb,ima,imb + vecteur les_var(1,gen_x); // insure x is the main var + lvar(makevecteur(coeff,rea,ima),les_var); + int les_vars=int(les_var.size()); + gen in_coeff,in_coeffnum,in_coeffden,in_rea,in_ima,in_anum,in_aden; + in_coeff=e2r(coeff,les_var,contextptr); + fxnd(in_coeff,in_coeffnum,in_coeffden); + vecteur in_coeffnumv; + if (in_coeffnum.type==_POLY) + in_coeffnumv=polynome2poly1(*in_coeffnum._POLYptr,1); + else + in_coeffnumv.push_back(in_coeffnum); + in_coeffden=firstcoefftrunc(in_coeffden); + in_rea=firstcoefftrunc(e2r(rea,les_var,contextptr)); + in_ima=firstcoefftrunc(e2r(ima,les_var,contextptr)); + vecteur resnum; + gen resden,resplus; + fxnd(in_rea+cst_i*in_ima,in_anum,in_aden); + solve_aPprime_plus_P(in_anum,in_aden,in_coeffnumv,resnum,resden); + resplus=rdiv(r2e(poly12polynome(resnum,1,les_vars),les_var,contextptr),r2e(poly12polynome(vecteur(1,resden*in_coeffden),1,les_vars),les_var,contextptr),contextptr); + if (step_infolevel(contextptr)){ + gprintf(step_polyexp,gettext("Primitive of %gen is polynomial of same degree*same exponential %gen"),makevecteur(coeff*symb_exp(reaxb+cst_i*imaxb),resplus*symb_exp(reaxb+cst_i*imaxb)),contextptr); + } + if (!trig_type){ + res = res + resplus*exp(reaxb,contextptr); + continue; + } + if (coeff_is_real){ + gen resre=re(resplus,contextptr); + rewrite_with_t_real(resre,gen_x,contextptr); + gen resim=im(resplus,contextptr); + rewrite_with_t_real(resim,gen_x,contextptr); + if (trig_type==1) + res = res + exp(reaxb,contextptr)*(resim*cos(imaxb,contextptr)+resre*sin(imaxb,contextptr)); + else + res = res + exp(reaxb,contextptr)*(resre*cos(imaxb,contextptr)-resim*sin(imaxb,contextptr)); + continue; + } + fxnd(in_rea-cst_i*in_ima,in_anum,in_aden); + solve_aPprime_plus_P(in_anum,in_aden,in_coeffnumv,resnum,resden); + gen resmoins=rdiv(r2e(poly12polynome(resnum,1,les_vars),les_var,contextptr),r2e(poly12polynome(vecteur(1,resden*in_coeffden),1,les_vars),les_var,contextptr),contextptr); + if (trig_type==1) + res = res + exp(reaxb,contextptr)*rdiv(resplus*exp(cst_i*imaxb,contextptr)-resmoins*exp(-cst_i*imaxb,contextptr),plus_two*cst_i,contextptr); + else + res = res + exp(reaxb,contextptr)*rdiv(resplus*exp(cst_i*imaxb,contextptr)+resmoins*exp(-cst_i*imaxb,contextptr),plus_two,contextptr); + } // end for (jt) + } // end for (it) + if (do_risch){ + gen tmp=remains_to_integrate; + remains_to_integrate=0; + res=res+risch(tmp,id_x,remains_to_integrate,contextptr); + } + if (is_undef(res)){ + remains_to_integrate=e; + return 0; + } + if (is_zero(im(e,contextptr)) &&has_i(res) && lop(res,at_erf).empty()){ + remains_to_integrate=re(remains_to_integrate,contextptr); + res=ratnormal(re(res,contextptr),contextptr); + } + return res; + } // end linearizable + + gen linear_integrate_nostep(const gen & e,const gen & x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT); + + bool is_a_monomial(const gen & g,int & expo){ + expo=0; + if (g.type!=_POLY) return true; + const polynome & p=*g._POLYptr; + expo=p.lexsorted_degree(); + vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); + for (;it!=itend;++it){ + if (it->index.front()!=expo) + return false; + } + return true; + } + + // return 1 if power is a fraction of int, 2 if a sqrt or more general exponent where x->1/x change of var can be tested + static int integrate_sqrt(gen & e,const gen & gen_x,const vecteur & rvar,gen & res,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ // x and a power + // subcase 1: power is a fraction of int + // find rational parametrization if possible + // subcase 2: 1st argument of power is linear, 2nd is constant && no inv + gen argument=rvar.back()._SYMBptr->feuille._VECTptr->front(); + gen exposant=rvar.back()._SYMBptr->feuille._VECTptr->back(); + if (exposant.is_symb_of_sommet(at_inv) && exposant._SYMBptr->feuille.type==_INT_) + exposant=fraction(1,exposant._SYMBptr->feuille); + if ( (exposant.type==_FRAC) && (exposant._FRACptr->num.type==_INT_) && (exposant._FRACptr->den.type==_INT_) ){ + int d=exposant._FRACptr->den.val,exponum=exposant._FRACptr->num.val; + gen a,b,c,tmprem,tmpres,tmpe; + if (is_linear_wrt(argument,gen_x,a,b,contextptr)){ + // argument=(ax+b)=t^d -> x=(t^d-a)/b and dx=d/a*t^(d-1)*dt + vecteur substin(makevecteur(argument,gen_x)); + vecteur substout(makevecteur(pow(gen_x,d),rdiv(pow(gen_x,d)-b,a,contextptr))); + tmpe=complex_subst(e,substin,substout,contextptr)*pow(gen_x,d-1); + tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); + gen fnc_inverse=pow(a*gen_x+b,fraction(1,d),contextptr); + remains_to_integrate=rdiv(d,a,contextptr)*complex_subst(tmprem,gen_x,fnc_inverse,contextptr); + res=rdiv(d,a,contextptr)*complex_subst(tmpres,gen_x,fnc_inverse,contextptr); + return 2; + } + vecteur tmpv(1,gen_x); + lvar(argument,tmpv); + gen fr,fr_n,fr_np,fr_d,fr_dp,ap,bp; + fr=e2r(argument,tmpv,contextptr); + fxnd(fr,fr_np,fr_dp); + int fr_nexpo,fr_dexpo; + if (is_a_monomial(fr_np,fr_nexpo) && is_a_monomial(fr_dp,fr_dexpo)){ + gen pui=fraction((fr_nexpo-fr_dexpo)*exponum,d); + res=e*gen_x/(pui+1); + return 2; + } + fr_n=r2e(fr_np,tmpv,contextptr); + fr_d=r2e(fr_dp,tmpv,contextptr); + if (is_linear_wrt(fr_n,gen_x,a,b,contextptr) && is_linear_wrt(fr_d,gen_x,ap,bp,contextptr) ){ + // argument=(a*x+b)/(ap*x+bp)=t^d + // -> x=(bp*t^d-b)/(a-ap*t^d) + // -> dx= d*(b*ap-a*bp)*t^(d-1)/(a-ap*t^d)^2 + vecteur substin(makevecteur(argument,gen_x)); + vecteur substout(makevecteur(pow(gen_x,d),rdiv(bp*pow(gen_x,d)-b,a-ap*pow(gen_x,d),contextptr))); + tmpe=complex_subst(e,substin,substout,contextptr)*rdiv(pow(gen_x,d-1),pow(a-ap*pow(gen_x,d),2),contextptr); + tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); + gen fnc_inverse=pow(rdiv(a*gen_x+b,ap*gen_x+bp,contextptr),fraction(1,d),contextptr); + gen tmp=gen(d)*(a*bp-b*ap); + remains_to_integrate=tmp*complex_subst(tmprem,gen_x,fnc_inverse,contextptr); + res=tmp*complex_subst(tmpres,gen_x,fnc_inverse,contextptr); + return 2; + } + bool frdconst=is_constant_wrt(fr_d,gen_x,contextptr); + if (frdconst){ + // multiply denominator by conjugate + identificateur tmpx(" x"); + gen e1=complex_subst(e,rvar.back(),tmpx,contextptr); // sqrt(argument,contextptr) + vecteur lv(1,tmpx); + lvar(e1,lv); + gen e2=e2r(e1,lv,contextptr),num,den; + fxnd(e2,num,den); + den=r2e(den,lv,contextptr); + num=r2e(num,lv,contextptr); + // multiply denominator of e2 by conjugate + gen pmini=pow(tmpx,d)-argument; + gen C=_egcd(makesequence(den,pmini,tmpx),contextptr); + if (is_undef(C)){ + res=C; + return 2; + } + num=_rem(makesequence(num*C[0],pmini,tmpx),contextptr); + if (is_undef(num)){ + res= num; + return 2; + } + den=C[2]; + // int(num/den), den does not depend on y=tmpx, the fractional power + // if num does not, then we can integrate + if (is_constant_wrt(num,tmpx,contextptr)){ + res=linear_integrate_nostep(num/den,gen_x,remains_to_integrate,intmode,contextptr); + return 1; + } + /* Possible improvement: remove multiplicities in denominator + for each monomial of num n*tmpx^deg, set gamma=deg/d + then make a partial fraction decomposition of n/den -> + int(n*y^gamma/D^(k+1)) for D squarefree and coprime with y + Bezout find U and V such that n=D*U+D'*y*V + let N=-V/k and r=U-(y*N'+(gamma+1)*N*y'), then + int(n*y^gamma/D^(k+1))=N*y^(gamma+1)/D^k+int(r*y^gamma/D^k) + */ + if (d==2){ + // write e as alpha+beta*sqrt(argument) + /* ( * 2nd order: dispatch for y=ax^2+bx+c * ) + ( * a>0 -> x=[m^2-c]/[b-2*sqrt[a]*m] * ) + ( * m=sqrt[y]-sqrt[a]*x * ) + ( * dx/sqrt[y]=2*dm/[b-2*sqrt[a]*m] * ) + */ + gen alpha,beta,xvar(gen_x); + if (!is_linear_wrt(num,tmpx,beta,alpha,contextptr)){ + res=gensizeerr(contextptr); + return 2; + } + alpha=integrate_rational(alpha/den,gen_x,remains_to_integrate,xvar,intmode,contextptr); + if (is_undef(alpha)){ + res=alpha; + return 2; + } + /* Instead we should factor argument in den + FIXME in usual.cc diff of ln should expand * and / and rm abs + write y=argument, P=beta + we want to integrate P*sqrt(y)/den=(P*y)/den* y^(-1/2) + *IF* den=y^l*D where D is prime with y (not always true...) + P/Dy^l = P_y/y^l + P_D/D <--> P = P_y*D + P_D*y^l, + find P_D and P_y by Bezout, find + g = Q*D+R*y^l then Pg = P*Q*D + P*R*y^l hence + P_D = P*R mod D/g and P_y = P*Q /g + [P*R div D] *y^l /g + */ + gen y=argument,P=beta,D=den; // P*y/den + C=_quorem(makesequence(D,y,gen_x),contextptr); + if (is_undef(C)){ + res= C; + return 2; + } + int l=0; + if (is_zero(C[1])){ // P/(den/y) + D=C[0]; + for (;;++l){ + C=_quorem(makesequence(D,y,gen_x),contextptr); + if (is_undef(C)){ + res=C; + return 2; + } + if (!is_zero(C[1])) + break; + D=C[0]; + } + } + else + P=P*y; + gen yl=pow(y,l); + C=_egcd(makesequence(D,yl,gen_x),contextptr); + if (is_undef(C)){ + res= C; + return 2; + } + gen g=C[2],Q=C[0],R=C[1]; + C=_quorem(makesequence(P*R,D,gen_x),contextptr); + if (is_undef(C)){ + res=C; + return 2; + } + gen PD=C[1]/g; + // changed made for int(1/(sin(x)*sqrt(sin(2*x)^3))); + C=_quorem(makesequence(P*Q+C[0]*yl,g,gen_x),contextptr); + if (!is_zero(C[1])) + return 0; + gen Py=C[0]; + // gen Py=(P*Q+C[0]*yl)/g; + C=_quorem(makesequence(Py,y,gen_x),contextptr); + if (is_undef(C)){ + res= C; + return 2; + } + /* + int[ Py/y^l*y^-1/2 ] = Q*y^[1/2-l] + int[ C*y^-1/2 ] + degre[Py]=n, degre[y]=k, find Q degre[Q]=n+1-k and C degre[C]=k-2 + so that Py = Q'*y + Q*y'*[1/2-l] + C y^l + to do this we represent Q by a n+2-k-vector, C by a k-1-vector + gluing Q and C we get a n+1-vector that must be solution of a + n+1*n+1 linear system. Now we build the matrix of this system + The n+2-k first columns are + y'[1/2-l] ... x^alpha*y'*[1/2-l]+alpha*x^[alpha-1]*y ... + The k-1 last columns are + y^l ... x^beta*y^l + Note 1: to avoid rational input in the matrix we multiply by 2 + coef of Q and C are found in the reverse order + for l!=0 n is more precisely max[deg[Py],k[l+1]-2] + Note 2: at the end we integrate only (C+PD/D)*y^(-1/2) + */ + gen tmpv=_e2r(makesequence(Py,gen_x),contextptr); + if (tmpv.type!=_VECT){ + if (tmpv.type==_FRAC){ + if (tmpv._FRACptr->den.type==_VECT){ + if (tmpv._FRACptr->den._VECTptr->size()!=1){ + *logptr(contextptr) << "Internal error integrating sqrt" << '\n'; + return 0; + } + tmpv._FRACptr->den=tmpv._FRACptr->den._VECTptr->front(); + } + if (tmpv._FRACptr->num.type==_VECT) + tmpv=multvecteur(inv(tmpv._FRACptr->den,contextptr),*tmpv._FRACptr->num._VECTptr); + } + if (tmpv.type!=_VECT) + tmpv=vecteur(1,tmpv); // change 3/1/2013 for int(sqrt(1+x^2)/(-2*x^2)) + // res= gensizeerr(contextptr); + // return 2; + } + vecteur colP=*tmpv._VECTptr; + int n=int(colP.size())-1; + tmpv=_e2r(makesequence(y,gen_x),contextptr); + if (tmpv.type!=_VECT){ + res= gensizeerr(contextptr); + return 2; + } + int k=int(tmpv._VECTptr->size())-1; + n=giacmax(n,k*(l+1)-2); + n=giacmax(n,k-1); + if (n){ + lrdm(colP,n); + gen yprime=(1-2*l)*derive(y,gen_x,contextptr); + if (is_undef(yprime)){ + res= yprime; + return 2; + } + matrice sys; + tmpv=_e2r(makesequence(yprime,gen_x),contextptr); + if (tmpv.type!=_VECT){ + res=gensizeerr(contextptr); + return 2; + } + vecteur col0(*tmpv._VECTptr); + vecteur col(col0); + lrdm(col,n); + sys.push_back(col); + col0.push_back(zero); + tmpv=_e2r(makesequence(2*y,gen_x),contextptr); + if (tmpv.type!=_VECT){ + res=gensizeerr(contextptr); + return 2; + } + vecteur col1(*tmpv._VECTptr); + for (int i=1;i0 -> x=[D*2u/[1+u^2]-b]/2a * ) + ( * u=[D-2*sqrt[-a]*sqrt[y]]/[2ax+b] * ) + ( * dx/sqrt[y]=-2*du/[sqrt[-a]*[1+u^2]] * ) + */ + gen sqrta(sqrt(-a,contextptr)); + identificateur id_u(" u"); + gen u(id_u),uu(u); + gen uasx=rdiv(D-plus_two*sqrta*sqrt(argument,contextptr),plus_two*a*gen_x+b,contextptr); + tmpe=ratnormal(e*sqrt(argument,contextptr),contextptr); + tmpe=complex_subst(tmpe,gen_x,rdiv(rdiv(plus_two*u*D,1+u*u,contextptr)-b,plus_two*a,contextptr),contextptr); + tmpe=-rdiv(plus_two,sqrta,contextptr)*tmpe/(1+u*u); + tmpres=integrate_rational(tmpe,u,tmprem,uu,intmode,contextptr); + // sqrt(a*x^2+b*x+c) -> a*[(x+b/2/a)^2-(D/a)^2] + // -> asin(a*x+b/2) + vecteur vin(makevecteur(u,symbolic(at_atan,u))),vout(makevecteur(uasx,inv(-2,contextptr)*sD*asin(ratnormal((-2*a*gen_x-b)/D,contextptr),contextptr))); + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,vin,vout,contextptr); + res=alpha+complex_subst(tmpres,vin,vout,contextptr); + return 2; + } + } // end sqrt of quadratic + else { + remains_to_integrate=e; + res=alpha; + return 2; + } + } // end if d==2 + } // end if denominator of argument of frac power is constant + int numdeg=0,numval=0,dendeg=0; + if (fr_dp.type==_POLY) dendeg=fr_dp._POLYptr->lexsorted_degree(); + if (dendeg>0 || fr_np.type!=_POLY) return 1; + numdeg=fr_np._POLYptr->lexsorted_degree(); + numval=fr_np._POLYptr->valuation(0); + return numval>0?2:1; + } // end exposant=fraction of integers + return 0; + } // end recusive var size==2 i.e. of integrate_sqrt + + static gen integrate_piecewise(gen& e,const gen & piece,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT,int intmode){ + gen & piecef=piece._SYMBptr->feuille; + if (piecef.type!=_VECT){ + e=subst(e,piece,piecef,false,contextptr); + return integrate_id_rem(e,gen_x,remains_to_integrate,contextptr,intmode); + } + vecteur piecev=*piecef._VECTptr,remainsv(piecev); + int nargs=int(piecev.size()); + bool addremains=false; + for (int i=0;i_SYMBptr->feuille,gen_x,a,b,contextptr); + coeff_cst=ratnormal(rdiv(a,coeff_trig,contextptr),contextptr)*b; + // express all angles in vart as n*(coeff_trig*x+coeff_cst)+angle=a*x+b, + // t=coeff_trig*x+coeff_cst + for (;vart!=vartend;++vart){ + is_linear_wrt(vart->_SYMBptr->feuille,gen_x,a,b,contextptr); + gen n=ratnormal(rdiv(a,coeff_trig,contextptr),contextptr); + if (n.type!=_INT_) return gensizeerr(gettext("trig_fraction")); + gen angle=ratnormal(b-n*coeff_cst,contextptr); + substout.push_back(symbolic(vart->_SYMBptr->sommet,n*gen_x+angle)); + } + gen f=complex_subst(e,var,substout,contextptr); // should be divided by coeff_trig + f=_texpand(f,contextptr); + gen tmprem,tmpres; + if (trig_fraction==4){ // everything depends on exp(x) + f=complex_subst(f,exp(gen_x,contextptr),gen_x,contextptr)*inv(gen_x,contextptr); + if ( (intmode &2)==0) + gprintf(step_ratfracexp,gettext("Integrate rational fraction of exponential %gen by %gen change of variable, leading to integral of %gen"),makevecteur(e,exp(gen_x,contextptr),f),contextptr); + tmpres=linear_integrate_nostep(f,gen_x,tmprem,intmode,contextptr); + gen expx=exp(coeff_trig*gen_x+coeff_cst,contextptr); + if ( (intmode & 2)==0) + gprintf(step_backsubst,gettext("Back substitution %gen->%gen in %gen"),makevecteur(gen_x,expx,tmprem),contextptr); + remains_to_integrate = expx*complex_subst(tmprem,gen_x,expx,contextptr); + return inv(coeff_trig,contextptr)*complex_subst(tmpres,gen_x,expx,contextptr); + } + f=halftan(f,contextptr); // now everything depends on tan(x/2) + // t=tan(x/2), dt=1/2(1+t^2)*dx + gen xsur2=rdiv(coeff_trig*gen_x+coeff_cst,plus_two,contextptr); + gen tanxsur2=tan(xsur2,contextptr); + f=complex_subst(f,tan(rdiv(gen_x,plus_two,contextptr),contextptr),gen_x,contextptr)*inv(plus_one+pow(gen_x,2),contextptr); + if ( (intmode &2)==0) + gprintf(step_ratfractrig,gettext("Integrate rational fraction of trigonometric %gen by %gen change of variable, leading to integral of %gen"),makevecteur(e,tanxsur2,f),contextptr); + vecteur vf(1,gen_x); + rlvarx(f,gen_x,vf); + if (vf.size()<=1) + tmpres=integrate_rational(f,gen_x,tmprem,tanxsur2,intmode,contextptr); + else { + tmpres=linear_integrate_nostep(f,gen_x,tmprem,intmode,contextptr); + if ( (intmode & 2)==0) + gprintf(step_backsubst,gettext("Back substitution %gen->%gen in %gen"),makevecteur(gen_x,tanxsur2,tmpres),contextptr); + tmpres=complex_subst(tmpres,gen_x,tanxsur2,contextptr); + // tmprem=complex_subst(tmprem,gen_x,tanxsur2,contextptr); + } + if (tmpres==0) + remains_to_integrate = e; + else + remains_to_integrate = rdiv(plus_two,coeff_trig,contextptr)*tmprem*(1+pow(tanxsur2,2)); + return rdiv(plus_two,coeff_trig,contextptr)*tmpres; + } + + // reduce g, a rational fraction wrt to x, to a sqff lnpart + // and adds the non sqff integrated part to ratpart + bool intgab_ratfrac(const gen & e,const gen & x,gen & value,GIAC_CONTEXT){ + vecteur l; + l.push_back(x); // insure x is the main var + l=vecteur(1,l); + alg_lvar(e,l); + int s=int(l.front()._VECTptr->size()); + if (!s){ + l.erase(l.begin()); + s=int(l.front()._VECTptr->size()); + } + if (!s) + return false; + gen r=e2r(e,l,contextptr); + gen r_num,r_den; + fxnd(r,r_num,r_den); + if (r_num.type==_EXT) + return false; + polynome num(s); + if (r_num.type==_POLY) + num=*r_num._POLYptr; + else + num=polynome(r_num,s); + if (r_den.type!=_POLY){ // not convergent + if (num.lexsorted_degree()%2) + value=undef; + else + value=subst(r2e(r_num,l,contextptr),x,1,false,contextptr)/r2e(r_den,l,contextptr)*plus_inf; + return true; + } + polynome den(*r_den._POLYptr); + if (num.lexsorted_degree()>den.lexsorted_degree()-2){ // not convergent + if ( (num.lexsorted_degree()-den.lexsorted_degree())%2 ) + value=undef; + else + value=subst(r2e(r_num,l,contextptr)/r2e(r_den,l,contextptr),x,1,false,contextptr)*plus_inf; + return true; + } + l.front()._VECTptr->front()=x; + vecteur lprime(l); + if (lprime.front().type!=_VECT){ + value=gensizeerr(gettext("in intgab_rational")); + return false; + } + lprime.front()=cdr_VECT(*(lprime.front()._VECTptr)); + // quick check for length 2 deno + vecteur vtmp; + polynome2poly1(den,1,vtmp); + if (integrate_deno_length_2(num,vtmp,l,lprime,value,true,2/* no step info*/,contextptr)){ + value=ratnormal(value,contextptr)*cst_pi; + return true; + } + polynome p_content(lgcd(den)); + factorization vden(sqff(den/p_content)); // first square-free factorization + vector< pf > pfde_VECT; + polynome ipnum(s),ipden(s),temp(s),tmp(s); + partfrac(num,den,vden,pfde_VECT,ipnum,ipden); + vector< pf >::iterator it=pfde_VECT.begin(); + vector< pf >::const_iterator itend=pfde_VECT.end(); + vector< pf > intdecomp,finaldecomp; + for (;it!=itend;++it){ + pf single(intreduce_pf(*it,intdecomp,true)); + // Now final factorization for single.den, + // then compute single.num/single.den'(root) for roots with im>0 + // this is the residue + // Example 1/(x^4+1) roots in C^+: exp(i*pi/4), exp(3*i*pi/4), + // num/den'=1/4/x^3=-x/4 -> -1/4*exp(i*pi/4)-1/4*exp(3*i*pi/4) + // -> -1/2*sin(pi/4)*i [*2*i*pi -> sqrt(2)/2*pi] + vden.clear(); + gen extra_div=1; + factor(single.den,p_content,vden,false,false,false,1,extra_div); + partfrac(single.num,single.den,vden,finaldecomp,temp,tmp); + } + it=finaldecomp.begin(); + itend=finaldecomp.end(); + gen lnpart(0),deuxaxplusb,sqrtdelta; + polynome a(s),b(s),c(s); + polynome d(s),E(s),lnpartden(s); + polynome delta(s),atannum(s),alpha(s); + for (;it!=itend;++it){ + int deg=it->fact.lexsorted_degree(); + // polynome & itnum=it->num; + // polynome & itden=it->den; + gen Delta; + switch (deg) { + case 1: // 1st order + value=undef; + return true; + case 2: // 2nd order + findabcdelta(it->fact,a,b,c,delta); + Delta=r2e(delta,lprime,contextptr); + if (is_positive(Delta,contextptr)){ + value=undef; + return true; + } + alpha=(it->den/it->fact).trunc1()*a*gen(2); + findde(it->num,d,E); + atannum=a*E*gen(2)-b*d; + atannum=atannum*gen(2); + simplify(atannum,alpha); + sqrtdelta=normalize_sqrt(sqrt(-Delta,contextptr),contextptr); + value += rdiv(r2e(atannum,lprime,contextptr),(r2e(alpha,lprime,contextptr))*sqrtdelta,contextptr); + break; + default: // divide a*it->num =b*it->den.derivative()+c + it->num.TPseudoDivRem(it->den.derivative(),b,c,a); + // remaining pf + if (!c.coord.empty()){ + vtmp=polynome2poly1(a*it->den,1); + if (!integrate_deno_length_2(c,vtmp,l,lprime,value,true,2/* no step info*/,contextptr)) + return false; + } + break ; + } + } + value=ratnormal(value,contextptr)*cst_pi; + return true; + } + + static gen integrate_rational_end(vector< pf >::iterator & it,vector< pf >::const_iterator & itend,const gen & x,const gen & xvar,const vecteur & l,const vecteur & lprime,const polynome & ipnum,const polynome & ipden,const gen & ratpart,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ + gen lnpart(0),deuxaxplusb,sqrtdelta; + int s=ipnum.dim; + polynome a(s),b(s),c(s); + polynome d(s),E(s),lnpartden(s); + polynome delta(s),atannum(s),alpha(s); + bool uselog; + remains_to_integrate=0; + for (;it!=itend;++it){ + int deg=it->fact.lexsorted_degree(); + // polynome & itnum=it->num; + // polynome & itden=it->den; + gen Delta; + switch (deg) { + case 1: // 1st order + lnpart=lnpart+rdiv(r2e(it->num,l,contextptr),r2e(firstcoeff(it->den),l,contextptr),contextptr)*lnabs2(r2e(it->fact,l,contextptr),xvar,contextptr); + break; + case 2: // 2nd order + findabcdelta(it->fact,a,b,c,delta); + Delta=r2e(delta,lprime,contextptr); + uselog=is_positive(Delta,contextptr); + alpha=(it->den/it->fact).trunc1()*a*gen(2); + findde(it->num,d,E); + atannum=a*E*gen(2)-b*d; + // ln part d/alpha*ln(fact) + lnpartden=alpha; + simplify(d,lnpartden); + lnpart=lnpart+rdiv(r2e(d,lprime,contextptr),r2e(lnpartden,lprime,contextptr),contextptr)*gen(uselog?lnabs2(r2e(it->fact,l,contextptr),xvar,contextptr):symbolic(at_ln,r2e(it->fact,l,contextptr))); + // atan or _FUNCnd ln part + deuxaxplusb=r2e(it->fact.derivative(),l,contextptr); + if (uselog){ + sqrtdelta=normalize_sqrt(sqrt(Delta,contextptr),contextptr); + simplify(atannum,alpha); + lnpart=lnpart+rdiv(r2e(atannum,lprime,contextptr),(r2e(alpha,lprime,contextptr))*sqrtdelta,contextptr)*lnabs2(rdiv(deuxaxplusb-sqrtdelta,deuxaxplusb+sqrtdelta,contextptr),xvar,contextptr); + } + else { + vecteur v=solve(x*x+Delta,x,0,contextptr); + if (v.size()==2 && !is_undef(v[0]) && !is_undef(v[1])){ + if (is_positive(-v[0],contextptr)) + sqrtdelta=v[1]; + else + sqrtdelta=v[0]; + } + else + sqrtdelta=normalize_sqrt(sqrt(-Delta,contextptr),contextptr); + atannum=atannum*gen(2); + simplify(atannum,alpha); + gen tmpatan=ratnormal(rdiv(deuxaxplusb,sqrtdelta,contextptr),contextptr); + gen residue; + if (tmpatan.is_symb_of_sommet(at_tan)) + tmpatan=tmpatan._SYMBptr->feuille; + else { + // avoid floor if possible + // atan(beta*tan(theta)+gamma)+floor() for beta>0 and gamma>-1 + // -> atan( cos(theta)*((beta-1)*sin(theta)+gamma*cos(theta))/ + // (cos(theta)^2+beta*sin(theta)^2+gamma*sin(theta)*cos()) ) + gen beta,gamma; + if ( //0 && + xvar.is_symb_of_sommet(at_tan) && is_linear_wrt(tmpatan,xvar,beta,gamma,contextptr) && is_strictly_greater(4*beta,gamma*gamma,contextptr) ){ + gen argtan=ratnormal(2*xvar._SYMBptr->feuille,contextptr); + gen si=symbolic(at_sin,argtan),ci=symbolic(at_cos,argtan); + tmpatan=symbolic(at_atan,ratnormal(((beta-1)*si+gamma*(1+ci))/(1+beta+gamma*si+(1-beta)*ci),contextptr)); + residue=xvar._SYMBptr->feuille; + } + else { + tmpatan=atan(tmpatan,contextptr); + if (xvar.is_symb_of_sommet(at_tan)){ + if (do_lnabs(contextptr)){ + // add residue + residue=r2e(it->fact.derivative().derivative(),l,contextptr); + residue=cst_pi*sign(residue,contextptr)*_floor((xvar._SYMBptr->feuille/cst_pi+plus_one_half),contextptr); + } + } + else { + // if xvar has a singularity at 0 e.g. xvar =x+1/x or x-1/x, + // add the residue at 0 + if (xvar.type!=_IDNT){ + // replacing tmpatan by atan(inv(tmpatan)) would avoid residue for int((x^2+1)/(x^4+3x^2+1)); but then it would not be continuous at 1 and -1 + residue=ratnormal(limit(tmpatan,*x._IDNTptr,0,-1,contextptr)-limit(tmpatan,*x._IDNTptr,0,1,contextptr),contextptr); + residue=residue*sign(x,contextptr)/2; + } + } + } + } + if (!angle_radian(contextptr)){ + if (angle_degree(contextptr)) + tmpatan=tmpatan*deg2rad_e; + //grad + else + tmpatan = tmpatan*grad2rad_e; + } + tmpatan += residue; + lnpart=lnpart+rdiv(r2e(atannum,lprime,contextptr),(r2e(alpha,lprime,contextptr))*sqrtdelta,contextptr)*tmpatan; + } // end else uselof + break; + default: // divide a*it->num =b*it->den.derivative()+c + it->num.TPseudoDivRem(it->den.derivative(),b,c,a); + // remaining pf + if (!c.coord.empty()){ + vecteur vtmp=polynome2poly1(a*it->den,1); + if (!integrate_deno_length_2(c,vtmp,l,lprime,lnpart,false,intmode,contextptr)) + remains_to_integrate += r2sym(vector< pf >(1,pf(c,a*it->den,it->fact,1)),l,contextptr); + } + // extract log part b/a*ln[fact] + simplify(b,a); + if (!is_zero(b)) + lnpart=lnpart+rdiv(r2e(b,l,contextptr),r2e(a,l,contextptr),contextptr)*lnabs(r2e(it->fact,l,contextptr),contextptr); + break ; + } + } + return rdiv(r2e(ipnum.integrate(),l,contextptr),r2e(ipden,l,contextptr),contextptr)+ratpart+lnpart; + } + + // integration of a rational fraction + static gen integrate_rational(const gen & e, const gen & x, gen & remains_to_integrate,gen & xvar,int intmode,GIAC_CONTEXT){ + if (x.type!=_IDNT) return gensizeerr(contextptr); // see limit + if (has_num_coeff(e)){ + gen ee=exact(e,contextptr); + if (!has_num_coeff(ee)){ + ee=integrate_rational(ee,x,remains_to_integrate,xvar,intmode,contextptr); + ee=evalf(ee,1,contextptr); + remains_to_integrate=evalf(remains_to_integrate,1,contextptr); + return ee; + } + } + const vecteur & varx=lvarx(e,x); + int varxs=int(varx.size()); + if (!varxs){ + remains_to_integrate=zero; + return e*xvar; + } + if ( (varxs>1) || (varx.front()!=x) ) { + remains_to_integrate = e; + return zero; + } + vecteur l; + l.push_back(x); // insure x is the main var + l=vecteur(1,l); + alg_lvar(e,l); + vecteur l_orig=l; + int s=int(l.front()._VECTptr->size()); + if (!s){ + l.erase(l.begin()); + s=int(l.front()._VECTptr->size()); + } + if (!s) + return gensizeerr(contextptr); + vecteur lprime(l); + if (lprime.front().type!=_VECT) return gensizeerr(gettext("in integrate_rational")); + lprime.front()=cdr_VECT(*(lprime.front()._VECTptr)); + gen r=e2r(e,l,contextptr); + // cout << "Int " << r << '\n'; + gen r_num,r_den; + fxnd(r,r_num,r_den); + if (r_num.type==_EXT){ + remains_to_integrate=e; + return zero; + } + if (r_den.type!=_POLY){ + l.front()._VECTptr->front()=xvar; + if (r_num.type==_POLY) + return rdiv(r2e(r_num._POLYptr->integrate(),l,contextptr),r2sym(r_den,l,contextptr),contextptr); + else + return e*xvar; + } + polynome den(*r_den._POLYptr),num(s); + if (r_num.type==_POLY) + num=*r_num._POLYptr; + else + num=polynome(r_num,s); + // cyclotomic-like polys + vecteur vtmp; + if (den.coord.size()==2 && den.lexsorted_degree()!=1 && num.lexsorted_degree() < den.lexsorted_degree() && den.coord.back().index.is_zero() && xvar.type==_IDNT){ + polynome2poly1(den,1,vtmp); + r=0; + if (!integrate_deno_length_2(num,vtmp,l,lprime,r,false,intmode,contextptr)) + remains_to_integrate=e; + return r; + } + // check for a t=x^aa change of variable: a divides deg(num)+1-deg(den) + // as well as all differences of degrees in the poly num and den + int den_deg=den.lexsorted_degree(),num_deg=num.lexsorted_degree(); + int aa=num_deg+1-den_deg,precedent,actuel; + vector< monomial > ::const_iterator num_it=num.coord.begin(),num_itend=num.coord.end(); + if (num_itend-num_it>1){ + precedent=num_it->index.front(); + ++num_it; + for (;num_it!=num_itend;++num_it){ + actuel=num_it->index.front(); + aa=gcd(aa,actuel-precedent); + precedent=actuel; + } + } + num_it=den.coord.begin(),num_itend=den.coord.end(); + if (num_itend-num_it>1){ + precedent=num_it->index.front(); + ++num_it; + for (;num_it!=num_itend;++num_it){ + actuel=num_it->index.front(); + aa=gcd(aa,actuel-precedent); + precedent=actuel; + } + } + if (!aa) + aa=den_deg; + if (aa>1){ // Apply + if ( (intmode & 2)==0) + gprintf(step_ratfracpow,gettext("Integrate rational fraction %gen, change of variable %gen"),makevecteur(e,symb_equal(x,symb_pow(x,aa))),contextptr); + int k=0; + k=den_deg % aa; + // shift num and den by x^k + index_t k1(num.dim); + k1.front()=k+1; + num=(num.shift(k1)).dividedegrees(aa); + index_t ka(num.dim); + ka.front()=k+aa; + den=gen(aa)*(den.shift(ka)).dividedegrees(aa); + if (!(aa%2) && xvar.is_symb_of_sommet(at_tan)){ + // t=tan(x)^2: c=cos(2x)=(1-t^2)/(1+t^2) -> t^2=(1-c)/(1+c) + xvar=symbolic(at_cos,ratnormal(2*xvar._SYMBptr->feuille,contextptr)); + xvar=(1-xvar)/(1+xvar); + aa/=2; + } + xvar=pow(xvar,aa); + return integrate_rational(r2e(fraction(num,den),l,contextptr),x,remains_to_integrate,xvar,intmode,contextptr); + } + int den_val=den.valuation(0),num_val=num.valuation(0); + if (den_deg+den_val==num_deg+num_val+2){ + // now detect pattern that simplifies trig fraction integration + /* cos is already detected by x^aa above with aa=2 + * + * sin: if the fraction, including dt, is invariant by t->v=1/t + * e.g (1-t^2)/(1+t^2)^2 dt = v^2(v^2-1)/(v^2+1)^2*( -1/v^2) dv + * or [equivalent] tF(t) must change sign + * let u=t+1/t, du=(1-1/t^2)dt, F(t)dt= F(t) * t^2/(t^2-1) du + * e.g. t^2/(1+t^2)^2 du + * N/(t^2-1) and D must be symm + * + * tan: if the fraction, including dt, is invariant by t->-1/t + * u=t-1/t, du=(1+1/t^2)dt, F(t)dt= F(t) * t^2/(t^2+1) du + * N/(t^2+1) and D must be antism. + */ + vecteur Nsave,Dsave,N,D,test(makevecteur(1,0,-1)),q,r; + polynome2poly1(num,1,N); + if (num_val && num_val=test.size() && DivRem(N,test,0,q,r) && r.empty()){ + r=D; + if (is_symmetric(q,N,true)*is_symmetric(r,D,true)==1){ + // yes! + type = (xvar.type==_SYMB) || D.size()>1; + } + } + if (!type) { + N=Nsave; D=Dsave; + } + if (!type && D.size()>=test.size() && DivRem(D,test,0,q,r) && r.empty()){ + r=N; + if (is_symmetric(r,N,true)*is_symmetric(q,D,true)==1){ + // yes! + type = (xvar.type==_SYMB) || D.size()>1; + if (type) + D=operator_times(D,makevecteur(1,0,-4),0); + } + } + if (type){ + if (xvar.is_symb_of_sommet(at_tan)){ + q=N; r=D; + xtoinvx(2,q,r,N,D,true); + xvar=symbolic(at_sin,ratnormal(2*xvar._SYMBptr->feuille,contextptr)); + } + else { + xvar=xvar+inv(xvar,contextptr); + } + num=poly12polynome(N,1,num.dim); + den=poly12polynome(D,1,den.dim); + return integrate_rational(r2e(fraction(num,den),l,contextptr),x,remains_to_integrate,xvar,intmode,contextptr); + } + test[2]=1; + N=Nsave; D=Dsave; + if (N.size()>=test.size() && DivRem(N,test,0,q,r) && r.empty()){ + r=D; + if (is_symmetric(q,N,false)*is_symmetric(r,D,false)==1){ + // yes! + type = (xvar.type==_SYMB) || D.size()>1; + } + } + if (!type){ + N=Nsave; D=Dsave; + } + if (!type && D.size()>=test.size() && DivRem(D,test,0,q,r) && r.empty()){ + r=N; + if (is_symmetric(r,N,false)*is_symmetric(q,D,false)==1){ + // yes! + type = (xvar.type==_SYMB && xvar._SYMBptr->sommet!=at_tan) || D.size()>1; + if (type) + D=operator_times(D,makevecteur(1,0,4),0); + } + } + if (type){ + if (xvar.is_symb_of_sommet(at_tan)){ + q=N; r=D; + xtoinvx(-2,q,r,N,D,true); + xvar=symbolic(at_tan,ratnormal(2*xvar._SYMBptr->feuille,contextptr)); + } + else + xvar=xvar-inv(xvar,contextptr); + num=poly12polynome(N,1); + den=poly12polynome(D,1); + for (;den.dim!=num.dim;){ + vector< monomial >::iterator dt,dtend; + if (den.dimindex.begin(),itend=dt->index.end(); + index_m new_i(itend-it+1); + index_t::iterator newit=new_i.begin(); + for (;it!=itend;++newit,++it) + *newit=*it; + *newit=0; + dt->index=new_i; + } + } + simplify(num,den); + return integrate_rational(r2e(fraction(num,den),l,contextptr),x,remains_to_integrate,xvar,intmode,contextptr); + } + } + if ( (intmode & 2)==0) + gprintf(step_ratfracsqrfree,gettext("Integrate rational fraction %gen"),makevecteur(_sqrfree(e,contextptr)),contextptr); + vecteur lf=*l.front()._VECTptr; + lf.front()=xvar; + l.front()=lf; + // l.front()._VECTptr->front()=xvar; + polynome p_content(lgcd(den)); + polynome primden(den/p_content); + factorization vden(sqff(primden)); // first square-free factorization + vector< pf > pfdecomp; + polynome ipnum(s),ipden(s),temp(s),tmp(s); + partfrac(num,den,vden,pfdecomp,ipnum,ipden); + vector< pf >::iterator it=pfdecomp.begin(); + vector< pf >::const_iterator itend=pfdecomp.end(); + vector< pf > intdecomp,finaldecomp; + for (;it!=itend;++it){ + if (it->den.lexsorted_degree()==0) + continue; + const pf & single =intreduce_pf(*it,intdecomp); + if ( (it->mult>1) && (intmode & 2)==0){ + gen fact1=pow(r2e(it->fact,l,contextptr),it->mult,contextptr); + gen fact2=it->den/pow(it->fact,it->mult); + gprintf(step_ratfrachermite,gettext("Partial fraction %gen -> Hermite reduction -> integrate squarefree part %gen"),makevecteur(inv(r2sym(fact2,l,contextptr),contextptr)*r2e(it->num,l,contextptr)/fact1,r2e(single.num,l,contextptr)/r2e(single.den,l,contextptr)),contextptr); + } + // factor(single.den,p_content,vden,false,withsqrt(contextptr),complex_mode(contextptr)); + gen extra_div=1; + factor(single.den,p_content,vden,false,false,false,1,extra_div); + partfrac(single.num,single.den,vden,finaldecomp,temp,tmp); + } + if ( (intmode & 2)==0) + gprintf(step_ratfracfinal,gettext("Partial fraction integration of %gen"),makevecteur(r2sym(finaldecomp,l_orig,contextptr)),contextptr); + it=finaldecomp.begin(); + itend=finaldecomp.end(); + gen ratpart=r2sym(intdecomp,l,contextptr); + // should remove constants in ratpart + gen tmp1=_fxnd(ratpart,contextptr); + if (xvar.type==_IDNT && tmp1.type==_VECT && tmp1._VECTptr->size()==2){ + gen tmp2=_quorem(makesequence(tmp1._VECTptr->front(),tmp1._VECTptr->back(),xvar),contextptr); + if (tmp2.type==_VECT && tmp2._VECTptr->size()==2){ + gen q=tmp2._VECTptr->front(),r=tmp2._VECTptr->back(); + gen C=subst(q,xvar,0,false,contextptr); + if (!is_zero(C)){ + q=ratnormal(q-C,contextptr); + tmp1=tmp1._VECTptr->back(); + tmp1=_collect(tmp1,contextptr); + tmp1=r*inv(tmp1,contextptr); + ratpart=q+tmp1; + } + } + } + return integrate_rational_end(it,itend,x,xvar,l,lprime,ipnum,ipden,ratpart,remains_to_integrate,intmode,contextptr); + } + + // integration of e when linear operations have been applied + static gen xln_x(const gen & x,GIAC_CONTEXT){ + return x*ln(x,contextptr)-x; + } + + static gen int_exp(const gen & x,GIAC_CONTEXT){ + return exp(x,contextptr); + } + + static gen int_sinh(const gen & x,GIAC_CONTEXT){ + return cosh(x,contextptr); + } + + static gen int_cosh(const gen & x,GIAC_CONTEXT){ + return sinh(x,contextptr); + } + + static gen int_sin(const gen & x,GIAC_CONTEXT){ + if (angle_radian(contextptr)) + return -cos(x,contextptr); + else if(angle_degree(contextptr)) + return -cos(x,contextptr)*gen(180)/cst_pi; + //grad + else + return -cos(x, contextptr)*gen(200) / cst_pi; + } + + static gen int_cos(const gen & x,GIAC_CONTEXT){ + if (angle_radian(contextptr)) + return sin(x,contextptr); + else if(angle_degree(contextptr)) + return sin(x,contextptr)*gen(180)/cst_pi; + //grad + else + return sin(x, contextptr)*gen(200) / cst_pi; + } + + static gen int_tan(const gen & x,GIAC_CONTEXT){ + gen g=-lnabs(cos(x,contextptr),contextptr); + if (angle_radian(contextptr)) + return g; + else if(angle_degree(contextptr)) + return g*gen(180)/cst_pi; + //grad + else + return g*gen(200) / cst_pi; + } + + static gen int_tanh(const gen & x,GIAC_CONTEXT){ + return -ln(cosh(x,contextptr),contextptr); + } + + static gen int_asin(const gen & x,GIAC_CONTEXT){ + if (angle_radian(contextptr)) + return x*asin(x,contextptr)+sqrt(1-pow(x,2),contextptr); + else if(angle_degree(contextptr)) + return x*asin(x,contextptr)*deg2rad_e+sqrt(1-pow(x,2),contextptr); + //grad + else + return x*asin(x, contextptr)*grad2rad_e + sqrt(1 - pow(x, 2), contextptr); + } + + static gen int_acos(const gen & x,GIAC_CONTEXT){ + if (angle_radian(contextptr)) + return x*acos(x,contextptr)-sqrt(1-pow(x,2),contextptr); + else if(angle_degree(contextptr)) + return x*acos(x,contextptr)*deg2rad_e-sqrt(1-pow(x,2),contextptr); + //grad + else + return x*acos(x, contextptr)*grad2rad_e - sqrt(1 - pow(x, 2), contextptr); + } + + static gen int_atan(const gen & x,GIAC_CONTEXT){ + if (angle_radian(contextptr)) + return x*atan(x,contextptr)-rdiv(ln(pow(x,2)+1,contextptr),plus_two,contextptr); + else if(angle_degree(contextptr)) + return x*atan(x,contextptr)*deg2rad_e-rdiv(ln(pow(x,2)+1,contextptr),plus_two,contextptr); + //grad + else + return x*atan(x, contextptr)*grad2rad_e - rdiv(ln(pow(x, 2) + 1, contextptr), plus_two, contextptr); + } + + static gen int_asinh(const gen & x,GIAC_CONTEXT){ + return x*asinh(x,contextptr)-sqrt(pow(x,2)+1,contextptr); + } + + static gen int_acosh(const gen & x,GIAC_CONTEXT){ + return x*acosh(x,contextptr)-sqrt(pow(x,2)-1,contextptr); + } + + static gen int_atanh(const gen & x,GIAC_CONTEXT){ + return x*atan(x,contextptr)-rdiv(ln(abs(pow(x,2)-1,contextptr),contextptr),plus_two,contextptr); + } + + static const gen_op_context primitive_tab_primitive[]={int_sin,int_cos,int_tan,int_exp,int_sinh,int_cosh,int_tanh,int_asin,int_acos,int_atan,xln_x,int_asinh,int_acosh,int_atanh}; + +#if 0 + static void insure_real_deno(gen & n,gen & d,GIAC_CONTEXT){ + gen i=im(d,contextptr),c=conj(d,contextptr); + if (!is_zero(i)){ + n=n*c; + d=d*c; + } + } +#endif + bool is_rewritable_as_f_of0(const gen & fu,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT); + + static bool in_is_rewritable_as_f_of(const gen & fu,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT){ + if (fu.type==_VECT){ + vecteur res; + const_iterateur it=fu._VECTptr->begin(),itend=fu._VECTptr->end(); + gen tmp; + for (;it!=itend;++it){ + if (!is_rewritable_as_f_of0(*it,u,tmp,gen_x,contextptr)) + return false; + res.push_back(tmp); + } + fx=gen(res,fu.subtype); + return true; + } + if (fu.type==_IDNT){ + if (fu!=gen_x){ + fx=fu; + return true; + } + return false; + } + if (fu.type!=_SYMB){ + fx=fu; + return true; + } + // symbolic + if (fu==u){ + fx=gen_x; + return true; + } + // decompose + unary_function_ptr s=fu._SYMBptr->sommet; + gen f=fu._SYMBptr->feuille,tmpfx; + if (in_is_rewritable_as_f_of(f,u,tmpfx,gen_x,contextptr)){ + fx=symbolic(s,tmpfx); + return true; + } + // try special treatment for integral powers + int fexp,uexp; + if ( (u.type!=_SYMB) || (s!=at_pow) || (f._VECTptr->back().type!=_INT_) ) + return false; + fexp=f._VECTptr->back().val; + if ( (u._SYMBptr->sommet==at_pow) && (u._SYMBptr->feuille._VECTptr->back().type==_INT_) && (u._SYMBptr->feuille._VECTptr->front()==f._VECTptr->front()) ){ + uexp=u._SYMBptr->feuille._VECTptr->back().val; + if (fexp%uexp) + return false; + fx=pow(gen_x,fexp/uexp); + return true; + } + // trigonometric fcns to an even power + f=f._VECTptr->front(); + if ( (fexp %2) || (f.type!=_SYMB) ) + return false; + fexp=fexp/2; + int ftrig=equalposcomp(primitive_tab_op,f._SYMBptr->sommet); + if (!ftrig) + return false; + int utrig=equalposcomp(primitive_tab_op,u._SYMBptr->sommet); + if (utrig==2 && u._SYMBptr->feuille==2*f._SYMBptr->feuille){ + // sin^2/cos^2/tan^2 in terms of cos(2x) + switch (ftrig){ + case 1: // sin + fx=pow((1-gen_x)/2,fexp); + return true; + case 2: // cos + fx=pow((1+gen_x)/2,fexp); + return true; + case 3: + fx=pow((1-gen_x)/(1+gen_x),fexp); + return true; + } + } + if (!utrig || f._SYMBptr->feuille!=u._SYMBptr->feuille) + return false; + switch (ftrig){ + case 1: // sin + switch (utrig){ + case 2: // sin^2=1-cos^2 + fx=pow(1-pow(gen_x,2),fexp); + return true; + case 3: // sin^2=1-1/(tan^2+1) + fx=pow(1-inv(pow(gen_x,2)+1,contextptr),fexp); + return true; + default: + return false; + } + case 2: // cos + switch (utrig){ + case 1: // cos^2=1-sin^2 + fx=pow(1-pow(gen_x,2),fexp); + return true; + case 3: // cos^2=1/(tan^2+1) + fx=pow(pow(gen_x,2)+1,-fexp); + return true; + default: + return false; + } + case 3: // tan + switch (utrig){ + case 1: // tan^2=1/(1-sin^2)-1 + fx=pow(inv(1-pow(gen_x,2),contextptr)-1,fexp); + return true; + case 2: // tan^2=1/cos^2-1 + fx=pow(pow(gen_x,-2)-1,fexp); + return true; + default: + return false; + } + } + return false; + } + + // try to rewrite fu(x), function of x as a fonction of u(x), if possible + // return fx(x) such that fu(x)=fx(u(x)) + // FIXME: should detect u=pow(.,inv(n)) with n integer + bool is_rewritable_as_f_of0(const gen & fu,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT){ + gen a,b; + if (is_linear_wrt(u,gen_x,a,b,contextptr)){ + fx=complex_subst(fu,gen_x,rdiv(gen_x-b,a,contextptr),contextptr); + return false;// true? + } + // try first if u is a linear expression of something else + if (u.type==_SYMB){ + if (u._SYMBptr->sommet==at_neg){ + gen tmpu=u._SYMBptr->feuille,tmpfx; + if (!is_rewritable_as_f_of0(fu,tmpu,tmpfx,gen_x,contextptr)) + return false; + fx=complex_subst(tmpfx,gen_x,-gen_x,contextptr); + return true; + } + if (u._SYMBptr->sommet==at_pow){ + gen tmpu=u._SYMBptr->feuille,tmpfx; + if (tmpu.type==_VECT && tmpu._VECTptr->size()==2){ + gen expo=ratnormal(inv(tmpu._VECTptr->back(),contextptr),contextptr); + tmpu=tmpu._VECTptr->front(); + if (expo.type==_INT_){ + if (is_linear_wrt(tmpu,gen_x,a,b,contextptr)){ + fx=complex_subst(fu,makevecteur(u,gen_x),makevecteur(gen_x,rdiv(pow(gen_x,expo,contextptr)-b,a,contextptr)),contextptr); + return true; + } + if (is_rewritable_as_f_of0(fu,tmpu,fx,gen_x,contextptr)){ + fx=complex_subst(fx,gen_x,pow(gen_x,expo,contextptr),contextptr); + return true; + } + } + } + } + gen alpha; + vecteur non_constant; + if (u._SYMBptr->sommet==at_prod ){ + if (u._SYMBptr->feuille.type!=_VECT) + return is_rewritable_as_f_of0(fu,u._SYMBptr->feuille,fx,gen_x,contextptr); + decompose_prod(*u._SYMBptr->feuille._VECTptr,gen_x,non_constant,alpha,true,contextptr); + if (non_constant.empty()) return false; // setsizeerr(gettext("in is_rewritable_as_f_of_f")); + if (!is_one(alpha)){ + gen tmpu,tmpfx; + tmpu=_prod(non_constant,contextptr); + if (!is_rewritable_as_f_of0(fu,tmpu,tmpfx,gen_x,contextptr)) + return false; + fx=complex_subst(tmpfx,gen_x,rdiv(gen_x,alpha,contextptr),contextptr); + return true; + } + } + if (u._SYMBptr->sommet==at_plus){ + if (u._SYMBptr->feuille.type!=_VECT) + return is_rewritable_as_f_of0(fu,u._SYMBptr->feuille,fx,gen_x,contextptr); + if (_is_polynomial(makesequence(fu,gen_x),contextptr)==1 && _is_polynomial(makesequence(u,gen_x),contextptr)==1){ + gen FU=_symb2poly(makesequence(fu,gen_x),contextptr); + gen U=_symb2poly(makesequence(u,gen_x),contextptr); + if (FU.type==_VECT && U.type==_VECT){ + vecteur vfu=*FU._VECTptr; + vecteur vu=*U._VECTptr; + int N=vfu.size()-1,M=vu.size()-1; + vecteur vfx(N/M+1); + for (;!vfu.empty();){ + int n=vfu.size()-1,m=vu.size()-1; + if (n % m) + break; + gen c=vfu[0]/pow(vu[0],n/m,contextptr); + vfx[N/M-n/m]=c; + vecteur vtmp; + gen cunm=_symb2poly(makesequence(c*pow(u,n/m),gen_x),contextptr); + submodpoly(vfu,gen2vecteur(cunm),vtmp); + vfu=*normal(vtmp,contextptr)._VECTptr; + vfu=trim(vfu,0); + } + if (vfu.empty()){ + fx=_poly2symb(makesequence(vfx,gen_x),contextptr); + return true; + } + } + } + decompose_plus(*u._SYMBptr->feuille._VECTptr,gen_x,non_constant,alpha,contextptr); + if (non_constant.empty()) return false; // setsizeerr(gettext("in is_rewritable_as_f_of_f 2")); + if (!is_zero(alpha)){ + gen tmpu,tmpfx; + tmpu=_plus(non_constant,contextptr); + if (!is_rewritable_as_f_of0(fu,tmpu,tmpfx,gen_x,contextptr)) + return in_is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr);; + fx=complex_subst(tmpfx,gen_x,gen_x-alpha,contextptr); + if (!has_i(fx)) // FIX for int(x^3/sqrt(1-x^2),x,-1,0); + return true; + } + } + } + return in_is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr); + } + + bool is_rewritable_as_f_of(const gen & fu_,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT){ + gen tempu=identificateur(" u"); + gen fu=complex_subst(fu_,u,tempu,contextptr); + if (is_undef(fu) || !is_rewritable_as_f_of0(fu,u,fx,gen_x,contextptr)) + return false; + fx=complex_subst(fx,tempu,gen_x,contextptr); + return true; + } + + gen firstcoefftrunc(const gen & e){ + if (e.type==_FRAC) + return fraction(firstcoefftrunc(e._FRACptr->num),firstcoefftrunc(e._FRACptr->den)); + if (e.type==_POLY) + return firstcoeff(*e._POLYptr).trunc1(); + return e; + } + + // special version of lvarx that does not remove cst powers + vecteur lvarxpow(const gen &e,const gen & x){ + const vecteur & v=lvar(e); + vecteur res; + vecteur::const_iterator it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (contains(*it,x)) + res.push_back(*it); + } + // do lvar again to comprim the first arg of ^ + return lvar(res); + } + + gen invexptoexpneg(const gen& g,GIAC_CONTEXT){ + if (g.type==_SYMB && g._SYMBptr->sommet==at_exp) + return exp(-g._SYMBptr->feuille,contextptr); + else + return symb_inv(g); + } + + gen integrate_gen_rem(const gen & e_orig,const gen & x_orig,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ + if (x_orig.type!=_IDNT){ + identificateur x(" x"); + gen e=subst(e_orig,x_orig,x,false,contextptr); + e=integrate_id_rem(e,x,remains_to_integrate,contextptr,intmode); + remains_to_integrate=quotesubst(remains_to_integrate,x,x_orig,contextptr); + return quotesubst(e,x,x_orig,contextptr); + } + return integrate_id_rem(e_orig,x_orig,remains_to_integrate,contextptr,intmode); + } + + static bool integrate_step0(gen & e,const gen & gen_x,vecteur & l1,vecteur & m1,gen & res,gen & remains_to_integrate,GIAC_CONTEXT,int intmode){ + const identificateur & id_x=*gen_x._IDNTptr; + vecteur l2,m2,l3,l4; + const_iterateur it=l1.begin(),itend=l1.end(); + int i=0; + for (;it!=itend;++it,++i){ + gen tmp=it->_SYMBptr->feuille; + identificateur tmpi(" s"+print_INT_(i)); + l2.push_back(tmpi*tmp); + l3.push_back(tmpi); + l4.push_back(symbolic(at_sign,tmp)); + } + it=m1.begin(),itend=m1.end(); + for (;it!=itend;++it,++i){ + l1.push_back(*it); + gen tmp=it->_SYMBptr->feuille; + identificateur tmpi(" s"+print_INT_(i)); + l2.push_back(tmpi); + l3.push_back(tmpi); + l4.push_back(*it); + } + *logptr(contextptr) << gettext("Warning, integration of abs or sign assumes constant sign by intervals (correct if the argument is real):\nCheck ") << l1 << '\n'; + e=complex_subst(e,l1,l2,contextptr); + res=integrate_id_rem(e,gen_x,remains_to_integrate,contextptr,intmode); + gen resadd; + if (is_undef(res)) return true; + // check what happens when si==0 + for (int j=0;jfeuille; + if (val2.is_symb_of_sommet(at_sin) || val2.is_symb_of_sommet(at_tan)) + val2=val2._SYMBptr->feuille; + bool warn=true; + if (is_linear_wrt(val2,gen_x,a,b,contextptr) && ((has_evalf(a,r,1,contextptr) && has_evalf(b,r,1,contextptr)) || lvar(res)==lidnt(res))){ + warn=val._SYMBptr->feuille!=val2; + r=-b/a; + vecteur l5(l4); +#if 1 + l5[j]=1; + gen limsup=subst(res,l3,l5,false,contextptr); + l5[j]=-1; + gen liminf=subst(res,l3,l5,false,contextptr); +#else + l5[j]=1; + bool dolim=l3.size()==1 && l5.size()==1 && l3.front().type==_IDNT; + gen limsup=dolim?limit(res,*l3.front()._IDNTptr,l5.front(),0,contextptr):subst(res,l3,l5,false,contextptr); + l5[j]=-1; + gen liminf=dolim?limit(res,*l3.front()._IDNTptr,l5.front(),0,contextptr):subst(res,l3,l5,false,contextptr); +#endif + gen tmp=ratnormal((limit(liminf,id_x,r,-1,contextptr)-limit(limsup,id_x,r,1,contextptr))/2,contextptr)*val; + if (is_undef(tmp) || is_inf(tmp)) + *logptr(contextptr) << gettext("Unable to cancel step at ")+r.print(contextptr) + " of " << limsup << "-" << liminf << '\n'; + else + resadd += tmp; + } + if (warn) + *logptr(contextptr) << gettext("Discontinuities at zeroes of ") << val._SYMBptr->feuille << " were not checked" << '\n'; + } + } + remains_to_integrate=complex_subst(remains_to_integrate,l3,l4,contextptr); + res=resadd+complex_subst(res,l3,l4,contextptr); + return true; + } + + static bool detect_inv_trigln(gen & e,vecteur & rvar,const gen & gen_x,gen & res,gen & remains_to_integrate,bool additional_check,int intmode,GIAC_CONTEXT){ + const_iterateur rvt=rvar.begin(),rvtend=rvar.end(); + for (;rvt!=rvtend;++rvt){ + if (rvt->type!=_SYMB) + continue; + int rvtt=equalposcomp(inverse_tab_op,rvt->_SYMBptr->sommet); + if (!rvtt || rvtt==3 || rvtt==7) // exclude atan and atanh + continue; + rvtt=equalposcomp(primitive_tab_op,rvt->_SYMBptr->sommet); + if (rvtt>7){ + unary_function_ptr inverse_sommet=primitive_tab_op[rvtt-8]; + gen feuille=rvt->_SYMBptr->feuille,a,b; + if (!is_linear_wrt(feuille,gen_x,a,b,contextptr)) + continue; + if (additional_check){ + // Additionaly check that e is polynomial wrt x + identificateur tmpidnt(" t"); + gen tmpcheck=subst(e,*rvt,tmpidnt,false,contextptr); + vecteur vx2(rlvarx(tmpcheck,gen_x)); + if ( vx2.size()>1) + continue; + if (vx2.size()){ + lvar(tmpcheck,vx2); + fraction ftemp=sym2r(tmpcheck,vx2,contextptr); + if (ftemp.den.type==_POLY && ftemp.den._POLYptr->lexsorted_degree()) + continue; + } + } + // make the change of var ln[ax+b]=t -> x=rdiv(exp(t)-b,a) + gen tmprem,tmpres,tmpe,xt,dxt,sqrtxt; + xt=rdiv(symbolic(inverse_sommet,gen_x)-b,a,contextptr); + dxt=derive(xt,gen_x,contextptr); + if (is_undef(dxt)){ + res=dxt; + return true; + } + // should add sqrt(1-.^2) + vecteur substin(makevecteur(gen_x,*rvt)); + vecteur substout(makevecteur(xt,gen_x)); + if ((rvtt==8 || rvtt==9)){ + vecteur tmpv=lop(e,at_pow); + for (unsigned tmpi=0;tmpifeuille; + if (tmpvi.type==_VECT && tmpvi._VECTptr->size()==2){ + gen tmpvi0=tmpvi._VECTptr->front(); + if (ratnormal(tmpvi0-1+pow(a*gen_x+b,2,contextptr),contextptr)==0){ + substin.push_back(tmpv[tmpi]); + substout.push_back(pow(symbolic(rvtt==8?at_cos:at_sin,gen_x),2*tmpvi._VECTptr->back(),contextptr)); + } + } + } + } + tmpe=ratnormal(complex_subst(e,substin,substout,contextptr)*dxt,contextptr); + if ( (intmode & 2)==0) + gprintf(step_ratfracchgvar,gettext("Integrate %gen, change of variable %gen->%gen, new integral %gen"),makevecteur(e,gen_x,xt,tmpe),contextptr); + tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); + if ( (intmode & 2)==0) + gprintf(step_backsubst,gettext("Back substitution %gen->%gen in %gen"),makevecteur(gen_x,*rvt,tmpres),contextptr); + remains_to_integrate=complex_subst(rdiv(tmprem,dxt,contextptr),gen_x,*rvt,contextptr); + // replace tan(asin/2) or tan(acos/2) and cos(asin) and sin(acos) + if ((rvtt==8 || rvtt==9) && has_op(tmpres,*at_tan)) + tmpres=tan2sincos2(tmpres,contextptr); + tmpres=_texpand(tmpres,contextptr); + res=complex_subst(tmpres,substout,substin,contextptr); + return true; + } + } + return false; + } + + gen integrate_id_rem(const gen & e_orig,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT){ + return integrate_id_rem(e_orig,gen_x,remains_to_integrate,contextptr,0); + } + + gen add_lnabs(const gen & g,GIAC_CONTEXT){ + return symbolic(at_ln,abs(g,contextptr)); + } + + void surd2pow(const gen & e,vecteur & subst1,vecteur & subst2,GIAC_CONTEXT){ + vecteur l1surd(lop(e,at_surd)); + vecteur l2surd(l1surd); + for (unsigned i=0;ifeuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2){ + vecteur gv=*g._SYMBptr->feuille._VECTptr; + gv=makevecteur(gv[0],inv(gv[1],contextptr)); + g=_pow(gen(gv,_SEQ__VECT),contextptr);//symbolic(at_pow,gen(gv,_SEQ__VECT)); + } + } + vecteur l1NTHROOT(lop(e,at_NTHROOT)); + vecteur l2NTHROOT(l1NTHROOT); + for (unsigned i=0;ifeuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2){ + vecteur gv=*g._SYMBptr->feuille._VECTptr; +#if defined GIAC_GGB + gv=makevecteur(subst(gv[1],l1NTHROOT,l2NTHROOT,false,contextptr),inv(gv[0],contextptr)); +#else + gv=makevecteur(gv[1],inv(gv[0],contextptr)); +#endif + g=_pow(gen(gv,_SEQ__VECT),contextptr);//symbolic(at_pow,gen(gv,_SEQ__VECT)); + } + } + subst1=mergevecteur(l1surd,l1NTHROOT); + subst2=mergevecteur(l2surd,l2NTHROOT); + if (!subst1.empty()) + *logptr(contextptr) << gettext("Temporary replacing surd/NTHROOT by fractional powers") << '\n'; + } + + bool is_elementary(const vecteur & v,const gen & x){ + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (*it==x) + continue; + if (!it->is_symb_of_sommet(at_exp) && (!it->is_symb_of_sommet(at_ln)) ) + return false; + } + return true; + } + + bool when2sign(gen &e,const gen &gen_x,GIAC_CONTEXT){ + vecteur lwhen(lop(e,at_when)); + if (!lwhen.empty()) lwhen=lvarx(lwhen,gen_x); + if (!lwhen.empty()){ + vecteur l2; + const_iterateur it=lwhen.begin(),itend=lwhen.end(); + int i=0; + for (;it!=itend;++it,++i){ + gen tmp=it->_SYMBptr->feuille,repl; + if (tmp.type!=_VECT || tmp._VECTptr->size()!=3) + return false; + vecteur & whenargs = *tmp._VECTptr; + tmp = whenargs[0]; + if ( (tmp.is_symb_of_sommet(at_superieur_strict) || + tmp.is_symb_of_sommet(at_superieur_egal) ) && + (repl=tmp._SYMBptr->feuille).type==_VECT && repl._VECTptr->size()==2){ + repl=repl._VECTptr->back()-repl._VECTptr->front(); + repl=(symbolic(at_sign,repl)+1)/2; + } + else { + repl=symbolic(at_same,gen(makevecteur(tmp,0),_SEQ__VECT)); + repl=symbolic(at_sign,repl); + } + l2.push_back(whenargs[1]+repl*(whenargs[2]-whenargs[1])); + } + e=complex_subst(e,lwhen,l2,contextptr); + } + return true; + } + + // intmode bit 0 is used for sqrt int control, bit 1 control step/step info + // bit 2 = 1 to avoid Risch call + gen integrate_id_rem(const gen & e_orig,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT,int intmode){ +#ifdef LOGINT + *logptr(contextptr) << gettext("integrate id_rem ") << e_orig << '\n'; +#endif + remains_to_integrate=0; + gen e(e_orig); + // Additional check: atan/asin in degree/grad + if (angle_mode(contextptr)){ + if (has_op(e,*at_asin)|| has_op(e,*at_atan) || has_op(e,*at_acos)) + return undeferr("Inverse trigonometric functions are supported in radian mode only."); + } + // Step -3: replace when by piecewise + e=when2piecewise(e,contextptr); + e=Heavisidetopiecewise(e,contextptr); // e=Heavisidetosign(e,contextptr); + if (is_constant_wrt(e,gen_x,contextptr) && lop(e,at_sign).empty()) + return e*gen_x; + if (e.type!=_SYMB) { + remains_to_integrate=zero; + if (e==gen_x) + return rdiv(pow(e,2),plus_two,contextptr); + else + return e*gen_x; + } + // Step -2: piecewise + vecteur lpiece(lop(e,at_piecewise)); + if (!lpiece.empty()) lpiece=lvarx(lpiece,gen_x); + if (!lpiece.empty()){ + *logptr(contextptr) << gettext("Warning: piecewise indefinite integration does not return a continuous antiderivative") << '\n'; + gen piece=lpiece.front(); + if (piece.is_symb_of_sommet(at_piecewise)) + return integrate_piecewise(e,piece,gen_x,remains_to_integrate,contextptr,intmode); + } +#ifdef LOGINT + *logptr(contextptr) << gettext("integrate step -2 ") << e << '\n'; +#endif + // Step -1: replace ifte(a,b,c) by b+sign(a==0)*(c-b) + // if a is A1>A2 or A1>=A2 condition, the sign(a==0) is replaced by (sign(A2-A1)+1)/2 + if (!when2sign(e,gen_x,contextptr)) + return gensizeerr(gettext("Bad when ")+e.print(contextptr)); +#ifdef LOGINT + *logptr(contextptr) << gettext("integrate step 0 ") << e << '\n'; +#endif + // Step 0: replace abs(var_dep_x) with sign*var_dep_x + // and then sign() with a constant + gen res; + vecteur l1(lop(e,at_abs)),m1(lop(e,at_sign)); + if (!l1.empty()) l1=lvarx(l1,gen_x); + if (!m1.empty()) m1=lvarx(m1,gen_x); + if (!l1.empty() || !m1.empty()){ + if (integrate_step0(e,gen_x,l1,m1,res,remains_to_integrate,contextptr,intmode)) + return res; + } + // Step1: detection of some unary_op[linear fcn] + if (e.is_symb_of_sommet(at_inv) && e._SYMBptr->feuille.is_symb_of_sommet(at_pow)){ + gen f=e._SYMBptr->feuille._SYMBptr->feuille; + if (f.type==_VECT && f._VECTptr->size()==2){ + gen b=f._VECTptr->back(); + if (!is_integer(b) && b.type!=_FRAC) + e=symbolic(at_pow,makevecteur(f._VECTptr->front(),-b)); + } + } + unary_function_ptr u=e._SYMBptr->sommet; + gen f=e._SYMBptr->feuille,a,b; + // particular case for ^, _FUNCnd arg must be constant + if ( ((intmode & 4)==0) && u==at_pow && f[0].is_symb_of_sommet(at_pow)){ + e=symbolic(at_pow,makesequence(f[0]._SYMBptr->feuille[0],f[0]._SYMBptr->feuille[1]*f[1])); + return integrate_id_rem(e,gen_x,remains_to_integrate,contextptr,intmode); + } + if ( (u==at_pow) && is_constant_wrt(f._VECTptr->back(),gen_x,contextptr) && is_linear_wrt(f._VECTptr->front(),gen_x,a,b,contextptr) ){ + if ( (intmode & 2)==0) + gprintf(step_linear,gettext("Integrate %gen, a linear expression u=%gen to a constant power n=%gen,\nIf n=-1 then ln(u)/a else u^(n+1)/((n+1)*%gen)"),makevecteur(e,a*gen_x+b,f._VECTptr->back(),a),contextptr); + b=f._VECTptr->back(); + if (is_minus_one(b)) + return rdiv(lnabs(f._VECTptr->front(),contextptr),a,contextptr); + return rdiv(pow(f._VECTptr->front(),b+plus_one,contextptr),a*(b+plus_one),contextptr); + } + if ( (u==at_surd) && is_constant_wrt(f._VECTptr->back(),gen_x,contextptr) && is_linear_wrt(f._VECTptr->front(),gen_x,a,b,contextptr) ){ + if ( (intmode & 2)==0) + gprintf(step_linear,gettext("Integrate %gen, a linear expression u=%gen to a constant power n=1/%gen,\nIf n=-1 then ln(u)/a else u^(n+1)/((n+1)*%gen)"),makevecteur(e,a*gen_x+b,f._VECTptr->front(),a),contextptr); + b=f._VECTptr->back(); + if (is_minus_one(b)) + return rdiv(lnabs(f._VECTptr->front(),contextptr),a,contextptr); + return f._VECTptr->front()*symbolic(at_surd,f)/(a+a/b); + } + if ( (u==at_NTHROOT) && is_constant_wrt(f._VECTptr->front(),gen_x,contextptr) && is_linear_wrt(f._VECTptr->back(),gen_x,a,b,contextptr) ){ + if ( (intmode & 2)==0) + gprintf(step_linear,gettext("Integrate %gen, a linear expression u=%gen to a constant power n=1/%gen,\nIf n=-1 then ln(u)/a else u^(n+1)/((n+1)*%gen)"),makevecteur(e,a*gen_x+b,f._VECTptr->front(),a),contextptr); + b=f._VECTptr->front(); + if (is_minus_one(b)) + return rdiv(lnabs(f._VECTptr->back(),contextptr),a,contextptr); + return f._VECTptr->back()*symbolic(at_NTHROOT,f)/(a+a/b); + } +#if 1 // ndef EMCC // re-enabled Aug. 2015 for integrate(1/surd(x^2,3),x,-1,1) + if (has_op(e,*at_surd) || has_op(e,*at_NTHROOT)){ + vecteur subst1,subst2; + surd2pow(e,subst1,subst2,contextptr); + gen g=subst(e,subst1,subst2,false,contextptr); + g=integrate_id_rem(g,gen_x,remains_to_integrate,contextptr,intmode | 4); + remains_to_integrate=subst(remains_to_integrate,subst2,subst1,false,contextptr); + g=subst(g,subst2,subst1,false,contextptr); + return g; + } +#endif +#ifdef LOGINT + *logptr(contextptr) << gettext("integrate step 1 ") << e << '\n'; +#endif + if (u==at_sum && f.type==_VECT && f._VECTptr->size()==4){ + vecteur & fv=*f._VECTptr; + if (!is_zero(derive(fv[1],gen_x,contextptr))) + return gensizeerr("Mute variable of sum depends on integration variable"); + if (!is_zero(derive(fv[2],gen_x,contextptr)) || !is_zero(derive(fv[3],gen_x,contextptr)) ) + return gensizeerr("Boundaries of sum depends on integration variables"); + if (is_inf(fv[2])||is_inf(fv[3])) + *logptr(contextptr) << "Warning: assuming integration and sum commutes" << '\n'; + gen res=integrate_id_rem(fv[0],gen_x,remains_to_integrate,contextptr,intmode); + res=_sum(makesequence(res,fv[1],fv[2],fv[3]),contextptr); + if (!is_zero(remains_to_integrate)) + remains_to_integrate=_sum(makesequence(remains_to_integrate,fv[1],fv[2],fv[3]),contextptr); + return res; + } + // unary op only + int s=equalposcomp(primitive_tab_op,u); + if (s && is_linear_wrt(f,gen_x,a,b,contextptr) ){ + if ( (intmode & 2)==0) + gprintf(step_funclinear,gettext("Integrate %gen: function %gen applied to a linear expression u=%gen, result %gen"),makevecteur(e,primitive_tab_op[s-1],a*gen_x+b,primitive_tab_primitive[s-1](a*gen_x+b,contextptr)/a),contextptr); + return rdiv(primitive_tab_primitive[s-1](f,contextptr),a,contextptr); + } + if (u==at_of && f.type==_VECT && f._VECTptr->size()==2 && is_linear_wrt(f._VECTptr->back(),gen_x,a,b,contextptr)){ + gen f0=f[0]; + if (f0.is_symb_of_sommet(at_function_diff) && f0._SYMBptr->feuille.type!=_VECT) + return symb_of(f0._SYMBptr->feuille,f[1])/a; + } + // Step2: detection of f(u)*u' + vecteur v(1,gen_x); + rlvarx(e,gen_x,v); + // detect constants and gcd for linear args + gen curgcd(v.size()<=2?1:0); bool allsame=true; + for (int i=1;ifeuille; + gen vf1=derive(vf,gen_x,contextptr); + vf1=ratnormal(vf1,contextptr); + if (is_zero(vf1) && gen_x.type==_IDNT){ + vf=limit(vf,*gen_x._IDNTptr,0,1,contextptr); + if (!is_undef(vf)){ + gen e1=complex_subst(e,v[i],v[i]._SYMBptr->sommet(vf,contextptr),contextptr); + vecteur w(1,gen_x); + rlvarx(e1,gen_x,w); + if (w.size()feuille,a,b; + if (is_linear_wrt(vf,gen_x,a,b,contextptr) && (a==1||a==-1)){ + if (b==0) break; // + gen e1=complex_subst(e,gen_x,a*(gen_x-b),contextptr); + gen E1=integrate_id_rem(e1,gen_x,remains_to_integrate,contextptr,intmode); + remains_to_integrate=complex_subst(remains_to_integrate,gen_x,a*gen_x+b,contextptr); + E1=complex_subst(E1,gen_x,a*gen_x+b,contextptr); + return a*E1/curgcd; + } + } + } + if (!allsame && curgcd!=0 && curgcd!=1){ + gen e1=complex_subst(e,gen_x,inv(curgcd,contextptr)*gen_x,contextptr); + v=vecteur(1,gen_x); + rlvarx(e1,gen_x,v); + vecteur vrep(v); + for (int i=1;ifeuille,contextptr),contextptr); + vrep[i]=symbolic(v[i]._SYMBptr->sommet,vf); + } + if (v!=vrep) e1=complex_subst(e1,v,vrep,contextptr); + gen E1=integrate_id_rem(e1,gen_x,remains_to_integrate,contextptr,intmode); + remains_to_integrate=complex_subst(remains_to_integrate,gen_x,curgcd*gen_x,contextptr); + E1=complex_subst(E1,gen_x,curgcd*gen_x,contextptr); + return E1/curgcd; + } + if (!lop(v,at_rootof).empty()){ + remains_to_integrate=e_orig; + return 0; + } + int rvarsize=int(v.size()); + if (rvarsize>1){ + gen e2=_texpand(e,contextptr); + if (is_undef(e2)) + e2=e; + vecteur v2(1,gen_x); + rlvarx(e2,gen_x,v2); + if (v2.size()feuille; + if (!lvar(v20[1]).empty()){ + e2=ratnormal(powexpand(e,contextptr),contextptr); + v2.clear(); + rlvarx(e2,gen_x,v2); + if (lvar(e2).size() find the value + tmprem=subst(u,gen_x,zero,false,contextptr); + e=subst(e,u,tmprem,false,contextptr); + return integrate_id_rem(e,gen_x,remains_to_integrate,contextptr,intmode | 2); + } + if (is_undef(fu) || is_inf(fu)) + continue; + bool issin=u.is_symb_of_sommet(at_sin),iscos=u.is_symb_of_sommet(at_cos); + if (iscos) + fu=_trigcos(tan2sincos(fu,contextptr),contextptr); + if (issin) + fu=_trigsin(tan2sincos(fu,contextptr),contextptr); + if (u.is_symb_of_sommet(at_tan)) + fu=_trigtan(fu,contextptr); + if (u.is_symb_of_sommet(at_atan) + // ?additional check with contains to avoid recursion in int by part + && !equalposcomp(lvar(e),u) + ){ + // ? change of variable with argument of atan + gen argatan=u._SYMBptr->feuille,a,b; + if (is_linear_wrt(argatan,gen_x,a,b,contextptr)){ + // t=atan(a*gen_x+b), gen_x=(tan(t)-b)/a + gen ck=subst(fu,makevecteur(u,gen_x,sqrt(pow(a*gen_x+b,2)+1,contextptr)),makevecteur(gen_x,(symbolic(at_sin,gen_x)/symbolic(at_cos,gen_x)-b)/a,symb_inv(symb_cos(gen_x))),false,contextptr); + // gen xval=assumeeval(gen_x,contextptr); + // giac_assume(symb_and(symb_superieur_egal(gen_x,0),symb_inferieur_egal(gen_x,cst_pi_over_2)),contextptr); + ck=linear_integrate_nostep(ck,gen_x,tmprem,intmode,contextptr); + // restorepurge(xval,gen_x,contextptr); + if (is_zero(tmprem)){ + ck=complex_subst(ck,gen_x,u,contextptr); + return ck; + } + } + } + bool tst=is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr); + if (tst && (issin || iscos)){ + gen fx1=ratnormal(fx/2/gen_x),fx2,fx21; + if (is_rewritable_as_f_of(fx1,pow(gen_x,2),fx2,gen_x,contextptr)){ // attempt with cos^2 or sin^2 + fx2=recursive_ratnormal(fx2,contextptr); + gen fx21=recursive_ratnormal(subst(-fx2,gen_x,1-gen_x,false,contextptr),contextptr); + int t1=taille(fx2,256),t2=taille(fx21,256); + if (t2<0.7*t1){ + if (issin) u=symb_cos(u._SYMBptr->feuille); else u=symb_sin(u._SYMBptr->feuille); + fx2=fx21; + } + u=pow(u,2); fx=fx2; + } + } + if (tst){ + if (taille(fx,256)>taille(e,255)){ + vecteur fxv=lvarx(fx,gen_x); + if (has_op(fxv,*at_ln) || has_op(fxv,*at_atan)) + tst=false; + } + } + if (tst){ + if ( (intmode & 2)==0) + gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,u),contextptr); +#if 0 + // no abs, for integrate(cot(ln(x))/x,x), but has side effect... + // would be better to add implicit assumptions + bool save_do_lnabs=do_lnabs(contextptr); + do_lnabs(false,contextptr); + e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); + do_lnabs(save_do_lnabs,contextptr); + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,*it,contextptr)*df; + e=complex_subst(e,gen_x,u,contextptr); + if (save_do_lnabs){ + vector ln_tab(1,at_ln); + vector lnabs_tab(1,add_lnabs); + e=subst(e,ln_tab,lnabs_tab,true,contextptr); + } + return e; +#else + // ln() in integration should not be ln(abs()) if complex change of variable, example a:=-2/(2*i*exp(2*i*x)+2*i)*exp(2*i*x); b:=int(a); simplify(diff(b)-a); + bool b=do_lnabs(contextptr); + if (has_i(u)) do_lnabs(false,contextptr); + e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); + do_lnabs(b,contextptr); + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,u,contextptr)*df; + bool batan=atan_tan_no_floor(contextptr); + atan_tan_no_floor(true,contextptr); + e=complex_subst(e,gen_x,u,contextptr); + atan_tan_no_floor(batan,contextptr); + // additional check for integrals like + // int(sqrt (1+x^(-2/3)),x,-1,0) + if (u.is_symb_of_sommet(at_pow)){ + gen powarg=u[1],powa,powb; + if (is_linear_wrt(powarg,gen_x,powa,powb,contextptr) && !is_zero(powa)){ + gen powx=-powb/powa; + // check derivative at powx+-1 + gen check=derive(e,gen_x,contextptr)/e_orig; + check=ratnormal(check,contextptr); + gen chkplus=subst(check,gen_x,powx+1.0,false,contextptr); + gen chkminus=subst(check,gen_x,powx-1.0,false,contextptr); + bool tstplus=is_zero(chkplus+1,contextptr); + bool tstminus=is_zero(chkminus+1,contextptr); + if (tstplus){ + if (tstminus) + e=-e; + else + e=-sign(gen_x,contextptr)*e; + } + else { + if (tstminus) + e=sign(gen_x,contextptr)*e; + } + } + } + if (!lop(lvarx(remains_to_integrate,gen_x),at_rootof).empty()){ + remains_to_integrate=e_orig; + return 0; + } + return e; +#endif + } + if (postaille(e,255)){ + vecteur fxv=lvarx(fx,gen_x); + if (has_op(fxv,*at_ln) || has_op(fxv,*at_atan)) + tst=false; + } + } + if (tst){ + if ( (intmode & 2)==0) + gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,uit),contextptr); + e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,*it,contextptr)*df; + return complex_subst(e,gen_x,uit,contextptr); + } + } + if (u.type!=_SYMB) + continue; + f=ratnormal(u._SYMBptr->feuille,contextptr); + // ratnormal added otherwise infinite recursion for int(1/sin(x^-1)) + if ( (f.type==_VECT) && (!f._VECTptr->empty()) ) + f=f._VECTptr->front(); + if (f.type!=_SYMB) + continue; + if (is_linear_wrt(f,gen_x,a,b,contextptr)) + continue; + df=derive(f,gen_x,contextptr); + // if rvarsize==2 and f=(a*gen_x+b)/(c*gen_x+d), make the change of var + // inf recurs will not happen, e=RAT(gen_x,function(RAT[gen_x])) + // will be replaced with RAT(RAT[f],function(f))*RAT[f] + // a simpler integral + gen A,B,C; + if (rvarsize==2 && is_quadratic_wrt(inv(df,contextptr),gen_x,A,B,C,contextptr)&&is_zero(ratnormal(B*B-4*A*C,contextptr))){ + A=2*A; + C=ratnormal(f*(A*gen_x+B),contextptr); + // f=C/(2*A*gen_x+B) + gen a,b; + if (is_linear_wrt(C,gen_x,a,b,contextptr)){ // always true + // f=(a*gen_x+b)/(A*gen_x+B) + C=gcd(gcd(a,b),gcd(A,B)); + if (is_positive(-A,contextptr)) + C=-C; + a=ratnormal(a/C); b=ratnormal(b/C); A=ratnormal(A/C); B=ratnormal(B/C); + // let f=x, gen_x=(B*x-b)/(-A*x+a) + e=subst(e,makevecteur(gen_x,f),makevecteur((B*gen_x-b)/(-A*gen_x+a),gen_x),false,contextptr)*(-A*b+B*a)/pow(gen_x*A-a,2); + e=linear_integrate_nostep(e,gen_x,tmprem,intmode,contextptr); + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,f,contextptr); + return complex_subst(e,gen_x,f,contextptr); + + } + } + fu=recursive_ratnormal(rdiv(e,df,contextptr),contextptr); // changed from ratnormal, made 30/06/2021 for int((4/x^5)*cos((1/x^4)-6) ); + if (is_rewritable_as_f_of(fu,f,fx,gen_x,contextptr) && !is_undef(fx)){ + if ( (intmode & 2)==0) + gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,f),contextptr); + e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,f,contextptr)*df; + return complex_subst(e,gen_x,f,contextptr); + } + } + } +#ifdef LOGINT + *logptr(contextptr) << gettext("integrate step 2 ") << e << '\n'; +#endif + if (e.type!=_SYMB){ + if (e==gen_x) + return pow(gen_x,2,contextptr)/2; + else + return e*gen_x; + } + // try with argument of the product or of a power + v.clear(); + bool est_puissance; + if (e._SYMBptr->sommet==at_pow){ + v=vecteur(1,e._SYMBptr->feuille._VECTptr->front()); + fu=pow(e._SYMBptr->feuille._VECTptr->front(),e._SYMBptr->feuille._VECTptr->back()-plus_one,contextptr); + est_puissance=true; + } + else { + if ( (e._SYMBptr->sommet==at_prod) && (e._SYMBptr->feuille.type==_VECT)) + v=*e._SYMBptr->feuille._VECTptr; + est_puissance=false; + } + const_iterateur vt=v.begin(),vtend=v.end(); + for (int i=0;(i=TRY_FU_UPRIME_MAXLEAFSIZE) + continue; + gen tmprem,u=linear_integrate_nostep(*vt,gen_x,tmprem,intmode|2,contextptr); + if (is_undef(u) || !is_zero(tmprem)){ + gen tst=*vt; + if ((intmode&8)==0 && tst.is_symb_of_sommet(at_pow)){ + gen vtbase=tst._SYMBptr->feuille[0],vtexpo=inv(tst._SYMBptr->feuille[1],contextptr); + if (vtexpo.type==_INT_ && vtexpo.val==4){ + if (evenodd==-1) + evenodd=is_even_odd(e,gen_x,contextptr); + if (evenodd==1){ + gen tmp=complex_subst(e,gen_x,inv(gen_x,contextptr),contextptr); + gen root=complex_subst(tst,gen_x,inv(gen_x,contextptr),contextptr); + gen sroot=simplify(root,contextptr); + if (is_even_odd(sroot,gen_x,contextptr)){ + tmp=complex_subst(tmp,root,sroot,contextptr); + tmp=-linear_integrate_nostep(tmp*pow(gen_x,-2,contextptr),gen_x,tmprem,intmode|2|8,contextptr); + if (!is_undef(tmp) && is_zero(tmprem)){ + tmp=simplifier(tmp,contextptr); + tmp=complex_subst(tmp,gen_x,inv(gen_x,contextptr),contextptr); + vecteur v=lop(tmp,at_pow); + vecteur w=gen2vecteur(simplify(v,contextptr)); + tmp=complex_subst(tmp,v,w,contextptr); + return tmp; + } + } + } + } + } + continue; + } + // tmprem==0 *vt has a closed form antiderivative + if (!est_puissance){ + vecteur vv(v); + vv.erase(vv.begin()+i,vv.begin()+i+1); + fu=symbolic(at_prod,gen(vv,_SEQ__VECT)); + // try integration by part if u is simple and fu polynomial + if (rvar.size()>1 && !is_zero(_is_polynomial(makesequence(fu,gen_x),contextptr))){ + vecteur vu; rlvarx(u,gen_x,vu); + int ok=0; + for (;ok auth; + auth.push_back(*at_exp); + auth.push_back(*at_pow); + auth.push_back(*at_sin); + auth.push_back(*at_cos); + auth.push_back(*at_tan); + auth.push_back(*at_sinh); + auth.push_back(*at_cosh); + auth.push_back(*at_tanh); +#else + vector auth={*at_exp,*at_pow,*at_sin,*at_cos,*at_tan,*at_sinh,*at_cosh,*at_tanh}; +#endif + if (!equalposcomp(auth,cur._SYMBptr->sommet)) + break; + } + if (ok==vu.size()){ + *logptr(contextptr) << "Trying integration by part\n"; + // integrate(fu*u')=[fu*u]-integrate(fu'*u) + gen res=integrate_id_rem(derive(fu,gen_x,contextptr)*u,gen_x,remains_to_integrate,contextptr,intmode); + if (is_zero(remains_to_integrate)) + return fu*u-res; + } + } + } + gen cst=extract_cst(u,gen_x,contextptr); + bool recur=rvarsize>2 && gen_x.type==_IDNT && strcmp(gen_x._IDNTptr->id_name,"t_nostep")==0 && u.is_symb_of_sommet(at_pow); // workaround for some stupid integrals like integrate(sin((d*x + c)^(2/3)*b + a)/(f*x + E),x); + if (!recur && + (is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr) || is_rewritable_as_f_of(simplifier(fu,contextptr),simplifier(u,contextptr),fx,gen_x,contextptr))){ + fx=cst*fx; + if ( (intmode & 2)==0) + gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,u),contextptr); + gen e1=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); +#if 1 // changed 2020 dec 13 for integrate(exp(t)*(t+1)^-2,t); + if (is_zero(tmprem)) + return complex_subst(e1,gen_x,u,contextptr); +#else + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,u,contextptr)*derive(u,gen_x,contextptr); + return complex_subst(e1,gen_x,u,contextptr); +#endif + } + if (vt->is_symb_of_sommet(at_pow)){ + gen vtbase=vt->_SYMBptr->feuille[0],vtexpo=vt->_SYMBptr->feuille[1]; + if (vtexpo.type==_INT_ && vtexpo.val %2){ + // for example *vt=x^9, retry with *vt=x^4 + u=linear_integrate_nostep(pow(vtbase,vtexpo.val/2,contextptr),gen_x,tmprem,intmode|2,contextptr); + if (is_undef(u) || !is_zero(tmprem)) + continue; + if (!est_puissance){ + vecteur vv(v); + vv.erase(vv.begin()+i,vv.begin()+i+1); + fu=symbolic(at_prod,gen(vv,_SEQ__VECT)); + } + cst=extract_cst(u,gen_x,contextptr); + fu=fu*pow(vtbase,vtexpo.val-vtexpo.val/2,contextptr); + if (is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr)){ + fx=cst*fx; + if ( (intmode & 2)==0) + gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,u),contextptr); + e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); + remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,u,contextptr)*derive(u,gen_x,contextptr); + return complex_subst(e,gen_x,u,contextptr); + } + } + } + } +#ifdef LOGINT + *logptr(contextptr) << gettext("integrate step 3 ") << e << '\n'; +#endif + // Step3: rational fraction? + if (rvarsize==1){ + gen xvar(gen_x); + return integrate_rational(e,gen_x,remains_to_integrate,xvar,intmode,contextptr); + } + bool do_risch=true; + if (intmode & 4) do_risch=false; + for (size_t i=0;ifeuille,gen_x,a,b,contextptr)){ + // W(ax+b) inside, change of variables ax+b=z*exp(z) + // W(ax+b)=z, dx=(z+1)*exp(z)*dz/a + vecteur substin(makevecteur(vw[0],gen_x)); + vecteur substout(makevecteur(gen_x,(gen_x*symbolic(at_exp,gen_x)))); + gen tmpe=complex_subst(e,substin,substout,contextptr)*(gen_x+1)*symbolic(at_exp,gen_x)/a,tmprem; + gen tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); + substout[1]=symbolic(at_exp,gen_x); substin[1]=(a*gen_x+b)/vw[0]; + remains_to_integrate=complex_subst(tmprem,substout,substin,contextptr); + res=complex_subst(tmpres,substout,substin,contextptr); + return res; + } + } + // square roots + if ( (rvarsize==2) && (rvar.back().type==_SYMB) && (rvar.back()._SYMBptr->sommet==at_pow) ){ + // FIXME remove ==2, requires adding intmode parameter everywhere... + if (integrate_sqrt(e,gen_x,rvar,res,remains_to_integrate,intmode,contextptr)==2){ + if ( (intmode & 1)==0 && is_zero(res)){ + // try again with x->1/x? + gen e2=normal(-complex_subst(e,gen_x,inv(gen_x,contextptr),contextptr)/gen_x/gen_x,contextptr); + gen remains_to_integrate2,res2=integrate_id_rem(e2,gen_x,remains_to_integrate2,contextptr,1); + if (!is_zero(res2)){ + res=complex_subst(res2,gen_x,inv(gen_x,contextptr),contextptr); + remains_to_integrate=-complex_subst(remains_to_integrate2,gen_x,inv(gen_x,contextptr),contextptr)/gen_x/gen_x; + return res; + } + remains_to_integrate=e; + } + return res; + } + } + // detection of inv of trig or ln of a linear expression + if (detect_inv_trigln(e,rvar,gen_x,res,remains_to_integrate,true,intmode,contextptr)) + return res; + + // integration by part? + if ( (e._SYMBptr->sommet==at_prod) && (e._SYMBptr->feuille.type==_VECT)){ + const_iterateur ibp=e._SYMBptr->feuille._VECTptr->begin(),ibpend=e._SYMBptr->feuille._VECTptr->end(); + for (int j=0;ibp!=ibpend;++ibp,++j){ + int test; + if (ibp->type!=_SYMB) + continue; + if ( (ibp->_SYMBptr->sommet==at_pow) && + (ibp->_SYMBptr->feuille._VECTptr->front().type==_SYMB) && + (ibp->_SYMBptr->feuille._VECTptr->back().type==_INT_) && + (ibp->_SYMBptr->feuille._VECTptr->back().val>0) ) + test=equalposcomp(inverse_tab_op,ibp->_SYMBptr->feuille._VECTptr->front()._SYMBptr->sommet); + else + test=equalposcomp(inverse_tab_op,ibp->_SYMBptr->sommet); + if (!test) + continue; + vecteur ibpv(*e._SYMBptr->feuille._VECTptr); + ibpv.erase(ibpv.begin()+j); + gen ibpe=_prod(ibpv,contextptr); +#if 1 + gen tmpres,tmprem,tmpprimitive,tmp; + tmpprimitive=linear_integrate_nostep(ibpe,gen_x,tmp,intmode|2,contextptr); + if (is_zero(tmp)){ + vecteur tmpv=rlvarx(tmpprimitive,gen_x); + unsigned tmpi=0; + for (;tmpisommet)) + break; + } + if (tmpi==tmpv.size()){ + if ( (intmode & 2)==0) + gprintf(step_bypart,gettext("Integration of %gen: by part, u*v'=%gen*(%gen)'"),makevecteur(e,*ibp,tmpprimitive),contextptr); + tmpres=tmpprimitive*derive(*ibp,gen_x,contextptr); + tmpres=recursive_normal(tmpres,true,contextptr); + tmpres=linear_integrate_nostep(tmpres,gen_x,tmprem,intmode,contextptr); + remains_to_integrate=-tmprem; + return tmpprimitive*(*ibp)-tmpres; + } + } +#else + vecteur tmpv(1,gen_x); + lvar(ibpe,tmpv); + tmpv.erase(tmpv.begin()); + if (lvarx(tmpv,gen_x).empty()){ + gen tmpres,tmprem,tmpprimitive,tmp,xvar(gen_x); + tmpprimitive=integrate_rational(ibpe,gen_x,tmp,xvar,intmode,contextptr); + if (is_zero(tmp) && lvarx(tmpprimitive,gen_x)==vecteur(1,gen_x)){ + tmpres=tmpprimitive*derive(*ibp,gen_x,contextptr); + tmpres=recursive_normal(tmpres,true,contextptr); + tmpres=linear_integrate_nostep(tmpres,gen_x,tmprem,intmode,contextptr); + remains_to_integrate=-tmprem; + return tmpprimitive*(*ibp)-tmpres; + } + } +#endif + } + } + else { // check for u'=1 + int test; + if ( (e._SYMBptr->sommet==at_pow) && (e._SYMBptr->feuille._VECTptr->front().type==_SYMB) && (e._SYMBptr->feuille._VECTptr->back().type==_INT_) && (e._SYMBptr->feuille._VECTptr->back().val>0) ) + test=equalposcomp(inverse_tab_op,e._SYMBptr->feuille._VECTptr->front()._SYMBptr->sommet); + else + test=equalposcomp(inverse_tab_op,e._SYMBptr->sommet); + if (test){ + if ( (intmode & 2)==0) + gprintf(step_bypart1,gettext("Integration of %gen by part of u*v' where u=1 and v=%gen'"),makevecteur(e,e),contextptr); + gen tmpres,tmprem; + tmpres=normal(derive(e,gen_x,contextptr),contextptr); + tmpres=linear_integrate_nostep(gen_x*tmpres,gen_x,tmprem,intmode,contextptr); + if (!has_i(e) && has_i(tmpres)){ + remains_to_integrate=e; + return 0; + } + remains_to_integrate=-tmprem; + return gen_x*e-tmpres; + } + } + // additional check on e for f:= x*(x + 1)*(2*x*(x - (2*x**3 + 2*x**2 + x + 1)*log(x + 1))*exp(3*x**2) + (x**2*exp(2*x**2) - log(x + 1)**2)**2)/((x + 1)*log(x + 1)**2 - (x**3 + x**2)*exp(2*x**2))**2 + if (!is_elementary(rvar,gen_x) && detect_inv_trigln(e,rvar,gen_x,res,remains_to_integrate,false,intmode,contextptr)) + return res; + + // rewrite inv(exp) + vector vsubstin(1,at_inv); + vector vsubstout(1,invexptoexpneg); + e=subst(e,vsubstin,vsubstout,true,contextptr); // changed to true for numint of programs (otherwise e becomes undef) + // detection of denominator=independent of x + v=lvarxwithinv(e,gen_x,contextptr); + // search for nop (for nop[inv]) + if (!has_nop_var(v)){ + // additional check for non integer powers + v=lop(lvar(e),at_pow); + vecteur vx=lvarx(v,gen_x); + if (vx.empty() || vx==vecteur(1,gen_x)) + return integrate_linearizable(e,gen_x,remains_to_integrate,intmode,true,contextptr); + // second try with ^ rewritten as exp(ln) + gen etmp=pow2expln(e,contextptr); + v=lvarxwithinv(etmp,gen_x,contextptr); + // search for nop (for nop[inv]) + if (!has_nop_var(v)){ + // additional check for non integer powers + v=lop(lvar(etmp),at_pow); + vecteur vx=lvarx(v,gen_x); + if (vx.empty() || vx==vecteur(1,gen_x)) + return integrate_linearizable(etmp,gen_x,remains_to_integrate,intmode,true,contextptr); + } + } + // trigonometric fraction (or exp _FRAC), rewrite all elemnts of rvar as + // tan of the common half angle, i.e. tan([coeff_trig*x+b]/2) + int trig_fraction=-1; + gen coeff_trig; + vecteur var(lvarx(e,gen_x)); + const_iterateur vart=var.begin(),vartend=var.end(); + for (;vart!=vartend;++vart){ + if (vart->type!=_SYMB){ + trig_fraction=false; + continue; + } + int vartt=equalposcomp(primitive_tab_op,vart->_SYMBptr->sommet); + if ( (!vartt) || (vartt>4) ) + trig_fraction=0; + if (trig_fraction==-1){ + trig_fraction=vartt; + } + else { + if (trig_fraction==4){ + if (vartt!=4) + trig_fraction=0; + } + else { + if (vartt==4) + trig_fraction=0; + } + } + if (trig_fraction ){ // trig of linear? + gen a,b; + if (!is_linear_wrt(vart->_SYMBptr->feuille,gen_x,a,b,contextptr)){ + trig_fraction=false; + continue; + } + if (is_zero(coeff_trig)) + coeff_trig=a; + else { + gen quotient=ratnormal(rdiv(a,coeff_trig,contextptr),contextptr); + if (quotient.type==_INT_) + continue; + if ( (quotient.type==_FRAC) && (quotient._FRACptr->num.type==_INT_) && (quotient._FRACptr->den.type==_INT_) ){ + coeff_trig=ratnormal(rdiv(coeff_trig,quotient._FRACptr->den,contextptr),contextptr); + continue; + } + if ( (quotient.type==_SYMB) && (quotient._SYMBptr->sommet==at_inv) && (quotient._SYMBptr->feuille.type==_INT_)){ + coeff_trig=ratnormal(rdiv(coeff_trig,quotient._SYMBptr->feuille,contextptr),contextptr); + continue; + } + trig_fraction=false; + } + } // end if (trig_fraction) + } + if (trig_fraction){ + bool b=do_lnabs(contextptr); + if (has_i(e)) + do_lnabs(false,contextptr); + res=integrate_trig_fraction(e,gen_x,var,coeff_trig,trig_fraction,remains_to_integrate,intmode,contextptr); + do_lnabs(b,contextptr); + return res; + } + if (!do_risch){ + // Propfrac step + gen nd=_fxnd(e,contextptr); + if (nd.type==_VECT && nd._VECTptr->size()==2){ + gen num=nd[0],den=nd[1]; + vecteur propf=lvarx(den,gen_x); + gen_sort_f(propf.begin(),propf.end(),islesscomplexthanf); + nd=_quorem(makesequence(num,den,propf.back()),contextptr); + if (nd.type==_VECT && nd._VECTptr->size()==2){ + gen q=nd[0],r=nd[1]; + if (!is_zero(q) && !is_zero(r)){ + gen tmprem=0,tmpres; + tmpres = integrate_id_rem(q,*gen_x._IDNTptr,tmprem,contextptr,1); + // remains_to_integrate += tmprem; tmprem=0; + if (is_zero(tmprem)){ + tmpres += integrate_id_rem(r/den,*gen_x._IDNTptr,tmprem,contextptr,1); + // remains_to_integrate += tmprem; + if (is_zero(tmprem)) + return res+tmpres; + } + } + } + } + remains_to_integrate+=e; + return 0; + } + // finish by calling the Risch algorithm + if ( (intmode & 2)==0) + gprintf(step_risch,gettext("Integrate %gen, no heuristic found, running Risch algorithm"),makevecteur(e),contextptr); + res=risch(e,*gen_x._IDNTptr,remains_to_integrate,contextptr); + if (!is_zero(remains_to_integrate) && taille(e,100)>taille(remains_to_integrate,100)){ + e=remains_to_integrate; + res += integrate_id_rem(e,*gen_x._IDNTptr,remains_to_integrate,contextptr,0); + } + return res; + } + + gen linear_integrate(const gen & e,const gen & x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ + gen ee(normalize_sqrt(e,contextptr)); + return linear_apply(ee,x,remains_to_integrate,intmode,contextptr,integrate_gen_rem); + } + + gen linear_integrate_nostep(const gen & e,const gen & x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ + int step_infolevelsave=step_infolevel(contextptr); + if ((intmode & 2)==2) + step_infolevel(contextptr)=0; + // temporarily remove assumptions by changing integration variable + identificateur t("t_nostep"); + gen tt(t); + gen ee=quotesubst(e,x,tt,contextptr); + ee=normalize_sqrt(ee,contextptr); + gen res=linear_apply(ee,tt,remains_to_integrate,intmode,contextptr,integrate_gen_rem); + step_infolevel(contextptr)=step_infolevelsave; + res=quotesubst(res,tt,x,contextptr); + remains_to_integrate=quotesubst(remains_to_integrate,tt,x,contextptr); + return res; + } + + gen min2abs(const gen & g,GIAC_CONTEXT){ + if (g.type!=_VECT || g._VECTptr->size()!=2) + return symbolic(at_min,g); + gen a=g._VECTptr->front(),b=g._VECTptr->back(); + return (a+b-abs(a-b,contextptr))/2; + } + + gen max2abs(const gen & g,GIAC_CONTEXT){ + if (g.type!=_VECT || g._VECTptr->size()!=2) + return symbolic(at_min,g); + gen a=g._VECTptr->front(),b=g._VECTptr->back(); + return (a+b+abs(a-b,contextptr))/2; + } + + gen rewrite_minmax(const gen & e,bool quotesubst,GIAC_CONTEXT){ + vector vu; + vu.push_back(at_min); + vu.push_back(at_max); + vector vv; + vv.push_back(min2abs); + vv.push_back(max2abs); + return subst(e,vu,vv,quotesubst,contextptr); + } + + gen integrate_id(const gen & e,const identificateur & x,GIAC_CONTEXT){ + if (e.type==_VECT){ + vecteur w; + vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end(); + for (;it!=itend;++it) + w.push_back(integrate_id(*it,x,contextptr)); + return w; + } + gen remains_to_integrate; + gen ee=rewrite_hyper(e,contextptr); + ee=rewrite_minmax(ee,true,contextptr); + gen res=_simplifier(linear_integrate(ee,x,remains_to_integrate,0,contextptr),contextptr); + if (is_zero(remains_to_integrate)) + return res; + else + return res+symbolic(at_integrate,gen(makevecteur(remains_to_integrate,x),_SEQ__VECT)); + } + + static gen integrate0_(const gen & e,const identificateur & x,gen & remains_to_integrate,GIAC_CONTEXT){ + if (step_infolevel(contextptr)) + gprintf(step_integrate_header,gettext("===== Step/step primitive of %gen with respect to %gen ====="),makevecteur(e,x),contextptr); + if (e.type==_VECT){ + vecteur w; + vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end(); + for (;it!=itend;++it) + w.push_back(integrate_id(*it,x,contextptr)); + return w; + } + gen ee=rewrite_hyper(e,contextptr),tmprem; + ee=rewrite_minmax(ee,true,contextptr); + gen res=linear_integrate(ee,x,tmprem,0,contextptr); + if (!is_zero(tmprem)){ + ee = tmprem; + gen k=extract_cst(ee,x,contextptr); + if (ee.is_symb_of_sommet(at_plus)){ + res += k*integrate_gen_rem(ee,x,tmprem,0,contextptr); + tmprem = k*tmprem; + } + } + remains_to_integrate=remains_to_integrate+tmprem; + if (step_infolevel(contextptr) && is_zero(remains_to_integrate)) + gprintf(gettext("Hence primitive of %gen with respect to %gen is %gen"),makevecteur(e,x,res),contextptr); + return res; + } + + static gen integrate0(const gen & e,const identificateur & x,gen & remains_to_integrate,GIAC_CONTEXT){ + bool b_acosh=keep_acosh_asinh(contextptr); + keep_acosh_asinh(true,contextptr); + gen res=integrate0_(e,x,remains_to_integrate,contextptr); + keep_acosh_asinh(b_acosh,contextptr); + return res; + } + + gen integrate_gen(const gen & e,const gen & f,GIAC_CONTEXT){ + if (f.type!=_IDNT){ + identificateur x(" x"); + gen e1=subst(e,f,x,false,contextptr); + return quotesubst(integrate_id(e1,x,contextptr),x,f,contextptr); + } + return integrate_id(e,*f._IDNTptr,contextptr); + } + + bool adjust_int_sum_arg(vecteur & v,int & s){ + if (s<2) + return false; // setsizeerr(contextptr); + if ( (s==2) && (v[1].type==_SYMB) && (v[1]._SYMBptr->sommet==at_equal || v[1]._SYMBptr->sommet==at_equal2 || v[1]._SYMBptr->sommet==at_same)){ + v.push_back(v[1]._SYMBptr->feuille._VECTptr->back()); + v[1]=v[1]._SYMBptr->feuille._VECTptr->front(); + if ( (v[2].type!=_SYMB) || (v[2]._SYMBptr->sommet!=at_interval) ) + return false; // settypeerr(contextptr); + v.push_back(v[2]._SYMBptr->feuille._VECTptr->back()); + v[2]=v[2]._SYMBptr->feuille._VECTptr->front(); + s=4; + } + return true; + } + + static int ggb_intcounter=0; + + gen ck_int_numerically(const gen & f,const gen & x,const gen & a,const gen &b,const gen & exactvalue,GIAC_CONTEXT){ + if (is_inf(a) || is_inf(b)) + return exactvalue; + gen tmp=evalf_double(exactvalue,1,contextptr); +#if defined HAVE_LIBMPFR && !defined NO_STDEXCEPT + if ( (tmp.type==_DOUBLE_ || tmp.type==_CPLX) + && !has_i(lop(exactvalue,at_erf)) // otherwise it's slow + ){ + try { + tmp=evalf_double(accurate_evalf(exactvalue,256),1,contextptr); + } catch (std::runtime_error & err){ + last_evaled_argptr(contextptr)=NULL; + } + } +#endif + if (tmp.type!=_DOUBLE_ && tmp.type!=_CPLX) + return exactvalue; + if (debug_infolevel) + *logptr(contextptr) << gettext("Checking exact value of integral with numeric approximation")<<'\n'; + gen tmp2; + if (!tegral(f,x,a,b,1e-6,(1<<10),tmp2,true,contextptr)) + return exactvalue; + tmp2=evalf_double(tmp2,1,contextptr); + if ( (tmp2.type!=_DOUBLE_ && tmp2.type!=_CPLX) || + (abs(tmp,contextptr)._DOUBLE_val<1e-8 && abs(tmp2,contextptr)._DOUBLE_val<1e-8) || + abs(tmp-tmp2,contextptr)._DOUBLE_val<=1e-3*abs(tmp2,contextptr)._DOUBLE_val + ) + return simplifier(exactvalue,contextptr); + *logptr(contextptr) << gettext("Error while checking exact value with approximate value, returning both!") << '\n'; + return makevecteur(exactvalue,tmp2); + } + + void comprim(vecteur & v){ + vecteur w; + for (unsigned i=0;iglobalcontextptr!=contextptr) return assumeeval(x,contextptr->globalcontextptr); + if (x.type!=_IDNT) + return x.eval(1,contextptr); + gen evaled; + if (x._IDNTptr->in_eval(1,x,evaled,contextptr)) + return evaled; + return x; + } + + void restorepurge(const gen & xval,const gen & x,GIAC_CONTEXT){ + // if (contextptr && contextptr->globalcontextptr!=contextptr) restorepurge(xval,x,contextptr->globalcontextptr); + if (xval==x + // || (xval.type==_VECT && xval.subtype==_ASSUME__VECT && xval._VECTptr->size()==1 && xval._VECTptr->front().val==_SYMB) + ) + purgenoassume(x,contextptr); + else + sto(xval,x,contextptr); + } + +#if !defined USE_GMP_REPLACEMENTS && !defined BF2GMP_H + // small utility for ggb floats looking like fractions + void ggb_num_coeff(gen & g){ + if (g.type!=_FRAC || g._FRACptr->den.type!=_ZINT) + return; + mpz_t t; mpz_init_set(t,*g._FRACptr->den._ZINTptr); + while (mpz_divisible_ui_p(t,2)){ + mpz_divexact_ui(t,t,2); + continue; + } + while (mpz_divisible_ui_p(t,5)){ + mpz_divexact_ui(t,t,5); + continue; + } + if (mpz_cmp_ui(t,1)==0) + g=evalf(g,1,context0); + mpz_clear(t); + } +#endif + +#ifdef NO_STDEXCEPT + inline gen protect_integrate(const gen & args,GIAC_CONTEXT){ + return _integrate(args,contextptr); + } +#else + gen protect_integrate(const gen & args,GIAC_CONTEXT){ + gen res; + try { + res=_integrate(args,contextptr); + } catch (std::runtime_error & err){ + last_evaled_argptr(contextptr)=NULL; + res=string2gen(err.what(),false); + res.subtype=-1; + } + return res; + } +#endif + gen integrate_chknum(const gen & v0,const gen & x,gen & rem,GIAC_CONTEXT){ + gen primitive; + if (has_num_coeff(v0)){ + primitive=integrate0(exact(v0,contextptr),*x._IDNTptr,rem,contextptr); + primitive=evalf(primitive,1,contextptr); + rem=evalf(rem,1,contextptr); + } + else + primitive=integrate0(v0,*x._IDNTptr,rem,contextptr); + return primitive; + } + + // auto-assumptions assuming g is real-defined + // if an assumption is already made on a variable, it is ignored + vecteur autoassume(const gen & g_,const gen & x_,GIAC_CONTEXT){ + gen g=eval(g_,1,contextptr),x=eval(x_,1,contextptr); + vecteur v(rlvar(g,false)); + vecteur ass,res,bases; // list of assumptions and assumed idnt + for (int i=0;ifeuille; + const unary_function_ptr & u=v[i]._SYMBptr->sommet; + gen base,expo; + if (u==at_pow && f.type==_VECT && f._VECTptr->size()==2){ + base=f[0]; + expo=f[1]; + } + if (u==at_sqrt || u==at_ln){ + base=f; + expo=plus_one_half; + } + if (expo!=0){ + if (equalposcomp(bases,base)) + continue; + bases.push_back(base); + if (is_assumed_integer(expo,contextptr)) + continue; + if (expo.type==_FRAC && expo._FRACptr->den.type==_INT_ && (expo._FRACptr->den.val%2==1)) + continue; + vecteur varbase(lvar(base)); + if (varbase.size()>=1){ + vecteur lid=lidnt(base); + if (!lid.empty()){ + gen var=lid[0],a,b,c,hyp,varval; + if (equalposcomp(lid,x)) + var=x; + bool addi=equalposcomp(res,var); // additional hyp? + if (!addi) + varval=assumeeval(var,contextptr); + if (addi || varval==var){ + if (var.type==_IDNT && is_linear_wrt(base,var,a,b,contextptr) && !is_zero(a)){ + int as=fastsign(a,contextptr); + gen avar,aa,ab; vecteur av; + if (as==0){ + av=lidnt(a); + if (av.size()==1 && !equalposcomp(res,av[0]) && is_linear_wrt(a,av[0],aa,ab,contextptr)){ + as=fastsign(aa,contextptr); + if (as==1) + hyp=symb_superieur_strict(av[0],-ab/aa); + else if (as==-1) + hyp=symb_inferieur_strict(av[0],-ab/aa); + if (as){ + res.push_back(av[0]); + ass.push_back(hyp); + giac_assume(hyp,contextptr); + as=1; + } + } + } + if (as){ + av=lidnt(b); + if (av.size()==1 && !equalposcomp(res,av[0]) && is_linear_wrt(b,av[0],aa,ab,contextptr)){ + as=fastsign(aa,contextptr); + if (as==1) + hyp=symb_superieur_strict(av[0],-ab/aa); + else if (as==-1) + hyp=symb_inferieur_strict(av[0],-ab/aa); + if (as){ + res.push_back(av[0]); + ass.push_back(hyp); + giac_assume(hyp,contextptr); + as=1; + b=0; + } + } + } + if (as==1) + hyp=symb_superieur_strict(var,-b/a); + else if (as==-1) + hyp=symb_inferieur_strict(var,-b/a); + } // end linear case + else { + if (var.type==_IDNT && is_quadratic_wrt(base,var,a,b,c,contextptr) && !is_zero(a)){ + int as=fastsign(a,contextptr); + gen avar,aa,ab; vecteur av; + if (as==0){ + av=lidnt(a); + if (av.size()==1 && !equalposcomp(res,av[0]) && is_linear_wrt(a,av[0],aa,ab,contextptr)){ + as=fastsign(aa,contextptr); + if (as==1) + hyp=symb_superieur_strict(av[0],-ab/aa); + else if (as==-1) + hyp=symb_inferieur_strict(av[0],-ab/aa); + if (as){ + res.push_back(av[0]); + ass.push_back(hyp); + giac_assume(hyp,contextptr); + } + } + } // end as==0 + } // end quadratic + varbase=lvarx(base,var); + if (varbase.size()==1 && lidnt(base).size()==1){ + gen var0=varbase[0],addhyp; + bool dosolve=false; + if (var0.type==_IDNT) + dosolve=true; + if (var0.type==_SYMB){ + const unary_function_ptr & u=var0._SYMBptr->sommet; + gen varf=var0._SYMBptr->feuille; + if (varf.type!=_VECT && is_linear_wrt(varf,var,a,b,contextptr)){ // f(a*x+b), if f is trig assume in a*x+b in a period + int as=fastsign(a,contextptr); + if (as){ + if (u==at_sin || u==at_cos) + addhyp=cst_pi; + else if (u==at_tan) + addhyp=cst_pi/2; + else + addhyp=0; + if (addhyp!=0){ + if (as==1) + addhyp=symb_and(symb_superieur_strict(var,(-addhyp-b)/a),symb_inferieur_strict(var,(addhyp-b)/a)); + else if (as==-1) + addhyp=symb_and(symb_inferieur_strict(var,(-addhyp-b)/a),symb_superieur_strict(var,(addhyp-b)/a)); + } + dosolve=true; + } + } + } + if (dosolve){ + if (!is_zero(addhyp)){ + ass.push_back(addhyp); + if (addi) + giac_additionally(addhyp,contextptr); + else { + res.push_back(var); + giac_assume(addhyp,contextptr); + addi=true; + } + } + hyp=symbolic(at_solve,makesequence(symb_superieur_strict(base,0),var)); + hyp=protecteval(hyp,1,contextptr); + } + } + } + } + if (hyp.type==_SYMB){ + ass.push_back(hyp); + if (addi) + giac_additionally(hyp,contextptr); + else { + res.push_back(var); + giac_assume(hyp,contextptr); + } + } + if (hyp.type==_VECT){ + vecteur hypv=*hyp._VECTptr; + for (int j=hypv.size()-1;j>=0;--j){ + // j decreasing will give "simpler" auto-assumptions for trig + gen curhyp=hypv[j]; + if (curhyp.type!=_SYMB) + continue; + const unary_function_ptr & u=curhyp._SYMBptr->sommet; + if (u!=at_and && u!=at_ou && + u!=at_superieur_strict && u!=at_superieur_egal && + u!=at_inferieur_strict && u!=at_inferieur_egal) + continue; + ass.push_back(curhyp); + if (addi || j) + giac_additionally(curhyp,contextptr); + else { + res.push_back(var); + giac_assume(curhyp,contextptr); + addi=true; + } + break; // solve will return different intervals, we select one + } + } // end hyp.type==_VECT + } // end if lidnt(base) not empty + } // end if lvar(base).size()>=1 + } // end if expo!=0 + } + if (!ass.empty()) + *logptr(contextptr) << "Auto-assuming " << ass << "\n"; + return res; + } + + gen abs2piecewise(const gen & x,GIAC_CONTEXT){ + return symbolic(at_piecewise,makesequence(symbolic(at_inferieur_strict,x,0),-x,x)); + } + + gen min2piecewise(const gen & g,GIAC_CONTEXT){ + if (g.type!=_VECT || g._VECTptr->size()!=2) + return symbolic(at_min,g); + gen a=g._VECTptr->front(),b=g._VECTptr->back(); + return symbolic(at_piecewise,makesequence(symbolic(at_inferieur_strict,a,b),a,b)); + } + + gen max2piecewise(const gen & g,GIAC_CONTEXT){ + if (g.type!=_VECT || g._VECTptr->size()!=2) + return symbolic(at_min,g); + gen a=g._VECTptr->front(),b=g._VECTptr->back(); + return symbolic(at_piecewise,makesequence(symbolic(at_inferieur_strict,a,b),b,a)); + } + + gen whenmaxmin2piecewise(const gen & g,GIAC_CONTEXT){ + vector vu; + vu.push_back(at_min); + vu.push_back(at_max); + vector vv; + vv.push_back(min2piecewise); + vv.push_back(max2piecewise); + gen r=subst(g,vu,vv,true,contextptr); + r=when2piecewise(r,contextptr); + return r; + } + + bool has_undef(const gen & g){ + if (is_undef(g)) + return true; + if (g.type==_VECT){ + unsigned s=unsigned(g._VECTptr->size()); + for (unsigned i=0;icoord.size()); + for (unsigned i=0;icoord[i].value)) + return true; + } + return false; + } + if (g.type==_SYMB) + return has_undef(g._SYMBptr->feuille); + return false; + } + + gen _integrate_(const gen &args,GIAC_CONTEXT); + + // integrate w=[M,N]=Mdx+Ndy along curve, v=[x,y] + // or more generally w vector field along curve, v=[x1,..,xdim] + gen curviligne(const vecteur & w,const vecteur & v,const gen & curve,const gen & V,const gen & tmin_,const gen & tmax_,GIAC_CONTEXT){ + if (curve.type==_VECT){ + gen S=0; + vecteur c=*curve._VECTptr; + for (int i=0;ifeuille); + gen res=0; + for (int i=0;isize()==2){ + eq=c[0]+vx_var*(c[1]-c[0]); + t=vx_var; + if (is_undef(tmin)) + tmin=0; + if (is_undef(tmax)) + tmax=1; + } + else if (c.is_symb_of_sommet(at_cercle)){ + vecteur cv=gen2vecteur(c._SYMBptr->feuille); + if (cv.size()<3) + return undef; + if (is_undef(tmin)) + tmin=cv[1]; + if (is_undef(tmax)) + tmax=cv[2]; + cv=gen2vecteur(cv[0]); + eq=(cv[0]+cv[1])/2+(cv[1]-cv[0])/2*symb_exp(cst_i*vx_var); + t=vx_var; + } + else return undef; + } + vecteur vt; + if (v.size()==2){ + gen xt,yt; + reim(eq,xt,yt,contextptr); + vt=makevecteur(xt,yt); + } + else { + if (eq.type!=_VECT || eq._VECTptr->size()!=v.size()) + return gendimerr(contextptr); + vt=*eq._VECTptr; + } + if (!is_undef(V)) + return subst(V,v,subst(vt,t,tmax,false,contextptr),false,contextptr)-subst(V,v,subst(vt,t,tmin,false,contextptr),false,contextptr); + gen M=subst(w,v,vt,false,contextptr); + gen g=dotvecteur(M,derive(vt,t,contextptr),contextptr); + return _integrate_(makesequence(g,t,tmin,tmax),contextptr); + } + + gen curviligne(const vecteur & w,const vecteur & v,const gen & curve,const gen & tmin,const gen &tmax,GIAC_CONTEXT){ + gen V; + if (!is_potential(w,v,V,contextptr)) + V=undef; + return curviligne(w,v,curve,V,tmin,tmax,contextptr); + } + + gen _integrate_(const gen &args,GIAC_CONTEXT){ +#ifdef LOGINT + *logptr(contextptr) << gettext("integrate begin") << '\n'; +#endif + if (has_undef(args)) + return undef; + if ( args.type==_STRNG && args.subtype==-1) return args; + vecteur v(gen2vecteur(args)); + if (v.size()==1){ + gen a,b,c=eval(args,1,contextptr); + if (c.type==_SPOL1){ + sparse_poly1 res=*c._SPOL1ptr; + sparse_poly1::iterator it=res.begin(),itend=res.end(); + for (;it!=itend;++it){ + gen e=it->exponent+1; + if (e==0) + return sparse_poly1(1,monome(undef,undef)); + it->coeff=it->coeff/e; + it->exponent=e; + } + return res; + } + if (c.type==_VECT && c.subtype==_POLY1__VECT){ + vecteur v=*c._VECTptr; + reverse(v.begin(),v.end()); + v=integrate(v,1); + reverse(v.begin(),v.end()); + v.push_back(0); + return gen(v,_POLY1__VECT); + } + if (is_algebraic_program(c,a,b) && a.type!=_VECT) + return symbolic(at_program,makesequence(a,0,_integrate(gen(makevecteur(b,a),_SEQ__VECT),contextptr))); + if (calc_mode(contextptr)==1) + v.push_back(ggb_var(v.front())); + else + v.push_back(vx_var); + } + int s=int(v.size()); + if (!adjust_int_sum_arg(v,s)) + return gensizeerr(contextptr); + if (s>=4 && complex_mode(contextptr)){ + complex_mode(false,contextptr); + gen res=_integrate_(args,contextptr); + complex_mode(true,contextptr); + return res; + } + if (s==1) + return gentoofewargs("integrate"); + if (s==2){ + gen v0=eval(v[0],1,contextptr); + gen v1=eval(v[1],1,contextptr); + int t1=graph_output_type(v1); + if (v0.type==_VECT && v0._VECTptr->size()==2 && (t1==2 || v1.is_symb_of_sommet(at_union))) + return curviligne(*v0._VECTptr,makevecteur(x__IDNT_e,y__IDNT_e),v1,undef,undef,contextptr); + } + if (s==7){ + for (int i=0;isize()==2 && v[1]._VECTptr->size()==2){ + x=v[1]._VECTptr->front(); + y=v[1]._VECTptr->back(); + M=v[0]._VECTptr->front(); + N=v[0]._VECTptr->back(); + } + else { + x=x__IDNT_e; + y=y__IDNT_e; + M=v[0]; + N=v[1]; + } + gen xt=v[2],yt=v[3],t=v[4],tmin=v[5],tmax=v[6]; + gen xy=makevecteur(x,y); gen xyt=makevecteur(xt,yt),V; + if (is_potential(makevecteur(M,N),*xy._VECTptr,V,contextptr)) + return subst(V,xy,subst(xyt,t,tmax,false,contextptr),false,contextptr)-subst(V,xy,subst(xyt,t,tmin,false,contextptr),false,contextptr); + M=subst(M,xy,xyt,false,contextptr); + N=subst(N,xy,xyt,false,contextptr); + gen g=M*derive(xt,t,contextptr)+N*derive(yt,t,contextptr); + return _integrate_(makesequence(g,t,tmin,tmax),contextptr); + } + if (v.back()!=at_assume && (s==3 || s==5)){ + if (v[0].type==_IDNT && v[0]!=v[1]) + v[0]=eval(v[0],1,contextptr); + if (v[0].type==_VECT){ + if (v[1].type==_IDNT) + v[1]=eval(v[1],1,contextptr); + if (v[1].type==_VECT && v[0]._VECTptr->size()==v[1]._VECTptr->size()){ + if (v[2].type==_IDNT) + v[2]=eval(v[2],1,contextptr); + // integrate([M,N],[x,y],G) + return curviligne(*v[0]._VECTptr,*v[1]._VECTptr,v[2],s==3?undef:v[3],s==3?undef:v[4],contextptr); + } + } + if (s==3 && calc_mode(contextptr)!=1) + // indefinite integration with constant of integration + return _integrate(gen(makevecteur(v[0],v[1]),_SEQ__VECT),contextptr)+v[2]; + v.insert(v.begin()+1,ggb_var(eval(v.front(),1,contextptr))); + ++s; + } + if (s>6) + return gentoomanyargs("integrate"); + gen x=v[1]; + if (x.is_symb_of_sommet(at_unquote)) + x=eval(x,1,contextptr); + if (storcl_38 && x.type==_IDNT && storcl_38(x,0,x._IDNTptr->id_name,undef,false,contextptr,NULL,false)){ + identificateur t("t_"); + x=v[1]; + v[0]=quotesubst(v[0],x,t,contextptr); + v[1]=t; + gen res=_integrate(gen(v,_SEQ__VECT),contextptr); + return quotesubst(res,t,x,contextptr); + } + if (x.type!=_IDNT){ + if (x.type<_IDNT) + return gensizeerr(contextptr); + if (abs_calc_mode(contextptr)==38 && x.type!=_SYMB) + return gensizeerr(contextptr); + if (x.type==_SYMB && x._SYMBptr->sommet!=at_of && x._SYMBptr->sommet!=at_at) + return gensizeerr(contextptr); + identificateur t(" t"); + v[0]=quotesubst(v[0],x,t,contextptr); + v[1]=t; + gen res=_integrate(gen(v,_SEQ__VECT),contextptr); + return quotesubst(res,t,x,contextptr); + } + int quoted=0; + if (x._IDNTptr->quoted){ + quoted=*x._IDNTptr->quoted; + *x._IDNTptr->quoted=1; + } + for (int i=2;i2) + ggb_num_coeff(v[2]); + if (s>3) + ggb_num_coeff(v[3]); + } +#endif + if (s>=4){ // take care of boundaries when evaluating + if (v.back()==at_assume){ + --s; + v.pop_back(); + } + else { + gen xval=assumeeval(x,contextptr); + gen a(v[2]),b(v[3]); + if (evalf_double(a,1,contextptr).type==_DOUBLE_ && evalf_double(b,1,contextptr).type==_DOUBLE_){ + bool neg=false; + if (is_greater(v[2],v[3],contextptr)){ + a=v[3]; b=v[2]; + neg=true; + v[2]=a; v[3]=b; + } + vecteur lv=lop(lvarx(v[0],v[1]),at_pow); + for (int i=0;ifeuille._VECTptr->back(); + if (expo.type==_INT_ && expo.val>0){ + lv.erase(lv.begin()+i); + --i; + } + } + lv=mergevecteur(lv,lop(lvarx(v[0],v[1]),at_surd)); + lv=mergevecteur(lv,lop(lvarx(v[0],v[1]),at_NTHROOT)); + if (lv.size()==1 && v[1].type==_IDNT){ + gen powarg=lv[0][1]; + if (lv[0][0]==at_NTHROOT) + powarg=lv[0][2]; + lv=protect_solve(powarg,*v[1]._IDNTptr,0,contextptr); + for (int i=0;iquoted_global_vars && !is_assumed_real(x,contextptr)){ + contextptr->quoted_global_vars->push_back(x); + gen tmp=eval(v[0],eval_level(contextptr),contextptr); + tmp=Heavisidetopiecewise(tmp,contextptr); + if (!is_undef(tmp)) v[0]=tmp; + contextptr->quoted_global_vars->pop_back(); + } + else { + gen tmp=eval(v[0],eval_level(contextptr),contextptr); + tmp=Heavisidetopiecewise(tmp,contextptr); + if (!is_undef(tmp)) v[0]=tmp; + } +#else + try { + if (contextptr && contextptr->quoted_global_vars && !is_assumed_real(x,contextptr)){ + contextptr->quoted_global_vars->push_back(x); + gen tmp=eval(v[0],eval_level(contextptr),contextptr); + tmp=Heavisidetopiecewise(tmp,contextptr); + if (!is_undef(tmp)) v[0]=tmp; + contextptr->quoted_global_vars->pop_back(); + } + else { + gen tmp=eval(v[0],eval_level(contextptr),contextptr); + tmp=Heavisidetopiecewise(tmp,contextptr); + if (!is_undef(tmp)) v[0]=tmp; + } + } catch (std::runtime_error & err){ + last_evaled_argptr(contextptr)=NULL; + CERR << "Unable to eval " << v[0] << ": " << err.what() << '\n'; + } +#endif + keep_acosh_asinh(b_acosh,contextptr); + if (x._IDNTptr->quoted) + *x._IDNTptr->quoted=quoted; + if (s>4 || (approx_mode(contextptr) && (s==4)) ){ + v[1]=x; + return intnum(gen(v,_SEQ__VECT),false,contextptr,true); + } + gen rem,borne_inf,borne_sup,res,v0orig,aorig,borig; + if (s==4){ +#ifndef POCKETCAS + if ( (has_num_coeff(v[0]) || + v[2].type==_FLOAT_ || v[2].type==_DOUBLE_ || v[2].type==_REAL || + v[3].type==_FLOAT_ || v[3].type==_DOUBLE_ || v[3].type==_REAL)){ + vecteur ld=makevecteur(unsigned_inf,cst_pi); + // should first remove mute variables inside embedded sum/int/fsolve + lidnt(makevecteur(true_lidnt(v[0]),evalf_double(v[2],1,contextptr),evalf_double(v[3],1,contextptr)),ld,false); + ld.erase(ld.begin()); + ld.erase(ld.begin()); + if (ld==vecteur(1,v[1]) || ld.empty()) + return intnum(gen(makevecteur(v[0],v[1],v[2],v[3]),_SEQ__VECT),false,contextptr,true); + } +#endif + v0orig=v[0]; + aorig=borne_inf=v[2]; + borig=borne_sup=v[3]; + if (borne_inf==borne_sup) + return 0; + v[0]=ceil2floor(v[0],contextptr,true); + vecteur lfloor(lop(v[0],at_floor)); + lfloor=lvarx(lfloor,x); + if (!lfloor.empty()){ + gen a,b,l,cond=lfloor.front()._SYMBptr->feuille,tmp; + if (lvarx(cond,x).size()>1 || !is_linear_wrt(cond,x,a,b,contextptr) ){ + *logptr(contextptr) << gettext("Floor definite integration: can only handle linear < or > condition") << '\n'; + if (!tegral(v0orig,x,aorig,borig,1e-12,(1<<10),res,true,contextptr)) + return undef; + return res; + } + if (is_inf(borne_inf) || is_inf(borne_sup)){ + *logptr(contextptr) << gettext("Floor definite integration: unable to handle infinite boundaries") << '\n'; + } + else { + // find integers of the form a*x+b in [borne_inf,borne_sup] + gen n1=_floor(a*borne_inf+b,contextptr); + // n1=a*x+b -> x=(n1-b)/a + gen stepx,stepn; + if (is_positive(a,contextptr)){ + stepx=inv(a,contextptr); + stepn=1; + } + else { + stepx=-inv(a,contextptr); + stepn=-1; + } + gen cur=borne_inf,next=(n1+stepn-b)/a,res=0; + if (stepn==-1 && n1==a*borne_inf+b) + n1 -= 1; + for (;is_greater(borne_sup,next,contextptr); cur=next,next+=stepx,n1+=stepn){ + tmp=quotesubst(v[0],lfloor.front(),n1,contextptr); + res += _integrate(makesequence(tmp,x,cur,next),contextptr); +#ifdef TIMEOUT + control_c(); +#endif + if (ctrl_c || interrupted) { + interrupted = true; ctrl_c=false; + gensizeerr(gettext("Stopped by user interruption."),res); + return res; + } + if (is_undef(res)) + return res; + } + tmp=quotesubst(v[0],lfloor.front(),n1,contextptr); + res += _integrate(makesequence(tmp,x,cur,borne_sup),contextptr); + return ck_int_numerically(v0orig,x,aorig,borig,res,contextptr); + } + } + v[0]=whenmaxmin2piecewise(v[0],contextptr); + vecteur lpiece(lop(v[0],at_piecewise)); + lpiece=lvarx(lpiece,x); + if (!lpiece.empty()){ + bool chsign=is_strictly_greater(borne_inf,borne_sup,contextptr); + if (chsign) + swapgen(borne_inf,borne_sup); + res=0; + gen piece=lpiece.front(); + if (!piece.is_symb_of_sommet(at_piecewise)) + return gensizeerr(contextptr); + gen piecef=piece._SYMBptr->feuille; + if (piecef.type!=_VECT || piecef._VECTptr->size()<2) + return gensizeerr(contextptr); + vecteur & piecev = *piecef._VECTptr; + // check conditions: they must be linear wrt x + int vs=int(piecev.size()); + for (int i=0;ifeuille[0]-cond._SYMBptr->feuille[1]; + unable=false; + } + if (cond.is_symb_of_sommet(at_inferieur_strict) || cond.is_symb_of_sommet(at_inferieur_egal)){ + cond=cond._SYMBptr->feuille[1]-cond._SYMBptr->feuille[0]; + unable=false; + } + gen a,b,l; + if (unable || !is_linear_wrt(cond,x,a,b,contextptr)){ + *logptr(contextptr) << gettext("Piecewise definite integration: can only handle linear < or > condition") << '\n'; + if (!tegral(v0orig,x,aorig,borig,1e-12,(1<<10),res,true,contextptr)) + return undef; + return res; + } + // check if a*x+b>0 on [borne_inf,borne_sup] + l=-b/a; + bool positif=ck_is_greater(a,0,contextptr); + gen tmp=quotesubst(v[0],piece,piecev[2*i+1],contextptr); + if (ck_is_greater(l,borne_sup,contextptr)){ + // borne_inf < borne_sup <= l + if (positif) // test is false, continue + continue; + // test is true we can compute the integral + res += _integrate(gen(makevecteur(tmp,x,borne_inf,borne_sup),_SEQ__VECT),contextptr); + return ck_int_numerically(v0orig,x,aorig,borig,(chsign?-res:res),contextptr); + } + if (ck_is_greater(borne_inf,l,contextptr)){ + // l <= borne_inf < borne_sup + if (!positif) // test is false, continue + continue; + // test is true we can compute the integral + res += _integrate(gen(makevecteur(tmp,x,borne_inf,borne_sup),_SEQ__VECT),contextptr); + return ck_int_numerically(v0orig,x,aorig,borig,(chsign?-res:res),contextptr); + } + // borne_inffeuille,x,a,b,contextptr) && !is_zero(a) && !is_zero(b)) + break; + } + if (isommet(a*x,contextptr)); + v[0]=subst(v[0],vin,vout,false,contextptr); + } + } + } + if (s==2){ + primitive=integrate_chknum(v[0],x,rem,contextptr); + if (calc_mode(contextptr)==1){ + ++ggb_intcounter; + primitive += diffeq_constante(ggb_intcounter,contextptr); + } + if (is_zero(rem)) + return primitive; + return primitive + symbolic(at_integrate,gen(makevecteur(rem,x),_SEQ__VECT)); + } + // here s==4 + bool ordonne=is_greater(borne_sup,borne_inf,contextptr); + bool desordonne=false; +#ifdef NO_STDEXCEPT + if (ordonne){ + gen xval=assumeeval(x,contextptr); + giac_assume(symb_and(symb_superieur_egal(x,borne_inf),symb_inferieur_egal(x,borne_sup)),contextptr); + primitive=integrate_chknum(v[0],x,rem,contextptr); + primitive=eval(primitive,1,contextptr); + restorepurge(xval,x,contextptr); + res=limit(primitive,*x._IDNTptr,borne_sup,-1,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,1,contextptr); + } + else { + if ( (desordonne=is_greater(borne_inf,borne_sup,contextptr) )){ + gen xval=assumeeval(x,contextptr); + giac_assume(symb_and(symb_superieur_egal(x,borne_sup),symb_inferieur_egal(x,borne_inf)),contextptr); + primitive=integrate_chknum(v[0],x,rem,contextptr); + primitive=eval(primitive,1,contextptr); + restorepurge(xval,x,contextptr); + res=limit(primitive,*x._IDNTptr,borne_sup,1,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,-1,contextptr) ; + } + else { + primitive=integrate_chknum(v[0],x,rem,contextptr); + res=limit(primitive,*x._IDNTptr,borne_sup,0,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,0,contextptr); + } + } +#else + try { + if (ordonne){ + gen xval=assumeeval(x,contextptr); + giac_assume(symb_and(symb_superieur_egal(x,borne_inf),symb_inferieur_egal(x,borne_sup)),contextptr); + primitive=integrate_chknum(v[0],x,rem,contextptr); + primitive=eval(primitive,1,contextptr); + restorepurge(xval,x,contextptr); + gen ri=limit(primitive,*x._IDNTptr,borne_inf,1,contextptr); + gen rs=limit(primitive,*x._IDNTptr,borne_sup,-1,contextptr); + res=rs-ri; + } + else { + if ( (desordonne=is_greater(borne_inf,borne_sup,contextptr) )){ + gen xval=assumeeval(x,contextptr); + giac_assume(symb_and(symb_superieur_egal(x,borne_sup),symb_inferieur_egal(x,borne_inf)),contextptr); + primitive=integrate_chknum(v[0],x,rem,contextptr); + primitive=eval(primitive,1,contextptr); + restorepurge(xval,x,contextptr); + res=limit(primitive,*x._IDNTptr,borne_sup,1,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,-1,contextptr) ; + } + else { + primitive=integrate_chknum(v[0],x,rem,contextptr); + res=limit(primitive,*x._IDNTptr,borne_sup,0,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,0,contextptr); + } + } + } catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + *logptr(contextptr) << "Error trying to find limit of " << primitive << '\n'; + return symbolic(at_integrate,makesequence(v[0],x,borne_inf,borne_sup)); + } +#endif + if (!lop(res,at_bounded_function).empty()) + res=undef; + if (is_undef(res)){ + if (res.type==_STRNG && abs_calc_mode(contextptr)==38) + return res; + res=subst(primitive,*x._IDNTptr,borne_sup,false,contextptr)-subst(primitive,*x._IDNTptr,borne_inf,false,contextptr); + } + vecteur sp; + gen prim2(primitive); + // remove multiplicative constants to compute sp + if (prim2.is_symb_of_sommet(at_prod)){ + gen primf=prim2._SYMBptr->feuille; + if (primf.type==_VECT){ + vecteur primv=*primf._VECTptr,primv2; + for (int i=0;i1){ + *logptr(contextptr) << gettext("No checks were made for singular points of antiderivative ")+primitive.print(contextptr)+gettext(" for definite integration in [")+borne_inf.print(contextptr)+","+borne_sup.print(contextptr)+"]" << '\n' ; + sp.clear(); + } + else { + if ((is_inf(borne_inf) || evalf_double(borne_inf,1,contextptr).type==_DOUBLE_) + && (is_inf(borne_sup) || evalf_double(borne_sup,1,contextptr).type==_DOUBLE_)){ + gen xval=assumeeval(x,contextptr); + if (is_greater(borne_sup,borne_inf,contextptr)) + giac_assume(symb_and(symb_superieur_egal(x,borne_inf),symb_inferieur_egal(x,borne_sup)),contextptr); + else + giac_assume(symb_and(symb_superieur_egal(x,borne_sup),symb_inferieur_egal(x,borne_inf)),contextptr); + sp=protect_find_singularities(primitive,*x._IDNTptr,2,contextptr); + restorepurge(xval,x,contextptr); + if (!lidnt(evalf_double(sp,1,contextptr)).empty()) + return gensizeerr("Unable to handle singularities of "+ primitive.print(contextptr)+" at "+gen(sp).print(contextptr)); + } + else + sp=protect_find_singularities(primitive,*x._IDNTptr,0,contextptr); + if (is_undef(sp)){ + *logptr(contextptr) << gettext("Unable to find singular points of antiderivative") << '\n' ; + if (!tegral(v0orig,x,aorig,borig,1e-12,(1<<10),res,true,contextptr)) + return undef; + return res; + } + } + // FIXME if v depends on an integer parameter, find values in inf,sup + comprim(sp); + int sps=int(sp.size()); + for (int i=0;ifeuille); + if (g._SYMBptr->sommet!=at_pow) + return symbolic(g._SYMBptr->sommet,f); + if (f.type!=_VECT || f._VECTptr->size()!=2) + return symbolic(at_pow,f); + gen f1=f._VECTptr->back(); + if (f1.type==_DOUBLE_ && f1._DOUBLE_val==int(f1._DOUBLE_val)) + f1=int(f1._DOUBLE_val); + else if (f1.type==_FLOAT_ && f1._FLOAT_val==int(get_double(f1._FLOAT_val))) + f1=int(get_double(f1._FLOAT_val)); + else return symbolic(at_pow,f);; + return symbolic(at_pow,makesequence(f._VECTptr->front(),f1)); + } + // "unary" version + gen _integrate(const gen & args_,GIAC_CONTEXT){ + bool setcplx=false; + if (!complex_mode(contextptr)){ + // if there are ln inside, switch to complex mode + vecteur v; + gen x=vx_var,f=args_; + if (args_.type==_VECT && args_._VECTptr->size()>=2){ + f=(*args_._VECTptr)[0]; + x=(*args_._VECTptr)[1]; + } + f=eval(f,1,contextptr); + rlvarx(f,x,v); + for (int i=0;isommet==at_ln){ + gen f=g._SYMBptr->feuille; + if (f.type==_SYMB && (f._SYMBptr->sommet==at_exp || f._SYMBptr->sommet==at_abs)) + continue; + setcplx=true; + } + if (0 && g._SYMBptr->sommet==at_pow){ + gen f=g._SYMBptr->feuille[0]; + if (f.type==_SYMB && (f._SYMBptr->sommet==at_exp || f._SYMBptr->sommet==at_abs)) + continue; + setcplx=true; + } + } + } + gen args(exactify_pow(args_)); + if (complex_variables(contextptr)) + *logptr(contextptr) << gettext("Warning, complex variables is set, this can lead to fairly complex answers. It is recommended to switch off complex variables in the settings or by complex_variables:=0; and declare individual variables to be complex by e.g. assume(a,complex).") << '\n'; + vecteur ass; + if (auto_assume(contextptr)){ + if (args.type==_VECT && args._VECTptr->size()>=2) + ass=autoassume(args._VECTptr->front(),(*args._VECTptr)[1],contextptr); + else if (args.type==_SYMB || args.type==_IDNT) + ass=autoassume(args,vx_var,contextptr); + } + if (!ass.empty()){ + *logptr(contextptr) << "Run purge(" << ass << "); or purge(unquote(assumptions)) to clear auto-assumptions\n" ; + sto(ass,identificateur("assumptions"),contextptr); + } + if (setcplx) + complex_mode(true,contextptr); + if (args.type==_VECT && args._VECTptr->size()==4){ + vecteur v = *args._VECTptr; + gen x=v[1],a=v[2],b=v[3]; + if (x.type==_IDNT && a.type!=_DOUBLE_ && b.type!=_DOUBLE_){ + gen v0=evalf_double(v[0],1,contextptr),resapprox,tmp; + vecteur lv=lidnt(v0); + if (lv.size()==1 && lv[0]==x && has_evalf(a,tmp,1,contextptr) && has_evalf(b,tmp,1,contextptr) && tegral(v[0],x,a,b,1e-6,(1<<10),resapprox,false,contextptr)){ + *logptr(contextptr) << "// โˆซ ~= " << resapprox << "\n"; + } + } + } + gen res=_integrate_(args,contextptr); + if (setcplx) + complex_mode(false,contextptr); + if (0){ + for (int i=0;i T(n+1); + //ligne du triangle de romberg avec T(n)=aire avec "pts du milieu" + //avec 2^n subdivisions + double h; + gen at; + //at sert a faire les substitutions c'est un gen = au debut a f((a+b)/2) + //et en cours de prog egal a f(am) + gen a=a_orig,b=b_orig; + a=a.evalf(1,contextptr).evalf_double(1,contextptr); + b=b.evalf(1,contextptr).evalf_double(1,contextptr); + h=b._DOUBLE_val-a._DOUBLE_val; + if (h==0) + return 0; + //h est la longueur de la subdivision + //T[0] est l'aire du premier rectangle "pt milieu" f((a+b)/2)*(b-a) + //puis T[j] = aire des rectangles "pt milieu" pour 2^j subdivisions + double pui4; + for (int j=0;j<=n;j++){ + //chaque fois que j augmente de 1 on double le nombre de subdivisions + + double ss; + //ss est la somme provenant des valeurs de f aux points am ainsi rajoutes + ss=0; + gen am; + + am=a+gen(h/2); + if (is_exactly_zero(am-a)){ + n=j-1; + break; + } + while (is_greater(b,am,contextptr)){ + at=subst(f,x,am,false,contextptr).evalf(1,contextptr); + ss=ss+at._DOUBLE_val; + am=am+gen(h); + } + //T[j] est la nouvelle valeur de l'aire calculee avec les "pts milieu" + T[j]=ss*h; + + h=h/2; + } + //pui4 est la valeur de 4^k + pui4=1; + for (int j=1;j<=n;j++){ + pui4=pui4*4; + for (int k=0;k<=n-j;k++){ + //on calcule T[k] en appliquant la formule de rec. de romberg + //avec T[j] qui contient a chaque etape l'integrale par les pts milieu + T[k]=(pui4*T[k+1]-T[k])/(pui4-1); + + } + //on vient de remplir la kieme ligne on recommence avec j=j+1 + //on doit calculer les "pts du milieu" pour le nouv. j et le mettre ds T[j] + } + + + //c'est donc T[0] la meilleur approx de l'integrale + return(T[0]); + } + + // Not linked currently + double rombergt(const gen & f,const gen & x, const gen & a, const gen & b, int n,GIAC_CONTEXT){ + //f est l'expression a integrer, x le nom de la variable, a et b les bornes + // n si on veut faire 2^n subdivisions + vector T(n+1); + //ligne du triangle de romberg avec T(n)=trapezes avec 2^n subdivisions + double h; + gen at; + //at sert a faire les substitutions c'est un gen egal au debut a f(a)+f(b) + //et en cours de prog egal a f(am) + h=b.evalf(1,contextptr)._DOUBLE_val-a.evalf(1,contextptr)._DOUBLE_val; + if (h==0) + return 0; + //h est la longueur de la subdivision + at=subst(f,x,b,false,contextptr).evalf(1,contextptr)+subst(f,x,a,false,contextptr).evalf(1,contextptr); + T[0]=at._DOUBLE_val*h/2; + //T[0] est l'aire du premier trapeze (f(a)+f(b))*(b-a)/2 + //puis T[j] = aire des trapezes pour 2^j subdivisions + double pui4; + for (int j=1;j<=n;j++){ + //chaque fois que j augmente de 1 on double le nombre de subdivisions + h=h/2; + double ss; + //ss est la somme provenant des valeurs de f aux points am ainsi rajoutes + ss=0; + gen am; + am=a+gen(h); + if (is_exactly_zero(am-a)){ + n=j-1; + break; + } + while (is_greater(b,am,contextptr)){ + at=subst(f,x,am,false,contextptr).evalf(1,contextptr); + ss=ss+at._DOUBLE_val; + am=am+gen(2*h); + } + //T[j] est la nouvelle valeur de l'aire des trapezes + T[j]=T[j-1]/2+ss*h; + //pui4 est la valeur de 4^k + pui4=1; + for (int k=j-1;k>=0;k--){ + pui4=pui4*4; + //on calcule T[k] en appliquant la formule de rec. de romberg + //avec T[j] qui contient a chaque etape l'integrale par les trapezes + T[k]=(pui4*T[k+1]-T[k])/(pui4-1); + } + //on vient de remplir la kieme ligne on recommence avec j=j+1 + //on doit calculer les trapezes pour le nouveau j et le mettre ds T[j] + } + //c'est donc T[0] la meilleur approx de l'integrale + return(T[0]); + } + + // find approx value of int(f) using Gauss quadrature with s=15 (order 30) + // returns approx value of int(f), of int(abs(f)) and error estimate + // error estimated using embedded order 14 and 6 method as + // err1=abs(i30-i14); err2=abs(i30-i6); err1*(err1/err2)^2 +#if 0 + static bool tegral_util(const gen & f,const gen &x, const gen &a,const gen &b,gen & i30,gen & i30abs, gen &err,GIAC_CONTEXT){ + gen h=evalf_double(b-a,1,contextptr),i14,i6; + int s30=15,s14=14,s6=6; + long_double c30[]={0.60037409897572857552e-2,0.31363303799647047846e-1,0.75896708294786391900e-1,0.13779113431991497629,0.21451391369573057623,0.30292432646121831505,0.39940295300128273885,0.50000000000000000000,0.60059704699871726115,0.69707567353878168495,0.78548608630426942377,0.86220886568008502371,0.92410329170521360810,0.96863669620035295215,0.99399625901024271424}; + long_double b30[]={0.15376620998058634177e-1,0.35183023744054062355e-1,0.53579610233585967506e-1,0.69785338963077157224e-1,0.83134602908496966777e-1,0.93080500007781105513e-1,0.99215742663555788228e-1,0.10128912096278063644,0.99215742663555788228e-1,0.93080500007781105514e-1,0.83134602908496966777e-1,0.69785338963077157224e-1,0.53579610233585967507e-1,0.35183023744054062355e-1,0.15376620998058634177e-1}; + long_double b14[]={0.21474028217339757006e-1,0.14373155100418764102e-1,0.92599218105237092609e-1,0.11827741709315709983e-1,0.15847003639679458478,0.38429189419875016111e-2,0.19741290152890658991,0.19741290152890658991,0.38429189419875016111e-2,0.15847003639679458478,0.11827741709315709983e-1,0.92599218105237092608e-1,0.14373155100418764102e-1,0.21474028217339757006e-1}; + long_double b6[]={0.10715760948621577132,0.31130901929813818033e-1,0.36171148858397041065,0,0.36171148858397041065,0.31130901929813818033e-1,0.10715760948621577132}; + vecteur v30(15),v30abs(15); + for (int i=0;i<15;i++){ + v30[i]=evalf_double(subst(f,x,a+double(c30[i])*h,false,contextptr),1,contextptr); + v30abs[i]=_l2norm(v30[i],contextptr); + if (v30abs[i].type!=_DOUBLE_) + return false; + } + i30abs=i30=i14=i6=0; + for (int i=0;i<15;i++){ + i30 += double(b30[i])*v30[i]; + i30abs += double(b30[i])*v30abs[i]; + } + for (int i=0;i<=6;i++){ + i14 += double(b14[i])*v30[i]; + } + for (int i=8;i<=14;i++){ + i14 += double(b14[i-1])*v30[i]; + } + for (int i=1;i<15;i+=2){ + if (i==7) + continue; + i6 += double(b6[(i-1)/2])*v30[i]; + } + i30 = i30*h; + i30abs = i30abs*h; + i14 = i14*h; + i6 = i6*h; + gen err1=_l2norm(i30-i14,contextptr); + gen err2=_l2norm(i30-i6,contextptr); + // check if err1 and err2 corresponds to errors in h^14 and h^6 + if (is_greater(abs(14./6.-ln(err1,contextptr)/ln(err2,contextptr)),.1,contextptr)) + err=err1; + else { + err=err1/err2; + err=err1*(err*err); + } + return true; + } +#else // using -1..1 scaling instead of 0..1 + static bool tegral_util(const gen & f,const gen &x, const gen &a,const gen &b,gen & i30,gen & i30abs, gen &err,GIAC_CONTEXT){ + gen h=evalf_double(b-a,1,contextptr),i14,i6; + //int s30=15,s14=14,s6=6; + long_double c30[]={-0.98799251802048542849,-0.93727339240070590430,-0.84820658341042721620,-0.72441773136017004742,-0.57097217260853884754,-0.39415134707756336990,-0.20119409399743452230,0.00000000000000000000,0.20119409399743452230,0.39415134707756336990,0.57097217260853884754,0.72441773136017004742,0.84820658341042721620,0.93727339240070590430,0.98799251802048542849}; + long_double b30[]={0.15376620998058634177e-1,0.35183023744054062355e-1,0.53579610233585967506e-1,0.69785338963077157224e-1,0.83134602908496966777e-1,0.93080500007781105513e-1,0.99215742663555788228e-1,0.10128912096278063644,0.99215742663555788228e-1,0.93080500007781105514e-1,0.83134602908496966777e-1,0.69785338963077157224e-1,0.53579610233585967507e-1,0.35183023744054062355e-1,0.15376620998058634177e-1}; + long_double b14[]={0.21474028217339757006e-1,0.14373155100418764102e-1,0.92599218105237092609e-1,0.11827741709315709983e-1,0.15847003639679458478,0.38429189419875016111e-2,0.19741290152890658991,0.19741290152890658991,0.38429189419875016111e-2,0.15847003639679458478,0.11827741709315709983e-1,0.92599218105237092608e-1,0.14373155100418764102e-1,0.21474028217339757006e-1}; + long_double b6[]={0.10715760948621577132,0.31130901929813818033e-1,0.36171148858397041065,0,0.36171148858397041065,0.31130901929813818033e-1,0.10715760948621577132}; + vecteur v30(15),v30abs(15); + for (int i=0;i<15;i++){ + v30[i]=evalf_double(eval(subst(f,x,((a+b)+double(c30[i])*h)/2,false,contextptr),1,contextptr),1,contextptr); + v30abs[i]=_l2norm(v30[i],contextptr); + if (v30abs[i].type!=_DOUBLE_) + return false; + } + i30abs=i30=i14=i6=0; + for (int i=0;i<=7;i++){ + i30 += double(b30[i])*v30[i]; + if (i<7) + i30 += double(b30[14-i])*v30[14-i]; + i30abs += double(b30[i])*v30abs[i]; + if (i<7) + i30abs += double(b30[14-i])*v30abs[14-i]; + } + for (int i=0;i<=6;i++){ + i14 += double(b14[i])*v30[i]; + } + for (int i=8;i<=14;i++){ + i14 += double(b14[i-1])*v30[i]; + } + for (int i=1;i<15;i+=2){ + if (i==7) + continue; + i6 += double(b6[(i-1)/2])*v30[i]; + } + i30 = i30*h; + i30abs = i30abs*h; + i14 = i14*h; + i6 = i6*h; + gen err1=_l2norm(i30-i14,contextptr); + gen err2=_l2norm(i30-i6,contextptr); + if (is_exactly_zero(err1) || is_exactly_zero(err2)) + err=0; + else { + // check if err1 and err2 corresponds to errors in h^14 and h^6 + if (is_greater(abs(14./6.-ln(err1,contextptr)/ln(err2,contextptr)),.1,contextptr)) + err=err1; + else { + err=err1/err2; + err=err1*(err*err); + } + } + return true; + } +#endif + + bool approxint_exact(const gen &f,const gen &x,GIAC_CONTEXT){ + if (!lop(f,at_when).empty() || !lop(f,at_piecewise).empty()) + return false; + if (!loptab(Heavisidetosign(f,contextptr),sign_floor_ceil_round_tab).empty() ) + return false; + if (f.type!=_SYMB || is_constant_wrt(f,x,contextptr)) + return true; + unary_function_ptr & u=f._SYMBptr->sommet; + gen g=f._SYMBptr->feuille,a,b,c; + if (u==at_exp) + return is_quadratic_wrt(g,x,a,b,c,contextptr); + if (u==at_sin || u==at_cos) + return is_linear_wrt(g,x,a,b,contextptr); + if (g.type!=_VECT) return false; + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + if (u==at_plus){ + for (;it!=itend;++it){ + if (!approxint_exact(*it,x,contextptr)) + return false; + } + return true; + } + if (u==at_prod){ + for (;it!=itend;++it){ + if (is_constant_wrt(*it,x,contextptr)) + continue; + if (!is_zero(a)) + return false; + a=*it; + } + return approxint_exact(a,x,contextptr); + } + return false; + } + + // nmax=max number of subdivisions (may be 1000 or more...) + bool tegral(const gen & f,const gen & x,const gen & a_,const gen &b_,const gen & eps,int nmax,gen & value,bool exactcheck,GIAC_CONTEXT){ + gen a=evalf(a_,1,contextptr),b=evalf(b_,1,contextptr); + if (a==b){ + value=0.0; + return true; + } + if (exactcheck){ + vecteur vf(1,x); + rlvarx(f,x,vf); + if (0 && vf.size()<=1){ // dangerous + gen r,F=linear_integrate(exact(f,contextptr),x,r,0,contextptr); + value=_limit(makesequence(F,x,exact(b,contextptr),-1),contextptr)-_limit(makesequence(F,x,exact(a,contextptr),1),contextptr); + value=evalf(value,1,contextptr); + return true; + } + if (approxint_exact(f,x,contextptr)){ + gen r,F=linear_integrate(f,x,r,0,contextptr); + if (is_zero(r)){ + value=subst(F,x,b,false,contextptr)-subst(F,x,a,false,contextptr); + return true; + } + } + } + // adaptive integration, cf. Hairer + gen i30,i30abs,err,maxerr,ERR,I30ABS; + int maxerrpos; + if (!tegral_util(f,x,a,b,i30,i30abs,err,contextptr)) + return false; + vecteur v(1,makevecteur(a,b,i30,i30abs,err)); + for (;int(v.size())size()<5) + return false; + vecteur w=*v[i]._VECTptr; + i30 = i30+w[2]; // += does not work in emscripten + I30ABS = I30ABS+w[3]; + ERR = ERR+w[4]; + if (is_strictly_greater(w[4],maxerr,contextptr)){ + maxerrpos=i; + maxerr=w[4]; + } + } + value=i30; + // could add a minimal number of intervals for integrals like + // integrate(when(x > 2, 1,2),x,0,2.01) or int(frac(x),x,0,6.01) + // but one will always find intervals where this would fail + if (v.size()>=8 && !is_undef(ERR) && is_greater(eps,ERR/I30ABS,contextptr)) + return true; + // cut interval at maxerrpos in 2 parts + vecteur & w = *v[maxerrpos]._VECTptr; + gen A=w[0],B=w[1],C=(A+B)/2; + if (A==C || B==C){ + // can not subdivise anymore + if (is_greater(1e-4,ERR/I30ABS,contextptr)){ + *logptr(contextptr) << "Low accuracy, error estimate " << ERR/I30ABS << "\nError might be underestimated if initial boundary was +/-infinity" << '\n'; + return true; + } + return false; + } + if (!tegral_util(f,x,A,C,i30,i30abs,err,contextptr)){ + if (is_greater(1e-4,ERR/I30ABS,contextptr)){ + *logptr(contextptr) << "Low accuracy, error estimate " << ERR/I30ABS << "\nError might be underestimated if initial boundary was +/-infinity" << '\n'; + return true; + } + return false; + } + v[maxerrpos]=makevecteur(A,C,i30,i30abs,err); + if (!tegral_util(f,x,C,B,i30,i30abs,err,contextptr)){ + if (is_greater(1e-4,ERR/I30ABS,contextptr)){ + *logptr(contextptr) << "Low accuracy, error estimate " << ERR/I30ABS << "\nError might be underestimated if initial boundary was +/-infinity" << '\n'; + return true; + } + return false; + } + v.push_back(makevecteur(C,B,i30,i30abs,err)); + } + return false; // too many iterations + } + + gen romberg(const gen & f0,const gen & x0,const gen & a,const gen &b,const gen & eps,int nmax,GIAC_CONTEXT){ + return evalf_int(f0,x0,a,b,eps,nmax,true,contextptr,false); + } + gen evalf_int(const gen & f0,const gen & x0,const gen & a,const gen &b,const gen & eps,int nmax,bool romberg_method,GIAC_CONTEXT,bool exactcheck){ + gen x(x0),f(f0); + if (x.type!=_IDNT){ + x=identificateur(" x"); + f=subst(f,x0,x,false,contextptr); + } + gen value=undef; + if (!romberg_method && tegral(f,x,a,b,eps,(1 << nmax),value,exactcheck,contextptr)) + return value; + if (!romberg_method) + *logptr(contextptr) << "Adaptive method failure, will try with Romberg, last approximation was " << value << '\n'; + // a, b and eps should be evalf-ed, and eps>0 + gen h=b-a; + vecteur old_line,cur_line; +#ifdef NO_STDEXCEPT + old_line.push_back(evalf(h*(limit(f,*x._IDNTptr,a,1,contextptr)+limit(f,*x._IDNTptr,b,-1,contextptr))/2,eval_level(contextptr),contextptr)); +#else + try { + old_line.push_back(evalf(h*(limit(f,*x._IDNTptr,a,1,contextptr)+limit(f,*x._IDNTptr,b,-1,contextptr))/2,eval_level(contextptr),contextptr)); + } catch (std::runtime_error & ){ + last_evaled_argptr(contextptr)=NULL; + old_line=vecteur(1,undef); + } +#endif + if (is_inf(old_line[0])|| is_undef(old_line[0]) || !lop(old_line[0],at_bounded_function).empty()){ + // FIXME middle point in arbitrary precision + *logptr(contextptr) << gettext("Infinity or undefined limit at bounds.\nUsing middle point Romberg method") << '\n'; + gen y=(a+b)/2; + gen fy=subst(f,x,y,false,contextptr); + // Workaround for undefined middle point + if (is_undef(fy) || is_inf(fy)){ + fy=limit(f,*x._IDNTptr,y,0,contextptr); + if (is_undef(fy) || is_inf(fy)) + return undef; + } + old_line=vecteur(1,fy*h); + // At the i-th step of the loop compute the middle approx of the integral + // and use old_line to compute cur_line + nmax=int(2.*nmax/3.+0.5); + int n=3; + h=(b-a)/3; + for (int i=0;inmax/2 && (ck_is_greater(eps,err,contextptr) + || ck_is_greater(eps*abs(cur_line[i+1],contextptr),err,contextptr)) ) + return (old_line[i]+cur_line[i+1])/2; + if (i!=nmax-1) + old_line=cur_line; + } + if (calc_mode(contextptr)==1) + return undef; + *logptr(contextptr) << gettext("Unable to find numeric integral using Romberg method, returning the last approximations") << '\n'; + cur_line=is_undef(value)?makevecteur(old_line.back(),cur_line.back()):makevecteur(cur_line.back(),value); + return cur_line; + // return rombergo(f,x,a,b,nmax,contextptr); + } + int n=1; + // At the i-th step of the loop compute the trapeze approx of the integral + // and use old_line to compute cur_line + for (int i=0;inmax/2 && (ck_is_greater(eps,err,contextptr) + || ck_is_greater(eps*abs(cur_line[i+1],contextptr),err,contextptr)) ) + return (old_line[i]+cur_line[i+1])/2; + if (i!=nmax-1) + old_line=cur_line; + } + if (calc_mode(contextptr)==1) + return undef; + *logptr(contextptr) << gettext("Unable to find numeric integral using Romberg method, returning the last approximations") << '\n'; + cur_line=is_undef(value)?makevecteur(old_line.back(),cur_line.back()):makevecteur(cur_line.back(),value); + return cur_line; + } + gen ggb_var(const gen & f){ + vecteur l=lidnt(makevecteur(cst_pi,unsigned_inf,undef,f)); + l=vecteur(l.begin()+3,l.end()); + if (l.empty() || equalposcomp(l,vx_var)) + return vx_var; + const_iterateur it=l.begin(),itend=l.end(); + for (;it!=itend;++it){ + string s=it->print(context0); + if (s[s.size()-1]=='x') + return *it; + } + return l.front(); + } + gen intnum(const gen & args,bool romberg_method,GIAC_CONTEXT,bool exactcheck){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) + return gensizeerr(contextptr); + const_iterateur it=args._VECTptr->begin(),itend=args._VECTptr->end(); + gen f=*it; + ++it; + gen x=*it,a,b; + if (itfeuille; + if (a.type==_VECT && a._VECTptr->size()==2){ + x=a._VECTptr->front(); + a=a._VECTptr->back(); + if (a.is_symb_of_sommet(at_interval)){ + a=a._SYMBptr->feuille; + if (a.type==_VECT && a._VECTptr->size()==2){ + b=a._VECTptr->back(); + a=a._VECTptr->front(); + ok=true; + } + } + } + } + if (!ok) + return symbolic(at_integrate,args); + } + if (is_inf(a) || is_inf(b)){ // change of variables x=tan(t), t=atan(x) + gen tanx(tan(x,contextptr)); + f=subst(f,x,tanx,false,contextptr)*(1+pow(tanx,2)); + a=atan(a,contextptr); + b=atan(b,contextptr); + gen res=intnum(makesequence(f,x,a,b),romberg_method,contextptr,exactcheck); + if (!angle_radian(contextptr)) + { + if(angle_degree(contextptr)) + res=deg2rad_d*res; + //grad + else + res = grad2rad_d*res; + } + return res; + } + a=a.evalf(1,contextptr); + b=b.evalf(1,contextptr); + if (a.type==_FLOAT_) a=evalf_double(a,1,contextptr); + if (b.type==_FLOAT_) b=evalf_double(b,1,contextptr); + ++it; + gen eps(epsilon(contextptr)); + int n=11; + if (it!=itend){ + eps=evalf(abs(*it,contextptr),1,contextptr); + ++it; + if (it!=itend && it->type==_INT_) + n=it->val; + } + if (eps.type!=_DOUBLE_ && eps.type!=_FLOAT_ && eps.type!=_REAL) + eps=epsilon(contextptr); + if ( x.type!=_IDNT || + (a.type!=_DOUBLE_ && a.type!=_REAL) + || (b.type!=_DOUBLE_ && b.type!=_REAL) + ) + return symbolic(at_integrate,args); + return evalf_int(f,x,a,b,eps,n,romberg_method,contextptr,exactcheck); + } + gen _romberg(const gen & args,GIAC_CONTEXT) { + return intnum(args,true,contextptr,false); + } + static const char _romberg_s []="romberg"; + static define_unary_function_eval (__romberg,&_romberg,_romberg_s); + define_unary_function_ptr5( at_romberg ,alias_at_romberg,&__romberg,0,true); + + gen _gaussquad(const gen & args,GIAC_CONTEXT) { + return intnum(args,false,contextptr,false); + } + static const char _gaussquad_s []="gaussquad"; + static define_unary_function_eval (__gaussquad,&_gaussquad,_gaussquad_s); + define_unary_function_ptr5( at_gaussquad ,alias_at_gaussquad,&__gaussquad,0,true); + +/********************************************************************** +* Desc: Solve P(x+1)-P(x)=Q(x) +* Algo: degree of P=degree of Q+1, constant coeff 0 +* If P=Sigma a_k x^k then write linear system for a_k +* Columns of the matrix of the system are lines +* of the Pascal triangle without the first element +* (since we must subtract identity matrix to the triangle) +* a_1 a_2 a_3 ... a_n+1 coeff of Q +* 1 1 1 1 X^0 +* 0 2 3 n+1 X^1 +* 0 0 3 ... X^2 +* 0 0 0 n+1 X^n +**********************************************************************/ + static vecteur solveP_x_plus_1_minus_P_x(const vecteur & Q){ + vecteur v(1,plus_one); + matrice m; + int n=int(Q.size()); + for (int i=0;ilexsorted_degree())){ // polynomial w.r.t. x + vecteur Q; + if (r_num.type!=_POLY){ + res=r_num*v.front()/r2e(r,v,contextptr); + return true; + } + Q=polynome2poly1(*r_num._POLYptr,1); + vecteur P(solveP_x_plus_1_minus_P_x(Q)); + gen den; + lcmdeno(P,den,contextptr); // lcmdeno_converted? + r_num=poly12polynome(P,1,r_num._POLYptr->dim); + r=rdiv(r_num,r_den*den,contextptr); + res=r2e(r,v,contextptr); + return true; + } + // rational fraction wrt x + int s=r_den._POLYptr->dim; + polynome den(*r_den._POLYptr),num(s); + if (r_num.type==_POLY) + num=*r_num._POLYptr; + else + num=polynome(r_num,s); + polynome p_content(s); + // partial fraction decomposition + factorization vden; + gen extra_div=1; + factor(den,p_content,vden,false,/* withsqrt */false,/* complex */ true,1,extra_div); + vector< pf > pfdecomp; + polynome ipnum(s),ipden(s); + partfrac(num,den,vden,pfdecomp,ipnum,ipden); + // discrete antiderivative of integral part + vecteur Q(polynome2poly1(ipnum,1)); + vecteur P(solveP_x_plus_1_minus_P_x(Q)); + ipnum=poly12polynome(P,1,ipnum.dim); + r=rdiv(ipnum,ipden,contextptr); + res=r2e(r,v,contextptr); + int vdim=int(v.size()); + // detect integral shifted denominators + vector shiftfree_pfdecomp; + vector< pf >::iterator it=pfdecomp.begin(); + vector< pf >::const_iterator itend=pfdecomp.end(); + for (;it!=itend;++it){ + vecteur it_fact(polynome2poly1(it->fact,1)); + vector::iterator jt=shiftfree_pfdecomp.begin(); + vector::const_iterator jtend=shiftfree_pfdecomp.end(); + int k; + for (;jt!=jtend;++jt){ + if (is_shift_of(it_fact,jt->fact,k)) + break; + } + if (jt==jtend) + shiftfree_pfdecomp.push_back(pf1(it->num,it->den,it->fact,it->mult)); + else { // it_fact is the shift of jt->fact + vecteur it_num(polynome2poly1(it->num,1)),it_den(polynome2poly1(it->den,1)); + // check which one has the highest multiplicity + if (jt->multmult){ // we must swap to keep highest mult in *jt + std::swap(jt->num,it_num); + std::swap(jt->den,it_den); + std::swap(jt->fact,it_fact); + std::swap(jt->mult,it->mult); + k=-k; + } + // do the shift (this will modify jt->num and the result res) + int decal; + if (k<0){ + decal=1; + k=-k; + } + else + decal=-1; + for (int j=0;j0) + res=res-rdiv(r2e(poly12polynome(it_num,1,vdim),v,contextptr),r2e(poly12polynome(it_den,1,vdim),v,contextptr),contextptr); + it_num=taylor(it_num,decal); + it_den=taylor(it_den,decal); + if (decal<0) + res=res+rdiv(r2e(poly12polynome(it_num,1,vdim),v,contextptr),r2e(poly12polynome(it_den,1,vdim),v,contextptr),contextptr); + } + modpoly constante=jt->den/it_den; + gen const_den; + lcmdeno(constante,const_den,contextptr); // lcmdeno_converted? + // should check if constante is a fraction + jt->num=constante*it_num+const_den*jt->num; + jt->den=const_den*jt->den; + } // end else + } // end for (;it!=itend;++it) + // now add psi parts for every element of the shiftfree decomposition + vector::iterator jt=shiftfree_pfdecomp.begin(); + vector::const_iterator jtend=shiftfree_pfdecomp.end(); + for (;jt!=jtend;++jt){ + vecteur & jtfact = jt->fact; + // vecteur & jtnum = jt->num; + vecteur & jtden = jt->den; + if (jtfact.size()!=2){ // add to remains_to_sum + remains_to_sum=remains_to_sum+rdiv(r2e(poly12polynome(jt->num,1,vdim),v,contextptr),r2e(poly12polynome(jt->den,1,vdim),v,contextptr),contextptr); + } + else { + gen racine=-rdiv(jtfact.back(),jtfact.front(),contextptr); + vecteur dec=taylor(jt->num,racine); + vecteur vv=cdr_VECT(v); + gen coeff(plus_one); + int decal=int(jt->mult-dec.size()); + for (int i=0;imult;++i){ + if (i>=decal){ + if (!allow_psi) + return false; + res=res+r2e(rdiv(dec[i-decal],coeff*jtden.front(),contextptr),vv,contextptr)*Psi(x-r2e(racine,vv,contextptr),i,contextptr); + } + coeff=gen(-i-1)*coeff; + } + } + } // end for(;jt!=jtend;++jt) + return true; // end non constant denominator + } // end rational fraction or polynomial + + polynome taylor(const polynome & P,const gen & g){ + vecteur v(polynome2poly1(P,1)); + v=taylor(v,g); + return poly12polynome(v,1,P.dim); + } + + + vecteur decalage_(const polynome & A,const polynome & B){ + int s=A.dim; + // find integer roots of resultant of A(x),B(x+t) with respect to x + vecteur l(s); + for (int i=0;i(A,b),l,context0); + bb=taylor(bb,1); + } + gen resu=_lagrange(makesequence(x,y,l.front()),context0); + resu=e2r(resu,l,context0); + if (resu.type!=_POLY) + return vecteur(0); + polynome pres=*resu._POLYptr; + // Make the list of the positive integer roots k in t of the resultant + return iroots(pres); + } + // IMPROVE: eval A and B at other variables to detect possible integer roots + // then try gcd(A(x),B(x+t)) + vecteur decalage(const polynome & A,const polynome & B){ + int s=A.dim; + if (s==1) + return decalage_(A,B); + vecteur l(s),L(s); + for (int i=0;i > > vA(Tsqff_char0(A)),vB(Tsqff_char0(B)); + std::vector< facteur< tensor > >::const_iterator itA=vA.begin(),itAend=vA.end(),itB=vB.begin(),itBend=vB.end(); + vecteur racines; + for (;itA!=itAend;++itA){ + for (;itB!=itBend;++itB){ + racines=mergeset(racines,decalage(itA->fact,itB->fact)); + } + } +#else + polynome a(A.untrunc1()); // add the t parameter + polynome b(B.untrunc1()); + // exchange var 1 (parameter t) and 2 (x variable) + vector i=transposition(0,1,s+1); + a.reorder(i); + b.reorder(i); + // now translate b by t + vecteur bb(polynome2poly1(b,1)); + polynome t(monomial(plus_one,1,1,s)); + bb=taylor(bb,t); + b=poly12polynome(bb,1,s+1); + polynome pres=Tresultant(a,b); + pres=pres.trunc1(); + // Make the list of the positive integer roots k in t of the resultant + vecteur racines(iroots(pres)); +#endif + // The algorithm begins with P0=1 Q0=A R0=B + P=polynome(monomial(plus_one,s)); + Q=A; + R=B; + int d=int(racines.size()); + for (int i=0;ir then y=p-q, if q(Q),rr=Tfirstcoeff(R); + if (q==r && qq==rr){ // cancellation + ++p; + y=p-giacmax(q,r); + if (q>0){ + vecteur vq=polynome2poly1(Q,1),vr=polynome2poly1(R,1); + gen ydeg=(vr[1]-vq[1])/qq;//gen ydeg=(vr[q-1]-vq[q-1])/qq; + if (ydeg.type==_INT_ && ydeg.val>y){ + y=ydeg.val; + p=y+q-1; + } + } + } + else + y=p-giacmax(q,r); + if (y<0) + return false; + // Then solve a linear system with p+1 equations and y+1 unknowns + // (p+1 rows, y+1 columns) + // built the matrix of the system column by column + // the column i is (X+1)^i*Q-X^i*R + vecteur v(1,plus_one); // this will contain (X+1)^i using pascal_next_line + vecteur w(v); // this is X^i + matrice m; + for (int i=0;i<=y;++i){ + vecteur current=v*vQ-w*vR; + // adjust current size to p + lrdm(current,p); + m.push_back(current); + v=pascal_next_line(v); + w.push_back(zero); + } + reverse(m.begin(),m.end()); // higher coeff at the beginning + // last column is P + lrdm(vP,p); + m.push_back(vP); + m=mtran(m); + int st=step_infolevel(contextptr); + step_infolevel(contextptr)=0; + m=mrref(m,contextptr); + step_infolevel(contextptr)=st; + vecteur res(y+1); + for (int i=0;i<=y;++i){ + if (is_zero(m[i][i])) + return false; + res[i]=m[i][y+1]/m[i][i]; + } + lcmdeno(res,deno,contextptr); // lcmdeno_converted? + Y=poly12polynome(res,1,P.dim); + return p==y || is_zero(m[y+1]); + // Or alternatively do a Rothstein-Trager like method if Q non constant + // Let P = Q U + R V with deg(V)feuille,x,a,b,contextptr)) + return false; + } + gen ratio=subst(e,x,x+1,false,contextptr)/e; + ratio=simplify(ratio,contextptr); + if (is_undef(ratio)) + return false; + v=lvarx(makevecteur(ratio,x),x); + if ( (v.size()!=1) || (v.front()!=x) ){ + ratio=simplify(_texpand(ratio,contextptr),contextptr); + v=lvarx(makevecteur(ratio,x),x); + if ( (v.size()!=1) || (v.front()!=x) ) + return false; + } + lvar(ratio,v); + for (unsigned i=1;inum,s); + B=gen2poly(f._FRACptr->den,s); + } + else { + A=gen2poly(f,s); + B=gen2poly(plus_one,s); + } + AB2PQR(A,B,P,Q,R); // A/B as E[P]/P*Q/E[R] + return true; + } + + static gen inner_sum(const gen & e,const gen & x,gen & remains_to_sum,int intmode,GIAC_CONTEXT){ + gen res; + if (rational_sum(e,x,res,remains_to_sum,true,contextptr)) + return res; + polynome P,Q,R; + vecteur v; + if (!is_hypergeometric(e,*x._IDNTptr,v,P,Q,R,contextptr)){ + remains_to_sum=e; + return zero; + } + int s=int(v.size()); + gen deno; + polynome Y(s); + if (!gosper(P,Q,R,Y,deno,contextptr)){ + remains_to_sum=e; + return zero; + } + remains_to_sum=zero; + gen facteur=r2e(Y*R,v,contextptr)/r2e(P,v,contextptr)/r2e(deno,vecteur(v.begin()+1,v.end()),contextptr); + return simplify(e*facteur,contextptr); + } + + // discrete antiderivative + gen sum(const gen & e,const gen & x,gen & remains_to_sum,GIAC_CONTEXT){ + if (x.type!=_IDNT) + return gensizeerr(contextptr); + vecteur v=lvarx(e,x); + v=loptab(v,sincostan_tab); + // keep only sincostan which are linear wrt x + vecteur newv(v); + v.clear(); + int s=int(newv.size()); + for (int i=0;ifeuille,x,a,b,contextptr)) + v.push_back(newv[i]); + } + if (!v.empty()){ + gen w=trig2exp(v,contextptr); + gen e1=_lin(subst(e,v,*w._VECTptr,true,contextptr),contextptr); + return _simplify(_evalc(linear_apply(e1,x,remains_to_sum,0,contextptr,inner_sum),contextptr),contextptr); + } + else + return linear_apply(e,x,remains_to_sum,0,contextptr,inner_sum); + } + + // discrete antiderivative evaluated + gen sum_loop(const gen & e,const gen & x,int i,int j,GIAC_CONTEXT){ + gen f(e),res; + if (i>j){ + int tmp=j; + j=i-1; + i=tmp+1; + f=-e; + } + for (;i<=j;++i){ + res=res+subst(f,x,i,false,contextptr).eval(eval_level(contextptr),contextptr); + } + return res; + } + + gen sum(const gen & e,const gen & x,const gen & a,const gen &b,GIAC_CONTEXT){ + if ( (a.type==_INT_) && (b.type==_INT_) && (absint(b.val-a.val)<100) ) + return sum_loop(e,x,a.val,b.val,contextptr); + gen res; + if ( sumab(e,x,a,b,res,true,contextptr) ) + return res; + gen remains_to_sum; +#if defined EMCC || defined GIAC_HAS_STO_38 + res=sum(e,x,remains_to_sum,contextptr); +#else + gen oldx=eval(x,1,contextptr),X(x); + if (!assume_t_in_ab(X,a,b,false,false,contextptr)) + return gensizeerr(contextptr); + res=sum(e,x,remains_to_sum,contextptr); + sto(oldx,X,contextptr); +#endif + gen tmp1=( (is_inf(b) && x.type==_IDNT)?limit(res,*x._IDNTptr,b,0,contextptr):subst(res,x,b+1,false,contextptr)); + gen tmp2=(is_inf(a) && x.type==_IDNT)?limit(res,*x._IDNTptr,a,0,contextptr):subst(res,x,a,false,contextptr); + res=tmp1-tmp2; + if (is_zero(remains_to_sum)) + return res; + if ( (a.type==_INT_) && (b.type==_INT_) && (absint(b.val-a.val)1 && v[1].type==_INT_){ + debut=giacmax(1,v[1].val); + if (s>2 && v[2].type==_INT_) + fin=v[2].val; + v=*v[0]._VECTptr; + s=int(v.size()); + fin=giacmin(s,fin); + } + gen res; + if (isprod){ + res=plus_one; + for (--debut;debuttabptr)[i.id_name]=value; + else + i.localvalue->back()=value; + } + + static void local_sto_increment(const gen & value,const identificateur & i,GIAC_CONTEXT){ + if (contextptr) + (*contextptr->tabptr)[i.id_name] += value; + else + i.localvalue->back() += value; + } + + static void local_sto_int(int value,const identificateur & i,GIAC_CONTEXT){ + if (contextptr) + (*contextptr->tabptr)[i.id_name].val=value; + else + i.localvalue->back().val=value; + } + + static void local_sto_int_increment(int value,const identificateur & i,GIAC_CONTEXT){ + if (contextptr) + (*contextptr->tabptr)[i.id_name].val += value; + else + i.localvalue->back().val += value; + } +#endif + + // type=0 for seq, 1 for prod, 2 for sum + gen seqprod(const gen & g,int type,GIAC_CONTEXT){ + vecteur v(gen2vecteur(g)); + if (v.size()==1) + v=gen2vecteur(eval(g,contextptr)); + if (v.size()<4){ + gen v2; + if (v.size()==3) + v2=eval(v[2],1,contextptr); + if (type==0 && v.size()==3 && v2.type==_VECT){ + // for example seq(2^k,k,[1,2,5]) + gen f=_unapply(makesequence(v[0],v[1]),contextptr); + return _map(makesequence(v2,f),contextptr); + } + if (v.size()==3 && v[1].is_symb_of_sommet(at_equal) && v[1]._SYMBptr->feuille[1].is_symb_of_sommet(at_interval)){ + gen f=v[1]._SYMBptr->feuille; + gen v1=f[0]; + gen v2=f[1]._SYMBptr->feuille[0],v3=f[1]._SYMBptr->feuille[1]; + return change_subtype(seqprod(makevecteur(v[0],v1,v2,v3,v[2]),type,contextptr),_SEQ__VECT); + } + if (v.size()==3 && !v[1].is_symb_of_sommet(at_equal) && g.subtype==_SEQ__VECT) + return change_subtype(seqprod(gen(makevecteur(symb_interval(v[0],v[1]),v[2]),_SEQ__VECT),type,contextptr),0); + if (type==0) + return _dollar(g,contextptr); + if (type==1) + return prodsum(v,true); + if (type==2) + return prodsum(v,false); + return gentoofewargs(""); + } + // v[1]=eval(v[1]); + v[2]=eval(v[2],contextptr); + v[3]=eval(v[3],contextptr); + gen step=1; + gen tmp; + if (v.size()==5) + step=eval(v[4],contextptr); + if (is_zero(step)) + return gensizeerr(contextptr); + if (!is_integral(v[3]) || !is_integral(v[2])){ + if (v.size()==4 && g.subtype==_SEQ__VECT){ + if (type==1) + return symbolic(at_product,g); + return gentypeerr(contextptr); + } + if (type==1 && (g.subtype!=_SEQ__VECT || v.size()!=5)) + return prodsum(v,true); + if (type==2 && (g.subtype!=_SEQ__VECT || v.size()!=5)) + return prodsum(v,false); + } + // This will not work if v[0] has auto-quoting functions inside + // because arguments are not evaled, hence replacement of v[1] by value + // is not done inside arguments. + // Example Ya:=desolve([y'+x*y=0,y(0)=a]); seq(plot(Ya),a,1,3); + gen debut=v[2],fin=v[3]; + if (is_greater(abs(fin-debut),type?max_sum_add(contextptr):LIST_SIZE_LIMIT,contextptr)) + return gendimerr(contextptr); + vecteur res; + double S=0,C=0; bool sumdouble=0; // 1 means adding double + if (is_strictly_greater(debut,fin,contextptr)){ + if (is_positive(step,contextptr)) + step=-step; + for (;!ctrl_c && !interrupted && is_greater(debut,fin,contextptr);debut=debut+step){ +#ifdef TIMEOUT + control_c(); +#endif + tmp=quotesubst(v[0],v[1],debut,contextptr); + tmp=eval(tmp,contextptr); + tmp=quotesubst(tmp,v[1],debut,contextptr); +#ifdef RTOS_THREADX + tmp=evalf(tmp,1,contextptr); +#endif + if (!res.empty() && res.back().type<_POLY ){ + if (type==1){ + res.back() = res.back()*tmp; + continue; + } + if (type==2){ + res.back() += tmp; + continue; + } + } + res.push_back(tmp); + } // for + } + else { + if (!is_greater(fin,debut,contextptr)) + return gensizeerr((gettext("Unable to sort boundaries ")+debut.print(contextptr))+(","+fin.print(contextptr))); + if (is_positive(-step,contextptr)) + step=-step; + for (;!ctrl_c && !interrupted && is_greater(fin,debut,contextptr);debut=debut+step){ +#ifdef TIMEOUT + control_c(); +#endif + tmp=quotesubst(v[0],v[1],debut,contextptr); + tmp=eval(tmp,contextptr); + tmp=quotesubst(tmp,v[1],debut,contextptr); +#ifdef RTOS_THREADX + tmp=evalf(tmp,1,contextptr); +#endif + if (!res.empty() && res.back().type<_POLY){ + if (sumdouble){ + if (tmp.type==_DOUBLE_){ + double d=tmp._DOUBLE_val; + if (d==0) continue; +#ifndef DOUBLEVAL + unsigned char * u = (unsigned char *)(&d); + *u &= 0xe0; + *u |= 0x10; // nearest rounding +#endif + double add=S+d; + C += S-(add-d); + S = add; + } + else { + sumdouble=false; + res.back()=S+C; + res.back() += tmp; + } + continue; + } + if (type==1){ + res.back() = res.back()*tmp; + continue; + } + if (type==2){ + res.back() += tmp; +#ifndef BIGENDIAN + if (res.back().type==_DOUBLE_){ + sumdouble=true; + S=res.back()._DOUBLE_val; + C=0; + } +#endif + continue; + } + } + res.push_back(tmp); + } //for + } + if (type==1) + return _prod(res,contextptr); + if (type==2){ + if (sumdouble) + res.back()=S+C; + return _plus(res,contextptr); + } + return res;// return gen(res,_SEQ__VECT); + } + +#if 0 + static identificateur independant_identificateur(const gen & g){ + string xname(" x"+g.print(context0)); + identificateur x(xname); + return x; + } + + // type=0 for seq, 1 for prod, 2 for sum + static gen seqprod2(const gen & g,int type,GIAC_CONTEXT){ + vecteur v(gen2vecteur(g)); + if (v.size()==1) + v=gen2vecteur(eval(g,eval_level(contextptr),contextptr)); + if (v.size()<4){ + if (type==0) + return _dollar(g,contextptr); + if (type==1) + return prodsum(v,true); + if (type==2) + return prodsum(v,false); + return gentoofewargs(""); + } + // v[1]=eval(v[1]); + v[2]=eval(v[2],eval_level(contextptr),contextptr); + v[3]=eval(v[3],eval_level(contextptr),contextptr); + gen step=1; + gen tmp; + if (v.size()==5) + step=eval(v[4],eval_level(contextptr),contextptr); + if (is_zero(step)) + return gensizeerr(contextptr); + if (v[3].type!=_INT_ || v[2].type!=_INT_){ + if (type==1) + return prodsum(v,true); + if (type==2) + return prodsum(v,false); + } + gen debut=v[2],fin=v[3]; + vecteur res; + gen nstep=evalf_double((fin-debut)/step,1,contextptr); + if (nstep.type!=_DOUBLE_) + return gensizeerr(gettext("Bad step")); + res.reserve(int(absdouble(nstep._DOUBLE_val))+1); + identificateur x=independant_identificateur(v[0]); + tmp=quotesubst(v[0],v[1],x,contextptr); + gen tmpev=eval(tmp,eval_level(contextptr),contextptr); + gen a,b; + if (is_linear_wrt(tmpev,x,a,b,contextptr)){ + if (is_strictly_greater(debut,fin,contextptr)){ + if (is_positive(step,contextptr)) // correct pos step to - + step=-step; + for (;is_greater(debut,fin,contextptr);debut+=step){ + res.push_back(a*debut+b); + } + } + else { + if (is_positive(-step,contextptr)) // correct negative step to + + step=-step; + if (step.type==_INT_){ + int D=debut.val,F=fin.val,S=step.val; + for (;D<=F;D+=S){ + res.push_back(D*a+b); + } + } + else { + for (;is_greater(fin,debut,contextptr);debut+=step){ + res.push_back(a*debut+b); + } + } + } + } + else { + int level=eval_level(contextptr); + context * newcontextptr= (context *) contextptr; + vecteur localvar(1,x); + int protect=bind(vecteur(1,debut),localvar,newcontextptr); + if (is_strictly_greater(debut,fin,newcontextptr)){ + if (is_positive(step,newcontextptr)) // correct pos step to - + step=-step; + if (step.type==_INT_){ + int D=debut.val,F=fin.val,S=step.val; + for (;D>=F;D+=S){ + res.push_back(tmp.eval(level,newcontextptr)); + local_sto_int_increment(S,x,newcontextptr); + } + } + else { + for (;is_greater(debut,fin,newcontextptr);debut+=step){ + local_sto(debut,x,newcontextptr); + res.push_back(tmp.eval(level,newcontextptr)); + } + } + } + else { + if (is_positive(-step,newcontextptr)) // correct negative step to + + step=-step; + if (step.type==_INT_){ + int D=debut.val,F=fin.val,S=step.val; + for (;D<=F;D+=S){ + res.push_back(tmp.eval(level,newcontextptr)); + local_sto_int_increment(S,x,newcontextptr); + } + } + else { + for (;is_greater(fin,debut,newcontextptr);debut+=step){ + local_sto(debut,x,newcontextptr); + res.push_back(tmp.eval(level,newcontextptr)); + } + } + } + leave(protect,localvar,newcontextptr); + } // end is_linear + if (type==1) + return _prod(res,contextptr); + if (type==2) + return _plus(res,contextptr); + return res;// return gen(res,_SEQ__VECT); + } +#endif + + bool maple_sum_product_unquote(vecteur & v,GIAC_CONTEXT){ + bool res=false; + int s=int(v.size()); + if (s<2) + return false; // setsizeerr(contextptr); + if (v[0].is_symb_of_sommet(at_quote)) + v[0]=v[0]._SYMBptr->feuille; + if (v[1].type!=_IDNT){ + if (is_equal(v[1]) && v[1]._SYMBptr->feuille.type==_VECT){ + res=true; + vecteur tmp =*v[1]._SYMBptr->feuille._VECTptr; + if (tmp.size()==2){ + if (tmp[0].is_symb_of_sommet(at_quote)) + tmp[0]=tmp[0]._SYMBptr->feuille; + v[1]=symbolic(at_equal,gen(makevecteur(tmp[0],eval(tmp[1],eval_level(contextptr),contextptr)),_SEQ__VECT)); + } + } + else + v[1]=eval(v[1],eval_level(contextptr),contextptr); + } + for (int i=2;isize()<2) ) + return prodsum(args.eval(eval_level(contextptr),contextptr),false); + vecteur v(*args._VECTptr); + if (v.size()>1 && v[1].is_symb_of_sommet(at_unquote)) + v[1]=eval(v[1],1,contextptr); + maple_sum_product_unquote(v,contextptr); + int s=int(v.size()); + if (is_zero(ratnormal(v[0],contextptr))) + return 0; + if (!adjust_int_sum_arg(v,s)) + return gensizeerr(contextptr); + if (v[1].type==_INT_){ + v[0]=eval(v[0],eval_level(contextptr),contextptr); + if (v[0].type==_VECT && s==2 && args.subtype==_SEQ__VECT && v[1].val>0){ + const vecteur & l=*v[0]._VECTptr; int step=v[1].val; + gen res; + for (int pos=0;posquoted_global_vars){ + contextptr->quoted_global_vars->push_back(x); + f=eval(f,eval_level(contextptr),contextptr); + contextptr->quoted_global_vars->pop_back(); + } + else { + if (it->_IDNTptr->quoted){ + int savequote=*it->_IDNTptr->quoted; + *it->_IDNTptr->quoted=1; + f=eval(f,eval_level(contextptr),contextptr); + *it->_IDNTptr->quoted=savequote; + } + else + f=eval(f,eval_level(contextptr),contextptr); + } + } + ++it; + if (it==itend){ + gen rem,res; + res=sum(f,x,rem,contextptr); + if (is_zero(rem)) + return res; + else + return res+symbolic(at_sum,makesequence(rem,x)); + } + gen a=*it; + ++it; + if (it==itend) + return prodsum(gen(v).eval(eval_level(contextptr),contextptr),false); + gen b=*it; + ++it; + if ( (x.type!=_IDNT) ) + return prodsum(gen(v).eval(eval_level(contextptr),contextptr),false); + return sum(f,x,a,b,contextptr); + } + + static const char _somme_s []="somme"; + static define_unary_function_eval_quoted (__somme,&_sum,_somme_s); + define_unary_function_ptr5( at_somme ,alias_at_somme,&__somme,_QUOTE_ARGUMENTS,true); + + // innert form + gen _Sum(const gen & args,GIAC_CONTEXT) { + if ( args.type==_STRNG && args.subtype==-1) return args; + return symbolic(at_sum,args); + } + static const char _Sum_s []="Sum"; + static define_unary_function_eval_quoted (__Sum,&_Sum,_Sum_s); + define_unary_function_ptr5( at_Sum ,alias_at_Sum,&__Sum,_QUOTE_ARGUMENTS,true); + + void fourier_assume(const gen &n,GIAC_CONTEXT){ + if (n.type==_IDNT && eval(n,1,contextptr)==n){ + *logptr(contextptr) << "Running assume(" << n << ",integer)" << '\n'; + sto(gen(makevecteur(change_subtype(2,1)),_ASSUME__VECT),n,contextptr); + } + } + + gen _wz_certificate(const gen & args,GIAC_CONTEXT) { + if ( args.type==_STRNG && args.subtype==-1) return args; + gen F,dF,G,n(n__IDNT_e),k(k__IDNT_e); + if (args.type==_VECT){ + int s=args._VECTptr->size(); + const vecteur & v=*args._VECTptr; + if (s==0 || s>4) return gensizeerr(contextptr); + if (s==1) F=v[0]; + if (s==2) F=v[0]/v[1]; + if (s==3){ F=v[0]; n=v[1]; k=v[2]; } + if (s==4){ F=v[0]/v[1]; n=v[2]; k=v[3]; } + } + else + F=args; + fourier_assume(n,contextptr); + fourier_assume(k,contextptr); + dF=simplify(subst(F,n,n+1,false,contextptr)-F,contextptr); + G=_sum(makesequence(dF,k),contextptr); + if (lop(G,at_sum).empty()){ + gen R=G/subst(F,k,k-1,false,contextptr); + R=_eval(simplify(R,contextptr),contextptr); + return _factor(R,contextptr); + } + return 0; + } + static const char _wz_certificate_s []="wz_certificate"; + static define_unary_function_eval_quoted (__wz_certificate,&_wz_certificate,_wz_certificate_s); + define_unary_function_ptr5( at_wz_certificate ,alias_at_wz_certificate,&__wz_certificate,0,true); + + // sum does also what maple add does + /* + gen _add(const gen & args,GIAC_CONTEXT) { + if ( args.type==_STRNG && args.subtype==-1) return args; + int & elevel =eval_level(contextptr); + int el=elevel; + elevel=1; + gen res; + try { + res=_sum(args,contextptr); + } + catch (std::runtime_error & e){ + last_evaled_argptr(contextptr)=NULL; + elevel=el; + throw(e); + } + elevel=el; + return res; + } + */ + static const char _add_s []="add"; + static define_unary_function_eval_quoted (__add,&_sum //&_add + ,_add_s); + define_unary_function_ptr5( at_add ,alias_at_add,&__add,_QUOTE_ARGUMENTS,true); + + gen bernoulli(const gen & x){ + if (x.type==_VECT && x._VECTptr->size()==2){ + gen a=x._VECTptr->front(),y=x._VECTptr->back(); + if (a.type!=_INT_) + return gensizeerr(gettext("bernoulli")); + bool all=a.val<0; + int n=absint(a.val); + if (n==0) + return plus_one; + if (n==1) + return y+minus_one_half; + gen bi=bernoulli(-n); + if (bi.type!=_VECT) + return gensizeerr(gettext("bernoulli")); + vecteur biv=*bi._VECTptr; + if (biv.size()<=n) + biv.push_back(0); + // bernoulli polynomials B_n=n*int(B_n-1)+bi[n] + vecteur allv; + vecteur cur(1,1); + if (all) + allv.push_back((y.type==_VECT?cur:plus_one)); + for (int i=1;i<=n;++i){ + cur=multvecteur(i,integrate(cur,1)); + cur.insert(cur.begin(),biv[i]); + if (all){ + vecteur tmp(cur); + reverse(tmp.begin(),tmp.end()); + if (y.type==_VECT) + allv.push_back(tmp); + else + allv.push_back(symb_horner(tmp,y)); + } + } + reverse(cur.begin(),cur.end()); + return all?allv:(y.type==_VECT?cur:symb_horner(cur,y)); + } + if (x.type!=_INT_) + return gensizeerr(gettext("bernoulli")); + bool all=x.val<0; + int n=absint(x.val); + if (!n) + return plus_one; + if (n==1) + return all?vecteur(1,minus_one_half):minus_one_half; + if (n%2){ + if (!all) + return zero; + --n; + } + if (!all){ + if (n==2) + return inv(6,context0); +#ifndef WIN32 // otherwise wrong for n>=28?? + if (0) +#endif + return bernoulli_rat(n); +#if defined HAVE_LIBBERNMM && !defined BF2GMP_H + if (n>= +#ifdef HAVE_LIBPARI + 1e5 +#else + 0 +#endif + ){ + mpq_t resq; + mpq_init(resq); + bernmm::bern_rat(resq,x.val,threads); + mpz_t num,den; + mpz_init(num); mpz_init(den); + mpq_get_num(num,resq); + mpq_get_den(den,resq); + mpq_clear(resq); + gen numer(num),denom(den); + mpz_clear(num); mpz_clear(den); + return numer/denom; + } +#endif +#ifdef HAVE_LIBPARI + return _pari(makesequence(string2gen("bernfrac",false),n),context0); +#endif + return bernoulli_rat(n); + } + gen a(plus_one); + gen b(rdiv(1-n,plus_two,context0)); + vecteur bi(makevecteur(plus_one,minus_one_half)); + int i=2; + for (; i< n-1; i+=2){ + // compute bernoulli(i) + gen A=1; + gen B=gen(1-i)/2; + for (int j=2; jsize()==2 && args._VECTptr->back().type!=_INT_) + return bernoulli(args); + return apply(args,bernoulli); + } + static const char _bernoulli_s []="bernoulli"; + static define_unary_function_eval (__bernoulli,&_bernoulli,_bernoulli_s); + define_unary_function_ptr5( at_bernoulli ,alias_at_bernoulli,&__bernoulli,0,true); + + vecteur double2vecteur(const double * y,int dim){ + vecteur ye; + ye.reserve(dim); + for (int i=0;i::infinity(); + + static int gsl_odesolve_function(double t, const double y[], double dydt[], void * params){ + odesolve_param * par =(odesolve_param *) params; +#ifndef NO_STDEXCEPT + try{ +#endif + gen res=subst(par->odesolve_f,par->odesolve_t,t,false,par->contextptr); + vecteur vtmp=double2vecteur(y,par->odesolve_system.dimension); + res=subst(res,par->odesolve_y,vtmp,false,par->contextptr); + res=res.evalf(1,par->contextptr); + // store result + if ( (res.type!=_VECT) || (res._VECTptr->size()!=par->odesolve_system.dimension)){ +#ifdef NO_STDEXCEPT + return 1; +#else + setsizeerr(par->contextptr); +#endif + } + const_iterateur it=res._VECTptr->begin(),itend=res._VECTptr->end(); + for (double * dydt_it=dydt;it!=itend;++it,++dydt_it){ + if (it->type==_DOUBLE_) + *dydt_it=it->_DOUBLE_val; + else { +#ifdef NO_STDEXCEPT + return 1; +#else + setsizeerr(par->contextptr); +#endif + } + } +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & err){ + CERR << err.what() << '\n'; + int n=par->odesolve_system.dimension,i=0; + for (double * dydt_it=dydt;iodesolve_system.dimension)); + gen res=subst(par->odesolve_ft,par->odesolve_t,t,false,par->contextptr); + res=subst(res,par->odesolve_y,yv,false,par->contextptr).evalf(1,par->contextptr); + // store result + if ( (res.type!=_VECT) || (res._VECTptr->size()!=par->odesolve_system.dimension)){ +#ifdef NO_STDEXCEPT + return 1; +#else + setsizeerr(par->contextptr); +#endif + } + const_iterateur it=res._VECTptr->begin(),itend=res._VECTptr->end(); + for (double * dfdt_it=dfdt;it!=itend;++it,++dfdt_it){ + if (it->type==_DOUBLE_) + *dfdt_it=it->_DOUBLE_val; + else { +#ifdef NO_STDEXCEPT + return 1; +#else + setsizeerr(par->contextptr); +#endif + } + } + res=subst(par->odesolve_fy,par->odesolve_t,t,false,par->contextptr); + res=subst(res,par->odesolve_y,yv,false,par->contextptr).evalf(1,par->contextptr); + // store result + if ( (res.type!=_VECT) || (res._VECTptr->size()!=par->odesolve_system.dimension)){ +#ifdef NO_STDEXCEPT + return 1; +#else + setsizeerr(par->contextptr); +#endif + } + it=res._VECTptr->begin(); + itend=res._VECTptr->end(); + for (double * dfdy_it=dfdy;it!=itend;++it){ + if (it->type!=_VECT){ +#ifdef NO_STDEXCEPT + return 1; +#else + setsizeerr(par->contextptr); +#endif + } + const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end(); + for (;jt!=jtend;++jt,++dfdy_it){ + if (jt->type==_DOUBLE_) + *dfdy_it=it->_DOUBLE_val; + else { +#ifdef NO_STDEXCEPT + return 1; +#else + setsizeerr(par->contextptr); +#endif + } + } + } +#ifndef NO_STDEXCEPT + } + catch (std::runtime_error & err){ + CERR << err.what() << '\n'; + int n=par->odesolve_system.dimension,i=0; + for (double * dydt_it=dfdt;i f(t,y) or a _VECT [f(t,y) t y] + gen odesolve(const gen & t0orig,const gen & t1orig,const gen & f,const gen & y0orig,double tstep,bool return_curve,double * ymin,double * ymax,int maxstep,GIAC_CONTEXT){ + bool iscomplex=false; + // switch to false if GSL is installed or true to force using giac code for real ode + gen t0_e=evalf_double(t0orig.evalf(1,contextptr),1,contextptr); + gen t1_e=evalf_double(t1orig.evalf(1,contextptr),1,contextptr); + // Now accept t0 and t1 complex! + if ( (t0_e.type!=_DOUBLE_ && t0_e.type!=_CPLX)|| (t1_e.type!=_DOUBLE_ && t1_e.type!=_CPLX)) + return gensizeerr(contextptr); + gen y0=evalf_double(y0orig.evalf(1,contextptr),1,contextptr); + if (y0.type!=_VECT) + y0=vecteur(1,y0); + vecteur y0v=*y0._VECTptr; + int dim=int(y0v.size()); + if (tstep==0){ + if (dim==2) + tstep=(gnuplot_xmax-gnuplot_xmin)/100; + else { + if (return_curve && abs(t1_e,contextptr)._DOUBLE_val>1e300) + tstep=abs(t0_e,contextptr)._DOUBLE_val/100; + else + tstep=abs(t1_e-t0_e,contextptr)._DOUBLE_val/100; + } + } + if (tstep>abs(t1_e-t0_e,contextptr)._DOUBLE_val) + tstep=abs(t1_e-t0_e,contextptr)._DOUBLE_val; +#if 1 + ALLOCA(double, y, dim*sizeof(double));// double * y =(double *)alloca(dim*sizeof(double)); +#else + double * y=new double[dim]; +#endif + for (int i=0;iodesolve_t=t_id; + par->odesolve_y=yv; + par->contextptr=contextptr; + par->odesolve_f=odesolve_f; + par->odesolve_fy=*diff1._VECTptr; + par->odesolve_ft=*diff2._VECTptr; + par->odesolve_system.function=gsl_odesolve_function; + par->odesolve_system.dimension=dim; + par->odesolve_system.jacobian=gsl_odesolve_jacobian; + par->odesolve_system.params=par; + // GSL call + const gsl_odeiv_step_type * T = gsl_odeiv_step_rk8pd; + gsl_odeiv_step * s = gsl_odeiv_step_alloc (T, dim); + gsl_odeiv_control * c = gsl_odeiv_control_y_new (1e-7, 1e-7); + gsl_odeiv_evolve * e = gsl_odeiv_evolve_alloc (dim); + double h; + if (return_curve){ + h=fabs(t); + if (h<1e-4) + h=1e-4; + } + else + h=(t1-t)/1e4; + double oldt=t0; + bool do_while=true; + for (int nstep=0;nsteptstep) + h=tstep; + int status = gsl_odeiv_evolve_apply (e, c, s, + &par->odesolve_system, + &t, t1, &h, + y); + if (status != GSL_SUCCESS) + return gensizeerr(gettext("RK8 evolve not successful")); + if (debug_infolevel>5) + CERR << nstep << ":" << t << ",y5=" << double2vecteur(y,dim) << '\n'; + if (return_curve) { + if ( (t-oldt)> tstep/2 || t==t1){ + oldt=t; + if (time_reverse) + resv.push_back(makevecteur(-t,double2vecteur(y,dim))); + else + resv.push_back(makevecteur(t,double2vecteur(y,dim))); + } + for (int i=0;iymax[i]) ) + do_while=false; + } + } + } + gsl_odeiv_evolve_free(e); + gsl_odeiv_control_free(c); + gsl_odeiv_step_free(s); + delete par; + if (return_curve){ + gen res(vecteur(0)); + res._VECTptr->swap(resv); + return res; + } + else { + if (t!=t1) + return makevecteur(t,double2vecteur(y,dim)); + return double2vecteur(y,dim); + } + } +#endif // HAVE_LIBGSL + vecteur odesolve_f; + if (tmp.type!=_VECT) + odesolve_f=vecteur(1,tmp); + else + odesolve_f=*tmp._VECTptr; + if (signed(odesolve_f.size())!=dim) + return gendimerr(contextptr); + // solve vector ode y'=f(t,y) with respect to time variable t_id in t0..t1 + // f is stored in odesolve_f, symbolic y in yv, initial value in a double array y + /* Butcher tableau for Dormand/Prince 4/5 + 0 | + 1/5 | 1/5 + 3/10 | 3/40 9/40 + 4/5 | 44/45 โˆ’56/15 32/9 + 8/9 | 19372/6561 โˆ’25360/2187 64448/6561 โˆ’212/729 + 1 | 9017/3168 โˆ’355/33 46732/5247 49/176 โˆ’5103/18656 + 1 | 35/384 0 500/1113 125/192 โˆ’2187/6784 11/84 + =============================================================================== + RK5 | 35/384 0 500/1113 125/192 โˆ’2187/6784 11/84 0 + RK4 5179/57600 0 7571/16695 393/640 โˆ’92097/339200 187/2100 1/40 + RK4 is used for computation of the tstep variable + RK4 error being estimated by |RK5-RK4| + Step is determined by the following algorithm + (cf. Ernst Hairer http://www.unige.ch/~hairer/poly/chap3.pdf, p.67 in French) + initialization: use h=tstep + compute RK5_final and RK4_final, then + err=|| RK5-RK4 || = sqrt(1/dim*sum(((RK5[i]-RK4[i])/(1+max(RK5[i]_init,RK5[i]_final)))^2,i=1..dim)) + and hoptimal = 0.9*h*(tolerance/||RK5-RK4||)^(1/5) + if (err<=hoptimal) then time += h; y_init=RK5_final; h=min(hoptimal,t_final-t_current) + else h=hoptimal + */ +#ifdef KHICAS + gen tolerance=epsilon(contextptr)>1e-9?epsilon(contextptr):1e-9; +#else + gen tolerance=epsilon(contextptr)>1e-12?epsilon(contextptr):1e-12; +#endif + vecteur yt(dim+1),ytvar(yv); + for (int i=0;ifront(),yt10); + } + } + else { + for (int k=0;k5) + CERR << nstep << ":" << t_e << ",y5=" << y_final5 << ",y4=" << y_final4 << " " << tstep << " tstep (optimal)=" << hopt << " err=" << err << '\n'; + if (is_strictly_greater(err,tolerance,contextptr)){ + // reject step + tstep=hopt._DOUBLE_val; + } + else { // accept + swap(firsteval,lasteval); + for (int i=0;iymax[i]) ) + do_while=false; + } + } + } + } // end integration loop + if (return_curve){ + gen res(vecteur(0)); + res._VECTptr->swap(resv); + return res; + } + else { + if (t_e!=t1_e) + return makevecteur(t_e,y_final5); + return y_final5; + } + } + // note that params is not used + + // standard format is expression,t=t0..t1,vars,init_values + // also accepted + // t0..t1,function,init_values + // expression,t,vars,init_values,t=tmin..tmax + // expression,[t,vars],[t0,init_values],t1 + static gen odesolve(const vecteur & w,GIAC_CONTEXT){ + vecteur v(w); + int vs=int(v.size()); + if (vs<3) + return gendimerr(contextptr); + // convert expression,[t,vars],[t0,init_values],t1 + gen t0t=v[0],t0,t1,f,t,y0; + if (v[1].type==_VECT && v[2].type==_VECT && v[2]._VECTptr->size()==v[1]._VECTptr->size() && vs>3){ + if (v[1]._VECTptr->size()<2) + return gendimerr(contextptr); + t0=v[2]._VECTptr->front(); + t1=v[3]; + gen newv1=symbolic(at_equal,v[1]._VECTptr->front(),symb_interval(v[2]._VECTptr->front(),v[3])); + gen newv2=vecteur(v[1]._VECTptr->begin()+1,v[1]._VECTptr->end()); + gen newv3=vecteur(v[2]._VECTptr->begin()+1,v[2]._VECTptr->end()); + v[1]=newv1; + v[2]=newv2; + v[3]=newv3; + } + int maxstep=1000,vstart=0; + double tstep=0; + if ( t0t.is_symb_of_sommet(at_interval)){ // functional form + t0=t0t._SYMBptr->feuille._VECTptr->front(); + t1=t0t._SYMBptr->feuille._VECTptr->back(); + f=v[1]; + y0=v[2]; + vstart=3; + } + else { // expression,t=tmin..tmax,y,y0 + if (vs<4) + return gentypeerr(contextptr); + y0=v[3]; + gen t=readvar(v[1]); + f=makevecteur(v[0],t,v[2]); + bool tminmax_defined,tstep_defined; + double tmin(-1e300),tmax(1e300); + vstart=1; + read_tmintmaxtstep(v,t,vstart,tmin,tmax,tstep,tminmax_defined,tstep_defined,contextptr); + if (t0!=t1){ + if (tstep==0) + tstep=evalf_double(abs(t1-t0,contextptr),1,contextptr)._DOUBLE_val/30; + } + else { + if (tmin>0 || tmax<0 || tmin>tmax || tstep<=0) + *logptr(contextptr) << gettext("Warning time reversal") << '\n'; + t0=tmin; + t1=tmax; + } + // if (tminmax_defined && tstep_defined) maxstep=2*int((tmax-tmin)/tstep)+1; + // commented since the real step is used is smaller than tstep most of the time! + vstart=3; + } + double ym[2]={gnuplot_xmin,gnuplot_ymin},yM[2]={gnuplot_xmin,gnuplot_ymin}; + double *ymin=0,*ymax=0; + vs=int(v.size()); + bool curve=false; + for (int i=vstart;isize()<3 ) ) + return symbolic(at_odesolve,args); + vecteur v(*args._VECTptr); + return odesolve(v,contextptr); + } + static const char _odesolve_s []="odesolve"; + static define_unary_function_eval (__odesolve,&_odesolve,_odesolve_s); + define_unary_function_ptr5( at_odesolve ,alias_at_odesolve,&__odesolve,0,true); + + gen preval(const gen & f,const gen & x,const gen & a,const gen & b,GIAC_CONTEXT){ + if (x.type!=_IDNT) + return gentypeerr(contextptr); + gen res; + if (is_greater(b,a,contextptr)) + res=limit(f,*x._IDNTptr,b,-1,contextptr)-limit(f,*x._IDNTptr,a,1,contextptr); + else { + if (is_greater(a,b,contextptr)) + res=limit(f,*x._IDNTptr,b,1,contextptr)-limit(f,*x._IDNTptr,a,-1,contextptr) ; + else + res=limit(f,*x._IDNTptr,b,0,contextptr)-limit(f,*x._IDNTptr,a,0,contextptr); + } + return res; + } + + // args=[u'*v,u] or [[F,u'*v],u] -> [F+u*v,-u*v'] + // a third argument would be the integration var + // if u=cste returns F+integrate(u'*v,x) + gen _ibpdv(const gen & args,GIAC_CONTEXT) { + if ( args.type==_STRNG && args.subtype==-1) return args; + if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) + return symbolic(at_ibpdv,args); + vecteur & w=*args._VECTptr; + gen X(vx_var),x(vx_var),a,b; + bool bound=false; + if (w.size()>=3) + x=X=w[2]; + if (is_equal(x)) + x=x._SYMBptr->feuille[0]; + if (w.size()>=5) + X=symb_equal(x,symb_interval(w[3],w[4])); + if (is_equal(X) && X._SYMBptr->feuille[1].is_symb_of_sommet(at_interval)){ + a=X._SYMBptr->feuille[1]._SYMBptr->feuille[0]; + b=X._SYMBptr->feuille[1]._SYMBptr->feuille[1]; + bound=true; + } + gen u(w[1]),v,uprimev,F; + if (w.front().type==_VECT){ + vecteur & ww=*w.front()._VECTptr; + if (ww.size()!=2) + return gensizeerr(contextptr); + F=ww.front(); + uprimev=ww.back(); + } + else + uprimev=w.front(); + gen uprime(derive(u,x,contextptr)); + if (is_zero(uprime)){ + gen tmp=integrate_gen(uprimev,x,contextptr); + if (bound) + tmp=preval(tmp,x,a,b,contextptr); + return tmp+F; + } + v=normal(rdiv(uprimev,derive(u,x,contextptr),contextptr),contextptr); + if (bound) + F += preval(u*v,x,a,b,contextptr); + else + F += u*v; + return makevecteur(F,normal(-u*derive(v,x,contextptr),contextptr)); + } + static const char _ibpdv_s []="ibpdv"; + static define_unary_function_eval (__ibpdv,&_ibpdv,_ibpdv_s); + define_unary_function_ptr5( at_ibpdv ,alias_at_ibpdv,&__ibpdv,0,true); + + gen fourier_an(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT){ + gen primi,iT=inv(T,contextptr); + gen omega=ratnormal(2*cst_pi*iT); + fourier_assume(n,contextptr); + primi=_integrate(gen(makevecteur(f*cos(omega*n*x,contextptr),x,a,ratnormal(a+T,contextptr)),_SEQ__VECT),contextptr); + gen an=iT*primi; + if (n!=0) + an=2*an; + return has_num_coeff(an)?an:recursive_normal(an,contextptr); + } + bool get_fourier(vecteur & v){ + if (v.size()<2) return false; + if (v.size()==2) + v=makevecteur(v[0],vx_var,cst_two_pi,v[1],-cst_pi); + if (v.size()==3) + v=makevecteur(v[0],v[1],cst_two_pi,v[2],-cst_pi); + if (v.size()==4) v.push_back(0); + if (equalposcomp(lidnt(v[3]),v[1])) + return false; + return v.size()==5; + } + gen _fourier_an(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT) return gensizeerr(contextptr); + vecteur v(*args._VECTptr); + if (!get_fourier(v)) return gensizeerr(contextptr); + return fourier_an(v[0],v[1],v[2],v[3],v[4],contextptr); + //gen f=v[0],x=v[1],T=v[2],n=v[3],a=v[4]; + //return fourier_an(f,x,T,n,a,contextptr); + } + static const char _fourier_an_s []="fourier_an"; + static define_unary_function_eval (__fourier_an,&_fourier_an,_fourier_an_s); + define_unary_function_ptr5( at_fourier_an ,alias_at_fourier_an,&__fourier_an,0,true); + + + gen fourier_bn(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT){ + fourier_assume(n,contextptr); + gen primi,iT=inv(T,contextptr); + gen omega=ratnormal(2*cst_pi*iT); + primi=_integrate(gen(makevecteur(f*sin(omega*n*x,contextptr),x,a,ratnormal(a+T,contextptr)),_SEQ__VECT),contextptr); + gen an=2*iT*primi; + return has_num_coeff(an)?an:recursive_normal(an,contextptr); + } + gen _fourier_bn(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT) return gensizeerr(contextptr); + vecteur v(*args._VECTptr); + if (!get_fourier(v)) return gensizeerr(contextptr); + return fourier_bn(v[0],v[1],v[2],v[3],v[4],contextptr); + // gen f=v[0],x=v[1],T=v[2],n=v[3],a=v[4]; + // return fourier_bn(f,x,T,n,a,contextptr); + } + static const char _fourier_bn_s []="fourier_bn"; + static define_unary_function_eval (__fourier_bn,&_fourier_bn,_fourier_bn_s); + define_unary_function_ptr5( at_fourier_bn ,alias_at_fourier_bn,&__fourier_bn,0,true); + + gen fourier_cn(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT){ + fourier_assume(n,contextptr); + gen primi,iT=inv(T,contextptr); + gen omega=ratnormal(2*cst_pi*iT); + primi=_integrate(gen(makevecteur(f*exp(-cst_i*omega*n*x,contextptr),x,a,ratnormal(a+T,contextptr)),_SEQ__VECT),contextptr); + gen cn=iT*primi; + return has_num_coeff(cn)?cn:recursive_normal(cn,contextptr); + } + gen _fourier_cn(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (args.type!=_VECT) return gensizeerr(contextptr); + vecteur v(*args._VECTptr); + if (!get_fourier(v)) return gensizeerr(contextptr); + return fourier_cn(v[0],v[1],v[2],v[3],v[4],contextptr); + // gen f=v[0],x=v[1],T=v[2],n=v[3],a=v[4]; + // return fourier_cn(f,x,T,n,a,contextptr); + } + + static const char _fourier_cn_s []="fourier_cn"; + static define_unary_function_eval (__fourier_cn,&_fourier_cn,_fourier_cn_s); + define_unary_function_ptr5( at_fourier_cn ,alias_at_fourier_cn,&__fourier_cn,0,true); + +#if defined FXCG || !defined USE_GMP_REPLACEMENTS + // periodic by Luka Marohniฤ‡ + // example f:=periodic(x^2,x,-1,1); plot(f,x=-5..5) + gen _periodic(const gen & g,GIAC_CONTEXT) { + if (g.type==_STRNG && g.subtype==-1) return g; + if (g.type!=_VECT || g.subtype!=_SEQ__VECT) + return gentypeerr(contextptr); + vecteur & gv = *g._VECTptr; + if (gv.size()!=4 && gv.size()!=2) + return gensizeerr(contextptr); + gen & e=gv[0],x,a,b; + //if (e.type!=_SYMB && e.type!=_IDNT) return gentypeerr(contextptr); + vecteur vars(*_lname(e,contextptr)._VECTptr); + if (vars.empty()) + return e; + if (gv.size()==2) { + if (!gv[1].is_symb_of_sommet(at_equal)) + return gentypeerr(contextptr); + vecteur & fl=*gv[1]._SYMBptr->feuille._VECTptr; + if ((x=fl[0]).type!=_IDNT || !fl[1].is_symb_of_sommet(at_interval)) + return gentypeerr(contextptr); + vecteur & ab=*fl[1]._SYMBptr->feuille._VECTptr; + a=ab[0]; + b=ab[1]; + } + else { + x=gv[1]; + if (x.type!=_IDNT) + return gentypeerr(contextptr); + if (find(vars.begin(),vars.end(),x)==vars.end()) + return e; + a=gv[2]; + b=gv[3]; + } + gen T(b-a); + if (!is_strictly_positive(T,contextptr)) + return gentypeerr(contextptr); + gen p(subst(e,x,x-T*_floor((x-a)/T,contextptr),false,contextptr)); + return p;// _unapply(makesequence(p,x),contextptr); + } + static const char _periodic_s []="periodic"; + static define_unary_function_eval (__periodic,&_periodic,_periodic_s); + define_unary_function_ptr5(at_periodic,alias_at_periodic,&__periodic,0,true); +#endif + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/intgab.cc b/android/app/src/main/cpp/giac/src/giac/cpp/intgab.cc new file mode 100644 index 0000000..7cf00ff --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/intgab.cc @@ -0,0 +1,2112 @@ +// -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c intgab.cc -DHAVE_CONFIG_H -DIN_GIAC" -*- +#include "giacPCH.h" +/* + * Copyright (C) 2000,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using namespace std; +#include +#include "vector.h" +#include +#include +#include "sym2poly.h" +#include "usual.h" +#include "intgab.h" +#include "subst.h" +#include "derive.h" +#include "lin.h" +#include "vecteur.h" +#include "gausspol.h" +#include "plot.h" +#include "prog.h" +#include "modpoly.h" +#include "series.h" +#include "tex.h" +#include "ifactor.h" +#include "risch.h" +#include "solve.h" +#include "intg.h" +#include "desolve.h" +#include "alg_ext.h" +#include "misc.h" +#include "maple.h" +#include "rpn.h" +#include "giacintl.h" +#ifdef HAVE_LIBGSL +#include +#include +#include +#include +#include +#include +#endif + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + // check whether an expression is meromorphic + // returns -1 if x is not an IDNT + // return 2 if rational + // return 3 if rational fraction of x, sin(a*x+b), cos(a*x+b) + // return 4 if rational fraction of x, exp(a*x+b) where re(a)!=0 + // return 5 if ln(P)*A==rational fraction + B==rational fraction + // TODO: 6 if exp(a[0]*x^2+a[1]*x+a[2])*b+P, P,b =rational, a[0]<0 + int is_meromorphic(const gen & g,const gen & x,gen & a,gen & b,gen & P,GIAC_CONTEXT){ + if (x.type!=_IDNT) + return -1; + if (g.type<=_IDNT) + return 2; + if (g.type==_VECT){ + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it){ + if (!is_meromorphic(*it,x,a,b,P,contextptr)) + return 0; + } + return 1; + } + if (g.type==_SYMB){ + vecteur v; + rlvarx(g,x,v); + islesscomplexthanf_sort(v.begin(),v.end()); + if (v==vecteur(1,x)) + return 2; + if (v.size()<2 || v[1].type!=_SYMB) + return 0; + P=v[1]._SYMBptr->feuille; + if (v.size()==2) { + if (v[1].is_symb_of_sommet(at_exp)){ + if (is_linear_wrt(P,x,a,b,contextptr)){ + if (is_zero(re(a,contextptr))){ + a=a/cst_i; + b=b/cst_i; + return 3; + } + return 4; + } + identificateur t(" t"); + gen tt(t); + gen g2=subst(g,v[1],tt,false,contextptr),bcst; + if (is_linear_wrt(g2,t,b,bcst,contextptr)){ + gen A,B,C; + if (is_quadratic_wrt(P,x,A,B,C,contextptr) && is_strictly_positive(-A,contextptr)){ + a=makevecteur(A,B,C); + P=bcst; + return 6; + } + } + } + if ( (v[1].is_symb_of_sommet(at_cos) || v[1].is_symb_of_sommet(at_sin)) && is_linear_wrt(P,x,a,b,contextptr) && is_zero(im(a,contextptr)) ) + return 3; + if (v[1].is_symb_of_sommet(at_ln)){ + identificateur t(" t"); + gen tt(t); + gen g2=subst(g,v[1],tt,false,contextptr); + if (is_linear_wrt(g2,t,a,b,contextptr)) + return 5; + } + } + if (v.size()==3){ + if (v[1].is_symb_of_sommet(at_cos) && v[2].is_symb_of_sommet(at_sin)){ + gen v2f=v[2]._SYMBptr->feuille; + if (P==v2f && is_linear_wrt(P,x,a,b,contextptr) && is_zero(im(a,contextptr))) + return 3; + } + } + const_iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if (it->type==_IDNT) + continue; + if (it->type!=_SYMB) + return 0; + unary_function_ptr * u=&it->_SYMBptr->sommet; + if (u==at_sin || u==at_cos || u==at_tan || u==at_exp || u==at_sinh || u==at_cosh || u==at_tanh){ + // the argument must not have singularities + if (find_singularities(it->_SYMBptr->feuille,*x._IDNTptr,1,contextptr).empty()) + continue; + } + return 0; + } + return 1; + } + return 0; + } + + int fast_is_even_odd(const gen & f,const gen & x,GIAC_CONTEXT){ + if (f==x) // x is odd + return 2; + if (f.type==_VECT){ + vecteur & v =*f._VECTptr; + const_iterateur it=v.begin(),itend=v.end(); + int res=0,current; + for (;it!=itend;++it){ + if (! (current=fast_is_even_odd(*it,x,contextptr)) ) + return 0; + if (!res) + res=current; + if (res!=current) + return 0; + } + return res; + } + if (f.type!=_SYMB) // constant is even + return 1; + gen & ff=f._SYMBptr->feuille; + int res; + const unary_function_ptr & u = f._SYMBptr->sommet; + if (u==at_pow && ff.type==_VECT && ff._VECTptr->size()==2){ + gen ff2=ff._VECTptr->back(); + if (ff2.type==_INT_){ + gen ff1=ff._VECTptr->front(); + res=fast_is_even_odd(ff1,x,contextptr); + if (res<2) + return res; + return (ff2.val%2)?2:1; + } + return 0; + } + res=fast_is_even_odd(ff,x,contextptr); + if (res<2) + return res; + // ff is odd + if (u==at_plus || u==at_neg || u==at_inv || u==at_sin || u==at_tan || u==at_sinh || u==at_tanh || u==at_atan || u==at_atanh) + return res; + if (u==at_prod){ + if (ff.type!=_VECT || (ff._VECTptr->size()%2)) + return res; + return 1; + } + if (u==at_cos || u==at_cosh || u==at_abs) + return 1; + return 0; + } + + // 0 none, 1 even, 2 odd + int is_even_odd(const gen & f,const gen & x,GIAC_CONTEXT){ + int res=fast_is_even_odd(f,x,contextptr); + if (res) + return res; + gen f1=f,f2=subst(f,x,-x,false,contextptr); + vecteur v=lvar(f); + if (v==vecteur(1,x)){ // rational case + if (is_zero(normal(f1-f2,contextptr))) + return 1; + if (is_zero(normal(f1+f2,contextptr))) + return 2; + return 0; + } + f1=_texpand(f1,contextptr); + f1=normal(recursive_ratnormal(f1,contextptr),contextptr); + f2=_texpand(f2,contextptr); + f2=normal(recursive_ratnormal(f2,contextptr),contextptr); + if (f1==f2) + return 1; + if (is_zero(ratnormal(invfracpow(f1+f2,contextptr),contextptr))) + return 2; + return 0; + } + + bool has_sparse_poly1(const gen & g){ + if (g.type==_SPOL1) + return true; + if (g.type==_VECT){ + vecteur & v=*g._VECTptr; + for (size_t i=0;ifeuille); + return false; + } + + // residue of g at x=a + gen residue(const gen & g_,const gen & x,const gen & a,GIAC_CONTEXT){ + if (x.type!=_IDNT) + return gensizeerr(contextptr); + gen xval=x._IDNTptr->eval(1,x,contextptr); + if (xval!=x){ +#if 1 + identificateur tmpid(x._IDNTptr->id_name+string("_")); + gen tmp(tmpid); + gen g(subst(g_,x,tmp,false,contextptr)); + return residue(g,tmp,a,contextptr); +#else + _purge(x,contextptr); + xval=x._IDNTptr->eval(1,x,contextptr); + if (xval!=x){ + string s="Unable to purge "+x.print(contextptr)+ ", choose another free variable name"; + *logptr(contextptr) << s << '\n'; + return gensizeerr(s); + } + gen res=residue(g_,x,a,contextptr); + sto(xval,x,contextptr); + return res; +#endif + } + gen g1=fxnd(g_); + if (g1.type==_VECT && g1._VECTptr->size()==2){ + gen n=g1._VECTptr->front(),d=derive(g1._VECTptr->back(),x,contextptr); + gen da=subst(d,*x._IDNTptr,a,false,contextptr); + if (!is_zero(da)){ + gen na=subst(n,*x._IDNTptr,a,false,contextptr); + n=recursive_normal(na/da,contextptr); + if (!is_zero(n) && !is_undef(n) && !is_inf(n)) + return n; + } + } + gen g=_pow2exp(tan2sincos(g_,contextptr),contextptr); + for (int ordre=2;ordre2 && v[1].type==_IDNT){ + vecteur res=find_singularities(v[0],*v[1]._IDNTptr,(is_zero(v[2])?1:9),contextptr); + comprim(res); + return res; + } + return singular(v[0],v[1],contextptr); + } + static const char _singular_s []="singular"; + static define_unary_function_eval (__singular,&_singular,_singular_s); + define_unary_function_ptr5( at_singular ,alias_at_singular,&__singular,0,true); + + bool assume_t_in_ab(const gen & t,const gen & a,const gen & b,bool exclude_a,bool exclude_b,GIAC_CONTEXT){ + vecteur v_interval(1,gen(makevecteur(a,b),_LINE__VECT)); + vecteur v_excluded; + if (exclude_a) + v_excluded.push_back(a); + if (exclude_b) + v_excluded.push_back(b); + return !is_undef(sto(gen(makevecteur(gen(_DOUBLE_).change_subtype(1),v_interval,v_excluded),_ASSUME__VECT),t,contextptr)); + } + + // reduce g, a rational fraction wrt to x, to a sqff lnpart + // and adds the non sqff integrated part to ratpart + static bool intreduce(const gen & e,const gen & x,gen & lnpart,gen & ratpart,GIAC_CONTEXT){ + vecteur l; + l.push_back(x); // insure x is the main var + l=vecteur(1,l); + alg_lvar(e,l); + int s=int(l.front()._VECTptr->size()); + if (!s){ + l.erase(l.begin()); + s=int(l.front()._VECTptr->size()); + } + if (!s) + return false; + gen r=e2r(e,l,contextptr); + gen r_num,r_den; + fxnd(r,r_num,r_den); + if (r_num.type==_EXT){ + return false; + } + if (r_den.type!=_POLY){ + l.front()._VECTptr->front()=x; + lnpart=0; + if (r_num.type==_POLY) + ratpart=rdiv(r2e(r_num._POLYptr->integrate(),l,contextptr),r2sym(r_den,l,contextptr),contextptr); + else + ratpart=e*x; + return true; + } + polynome den(*r_den._POLYptr),num(s); + if (r_num.type==_POLY) + num=*r_num._POLYptr; + else + num=polynome(r_num,s); + l.front()._VECTptr->front()=x; + polynome p_content(lgcd(den)); + factorization vden(sqff(den/p_content)); // first square-free factorization + vector< pf > pfde_VECT; + polynome ipnum(s),ipden(s),temp(s),tmp(s); + partfrac(num,den,vden,pfde_VECT,ipnum,ipden); + vector< pf >::iterator it=pfde_VECT.begin(); + vector< pf >::const_iterator itend=pfde_VECT.end(); + vector< pf > ratpartv; + for (;it!=itend;++it){ + pf single(intreduce_pf(*it,ratpartv)); + lnpart += r2e(single.num,l,contextptr)/r2e(single.den,l,contextptr); + // FIXME: add ratpartv to ratpart + } + return true; + } + + static bool intgab_sincos(const gen & g,const gen & x,const gen & a,const gen & b,gen & A, gen & B,gen & res,GIAC_CONTEXT){ + gen g1=trig2exp(g,contextptr); + // write it as a rational fraction of x,X=exp(i*(A*x+b)) + identificateur Xid(" X"); + gen X(Xid),expx(exp(cst_i*(A*x+B),contextptr)); + g1=subst(g1,expx,X,false,contextptr); + if (is_positive(-A,contextptr)) + g1=subst(g1,X,inv(X,contextptr),false,contextptr); + // Separable variables? + vecteur f=factors(g1,x,contextptr); // Factor then split factors + gen xfact(plus_one),Xfact(plus_one); + if (separate_variables(f,Xid,x,Xfact,xfact,contextptr)){ + // xfact must be a proper fraction + if (!is_zero(limit(xfact,*x._IDNTptr,plus_inf,1,contextptr))){ + res=undef; + return true; + } + // Xfact must be rewritten as a generalized polynomial part + // + a rational part N/D, the roots of D are in pairs r, 1/conj(r) + // if there are roots with norm = 1, D vanishes inf. times on R + // hence the integral is undef + // we select all roots with norm > 1 and take the corresp. part of + // the partial fraction expansion, we have + // N/D=2*re(true_poly_part)+2*re(n/d)-re(n(0)/d(0)) + // where d has no poles in C^+ and X tends to 0 at inf in C^+ + vecteur vX(1,X); + lvar(Xfact,vX); + gen ND=sym2r(Xfact,vX,contextptr); + gen N,D; + fxnd(ND,N,D); + polynome Np,Dp,Q,R; + if (D.type!=_POLY) + return false; + Dp=*D._POLYptr; + if (N.type==_POLY) + Np=*N._POLYptr; + else + Np=polynome(N,1); + Np.TDivRem(Dp,Q,R); + int Qd=Q.degree(0); + // Q is the true poly part + if (Qd){ + // Dp must be divisible by Qd + int Dval=Dp.valuation(0); + if (Dval!=Qd) + return false; // setsizeerr(); + index_t decal(vX.size()); + decal[0]=-Dval; + Dp=Dp.shift(decal); + polynome XQd(gen(1),int(vX.size())),U(int(vX.size())),V(int(vX.size())),C(int(vX.size())); + decal[0]=Dval; + XQd=XQd.shift(decal); + Tabcuv(Dp,XQd,R,U,V,C); // C*Np=Dp*U+X^Dval*V + // Np/(Dp*X^Dval)=V/Dp/C+... + R=V; + Dp=Dp*C; + } + if (!Q.coord.empty() && Q.coord.back().index.is_zero()) + Q.coord.back().value=Q.coord.back().value/2; + // R/Dp is the true fractional part, Q is the true poly. part + // now check roots of norm=1 + gen dp=r2sym(Dp,vX,contextptr); + identificateur XXi(" x"),XYi(" y"); + gen XX(XXi),XY(XYi); + dp=subst(dp,X,XX+cst_i*XY,false,contextptr); + dp=_resultant(gen(makevecteur(dp,XX*XX+XY*XY-1,XY),_SEQ__VECT),contextptr); + if (is_undef(dp)) return false; + dp=gcd(re(dp,contextptr),im(dp,contextptr),contextptr); + vecteur vdp=factors(dp,XX,contextptr); + int vdps=int(vdp.size()); + for (int i=0;i0){ + res=undef; + return true; + } + } + // ok, now find roots of norm>1 + factorization fd; + polynome Dp_content; + gen extra_div=1; + if (!factor(Dp,Dp_content,fd,false,true,true,1,extra_div) || extra_div!=1){ + *logptr(contextptr) << gettext("Unable to factor ") << r2sym(Dp,vX,contextptr) << '\n'; + res=undef; + return true; + } + // check that each factor has degree 1 + polynome D1(gen(1),int(vX.size())); + factorization::const_iterator f_it=fd.begin(),f_itend=fd.end(); + for (;f_it!=f_itend;++f_it){ + if (f_it->fact.degree(0)>1){ + *logptr(contextptr) << gettext("Unable to factor ") << r2sym(f_it->fact,vX,contextptr) << '\n'; + res=undef; + return true; + } + if (f_it->fact.coord.size()==2){ + gen f1=f_it->fact.coord.front().value; + gen f2=f_it->fact.coord.back().value; + gen f21=r2sym(-f2/f1,vecteur(0),contextptr); + if (is_positive(abs(f21,contextptr)-1,contextptr)) + D1=D1*pow(f_it->fact,f_it->mult); + } + } // end f_it + // keep only those roots + polynome D2,tmp,U,V,C; + Dp.TDivRem(D1,D2,tmp); + Tabcuv(D1,D2,R,U,V,C); // R/D=(D1*U+D2*V)/(C*D1*D2) -> V/(C*D1) + Dp=C*D1; + R=V; // back to integrating 2*Re(R/Dp) + // find R/Dp at 0, real part should be subtracted + vecteur Rv(polynome2poly1(R,1)),Dv(polynome2poly1(Dp,1)),Qv(polynome2poly1(Q,1)); + vecteur vX1(vX.begin()+1,vX.end()); + Rv=*r2sym(Rv,vX1,contextptr)._VECTptr; + Dv=*r2sym(Dv,vX1,contextptr)._VECTptr; + Qv=*r2sym(Qv,vX1,contextptr)._VECTptr; + gen correc=re(Rv.back()/Dv.back(),contextptr); + xfact=xfact*(2*(horner(Rv,expx)/horner(Dv,expx)+horner(Qv,expx))-correc); + res=0; + vecteur v=singular(xfact,x,contextptr); + if (!v.empty() && is_undef(v.front())) + return false; + int s=int(v.size()); + for (int i=0;isize()!=2) + return false; + B += tmp._VECTptr->back(); + tmp=-derive(tmp._VECTptr->front(),x,contextptr); + } + // int(exp(A_*x^2+B_*x+C_)*B,x,-inf,inf) + // =int(exp(A_*(x+B_/2/A_)^2+(-B_^2/4/A_+C_))*B,x,-inf,inf) + // =sqrt(pi/A_)*B*exp(B_^2/4/A_-C_) + res=sqrt(-cst_pi/A_,contextptr)*B*exp(ratnormal(C_-B_*B_/4/A_,contextptr),contextptr); + return true; + } + if (typeint==5){ + // A*ln(P(x))+B, A/B/P rational fractions + bool estreel=is_zero(im(A,contextptr))&&is_zero(im(P,contextptr)); + vecteur lv(1,x); + lvar(P,lv); + int lvs=int(lv.size()); + for (int i=0;ilexsorted_degree(); + int dendeg=0; + if (Aden.type==_POLY) + dendeg=Aden._POLYptr->lexsorted_degree(); + if (numdeg>=dendeg-1) + return false; + // A must have non real roots + vecteur rA=singular(A,x,contextptr); + if (!rA.empty() && is_undef(rA)) + return false; + for (int i=0;i0, contour is C- + // for im<=0, contour is C+, + // for roots of P take +residue(ln(x-r)*A) + // for poles of P take -residue(ln(x-r)*A) + int rAs=int(rA.size()),rPs=int(rP.size()); + for (int i=0;i x+2*i*pi/A + // if the rat frac of x and rat frac of exp are separate + // the problem is to find a function such that + // f(.+2*i*pi/A)-f(.)=ratfrac(x) + identificateur Xid(" X"); + gen X(Xid),expx(symb_exp(A*x+B)); + gen g1=subst(g,expx,X,false,contextptr); + // Separable variables? + vecteur f=factors(g1,x,contextptr); // Factor then split factors + gen xfact(plus_one),Xfact(plus_one),T(2*cst_i*cst_pi/A); + gen imT(im(T,contextptr)); + if (separate_variables(f,x,Xid,xfact,Xfact,contextptr)){ + // rescale xfact, in order to find a discrete antiderivative + gen xfactscaled=subst(xfact,x,x*T,false,contextptr),remains_to_sum,xfactint; + if (!rational_sum(xfactscaled,x,xfactint,remains_to_sum, + /* psi allowed */ true,contextptr)) + return false; + // psi function has poles at 0,-1,-2,... + // all have Laurent series -1/(x-pole) + xfactint=ratnormal(subst(xfactint,x,x/T,false,contextptr),contextptr); + // now int()==contour_integral of xfactint*Xfact over rectangle + // -inf .. + inf -> inf+T ..-inf+T -> + // just compute all residues at poles where im is in [0,im(T)] + // for xfactint, poles are the same as the poles of xfact translated + // for Xfact, find pole in X then take A*x+B=ln(pole in X) + vecteur rA=singular(xfact,x,contextptr); + vecteur rP=singular(Xfact,X,contextptr); + if (is_undef(rA) || is_undef(rP)) + return false; + gen tmp=xfactint*subst(Xfact,X,expx,false,contextptr); + gen somme_residus; + int rAs=int(rA.size()),rPs=int(rP.size()); + vecteur lrac; + for (int i=0;i0) but should handle transc. func. + // correctly... +#ifndef NO_STDEXCEPT + try { +#endif + gen gl,glim; + identificateur t(" t"),r(" r"); + gen gt(t),gr(r),geff(g); + if (typeint==2){ + // replace g by the log part of g + if (intgab_ratfrac(g,x,res,contextptr)){ + return true; + } + gen ratpart,lnpart; + if (!intreduce(g,x,lnpart,ratpart,contextptr)) + return false; + gl=limit(g,*x._IDNTptr,plus_inf,1,contextptr); + geff=lnpart; + } + else { + // has limit 0 at infinity in the upper or lower half plane + // replace x by r*exp(i.t), assume(t in ]0,pi[ or ]-pi,0[) + // and look for limit(r*g) + glim=gr*subst(g,x,gr*symbolic(at_exp,cst_i*t),false,contextptr); + if (!assume_t_in_ab(gt,0,cst_pi,true,true,contextptr)) + return false; + gl=limit(glim,r,plus_inf,1,contextptr); + } + if (is_zero(gl)){ // use upper half plan + res=0; + vecteur v=singular(geff,x,contextptr); + if (is_undef(v)) + return false; + int s=int(v.size()),nresidue=0; + for (int i=0;isommet==at_pow && g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2) + return symb_pow(g._SYMBptr->feuille._VECTptr->front(),-g._SYMBptr->feuille._VECTptr->back()); + if (g._SYMBptr->sommet==at_prod && g._SYMBptr->feuille.type==_VECT){ + vecteur v=*g._SYMBptr->feuille._VECTptr; + for (unsigned i=0;i inv_v(1,at_inv); + vector< gen_op_context > applyinv_v(1,doapplyinv); + return subst(g,inv_v,applyinv_v,false,contextptr); + } + + bool helper_polyexp(const gen & gan,const gen & gad_b,const gen & expo_a,const gen & x,gen & res,GIAC_CONTEXT){ + // -1/gad_b*int(gan/(exp(expo_a*t)-1),t,0,inf) + gen ganv=_coeff(makesequence(gan,x),contextptr); + if (ganv.type==_VECT && !ganv._VECTptr->empty() && is_zero(ganv._VECTptr->back())){ + res=0; + vecteur v=*ganv._VECTptr; + gen facti=pow(expo_a,-2,contextptr); + for (int i=1;ifeuille.type==_VECT){ + // extract csts + vecteur v=*g0_._SYMBptr->feuille._VECTptr,v1,v2; + for (unsigned i=0;ifeuille; + if (g0_.type==_VECT && g0_._VECTptr->size()==2){ + gen expo=g0_._VECTptr->back(); + gen base=g0_._VECTptr->front(); + vecteur lv=lvarxwithinv(base,x,contextptr);//rlvarx(base,x); + if (lv.size()==1 && lv.front()==x){ + int na=0,nb=0; + for (;;){ + gen tmp=_quorem(makesequence(base,x-a,x),contextptr); + if (tmp.type==_VECT && tmp._VECTptr->size()==2 && tmp._VECTptr->back()==0){ + ++na; + base=tmp._VECTptr->front(); + continue; + } + tmp=_quorem(makesequence(base,b-x,x),contextptr); + if (tmp.type!=_VECT || tmp._VECTptr->size()!=2 || tmp._VECTptr->back()!=0) + break; + ++nb; + base=tmp._VECTptr->front(); + } + if (derive(base,x,contextptr)==0){ + g0mult=pow(base,expo,contextptr); + g0_=symbolic(at_pow,makesequence(x-a,na*expo))*symbolic(at_pow,makesequence(b-x,nb*expo)); + na=nb=0; // insure next tests are not true + } + else + base=g0_._VECTptr->front(); + bool exchanged=false; + if (na==1 && !nb){ // exchange a and b + // x->b+a-x + base=subst(base,x,b+a-x,false,contextptr); + nb=1; na=0; + exchanged=true; + } + if (nb==1 && !na){ + gen tmp=_horner(makesequence(base,a,x),contextptr); + base=base-tmp; + for (;;){ + gen tmp=_quorem(makesequence(base,x-a,x),contextptr); + if (tmp.type==_VECT && tmp._VECTptr->size()==2 && tmp._VECTptr->back()==0){ + ++na; + base=tmp._VECTptr->front(); + continue; + } + break; + } + if (derive(base,x,contextptr)==0){ + // pow(-base,expo)*int(((b-a)^na-(x-a)^na)^expo,x,a,b) + // let x=a+(b-a)*t^(1/na) + // -> pow(-base,expo)*(b-a)^(1+na*expo)/na*int((1-t)^expo*t^(1/na-1),t,0,1) + res= pow(-base,expo,contextptr)*pow(b-a,1+na*expo,contextptr)*Gamma(inv(na,contextptr),contextptr)*Gamma(expo+1,contextptr)/Gamma(expo+1+inv(na,contextptr),contextptr)/na; + return true; + } + } // nb==1 && !na + } // lv.size()==1 && lv.front()==x + } // g0_.type==-_VECT of size 2 + } // a!=inf && b!=inf && pow + if (!is_inf(a) && !is_inf(b) && g0_.is_symb_of_sommet(at_prod) && g0_._SYMBptr->feuille.type==_VECT && g0_._SYMBptr->feuille._VECTptr->size()==2){ // Beta? + // rewrite ^ of powers + vecteur v=*g0_._SYMBptr->feuille._VECTptr,v1; + for (unsigned i=0;ifeuille,vb=v1.back()._SYMBptr->feuille; + if (va.type==_VECT && va._VECTptr->size()==2 && vb.type==_VECT && vb._VECTptr->size()==2){ + gen va1=va._VECTptr->front(),va1x,va1c,va2=va._VECTptr->back(),vb1=vb._VECTptr->front(),vb2=vb._VECTptr->back(),vb1x,vb1c; + if (va1.is_symb_of_sommet(at_pow) && va1._SYMBptr->feuille.type==_VECT && va1._SYMBptr->feuille._VECTptr->size()==2){ + va2=va1._SYMBptr->feuille._VECTptr->back()*va2; + va1=va1._SYMBptr->feuille._VECTptr->front(); + } + if (vb1.is_symb_of_sommet(at_pow) && vb1._SYMBptr->feuille.type==_VECT && vb1._SYMBptr->feuille._VECTptr->size()==2){ + vb2=vb1._SYMBptr->feuille._VECTptr->back()*vb2; + vb1=vb1._SYMBptr->feuille._VECTptr->front(); + } + if (is_linear_wrt(va1,x,va1x,va1c,contextptr) && is_linear_wrt(vb1,x,vb1x,vb1c,contextptr)){ + if (is_zero(recursive_normal(va1c/va1x+a,contextptr),contextptr) && + is_zero(recursive_normal(vb1c/vb1x+b,contextptr),contextptr)){ + // int( (va1x*(x-a))^va2*(vb1x*(x-b))^vb2,a,b) + res=g0mult*pow(va1x,va2,contextptr)*pow(-vb1x,vb2,contextptr)*pow(b-a,va2+vb2+1,contextptr)*Beta(va2+1,vb2+1,contextptr); + return true; + } + if (is_zero(recursive_normal(va1c/va1x+b,contextptr),contextptr) && + is_zero(recursive_normal(vb1c/vb1x+a,contextptr),contextptr)){ + // int( (va1x*(x-b))^va2*(vb1x*(x-a))^vb2,a,b) + res=g0mult*pow(-va1x,va2,contextptr)*pow(vb1x,vb2,contextptr)*pow(b-a,va2+vb2+1,contextptr)*Beta(va2+1,vb2+1,contextptr); + return true; + } + } + } + } + } + // detect Dirac + vecteur v=lop(g0,at_Dirac); + if (!v.empty()){ + gen A,B,a0,b0; +#ifdef GIAC_HAS_STO_38 + identificateur t("tsumab_"); +#else + identificateur t(" tsumab"); +#endif + gen h=quotesubst(g0,v.front(),t,contextptr); + if (!is_linear_wrt(h,t,A,B,contextptr)) + return false; + gen heav=v.front()._SYMBptr->feuille; + if (heav.type==_VECT && heav._VECTptr->size()==2 && heav._VECTptr->back().type==_INT_ ){ + int diracorder=heav._VECTptr->back().val; + if (diracorder<0){ + *logptr(contextptr) << gettext("Negative second Dirac argument") << '\n'; + return false; + } + A=derive(A,x,diracorder,contextptr); + if (is_undef(A)) + return false; + if (diracorder%2) + A=-A; + heav=heav._VECTptr->front(); + } + if (!is_linear_wrt(heav,x,a0,b0,contextptr) || is_zero(a0)) + return false; + if (!intgab(B,x,a,b,res,contextptr)) + return false; + gen c=-b0/a0; + if (ck_is_greater(c,a,contextptr) && ck_is_greater(b,c,contextptr)) + res += quotesubst(A,x,c,contextptr); + else + *logptr(contextptr) << gettext("Warning, Dirac function outside summation interval") << '\n'; + return true; + } + if (a==b){ + res=0; + return true; + } + gen g=hyp2exp(g0,contextptr); + vecteur lvarg = lvar(g); + bool rational = lvarg==vecteur(1,x); + if (!rational){ + int s1=nvars_depend_x(loptab(g,sincostan_tab),x); + // rewrite cos/sin/tan if more than 1 available, + // do not rewrite atan/asin/acos + if (s1) // check added otherwise int(1/(x-a)^999,x,a-1,a+1) takes forever + g=tsimplify_noexpln(g,s1,0,contextptr); + } + // FIXME should check integrability at -/+inf + if (a==minus_inf){ + gen A=limit(g,*x._IDNTptr,a,1,contextptr); + if (!is_zero(A) && b!=plus_inf){ + res=-a*A; + return !is_undef(res); // true; + } + if (b==plus_inf){ + vecteur singu=find_singularities(g,*x._IDNTptr,0 /* real singularities*/,contextptr); + if (!singu.empty()){ + *logptr(contextptr) << "Warning, singularities at " << singu << '\n'; + if (calc_mode(contextptr)==1 || abs_calc_mode(contextptr)==38){ + res=undef; + return true; + } + } + gen B=limit(g,*x._IDNTptr,b,-1,contextptr); + if (!is_zero(B)){ + if (is_zero(A)) + res=b*B; + else + res=b*B-a*A; + return !is_undef(res); // true; + } + int ieo=is_even_odd(g,x,contextptr); + if (ieo==2){ + res=0; + return true; + } + if (is_zero(A) && intgab_r(g,x,a,b,rational,res,contextptr)) + return true; + if (ieo==1){ + // simplify g on 0..inf + assumesymbolic(symb_superieur_egal(x,0),0,contextptr); + gen g1=eval(g,1,contextptr); + purgenoassume(x,contextptr); + if (g1!=eval(g,1,contextptr)){ + res=2*_integrate(makesequence(g1,x,0,plus_inf),contextptr); + return true; + } + } + return false; + } // end b==plus_inf (a is still minus_inf) + // subst x by x+b, check parity: even -> 1/2 int(-inf,+inf) + gen gb=subst(g,x,x+b,false,contextptr); + int eo=is_even_odd(gb,x,contextptr); + if (eo==1){ + if ( (rational && intgab_ratfrac(gb,x,res,contextptr)) || + intgab(gb,x,a,plus_inf,res,contextptr) ){ + if (!is_inf(res)) + res=ratnormal(res/2,contextptr); + return true; + } + } + vecteur v; + rlvarx(gb,x,v); + int vs=int(v.size()); + for (int i=0;ifeuille,a,b; + // if f is a*x make the change of var x=-exp(t) + if (is_linear_wrt(f,x,a,b,contextptr) && is_zero(b)){ + vecteur vin=makevecteur(v[i],x); + vecteur vout=makevecteur(ln(-a,contextptr)+x,-exp(x,contextptr)); + gb=quotesubst(gb,vin,vout,contextptr)*exp(x,contextptr); + return intgab(gb,x,minus_inf,plus_inf,res,contextptr); + } + } + } + return false; + } // end a==minus_inf + if (b==plus_inf){ + gen ga_orig=subst(g,x,x+a,false,contextptr),ga(ga_orig); + // additional check for int(t^n/(exp(alpha*t)-1),t,0,inf)=n!/alpha^(n+1)*Zeta(n+1) + vecteur vax=rlvarx(ga,x); + if (vax.size()==2 && vax.front()==x && vax.back().is_symb_of_sommet(at_exp)){ + gen expo=vax.back(),expo_a,expo_b; + if (is_linear_wrt(expo._SYMBptr->feuille,x,expo_a,expo_b,contextptr) && is_strictly_positive(expo_a,contextptr)){ + gen gand=_fxnd(ga,contextptr); + if (gand.type==_VECT && gand._VECTptr->size()==2){ + gen gan=gand._VECTptr->front(),gad=gand._VECTptr->back(),gad_a,gad_b; + // gad must be a power of expo-exp(expo_b), starting with linear + if (rlvarx(gan,x).size()==1 && is_linear_wrt(gad,expo,gad_a,gad_b,contextptr)){ + // gad=gad_a*(expo+gad_b/gad_a) + gen test=ratnormal(gad_a*exp(expo_b,contextptr)+gad_b,contextptr); + if (is_zero(test) && helper_polyexp(gan,gad_b,expo_a,x,res,contextptr)) + return true; + test=ratnormal(gad_a*exp(expo_b,contextptr)-gad_b,contextptr); + if (is_zero(test)){ + gen res2,res1; + if (helper_polyexp(gan,gad_b,2*expo_a,x,res2,contextptr) && helper_polyexp(gan,gad_b,expo_a,x,res1,contextptr)){ + res=ratnormal(2*res2-res1,contextptr); + return true; + } + } + } // end if (rlvarx(gan,x).size()==1 + } // end if gand.type==_VECT + identificateur t(" tintgab"); + gen y(t); + ga=subst(ga,expo,y,false,contextptr); + vecteur f=factors(ga,x,contextptr); // Factor then split factors + gen xfact(plus_one),yfact(plus_one); + if (separate_variables(f,x,y,xfact,yfact,contextptr)){ + // yfact must be a fraction with denominator a power of expo-exp(expo_b) + gen y0=exp(expo_b,contextptr); + gen expofact=_fxnd(yfact,contextptr); + if (expofact.type==_VECT && expofact._VECTptr->size()==2){ + gen exponum=expofact._VECTptr->front(),expoden=expofact._VECTptr->back(); + int n=_degree(makesequence(expoden,y),contextptr).val; + gen coeffden=ratnormal(expoden/pow(y-y0,n,contextptr),contextptr); + if (n>1 && is_zero(derive(coeffden,y,contextptr))){ + // 1/expoden*xfact*exponum(y)/(y-1)^n, y'=expo_a*y + gen additional=_quorem(makesequence(exponum,pow(y-1,n-1),y),contextptr); + exponum=additional[1]; + gen xfactc=_coeff(makesequence(xfact,x),contextptr); + if (xfactc.type==_VECT && !xfactc._VECTptr->empty()){ + vecteur & xfactv=*xfactc._VECTptr; + // check cancellation of xfact at 0 at least order n + bool check=true; + for (int i=1;i<=n;++i){ + if (xfactv[xfactv.size()-i]!=0){ + check=false; + break; + } + } + if (check){ + // reduce degree by integration by part + // int(P(t)*Q(e^at)/(e^at-1)^n= + // int( (1/(n-1)*P'/a-P)*Q(e^at)+1/(n-1)P*Q'(e^at))/(e^at-1)^(n-1) + gen int1=(derive(xfact,x,contextptr)/((n-1)*expo_a)-xfact)*subst(exponum/pow(y-1,n-1,contextptr),y,exp(expo_a*x,contextptr),false,contextptr); + int1=_integrate(makesequence(int1,x,0,plus_inf),contextptr); + gen int2=xfact/gen(n-1)*subst(derive(exponum,y,contextptr)/pow(y-1,n-1,contextptr),y,exp(expo_a*x,contextptr),false,contextptr); + int2=_integrate(makesequence(int2,x,0,plus_inf),contextptr); + gen int3=xfact*subst(additional[0]/(y-1),y,exp(expo_a*x,contextptr),false,contextptr); + int3=_integrate(makesequence(int3,x,0,plus_inf),contextptr); + res=(int1+int2+int3)/coeffden; + return true; + } + } + } + } + } + } // end if (is_linear_wrt(expo...)) + } // end varx.size()==2 + ga=ga_orig; + int eo=is_even_odd(ga,x,contextptr); + if (eo==1){ + vecteur singu=find_singularities(g,*x._IDNTptr,0 /* real singularities*/,contextptr); + if (singu.empty()){ + if ( (rational && intgab_ratfrac(ga,x,res,contextptr)) || + intgab(ga,x,minus_inf,plus_inf,res,contextptr) ){ + if (!is_inf(res)) + res=ratnormal(res/2,contextptr); + return !is_undef(res); + } + } + } + vecteur v; + rlvarx(ga,x,v); + int vs=int(v.size()); + for (int i=0;ifeuille,a,b; + // if f is a*x make the change of var x=exp(t) + if (is_linear_wrt(f,x,a,b,contextptr) && is_zero(b)){ + vecteur vin=makevecteur(v[i],x); + vecteur vout=makevecteur(ln(a,contextptr)+x,exp(x,contextptr)); + ga=quotesubst(ga,vin,vout,contextptr)*exp(x,contextptr); + return intgab(ga,x,minus_inf,plus_inf,res,contextptr); + } + } + } + return false; + } + gen gab=subst(g0,x,b,false,contextptr)-subst(g0,x,a,false,contextptr); + gen gabd; + if (!has_evalf(gab,gabd,1,contextptr) || is_zero(gabd)) + gab=simplify(gab,contextptr); + gen gm=subst(g0,x,b,false,contextptr)+subst(g0,x,a,false,contextptr); + if (!has_evalf(gm,gabd,1,contextptr) || is_zero(gabd)) + gm=simplify(gm,contextptr); + if (is_constant_wrt(g,x,contextptr) && lop(g,at_sign).empty() ){ + if (contains(g,x)) + g=ratnormal(g,contextptr); + res=g*(b-a); + return true; + } + int eo=0; + if (is_zero(gab) || is_zero(gm) ){ + identificateur t("tintgab_"); + gen tt(t); + gm=subst(g0,x,tt+(a+b)/2,false,contextptr); + eo=is_even_odd(gm,tt,contextptr); + } + if (!nonrecursive && eo==1){ + if (!intgab(g0,x,a,(a+b)/2,res,true,contextptr)) + return false; + res=2*res; + return true; + } + if (eo==2){ +#if 0 // set to 1 if you want to check for singularities before returning 0 + vecteur sp=find_singularities(g,*x._IDNTptr,false,contextptr); + for (int i=0;isommet!=at_exp && vx[i]._SYMBptr->sommet!=at_sin && vx[i]._SYMBptr->sommet!=at_cos && vx[i]._SYMBptr->sommet!=at_tan)) + gm=1; + } + if (is_zero(gm)){ + gm=subst(g0,x,x+(b-a),false,contextptr); + gm=simplify(gm-g0,contextptr); + } + } +#ifndef NO_STDEXCEPT + try { +#endif + if (is_zero(gm)){ + // try to rewrite g as a function of exp(2*i*pi*x/(b-a)) + g=_lin(trig2exp(g0,contextptr),contextptr); + vecteur v; + rlvarx(g,x,v); + islesscomplexthanf_sort(v.begin(),v.end()); + int i,s=int(v.size()); + if (s>=2){ + gen v0,alpha,beta,alphacur,betacur,gof,periode,periodecur; + for (i=0;ifeuille; + if (is_linear_wrt(v0arg,x,alphacur,betacur,contextptr) && is_integer( (periodecur=normal(alphacur*(b-a)/cst_two_pi/cst_i,contextptr)) )){ + periode=gcd(periode,periodecur,contextptr); + } + } + } + if (!is_zero(periode)){ + alpha=normal(periode*cst_two_pi/(b-a)*cst_i,contextptr); + if (is_zero(re(alpha,contextptr))){ + beta=normal(betacur*alpha/alphacur,contextptr); + gen radius=exp(re(beta,contextptr),contextptr); + // vO=exp(alpha*x+beta) -> x=(ln(v0)-beta)/alpha + vecteur vin=makevecteur(x); + vecteur vout=makevecteur((ln(x,contextptr)-beta)/alpha); + // check for essential singularities + vecteur v2=lop(recursive_normal(rlvarx(subst(v,vin,vout,false,contextptr),x),contextptr),at_exp); + vecteur w2=singular(exp2pow(v2,contextptr),x,contextptr); + unsigned w2i=0; + for (;w2i-alpha + alpha=-alpha; + beta=normal(betacur*alpha/alphacur,contextptr); + radius=exp(re(beta,contextptr),contextptr); + // vO=exp(alpha*x+beta) -> x=(ln(v0)-beta)/alpha + vin=makevecteur(x); + vout=makevecteur((ln(x,contextptr)-beta)/alpha); + // check for essential singularities + v2=lop(recursive_normal(rlvarx(subst(v,vin,vout,false,contextptr),x),contextptr),at_exp); + w2=singular(v2,x,contextptr); + w2i=0; + for (;w2i0) + return false; + roots.clear(); + if (deg<1) + return true; + roots=crationalroot(PP,false); + roots=*_sort(roots,contextptr)._VECTptr; + if (int(roots.size())!=deg) + return false; + return true; + } + + // tmp1=sum_k a_k x^k, find sum_k a_k/s_k x^k + // where s_x=product(k-decals[i],i) and decals[i] is rationnal + // if decals[i] is an integer, multiply by x^(-1-decals[i]), int + // and mult by x^decals[i] + static bool in_sumab_int(gen & tmp1,const gen & gx,const vecteur & decals,const gen & lcoeff,GIAC_CONTEXT){ + int nstep=int(decals.size()); + gen coeff=lcoeff; + gen remains; + for (int i=0;inum; + gen d=decals[i]._FRACptr->den; + // coeff*(k-n/d)=coeff/d*(d*k-n) + coeff = coeff/d; + // sum a_k/(d*k-n)*gx^k + // set gx=X^d : sum_ a_k/(d*k-n)*X^(d*k) + tmp1=subst(tmp1,gx,pow(gx,d,contextptr),false,contextptr); + tmp1=tmp1*pow(gx,-1-n,contextptr); + tmp1=integrate_id_rem(tmp1,gx,remains,contextptr,0); + if (is_undef(tmp1)) return false; + tmp1=tmp1-limit(tmp1,*gx._IDNTptr,0,1,contextptr); + if (is_inf(tmp1)) return false; // for sum(1/((n+1)*(2*n-1)),n,0,inf); + tmp1=ratnormal(tmp1*pow(gx,n,contextptr),contextptr); + tmp1=ratnormal(subst(tmp1,gx,pow(gx,inv(d,contextptr),contextptr),false,contextptr),contextptr); + } + else { + tmp1=tmp1*pow(gx,-1-decals[i],contextptr); + tmp1=integrate_id_rem(tmp1,gx,remains,contextptr,0); + if (is_undef(tmp1)) return false; + tmp1=tmp1-limit(tmp1,*gx._IDNTptr,0,1,contextptr); + tmp1=tmp1*pow(gx,decals[i],contextptr); + } + if (!is_zero(remains)) + return false; + } + tmp1=tmp1/coeff; + return true; + // do_lnabs(b,contextptr); + } + + static bool sumab_int(gen & tmp1,const gen & gx,const vecteur & decals,const gen & lcoeff,GIAC_CONTEXT){ + bool b=do_lnabs(contextptr); + do_lnabs(false,contextptr); + // bool c=complex_mode(contextptr); + // complex_mode(true,contextptr); + bool bres=in_sumab_int(tmp1,gx,decals,lcoeff,contextptr); + do_lnabs(b,contextptr); + // complex_mode(c,contextptr); + return bres; + } + + static bool sumab_ps(const polynome & Q,const polynome & R,const vecteur & v,const gen & a,const gen & x,const gen & g,bool est_reel,const polynome & p,const polynome & s,gen & res,GIAC_CONTEXT){ + // p corresponds to derivation, s to integration + // cerr << "p=" << p << " s=" << s << " Q=" << Q << " R=" << R << '\n'; + // Q must be independent of x + // If R is independent of x we use the geometric series + // If R=x-integer the exponential (must change bounds by integer) + // If R=2x(2x+1) sinh/cosh etc. + if (Q.degree(0)==0){ + // count "integrations" step in s + int intstep; + vecteur decals; + polynome lcoeffs; + if (is_admissible_poly(s,intstep,lcoeffs,decals,contextptr)){ + gen lcoeff=r2e(lcoeffs,v,contextptr); +#ifdef GIAC_HAS_STO_38 + identificateur idx("sumw_"); // identificateur idx(" x"); // +#else + identificateur idx(" sumw"); // identificateur idx(" x"); // +#endif + gen gx(idx); // ("` sumw`",contextptr); + // parser instead of temporary otherwise bug with a:=1; ZT(f,z):=sum(f(n)/z^n,n,0,inf); ZT(k->c^k,z); ZT; + // otherwise while purge(gx) happens, the string `sumw` is destroyed + // and the global map is not sorted correctly anymore + if (!assume_t_in_ab(gx,0,1,true,true,contextptr)) + return false; + // R must be the product of degree(R) consecutive terms + int r=R.degree(0); + if (r==1){ + vecteur Rv=iroots(R); + if (Rv.size()!=1){ + purgenoassume(gx,contextptr); + return false; + } + gen R0=Rv[0]; + if (is_strictly_greater(R0,a,contextptr)){ + res=undef; + purgenoassume(gx,contextptr); + return true; + } + // Q=Q/R.coord.front().value; + index_t ind=R.coord.front().index.iref(); + ind[0]=0; + gen Qg=r2e(Q,v,contextptr)/r2e(polynome(monomial(R.coord.front().value,ind)),v,contextptr); + // (g|x=a)*s(a)/p(a)/Q^(a-R0)/(a-R0)!*sum(p(n)/s(n)*Q^(n-R0)/(n-R0)!,n=a..inf); + // first compute sum(p(n)*Q^(n-R0)/(n-R0)!,n=R0..inf) + // = sum(p(n+R0)*Q^(n)/n!,n=0..inf) + int d=p.degree(0); + gen Pg=r2e(p,v,contextptr); + vecteur vx(d+1),vy(d+1); + for (int i=0;i<=d;++i){ + vx[i]=i; + vy[i]=ratnormal(subst(Pg,x,R0+i,false,contextptr),contextptr); + } + vecteur w=divided_differences(vx,vy); + // p(n+R0)=w[0]+w[1]*n+w[2]*n*(n-1)+... + // hence the sum is exp(Q)*(w[0]+w[1]*Q+...) + reverse(w.begin(),w.end()); + gen tmp1=symb_horner(w,gx)*exp(gx,contextptr),remains; + // subtract sum(p(n)*Q^(n-R0)/(n-R0)!,n=R0..a-1) + for (int n=R0.val;n=2){ + polynome Rc=lgcd(R); + vecteur Rv=polynome2poly1(R/Rc,1); + // Rv should be a multiple of (r*x-R0)*(r*x-(R0+1))*... + // -Rv[1]/Rv[0]= sum of roots = r*R0 + sum(j,j=0..r-1) + // R0 = -Rv[1]/Rv[0] - (r-1)/2 + gen R0=-Rv[1]/Rv[0]-gen(r-1)/gen(2); + if (R0.type!=_INT_){ + purgenoassume(gx,contextptr); + return false; + } + // check that Rv = cst*product(r*x-(R0+j),j=0..r-1) + vecteur test(1,1); + for (int j=0;jr*a.val){ + res=undef; + purgenoassume(gx,contextptr); + return true; + } + Rc=Rv[0]/pow(gen(r),r)*Rc; + gen Qg=r2e(Q,v,contextptr)/r2e(Rc,v,contextptr); + if (r==2) + Qg=sqrt(Qg,contextptr); + else + Qg=pow(Qg,inv(gen(r),contextptr),contextptr); + // (g|x=a)*s(a)/p(a)/Qg^(r*a-R0)*(r*a-R0)!*sum(p(n)/s(n)*Qg^(r*n-R0)/(r*n-R0)!,n=a..inf); + gen coeffa=g*r2e(s,v,contextptr)/r2e(p,v,contextptr)/pow(Qg,r*a-R0,contextptr)*factorial(r*a.val-r0); + coeffa=limit(coeffa,*x._IDNTptr,a,1,contextptr); + // Set k=r*n-R0 and compute sum((p/s)((k+R0)/r)*X^k/k!,k=r*a-R0..inf) + int d=p.degree(0); + gen Pg=r2e(p,v,contextptr); + vecteur vx(d+1),vy(d+1); + for (int i=0;i<=d;++i){ + vx[i]=i; + vy[i]=ratnormal(subst(Pg,x,(i+R0)/r,false,contextptr),contextptr); + } + vecteur w=divided_differences(vx,vy); + reverse(w.begin(),w.end()); + gen tmp=symb_horner(w,gx)*exp(gx,contextptr),remains; + // subtract sum(...,k=0..r*a-R0-1) + for (int k=0;k0);somme(x^(4n+1)/(4n+1)!,n,1,inf); + tmp -= subst(Pg,x,(k+R0)/r,false,contextptr)*pow(gx,k)/factorial(k); + } + // keep terms which are = -R0 mod r = N + // for example if r=2 and R0 even, keep even terms + // that is (f(X)+f(-X))/2 + // more generally take + // 1/r*sum(f(X*exp(2i pi*k/r))*exp(-2i pi*k*N/r),k=0..r-1) + int N= -r0 % r; + gen tmp1=0,tmpadd; + for (int k=0;kfeuille.type==_VECT){ + vecteur vp=*gp._SYMBptr->feuille._VECTptr; + res=0; + int i=0; + for (;ifeuille,x,a,b,contextptr) && in_sumab(B,x,a_orig,b_orig,res,testi,false,contextptr)){ + // sum(A*Kronecker(a*x+b),x,a_orig,b_orig)+res + gen xval=-b/a; + if (is_integer(xval) && is_greater(xval,a_orig,contextptr) && is_greater(b_orig,xval,contextptr)) + res += subst(A,x,xval,false,contextptr); + return true; + } + } + vD=lop(v,at_Heaviside); + if (!vD.empty()){ + gen vD0=vD.front(),A,B,a,b; + if (is_linear_wrt(g,vD0,A,B,contextptr) && is_linear_wrt(vD0._SYMBptr->feuille,x,a,b,contextptr) && in_sumab(B,x,a_orig,b_orig,res,testi,false,contextptr)){ + // sum(A*Heaviside(a*x+b),x,a_orig,b_orig)+res + gen xval=-b/a,resadd; + if (is_integer(xval) && is_strictly_positive(a,contextptr) && in_sumab(A,x,max(a_orig,xval,contextptr),b_orig,resadd,testi,false,contextptr)){ + res += resadd; + return true; + } + } + } + v=loptab(v,sincostan_tab); + bool est_reel=testi?!has_i(g):true; + if (!v.empty()){ + gen w=trig2exp(v,contextptr); + vecteur vexp; + lin(subst(g,v,*w._VECTptr,true,contextptr),vexp,contextptr); + const_iterateur it=vexp.begin(),itend=vexp.end(); + for (;it!=itend;){ + gen coeff=*it,tmp; + ++it; // it -> on the arg of the exp that must be linear + gen axb=coeff*symbolic(at_exp,*it); + ++it; + if (!sumab(axb,*x._IDNTptr,a_orig,b_orig,tmp,!est_reel,contextptr)){ + return false; + } + res += tmp; + } + return true; + } + v.clear(); + polynome p,q,r; + gen a(a_orig),b(b_orig); + if (!est_reel || complex_mode(contextptr)){ + bool b=complex_mode(contextptr); + complex_mode(contextptr)=false; + gen reg(g),img(0),reres,imres; + if (!est_reel){ + reg=re(g,contextptr),img=im(g,contextptr); + } + if (!in_sumab(reg,x,a_orig,b_orig,reres,false,false,contextptr) || !in_sumab(img,x,a_orig,b_orig,imres,false,false,contextptr)){ + complex_mode(contextptr)=b; + return false; + } + complex_mode(contextptr)=b; + res=reres+cst_i*imres; + return true; + } + bool Hyper=is_hypergeometric(g,*x._IDNTptr,v,p,q,r,contextptr); + // g(x+1)/g(x) as p(x+1)/p(x)*q(x)/r(x+1) + if (Hyper){ + // Newton binomial: sum_{x=a}^{b} comb(b-a,x-a)*p^x = (p+1)^(b-a)*p^a + // n=b-a + // comb(n,x+1-a)*p^(x+1)/comb(n,x-a)/p^x + // = p*(x-a)!*(n-x+a)!/(x+1-a)!/(n-x-1+a)!=p*(n-x+a)/(x+1-a) + // q=(-qa)*(n-x+a)=(-qa)*(b-x), r=ra*(x-a) -> -q/qa+r/ra=n + // can be generallized with j-unitroots to + // sum_{x=a}^{b} comb(b-a,j*x-j*a)*p^x + // + gen Q=r2sym(q,v,contextptr),R=r2sym(r,v,contextptr),Qa,Qb,Ra,Rb; + if (is_inf(a) || is_inf(b)){ + // gen P=r2sym(p,v,contextptr); + // limit |P(x+1)/P(x)*Q/R| must be <=1 + // for a polynomial limit p(x+1)/p(x) is always 1, + // so we have only Q/R in the limit + int qs=q.lexsorted_degree(),rs=r.lexsorted_degree(); + if (qs>rs){ + res=unsigned_inf; // FIXME: should be more precise! + return true; + } + if (qs==rs){ + gen l=limit(Q/R,*x._IDNTptr,plus_inf,1,contextptr); + l=abs(l,contextptr); + gen tst=superieur_egal(1,l,contextptr); + if (tst.type==_INT_){ + if (tst.val==0){ + res=unsigned_inf; + return true; + } + } + else + *logptr(contextptr) << gettext("Run assume(") << tst << ") otherwise serie is divergent\n"; + } + } + if (a.type==_INT_ && b==plus_inf && p.lexsorted_degree()==0 && r.coord.size()==1 && q+r==0 ){ + // gen coeff=inv(r.coord.front().value,contextptr); + int pui=r.lexsorted_degree(); + // coeff*sum((-1)^k/k^pui,k,a,inf) + // if a is even set res=0, if a is odd set res=-1/a^pui and a++ + res=0; R=inv(R,contextptr); + if (pui==1){ + if (a.val<=0){ + res=R*plus_inf; + return true; + } + res=symbolic(at_ln,2); + if (a.val>1) + res = res-_sum(makesequence(R,x,1,a.val-1),contextptr); + res=res*subst(g/R,x,1,false,contextptr); + return true; + } + // add sum(1/k^pui,k,a,inf) + // -> 2*sum(1/(2*k)^pui,k,a/2,inf)=2^(1-pui)*sum(1/k^pui,k,a/2,inf) + res = - _sum(makesequence(R,x,a,plus_inf),contextptr) + pow(2,1-pui,contextptr)*_sum(makesequence(R,x,(a.val+1)/2,plus_inf),contextptr); + res = -res*subst(g/R,x,a,false,contextptr); + return true; + } + gen n=b-a; + if (is_linear_wrt(Q,x,Qa,Qb,contextptr) && is_linear_wrt(R,x,Ra,Rb,contextptr)){ + // Q/R=(Qa*x+Qb)/(Ra*x+Rb)=(-Qa/Ra)*(-x-Qb/Qa)/(x+Rb/Ra) + gen trueb=normal(-Qb/Qa,contextptr); + gen truea=normal(-Rb/Ra,contextptr); + gen truen=normal(trueb-truea,contextptr); + gen diffa=normal(a-truea,contextptr); + gen diffb=normal(b-trueb,contextptr); + if (diffa.type==_INT_ && diffb.type==_INT_){ + gen P=r2sym(p,v,contextptr); + if (p.lexsorted_degree()==0){ + res = P*(-Qa/Ra)+1; + if (!is_zero(res)) + res=simplify(pow(res,truen,contextptr)*limit(g,*x._IDNTptr,truea,0,contextptr),contextptr); + if (absint(diffb.val)>100 || absint(diffa.val)>100) + return false; + if (diffb.val>0){ // b>trueb: add sum(g,x,trueb+1,b-1) + for (int i=0;i0){ // a>truea : subtract sum(g,x,truea,a-1) + for (int i=0;isize()!=2) + return false; // setsizeerr(); + if (!in_sumab(gsurP*prod,x,a_orig,b_orig,tmpres,false,false,contextptr)) + return false; + res += tmp._VECTptr->back()*tmpres; + prod = prod*R; + R=subst(R,x,x-1,false,contextptr); // R=R-1; + P=tmp._VECTptr->front(); + } + return true; + } + } + } + if (!is_inf(a) && !is_inf(b)) + return false; + if (b==plus_inf && a.type==_INT_ && Hyper){ + polynome s,Q,R; + // limit of q/r at infinity must be 0 + gen test=r2e(q,v,contextptr)/r2e(r,v,contextptr); + test=ratnormal(test*test-1,contextptr); + if (is_zero(test)){ + res=_limit(gen(makevecteur(g,x,plus_inf),_SEQ__VECT),contextptr); + if (!is_zero(res)){ + return is_inf(res); + } + } + if (is_strictly_positive(test,contextptr)){ + res=_limit(gen(makevecteur(g,x,plus_inf),_SEQ__VECT),contextptr); + return true; + } + r=taylor(r,1); + // r(x)/q(x)=s(x+1)/s(x)*R(x)/Q(x+1) + AB2PQR(r,q,s,R,Q); + R=taylor(R,-1); + simplify(p,s); + // IMPROVE: make a partial fraction decomposition of p(n)/s(n) + // [could also make ln return ln(1-x) instead of ln(x-1)] + if (sumab_ps(Q,R,v,a,x,g,est_reel,p,s,res,contextptr)) + return true; + } + gen A,B,P; + int type=is_meromorphic(g,x,A,B,P,contextptr); + int even=is_even_odd(g,x,contextptr); + bool complete=(a==minus_inf && b==plus_inf); + if (type==2){ + if (!is_zero(limit(g,*x._IDNTptr,plus_inf,0,contextptr))){ + res=undef; + return true; + } + if ( complete || even==1){ + if (!complete){ + if (a==minus_inf){ + a=-b; + b=plus_inf; + } + if (a.type!=_INT_) + return false; + } + int ai=a.val; + // find the value of int(cos(pi*x)/sin(pi*x)*g,circle(0,R)) + vecteur v=singular(g,x,contextptr); + if (is_undef(v)) + return false; + gen g2=g*cst_pi*symb_cos(cst_pi*x)/symb_sin(cst_pi*x); + // if root is integer it must not be inside a..b + // the sum of residues of v + sum(g,n=-inf..inf, n not in v) will be 0 + gen somme_residus; + int vs=int(v.size()); + gen correc=0; + for (int i=0;i0){ + for (int i=1;i=ai;--i) + correc += quotesubstcheck(g,x,i,v,contextptr); + } + res=(-quotesubstcheck(g,x,0,v,contextptr)-somme_residus)/2; + } + res=correc+res; + res=recursive_normal(trig2exp(res,contextptr),contextptr); + return true; + } + } + return false; + } + + // if true put int(g,x=a..b) into res + // a or b must be +/-infinity and afeuille); + int args=int(argv.size()),i; + res=0; + gen tmp; + for (i=0;ifeuille; + if (heav.type==_VECT && heav._VECTptr->size()==3){ + B=B+A*heav._VECTptr->back(); + A=A*((*heav._VECTptr)[1]-heav._VECTptr->back()); + heav=heav._VECTptr->front(); + } + else return false; // setsizeerr(); + if (!is_linear_wrt(heav,x,a,b,contextptr) || is_zero(a)) + return false; + if (!sumab(B,x,a_orig,b_orig,res,testi,contextptr)) + return false; + gen c=-b/a; + if (ck_is_greater(c,a_orig,contextptr) && ck_is_greater(b_orig,c,contextptr)) + res += quotesubst(A,x,c,contextptr); + else + *logptr(contextptr) << gettext("Warning, Dirac function outside summation interval") << '\n'; + return true; + } + // detect Heaviside + v=lop(g,at_Heaviside); + if (v.empty()) + return in_sumab(g,x,a_orig,b_orig,res,testi,true /* do partfrac */,contextptr); + gen A,B,a,b; + identificateur t(" tsumab"); + gen h=quotesubst(g,v.front(),t,contextptr); + if (!is_linear_wrt(h,t,A,B,contextptr)) + return false; + // A*Heaviside()+B + gen heav=v.front()._SYMBptr->feuille; + if (!is_linear_wrt(heav,x,a,b,contextptr) || is_zero(a)) + return false; + if (!sumab(B,x,a_orig,b_orig,res,testi,contextptr)) + return false; + // for A additional condition a*x+b>=0 : if a>0 x>=-b/a else x<=-b/a + gen c=-b/a; + gen newa,newb; + if (ck_is_positive(a,contextptr)){ + if (ck_is_greater(a_orig,c,contextptr)){ + newa=a_orig; newb=b_orig; + } + else { + if (ck_is_greater(b_orig,c,contextptr)){ + newa=_ceil(c,contextptr); + newb=b_orig; + } + else + return true; + } + } + else { + if (ck_is_greater(a_orig,c,contextptr)) + return true; + if (ck_is_greater(b_orig,c,contextptr)){ + newa=a_orig; + newb=_floor(c,contextptr); + } + else { + newa=a_orig; + newb=b_orig; + } + } + gen sumA; + if (!sumab(A,x,newa,newb,sumA,testi,contextptr)) + return false; + res += sumA; + return true; + } + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/isom.cc b/android/app/src/main/cpp/giac/src/giac/cpp/isom.cc new file mode 100644 index 0000000..58d8ee6 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/isom.cc @@ -0,0 +1,310 @@ +// -*- mode:C++ ; compile-command: "g++ -I.. -g -c isom.cc " -*- +#include "giacPCH.h" + +/* + * Copyright (C) 2001,14 R. De Graeve, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using namespace std; +#include "isom.h" +#include "gen.h" +#include "vecteur.h" +#include "derive.h" +#include "subst.h" +#include "usual.h" +#include "symbolic.h" +#include "sym2poly.h" +#include "giacintl.h" + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + + vecteur isom(const vecteur & M,GIAC_CONTEXT){ + gen errcode=checkanglemode(contextptr); + if (is_undef(errcode)) return vecteur(1,errcode); + int n; + n=int(M.size()); + vecteur I; + // for (int i=0;i=0 l'angle est acos(t) + return(makevecteur(nn,acos(t,contextptr),b)); + } + else { + //si s<0 l'angle est -acos(t) + return(makevecteur(nn,-acos(t,contextptr),b)); + } + } + } + return 0; + } + static gen symb_isom(const gen & args){ + return symbolic(at_isom,args); + } + gen _isom(const gen & args,GIAC_CONTEXT){ + if ( args.type==_STRNG && args.subtype==-1) return args; + if (!ckmatrix(args)) + return symb_isom(args); + return isom(*args._VECTptr,contextptr); + } + static const char _isom_s []="isom"; + static define_unary_function_eval (__isom,&_isom,_isom_s); + define_unary_function_ptr5( at_isom ,alias_at_isom,&__isom,0,true); + + static int mkisom_teste(gen& n,int b, int & d1){ + int d; + //d est la valeur de teste c'est la dim de l'espace du mkisom (d=2 ou >=3 ) + //d>3 pour faire des isometries orthogonales par rapport a un hyperplan + if (n.type==_VECT){ + // n est un vecteur et d1 est la dimension du vecteur n + //si n n'est pas un vecteur il le devient! (cf else ...donc d1>=1) + vecteur e=*(n._VECTptr); + d1=int(e.size()); + if (d1>=3) { + d=d1; + } + else{ + if (d1==1){ + if (b==1){d=2;}else {d=3;} + } + else{ + if (n[0].type==_VECT){d=3;}else{d=2;} + } + } + } + else{ + //ds ce cas n n'est pas un vecteur: il le devient! + n=makevecteur(n); + d1=1; + if (b==1) {d=2;}else {d=3;} + } + return(d); + } + + vecteur mkisom(const gen & n_orig,int b,GIAC_CONTEXT) { + checkanglemode(contextptr); + //n=les elements caracteristiques de l'isometrie et b=+1(rot) ou b=-1 + int d; + int d1; + gen n(n_orig); + d=mkisom_teste(n,b,d1); + //d=2 pour les isometries de R2 et d=3 pour celles de R3; + //d1=dimension de n (n est devenu un vecteur) + if (d==2) { + if (b==1){ + gen theta; + theta=n[0]; + vecteur M2; + vecteur li(2); + li[0]=cos(theta,contextptr); + li[1]=-sin(theta,contextptr); + M2.push_back(li); + li[0]=sin(theta,contextptr); + li[1]=cos(theta,contextptr); + M2.push_back(li); + return(M2); + } + else { + //if (b==-1){ + gen a=n[0]; + gen b=n[1]; + vecteur M2; + vecteur li(2); + li[0]=rdiv(b*b-a*a,a*a+b*b,contextptr); + li[1]=-rdiv(gen(2)*a*b,a*a+b*b,contextptr); + M2.push_back(li); + li[0]=-rdiv(gen(2)*a*b,a*a+b*b,contextptr); + li[1]=-rdiv(b*b-a*a,a*a+b*b,contextptr); + M2.push_back(li); + return(M2); + //} + } + } + if (d>=3) { + vecteur S; + vecteur R; + if (d1==1){ + //on a une symetrie point + vecteur I; + I=midn(d); + return negvecteur(I); + } + vecteur nn(d); + //on a une symetrie plan ou une rotation ou le produit rotation symetrie + if (d1>=3){ + //on a une symetrie plan et nn=n est normal au plan + //gen norme2=dotvecteur(n,n); + nn=*(n._VECTptr); + } + else { + //on a une rot d'axe nn=n[0] ou rot*sym d'axe nn=n[0] et plan orth a nn + nn=*(n[0])._VECTptr; + } + vecteur ntn(d); + //ntn est la matrice d*d egale a : nn*transpose(nn)/(nn*nn) + gen norme2=dotvecteur(nn,nn); + //nnn est le vecteur nn divise par sa norme au carre + vecteur nnn=divvecteur(nn, norme2); + for (int i=0;i=3) {return(S);} + if (d1==2){ + //on a une rotation si b=1 + vecteur A; + //A a comme vecteurs colonnes : produitvectoriel(nnn,ei) + vecteur li(3); + li[0]=0; + li[1]=-nnn[2]; + li[2]=nnn[1]; + A.push_back(li); + li[0]=nnn[2]; + li[1]=0; + li[2]=-nnn[0]; + A.push_back(li); + li[0]=-nnn[1]; + li[1]=nnn[0]; + li[2]=0; + A.push_back(li); + // A*sqrt(norme2) pour avoir la matrice prod vect(n,ei) avec norme(n)=1; + A=multvecteur(sqrt(norme2,contextptr),A); + //cout<size()); + if (s!=2) + return gendimerr(); + if (args._VECTptr->back().type==_INT_){ + gen n=args._VECTptr->front(); + int b=args._VECTptr->back().val; + return mkisom(n,b,contextptr); + } + return symb_mkisom(args); + } + static const char _mkisom_s []="mkisom"; + static define_unary_function_eval (__mkisom,&_mkisom,_mkisom_s); + define_unary_function_ptr5( at_mkisom ,alias_at_mkisom,&__mkisom,0,true); + + + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/k_csdk.c b/android/app/src/main/cpp/giac/src/giac/cpp/k_csdk.c new file mode 100644 index 0000000..ca0b8a9 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/k_csdk.c @@ -0,0 +1,1550 @@ +// implementation of the minimal C SDK for KhiCAS +int (*khicas_shutdown)()=0; + +short shutdown_state=0; +short exam_mode=0,nspire_exam_mode=0; +unsigned exam_start=0; // RTC start +int exam_duration=0; +// <0: indicative duration, ==0 time displayed during exam, >0 end exam_mode after +const int exam_bg1=0x4321,exam_bg2=0x1234; +int exam_bg(){ + return exam_mode?(exam_duration>0?exam_bg1:exam_bg2):0x50719; +} + +void SetQuitHandler( void (*f)(void)){} +#ifdef TICE +int clip_ymin=0; +// TI83 +const int STATUS_AREA_PX=18; +// debug: dbg_printf() Add #include to a source file, and use make debug instead of make to build a debug program. You may need to run make clean beforehand in order to ensure all source files are rebuilt. +// ASM syscalls: https://wikiti.brandonw.net/index.php?title=Category:84PCE:Syscalls:By_Name +// doc: https://ce-programming.github.io/toolchain/index.html +// Makefile options https://ce-programming.github.io/toolchain/static/makefile-options.html +// memory layout: https://ce-programming.github.io/toolchain/static/faq.html +// parameters are in CEdev/meta (and app_tools if present) +// makefile.mk: +// BSSHEAP_LOW ?= D052C6 +// BSSHEAP_HIGH ?= D13FD8 +// STACK_HIGH ?= D1A87E +// INIT_LOC ?= D1A87F +// Can we set STACK_HIGH to another value? I think the global area stack+data could be "reversed", I mean stack top at 0xD2A87F and data(+code+ro_data for RAM programs) at a new position: INIT_LOC=D1987E (maybe +1 or +2) + +// TI stack 4K D1A87Eh: Top of the SPL stack. +// change stack pointer (if STACK_HIGH change does not work) +// requires assembly code (https://0x04.net/~mwk/doc/z80/eZ80.pdf), +// save stack pointer +// LD (Mmn), SP +// set HL to the new stack address (top of the area-3) +// LD SP,HL +// call main +// restore stack pointer +// LD SP,(Mmn) +// 1023 bytes: uint8_t[1023] os_RamCode (do not use if flash write occurs) +// 0xD052C6: 60989 bytes used for bss+heap (temp buffers in TI OS) +// 0xD1A881: Start of UserMem. 64K for code, data, ro data +// size_t os_MemChk(void **free) size and position of free ram area +// Or we could create a VarApp in RAM with no real data inside and use this area for temporary storage. +// 0xD40000: Start of VRAM. 320x240x2 bytes = 153600 bytes. +// half may be used in 8 bits palette mode (graphx) +#include "k_csdk.h" +#include +#include +#include +#include +#include +#include // boot_GetTime(uint8_t *seconds, uint8_t *minutes, uint8_t *hours), boot_SetTime(uint8_t seconds, uint8_t minutes, uint8_t hours) +#include +#include +#include +#include +#include +#define FILENAME_MAXRECORDS 32 +#define FILENAME_MAXSIZE 9 +#define FILE_MAXSIZE 16384 +char os_filenames[FILENAME_MAXRECORDS][FILENAME_MAXSIZE]; + +void sdk_init(){ + dbg_printf("SDK Init\n"); + gfx_Begin(); + unsigned short * addr=gfx_palette; + for (int r=0;r<4;r++){ + for (int g=0;g<8;g++){ + for (int b=0;b<4;b++){ + int R=r*255/3,G=g*255/7,B=b*255/3; + addr[(r<<5)|(g<<2)|b]=gfx_RGBTo1555(R,G,B); + // dbg_printf("palette %i %i %i %i\n",(r<<5)|(g<<2)|b,R,G,B); + } + } + } + // 128-254 arc-en-ciel? 255 should remain white +} + +void sdk_end(){ + dbg_printf("SDK End\n"); + gfx_End(); +} + +void clear_screen(void){ + gfx_FillScreen(255); // gfx_ZeroScreen(void); +} + +int alpha=0,alphalock=0,prevalpha=0,shift=0; +int handle_f5(){ + if (alphalock) + alphalock=3-alphalock; + else + alphalock=2; + return alphalock; +} +void dbgprint(int i){ + char buf[16]={0}; + buf[0]='0'+i/100; + buf[1]='0'+(i % 100)/10; + buf[2]='0'+(i % 10); + os_draw_string(20,60,SDK_WHITE,SDK_BLACK,buf,false); +} +int getkey(int allow_suspend){ + sync_screen(); + statusline(0); + for (;;){ + int i=0; + while (!i){ + i=os_GetCSC(); + } + // dbgprint(i); + int decal=(alpha>>1)<<5; // 0 or 32 for upper or lowercase + int Alpha=alpha,Shift=shift; + shift=0; prevalpha=alpha; + if (!alphalock) + alpha=0; + switch (i){ + case sk_Fx: + return Alpha?KEY_CTRL_F11:Shift?KEY_CTRL_F6:KEY_CTRL_F1; + case sk_Fenetre: + return Alpha?KEY_CTRL_F12:Shift?KEY_CTRL_F7:KEY_CTRL_F2; + case sk_Zoom: + return Alpha?KEY_CTRL_F13:Shift?KEY_CTRL_F8:KEY_CTRL_F3; + case sk_Trace: + return Alpha?KEY_CTRL_F14:Shift?KEY_CTRL_F9:KEY_CTRL_F4; + case sk_Graph: + return Alpha?KEY_CTRL_F15:Shift?KEY_CTRL_F10:KEY_CTRL_F5; + case sk_Mode: + return KEY_CTRL_SETUP; + case sk_Del: + return KEY_CTRL_DEL; + case sk_GraphVar: + return KEY_CTRL_XTT; + // sk_Stats + case sk_Right: + return Shift?KEY_SHIFT_RIGHT:KEY_CTRL_RIGHT; + case sk_Left: + return Shift?KEY_SHIFT_LEFT:KEY_CTRL_LEFT; + case sk_Up: + return Shift?KEY_CTRL_PAGEUP:KEY_CTRL_UP; + case sk_Down: + return Shift?KEY_CTRL_PAGEDOWN:KEY_CTRL_DOWN; + case sk_Enter: + return Alpha?KEY_SHIFT_ANS:KEY_CTRL_EXE; + case sk_Alpha: + if (alphalock){ + alpha=alphalock=0; + } + else { + if (Shift) + alphalock=alpha=2; + else { + alpha=2; + if (prevalpha) + alphalock=alpha=prevalpha; + } + } + statusline(0); + continue; + case sk_2nd: + if (alphalock) + alpha=3-alpha; // maj <> min + else + shift=!Shift; + statusline(0); + continue; + case sk_Math: + return Alpha?KEY_CHAR_A+decal:KEY_CTRL_F6; + case sk_Matrice: + return Alpha?KEY_CHAR_B+decal:KEY_CHAR_MAT; + case sk_Prgm: + return Alpha?KEY_CHAR_C+decal:KEY_CTRL_PRGM; + case sk_Vars: + return KEY_CTRL_VARS; + case sk_Annul: + return Shift?KEY_CTRL_AC:KEY_CTRL_EXIT; + case sk_TglExact: + return KEY_CHAR_D+decal; + case sk_Trig: + return Alpha?KEY_CHAR_E+decal:(Shift?KEY_CHAR_PI:KEY_CHAR_SIN); + case sk_Cos: + return Alpha?KEY_CHAR_F+decal:KEY_CHAR_COS; + case sk_Tan: + return Alpha?KEY_CHAR_G+decal:KEY_CHAR_TAN; + case sk_Power: + return Alpha?KEY_CHAR_H+decal:KEY_CHAR_POW; + case sk_Square: + return Alpha?KEY_CHAR_I+decal:Shift?KEY_CHAR_ROOT:KEY_CHAR_SQUARE; + case sk_Comma: + return Alpha?KEY_CHAR_J+decal:Shift?KEY_CHAR_E:KEY_CHAR_COMMA; + case sk_LParen: + return Alpha?KEY_CHAR_K+decal:Shift?KEY_CHAR_LBRACE:KEY_CHAR_LPAR; + case sk_RParen: + return Alpha?KEY_CHAR_L+decal:Shift?KEY_CHAR_RBRACE:KEY_CHAR_RPAR; + case sk_Div: + return Alpha?KEY_CHAR_M+decal:Shift?KEY_CHAR_E+32:KEY_CHAR_DIV; + case sk_Log: + return Alpha?KEY_CHAR_N+decal:Shift?KEY_CHAR_EXPN10:KEY_CHAR_LOG; + case sk_7: + return Alpha?KEY_CHAR_O+decal:KEY_CHAR_7; + case sk_8: + return Alpha?KEY_CHAR_P+decal:KEY_CHAR_8; + case sk_9: + return Alpha?KEY_CHAR_Q+decal:KEY_CHAR_9; + case sk_Mul: + return Alpha?KEY_CHAR_R+decal:Shift?KEY_CHAR_LBRCKT:KEY_CHAR_MULT; + case sk_Ln: + return Alpha?KEY_CHAR_S+decal:Shift?KEY_CHAR_EXP:KEY_CHAR_LN; + case sk_4: + return Alpha?KEY_CHAR_T+decal:KEY_CHAR_4; + case sk_5: + return Alpha?KEY_CHAR_U+decal:KEY_CHAR_5; + case sk_6: + return Alpha?KEY_CHAR_V+decal:KEY_CHAR_6; + case sk_Sub: + return Alpha?KEY_CHAR_W+decal:Shift?KEY_CHAR_RBRCKT:KEY_CHAR_MINUS; + case sk_Store: + return Alpha?KEY_CHAR_X+decal:KEY_CHAR_STORE; + case sk_1: + return Alpha?KEY_CHAR_Y+decal:KEY_CHAR_1; + case sk_2: + return Alpha?KEY_CHAR_Z+decal:KEY_CHAR_2; + case sk_3: + return Alpha?KEY_CHAR_THETA:KEY_CHAR_3; + case sk_Add: + return KEY_CHAR_PLUS; + case sk_0: + return Alpha?KEY_CHAR_SPACE:Shift?KEY_CTRL_CATALOG:KEY_CHAR_0; + case sk_DecPnt: + return Alpha?':':Shift?KEY_CHAR_I+32:KEY_CHAR_DP; + case sk_Chs: + return Alpha?'?':Shift?KEY_CHAR_ANS:KEY_CHAR_PMINUS; + default: + return i; + } + } +} +void GetKey(int * key){ + *key=getkey(0); +} +int iskeydown(int key){ + kb_Scan(); + return kb_IsDown(key); +} + +// if (kb_On) ... +void enable_back_interrupt(){ + kb_EnableOnLatch(); +} +void disable_back_interrupt(){ + kb_DisableOnLatch(); +} +int isalphaactive(){ + return alpha; +} +int alphawasactive(int * key){ + return prevalpha; +} +void lock_alpha(){ + alpha=alphalock=1; +} +void reset_kbd(){ + shift=alpha=alphalock=0; +} +int GetSetupSetting(int k){ + if (k!=0x14) return -1; + if (!alpha) return 0; + if (!alphalock) return alpha==2?8:4; + return alpha==2?0x88:0x84; +} + +void os_wait_1ms(int ms){ + msleep(ms); // delay(ms)? +} +double millis(){ + return rtc_Days*86400.0+rtc_Hours*3600.+rtc_Minutes*60.+rtc_Seconds; +} +int os_set_angle_unit(int mode){ + if (mode) os_ResetFlag(TRIG,DEGREES); else os_SetFlag(TRIG,DEGREES); + return true; +} + +int os_get_angle_unit(){ + int i=os_TestFlag(TRIG,DEGREES); + return i?0:1; +} +int file_exists(const char * filename){ + int h=ti_Open(filename, "r"); + if (!h) + return false; + ti_Close(h); + return true; +} +int erase_file(const char * filename){ + if (!file_exists(filename)) + return false; + ti_Delete(filename); + return true; +} +const char * read_file(const char * filename){ + const char * ext=0; + int l=strlen(filename); + char var[9]={0}; + strncpy(var,filename,8); + for (--l;l>0;--l){ + if (filename[l]=='.'){ + ext=filename+l+1; + if (l<9) + var[l]=0; + break; + } + } + int h=ti_Open(var, "r"); + if (!h) + return 0; + int s=ti_GetSize(h); + if (s>7){ + //unsigned short u; + //ti_Read(&u,1,2,h); + char subtype[8]={0}; + ti_Read(subtype,1,4,h); + if (strncmp(subtype,"PYCD",4)==0 || strncmp(subtype,"XCAS",4)==0){ + unsigned char dx; + ti_Read(&dx,1,1,h); + if (dx!=0){ + // skip desktop filename + char buf[256]={0}; + ti_Read(buf,1,1,dx); + s -= 4+dx; + dbg_printf("subtype=%s filename=%s %i %i\n",subtype,buf,dx,s); + } + else + s -= 4; + } + else + ti_Seek(0,SEEK_SET,h); + } + char * ptr=0; +#if 0 + // Direct access to the data, ptr should not be used if any change to the TI variables occurs, unfortunately there is no 0 at end of string + ptr= ti_GetDataPtr(h); + ti_Close(h); + dbg_printf("data=%x %x %x %x %x %x %x %x\n",ptr[0],ptr[1],ptr[2],ptr[3],ptr[4],ptr[5],ptr[6],ptr[7]); + return ptr; +#endif + // Code requiring a copy + // if it starts with + // char * ptr=(char *) gfx_vram+LCD_WIDTH_PX*LCD_HEIGHT_PX; // pointer in vram buffer + int S=os_MemChk((void **)&ptr); + if (s>=S) + return 0; + S=ti_Read(ptr,1,s,h); + ptr[S]=0; + ti_Close(h); + dbg_printf("data=%s\n",ptr); + return ptr; +} +int write_file(const char * filename,const char * s,int len){ + // find extension + const char * ext=0; + int l=strlen(filename); + char var[9]={0}; + strncpy(var,filename,8); + for (--l;l>0;--l){ + if (filename[l]=='.'){ + ext=filename+l+1; + if (l<9) + var[l]=0; + break; + } + } + int h=ti_Open(var,"w"); + if (!h) return false; + if (ext){ + bool ispy=strncmp(ext,"py",2)==0; + bool isxw=strncmp(ext,"xw",2)==0; + if (ispy || isxw){ + const char * subtype=isxw?"XCAS":"PYCD"; + ti_Write(subtype,strlen(subtype),1,h); + unsigned char dx=strlen(filename)+1; + ti_Write(&dx,1,1,h); + ti_Write(filename,dx-1,1,h); + } + } + int Len=ti_Write(s,1,len,h); + ti_Close(h); + return Len==len; +} + +int os_file_browser(const char ** filenames,int maxrecords,const char * extension,int storage){ + if (maxrecords>FILENAME_MAXRECORDS) + maxrecords=FILENAME_MAXRECORDS; + void * ptr=os_GetSymTablePtr(); + int cur=0; + for (int count=0;cur=FILENAME_MAXSIZE || !dataptr) + continue; + s[l]=0; + dbg_printf("filebrowser %s %i %x %x %x %x %x %x %x %x %x %x %x %x %x\n",s,type,dataptr[0]&0xff,dataptr[1]&0xff,dataptr[2]&0xff,dataptr[3]&0xff,dataptr[4]&0xff,dataptr[5]&0xff,dataptr[6]&0xff,dataptr[7]&0xff,dataptr[8]&0xff,dataptr[9]&0xff,dataptr[10]&0xff,dataptr[11]&0xff,dataptr[12]&0xff); + // if type==21 dataptr[1]*256+dataptr[0]==size, then data + // xcas session begins with 4 bytes size, on the 83 should be 00 00 xx xx + if (type==21 && dataptr[2]==0 && dataptr[3]==0) + ext="xw"; + // python app, starts with 2 bytes size, "PYCD" or "PYSC" + // the script ifself begins at data.begin() + 6 + scriptOffset + // where scriptOffset = dataptr[6] + 1 + if (!ext){ + if (strncmp(&dataptr[2],"PYCD",4)==0 || strncmp(&dataptr[2],"PYSC",4)==0) + ext="py"; + else if (strncmp(&dataptr[2],"XCAS",4)==0) + ext="xw"; + else { // extension from filename _xw or _py or _... + //dbg_printf("os_file_browser %i %i %x\n",type,l,dataptr); + //dbg_printf("filename %i %s\n",count,s); + for (j=l-1;j>0;--j){ + if (s[j]=='_'){ + ext=s+j+1; + break; + } + } + } + } + if (ext && strcmp(ext,extension)==0){ + if (exam_mode && + (strcmp(s,"session")!=0 + ) + ) + continue; + strncpy(os_filenames[cur],s,FILENAME_MAXSIZE); + filenames[cur]=os_filenames[cur]; + dbg_printf("extension match %i %s %s\n",cur,s,filenames[cur]); + ++cur; + } + } + dbg_printf("filebrowser %i\n",cur); + return cur; +} +// gfx_Begin, gfx_SetDrawBuffer(); gfx_End +// GFX_LCD_WIDTH, HEIGHT, gfx_vbuffer=LCD RAM buffer 76800 bytes +// gfx_vram Total of 153600 bytes in size = 320x240x2 +// gfx_SetDrawBuffer()gfx_SetDrawScreen() +// uint8_t gfx_SetColor(uint8_t index) +// gfx_SetPixel(uint24_t x, uint8_t y) +// uint8_t gfx_GetPixel(uint24_t x, uint8_t y) +// gfx_FillRectangle(int x, int y, int width, int height) +// gfx_FillRectangle_NoClip(uint24_t x, uint8_t y, uint24_t width, uint8_t height) +// gfx_Wait(void)๏ƒ +// gfx_PrintStringXY(const char *string, int x, int y) +//gfx_SetTextFGColor(uint8_t color) +// gfx_SetTextScale(uint8_t width_scale, uint8_t height_scale) +// gfx_SetTextConfig +void sync_screen(){ + //gfx_Wait(); + // gfx_BlitBuffer(); // shoud be done if gfx_SetDrawBuffer() is active; +} +int c_rgb565to888(int c){ + c &= 0xffff; + int r=(c>>11)&0x1f,g=(c>>5)&0x3f,b=c&0x1f; + return (r<<19)|(g<<10)|(b<<3); +} + +int convertcolor(int c){ + // convert 16 bits to default palette + c &= 0xffff; + int r=(c>>11)&0x1f,g=(c>>5)&0x3f,b=c&0x1f; + int R = ((r>>3)<<5) | ((g>>3)<<2) | (b>>3); + //dbg_printf("convert %i r=%i g=%i b=%i to %i\n",c,r,g,b,R); + return R; +} +void setcolor(int c){ + gfx_SetColor(convertcolor(c)); + //gfx_SetTextTransparentColor(0); +} +void os_set_pixel(int x,int y,int c){ + setcolor(c); + gfx_SetPixel(x,y); +} +void os_fill_rect(int x,int y,int w,int h,int c){ + setcolor(c); + gfx_FillRectangle(x,y,w,h); +} +int os_get_pixel(int x,int y){ + return gfx_GetPixel(x,y); +} + +// FIXME? use gfx_SetTransparentColor with a value != FG and BG instead of fill rectangle +int os_draw_string_small(int x,int y,int c,int bg,const char * s,int fake){ + y+=STATUS_AREA_PX; + gfx_SetTextScale(1,1); + int dx=gfx_GetStringWidth(s); + if (!fake){ + gfx_SetColor(bg); + gfx_FillRectangle(x,y,dx,8); + int c_=gfx_SetTextFGColor(c); + int bg_=gfx_SetTextBGColor(bg); + gfx_PrintStringXY(s,x,y); + gfx_SetTextFGColor(c_); + gfx_SetTextBGColor(bg_); + } + return x+dx; +} +int os_draw_string_medium(int x,int y,int c,int bg,const char * s,int fake){ + y+=STATUS_AREA_PX; + gfx_SetTextScale(1,2); + //gfx_SetFontHeight(12); + int dx=gfx_GetStringWidth(s); + if (!fake){ + gfx_SetColor(bg); + gfx_FillRectangle(x,y,dx,16); + int c_=gfx_SetTextFGColor(c); + int bg_=gfx_SetTextBGColor(bg); + gfx_PrintStringXY(s,x,y); + gfx_SetTextFGColor(c_); + gfx_SetTextBGColor(bg_); + } + return x+dx; +} +int os_draw_string(int x,int y,int c,int bg,const char * s,int fake){ + y+=STATUS_AREA_PX; + gfx_SetTextScale(2,2); + int dx=gfx_GetStringWidth(s); + if (!fake){ + gfx_SetColor(bg); + gfx_FillRectangle(x,y,dx,16); + int c_=gfx_SetTextFGColor(c); + int bg_=gfx_SetTextBGColor(bg); + gfx_PrintStringXY(s,x,y); + gfx_SetTextFGColor(c_); + gfx_SetTextBGColor(bg_); + } + return x+dx; +} + +const int statuscolor=12345; +void statuslinemsg(const char * msg){ + os_draw_string(0,-STATUS_AREA_PX,statuscolor,SDK_BLACK,msg,false); +} + +void set_time(int h,int m){ + rtc_Set(rtc_Seconds,m,h,rtc_Days); +} + +void get_time(int *h,int *m){ + *h=rtc_Hours; + *m=rtc_Minutes; +} + +void display_time(){ + int h=rtc_Hours,m=rtc_Minutes; + char msg[10]; + msg[0]=' '; + msg[1]='0'+(h/10); + msg[2]='0'+(h%10); + msg[3]= 'h'; + msg[4]= ('0'+(m/10)); + msg[5]= ('0'+(m%10)); + msg[6]=0; + //msg[6]= 'm'; + //msg[7] = ('0'+(s/10)); + //msg[8] = ('0'+(s%10)); + //msg[9]=0; + os_fill_rect(270,0,LCD_WIDTH_PX-270,15,SDK_BLACK); + os_draw_string_medium(270,-STATUS_AREA_PX,statuscolor,SDK_BLACK,msg,false); +} + +void statusflags(){ + char *msg=0; + if (alpha==2){ + msg=alphalock?"alock":"alpha"; + } + else if (alpha==1){ + msg=alphalock?"ALOCK":"ALPHA"; + } + else { + if (shift) + msg="2nd"; + else + msg=""; + } + os_fill_rect(0,0,LCD_WIDTH_PX,16,SDK_BLACK); + os_draw_string_medium(225,-STATUS_AREA_PX,statuscolor,SDK_BLACK,msg,false); + os_draw_string_medium(160,-STATUS_AREA_PX,statuscolor,SDK_BLACK,os_get_angle_unit()?" rad ":" deg ",false); + display_time(); +} +void statusline(int mode){ + statusflags(); + if (mode==0) + os_draw_string_medium(190,-STATUS_AREA_PX,statuscolor,SDK_BLACK," CAS ",false); + if (mode==0) + return; + sync_screen(); +} +#endif + +#ifdef NSPIRE_NEWLIB +// NB changes for the nspire cx ii +// on_key_pressed() should be modified (returns always true) +// https://hackspire.org/index.php?title=Memory-mapped_I/O_ports_on_CX_II#90140000_-_Power_management +// cx ii power management 0x90140000, +// cx 900B0018 (R/W), 900B0020 (?) +// cx ii 90140050 (R/W): Disable bus access to peripherals. Reads will just return the last word read from anywhere in the address range, and writes will be ignored. +// cx 900F0020 (R/W): LCD contrast/backlight. Valid range for contrast: 0x11a to 0x1ce; normal value is 0x174. However, it can range from 0x100 (backlight off) to about 0x1d0 (about max brightness). +// -> cx ii The OS controls the LCD backlight by writing to 90130018. +#include +#include "os.h" // Ndless/ndless-sdk/include/os.h +#include +#include +#include +#include +#include "k_defs.h" + +void sdk_init(void){ + lcd_init(lcd_type()); // clrscr(); +} + +void sdk_end(void){ + lcd_init(SCR_TYPE_INVALID); + refresh_osscr(); +} + +int c_rgb565to888(int c){ + c &= 0xffff; + int r=(c>>11)&0x1f,g=(c>>5)&0x3f,b=c&0x1f; + return (r<<19)|(g<<10)|(b<<3); +} + +const int nspire_statusarea=18; +int nspireemu=false; + +int waitforvblank(){ + return 0; +} + +int back_key_pressed(){ + return isKeyPressed(KEY_NSPIRE_DEL); +} +// next 3 functions may be void if not inside a window class hierarchy +void os_show_graph(){} // show graph inside Python shell (Numworks), not used +void os_hide_graph(){} // hide graph, not used anymore +void os_redraw(){} // force redraw of window class hierarchy + +int os_set_angle_unit(int mode){ + return false; +} +int os_get_angle_unit(){ + return 0; +} + +double millis(){ + unsigned NSPIRE_RTC_ADDR=0x90090000; + unsigned t1= * (volatile unsigned *) NSPIRE_RTC_ADDR; + return 1000.0*t1; +} + + +void get_hms(int *h,int *m,int *s){ + unsigned NSPIRE_RTC_ADDR=0x90090000; + unsigned t1= * (volatile unsigned *) NSPIRE_RTC_ADDR; + if (exam_mode){ + unsigned t=t1-exam_start; + if (exam_duration>0 && t>exam_duration){ + ;//set_exam_mode(0); + } + else { + if (exam_duration>0) + t1=exam_duration-t; + else { + if (exam_duration<0 && t<-exam_duration) + t1=-exam_duration-t; + } + } + } + unsigned d=t1/86400; + *s=t1%86400; + *h=*s/3600; + *m=(*s-3600* *h)/60; + *s%=60; +} + +void get_time(int *h,int *m){ + int s; + get_hms(h,m,&s); +} + +void set_time(int h,int m){ + // FIXME +} + +#ifndef is_cx2 +#define is_cx2 false +#endif + +double loopsleep(int ms){ + double n=ms*(is_cx2?3000:1000),j=0.0; + for (double i=0;iNSPIRE_FILEBUFFER-1){ + fclose(f); + return 0; + } + for (int i=0;iFILENAME_MAXRECORDS-1) + maxrecords=FILENAME_MAXRECORDS-1; + dp = opendir ("."); + if (dp == NULL){ + filenames[0]=0; + return 0; + } + int cur=0; + while ( (ep = readdir (dp)) && curd_name,*ext=0; + int l=strlen(s_),j; + char s[l+1]; + strcpy(s,s_); + for (j=l-1;j>0;--j){ + if (s[j]=='.'){ + ext=s+j+1; + break; + } + } + if (ext && strcmp(ext,"tns")==0){ + s[j]=0; + for (;j>0;--j){ + if (s[j]=='.'){ + ext=s+j+1; + break; + } + } + } + if (ext && strcmp(ext,extension)==0){ + if (exam_mode && + (strcmp(s_,"session.xw")!=0 && + strcmp(s_,"session.xw.tns")!=0 && + strcmp(s_,"session.py")!=0 && + strcmp(s_,"session.py.tns")!=0 + ) + ) + continue; + strncpy(os_filenames[cur],s_,FILENAME_MAXSIZE); + filenames[cur]=os_filenames[cur]; + ++cur; + } + } + closedir (dp); + filenames[cur]=NULL; +#if 0 + qsort(filenames,cur,sizeof(char *),c_trialpha); +#else + // qsort would be faster for large n, but here n0){ + finished=false; + const char * tmp=filenames[i-1]; + filenames[i-1]=filenames[i]; + filenames[i]=tmp; + } + } + if (finished) + break; + } +#endif + return cur; +} + +Gc nspire_gc=0; + +void reset_gc(){ + if (nspire_gc){ + gui_gc_finish(nspire_gc); + //gui_gc_free(nspire_gc); + } + nspire_gc=0; +} + +Gc * get_gc(){ + if (!nspire_gc){ + nspire_gc=gui_gc_global_GC(); + gui_gc_setRegion(nspire_gc, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + gui_gc_begin(nspire_gc); + } + return &nspire_gc; +} + +void os_set_pixel(int x,int y,int c){ + get_gc(); + gui_gc_setColor(nspire_gc,c_rgb565to888(c)); + gui_gc_drawRect(nspire_gc,x,y+nspire_statusarea,0,0); +} + +void os_fill_rect(int x,int y,int w,int h,int c){ + get_gc(); + gui_gc_setColor(nspire_gc,c_rgb565to888(c)); + gui_gc_fillRect(nspire_gc,x,y+nspire_statusarea,w,h); +} + +int os_get_pixel(int x,int y){ + if (x<0 || x>=SCREEN_WIDTH || y<0 || y>=SCREEN_HEIGHT) + return -1; +#if 1 + get_gc(); + char ** off_buff = ((((char *****)nspire_gc)[9])[0])[0x8]; + int res = *(unsigned short *) (off_buff[y+nspire_statusarea] + 2*x); + return res; +#else + unsigned short * addr=*(unsigned short **) 0xC0000010; + int r=addr[(y+nspire_statusarea)*SCREEN_WIDTH+x]; + return r; +#endif +} + +int nspire_draw_string(int x,int y,int c,int bg,int f,const char * s,int fake){ + // void ascii2utf16(void *buf, const char *str, int max_size): converts the UTF-8 string str to the UTF-16 string buf of size max_size. + int l=strlen(s); + char utf16[2*l+2]; + ascii2utf16(utf16,s,l); + utf16[2*l]=0; + utf16[2*l+1]=0; + get_gc(); + gui_gc_setFont(nspire_gc,f); + int dx=gui_gc_getStringWidth(nspire_gc, f, utf16, 0, l) ; + if (fake) + return x+dx; + int dy=17; + if (f==Regular9) + dy=13; + if (f==Regular11) + dy=16; + gui_gc_setColor(nspire_gc,c_rgb565to888(bg)); + gui_gc_fillRect(nspire_gc,x,y,dx,dy); + gui_gc_setColor(nspire_gc,c_rgb565to888(c)); + //gui_gc_setPen(nspire_gc, GC_PS_MEDIUM, GC_PM_SMOOTH); + gui_gc_drawString(nspire_gc, utf16, x, y-1, GC_SM_NORMAL | GC_SM_TOP); // normal mode + return x+dx; +} + +int os_draw_string(int x,int y,int c,int bg,const char * s,int fake){ + get_gc(); + gui_gc_clipRect(nspire_gc,0,nspire_statusarea,SCREEN_WIDTH,SCREEN_HEIGHT-nspire_statusarea,0); + int i=nspire_draw_string(x,y+nspire_statusarea,c,bg,Regular12,s,fake); + gui_gc_clipRect(nspire_gc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GC_CRO_RESET); + return i; +} +int os_draw_string_small(int x,int y,int c,int bg,const char * s,int fake){ + get_gc(); + gui_gc_clipRect(nspire_gc,0,nspire_statusarea,SCREEN_WIDTH,SCREEN_HEIGHT-nspire_statusarea,GC_CRO_SET); + int i=nspire_draw_string(x,y+nspire_statusarea,c,bg,Regular9,s,fake); + gui_gc_clipRect(nspire_gc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GC_CRO_RESET); + return i; +} + +int os_draw_string_medium(int x,int y,int c,int bg,const char * s,int fake){ + get_gc(); + gui_gc_clipRect(nspire_gc,0,nspire_statusarea,SCREEN_WIDTH,SCREEN_HEIGHT-nspire_statusarea,GC_CRO_SET); + int i=nspire_draw_string(x,y+nspire_statusarea,c,bg,Regular11,s,fake); + gui_gc_clipRect(nspire_gc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GC_CRO_RESET); + return i; +} + +void statuslinemsg(const char * msg){ + get_gc(); + int bg=exam_bg(); + gui_gc_setColor(nspire_gc,c_rgb565to888(bg)); + gui_gc_fillRect(nspire_gc,0,0,SCREEN_WIDTH,nspire_statusarea); + nspire_draw_string(0,0,exam_mode?0xffff:0,bg,Regular9,msg,false); + if (nspireemu) + nspire_draw_string(190,0,exam_mode?0xffff:0,bg,Regular9," emu ",false); + else + nspire_draw_string(190,0,exam_mode?0xffff:0,bg,Regular9," CAS ",false); +} + +void display_time(){ + int h,m,s; + get_hms(&h,&m,&s); + char msg[10]; + msg[0]=' '; + msg[1]='0'+(h/10); + msg[2]='0'+(h%10); + msg[3]= 'h'; + msg[4]= ('0'+(m/10)); + msg[5]= ('0'+(m%10)); + msg[6]=0; + //msg[6]= 'm'; + //msg[7] = ('0'+(s/10)); + //msg[8] = ('0'+(s%10)); + //msg[9]=0; + int bg=exam_bg(); + gui_gc_setColor(nspire_gc,c_rgb565to888(bg)); + gui_gc_fillRect(nspire_gc,270,0,SCREEN_WIDTH-270,nspire_statusarea); + nspire_draw_string(270,0,exam_mode?0xffff:0,bg,Regular9,msg,false); +} + +void sync_screen(){ + get_gc(); + //gui_gc_finish(nspire_gc); + gui_gc_blit_to_screen(nspire_gc); + ck_msleep(10); + //nspire_gc=0; + // gui_gc_begin(nspire_gc); +} + +// Nspire peripheral reset : +// https://github.com/nDroidProject/nDroid-bootloader/blob/master/kernel.c +// https://hackspire.org/index.php?title=Memory-mapped_I/O_ports_on_CX#CC000000_-_SHA-256_hash_generator +// hardware ports +// https://hackspire.org/index.php?title=Memory-mapped_I/O_ports_on_CX + +int nspire_shift=0; +int nspire_ctrl=0; +int nspire_select=false; +void statusflags(){ + char *msg=0; + if (nspire_ctrl){ + if (nspire_shift) + msg="shift ctrl"; + else + msg=" ctrl"; + } + else { + if (nspire_shift) + msg="shift"; + else + msg=""; + } + int bg=exam_bg(); + gui_gc_setColor(nspire_gc,c_rgb565to888(bg)); + gui_gc_fillRect(nspire_gc,210,0,SCREEN_WIDTH-210,nspire_statusarea); + nspire_draw_string(224,0,exam_mode?0xffff:0,bg,Regular9,msg,false); + if (nspireemu) + nspire_draw_string(190,0,exam_mode?0xffff:0,bg,Regular9," emu ",false); + else + nspire_draw_string(190,0,0xf800,bg,Regular9," CAS ",false); +} +void statusline(int mode){ + statusflags(); + display_time(); + if (mode==0) + return; + sync_screen(); +} + + +#define SHIFTCTRL(x, y, z) (nspire_ctrl ? (z) : nspire_shift ? (y) : (x)) +#define SHIFT(x, y) SHIFTCTRL(x, y, x) +#define CTRL(x, y) SHIFTCTRL(x, x, y) +#define NORMAL(x) SHIFTCTRL(x, x, x) + +int ascii_get(int* adaptive_cursor_state){ + if (isKeyPressed(KEY_NSPIRE_CTRL)){ + nspire_ctrl=!nspire_ctrl; + statusline(0); + sync_screen(); + return -2; + } + if (isKeyPressed(KEY_NSPIRE_SHIFT)){ + nspire_shift=!nspire_shift; + statusline(0); + sync_screen(); + return -1; + } + *adaptive_cursor_state = SHIFTCTRL(0, 1, 4); + if (isKeyPressed(KEY_NSPIRE_LEFT)|| isKeyPressed(KEY_NSPIRE_LEFTUP) || isKeyPressed(KEY_NSPIRE_DOWNLEFT)) return SHIFTCTRL(KEY_CTRL_LEFT,KEY_SHIFT_LEFT,KEY_LEFT_CTRL); + if (isKeyPressed(KEY_NSPIRE_RIGHT)|| isKeyPressed(KEY_NSPIRE_UPRIGHT) || isKeyPressed(KEY_NSPIRE_RIGHTDOWN)) return SHIFTCTRL(KEY_CTRL_RIGHT,KEY_SHIFT_RIGHT,KEY_RIGHT_CTRL); + if (isKeyPressed(KEY_NSPIRE_UP)) return SHIFTCTRL(KEY_CTRL_UP,KEY_CTRL_PAGEUP,KEY_UP_CTRL); + if (isKeyPressed(KEY_NSPIRE_DOWN)) return SHIFTCTRL(KEY_CTRL_DOWN,KEY_CTRL_PAGEDOWN,KEY_DOWN_CTRL); + + if (isKeyPressed(KEY_NSPIRE_ESC)) return KEY_CTRL_EXIT ; + if (isKeyPressed(KEY_NSPIRE_HOME)) return KEY_CTRL_MENU ; + if (isKeyPressed(KEY_NSPIRE_MENU)) return KEY_CTRL_CATALOG ; + if (isKeyPressed(KEY_NSPIRE_SIN)) return SHIFT(KEY_CHAR_SIN,KEY_CHAR_ASIN); + if (isKeyPressed(KEY_NSPIRE_COS)) return SHIFT(KEY_CHAR_COS,KEY_CHAR_ACOS); + if (isKeyPressed(KEY_NSPIRE_TAN)) return SHIFT(KEY_CHAR_TAN,KEY_CHAR_ATAN); + + // Characters + if (isKeyPressed(KEY_NSPIRE_A)) return SHIFTCTRL('a','A',KEY_CTRL_A); + if (isKeyPressed(KEY_NSPIRE_B)) return SHIFTCTRL('b','B',KEY_BOOK); + if (isKeyPressed(KEY_NSPIRE_C)) return SHIFTCTRL('c','C',KEY_CTRL_CLIP); + if (isKeyPressed(KEY_NSPIRE_D)) return SHIFTCTRL('d','D',KEY_CTRL_D); + if (isKeyPressed(KEY_NSPIRE_E)) return SHIFTCTRL('e','E',KEY_CTRL_F10); + if (isKeyPressed(KEY_NSPIRE_F)) return SHIFTCTRL('f','F',KEY_CTRL_F11); + if (isKeyPressed(KEY_NSPIRE_G)) return SHIFTCTRL('g','G',KEY_CTRL_F12); + if (isKeyPressed(KEY_NSPIRE_H)) return SHIFTCTRL('h','H',KEY_CTRL_F13); + if (isKeyPressed(KEY_NSPIRE_I)) return SHIFTCTRL('i','I',KEY_CTRL_F14); + if (isKeyPressed(KEY_NSPIRE_J)) return SHIFTCTRL('j','J',KEY_CTRL_F15); + if (isKeyPressed(KEY_NSPIRE_K)) return SHIFTCTRL('k','K',KEY_CTRL_AC); + if (isKeyPressed(KEY_NSPIRE_L)) return SHIFTCTRL('l','L',KEY_CTRL_F14); + if (isKeyPressed(KEY_NSPIRE_M)) return SHIFTCTRL('m','M',KEY_CTRL_CATALOG); + if (isKeyPressed(KEY_NSPIRE_N)) return SHIFTCTRL('n','N',KEY_CTRL_N); + if (isKeyPressed(KEY_NSPIRE_O)) return SHIFTCTRL('o','O',KEY_SHIFT_OPTN); + if (isKeyPressed(KEY_NSPIRE_P)) return SHIFTCTRL('p','P',KEY_CTRL_PRGM); + if (isKeyPressed(KEY_NSPIRE_Q)) return SHIFT('q','Q'); + if (isKeyPressed(KEY_NSPIRE_R)) return SHIFTCTRL('r','R',KEY_CTRL_R); + if (isKeyPressed(KEY_NSPIRE_S)) return SHIFTCTRL('s','S',KEY_CTRL_S); + if (isKeyPressed(KEY_NSPIRE_T)) return SHIFTCTRL('t','T',KEY_CTRL_T); + if (isKeyPressed(KEY_NSPIRE_U)) return SHIFTCTRL('u','U',KEY_CTRL_F13); + if (isKeyPressed(KEY_NSPIRE_V)) return SHIFTCTRL('v','V',KEY_CTRL_PASTE); + if (isKeyPressed(KEY_NSPIRE_W)) return SHIFT('w','W'); + if (isKeyPressed(KEY_NSPIRE_X)) return SHIFTCTRL('x','X',KEY_CTRL_CUT); + if (isKeyPressed(KEY_NSPIRE_Y)) return SHIFT('y','Y'); + if (isKeyPressed(KEY_NSPIRE_Z)) return SHIFTCTRL('z','Z',KEY_CTRL_UNDO); + + // Numbers + if (nspireemu){ // for firebird, redefine ctrl + if (isKeyPressed(KEY_NSPIRE_0)) return SHIFTCTRL('0',KEY_CTRL_F10,')'); + if (isKeyPressed(KEY_NSPIRE_1)) return SHIFTCTRL('1',KEY_CTRL_F1,'!'); + if (isKeyPressed(KEY_NSPIRE_2)) return SHIFTCTRL('2',KEY_CTRL_F2,'@'); + if (isKeyPressed(KEY_NSPIRE_3)) return SHIFTCTRL('3',KEY_CTRL_F3,'#'); + if (isKeyPressed(KEY_NSPIRE_4)) return SHIFTCTRL('4',KEY_CTRL_F4,'$'); + if (isKeyPressed(KEY_NSPIRE_5)) return SHIFTCTRL('5',KEY_CTRL_F5,'%'); + if (isKeyPressed(KEY_NSPIRE_6)) return SHIFTCTRL('6',KEY_CTRL_F6,'^'); + if (isKeyPressed(KEY_NSPIRE_7)) return SHIFTCTRL('7',KEY_CTRL_F7,'&'); + if (isKeyPressed(KEY_NSPIRE_8)) return SHIFTCTRL('8',KEY_CTRL_F8,'*'); + if (isKeyPressed(KEY_NSPIRE_9)) return SHIFTCTRL('9',KEY_CTRL_F9,'('); + } + else { + if (isKeyPressed(KEY_NSPIRE_0)) return SHIFTCTRL('0',KEY_CTRL_F10,KEY_CTRL_F10); + if (isKeyPressed(KEY_NSPIRE_1)) return SHIFTCTRL('1',KEY_CTRL_F1,KEY_CTRL_F1); + if (isKeyPressed(KEY_NSPIRE_2)) return SHIFTCTRL('2',KEY_CTRL_F2,KEY_CTRL_F2); + if (isKeyPressed(KEY_NSPIRE_3)) return SHIFTCTRL('3',KEY_CTRL_F3,KEY_CTRL_F3); + if (isKeyPressed(KEY_NSPIRE_4)) return SHIFTCTRL('4',KEY_CTRL_F4,KEY_CTRL_F4); + if (isKeyPressed(KEY_NSPIRE_5)) return SHIFTCTRL('5',KEY_CTRL_F5,KEY_CTRL_F5); + if (isKeyPressed(KEY_NSPIRE_6)) return SHIFTCTRL('6',KEY_CTRL_F6,KEY_CTRL_F6); + if (isKeyPressed(KEY_NSPIRE_7)) return SHIFTCTRL('7',KEY_CTRL_F7,KEY_CTRL_F7); + if (isKeyPressed(KEY_NSPIRE_8)) return SHIFTCTRL('8',KEY_CTRL_F8,KEY_CTRL_F8); + if (isKeyPressed(KEY_NSPIRE_9)) return SHIFTCTRL('9',KEY_CTRL_F9,KEY_CTRL_F9); + } + + // Symbols + if (isKeyPressed(KEY_NSPIRE_FRAC)) return SHIFTCTRL(KEY_EQW_TEMPLATE,KEY_AFFECT,KEY_AFFECT); + if (isKeyPressed(KEY_NSPIRE_SQU)) return CTRL(KEY_CHAR_SQUARE,KEY_CHAR_ROOT); + if (isKeyPressed(KEY_NSPIRE_TENX)) return CTRL(KEY_CHAR_EXPN10,KEY_CHAR_LOG); + if (isKeyPressed(KEY_NSPIRE_eEXP)) return CTRL(KEY_CHAR_EXPN,KEY_CHAR_LN); + if (isKeyPressed(KEY_NSPIRE_COMMA)) return SHIFTCTRL(',',';',':'); + if (isKeyPressed(KEY_NSPIRE_PERIOD)) return SHIFTCTRL('.',KEY_CTRL_F11,':'); + if (isKeyPressed(KEY_NSPIRE_COLON)) return NORMAL(':'); + if (isKeyPressed(KEY_NSPIRE_LP)) return SHIFTCTRL('(',KEY_CTRL_F13,KEY_CHAR_CROCHETS); + if (isKeyPressed(KEY_NSPIRE_RP)) return SHIFTCTRL(')',KEY_CTRL_F14,KEY_CHAR_ACCOLADES); + if (isKeyPressed(KEY_NSPIRE_SPACE)) return SHIFTCTRL(' ','_','_'); + if (isKeyPressed(KEY_NSPIRE_DIVIDE)) + return SHIFTCTRL('/','%','\\'); + if (isKeyPressed(KEY_NSPIRE_MULTIPLY)) return SHIFTCTRL('*','\'','\"'); + if (isKeyPressed(KEY_NSPIRE_MINUS)) return SHIFTCTRL('-','_', '<'); + if (isKeyPressed(KEY_NSPIRE_NEGATIVE)) return SHIFTCTRL('-',KEY_CTRL_F12,KEY_CHAR_ANS); + if (isKeyPressed(KEY_NSPIRE_PLUS)) return SHIFTCTRL('+', KEY_CHAR_NORMAL,'>'); + if (isKeyPressed(KEY_NSPIRE_EQU)) return SHIFTCTRL('=', '|',KEY_CHAR_STORE); + if (isKeyPressed(KEY_NSPIRE_LTHAN)) return NORMAL('<'); + if (isKeyPressed(KEY_NSPIRE_GTHAN)) return NORMAL('>'); + if (isKeyPressed(KEY_NSPIRE_QUOTE)) return NORMAL('\"'); + if (isKeyPressed(KEY_NSPIRE_APOSTROPHE)) return NORMAL('\''); + if (isKeyPressed(KEY_NSPIRE_QUES)) return SHIFTCTRL('?','|','!'); + if (isKeyPressed(KEY_NSPIRE_QUESEXCL)) return SHIFTCTRL('?','|','!'); + if (isKeyPressed(KEY_NSPIRE_BAR)) return NORMAL('|'); + if (isKeyPressed(KEY_NSPIRE_EXP)) return SHIFT('^',KEY_CHAR_RECIP); + if (isKeyPressed(KEY_NSPIRE_EE)) return SHIFTCTRL('&','%', '@'); + if (isKeyPressed(KEY_NSPIRE_PI)) return KEY_CHAR_PI; + if (isKeyPressed(KEY_NSPIRE_FLAG)) return SHIFTCTRL(';',':',KEY_CHAR_IMGNRY); + if (isKeyPressed(KEY_NSPIRE_ENTER)) return SHIFTCTRL(KEY_CTRL_OK,'~',KEY_CTRL_EXE); + if (isKeyPressed(KEY_NSPIRE_TRIG)) return SHIFTCTRL(KEY_CHAR_SIN,KEY_CHAR_COS,KEY_CHAR_TAN); + + // Special chars + if (isKeyPressed(KEY_NSPIRE_SCRATCHPAD)) return SHIFTCTRL(KEY_CTRL_SETUP,KEY_LOAD,KEY_SAVE); + if (isKeyPressed(KEY_NSPIRE_VAR)) return SHIFTCTRL(KEY_CTRL_VARS,KEY_CHAR_FACTOR,KEY_CHAR_STORE); + if (isKeyPressed(KEY_NSPIRE_DOC)) return SHIFTCTRL(KEY_CTRL_MENU,KEY_CTRL_SD,KEY_CTRL_INS); + if (isKeyPressed(KEY_NSPIRE_CAT)) return KEY_BOOK; + if (isKeyPressed(KEY_NSPIRE_DEL)) return SHIFTCTRL(KEY_CTRL_DEL,KEY_CTRL_DEL,KEY_CTRL_AC); + if (isKeyPressed(KEY_NSPIRE_RET)) return KEY_CTRL_EXE; + if (isKeyPressed(KEY_NSPIRE_TAB)) return '\t'; + + return 0; +} + +int handle_f5(){ return 0; } +int iskeydown(int key){ + t_key t=KEY_NSPIRE_SPACE; + switch (key){ + case 0: + t=KEY_NSPIRE_LEFT; + break; + case 1: + t=KEY_NSPIRE_UP; + break; + case 2: + t=KEY_NSPIRE_DOWN; + break; + case 3: + t=KEY_NSPIRE_RIGHT; + break; + case 4: + t=KEY_NSPIRE_ENTER; + break; + case 5: + t=KEY_NSPIRE_ESC; + break; + case 6: + t=KEY_NSPIRE_HOME; + break; + case 7: + t=KEY_NSPIRE_MENU; + break; + case 12: + t=KEY_NSPIRE_SHIFT; + break; + case 13: + t=KEY_NSPIRE_CTRL; + break; + case 14: + t=KEY_NSPIRE_SCRATCHPAD; + break; + case 15: + t=KEY_NSPIRE_VAR; + break; + case 16: + t=KEY_NSPIRE_DOC; + break; + case 17: + t=KEY_NSPIRE_DEL; + break; + case 18: + t=KEY_NSPIRE_eEXP; + break; + case 19: + t=KEY_NSPIRE_EQU; + break; + case 20: + t=KEY_NSPIRE_TENX; + break; + case 21: + t=KEY_NSPIRE_I; + break; + case 22: + t=KEY_NSPIRE_COMMA; + break; + case 23: + t=KEY_NSPIRE_EXP; + break; + case 24: + t=KEY_NSPIRE_TRIG; + break; + case 25: + t=KEY_NSPIRE_C; + break; + case 26: + t=KEY_NSPIRE_T; + break; + case 27: + t=KEY_NSPIRE_PI; + break; + case 28: + t=KEY_NSPIRE_S; + break; + case 29: + t=KEY_NSPIRE_SQU; + break; + case 30: + t=KEY_NSPIRE_7; + break; + case 31: + t=KEY_NSPIRE_8; + break; + case 32: + t=KEY_NSPIRE_9; + break; + case 33: + t=KEY_NSPIRE_LP; + break; + case 34: + t=KEY_NSPIRE_RP; + break; + case 36: + t=KEY_NSPIRE_4; + break; + case 37: + t=KEY_NSPIRE_5; + break; + case 38: + t=KEY_NSPIRE_6; + break; + case 39: + t=KEY_NSPIRE_MULTIPLY; + break; + case 40: + t=KEY_NSPIRE_DIVIDE; + break; + case 42: + t=KEY_NSPIRE_1; + break; + case 43: + t=KEY_NSPIRE_2; + break; + case 44: + t=KEY_NSPIRE_3; + break; + case 45: + t=KEY_NSPIRE_PLUS; + break; + case 46: + t=KEY_NSPIRE_MINUS; + break; + case 48: + t=KEY_NSPIRE_0; + break; + case 49: + t=KEY_NSPIRE_PERIOD; + break; + case 50: + t=KEY_NSPIRE_EE; + break; + case 51: + t=KEY_NSPIRE_NEGATIVE; + break; + case 52: + t=KEY_NSPIRE_RET; + break; + } + return isKeyPressed(t); +} + + +// ? see also ndless-sdk/thirdparty/nspire-io/arch-nspire/nspire.c nio_ascii_get +int getkey(int allow_suspend){ + sync_screen(); + if (shutdown_state) + return KEY_SHUTDOWN; + int lastkey=-1; + unsigned NSPIRE_RTC_ADDR=0x90090000; + static unsigned lastt=0; + for (;;){ + unsigned t1= * (volatile unsigned *) NSPIRE_RTC_ADDR; + if (lastt==0) + lastt=t1; + if (t1-lastt>10){ + display_time(); + sync_screen(); + } + int autosuspend=(t1-lastt>=100); + if (nspire_exam_mode!=2 && + is_cx2 && nspire_ctrl && on_key_pressed()){ + os_fill_rect(50,90,200,40,0x1234); + nspire_draw_string(60,120,0,0xffff,Regular12,"Quit KhiCAS to shutdown",false); + nspire_ctrl=false; + statusline(1); + continue; + } + if ( (nspire_exam_mode==2 || !is_cx2) && + allow_suspend && (autosuspend || (nspire_ctrl && on_key_pressed()))){ + nspire_ctrl=nspire_shift=false; + while (!autosuspend && on_key_pressed()) + loopsleep(10); + // somewhat OFF by setting LCD to 0 + unsigned NSPIRE_CONTRAST_ADDR=is_cx2?0x90130014:0x900f0020; + unsigned oldval=*(volatile unsigned *)NSPIRE_CONTRAST_ADDR,oldval2; + if (is_cx2){ + oldval2=*(volatile unsigned *) (NSPIRE_CONTRAST_ADDR+4); + *(volatile unsigned *) (NSPIRE_CONTRAST_ADDR+4)=0xffff; + } + *(volatile unsigned *)NSPIRE_CONTRAST_ADDR=is_cx2?0xffff:0x100; + static volatile uint32_t *lcd_controller = (volatile uint32_t*) 0xC0000000; + lcd_controller[6] &= ~(0b1 << 11); + loopsleep(20); + lcd_controller[6] &= ~ 0b1; + unsigned offtime=* (volatile unsigned *) NSPIRE_RTC_ADDR; + for (int n=0;!on_key_pressed();++n){ + loopsleep(100); + idle(); + if (!exam_mode && nspire_exam_mode!=2 && khicas_shutdown + // && n&0xff==0 + ){ + unsigned curtime=* (volatile unsigned *) NSPIRE_RTC_ADDR; + if (curtime-offtime>7200){ + shutdown_state=1; + // after 2 hours, leave KhiCAS + // that way the OS will really shutdown the calc + lcd_controller[6] |= 0b1; + loopsleep(20); + lcd_controller[6]|= 0b1 << 11; + if (is_cx2) + *(volatile unsigned *)(NSPIRE_CONTRAST_ADDR+4)=oldval2; + *(volatile unsigned *)NSPIRE_CONTRAST_ADDR=oldval; + statuslinemsg("Press ON to disable KhiCAS auto shutdown"); + //os_fill_rect(0,0,320,222,0xffff); + sync_screen(); + int m=0,mmax=150; + for (;m=KEY_CTRL_LEFT && i<=KEY_CTRL_RIGHT) || + (i>=KEY_UP_CTRL && i<=KEY_RIGHT_CTRL) || + (i>=KEY_SELECT_LEFT && i<=KEY_SELECT_RIGHT) || + i==KEY_CTRL_DEL){ + int delay=(lastkey==i)?5:60,j; + for (j=0;j +#include +#include +#include +#include +#define HAVE_TIME_H +#include + +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC + xcas::tableur * new_tableur(GIAC_CONTEXT){ + xcas::tableur * sheetptr=new xcas::tableur; +#ifdef NUMWORKS + sheetptr->nrows=14; sheetptr->ncols=4; +#else + sheetptr->nrows=20; sheetptr->ncols=5; +#endif + gen g=vecteur(sheetptr->ncols); + sheetptr->m=makefreematrice(vecteur(sheetptr->nrows,g)); + makespreadsheetmatrice(sheetptr->m,contextptr); + sheetptr->cur_row=sheetptr->cur_col=sheetptr->disp_row_begin=sheetptr->disp_col_begin=0; + sheetptr->sel_row_begin=sheetptr->sel_col_begin=-1; + sheetptr->cmd_pos=sheetptr->cmd_row=sheetptr->cmd_col=-1; + sheetptr->changed=false; + sheetptr->recompute=true; + sheetptr->matrix_fill_cells=true; + sheetptr->movedown=true; + sheetptr->filename="session"; + return sheetptr; + } + gen current_sheet(const gen & g,GIAC_CONTEXT){ + if (!xcas::sheetptr) + xcas::sheetptr=new_tableur(contextptr); + xcas::tableur & t=*xcas::sheetptr; + if (ckmatrix(g,true)){ + t.m=*g._VECTptr; + makespreadsheetmatrice(t.m,contextptr); + t.cur_row=t.cur_col=0; + t.nrows=t.m.size(); + t.ncols=t.m.front()._VECTptr->size(); + t.sel_row_begin=-1; + t.cmd_row=t.cmd_pos=-1; + return 1; + } + int r,c; + if (iscell(g,c,r,contextptr)){ + if (r>=t.nrows||c>=t.ncols) + return undef; + gen tmp=t.m[r]; + tmp=tmp[c]; + return tmp[1]; + } + if (g.type==_VECT && g.subtype==0 && g._VECTptr->empty()) + return gen(extractmatricefromsheet(t.m,false),_SPREAD__VECT); + gen m(extractmatricefromsheet(t.m),_MATRIX__VECT); + if (g.type==_VECT && g._VECTptr->empty()) + return m; + return m[g]; + } + static const char _current_sheet_s []="current_sheet"; + static define_unary_function_eval(__current_sheet,¤t_sheet,_current_sheet_s); + define_unary_function_ptr5( at_current_sheet ,alias_at_current_sheet,&__current_sheet,_QUOTE_ARGUMENTS,true); + +#ifndef NO_NAMESPACE_GIAC +} +#endif // ndef NO_NAMESPACE_GIAC + + +using namespace std; +using namespace giac; +using namespace xcas; + +#if 0 +int ext_main(){ + while (1){ + statuslinemsg("Numworks loader"); + drawRectangle(0,0,LCD_WITH_PX,LCD_HEIGHT_PX,_BLACK); + os_draw_string(0,20,_WHITE,_BLACK,"1. Khicas shell"); + os_draw_string(0,40,_WHITE,_BLACK,"2. Epsilon (Numworks HOME)"); + int k=getkey(1); + if (k=='1' ) run_epsilon(); + if (k=='2') caseval("*"); + } +} +#else +int ext_main(){ + //tab16=(four_int *) malloc(sizeof(four_int)*8*32); + //tab24=(six_int*) malloc(sizeof(six_int)*8*32); + //tab48=(twelve_int*) malloc(sizeof(twelve_int)*8*32); + caseval("*"); + return 0; +} +#endif + +void handle_flash(GIAC_CONTEXT); + +#ifdef HP39 +const int C20=14; +extern "C" int khicas_1bpp; +unsigned short mmind_col[]={212,170,127,85,42,0}; +#else +const int C20=20; +unsigned short mmind_col[]={COLOR_BLUE,COLOR_RED,COLOR_MAGENTA,COLOR_GREEN,COLOR_CYAN,COLOR_YELLOW}; +#endif + +#ifndef NUMWORKS_SLOTB +void mastermind_disp(const vector & solution,const vector< vector > & essais,const vector & essai,bool fulldisp,GIAC_CONTEXT){ + int x0=C20*3/2,y0=C20/2; + if (fulldisp) + drawRectangle(0,0,LCD_WIDTH_PX,LCD_HEIGHT_PX,_WHITE); + else + drawRectangle(0,y0+6*C20,LCD_WIDTH_PX,LCD_HEIGHT_PX-(y0+4*C20),_WHITE); + if (fulldisp){ + // grille + for (int i=y0;i<=y0+4*C20;i+=C20) + draw_line(x0,i,x0+12*C20,i,_BLACK); + for (int j=x0;j<=x0+12*C20;j+=C20) + draw_line(j,y0,j,y0+4*C20,_BLACK); + // affichage des coups precedents et resultats + for (int c=0;c & essai=essais[c]; + for (int i=0;i<4;++i){ + draw_filled_circle(x0+C20*c+C20/2,y0+C20*i+C20/2,C20/2,mmind_col[essai[i]],true,true,contextptr); + if (essai[i] % 2) + draw_line(x0+C20*c,y0+C20*i+C20/2,x0+C20*c+C20,y0+C20*i+C20/2,essai[i]>2?COLOR_WHITE:COLOR_BLACK); + } + // resultats + vector S(solution),E(essai); + // bien places + int bien=0; + for (int i=0;i=S.size() || e>=E.size()) + break; + if (S[s]==E[e]){ + ++mal; + ++s; ++e; + continue; + } + if (S[s]2?COLOR_WHITE:COLOR_BLACK); + } + // draw_filled_circle(x0+C20*i+C20/2,y+C20/2,C20/2,mmind_col[essai[i]],true,true,contextptr); +} + +int do_mastermind(GIAC_CONTEXT){ + // Mastermind + vector solution(4),essai; + vector< vector > essais; + const int nbcouleurs=6; + const int nbessais=12; + for (int i=0;i<4;++i) + solution[i]=giac_rand(contextptr) % nbcouleurs; + int i=0,j=0; + bool fulldisp=true; + for (;;){ + mastermind_disp(solution,essais,essai,fulldisp,contextptr); + // saisie du prochain coup + int key=getkey(1); + if (key==KEY_SHUTDOWN) + return key; + fulldisp=false; + if (key==KEY_CTRL_MENU) + return key; + if (key==KEY_PRGM_ACON){ + fulldisp=true; + continue; + } + if (key>='0' && key<='5'){ + if (essai.size()==4) + continue; + essai.push_back(key-'0'); + } + if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK){ + if (essai.size()==4){ + if (essai==solution){ + char buf[16]; giac::sprint_int(buf,essais.size()); + confirm(lang!=1?"Solution found! Tries:":"Vous avez trouve. Essais:",buf); + return i; + } + fulldisp=true; + essais.push_back(essai); + essai.clear(); + if (essais.size()==nbessais){ + mastermind_disp(solution,essais,essai,true,contextptr); + for (int i=0;i horner_newton(const vector > & p,const std::complex &x){ + complex num,den; + vector >::const_iterator it=p.begin(),itend=p.end(); + int n=itend-it-1; + for (;n;--n,++it){ + num *= x; + den *= x; + num += *it; + den += double(n)*(*it); + } // end for + // last step + num *= x; + num += *it; + return x-num/den; +} + +complex horner_newton(const vector & p,const std::complex &x){ + vector::const_iterator it=p.begin(),itend=p.end(); + int n=itend-it-1; + complex num=*it*x+*(it+1),den=(double(n)*(*it))*x+double(n-1)*(*(it+1)); + for (it+=2,n-=2;n;--n,++it){ + num *= x; + den *= x; + num += *it; + den += double(n)*(*it); + } // end for + // last step + num *= x; + num += *it; + return x-num/den; +} + +int do_fractale(GIAC_CONTEXT){ + freeze=true; + int X=LCD_WIDTH_PX, +#if 1 // def HP39 + Y=LCD_HEIGHT_PX, +#else + Y=LCD_HEIGHT_PX-18, +#endif + Nmax=16,Nmaxmin=5,Nmaxmax=50; + bool mandel=do_confirm("EXE: Mandelbrot, Back: bassins racines"); + vecteur P; vector > p,Z; + double np=0; complex na; + // if the polynomial is x^np+a=0 + // Newton iteration is x-(x^n+a)/(n*x^(n-1))=((n-1)*x-a)/(n*x^(n-1)) + vector pr; + bool real=true; + if (!mandel){ // Input Julia + string s; + inputline("Polynome (x^3-1)?","",s,false,65,contextptr); + if (s.empty()) s="x^3-1"; + gen g(s,contextptr); + g=_symb2poly(g,contextptr); + if (g.type!=_VECT || g._VECTptr->size()<3 || g._VECTptr->size()>9){ + do_confirm("Not a polynomial or degree<2 or degree>8"); + return 0; + } + P=*g._VECTptr; + if (!convert(P,p,true)){ + do_confirm("Unable to convert"); + return 0; + } + // detect x^n+a==0 + np=P.size()-1; + for (int i=1;i0; + int Ysym=2*ymax/(ymax-ymin)*Y-1; + for (int y=0;y c(xmin,h*y+ymax); + for (int x=0;x z(0); + for (j=0;j4) // this is more efficient than abs(z)>2 + break; + } +#ifdef HP39 + int color=(255*j)/Nmax; +#else + int color=126*j+2079; +#endif + os_set_pixel(x,y,color); + if (sym && ysym>0 && ysym c(xmin,h*y+ymax); + for (int x=0;x z(c),zp; + int nrac=Z.size(),j; + // Newton iterations + for (j=0;j1e20) + break; + zp=z; + if (np){ + z *=z ; + for (int i=3;i0 && ysymNmaxmin){ + --Nmax; continue; + } + if ( (k=='m' || k=='>' || k=='7' || k==KEY_CHAR_SQUARE) && Nmax & elem=text.elements; + elem = std::vector (2); + elem[0].s = (lang==1)?"Deplacez le curseur sur une ligne, tapez EXE/OK pour entrer une nouvelle valeur ou tapez sur Ans pour resoudre.":"Move cursor on a line, type EXE/OK to enter a new value or type Ans to solve"; + elem[0].newLine = 0; + if (mode==-1) + elem[1].s = (lang==1)?"Par exemple entrez le montant de l'emprunt en 1, 0 en 2, le taux d'interet, le nombre d'annees puis placez le curseur en 5 et tapez Ans.":"For example, enter due amount in 1, 0 in 2, interest rate, number of years then move cursor on 5 and type Ans"; + else + elem[1].s = (lang==1)?"Pour calculer l'evolution d'un placement, entrer le montant place au debut, le taux d'interet, le nombre d'annees, 0 en 5 (paiement) puis deplacez le curseur en 2 et tapez Ans":""; + elem[1].newLine = 1; + sres=doTextArea(&text,contextptr); + continue; + } + if (sres == KEY_CHAR_ANS){ + if (choix==3) + continue; + double t1=std::pow(1+ir/100,1./irpy); + double t=t1-1; + double & u0=pv; + double & un=fv; + double & r=pm; + double C=r/t; + double n=nb*irpy; + // un=(1+t)^n*(u0-r/t)+r/t + if (choix==0){ // solve for u0=(1+t)^(-n)*(un-r/t)+r/t + u0=pow(t1,-n)*(un-C)+C; + } + if (choix==1){ + un=pow(t1,n)*(u0-C)+C; + } + if (choix==2){ // solve for T + giac::gen sol=un-pow(1+vx_var,n,contextptr)*(u0-gen(r)/vx_var)-gen(r)/vx_var; + sol=giac::_fsolve(makesequence(sol,vx_var,t),contextptr); + if (sol.type==_DOUBLE_){ + t=sol._DOUBLE_val; + ir=100*(std::pow(1+t,irpy)-1); + } + else continue; + } + if (choix==4){ // solve for r=t*(u0*(t+1)**n-๏ปฟun)/((t+1)**n-1) + double tmp=pow(t+1,n); + r=t*(u0*tmp-un)/(tmp-1); + } + if (choix==5){ // solve for n=(-ln(t*u0-r)+ln(t*๏ปฟun-r))/ln(t+1) + double n=std::log((t*un-r)/(t*u0-r))/std::log(t+1); + nb=n/irpy; + } + solved=true; + } + int keynumber=-1; + if (sres>=KEY_CHAR_0 && sres<=KEY_CHAR_9) keynumber=sres-KEY_CHAR_0; + if (sres==KEY_CTRL_EXE || sres == MENU_RETURN_SELECTION || sres == KEY_CTRL_OK || keynumber>=0) { + if (smallmenu.selection==7) // quit + break; + double d=*tabd[choix]; + if (choix<2 && mode==1) d=-d; + if (keynumber>=0) + d=keynumber; + if (!inputdouble(tab[choix],d,contextptr)) + continue; + if (choix<2 && mode==1) d=-d; + if (choix==3){ + if (d<1) + d=1; + if (d>365) + d=365; + } + if (choix==5){ + if (d<=0) + d=1; + if (d>365) + d=365; + } + *tabd[choix]=d; + solved=false; + } + } + return 0; +} +#endif + +int geoapp(GIAC_CONTEXT); + +int khicas_addins_menu(GIAC_CONTEXT){ + Menu smallmenu; +#ifdef NUMWORKS + smallmenu.numitems=12; // INCREMENT IF YOU ADD AN APPLICATION +#else + smallmenu.numitems=11; // INCREMENT IF YOU ADD AN APPLICATION +#endif + // and uncomment first smallmenuitems[app_number].text="Reserved" + // replace by your application name + // and add if (smallmenu.selection==app_number-1){ call your code } + MenuItem smallmenuitems[smallmenu.numitems]; + smallmenu.items=smallmenuitems; + smallmenu.height=MENUHEIGHT; + smallmenu.width=28; + //smallmenu.scrollbar=1; + smallmenu.scrollout=1; + smallmenuitems[0].text = (char*)((lang==1)?"Geometrie":"Geometry"); + smallmenuitems[1].text = (char*)((lang==1)?"Tableur":"Spreadsheet"); + smallmenuitems[2].text = (char*)((lang==1)?"Table periodique":"Periodic table"); + smallmenuitems[3].text = (char*)((lang==1)?"Pret":"Mortgage"); + smallmenuitems[4].text = (char*)((lang==1)?"Epargne":"TVM"); + smallmenuitems[5].text = (char*)((lang==1)?"Table caracteres":"Char table"); +#ifdef NUMWORKS_SLOTB + smallmenuitems[6].text = (char*)"Not in short version"; + smallmenuitems[7].text = (char*)"Not in short version"; + smallmenuitems[8].text = (char*)"Not in short version"; +#else + smallmenuitems[6].text = (char*)((lang==1)?"Exemple simple: Syracuse":"Simple example; Syracuse"); + smallmenuitems[7].text = (char*)((lang==1)?"Exemple de jeu: Mastermind":"Game example: Mastermind"); + smallmenuitems[8].text = (char*)((lang==1)?"Exemples de fractales":"Fractals examples"); +#endif + // smallmenuitems[8].text = (char*)"Mon application"; // adjust numitem ! + // smallmenuitems[9].text = (char*)"Autre application"; + // smallmenuitems[10].text = (char*)"Encore une autre"; + // smallmenuitems[11].text = (char*)"Une avant-derniere"; + // smallmenuitems[12].text = (char*)"Une derniere"; +#ifdef NUMWORKS + smallmenuitems[smallmenu.numitems-3].text = (char*)((lang==1)?"Personnaliser la flash":"Customize flash"); +#endif + smallmenuitems[smallmenu.numitems-2].text = (char*)((lang==1)?"Quitter le menu":"Leave menu"); + smallmenuitems[smallmenu.numitems-1].text = (char*)((lang==1)?"Quitter KhiCAS":"Leave KhiCAS"); + while(1) { + int sres = doMenu(&smallmenu); + if(sres == MENU_RETURN_SELECTION || sres==KEY_CTRL_EXE) { + if (smallmenu.selection==smallmenu.numitems){ + return KEY_CTRL_MENU; + } +#ifdef NUMWORKS + if (smallmenu.selection==smallmenu.numitems-2) + handle_flash(contextptr); +#endif + // Attention les entrees sont decalees de 1 + if (smallmenu.selection==1) // geometry + geoapp(contextptr); + if (smallmenu.selection==2) // tableur + sheet(contextptr); + if (smallmenu.selection==3){ // table periodique + const char * name,*symbol; + char protons[32],nucleons[32],mass[32],electroneg[32]; + int res=periodic_table(name,symbol,protons,nucleons,mass,electroneg); + if (!res) + continue; + char console_buf[64]={0}; + char * ptr=console_buf; + if (res & 1) + ptr=strcpy(ptr,name)+strlen(ptr); + if (res & 2){ + if (res & 1) + ptr=strcpy(ptr,",")+strlen(ptr); + ptr=strcpy(ptr,symbol)+strlen(ptr); + } + if (res & 4){ + if (res&3) + ptr=strcpy(ptr,",")+strlen(ptr); + ptr=strcpy(ptr,protons)+strlen(ptr); + } + if (res & 8){ + if (res&7) + ptr=strcpy(ptr,",")+strlen(ptr); + ptr=strcpy(ptr,nucleons)+strlen(ptr); + } + if (res & 16){ + if (res&15) + ptr=strcpy(ptr,",")+strlen(ptr); + ptr=strcpy(ptr,mass+2)+strlen(ptr); + ptr=strcpy(ptr,"_(g/mol)")+8; + } + if (res & 32){ + if (res&31) + ptr=strcpy(ptr,",")+strlen(ptr); + ptr=strcpy(ptr,electroneg+4)+strlen(ptr); + } + copy_clipboard(console_buf,true); + return KEY_CTRL_PASTE; + // return Console_Input(console_buf); + } + if (smallmenu.selection==4){ + finance(-1,contextptr); + continue; + } + if (smallmenu.selection==5){ + finance(1,contextptr); + continue; + } + if (smallmenu.selection==6){ + int c=chartab(); + if (c>=0){ + char buf[2]={c,0}; + copy_clipboard(buf,true); + return KEY_CTRL_PASTE; + } + break; + } +#ifndef NUMWORKS_SLOTB + if (smallmenu.selection==7){ + // Exemple simple d'application tierce: la suite de Syracuse + // on entre la valeur de u0 + double d; int i; + for (;;){ + inputdouble(gettext("Suite de Syracuse. u0?"),d,contextptr); + i=(d); + if (i==d) + break; + confirm(gettext("u0 doit etre entier!"),gettext("Recommencez")); + } + i=max(i,1); + vecteur v(1,i); // initialise une liste avec u0 + while (i!=1){ + if (i%2) + i=3*i+1; + else + i=i/2; + v.push_back(i); + } + // representation graphique de la liste en appelant la commande Xcas listplot + displaygraph(_listplot(v,contextptr),symbolic(at_listplot,v),contextptr); + // copie vers presse-papier en l'affichant + copy_clipboard(gen(v).print(contextptr),true); + continue; + // on entre la liste en ligne de commande et on quitte + return Console_Input(gen(v).print(contextptr).c_str()); + } + if (smallmenu.selection==8) // mastermind, on ne quitte pas + mastermind(contextptr); + if (smallmenu.selection==9){ + fractale(contextptr); + } +#endif + } // end sres==menu_selection + Console_Disp(1,contextptr); + break; + } // end endless while + return CONSOLE_SUCCEEDED; +} + +/* ******************* + * FLASH * + ********************* */ +#ifdef NUMWORKS + +void flash_info(const char * buf,std::vector &v,size_t & first_modif,bool modif,int initpos,GIAC_CONTEXT){ + if (v.empty()){ + do_confirm(lang==1?"Pas de fichier.":"No file found"); + return; + } + Menu smallmenu; + smallmenu.numitems=v.size(); + MenuItem smallmenuitems[smallmenu.numitems]; + smallmenu.items=smallmenuitems; + smallmenu.height=modif?11:12; + smallmenu.scrollbar=1; + smallmenu.scrollout=1; + smallmenu.title = (char*)(lang==1?"Info Flash":"Flash Files"); + smallmenu.type = MENUTYPE_FKEYS; + smallmenu.selection=initpos; + if (modif){ + smallmenu.title = (char*)(lang==1?"Modifier fichiers":"Modify files"); + } + vector vs(v.size()); + for (int i=0;i=0 && i10)){ + smallmenuitems[i].value=!smallmenuitems[i].value; + int m=v[i].mode; + if (smallmenuitems[i].value) + m = ((m/100) | 4)*100+(m%100); + else + m = ((m/100) & 3)*100+(m%100); + v[i].mode=m; + if (smallmenuitems[i].value){ + // uncheck all files having the same filename + const string & filename=v[i].filename; + for (int j=0;j v=tar_fileinfo(buf,0); + int initpos=1; + if (modif) + initpos=v.size(); + flash_info(buf,v,first_modif,modif,initpos,contextptr); +} + +extern "C" int filesize(const char *); +// copy text file from ram scriptstore +int flash_from_ram(const char * buf,const char * ext,size_t & first_modif,GIAC_CONTEXT){ + char filename[MAX_FILENAME_SIZE+1]; + int n=giac_filebrowser(filename,ext,(lang==1?"Choisir fichier a copier":"Select file to copy"),0); + if (n==0) return 0; + const char * data=read_file(filename); +#if defined DEVICE || defined NUMWORKS + int l=strlen(data); +#else + int l=filesize(filename); +#endif + if (l) + n=flash_adddata(buf,filename,data,l,0); + return n; +} + +void handle_flash(GIAC_CONTEXT){ +#if 0 // def NUMWORKS_SLOTB + return ; // disabled to save roomX +#endif + const char flash_fr[]="Application de sauvegarde et gestion des scripts en memoire flash. Necessite 70K de memoire libre (a lancer tout de suite apres avoir ouvert KhiCAS). Attention a l'usure de la flash: utiliser avec parcimonie! Ne pas vider la corbeille avant que cela ne soit necessaire (ainsi les nouveaux fichiers s'ecriront sur d'autres secteurs). L'auteur decline toute responsabilite en cas d'usure prematuree de votre memoire flash."; + const char flash_en[]="This app lets you save and handle scripts in flash memory. Requires 70K of free RAM (run it immediatly after launching KhiCAS). In order to avoid premature wear of your flash, run this app only when required. Don't empty the trash unless it's necessary (that way new files will be written in other sectors). The author declines all responsability in the event of premature wear of your flash memory."; + textArea text; + text.editable=false; + text.clipline=-1; + text.title =(lang==1)?"EXIT: annuler, EXE: ok":"EXIT: cancel, EXE: run"; + add(&text,(lang==1)?flash_fr:flash_en); + int key=doTextArea(&text,contextptr); + if ( (key!=1 && key!=KEY_CTRL_EXE && key!=KEY_CTRL_OK) +#ifdef DEVICE + || inexammode() +#endif + ) + return; + text.elements.clear(); + buf64k=(char *)malloc(1<<16); + if (buf64k==0){ + confirm(lang==1?"Pas assez de memoire RAM.":"RAM Memory full",lang==1?"Purgez et relancez KhiCAS":"Purge and restart KhiCAS"); + return; + } +#ifndef DEVICE + char * freeptr=0; + const char * flash_buf=file_gettar_aligned("apps.tar",freeptr); +#endif + // skip user apps + while (numworks_maxtarsize>0 && ( + ((unsigned char) *flash_buf)==0xba || + ((unsigned char) flash_buf[1])==0xbe) + ){ + flash_buf += 0x10000; + numworks_maxtarsize -= 0x10000; + } + Menu smallmenu; + smallmenu.numitems=6; + MenuItem smallmenuitems[smallmenu.numitems]; + smallmenu.items=smallmenuitems; + smallmenu.height=12; + smallmenu.scrollbar=1; + smallmenu.scrollout=1; + smallmenuitems[0].text = (char*)(lang==1?"Informations flash":"Flash informations"); + smallmenuitems[1].text = (char*)(lang==1?"KhiCAS RAM->flash":"KhiCAS RAM->flash"); + smallmenuitems[2].text = (char*)(lang==1?"Python RAM->flash":"Python RAM->flash"); + smallmenuitems[3].text = (char*)(lang==1?"Modifier infos fichiers":"Modify file infos"); + smallmenuitems[4].text = (char*)(lang==1?"Vider la corbeille":"Empty trash"); + smallmenuitems[5].text = (char*)(lang==1?"Quitter":"Leave"); + while (1){ + size_t first_modif=tar_totalsize(flash_buf,numworks_maxtarsize); + string title=(lang==1?"Flash libre ":"Free flash "); + title += print_INT_(numworks_maxtarsize-first_modif); + smallmenu.title = (char*)title.c_str(); + smallmenu.selection = 1; + int sres = doMenu(&smallmenu); + if (sres==MENU_RETURN_EXIT){ +#if defined NUMWORKS && !defined DEVICE + if (do_confirm(lang==1?"Quitter sans synchroniser?":"Leave without synchronization")) +#endif + break; + } + if (sres == MENU_RETURN_SELECTION || sres==KEY_CTRL_EXE) { + if (smallmenu.selection == smallmenu.numitems){ +#if defined NUMWORKS && !defined DEVICE + if (do_confirm(lang==1?"Synchroniser apps.tar?":"Synchronize apps.tar?")) + file_savetar("apps.tar",(char *)flash_buf,tar_totalsize(flash_buf,0)); +#endif + break; + } + if (smallmenu.selection == 1){ + flash_info(flash_buf,first_modif,false,contextptr); // info only, no erase + continue; + } + if (smallmenu.selection==2 || smallmenu.selection==3){ + if (flash_from_ram(flash_buf,smallmenu.selection==3?"py":"xw",first_modif,contextptr)){ + // uncheck files having the same filename + std::vector v=tar_fileinfo(flash_buf,0); + int n=v.size(); + if (n){ + --n; + string & filename=v[n].filename; + int modif=0; + for (int j=0;j65536 && do_confirm(lang==1?"Il reste de la place, etes-vous sur?":"There's still room, are you sure?")) + flash_emptytrash(flash_buf,&first_modif); + } + } + } + free(buf64k); +#ifndef DEVICE + //free(freeptr); +#endif +} +#else +void handle_flash(GIAC_CONTEXT){ + +} +#endif + +/* ************************** + * SPREADSHEET CODE * + ************************** */ +#ifdef HP39 +const int row_height=15; +const int col_width=45; +#else +const int row_height=20; +const int col_width=60; +#endif +string printcell(int i,int j){ + string s=""; + s+=('A'+j); + s+=print_INT_(i); + return s; +} +string printsel(int r,int c,int R,int C){ + return printcell(r,c)+":"+printcell(R,C); +} + +void change_undo(tableur & t){ + t.undo=t.m; + t.changed=true; +} + +void save_sheet(tableur & t,GIAC_CONTEXT){ +#if 1 + string s=print_tableur(t,contextptr); +#else + string s=gen(extractmatricefromsheet(t.m,false),_SPREAD__VECT).print(contextptr); +#endif + string filename(remove_path(remove_extension(t.filename))); + filename+=".tab"; +#ifdef NSPIRE_NEWLIB + filename+=".tns"; +#endif + write_file(filename.c_str(),s.c_str(),s.size()); +} +void sheet_status(tableur & t,GIAC_CONTEXT){ + string st; + if (python_compat(contextptr)) + st="tabl Py "; + else + st="tabl Xcas "; + if (t.var.type==_IDNT) + st += t.var.print(contextptr); + else + st += "<>"; + st += ' '; + st += t.filename ; + st += " R"; + st += print_INT_(t.nrows); + st += " C"; + st += print_INT_(t.ncols); + if (t.changed) + st += " *"; + else + st += " -"; + if (t.sel_row_begin>=0) + st += (lang==1)?" esc: annule selection":" esc: cancel selection"; + else { + if (t.cmd_row>=0) + st += (lang==1)?" esc: annule ligne cmd":" esc: cancel cmdline"; + } + statuslinemsg(st.c_str()); +} +bool sheet_display(tableur &t,GIAC_CONTEXT){ + int disp_rows=LCD_HEIGHT_PX/row_height-3; + int disp_cols=LCD_WIDTH_PX/(col_width+4)-1; + if (t.disp_row_begin>t.cur_row) + t.disp_row_begin=t.cur_row; + if (t.disp_row_begint.cur_col) + t.disp_col_begin=t.cur_col; + if (t.disp_col_begin=0 && t.sel_row_beginsel_R) + swapint(sel_r,sel_R); + if (sel_c>sel_C) + swapint(sel_c,sel_C); + bool has_cmd=t.cmd_row>=0 && t.cmd_row=26){ // if we accept more than 26 cols + colname[0] += j/26; + colname[1] = 'A'+(j%26); + colname[2]=0; + } + else + colname[0] += (j % 26); + os_draw_string(x+col_width/2-4,2,_BLACK,_WHITE,colname); + x+=col_width+4; + } + int waitn=2; + for (int i=t.disp_row_begin;isize()==3){ + bool iscur=i==t.cur_row && j==t.cur_col; + string s; + if (iscur){ + if (!has_cmd) + t.cmdline=(*vj._VECTptr)[0].print(contextptr); + } + bool rev=has_sel?(sel_r<=i && i<=sel_R && sel_c<=j && j<=sel_C):iscur; + if (rev) + drawRectangle(x+1,y,col_width+4,row_height,color_gris); + s=(*vj._VECTptr)[1].print(contextptr); + int dx=os_draw_string(0,0,0,0,s.c_str(),true); // find width + if (dx=LCD_WIDTH_PX-50; + int sheety=LCD_HEIGHT_PX-2*row_height,xtooltip=0; + if (t.cmd_row>=0 && t.cmd_pos>=0 && t.cmd_pos<=s.size()){ +#ifdef HP39 + xend=os_draw_string(xend,sheety,_BLACK,_WHITE,printcell(t.cmd_row,t.cmd_col).c_str())+5; +#else + xend=os_draw_string(xend,sheety,_BLUE,_WHITE,printcell(t.cmd_row,t.cmd_col).c_str())+5; +#endif + string s1=s.substr(0,t.cmd_pos); +#if 1 + xtooltip=xend=print_color(xend,sheety,s1.c_str(),_BLACK,false,small,contextptr); +#else + if (small) + xend=os_draw_string_small(xend,sheety,_BLACK,_WHITE,s1.c_str(),false); + else + xend=os_draw_string(xend,sheety,_BLACK,_WHITE,s1.c_str(),false); +#endif + drawRectangle(xend+1,sheety+2,2,small?10:13,_BLACK); + xend+=4; + s=s.substr(t.cmd_pos,s.size()-t.cmd_pos); + if (has_sel){ + s1=printsel(sel_r,sel_c,sel_R,sel_C); +#ifdef HP39 + xend=os_draw_string_small(xend,sheety,_BLACK,_WHITE,s1.c_str(),false); +#else + xend=os_draw_string_small(xend,sheety,_BLACK,color_gris,s1.c_str(),false); +#endif + } + else { + if (t.cmd_row!=t.cur_row || t.cmd_col!=t.cur_col) +#ifdef HP39 + xend=os_draw_string_small(xend,sheety,_BLACK,_WHITE,printcell(t.cur_row,t.cur_col).c_str(),false); +#else + xend=os_draw_string_small(xend,sheety,_BLACK,color_gris,printcell(t.cur_row,t.cur_col).c_str(),false); +#endif + } + } // end cmdline active + else + xend=os_draw_string(xend,sheety,_BLACK,_WHITE,printcell(t.cur_row,t.cur_col).c_str())+5; + int bg=t.cmd_row>=0?_WHITE:57051; +#if 1 + xend=print_color(xend,sheety,s.c_str(),_BLACK,false,small,contextptr); +#else + if (small) + xend=os_draw_string_small(xend,sheety,_BLACK,bg,s.c_str(),false); + else + xend=os_draw_string(xend,sheety,_BLACK,bg,s.c_str(),false); +#endif + if (t.keytooltip) + t.keytooltip=tooltip(xtooltip,sheety,t.cmd_pos,t.cmdline.c_str(),contextptr); + python_compat(p,contextptr); xcas_python_eval=xpe; + // fast menus +#ifdef HP39 + string menu("stat1d |stat2d | seq | edit| view | graph "); + drawRectangle(0,114,LCD_WIDTH_PX,14,bg); + os_draw_string_small(0,114,_WHITE,_BLACK,menu.c_str()); +#else + string menu("shift-1 stat1d|2 2d|3 seq|4 edit|5 view|6 graph|7 R|8 list| "); + bg=65039;// bg=52832; + drawRectangle(0,205,LCD_WIDTH_PX,17,bg); + os_draw_string_small(0,205,_BLACK,bg,menu.c_str()); +#endif + return true; +} + +void activate_cmdline(tableur & t){ + if (t.cmd_row==-1){ + t.cmd_row=t.cur_row; + t.cmd_col=t.cur_col; + t.cmd_pos=t.cmdline.size(); + } +} + +bool sheet_eval(tableur & t,GIAC_CONTEXT,bool ckrecompute=true){ + t.changed=true; + if (!ckrecompute || t.recompute) + spread_eval(t.m,contextptr); + return true; +} + +void copy_right(tableur & t,GIAC_CONTEXT){ + int R=t.cur_row,C=t.cur_col,c=t.ncols; + vecteur v=*t.m[R]._VECTptr; + gen g=v[C]; + for (int i=C+1;iR) + dr=R-r; + if (dr && ckmatrix(m,true)){ + dc=m.front()._VECTptr->size(); + if (c+dc>C) + dc=C-c; + if (dc){ + for (int i=0;isize(),nr=t.nrows,nc=t.ncols; + if (nr!=cur_r || nc!=cur_c){ + if (do_confirm(((lang==1?"Redimensionner ":"Resize ")+print_INT_(cur_r)+"x"+print_INT_(cur_c)+"->"+print_INT_(nr)+"x"+print_INT_(nc)).c_str())){ + vecteur fill(3,0); + if (nr0){ + decimal_digits(d,contextptr); + } + continue; + } + if (smallmenu.selection == 2){ + double d=t.nrows; + if (inputdouble((lang==1?"Nombre de lignes?":"Rows?"),d,contextptr) && d==int(d) && d>0){ + t.nrows=d; + } + continue; + } + if (smallmenu.selection == 3){ + double d=t.ncols; + if (inputdouble((lang==1?"Nombre de colonnes?":"Colonnes?"),d,contextptr) && d==int(d) && d>0){ + t.ncols=d; + } + continue; + } + if (smallmenu.selection == 4){ + t.recompute=!t.recompute; + continue; + } + if (smallmenu.selection==5){ + t.matrix_fill_cells=!t.matrix_fill_cells; + continue; + } + if (smallmenu.selection == 6){ + t.movedown=!t.movedown; + continue; + } + if (smallmenu.selection == smallmenu.numitems){ + change_undo(t); + resizesheet(t); + break; + } + } + } // end endless while +} + +void sheet_graph(tableur &t,GIAC_CONTEXT){ + vecteur v; + sheet_pnt(t.m,v); + gen g(v); + check_do_graph(g,0,2,contextptr); +} + +int sheet_menu_menu(tableur & t,GIAC_CONTEXT){ + t.cmd_row=-1; t.cmd_pos=-1; t.sel_row_begin=-1; + Menu smallmenu; + smallmenu.numitems=14; + MenuItem smallmenuitems[smallmenu.numitems]; + smallmenu.items=smallmenuitems; + smallmenu.height=12; + //smallmenu.width=24; + smallmenu.scrollbar=1; + smallmenu.scrollout=1; +#ifdef NUMWORKS + smallmenu.title = (char*)(lang==1?"Back: annule menu tableur":"Back: cancel sheet menu"); +#else + smallmenu.title = (char*)(lang==1?"Esc: annule menu tableur":"Esc: cancel sheet menu"); +#endif + smallmenuitems[0].text = (char *)(lang==1?"Sauvegarde tableur (shift sto)":"Save sheet (shift sto)"); + smallmenuitems[1].text = (char *)(lang==1?"Sauvegarder tableur comme":"Save sheet as"); + if (nspire_exam_mode==2) smallmenuitems[1].text=smallmenuitems[0].text = (char*)(lang==1?"Sauvegarde desactivee":"Saving disabled"); + smallmenuitems[2].text = (char*)(lang==1?"Charger":"Load"); + string cell=(lang==1?"Editer cellule ":"Edit cell ")+printcell(t.cur_row,t.cur_col); + smallmenuitems[3].text = (char*)cell.c_str(); + smallmenuitems[4].text = (char*)(lang==1?"Voir graphique (shift 6)":"View graph (shift 4)"); +#ifdef NUMWORKS + smallmenuitems[5].text = (char*)(lang==1?"Copie vers le bas (shift 4)":"Copy down (shift 7)"); + smallmenuitems[6].text = (char*)(lang==1?"Copie vers droite (shift 4)":"Copy right (shift 7)"); +#else + smallmenuitems[5].text = (char*)(lang==1?"Copier vers le bas (ctrl D)":"Copy down (ctrl D)"); + smallmenuitems[6].text = (char*)(lang==1?"Copier vers la droite (ctrl R)":"Copy right (ctrl R)"); +#endif + smallmenuitems[7].text = (char*)(lang==1?"Inserer une ligne":"Insert row"); + smallmenuitems[8].text = (char*)(lang==1?"Inserer une colonne":"Insert column"); + smallmenuitems[9].text = (char*)(lang==1?"Effacer ligne courante":"Remove current row"); + smallmenuitems[10].text = (char*)(lang==1?"Effacer colonne courante":"Remove current column"); + smallmenuitems[11].text = (char*)(lang==1?"Remplir le tableau de 0":"Fill sheet with 0"); + smallmenuitems[smallmenu.numitems-2].text = (char*) "Config"; + smallmenuitems[smallmenu.numitems-1].text = (char*) (lang==1?"Quitter tableur":"Leave sheet"); + while(1) { + int sres = doMenu(&smallmenu); + if (sres==MENU_RETURN_EXIT) + return -1; + if (sres == MENU_RETURN_SELECTION || sres==KEY_CTRL_EXE) { + if (smallmenu.selection == 1){ + // save + save_sheet(t,contextptr); + return -1; + } + if (smallmenu.selection == 2 ){ + // save + char buf[270]; + if (get_filename(buf,".tab")){ + t.filename=remove_path(remove_extension(buf)); + save_sheet(t,contextptr); + return -1; + } + } + if (smallmenu.selection== 3 && !exam_mode) { + char filename[128]; + if (giac_filebrowser(filename,"tab",(lang==1?"Fichiers tableurs":"Sheet files"),2)){ + if (t.changed && do_confirm(lang==1?"Sauvegarder le tableur actuel?":"Save current sheet?")) + save_sheet(t,contextptr); + const char * s=read_file(filename); + if (s){ + gen g(s,contextptr); + g=eval(g,1,contextptr); + if (ckmatrix(g,true)){ + t.filename=filename; + t.m=*g._VECTptr; + t.nrows=t.m.size(); + t.ncols=t.m.front()._VECTptr->size(); + t.cur_col=t.cur_row=0; + t.sel_row_begin=t.cmd_row=-1; + fix_sheet(t,contextptr); + } + else + s=0; + } + if (!s) + do_confirm(lang==1?"Erreur de lecture du fichier":"Error reading file"); + } + return -1; + } // end load + if (smallmenu.selection==4){ + activate_cmdline(t); + t.cmd_pos=t.cmdline.size(); + return -1; + } + if (smallmenu.selection==5){ + sheet_graph(t,contextptr); + return -1; + } + if (smallmenu.selection==6){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + copy_down(t,contextptr); + return -1; + } + if (smallmenu.selection==7){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + copy_right(t,contextptr); + return -1; + } + if (smallmenu.selection==8){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_insert(t.m,t.cur_row,t.cur_col,1,0,makevecteur(0,0,2),contextptr); + t.nrows++; + return -1; + } + if (smallmenu.selection==9){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_insert(t.m,t.cur_row,t.cur_col,0,1,makevecteur(0,0,2),contextptr); + t.ncols++; + return -1; + } + if (smallmenu.selection==10 && t.nrows>=2){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_erase(t.m,t.cur_row,t.cur_col,1,0,contextptr); + --t.nrows; + return -1; + } + if (smallmenu.selection==11 && t.ncols>=2){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_erase(t.m,t.cur_row,t.cur_col,0,1,contextptr); + --t.ncols; + return -1; + } + if (smallmenu.selection==12){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + gen g=vecteur(t.ncols); + t.m=makefreematrice(vecteur(t.nrows,g)); + makespreadsheetmatrice(t.m,contextptr); + return -1; + } + if (smallmenu.selection == smallmenu.numitems-1){ + sheet_menu_setup(t,contextptr); + continue; + } + if (smallmenu.selection == smallmenu.numitems){ + return 0; + } + } + } // end endless while + return 1; +} + +bool is_empty_cell(const gen & g){ + if (g.type==_VECT) return is_zero(g[0]); + return is_zero(g); +} + +void sheet_cmd(tableur & t,const char * ans){ + string s=ans; + if (t.sel_row_begin>=0){ + t.cmdline=""; + s="="+s+"matrix("+print_INT_(absint(t.sel_row_begin-t.cur_row)+1)+","+print_INT_(absint(t.sel_col_begin-t.cur_col)+1)+","+printsel(t.sel_row_begin,t.sel_col_begin,t.cur_row,t.cur_col)+")"; + if (t.cur_row=0 && t.cmd_colsize()){ + vecteur w=*v._VECTptr; + g=spread_convert(g,t.cur_row,t.cur_col,contextptr); + w[t.cmd_col]=makevecteur(g,g,0); + t.m[t.cmd_row]=w; + sheet_eval(t,contextptr,true); + } + } + } + t.cur_row=t.cmd_row; + t.cur_col=t.cmd_col; + t.cmd_row=-1; + t.cmd_pos=-1; + if (t.movedown){ + ++t.cur_row; + if (t.cur_row>=t.nrows){ + t.cur_row=0; + ++t.cur_col; + if (t.cur_col>=t.ncols) + t.cur_col=0; + } + } + else { + ++t.cur_col; + if (t.cur_col>=t.ncols){ + t.cur_col=0; + ++t.cur_row; + if (t.cur_row>=t.nrows){ + t.cur_row=0; + } + } + } +} + +void sheet_help_insert(tableur & t,int exec,GIAC_CONTEXT){ + int back; + string adds=help_insert(t.cmdline.substr(0,t.cmd_pos).c_str(),back,exec,contextptr); + if (back>=t.cmd_pos){ + t.cmdline=t.cmdline.substr(0,t.cmd_pos-back)+t.cmdline.substr(t.cmd_pos,t.cmdline.size()-t.cmd_pos); + t.cmd_pos-=back; + } + if (!adds.empty()) + sheet_cmd(t,adds.c_str()); +} + +giac::gen sheet(GIAC_CONTEXT){ + if (!sheetptr) + sheetptr=new_tableur(contextptr); + tableur & t=*sheetptr; + sheet_eval(t,contextptr,true); + t.changed=false; + bool status_freeze=false; + t.keytooltip=false; + for (;;){ + int R=t.cur_row,C=t.cur_col; + if (t.cmd_row>=0){ + R=t.cmd_row; + C=t.cmd_col; + } + printcell_current_row(contextptr)=R; + printcell_current_col(contextptr)=C; + if (!status_freeze) + sheet_status(t,contextptr); + sheet_display(t,contextptr); + int key=getkey(1); + if (key==KEY_SHUTDOWN) + return key; + if (t.keytooltip){ + t.keytooltip=false; + if (key==KEY_CTRL_EXIT) + continue; + if (key==KEY_CTRL_RIGHT && t.cmd_pos==t.cmdline.size()) + key=KEY_CTRL_OK; + if (key==KEY_CTRL_DOWN || key==KEY_CTRL_VARS) + key=KEY_BOOK; + if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK || key==KEY_CHAR_ANS){ + sheet_help_insert(t,key,contextptr); + continue; + } + } + status_freeze=false; + if (key==KEY_CTRL_SETUP){ + sheet_menu_setup(t,contextptr); + continue; + } + if (key==KEY_CHAR_STORE && t.cmd_row<0){ + save_sheet(t,contextptr); + continue; + } + if (key==KEY_CTRL_MENU){ + if (sheet_menu_menu(t,contextptr)==0) + return 0; + } + if (key==KEY_CTRL_EXIT){ + if (t.sel_row_begin>=0){ + t.sel_row_begin=-1; + continue; + } + if (t.cmd_row>=0){ + bool b= t.cmd_row==t.cur_row && t.cmd_col==t.cur_col; + t.cur_row=t.cmd_row; + t.cur_col=t.cmd_col; + if (b) + t.cmd_row=-1; + continue; + } + if (!t.changed || do_confirm("Quit?")) + return 0; + } + switch (key){ + case KEY_CTRL_UNDO: + std::swap(t.m,t.undo); + sheet_eval(t,contextptr); + continue; + case KEY_CTRL_CLIP: + if (t.sel_row_begin<0){ + t.sel_row_begin=t.cur_row; + t.sel_col_begin=t.cur_col; + } + else { + int r=t.cur_row,R=t.sel_row_begin,c=t.cur_col,C=t.sel_col_begin; + if (r>R) + swapint(r,R); + if (c>C) + swapint(c,C); + t.clip=matrice_extract(t.m,r,c,R-r+1,C-c+1); + copy_clipboard(gen(extractmatricefromsheet(t.clip)).print(contextptr).c_str(),true); + t.sel_row_begin=-1; + } + continue; + case KEY_CTRL_PASTE: + paste(t,contextptr); + status_freeze=true; + continue; + case KEY_SELECT_RIGHT: + if (t.sel_row_begin<0){ + t.sel_row_begin=t.cur_row; + t.sel_col_begin=t.cur_col; + } + case KEY_CTRL_RIGHT: + if (t.cmd_pos>=0 && t.cmd_row==t.cur_row && t.cmd_col==t.cur_col && t.sel_row_begin==-1){ + ++t.cmd_pos; + if (t.cmd_pos>t.cmdline.size()) + t.cmd_pos=t.cmdline.size(); + } + else { + ++t.cur_col; + if (t.cur_col>=t.ncols) + t.cur_col=0; + } + continue; + case KEY_SHIFT_RIGHT: + if (t.cmd_pos>=0 && t.cmd_row==t.cur_row && t.cmd_col==t.cur_col && t.sel_row_begin==-1){ + t.cmd_pos=t.cmdline.size(); + } + else + t.cur_col=t.ncols-1; + break; + case KEY_SELECT_LEFT: + if (t.sel_row_begin<0){ + t.sel_row_begin=t.cur_row; + t.sel_col_begin=t.cur_col; + } + case KEY_CTRL_LEFT: + if (t.cmd_pos>=0 && t.cmd_row==t.cur_row && t.cmd_col==t.cur_col && t.sel_row_begin==-1){ + if (t.cmd_pos>0) + --t.cmd_pos; + } + else { + --t.cur_col; + if (t.cur_col<0) + t.cur_col=t.ncols-1; + } + continue; + case KEY_SHIFT_LEFT: + if (t.cmd_pos>=0 && t.cmd_row==t.cur_row && t.cmd_col==t.cur_col && t.sel_row_begin==-1){ + t.cmd_pos=0; + } + else { + t.cur_col=0; + } + break; + case KEY_SELECT_UP: + if (t.sel_row_begin<0){ + t.sel_row_begin=t.cur_row; + t.sel_col_begin=t.cur_col; + } + case KEY_CTRL_UP: + --t.cur_row; + if (t.cur_row<0) + t.cur_row=t.nrows-1; + continue; + case KEY_SELECT_DOWN: + if (t.sel_row_begin<0){ + t.sel_row_begin=t.cur_row; + t.sel_col_begin=t.cur_col; + } + case KEY_CTRL_DOWN: + ++t.cur_row; + if (t.cur_row>=t.nrows) + t.cur_row=0; + continue; + case KEY_CTRL_DEL: + if (t.cmd_row>=0){ + if (t.cmd_pos>0){ + t.cmdline.erase(t.cmdline.begin()+t.cmd_pos-1); + --t.cmd_pos; + t.keytooltip=true; + } + } + else { + t.cmdline=""; + t.cmd_row=t.cur_row; + t.cmd_col=t.cur_col; + t.cmd_pos=0; + } + continue; + case KEY_CTRL_EXE: +#if 1 + if (t.cmd_row<0){ + sheet_eval(t,contextptr); + continue; + } +#else + if (t.cmd_row<0){ + int r=t.sel_row_begin; + if (r<0) + return extractmatricefromsheet(t.m); + int R=t.cur_row,c=t.sel_col_begin,C=t.cur_col; + if (r>R) + swapint(r,R); + if (c>C) + swapint(c,C); + return extractmatricefromsheet(matrice_extract(t.m,r,c,R-r+1,C-c+1)); + } +#endif + case KEY_CTRL_OK: + if (t.cmd_row>=0){ + string s; + if (t.sel_row_begin>=0){ + s=printsel(t.sel_row_begin,t.sel_col_begin,t.cur_row,t.cur_col); + t.cur_row=t.cmd_row; + t.cur_col=t.cmd_col; + t.sel_row_begin=-1; + } + if (t.cmd_row!=t.cur_row || t.cmd_col!=t.cur_col){ + s=printcell(t.cur_row,t.cur_col); + t.cur_row=t.cmd_row; + t.cur_col=t.cmd_col; + } + if (s.empty()) + sheet_cmdline(t,contextptr); + else { + insert(t.cmdline,t.cmd_pos,s.c_str()); + t.cmd_pos+=s.size(); + } + } // if t.cmd_row>=0 + else { + t.cmd_row=t.cur_row; + t.cmd_col=t.cur_col; + t.cmd_pos=t.cmdline.size(); + } + continue; + case KEY_CTRL_F5: // view + { + string value((*t.m[t.cur_row]._VECTptr)[t.cur_col][1].print(contextptr)); + char buf[1024]; + strcpy(buf,value.substr(0,1024-1).c_str()); + textedit(buf,1024-1,contextptr ); + } + continue; + case KEY_CTRL_F6: // view graph + sheet_graph(t,contextptr); + continue; + case KEY_CTRL_D: // copy down + copy_down(t,contextptr); + continue; +#ifndef NUMWORKS + case KEY_CTRL_R: + copy_right(t,contextptr); + continue; + case KEY_CTRL_CATALOG: +#endif + case KEY_BOOK: case '\t': + { + if (t.cmd_pos>=0) + sheet_help_insert(t,0,contextptr); + } + continue; + } // end switch + if ( (key >= KEY_CTRL_F1 && key <= KEY_CTRL_F6) || + (key >= KEY_CTRL_F7 && key <= KEY_CTRL_F14) + ){ + const char tmenu[]= "F1 stat1d\nsum(\nmean(\nstddev(\nmedian(\nhistogram(\nbarplot(\nboxwhisker(\nF2 stat2d\nlinear_regression_plot(\nlogarithmic_regression_plot(\nexponential_regression_plot(\npower_regression_plot(\npolynomial_regression_plot(\nsin_regression_plot(\nscatterplot(\npolygonscatterplot(\nF3 seq\nrange(\nseq(\ntableseq(\nplotseq(\ntablefunc(\nrandvector(\nrandmatrix(\nF4 edt\n$\n:\nedit_cell\nundo\ncopy_down\ncopy_right\ninsert_row\ninsert_col\nF6 graph\nreserved\nF= poly\nproot(\npcoeff(\nquo(\nrem(\ngcd(\negcd(\nresultant(\nGF(\nF: arit\nF9 mod \nirem(\nifactor(\ngcd(\nisprime(\nnextprime(\npowmod(\niegcd(\nF8 list\nmakelist(\nrange(\nseq(\nlen(\nappend(\nranv(\nsort(\napply(\nF; plot\nplot(\nplotseq(\nplotlist(\nplotparam(\nplotpolar(\nplotfield(\nhistogram(\nbarplot(\nF7 real\nexact(\napprox(\nfloor(\nceil(\nround(\nsign(\nmax(\nmin(\nF< prog\n:\n&\n#\nhexprint(\nbinprint(\nf(x):=\ndebug(\npython(\nF> cplx\nabs(\narg(\nre(\nim(\nconj(\ncsolve(\ncfactor(\ncpartfrac(\nF= misc\n!\nrand(\nbinomial(\nnormald(\nexponentiald(\n\\\n % \n\n"; + const char * s=console_menu(key,(char *)tmenu,0); + if (s && strlen(s)){ + if (strcmp(s,"undo")==0){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + std::swap(t.m,t.undo); + sheet_eval(t,contextptr); + continue; + } + if (strcmp(s,"copy_down")==0){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + copy_down(t,contextptr); + continue; + } + if (strcmp(s,"copy_right")==0){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + copy_right(t,contextptr); + continue; + } + if (strcmp(s,"insert_row")==0){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_insert(t.m,t.cur_row,t.cur_col,1,0,makevecteur(0,0,2),contextptr); + t.nrows++; + continue; + } + if (strcmp(s,"insert_col")==0){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_insert(t.m,t.cur_row,t.cur_col,0,1,makevecteur(0,0,2),contextptr); + t.ncols++; + continue; + } + if (strcmp(s,"erase_row")==0 && t.nrows>=2){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_erase(t.m,t.cur_row,t.cur_col,1,0,contextptr); + --t.nrows; + continue; + } + if (strcmp(s,"erase_col")==0 && t.ncols>=2){ + t.cmd_pos=t.cmd_row=t.sel_row_begin=-1; + change_undo(t); + t.m=matrice_erase(t.m,t.cur_row,t.cur_col,0,1,contextptr); + --t.ncols; + continue; + } + if (strcmp(s,"edit_cell")==0){ + if (t.cmd_row<0 && t.sel_row_begin<0){ + char buf[1024]; + strcpy(buf,t.cmdline.substr(0,1024-1).c_str()); + if (textedit(buf,1024-1,contextptr )){ + t.cmdline=buf; + t.cmd_row=t.cur_row; t.cmd_col=t.cur_col; + sheet_cmdline(t,contextptr); + } + } + continue; + } + if (t.cmd_row<0) + t.cmdline=""; + sheet_cmd(t,s); + } + continue; + } + if (key==KEY_CHAR_CROCHETS || key==KEY_CHAR_ACCOLADES){ + if (t.cmd_row<0) + t.cmdline=""; + activate_cmdline(t); + t.cmdline.insert(t.cmdline.begin()+t.cmd_pos,key==KEY_CHAR_CROCHETS?'[':'{'); + ++t.cmd_pos; + t.cmdline.insert(t.cmdline.begin()+t.cmd_pos,key==KEY_CHAR_CROCHETS?']':'}'); + continue; + } + if (key>=32 && key<128){ + if (t.cmd_row<0) + t.cmdline=""; + activate_cmdline(t); + t.cmdline.insert(t.cmdline.begin()+t.cmd_pos,char(key)); + ++t.cmd_pos; + t.keytooltip=true; + continue; + } + if (const char * ans=keytostring(key,0,false,contextptr)){ + if (ans && strlen(ans)){ + if (t.cmd_row<0) + t.cmdline=""; + sheet_cmd(t,ans); + } + continue; + } + if (key==KEY_CTRL_AC && t.cmd_row>=0){ + if (t.cmdline=="") + t.cmd_row=-1; + t.cmdline=""; + t.cmd_pos=0; + continue; + } + + } +} + +int geoapp(GIAC_CONTEXT){ + int res=newgeo(contextptr); + if (res<0) return res; + // load a figure? + textArea * text=geoptr->hp; + vector fign,figs; + vecteur V(gen2vecteur(giac::_VARS(0,contextptr))); + for (int i=0;isize()==2 && val._VECTptr->front()==at_pnt){ + vecteur & v=*val._VECTptr; + if (v[1].type==_STRNG){ + fign.push_back(tmp.print(contextptr)); + figs.push_back(*v[1]._STRNGptr); + } + } + } + if (1 || !figs.empty()){ + if (0 && figs.size()==1){ + text->elements.clear(); + add(text,figs[0]); + text->filename=fign[0]; + } + else { + const char * tab[figs.size()+3]; + for (int i=0;i=0 && selements.clear(); + if (sfilename=fign[s]+".py"; + geoparse(text,contextptr); + } + else { + geoptr->plot_instructions.clear(); + geoptr->symbolic_instructions.clear(); + geoptr->is3d=(s==figs.size()+1); + geoptr->update_rotation(); + geoptr->orthonormalize(); + text->filename="figure"+print_INT_(figs.size()+1)+".py"; + } + } + else return -3; + } + } + return geoloop(geoptr); +} +#endif diff --git a/android/app/src/main/cpp/giac/src/giac/cpp/kdisplay.cc b/android/app/src/main/cpp/giac/src/giac/cpp/kdisplay.cc new file mode 100644 index 0000000..3207f21 --- /dev/null +++ b/android/app/src/main/cpp/giac/src/giac/cpp/kdisplay.cc @@ -0,0 +1,26446 @@ +// -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -g -c Equation.cc -DHAVE_CONFIG_H -DIN_GIAC -Wall" -*- +/* + * Copyright (C) 2005,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +const char fourier_url[]="https://www-fourier.univ-grenoble-alpes.fr/~parisse/"; + +#define MAX_DISP_RADIUS 2048 // max displayable circle radius in pixels +#include "config.h" +#include "giacPCH.h" +#if defined HAVE_UNISTD_H && !defined NUMWORKS && !defined HP39 +#include +#endif +#ifdef NSPIRE_NEWLIB +#include +#include +#include +#include +#include +#include +#include "sha256.h" +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif +#ifndef is_cx2 +#define is_cx2 false +#endif +int osok=1; +extern "C" int shell_x,shell_y,shell_fontw,shell_fonth; +#ifdef HP39 +extern "C" char Setup_GetEntry(unsigned int index); +#define MINI_OVER 0 +#define MINI_REV 1 +int shell_x=0,shell_y=0,shell_fontw=7,shell_fonth=14; +int fileBrowser(char* filename, char* filter, char* title); +#define _green 0 +#define _red 0 +#define dbgprintf printf +#else +int shell_x=0,shell_y=0,shell_fontw=12,shell_fonth=18; +#define _green _GREEN +#define _red _RED +#define dbgprintf(...) +#endif + + + +// pour le mode examen cx2, il y a 2 endroits ou is_cx2 est utilise dans smallmenu.selection==1 +// soit par extinction des leds (marche avec OS 5.2) +// soit comme sur la CX si l'ecriture en flash NAND marche un jour +#ifdef SDL_KHICAS +#include +extern "C" void console_log(const char * s){ + EM_ASM({ + var value = UTF8ToString($0); + console.log(value); + },s); +} +#else +extern "C" void console_log(const char *){} +#endif + + + +#if defined KHICAS || defined SDL_KHICAS +#include "qrcodegen.h" + +#ifdef NUMWORKS +#ifdef TLSF +extern "C" unsigned tlsf_avail(); // memory available +#endif +#if !defined NUMWORKS_SLOTB // || defined SDL_KHICAS || defined SIMU +#define QRHELP +#endif + +#if defined NUMWORKS && defined DEVICE +unsigned ram_avail(){ +#ifdef TLSF + return tlsf_avail(); +#else + return _heap_size-((int)_heap_ptr-(int)_heap_base); +#endif +} +#endif + +#if defined NUMWORKS_SLOTB || defined NUMWORKS_SLOTAB +extern "C" void sync_screen();//{} +#endif + +char * freeptr=0; +#ifndef DEVICE +#ifdef __APPLE__ +#include +#endif +const char * flash_filename(){ +#ifdef __APPLE__ + static string s=""; + char ptr[256]={0}; + if (getcwd(ptr,256)){ + s=ptr; + if (s=="/"){ + if (getenv("HOME")){ + s=getenv("HOME"); + string s1 = s+"/Library/Application\ Support/Upsilon/"; + mkdir(s1.c_str(),0755); // ignore error if dir exists + if (giac::is_file_available((s1+"scripts.tar").c_str())) + s=s1; + else + s+="/Documents/"; + } + } + if (s.size()==0 || s[s.size()-1]!='/') + s += '/'; + s+="scripts.tar"; + cout << "User flash filename " << s << "\n"; + return s.c_str(); + } +#endif + return "scripts.tar"; +} +const char * flash_buf=file_gettar_aligned(flash_filename(),freeptr); +extern "C" const char * flash_read(const char * filename){ + return tar_loadfile(flash_buf,filename,0); +} +extern "C" int flash_filebrowser(const char ** filenames,int maxrecords,const char * extension){ + return tar_filebrowser(flash_buf,filenames,maxrecords,extension); +} +#else +#ifdef NUMWORKS_SLOTAB +const char * flash_buf=(const char *)0x90400000; +#else +const char * flash_buf=(const char *)0x90200000; +#endif +#endif + +#else // NUMWORKS +#define QRHELP +#endif // NUMWORKS + +#if defined NUMWORKS && !defined DEVICE && !defined KHICAS && !defined SDL_KHICAS //ndef NSPIRE_NEWLIB +extern "C" { + short int nspire_exam_mode=0; +} +#endif +#define XWASPY 1 // save .xw file as _xw.py (to be recognized by Numworks workshop) +const int xwaspy_shift=33; // must be between 32 and 63, reflect in xcas.js and History.cc +#include "kdisplay.h" +#include +#include +#include +#include +#include +#include "input_lexer.h" +#include "input_parser.h" + + +#if defined NUMWORKS && defined DEVICE + void py_ck_ctrl_c(){ + if (giac::ctrl_c || giac::interrupted) + raisememerr(); + } +#else + void py_ck_ctrl_c(){} +#endif + +#ifdef SDL_KHICAS +#define COLOR_BLACK 0 +#define COLOR_WHITE 65535 +#endif + +//giac::context * contextptr=0; +#if defined NUMWORKS_SLOTBFR || defined NUMWORKS_SLOTBEN +#ifdef NUMWORKS_SLOTBFR +const int lang=1; +#else +const int lang=0; +#endif +#else +int lang=1; +#endif + +#ifndef BW +int clip_ymin=0; +#endif +short int nspirelua=0; +bool warn_nr=true; +bool xthetat=false; +#ifdef BW +bool freezeturtle=false; +#endif +bool nws_freezeturtle=false; +bool global_show_axes=true; +int esc_flag=0; +int xcas_python_eval=0; +char * python_heap=0; + +#ifdef QUICKJS +#include "qjsgiac.h" +#endif + +#ifdef MICROPY_LIB +extern "C" int mp_token(const char * line); + +void python_free(){ + if (!python_heap) return; + mp_deinit(); free(python_heap); python_heap=0; +} + +int python_init(int stack_size,int heap_size){ +#if 1 // defined NUMWORKS + python_free(); + python_heap=micropy_init(stack_size,heap_size); + if (!python_heap) + return 0; +#endif + return 1; +} + +int micropy_ck_eval(const char *line){ + giac::ctrl_c=giac::interrupted=false; + giac::freeze=false; + if (python_heap && line[0]==0) + return 1; + if (!python_heap){ + python_init(pythonjs_stack_size,pythonjs_heap_size); + } + if (!python_heap){ + console_output("Memory full",11); + return RAND_MAX; + } + enable_back_interrupt(); + int res=micropy_eval(line); + disable_back_interrupt(); + return res; + // if MP_PARSE_SINGLE_INPUT is used, split input if newline not followed by a space, return shift + int shift=0,nl=0; + const char * ptr=line; + for (;;++ptr){ + if (*ptr=='\n') + ++nl; + if (*ptr==0 || (*ptr=='\n' && *(ptr+1)!=' ')){ + int n=ptr-line; + char buf[n+1]; + strncpy(buf,line,n); + buf[n]=0; + micropy_eval(buf); + if (parser_errorline) + return shift; + if (*ptr==0) + return 0; + line=ptr+1; + shift=nl; + } + } + return 0; +} +#endif + +using namespace std; +using namespace giac; +#ifdef HP39 +const int LCD_WIDTH_PX=256; +const int LCD_HEIGHT_PX=127; +#else +//const int LCD_WIDTH_PX=320; +//const int LCD_HEIGHT_PX=222; +#endif +char* fmenu_cfg=0; +int khicas_addins_menu(GIAC_CONTEXT); // in kadd.cc +#ifdef MICROPY_LIB +extern "C" const char * const * mp_vars(); +#endif +#if defined NUMWORKS && defined DEVICE +extern "C" void extapp_clipboardStore(const char *text); +extern "C" const char * extapp_clipboardText(); +#endif + +#ifdef BW + int PrintMini(int x,int y,const char * s,int mode){ + if (mode==TEXT_MODE_NORMAL) + return os_draw_string_medium(x,y,SDK_BLACK,SDK_WHITE,s,false); + else + return os_draw_string_medium(x,y,SDK_BLACK,color_gris,s,false); + } + +int get_free_memory(){ + return -1; +} +#endif + +#if defined NUMWORKS // || (defined NSPIRE_NEWLIB && !defined BW) +#if !defined SDL_KHICAS + int GetSetupSetting(int mode){ + return 0; + } +#endif + + void SetSetupSetting(int mode,int){ + } + + int handle_f5(){ + lock_alpha(); + return 0; + } +#endif +// Numworks Logo commands +#ifndef NO_NAMESPACE_GIAC +namespace giac { +#endif // ndef NO_NAMESPACE_GIAC +#if 0 + void Bdisp_PutDisp_DD(){ + sync_screen(); + } + void Bdisp_AllClr_VRAM(){ + waitforvblank(); + drawRectangle(0,0,LCD_WIDTH_PX,LCD_HEIGHT_PX,_WHITE); + } +#endif +#ifdef BW + void drawLine(int x1,int y1,int x2,int y2,int c){ + draw_line(x1,y1,x2,y2,c); + } + void draw_line(int x1,int y1,int x2,int y2,int c,GIAC_CONTEXT){ + draw_line(x1,y1,x2,y2,c); + } + +#else + void drawLine(int x1,int y1,int x2,int y2,int c){ + draw_line(x1,y1,x2,y2,c,context0); + } +#endif + void stroke_rectangle(int x,int y,int w,int h,int c){ + drawLine(x,y,x+w,y,c); + drawLine(x,y+h,x+w,y+h,c); + drawLine(x,y,x,y+h,c); + drawLine(x+w,y,x+w,y+h,c); + } + void DefineStatusMessage(const char * s,int a,int b,int c){ + statuslinemsg(s); + } + + void DisplayStatusArea(){ + sync_screen(); + } + + void set_xcas_status(){ + statusline(1+2*xcas_python_eval); + } + +#ifndef BW + int chartab(){ + static int row=0,col=0; + for (;;){ + int cur=32+16*row+col; + col &= 0xf; + if (row<0) row=5; else if (row>5) row=0; + // display table + drawRectangle(0,0,LCD_WIDTH_PX,LCD_HEIGHT_PX,_WHITE); + os_draw_string_medium(0,0,_BLACK,_WHITE,lang==1?"Selectionner caractere":"Select char"); +#ifdef HP39 + int dy=12; + for (int r=0;r<6;++r){ + for (int c=0;c<16;++c){ + int currc=32+16*r+c; + unsigned char buf[2]={currc==127?(unsigned char)'X':(unsigned char)currc,0}; + os_draw_string(12*c,dy+16*r,cur==currc?_WHITE:_BLACK,cur==currc?_BLACK:_WHITE,buf); + } + } +#else + for (int r=0;r<6;++r){ + for (int c=0;c<16;++c){ + char buf[2]={char(32+16*r+c),0}; + os_draw_string(20*c,20+20*r,_BLACK,(r==row && c==col?color_gris:_WHITE),buf); + } + } +#endif + string s("Current "); + s += char(cur); + s += " "; + s += print_INT_(cur); + s += " "; + s += hexa_print_INT_(cur); +#ifdef HP39 + os_draw_string_medium(0,112,_BLACK,_WHITE,(const unsigned char *)s.c_str()); +#else + os_draw_string(0,160,_BLACK,_WHITE,s.c_str()); + os_draw_string(0,180,_BLACK,_WHITE,lang==1?"EXE: copier caractere":"EXE: copy char"); +#endif + // interaction + int key=getkey(1); + //dbgprintf("key %i %i\n",key,cur); + if (key==KEY_CTRL_EXIT) + return -1; + if (key==KEY_CTRL_OK || key==KEY_CTRL_EXE) + return cur; + if (key==KEY_CTRL_LEFT) + --col; + if (key==KEY_CTRL_RIGHT) + ++col; + if (key==KEY_CTRL_UP) + --row; + if (key==KEY_CTRL_DOWN) + ++row; + } + } + + void delete_clipboard(){} + + bool clip_pasted=true; + + string * clipboard(){ + static string * ptr=0; + if (!ptr) + ptr=new string; + return ptr; + } + + void copy_clipboard(const string & s,bool status){ + dbgprintf("clip %s\n",s.c_str()); +#if defined NUMWORKS && defined DEVICE && !defined NUMWORKS_SLOTB && !defined NUMWORKS_SLOTAB + extapp_clipboardStore(s.c_str()); +#else + if (1 || clip_pasted) // adding to clipboard is sometimes annoying + *clipboard()=s; + else + *clipboard()+=s; +#endif + clip_pasted=false; + if (status){ + DefineStatusMessage((char*)((lang==1)?"Selection copiee vers presse-papiers.":"Selection copied to clipboard"), 1, 0, 0); + DisplayStatusArea(); + } + } + + const char * paste_clipboard(){ + dbgprintf("clip %s\n",clipboard()->c_str()); + clip_pasted=true; +#if defined NUMWORKS && defined DEVICE && !defined NUMWORKS_SLOTB && !defined NUMWORKS_SLOTAB + return extapp_clipboardText(); +#endif + return clipboard()->c_str(); + } + + + int print_msg12(const char * msg1,const char * msg2,int textY=40){ + drawRectangle(0, textY+10, LCD_WIDTH_PX, 44, COLOR_WHITE); + drawRectangle(3,textY+10,316,3, COLOR_BLACK); + drawRectangle(3,textY+10,3,44, COLOR_BLACK); + drawRectangle(316,textY+10,3,44, COLOR_BLACK); + drawRectangle(3,textY+54,316,3, COLOR_BLACK); + int textX=30; + if (msg1){ + if (strlen(msg1)>=30) + os_draw_string_small_(textX,textY+15,msg1); + else + os_draw_string_(textX,textY+15,msg1); + } + textX=10; + textY+=33; + if (msg2){ + if (strlen(msg2)>=30) + os_draw_string_small_(textX,textY,msg2); + else + textX=os_draw_string_(textX,textY,msg2); + } + return textX; + } + + void insert(string & s,int pos,const char * add){ + if (pos>s.size()) + pos=s.size(); + if (pos<0) + pos=0; + s=s.substr(0,pos)+add+s.substr(pos,s.size()-pos); + } + + bool do_confirm(const char * s){ +#ifdef NSPIRE_NEWLIB + return confirm(s,((lang==1)?"enter: oui, esc:annuler":"enter: yes, esc: cancel"))==KEY_CTRL_F1; +#else + return confirm(s,((lang==1)?"OK: oui, Back:annuler":"OK: yes, Back: cancel"))==KEY_CTRL_F1; +#endif + } + + int confirm(const char * msg1,const char * msg2,bool acexit,int y){ + int key=0; + print_msg12(msg1,msg2,y); + while (key!=KEY_CTRL_F1 && key!=KEY_CTRL_F6){ + GetKey(&key); + if (key==KEY_SHUTDOWN) + return key; + if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK || key==KEY_CHAR_CR) + key=KEY_CTRL_F1; + if (key==KEY_CTRL_AC || key==KEY_CTRL_EXIT || key==KEY_CTRL_MENU){ + if (acexit) return -1; + key=KEY_CTRL_F6; + } + set_xcas_status(); + } + return key; + } + + bool confirm_overwrite(){ +#ifdef NSPIRE_NEWLIB + return do_confirm((lang==1)?"enter: oui, esc:annuler":"enter: yes, esc: cancel")==KEY_CTRL_F1; +#else + return do_confirm((lang==1)?"OK: oui, Back:annuler":"OK: yes, Back: cancel")==KEY_CTRL_F1; +#endif + } + + void invalid_varname(){ + confirm((lang==1)?"Nom de variable incorrect":"Invalid variable name", +#ifdef NSPIRE_NEWLIB + (lang==1)?"enter: ok":"enter: ok" +#else + (lang==1)?"OK: ok":"OK: ok" +#endif + ); + } +#endif + + +#ifdef SCROLLBAR + typedef scrollbar TScrollbar; +#endif + +#ifndef BW +#ifdef HP39 +#define C24 16 // 24 on 90 +#define C18 16 // 18 +#define C10 8 // 18 +#define C6 6 // 6 +#else +#define C24 18 // 24 on 90 +#define C18 18 // 18 +#define C10 10 // 18 +#define C6 6 // 6 +#endif +#endif + + int MB_ElementCount(const char * s){ + return strlen(s); // FIXME for UTF8 + } + + void PrintXY(int x,int y,const char * s,int mode,int c=SDK_BLACK,int bg=SDK_WHITE){ + if (mode==TEXT_MODE_NORMAL) + os_draw_string(x,y,c,bg,s); + else { +#ifndef HP39 + if (c==SDK_BLACK && bg==SDK_WHITE) + os_draw_string(x,y,c,color_gris,s); + else +#endif + os_draw_string(x,y,bg,c,s); + } + } + + int PrintMiniMini(int x,int y,const char * s,int mode,int c=SDK_BLACK,int bg=SDK_WHITE,bool fake=false){ +#ifdef SDL_KHICAS + // console_log(("printminimini "+string(s)+" "+print_INT_(x)+","+print_INT_(y)+" mode="+print_INT_(mode)+" c="+print_INT_(c)+" bg="+print_INT_(bg)+(fake?"fake":"")).c_str()); + if (mode==TEXT_MODE_NORMAL) + return numworks_draw_string_small(x,y,c,bg,s,fake); + else + return numworks_draw_string_small(x,y,bg,c,s,fake); +#else + if (mode==TEXT_MODE_NORMAL) + return os_draw_string_small(x,y,c,bg,s,fake); + else { +#ifndef HP39 + if (c==SDK_BLACK && bg==SDK_WHITE) + return os_draw_string_small(x,y,c,color_gris,s,fake); + else +#endif + return os_draw_string_small(x,y,bg,c,s,fake); + } +#endif + } + + + int PrintMini7(int x,int y,const char * s,int mode,int c,int bg,bool fake){ + //console_log(("printmini7 "+string(s)+" "+print_INT_(x)+","+print_INT_(y)+" mode="+print_INT_(mode)+" c="+print_INT_(c)+" bg="+print_INT_(bg)+(fake?"fake":"")).c_str()); + if (mode==TEXT_MODE_NORMAL) + return os_draw_string_medium(x,y,c,bg,s,fake); + else { +#ifndef HP39 + if (c==SDK_BLACK && bg==SDK_WHITE) + return os_draw_string_medium(x,y,c,color_gris,s,fake); + else +#endif + return os_draw_string_medium(x,y,bg,c,s,fake); + } + } + + int PrintMini(int x,int y,const char * s,int mode){ + return PrintMini7(x,y,s,mode,SDK_BLACK,SDK_WHITE,false); + } + +#ifndef BW + void printCentered(const char* text, int y) { + int len = strlen(text); + int x = LCD_WIDTH_PX/2-(len*6)/2; + PrintXY(x,y,text,0); + } +#endif + + int doMenu(Menu* menu, MenuItemIcon* icontable) { // returns code telling what user did. selection is on menu->selection. menu->selection starts at 1! + int itemsStartY=menu->startY; // char Y where to start drawing the menu items. Having a title increases this by one + int itemsHeight=menu->height; + int showtitle = menu->title != NULL; + if (showtitle) { + itemsStartY++; + itemsHeight--; + } + char keyword[5]; + keyword[0]=0; + if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems)) + menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems); + if(menu->selection-1 < menu->scroll) + menu->scroll = menu->selection -1; + + while(1) { + // Cursor_SetFlashOff(); + if (menu->selection <=1) + menu->selection=1; + if (menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems)) + menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems); + if (menu->selection-1 < menu->scroll) + menu->scroll = menu->selection -1; + if(menu->statusText != NULL) DefineStatusMessage(menu->statusText, 1, 0, 0); + // Clear the area of the screen we are going to draw on + if(0 == menu->pBaRtR) { + int x=C10*menu->startX-1, + y=C24*(menu->miniMiniTitle ? itemsStartY:menu->startY)-1, + w=2+C10*menu->width /* + ((menu->scrollbar && menu->scrollout)?C10:0) */, + h=2+C24*menu->height-(menu->miniMiniTitle ? C24:0); + if (y<0) y=0; + if (y>C58) y=C58; + if (y+h>C58) h=C58-y; + // drawRectangle(x, y, w, h, COLOR_WHITE); + draw_line(x,y,x+w,y,COLOR_BLACK,context0); + draw_line(x,y+h,x+w,y+h,COLOR_BLACK,context0); + draw_line(x,y,x,y+h,COLOR_BLACK,context0); + draw_line(x+w,y,x+w,y+h,COLOR_BLACK,context0); + } + if (menu->numitems>0) { + for(int curitem=0; curitem < menu->numitems; curitem++) { + // print the menu item only when appropriate + if(menu->scroll <= curitem && menu->scroll > curitem-itemsHeight) { + if ((curitem-menu->scroll) % 6==0) + waitforvblank(); + char menuitem[256] = ""; + if(menu->numitems>=100 || menu->type == MENUTYPE_MULTISELECT){ + strcpy(menuitem, " "); //allow for the folder and selection icons on MULTISELECT menus (e.g. file browser) + strcpy(menuitem+2,menu->items[curitem].text); + } + else if (menu->type==MENUTYPE_NO_NUMBER) + strcpy(menuitem,menu->items[curitem].text); + else { + int cur=curitem+1; + if (menu->numitems<10){ + menuitem[0]='0'+cur; + menuitem[1]=' '; + menuitem[2]=0; + } + else { + menuitem[0]=cur>=10?('0'+(cur/10)):' '; + menuitem[1]='0'+(cur%10); + menuitem[2]=' '; + menuitem[3]=0; + } + strncat(menuitem, menu->items[curitem].text, 250); + } + if(menu->items[curitem].type != MENUITEM_SEPARATOR) { + //make sure we have a string big enough to have background when item is selected: + // MB_ElementCount is used instead of strlen because multibyte chars count as two with strlen, while graphically they are just one char, making fillerRequired become wrong + int fillerRequired = menu->width - MB_ElementCount(menu->items[curitem].text) - (menu->type == MENUTYPE_MULTISELECT ? 2 : 3); + for(int i = 0; i < fillerRequired; i++) + strcat(menuitem, " "); + dbgprintf("menu %i %i\n",curitem,C10*menu->width); + drawRectangle(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),C10*menu->width,C24,(menu->selection == curitem+1 ? color_gris : _WHITE)); + PrintXY(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),menuitem, (menu->selection == curitem+1 ? TEXT_MODE_INVERT : TEXT_MODE_NORMAL)); + } else { + /*int textX = (menu->startX-1) * C18; + int textY = curitem*C24+itemsStartY*C24-menu->scroll*C24-C24+C10; + clearLine(menu->startX, curitem+itemsStartY-menu->scroll, (menu->selection == curitem+1 ? textColorToFullColor(menu->items[curitem].color) : COLOR_WHITE)); + drawLine(textX, textY+C24-4, LCD_WIDTH_PX-2, textY+C24-4, COLOR_GRAY); + PrintMini7(&textX, &textY, (unsigned char*)menuitem, 0, 0xFFFFFFFF, 0, 0, (menu->selection == curitem+1 ? COLOR_WHITE : textColorToFullColor(menu->items[curitem].color)), (menu->selection == curitem+1 ? textColorToFullColor(menu->items[curitem].color) : COLOR_WHITE), 1, 0);*/ + } + // deal with menu items of type MENUITEM_CHECKBOX + if(menu->items[curitem].type == MENUITEM_CHECKBOX) { + PrintXY(C10*(menu->startX+menu->width-4),C18*(curitem+itemsStartY-menu->scroll), + (menu->items[curitem].value == MENUITEM_VALUE_CHECKED ? " [+]" : " [-]"), + (menu->selection == curitem+1 ? TEXT_MODE_INVERT : (menu->pBaRtR == 1? TEXT_MODE_NORMAL : TEXT_MODE_NORMAL))); + } + // deal with multiselect menus + if(menu->type == MENUTYPE_MULTISELECT) { + if((curitem+itemsStartY-menu->scroll)>=itemsStartY && + (curitem+itemsStartY-menu->scroll)<=(itemsStartY+itemsHeight) && + icontable != NULL + ) { +#if 0 + if (menu->items[curitem].isfolder == 1) { + // assumes first icon in icontable is the folder icon + CopySpriteMasked(icontable[0].data, (menu->startX)*C18, (curitem+itemsStartY-menu->scroll)*C24, 0x12, 0x18, 0xf81f ); + } else { + if(menu->items[curitem].icon >= 0) CopySpriteMasked(icontable[menu->items[curitem].icon].data, (menu->startX)*C18, (curitem+itemsStartY-menu->scroll)*C24, 0x12, 0x18, 0xf81f ); + } +#endif + } + if (menu->items[curitem].isselected) { + if (menu->selection == curitem+1) { + PrintXY(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),"\xe6\x9b", TEXT_MODE_NORMAL); + } else { + PrintXY(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),"\xe6\x9b", TEXT_MODE_NORMAL); + } + } + } + } + } // end for curitemnumitem + int dh=menu->height-menu->numitems-(showtitle?1:0); + if (dh>0) + drawRectangle(C10*menu->startX,C24*(menu->numitems+(showtitle?1:0)),C10*menu->width,C24*dh,_WHITE); + if (menu->scrollbar) { +#ifdef SCROLLBAR + TScrollbar sb; + sb.I1 = 0; + sb.I5 = 0; + sb.indicatormaximum = menu->numitems; + sb.indicatorheight = itemsHeight; + sb.indicatorpos = menu->scroll; + sb.barheight = itemsHeight*C24; + sb.bartop = (itemsStartY-1)*C24; + sb.barleft = menu->startX*C18+menu->width*C18 - C18 - (menu->scrollout ? 0 : 5); + sb.barwidth = C10; + Scrollbar(&sb); +#endif + } + //if(menu->type==MENUTYPE_MULTISELECT && menu->fkeypage == 0) drawFkeyLabels(0x0037); // SELECT (white) + } else { + giac::printCentered(menu->nodatamsg, (itemsStartY*C24)+(itemsHeight*C24)/2-12); + } + if(showtitle) { + int textX = C10*menu->startX, textY=menu->startY*C24; + drawRectangle(textX,textY,C10*menu->width,C24,_WHITE); + if (menu->miniMiniTitle) + PrintMini( textX, textY, menu->title, 0 ); + else + PrintXY(textX, textY, menu->title, TEXT_MODE_NORMAL); + if(menu->subtitle != NULL) { + int textX=(MB_ElementCount(menu->title)+menu->startX-1)*C18+C10, textY=C10; + PrintMini(textX, textY, menu->subtitle, 0); + } + int xpos=textX+C10*(menu->width-5); + PrintXY(xpos, 1, "____", 0); + PrintXY(xpos, 1, keyword, 0); + } + /*if(menu->darken) { + DrawFrame(COLOR_BLACK); + VRAMInvertArea(menu->startX*C18-C18, menu->startY*C24, menu->width*C18-(menu->scrollout || !menu->scrollbar ? 0 : 5), menu->height*C24); + }*/ + if(menu->type == MENUTYPE_NO_KEY_HANDLING) return MENU_RETURN_INSTANT; // we don't want to handle keys + int key; + GetKey(&key); + if (key==KEY_SHUTDOWN) + return key; + if (key==KEY_CTRL_MENU){ + menu->selection=menu->numitems; + return MENU_RETURN_SELECTION; + } + if (key<256 && my_isalpha(key)){ + key=tolower(key); + int pos=strlen(keyword); + if (pos>=4) + pos=0; + keyword[pos]=key; + keyword[pos+1]=0; + int cur=0; + for (;curnumitems;++cur){ +#if 1 + if (strcmp(menu->items[cur].text,keyword)>=0) + break; +#else + char c=menu->items[cur].text[0]; + if (key<=c) + break; +#endif + } + if (curnumitems){ + menu->selection=cur+1; + if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems)) + menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems); + if(menu->selection-1 < menu->scroll) + menu->scroll = menu->selection -1; + } + continue; + } + switch(key) { + case KEY_CTRL_PAGEDOWN: + menu->selection+=6; + if (menu->selection >= menu->numitems) + menu->selection=menu->numitems; + if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems)) + menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems); + break; + case KEY_CTRL_DOWN: + if(menu->selection == menu->numitems) + { + if(menu->returnOnInfiniteScrolling) { + return MENU_RETURN_SCROLLING; + } else { + menu->selection = 1; + menu->scroll = 0; + } + } + else + { + menu->selection++; + if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems)) + menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems); + } + if(menu->pBaRtR==1) return MENU_RETURN_INSTANT; + break; + case KEY_CTRL_PAGEUP: + menu->selection-=6; + if (menu->selection <=1) + menu->selection=1; + if(menu->selection-1 < menu->scroll) + menu->scroll = menu->selection -1; + break; + case KEY_CTRL_UP: + if(menu->selection == 1) + { + if(menu->returnOnInfiniteScrolling) { + return MENU_RETURN_SCROLLING; + } else { + menu->selection = menu->numitems; + menu->scroll = menu->selection-(menu->numitems>itemsHeight ? itemsHeight : menu->numitems); + } + } + else + { + menu->selection--; + if(menu->selection-1 < menu->scroll) + menu->scroll = menu->selection -1; + } + if(menu->pBaRtR==1) return MENU_RETURN_INSTANT; + break; + case KEY_CTRL_F1: + if(menu->type==MENUTYPE_MULTISELECT && menu->fkeypage == 0 && menu->numitems > 0) { + /*if(menu->items[menu->selection-1].isselected) { + menu->items[menu->selection-1].isselected=0; + menu->numselitems = menu->numselitems-1; + } else { + menu->items[menu->selection-1].isselected=1; + menu->numselitems = menu->numselitems+1; + } + return key; //return on F1 too so that parent subroutines have a chance to e.g. redraw fkeys*/ + } else if (menu->type == MENUTYPE_FKEYS || menu->type==MENUTYPE_NO_NUMBER) { + return key; + } + break; + case KEY_CTRL_F2: + case KEY_CTRL_F3: + case KEY_CTRL_F4: + case KEY_CTRL_F5: + case KEY_CTRL_F6: case KEY_CTRL_CATALOG: case KEY_BOOK: case '\t': case KEY_CHAR_EXPN10: case KEY_CTRL_SETUP: + case KEY_CHAR_ANS: + if (menu->type == MENUTYPE_FKEYS || menu->type==MENUTYPE_NO_NUMBER || menu->type==MENUTYPE_MULTISELECT) return key; // MULTISELECT also returns on Fkeys + break; + case KEY_CTRL_PASTE: + if (menu->type==MENUTYPE_MULTISELECT) return key; // MULTISELECT also returns on paste + case KEY_CTRL_OPTN: + if (menu->type==MENUTYPE_FKEYS || menu->type==MENUTYPE_MULTISELECT) return key; + break; + case KEY_CTRL_FORMAT: + if (menu->type==MENUTYPE_FKEYS) return key; // return on the Format key so that event lists can prompt to change event category + break; + case KEY_CTRL_RIGHT: + if(menu->type != MENUTYPE_MULTISELECT) return KEY_BOOK; // break; + // else fallthrough + case KEY_CTRL_EXE: case KEY_CTRL_OK: case KEY_CHAR_CR: + if(menu->numitems>0) return key==KEY_CTRL_OK?MENU_RETURN_SELECTION:key; + break; + case KEY_CTRL_LEFT: + if(menu->type != MENUTYPE_MULTISELECT) break; + // else fallthrough + case KEY_CTRL_DEL: + if (strlen(keyword)) + keyword[strlen(keyword)-1]=0; + else { + if (strcmp(menu->title,"Variables")==0) + return key; + } + break; + case KEY_CTRL_AC: + if (strlen(keyword)){ + keyword[0]=0; + lock_alpha();//SetSetupSetting( (unsigned int)0x14, 0x88); + //DisplayStatusArea(); + break; + } + case KEY_CTRL_EXIT: + return MENU_RETURN_EXIT; + break; + case KEY_CHAR_1: + case KEY_CHAR_2: + case KEY_CHAR_3: + case KEY_CHAR_4: + case KEY_CHAR_5: + case KEY_CHAR_6: + case KEY_CHAR_7: + case KEY_CHAR_8: + case KEY_CHAR_9: + if (menu->type==MENUTYPE_NO_NUMBER) + return key; + if(menu->numitems>=(key-0x30)) { + menu->selection = (key-0x30); + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_0: + if (menu->type==MENUTYPE_NO_NUMBER) + return key; + if(menu->numitems>=10) { + menu->selection = 10; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_EXPN: + if(menu->numitems>=11) { + menu->selection = 11; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_LN: + if(menu->numitems>=12) { + menu->selection = 12; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_LOG: + if(menu->numitems>=13) { + menu->selection = 13; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_IMGNRY: + if(menu->numitems>=14) { + menu->selection = 14; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_COMMA: + if(menu->numitems>=15) { + menu->selection = 15; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_POW: + if(menu->numitems>=16) { + menu->selection = 16; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_SIN: + case KEY_CHAR_COS: + case KEY_CHAR_TAN: + if(menu->numitems>=(key-112)) { + menu->selection = (key-112); + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_PI: + if(menu->numitems>=20) { + menu->selection = 20; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_ROOT: + if(menu->numitems>=21) { + menu->selection = 21; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_SQUARE: + if(menu->numitems>=22) { + menu->selection = 22; + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + case KEY_CHAR_LPAR: + case KEY_CHAR_RPAR: + if(menu->numitems>=(key-17)) { + menu->selection = (key-17); + if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION; + } + break; + } + } + return MENU_RETURN_EXIT; + } + +#define CAT_CATEGORY_ALL 0 +#define CAT_CATEGORY_ALGEBRA 1 +#define CAT_CATEGORY_LINALG 2 +#define CAT_CATEGORY_CALCULUS 3 +#define CAT_CATEGORY_ARIT 4 +#define CAT_CATEGORY_COMPLEXNUM 5 +#define CAT_CATEGORY_PLOT 6 +#define CAT_CATEGORY_POLYNOMIAL 7 +#define CAT_CATEGORY_PROBA 8 +#define CAT_CATEGORY_PROGCMD 9 +#define CAT_CATEGORY_REAL 10 +#define CAT_CATEGORY_SOLVE 11 +#define CAT_CATEGORY_STATS 12 +#define CAT_CATEGORY_TRIG 13 +#define CAT_CATEGORY_OPTIONS 14 +#define CAT_CATEGORY_LIST 15 +#define CAT_CATEGORY_MATRIX 16 +#define CAT_CATEGORY_PROG 17 +#define CAT_CATEGORY_SOFUS 18 +#define CAT_CATEGORY_PHYS 19 +#define CAT_CATEGORY_UNIT 20 +#define CAT_CATEGORY_2D 21 +#define CAT_CATEGORY_3D 22 +#define CAT_CATEGORY_LOGO 23 // should be the last one +#define XCAS_ONLY 0x80000000 + void init_locale(){ +#if !defined NUMWORKS_SLOTBFR && !defined NUMWORKS_SLOTBEN + lang=1; +#endif + } + + const catalogFunc completeCatfr[] = { // list of all functions (including some not in any category) + // {"cosh(x)", 0, "Hyperbolic cosine of x.", 0, 0, CAT_CATEGORY_TRIG}, + // {"exp(x)", 0, "Renvoie e^x.", "1.2", 0, CAT_CATEGORY_REAL}, + // {"log(x)", 0, "Logarithme naturel de x.", 0, 0, CAT_CATEGORY_REAL}, + // {"sinh(x)", 0, "Hyperbolic sine of x.", 0, 0, CAT_CATEGORY_TRIG}, + // {"tanh(x)", 0, "Hyperbolic tangent of x.", 0, 0, CAT_CATEGORY_TRIG}, + {" boucle for (pour)", "for ", "Boucle definie pour un indice variant entre 2 valeurs fixees", "#\nfor ", 0, CAT_CATEGORY_PROG}, + {" boucle liste", "for in", "Boucle sur les elements d'une liste.", "#\nfor in", 0, CAT_CATEGORY_PROG}, + {" boucle while (tantque)", "while ", "Boucle indefinie tantque.", "#\nwhile ", 0, CAT_CATEGORY_PROG}, + {" test si alors", "if ", "Test", "#\nif ", 0, CAT_CATEGORY_PROG}, + {" test sinon", "else ", "Clause fausse du test", 0, 0, CAT_CATEGORY_PROG}, + {" fonction def.", "f(x):=", "Definition de fonction.", "#\nf(x):=", 0, CAT_CATEGORY_PROG}, + {" local j,k;", "local ", "Declaration de variables locales Xcas", 0, 0, CAT_CATEGORY_PROG | XCAS_ONLY}, + {" range(a,b)", "in range(", "Dans l'intervalle [a,b[ (a inclus, b exclus)", "# in range(1,10)", 0, CAT_CATEGORY_PROG}, + {" return res;", "return ", "return ou retourne quitte la fonction et renvoie le resultat res", 0, 0, CAT_CATEGORY_PROG}, + //{" edit list ", "list(", "Assistant creation de liste.", 0, 0, CAT_CATEGORY_LIST}, + //{" edit matrix ", "matrix(", "Assistant creation de matrice.", 0, 0, CAT_CATEGORY_MATRIX }, + {" mksa(x)", 0, "Conversion en unites MKSA", 0, 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8) | XCAS_ONLY}, + {" ufactor(a,b)", 0, "Factorise l'unite b dans a", "100_J,1_kW", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8) | XCAS_ONLY}, + {" usimplify(a)", 0, "Simplifie l'unite dans a", "100_l/10_cm^2", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8) | XCAS_ONLY}, + //{"fonction def Xcas", "fonction f(x) local y; ffonction:;", "Definition de fonction.", "#fonction f(x) local y; y:=x^2; return y; ffonction:;", 0, CAT_CATEGORY_PROG}, + {"!", "!", "Non logique (prefixe) ou factorielle de n (suffixe).", "#7!", "#!b", CAT_CATEGORY_PROGCMD}, + {"#", "#", "Commentaire Python, en Xcas taper //.", 0, 0, CAT_CATEGORY_PROG}, + {"%", "%", "a % b signifie a modulo b", 0, 0, CAT_CATEGORY_ARIT | (CAT_CATEGORY_PROGCMD << 8)}, + {"&", "&", "Et logique ou +", "#1&2", 0, CAT_CATEGORY_PROGCMD}, + {":=", ":=", "Affectation vers la gauche (inverse de =>).", "#a:=3", 0, CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)|XCAS_ONLY}, +#ifdef QRHELP + {"<", "<", "Inferieur strict. Raccourci SHIFT F2", 0, 0, CAT_CATEGORY_PROGCMD}, +#endif + {"=>", "=>", "Affectation vers la droite ou conversion en (touche ->). Par exemple 5=>a ou x^4-1=>* ou (x+1)^2=>+ ou sin(x)^2=>cos.", "#5=>a", "#15_m=>_cm", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_PHYS <<8) | (CAT_CATEGORY_UNIT << 16) | XCAS_ONLY}, +#ifdef QRHELP + {">", ">", "Superieur strict. Raccourci F2.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"\\", "\\", "Caractere \\", 0, 0, CAT_CATEGORY_PROGCMD}, +#endif + {"_", "_", "Caractere _. Prefixe d'unites.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"_(km/h)", "_(km/h)", "Vitesse en kilometre/heure", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_(m/s)", "_(m/s)", "Vitesse en metre/seconde", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, +#ifdef QRHELP + {"_(m/s^2)", "_(m/s^2)", "Acceleration en metre par seconde au carre", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_(m^2/s)", "_(m^2/s)", "Viscosite", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, +#endif + {"_A", 0, "Intensite electrique en Ampere", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Bq", 0, "Radioactivite: Becquerel", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_C", 0, "Charge electrique en Coulomb", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Ci", 0, "Radioactivite: Curie", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_F", 0, "Farad", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_F_", 0, "constante de Faraday (charge globale d'une mole de charges รฉlรฉmentaires).", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_G_", 0, "constante de gravitation universelle. Force=_G_*m1*m2/r^2", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_H", 0, "Henry", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Hz", 0, "Hertz", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_J", 0, "Energie en Joule=kg*m^2/s^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_K", 0, "Temperature en Kelvin", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Kcal", 0, "Energie en kilo-calorier", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_MeV", 0, "Energie en mega-electron-Volt", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_N", 0, "Force en Newton=kg*m/s^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_NA_", 0, "Avogadro", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_Ohm", 0, "Resistance electrique en Ohm", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_PSun_", 0, "puissance du Soleil", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_Pa", 0, "Pression en Pascal=kg/m/s^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_REarth_", 0, "Rayon de la Terre", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, +#ifndef NUMWORKS_SLOTB + {"_RSun_", 0, "rayon du Soleil", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, +#endif + {"_R_", 0, "constante des gaz (de Boltzmann par mole)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_S", 0, "", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_StdP_", 0, "Pression standard (au niveau de la mer)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_StdT_", 0, "temperature standard (0 degre Celsius exprimes en Kelvins)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_Sv", 0, "Radioactivite: Sievert", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_T", 0, "Tesla", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_V", 0, "Tension electrique en Volt", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Vm_", 0, "Volume molaire", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_W", 0, "Puissance en Watt=kg*m^2/s^3", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Wb", 0, "Weber", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_alpha_", 0, "constante de structure fine", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_c_", 0, "vitesse de la lumiere", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_cd", 0, "Luminosite en candela", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, +#ifndef NUMWORKS_SLOTB + {"_cdf", "_cdf", "Suffixe de distribution cumulee. Taper F2 pour la distribution cumulee inverse.", "#_icdf", 0, CAT_CATEGORY_PROBA|XCAS_ONLY}, +#endif + {"_d", 0, "Temps: jour", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_deg", 0, "Angle en degres", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_eV", 0, "Energie en electron-Volt", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_epsilon0_", 0, "permittivite du vide", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_ft", 0, "Longueur en pieds", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_g_", 0, "gravite au sol", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_grad", 0, "Angle en grades", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_h", 0, "Heure", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_h_", 0, "constante de Planck", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_ha", 0, "Aire en hectare", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_hbar_", 0, "constante de Planck/(2*pi)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_inch", 0, "Longueur en pouces", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_kWh", 0, "Energie en kWh", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_k_", 0, "constante de Boltzmann", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_kg", 0, "Masse en kilogramme", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_l", 0, "Volume en litre", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_m", 0, "Longueur en metre", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, +#ifndef NUMWORKS_SLOTB + {"_mEarth_", 0, "masse de la Terre", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, +#endif + {"_m^2", 0, "Aire en m^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_m^3", 0, "Volume en m^3", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_me_", 0, "masse electron", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_miUS", 0, "Longueur en miles US", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_mn", 0, "Temps: minute", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_mp_", 0, "masse proton", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_mpme_", 0, "ratio de masse proton/electron", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_mu0_", 0, "permeabilite du vide", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_phi_", 0, "quantum flux magnetique", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, +#ifndef NUMWORKS_SLOTB + {"_plot", "_plot", "Suffixe pour graphe d'une regression.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS| XCAS_ONLY}, +#endif + {"_qe_", 0, "charge de l'electron", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_qme_", 0, "_q_/_me_", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_rad", 0, "Angle en radians", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_rem", 0, "Radioactivite: rem", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_s", 0, "Temps: seconde", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_sd_", 0, "Jour sideral", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_syr_", 0, "Annee siderale", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_tr", 0, "Angle en tours", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_yd", 0, "Longueur en yards", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"a and b", " and ", "Et logique", 0, 0, CAT_CATEGORY_PROGCMD}, + {"a or b", " or ", "Ou logique", 0, 0, CAT_CATEGORY_PROGCMD}, + {"abcuv(a,b,c)", 0, "Cherche 2 polynomes u,v tels que a*u+b*v=c","x+1,x^2-2,x", 0, CAT_CATEGORY_POLYNOMIAL| XCAS_ONLY}, + {"abs(x)", 0, "Valeur absolue, module ou norme de x", "-3", "[1,2,3]", CAT_CATEGORY_COMPLEXNUM | (CAT_CATEGORY_REAL<<8)}, + {"add(u,v)", 0, "En Python, addition de listes ou listes de listes u et v comme des vecteurs ou matrices.","[1,2,3],[0,1,3]", "[[1,2]],[[3,4]]", CAT_CATEGORY_LINALG}, + {"append", 0, "Ajoute un element en fin de liste l","#l.append(x)", 0, CAT_CATEGORY_LIST}, + {"approx(x)", 0, "Valeur approchee de x. Raccourci S-D", "pi", 0, CAT_CATEGORY_REAL| XCAS_ONLY}, + {"aire(objet)", 0, "Aire algebrique", "cercle(0,1)", "triangle(-1,1+i,3)", CAT_CATEGORY_2D }, + {"arg(z)", 0, "Argument du complexe z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM | XCAS_ONLY}, + {"asc(string)", 0, "Liste des codes ASCII d'une chaine", "\"Bonjour\"", 0, CAT_CATEGORY_ARIT}, + {"assume(hyp)", 0, "Hypothese sur une variable.", "x>1", "x>-1 and x<1", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_SOFUS<<8) | XCAS_ONLY}, + {"avance n", "avance ", "La tortue avance de n pas, par defaut n=10", "#avance 40", 0, CAT_CATEGORY_LOGO}, + {"axes", "axes", "Axes visibles ou non axes=1 ou 0", "#axes=0", "#axes=1", CAT_CATEGORY_PROGCMD << 8|XCAS_ONLY}, + {"baisse_crayon ", "baisse_crayon ", "La tortue se deplace en marquant son passage.", 0, 0, CAT_CATEGORY_LOGO}, + {"barplot(list)", 0, "Diagramme en batons d'une serie statistique 1d.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS | (CAT_CATEGORY_PLOT<<8)}, + {"barycentre([pnt,coeff],...)", 0, "Barycentre d'une sequnence de [points,coefficients]. Utiliser isobarycenter si tous les coefficients sont egaux.", "[1,1],[i,1],[2,3]", 0, CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"binomial(n,p,k)", 0, "binomial(n,p,k) probabilite de k succes avec n essais ou p est la proba de succes d'un essai. binomial_cdf(n,p,k) est la probabilite d'obtenir au plus k succes avec n essais. binomial_icdf(n,p,t) renvoie le plus petit k tel que binomial_cdf(n,p,k)>=t", "10,.5,4", 0, CAT_CATEGORY_PROBA | XCAS_ONLY}, + {"bissectrice(A,B,C)", 0, "Bissectrice de l'angle AB,AC", "1,i,2+i", 0,CAT_CATEGORY_2D}, + {"bitxor", "bitxor", "Ou exclusif", "#bitxor(1,2)", 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"black", "black", "Option d'affichage", "#display=black", 0, CAT_CATEGORY_PROGCMD}, + {"blue", "blue", "Option d'affichage", "#display=blue", 0, CAT_CATEGORY_PROGCMD}, + {"caseval", "caseval", "Evalue une chaine de caractere en appelant le CAS.", "caseval(\"limit(sin(x)/x,x=0)\")", "caseval(\"factor(x^10-1)\")", CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_CALCULUS <<8)}, + {"cache_tortue ", "cache_tortue ", "Cache la tortue apres avoir trace le dessin.", 0, 0, CAT_CATEGORY_LOGO}, + {"camembert(list)", 0, "Diagramme en camembert d'une serie statistique 1d.", "[[\"France\",6],[\"Allemagne\",12],[\"Suisse\",5]]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"ceil(x)", 0, "Partie entiere superieure", "1.2", 0, CAT_CATEGORY_REAL}, + {"centre(objet)", 0, "Centre d'un cercle ou d'une sphere. Pour une conique a centre, renvoie le centre, un foyer et un point de la conique. Pour une parabole, renvoie le foyer et le sommet.", "cercle(0,1)", "sphere([0,0,0],[1,1,1])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"cercle(centre,rayon)", 0, "Cercle donne par centre et rayon ou par un diametre", "2+i,3", "1-i,1+i", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"circonscrit(A,B,C)", 0, "Cercle circonscrit", "-1,2+i,3", 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"cfactor(p)", 0, "Factorisation sur C.", "x^4-1", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8) | XCAS_ONLY}, + {"char(liste)", 0, "Chaine donnee par une liste de code ASCII", "[97,98,99]", 0, CAT_CATEGORY_ARIT}, + {"charpoly(M,x)", 0, "Polynome caracteristique de la matrice M en la variable x.", "[[1,2],[3,4]],x", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"clearscreen()", "clearscreen()", "Efface l'ecran.", 0, 0, CAT_CATEGORY_PROGCMD|XCAS_ONLY}, + {"coeff(p,x,n)", 0, "Coefficient de x^n dans le polynome p.", "(1+x)^6,x,3", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"comb(n,k)", 0, "Renvoie k parmi n.", "10,4", 0, CAT_CATEGORY_PROBA | XCAS_ONLY}, + {"cond(A,[1,2,inf])", 0, "Nombre de condition d'une matrice par rapport a la norme specifiee (par defaut 1)", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"cone(A,v,theta,[h])", 0, "Cone de sommet A, axe v, angle theta, hauteur h optionnelle", "[0,0,0],[0,0,1],pi/6", "[0,0,0],[0,0,1],pi/6,4", CAT_CATEGORY_3D}, + {"conique(expression)", 0, "Conique donnee par une equation polynomiale de degre 2 ou passant par 5 points", "x^2+x*y+y^2=5", "1,i,2+i,3-i,4+2i", CAT_CATEGORY_2D}, + {"coordonnees(object)", 0, "Coordonnees (cartesiennes)", "point(1,2)", "point(1,2,3)", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"conj(z)", 0, "Conjugue complexe de z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM}, + {"correlation(l1,l2)", 0, "Correlation listes l1 et l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"covariance(l1,l2)", 0, "Covariance listes l1 et l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"cpartfrac(p,x)", 0, "Decomposition en elements simples sur C.", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8) | XCAS_ONLY}, + {"crayon ", "crayon ", "Couleur de trace de la tortue", "#crayon rouge", 0, CAT_CATEGORY_LOGO}, + {"cross(u,v)", 0, "Produit vectoriel de u et v.","[1,2,3],[0,1,3]", 0, CAT_CATEGORY_LINALG | (CAT_CATEGORY_2D << 8)}, + {"csolve(equation,x)", 0, "Resolution exacte dans C d'une equation en x (ou d'un systeme polynomial).","x^2+x+1=0", 0, CAT_CATEGORY_SOLVE | (CAT_CATEGORY_COMPLEXNUM << 8) | XCAS_ONLY}, + {"cube(A,B,C)", 0, "Cube d'arete AB avec une face dans le plan ABC", "[0,0,0],[1,0,0],[0,1,0]","[0,0,0],[0,2,sqrt(5)/2+3/2],[0,0,1]", CAT_CATEGORY_3D}, + {"curl(u,vars)", 0, "Rotationnel du vecteur u.", "[2*x*y,x*z,y*z],[x,y,z]", 0, CAT_CATEGORY_LINALG | XCAS_ONLY}, + {"curvature([x(t),y(t)],t,t0)", 0, "Courbure de la courbe parametree [x(t),y(t)] en t0", "[t,t^2],t,1", "[t,t^2],t", CAT_CATEGORY_CALCULUS | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"cyan", "cyan", "Option d'affichage", "#display=cyan", 0, CAT_CATEGORY_PROGCMD}, + {"cylinder(A,v,r,[h])", 0, "Cylindre d'axe A,v de rayon r et de hauteur optionnelle h", "[0,0,0],[0,1,0],2", "[0,0,0],[0,1,0],2,3", CAT_CATEGORY_3D}, + {"debug(f(args))", 0, "Execute la fonction f en mode pas a pas.", 0, 0, CAT_CATEGORY_PROG | XCAS_ONLY}, + {"degree(p,x)", 0, "Degre du polynome p en x.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"denom(x)", 0, "Denominateur de l'expression x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"desolve(equation,t,y)", 0, "Resolution exacte d'equation differentielle ou de systeme differentiel lineaire a coefficients constants.", "[y'+y=exp(x),y(0)=1]", "[y'=[[1,2],[2,1]]*y+[x,x+1],y(0)=[1,2]]", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_CALCULUS << 8) | XCAS_ONLY}, + {"det(A)", 0, "Determinant de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"diff(f,var,[n])", 0, "Derivee de l'expression f par rapport a var (a l'ordre n, n=1 par defaut), par exemple diff(sin(x),x) ou diff(x^3,x,2). Pour deriver f par rapport a x, utiliser f' (raccourci F3). Pour le gradient de f, var est la liste des variables.", "sin(x),x", "sin(x^2),x,3", CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"discriminant(p)", 0, "Discriminant du polynome p", "#P:=a*x^2+b*x+c;discriminant(P);", "discriminant(x^2+x+1)", CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"display", "display", "Option d'affichage", "#display=red", 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"disque n", "disque ", "Cercle rempli tangent a la tortue, de rayon n. Utiliser disque n,theta pour remplir un morceau de camembert ou disque n,theta,segment pour remplir un segment de disque", "#disque 30", "#disque(30,90)", CAT_CATEGORY_LOGO}, + {"distance(A,B)", 0, "Distance de 2 objets geometriques", "point(1,2,3),point(4,1,2)", 0, CAT_CATEGORY_3D | (CAT_CATEGORY_2D << 8) }, + {"dot(a,b)", 0, "Produit scalaire de 2 vecteurs. Raccourci: *", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_LINALG | (CAT_CATEGORY_2D << 8)}, + {"dodecahedron(A,B,C)", 0, "Dodecaedre d'arete AB avec une face dans le plan ABC", "[0,0,0],[0,2,sqrt(5)/2+3/2],[0,0,1]", 0, CAT_CATEGORY_3D}, + {"draw_arc(x1,y1,rx,ry,theta1,theta2,c)", 0, "Arc d'ellipse pixelise.", "100,100,60,80,0,pi,magenta", 0, CAT_CATEGORY_PROGCMD}, + {"draw_circle(x1,y1,r,c)", 0, "Cercle pixelise. Option filled pour le remplir.", "100,100,60,cyan+filled", 0, CAT_CATEGORY_PROGCMD}, + {"draw_line(x1,y1,x2,y2,c)", 0, "Droite pixelisee.", "100,50,300,200,blue", 0, CAT_CATEGORY_PROGCMD}, + {"draw_pixel(x,y,color)", 0, "Colorie le pixel x,y. Faire draw_pixel() pour synchroniser l'ecran.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"draw_polygon([[x1,y1],...],c)", 0, "Polygone pixelise.", "[[100,50],[30,20],[60,70]],red+filled", 0, CAT_CATEGORY_PROGCMD}, + {"draw_rectangle(x,y,w,h,c)", 0, "Rectangle pixelise.", "100,50,30,20,red+filled", 0, CAT_CATEGORY_PROGCMD}, + {"draw_string(s,x,y,c)", 0, "Affiche la chaine s en x,y", "\"Bonjour\",80,60", 0, CAT_CATEGORY_PROGCMD}, + {"droite(equation)", 0, "Droite donnee par une equation ou 2 points", "y=2x+1", "1+i,2-i", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | (CAT_CATEGORY_2D << 16) | XCAS_ONLY}, + {"ecris ", "ecris ", "Ecrire a la position de la tortue", "#ecris \"coucou\"", 0, CAT_CATEGORY_LOGO}, + {"efface", "efface", "Remise a zero de la tortue", 0, 0, CAT_CATEGORY_LOGO | XCAS_ONLY}, + {"egcd(A,B)", 0, "Cherche des polynomes U,V,D tels que A*U+B*V=D=gcd(A,B)","x^2+3x+1,x^2-5x-1", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"eigenvals(A)", 0, "Valeurs propres de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"eigenvects(A)", 0, "Vecteurs propres de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + //{"elif (test)", "elif", "Tests en cascade", 0, 0, CAT_CATEGORY_PROG | XCAS_ONLY}, + //{"end", "end", "Fin de bloc", 0, 0, CAT_CATEGORY_PROG}, + {"ellipse(F1,F2,M)", 0, "Ellipse donnee par les 2 foyers et un point", "-1,1,2", 0, CAT_CATEGORY_2D}, + {"equation(objet)", 0, "Equation cartesienne. Utiliser parameq pour parametrique.", "circle(0,1)", "ellipse(-1,1,3)", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"erf(x)", 0, "Fonction erreur en x.", "1.2", 0, CAT_CATEGORY_PROBA}, + {"erfc(x)", 0, "Fonction erreur complementaire en x.", "1.2", 0, CAT_CATEGORY_PROBA}, + {"euler(n)",0,"Indicatrice d'Euler: nombre d'entiers < n premiers avec n","25",0,CAT_CATEGORY_ARIT}, + {"eval(f)", 0, "Evalue f.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"evalc(z)", 0, "Ecrit z=x+i*y.", "1/(1+i*sqrt(3))", 0, CAT_CATEGORY_COMPLEXNUM | XCAS_ONLY}, + {"exact(x)", 0, "Convertit x en rationnel. Raccourci shift S-D", "1.2", 0, CAT_CATEGORY_REAL | XCAS_ONLY}, + {"exp2trig(expr)", 0, "Conversion d'exponentielles complexes en sin/cos", "exp(i*x)", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, +#ifdef QRHELP + {"exponential_regression(Xlist,Ylist)", 0, "Regression exponentielle.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"exponential_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression exponentielle.", "#X,Y:=[1,2,3,4,5],[1,3,4,6,8];exponential_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, +#endif + {"exponentiald(lambda,x)", 0, "Loi exponentielle de parametre lambda. exponentiald_cdf(lambda,x) probabilite que \"loi exponentielle <=x\" par ex. exponentiald_cdf(2,3). exponentiald_icdf(lambda,t) renvoie x tel que \"loi exponentielle <=x\" vaut t, par ex. exponentiald_icdf(2,0.95) ", "5.1,3.4", 0, CAT_CATEGORY_PROBA | XCAS_ONLY}, + {"extend", 0, "Concatene 2 listes. Attention en Xcas, ne pas utiliser + qui effectue l'addition de 2 vecteurs.","#l1.extend(l2)", 0, CAT_CATEGORY_LIST}, + {"factor(p,[x])", 0, "Factorisation du polynome p (utiliser ifactor pour un entier). Raccourci: p=>*", "x^4-1", "x^6+1,sqrt(3)", CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_POLYNOMIAL << 8) | XCAS_ONLY}, + {"filled", "filled", "Option d'affichage", 0, 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"float(x)", 0, "Convertit x en nombre approche (flottant).", "pi", 0, CAT_CATEGORY_REAL}, + {"floor(x)", 0, "Partie entiere de x", "pi", 0, CAT_CATEGORY_REAL}, + {"fonction f(x)", "fonction", "Definition de fonction (Xcas). Par exemple\nfonction f(x)\n local y;\ny:=x*x;\nreturn y;\nffonction", 0, 0, CAT_CATEGORY_PROG | XCAS_ONLY}, + {"frenet([x(t),y(t)],t,t0)", 0, "Courbure, centre de courbure et repere de Frenet de la courbe parametree [x(t),y(t)] en t0", "[t,t^2],t,1", "[t,t^2],t", CAT_CATEGORY_CALCULUS | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, +#ifndef NUMWORKS_SLOTB + {"from arit import *", "from arit import *", "Instruction pour utiliser les fonctions d'arithmetique entiere en Python", "#from arit import *", "#import arit", CAT_CATEGORY_ARIT}, + {"from cas import *", "from cas import *", "Permet d'utiliser le calcul formel depuis Python", "#from cas import *", "#import cas", CAT_CATEGORY_ALGEBRA|(CAT_CATEGORY_CALCULUS<<8)}, + {"from cmath import *", "from cmath import *", "Instruction pour utiliser les fonctions de maths sur les complexes (trigo, exponentielle, log, ...) en Python", "#from cmath import *;i=1j", "#import cmath", CAT_CATEGORY_COMPLEXNUM}, + {"from linalg import *", "from linalg import *", "Instruction pour utiliser les fonctions d'algebre lineaire en Python", "#from linalg import *;i=1j", "#import linalg", CAT_CATEGORY_LINALG | (CAT_CATEGORY_MATRIX<<8) | (CAT_CATEGORY_POLYNOMIAL<<16)}, + {"from numpy import *", "from numpy import *", "Instruction pour utiliser les fonctions sur les matrice en Python", "#from numpy import *;i=1j", "#import numpy", CAT_CATEGORY_LINALG | (CAT_CATEGORY_MATRIX <<8) | (CAT_CATEGORY_COMPLEXNUM << 16)}, + {"from math import *", "from math import *", "Instruction pour utiliser les fonctions de maths (trigo, exponentielle, log, ...) en Python", "#from math import *", "#import math", CAT_CATEGORY_REAL}, + {"from matplotl import *", "from matplotl import *", "Instruction pour utiliser les fonctions de trace en Python", "#from matplotl import *", "#import matplotl", CAT_CATEGORY_PROBA|(CAT_CATEGORY_PLOT <<8)|(CAT_CATEGORY_STATS<<16)}, + {"from random import *", "from random import *", "Instruction pour utiliser les fonctions aleatoires en Python", "#from random import *", "#import random", CAT_CATEGORY_PROBA}, + {"from turtle import *", "from turtle import *", "Instruction pour utiliser la tortue en Python", "#from turtle import *", "#import turtle", CAT_CATEGORY_LOGO}, +#endif + {"fsolve(equation,x=a[..b])", 0, "Resolution approchee de equation pour x dans l'intervalle a..b ou en partant de x=a.","cos(x)=x,x=0..1", "cos(x)-x,x=0.0", CAT_CATEGORY_SOLVE | XCAS_ONLY}, + {"gauss(q)", 0, "Reduction de Gauss d'une forme quadratique q", "x^2+x*y+x*z,[x,y,z]", "x^2+4*x*y,[]", CAT_CATEGORY_LINALG | XCAS_ONLY }, + {"gcd(a,b,...)", 0, "Plus grand commun diviseur. En Python ne fonctionne qu'avec des entiers. Voir iegcd ou egcd pour Bezout.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8)}, + {"gl_x", "gl_x", "Reglage graphique X gl_x=xmin..xmax", "#gl_x=0..2", 0, CAT_CATEGORY_PROGCMD << 8 | XCAS_ONLY}, + {"gl_y", "gl_y", "Reglage graphique Y gl_y=ymin..ymax", "#gl_y=-1..1", 0, CAT_CATEGORY_PROGCMD << 8 | XCAS_ONLY}, + {"green", "green", "Option d'affichage", "#display=green", 0, CAT_CATEGORY_PROGCMD}, + {"halftan(expr)", 0, "Exprime cos, sin, tan avec tan(angle/2).","cos(x)", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"hauteur(A,B,C)", 0, "Hauteur du triangle ABC issue de A", "1,i,2+i", 0,CAT_CATEGORY_2D}, + {"hermite(n)", 0, "n-ieme polynome de Hermite", "10", "10,t", CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"hilbert(n)", 0, "Matrice de Hilbert de taille n.", "4", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"histogram(list,min,size)", 0, "Histogramme d'une liste de donneees, classes commencant a min de taille size.","ranv(100,uniformd,0,1),0,0.1", 0, CAT_CATEGORY_STATS | (CAT_CATEGORY_PLOT<<8)}, + {"homothetie(centre,rapport,objet)", 0, "Image de l'objet par homothetie de rapport", "0,2,circle(1,1)", 0, CAT_CATEGORY_2D }, + {"hyperbole(F1,F2,M)", 0, "Hyperbole donnee par 2 foyers et un point", "-2-i,2+i,1", 0, CAT_CATEGORY_2D}, + {"iabcuv(a,b,c)", 0, "Cherche 2 entiers u,v tels que a*u+b*v=c","23,13,15", 0, CAT_CATEGORY_ARIT | XCAS_ONLY}, + {"ichinrem([a,m],[b,n])", 0,"Restes chinois entiers de a mod m et b mod n.", "[3,13],[2,7]", 0, CAT_CATEGORY_ARIT | XCAS_ONLY}, + {"icosahedron(A,B,C)", 0, "Icosaedre de centre A, de sommet B oรน le plan ABC contient le sommet le plus proche (parmi les 5) de B", "[0,0,0],[sqrt(5),0,0],[1,2,0]", 0, CAT_CATEGORY_3D}, + {"idivis(n)", 0, "Liste des diviseurs d'un entier n.", "10", 0, CAT_CATEGORY_ARIT}, + {"idn(n)", 0, "matrice identite n * n", "4", 0, CAT_CATEGORY_MATRIX}, + {"iegcd(a,b)", 0, "Determine les entiers u,v,d tels que a*u+b*v=d=gcd(a,b)","23,13", 0, CAT_CATEGORY_ARIT}, + {"ifactor(n)", 0, "Factorisation d'un entier (pas trop grand!). Raccourci n=>*", "1234", 0, CAT_CATEGORY_ARIT}, + {"ilaplace(f,s,x)", 0, "Transformee inverse de Laplace de f", "s/(s^2+1),s,x", 0, CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"im(z)", 0, "Partie imaginaire (z.im en Python)", "1+i", 0, CAT_CATEGORY_COMPLEXNUM}, + {"inscrit(A,B,C)", 0, "Cercle inscrit", "-1,2+i,3", 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"inf", "inf", "Plus l'infini. Utiliser -inf pour moins l'infini ou infinity pour l'infini complexe. Raccourci shift INS.", "-inf", "infinity", CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"input()", "input()", "Lire une chaine au clavier", "\"Valeur ?\"", 0, CAT_CATEGORY_PROG}, + {"integrate(f,x,[,a,b])", 0, "Primitive de f par rapport a la variable x, par ex. integrate(x*sin(x),x). Pour calculer une integrale definie, entrer les arguments optionnels a et b, par ex. integrate(x*sin(x),x,0,pi). Pour une integrale curviligne, integrate([champ_x,champ_y],[x,y],courbe,tmin,tmax), par ex. aire ellipse G:=plotparam([2*cos(t),sin(t)],t):; integrate([0,x],[x,y],G,0,2*pi). Raccourci SHIFT F3.", "x*sin(x),x", "cos(x)/(1+x^4),x,0,inf", CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"interp(X,Y[,interp])", 0, "Interpolation de Lagrange aux points (xi,yi) avec X la liste des xi et Y des yi. Renvoie la liste des differences divisees si interp est passe en parametre.", "[1,2,3,4,5],[0,1,3,4,4]", "[1,2,3,4,5],[0,1,3,4,4],interp", CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"inter(A,B)", 0, "Liste des intersections. Utiliser single_inter si l'intersection est unique.", "line(y=x),circle(0,1)", 0, CAT_CATEGORY_3D | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"inter_unique(A,B)", 0, "Premiere intersection. Utiliser inter pour une liste d'intersections.", "line(y=x),line(x+y=3)", 0, CAT_CATEGORY_3D | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"inv(A)", 0, "Inverse de A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX|(CAT_CATEGORY_LINALG<<8)}, + {"inverser(v)", "inverser ", "La variable v est remplacee par son inverse", "#v:=3; inverser v", 0, CAT_CATEGORY_SOFUS | XCAS_ONLY}, + {"iquo(a,b)", 0, "Quotient euclidien de deux entiers.", "23,13", 0, CAT_CATEGORY_ARIT | XCAS_ONLY}, + {"irem(a,b)", 0,"Reste euclidien de deux entiers", "23,13", 0, CAT_CATEGORY_ARIT | XCAS_ONLY}, + {"isprime(n)", 0, "Renvoie 1 si n est premier, 0 sinon.", "11", "10", CAT_CATEGORY_ARIT}, + {"is_collinear(A,B,C)", 0, "Renvoie 1 ou 2 si A, B, C sont alignes, 0 sinon.", "1,i,-1", "i,0,-i", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_concyclic(A,B,C,D)", 0, "Renvoie 1 si A, B, C, D sont cocyliques, 0 sinon.", "1,i,-1,-i", "1,i,0,-i", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_element(A,G)", 0, "Renvoie 1 si A appartient a G, 0 sinon.", "point(0),circle(0,1)", "point(i),square(0,1)", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_parallel(D,E)", 0, "Renvoie 1 si D et E sont paralleles, 0 sinon.", "line(y=x),line(y=-x)", "line(y=x),line(y=x+1)", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_perpendicular(D,E)", 0, "Renvoie 1 si D et E sont perpendiculaires, 0 sinon.", "line(y=x),line(y=-x)", "line(y=x),line(y=x+1)", CAT_CATEGORY_2D | XCAS_ONLY }, + {"jordan(A)", 0, "Forme normale de Jordan de la matrice A, renvoie P et D tels que P^-1*A*P=D", "[[1,2],[3,4]]", "[[1,1,-1,2,-1],[2,0,1,-4,-1],[0,1,1,1,1],[0,1,2,0,1],[0,0,-3,3,-1]]", CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"laguerre(n,a,x)", 0, "n-ieme polynome de Laguerre (a=0 par defaut).", "10", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"laplace(f,x,s)", 0, "Transformee de Laplace de f","sin(x),x,s", 0, CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"lcm(a,b,...)", 0, "Plus petit commun multiple.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8) | XCAS_ONLY}, + {"lcoeff(p,x)", 0, "Coefficient dominant du polynome p.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"legendre(n)", 0, "n-ieme polynome de Legendre.", "10", "10,t", CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, +#ifdef RELEASE + {"len(l)", 0, "Taille d'une liste.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_LIST}, +#endif + {"leve_crayon ", "leve_crayon ", "La tortue se deplace sans marquer son passage", 0, 0, CAT_CATEGORY_LOGO}, + {"limit(f,x=a)", 0, "Limite de f en x = a. Ajouter 1 ou -1 pour une limite a droite ou a gauche, limit(sin(x)/x,x=0) ou limit(abs(x)/x,x=0,1). Raccourci: SHIFT MIXEDFRAC", "sin(x)/x,x=0", "exp(-1/x),x=0,1", CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"droite(A,B)", 0, "Droite donnee par equation ou 2 points", "y=x-1", "[0,0,0],[1,-2,3]", CAT_CATEGORY_2D | XCAS_ONLY}, + {"line_width_", "line_width_", "Prefixe d'epaisseur (2 a 8)", 0, 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"linear_regression(Xlist,Ylist)", 0, "Regression lineaire.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"linear_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression lineaire.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];linear_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS | (CAT_CATEGORY_PLOT<<8)}, + {"linetan(expr,x,x0)", 0, "Tangente au graphe en x=x0.", "sin(x),x,pi/2", 0, CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"linsolve([eq1,eq2,..],[x,y,..])", 0, "Resolution de systeme lineaire. Peut utiliser le resultat de lu pour resolution en O(n^2).","[x+y=1,x-y=2],[x,y]", "#p,l,u:=lu([[1,2],[3,4]]); linsolve(p,l,u,[5,6])", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_LINALG <<8) | (CAT_CATEGORY_MATRIX << 16) | XCAS_ONLY}, + {"logarithmic_regression(Xlist,Ylist)", 0, "Regression logarithmique.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + //{"logarithmic_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression logarithmique.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];logarithmic_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"lu(A)", 0, "decomposition LU de la matrice A, P*A=L*U, renvoie P permutation, L et U triangulaires inferieure et superieure", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"magenta", "magenta", "Option d'affichage", "#display=magenta", 0, CAT_CATEGORY_PROGCMD}, + {"map(f,l)", 0, "Applique f aux elements de la liste l.","lambda x:x*x,[1,2,3]", 0, CAT_CATEGORY_LIST}, + {"matpow(A,n)", 0, "Renvoie A^n, la matrice A la puissance n", "[[1,2],[3,4]],n","#assume(n>=1);matpow([[0,2],[0,4]],n)", CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"matrix(l,c,func)", 0, "Matrice de terme general donne.", "2,3,(j,k)->j^k", 0, CAT_CATEGORY_MATRIX}, + {"mean(l)", 0, "Moyenne arithmetique liste l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"median(l)", 0, "Mediane", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"mediane(A,B,C)", 0, "Mediane du triangle ABC issue de A", "1,i,2+i", 0,CAT_CATEGORY_2D}, + {"mediatrice(A,B)", 0, "Mediatrice du segment AB", "1,i", 0,CAT_CATEGORY_2D}, + {"milieu(A,B)", 0, "Milieu de AB", "1,i", 0,CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8)}, + {"montre_tortue ", "montre_tortue ", "Affiche la tortue", 0, 0, CAT_CATEGORY_LOGO}, + {"mul(A,B)", 0, "En Python, multiplie des listes de listes u et v comme des matrices.","[[1,2],[3,4]],[5,6]", "[[1,2],[3,4]].[[5,6],[7,8]]", CAT_CATEGORY_LINALG}, + {"mult_c_conjugate", 0, "Multiplier par le conjugue complexe.", "1+2*i", 0, (CAT_CATEGORY_COMPLEXNUM << 8) | XCAS_ONLY}, + {"mult_conjugate", 0, "Multiplier par le conjugue (sqrt).", "sqrt(2)-sqrt(3)", 0, CAT_CATEGORY_ALGEBRA | XCAS_ONLY}, + {"normald([mu,sigma],x)", 0, "Loi normale, par defaut mu=0 et sigma=1. normald_cdf([mu,sigma],x) probabilite que \"loi normale <=x\" par ex. normald_cdf(1.96). normald_icdf([mu,sigma],t) renvoie x tel que \"loi normale <=x\" vaut t, par ex. normald_icdf(0.975) ", "1.2", 0, CAT_CATEGORY_PROBA | XCAS_ONLY}, + {"not(x)", 0, "Non logique.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"numer(x)", 0, "Numerateur de x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"octahedron(A,B,C)", 0, "Octaedre d'arete AB avec une face dans le plan ABC", "[0,0,0],[3,0,0],[0,1,0]", 0, CAT_CATEGORY_3D}, + {"odesolve(f(t,y),[t,y],[t0,y0],t1)", 0, "Solution approchee d'equation differentielle y'=f(t,y) et y(t0)=y0, valeur en t1 (ajouter curve pour les valeurs intermediaires de y)", "sin(t*y),[t,y],[0,1],2", "0..pi,(t,v)->{[-v[1],v[0]]},[0,1]", CAT_CATEGORY_SOLVE | XCAS_ONLY}, + {"osculating_circle([x(t),y(t)],t,t0)", 0, "Cercle osculateur de la courbe parametree [x(t),y(t)] en t0", "[t,t^2],t,1", "[t,t^2],t", CAT_CATEGORY_CALCULUS | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"parabole(F,A)", 0, "Parabole donnee par foyer et sommet", "-2-i,2+i", 0, CAT_CATEGORY_2D}, + {"parameq(objet)", 0, "Equations parametriques. Utiliser equation pour une equation cartesienne", "circle(0,1)", "ellipse(-1,1,3)", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"partfrac(p,x)", 0, "Decomposition en elements simples. Raccourci p=>+", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA | XCAS_ONLY}, + {"pas_de_cote n", "pas_de_cote ", "Saut lateral de la tortue, par defaut n=10", "#pas_de_cote 30", 0, CAT_CATEGORY_LOGO}, + {"plan(equation)", 0, "Plan donne par equation ou 3 points", "z=x+y-1", "[0,0,0],[1,0,0],[0,1,0]", CAT_CATEGORY_3D | XCAS_ONLY}, + {"plot(expr,x)", 0, "Xcas: graphe de fonction, par exemple plot(sin(x)), plot(ln(x),x.0,5), plot(x^2-y^2), plot(x^2-y^2<1), plot(x^2-y^2=1). Python et Xcas: plot(Xlist,Ylist) ligne polygonale", "[1,2,3,4,5,6],[2,3,5,2,1,4]","ln(x),x=0..5,xstep=0.1", CAT_CATEGORY_PLOT }, + {"plotfunc(expr,[x,y])", 0, "Xcas: graphe de fonction 3d", "x^2-y^2,[x,y]","x^2-y^2,[x=-2..2,y=-2..2],nstep=700", CAT_CATEGORY_PLOT | (CAT_CATEGORY_3D << 8) | XCAS_ONLY }, + {"plotarea(expr,x=a..b,[n,meth])", 0, "Aire sous la courbe selon une methode d'integration.", "1/x,x=1..5,4,rectangle_gauche", 0, CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plotcontour(expr,[x=xm..xM,y=ym..yM],niveaux)", 0, "Lignes de niveau de expr.", "x^2+2y^2, [x=-2..2,y=-2..2],[1,2]", 0, CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plotdensity(expr,[x=xm..xM,y=ym..yM])", 0, "Representation en niveaux de couleurs d'une expression de 2 variables.", "x^2-y^2,[x=-3..3,y=-2..2]", 0, CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plotfield(f(t,y), [t=tmin..tmax,y=ymin..ymax])", 0, "Champ des tangentes de y'=f(t,y), optionnellement graphe avec plotode=[t0,y0]", "sin(t*y), [t=-3..3,y=-3..3],plotode=[0,1]", "5*[-y,x], [x=-1..1,y=-1..1]", CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plotlist(list)", 0, "Graphe d'une liste", "[3/2,2,1,1/2,3,2,3/2]", "[1,13],[2,10],[3,15],[4,16]", CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plotode(f(t,y), [t=tmin..tmax,y],[t0,y0])", 0, "Graphe de solution d'equation differentielle y'=f(t,y), y(t0)=y0.", "sin(t*y),[t=-3..3,y],[0,1]", 0, CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plotparam([x,y],t)", 0, "Graphe en parametriques. Par exemple plotparam([sin(3t),cos(2t)],t,0,pi) ou plotparam(exp(i*t),t,0,pi)", "[sin(3t),cos(2t)],t,0,pi", "[t^2,t^3],t=-1..1,tstep=0.1", CAT_CATEGORY_PLOT | (CAT_CATEGORY_3D << 8) | XCAS_ONLY}, + {"plotpolar(r,theta)", 0, "Graphe en polaire.","cos(3*x),x,0,pi", "1/(1+cos(x)),x=0..pi,tstep=0.05", CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plotseq(f(x),x=[u0,m,M],n)", 0, "Trace f(x) sur [m,M] et n termes de la suite recurrente u_{n+1}=f(u_n) de 1er terme u0.","sqrt(2+x),x=[6,0,7],5", 0, CAT_CATEGORY_PLOT | XCAS_ONLY}, + {"plus_point", "plus_point", "Option d'affichage", "#display=blue+plus_point", 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"point(x,y[,z])", 0, "Point", "1,2", "1,2,3", CAT_CATEGORY_PLOT | (CAT_CATEGORY_2D << 8) | (CAT_CATEGORY_3D << 16) | XCAS_ONLY}, + {"polygone(list)", 0, "Polygone ferme donne par la liste de ses sommets.", "1-i,2+i,3,3-2i", 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"polygonscatterplot(Xlist,Ylist)", 0, "Nuage de points relies.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"polyhedron(A,B,C,D,...)", 0, "Polyedre convexe dont les sommets sont parmi A,B,C,D,...", "[0,0,0],[0,5,0],[0,0,5],[1,2,6]", 0, CAT_CATEGORY_3D}, +#ifdef QRHELP + {"polynomial_regression(Xlist,Ylist,n)", 0, "Regression polynomiale de degre <= n.", "[1,2,3,4,5],[0,1,3,4,4],2", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"polynomial_regression_plot(Xlist,Ylist,n)", 0, "Graphe d'une regression polynomiale de degre <= n.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y);", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"pour (boucle Xcas)", "pour de to faire fpour;", "Boucle definie.","#pour j de 1 to 10 faire print(j,j^2); fpour;", 0, CAT_CATEGORY_PROG | XCAS_ONLY}, + {"power_regression(Xlist,Ylist,n)", 0, "Regression puissance.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"power_regression_plot(Xlist,Ylist,n)", 0, "Graphe d'une regression puissance.", "#X,Y:=[1,2,3,4,5],[1,1,3,4,4];power_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, +#endif + {"pow(a,n,p)", 0, "Renvoie a^n mod p","123,456,789", 0, CAT_CATEGORY_ARIT}, + {"powmod(a,n,p[,P,x])", 0, "Renvoie a^n mod p, ou a^n mod un entier p et un polynome P en x.","123,456,789", "x+1,452,19,x^4+x+1,x", CAT_CATEGORY_ARIT | XCAS_ONLY}, + {"print(expr)", 0, "Afficher dans la console", 0, 0, CAT_CATEGORY_PROG}, + {"projection(obj1,obj2)", 0, "Projection sur obj1 de obj2", "line(y=x),point(2,3)", 0, CAT_CATEGORY_2D }, + {"pcoeff(p)", 0, "Polynome unitaire dont on donne la liste des racines (fonction reciproque de proot)", "[1,2,3]", 0, CAT_CATEGORY_POLYNOMIAL}, + {"peval(p,x)", 0, "Valeur d'un polynome en un point", "[1,2,3],4", 0, CAT_CATEGORY_POLYNOMIAL}, + {"proot(p)", 0, "Racines reelles et complexes approchees d'un polynome. Exemple proot([1,2.1,3,4.2]) ou proot(x^3+2.1*x^2+3x+4.2)", "[1.,2.1,3,4.2]","x^3+2.1*x^2+3x+4.2", CAT_CATEGORY_POLYNOMIAL|(CAT_CATEGORY_SOLVE<<8)}, + {"purge(x)", 0, "Purge le contenu de la variable x. Raccourci SHIFT-FORMAT", 0, 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_SOFUS<<8) | XCAS_ONLY}, + {"pyramid(A,B,C)", 0, "Tetraedre d'arete AB avec une face dans le plan ABC", "[0,0,0],[3,0,0],[0,1,0]", "[0,0,0],[3,0,0],[0,3,0],[0,0,4]", CAT_CATEGORY_3D}, + {"python(f)", 0, "Affiche la fonction f en syntaxe Python.", 0, 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"python_compat(0|1|2|4)", 0, "python_compat(0) syntaxe Xcas, python_compat(1) syntaxe Python avec ^ interprete comme puissance, python_compat(2) ^ interprete comme ou exclusif bit a bit", "0", "1", CAT_CATEGORY_PROG | XCAS_ONLY}, + {"qr(A)", 0, "Factorisation A=Q*R avec Q orthogonale et R triangulaire superieure", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"quadric(equation)", 0, "Quadrique donnee par une equation (ou 9 points)", "x^2-y^2+z^2", "x^2+x*y+y^2+z^2-3", CAT_CATEGORY_3D}, + {"quartile1(l)", 0, "1er quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"quartile3(l)", 0, "3eme quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"quo(p,q,x)", 0, "Quotient de division euclidienne polynomiale en x.", 0, 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"quote(x)", 0, "Renvoie l'expression x non evaluee.", 0, 0, CAT_CATEGORY_ALGEBRA | XCAS_ONLY}, + {"rayon(objet)", 0, "Rayon d'un cercle ou d'une sphere", "circle(0,1)", "sphere([0,0,0],[1,1,1])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"rand()", "rand()", "Reel aleatoire entre 0 et 1", 0, 0, CAT_CATEGORY_PROBA}, + {"randint(a,b)", 0, "Entier aleatoire entre a et b. En Xcas, avec un seul argument n, entier entre 1 et n.", "5,20", "6", CAT_CATEGORY_PROBA}, + {"ranm(n,m,[loi,parametres])", 0, "Matrice aleatoire a coefficients entiers ou selon une loi de probabilites (ranv pour un vecteur). Exemples ranm(2,3), ranm(3,2,binomial,20,.3), ranm(4,2,normald,0,1)", "3,3","4,2,normald,0,1", CAT_CATEGORY_MATRIX}, + {"ranv(n,[loi,parametres])", 0, "Vecteur aleatoire", "4,normald,0,1", "10,30", CAT_CATEGORY_LINALG}, + {"ratnormal(x)", 0, "Ecrit sous forme d'une fraction irreductible.", "(x+1)/(x^2-1)^2", 0, CAT_CATEGORY_ALGEBRA | XCAS_ONLY}, + {"re(z)", 0, "Partie reelle (z.re en Python)", "1+i", 0, CAT_CATEGORY_COMPLEXNUM}, +#ifndef NUMWORKS + {"read(\"filename\")", "read(\"", "Lire un fichier. Voir aussi write", 0, 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, +#endif + {"rectangle_plein a,b", "rectangle_plein ", "Rectangle direct rempli depuis la tortue de cotes a et b (si b est omis, la tortue remplit un carre)", "#rectangle_plein 30", "#rectangle_plein(20,40)", CAT_CATEGORY_LOGO | XCAS_ONLY}, + {"recule n", "recule ", "La tortue recule de n pas, par defaut n=10", "#recule 30", 0, CAT_CATEGORY_LOGO}, + {"red", "red", "Option d'affichage", "#display=red", 0, CAT_CATEGORY_PROGCMD}, + {"reflection(obj1,obj2)", 0, "Symetrique de obj2", "line(y=x),cercle(1,1)", 0, CAT_CATEGORY_2D }, + {"rem(p,q,x)", 0, "Reste de division euclidienne polynomiale en x", 0, 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"repete(n,...)", "repete( ", "Repete plusieurs fois les instructions", "#repete(4,avance,tourne_gauche)", 0, CAT_CATEGORY_LOGO | XCAS_ONLY}, +#ifdef RELEASE + {"residue(f(z),z,z0)", 0, "Residu de l'expression en z0.", "1/(x^2+1),x,i", 0, CAT_CATEGORY_COMPLEXNUM | XCAS_ONLY}, +#endif + {"resultant(p,q,x)", 0, "Resultant en x des polynomes p et q.", "#P:=x^3+p*x+q;resultant(P,P',x);", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"revert(p[,x])", 0, "Developpement de Taylor reciproque, p doit etre nul en 0","x+x^2+x^4", 0, CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"rgb(r,g,b)", 0, "couleur definie par niveau de rouge, vert, bleu entre 0 et 255", "255,0,255", 0, CAT_CATEGORY_PROGCMD}, + {"rhombus_point", "rhombus_point", "Option d'affichage", "#display=magenta+rhombus_point", 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"rond n", "rond ", "Cercle tangent a la tortue de rayon n. Utiliser rond n,theta pour un arc de cercle.", "#rond 30", "#rond(30,90)", CAT_CATEGORY_LOGO}, + {"rotation(centre,angle,objet)", 0, "Image de l'objet par la rotation de centre et angle donnes en argyment", "2-i,pi/2,circle(0,1)", "sphere([0,0,0],[1,1,1])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"rref(M)","rref","Reduction d'une matrice par le pivot de Gauss.","[[1,2,3],[4,5,6]]",0,CAT_CATEGORY_MATRIX|(CAT_CATEGORY_LINALG<<8)}, + {"rsolve(equation,u(n),[init])", 0, "Expression d'une suite donnee par une recurrence.","u(n+1)=2*u(n)+3,u(n),u(0)=1", "([u(n+1)=3*v(n)+u(n),v(n+1)=v(n)+u(n)],[u(n),v(n)],[u(0)=1,v(0)=2]", CAT_CATEGORY_SOLVE | XCAS_ONLY}, + {"saute n", "saute ", "La tortue fait un saut de n pas, par defaut n=10", "#saute 30", 0, CAT_CATEGORY_LOGO}, + {"scatterplot(Xlist,Ylist)", 0, "Nuage de points (scatter en Python)", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS| (CAT_CATEGORY_PLOT<<8)}, + {"segment(A,B)", 0, "Segment", "1,2+i", "[1,2,1],[-1,3,2]", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"seq(expr,var,a,b[,pas])", 0, "Liste de terme general donne.","j^2,j,1,10", "j^2,j,1,10,2", CAT_CATEGORY_LIST | XCAS_ONLY}, + {"si (test Xcas)", "si alors sinon fsi;", "Test.", "#f(x):=si x>0 alors x; sinon -x; fsi;", 0, CAT_CATEGORY_PROG | XCAS_ONLY}, + {"sign(x)", 0, "Renvoie -1 si x est negatif, 0 si x est nul et 1 si x est positif.", 0, 0, CAT_CATEGORY_REAL | XCAS_ONLY}, + {"similitude(centre,rapport,angle,objet)", 0, "Image de l'objet par similitude", "0,2,pi/2,circle(1,1)", 0, CAT_CATEGORY_2D }, + {"simplify(expr)", 0, "Renvoie en general expr sous forme simplifiee. Raccourci expr=>/", "sin(3x)/sin(x)", "ln(4)-ln(2)", CAT_CATEGORY_ALGEBRA | XCAS_ONLY}, + {"sin_regression(Xlist,Ylist)", 0, "Regression trigonometrique.", "[1,2,3,4,5,6,7,8,9,10,11,12,13,14],[0.1,0.5,0.8,1,0.7,0.5,0.05,-.5,-.75,-1,-.7,-.4,0.1,.5]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, +#ifdef QRHELP + {"sin_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression trigonometrique.", "#X,Y:=[1,2,3,4,5,6,7,8,9,10,11,12,13,14],[0.1,0.5,0.8,1,0.7,0.5,0.05,-.5,-.75,-1,-.7,-.4,0.1,.5];sin_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, +#endif + {"solve()", 0, "Xcas: solve(equation,x) resolution exacte d'une equation en x (ou d'un systeme polynomial). Utiliser csolve pour les solutions complexes, linsolve pour un systeme lineaire. Python et Xcas: solve(A,b) resolution d'un systeme de Cramer A*x=b", "x^2-x-1=0,x", "[x^2-y^2=0,x^2-z^2=0],[x,y,z]", CAT_CATEGORY_SOLVE}, + {"sommets(objet)", 0, "Liste des sommets d'un polygone ou polyedre", "triangle(1,i,2)", "cube([0,0,0],[1,0,0],[0,1,0])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"sorted(l)", 0, "Trie une liste.","[3/2,2,1,1/2,3,2,3/2]", "[[1,2],[2,3],[4,3]],(x,y)->when(x[1]==y[1],x[0]>y[0],x[1]>y[1]", CAT_CATEGORY_LIST}, + {"sphere(A,r)", 0, "Sphere de centre A et rayon r ou de diametre AB", "[0,0,0],1", "[0,0,0],[1,1,1]", CAT_CATEGORY_3D}, + {"square_point", "square_point", "Option d'affichage", "#display=cyan+square_point", 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY }, + {"star_point", "star_point", "Option d'affichage", "#display=magenta+star_point", 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"stddev(l)", 0, "Ecart-type d'une liste l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS | XCAS_ONLY}, + {"sub(u,v)", 0, "En Python, soustrait des listes ou listes de listes u et v comme des vecteurs ou matrices.","[1,2,3],[0,1,3]", "[[1,2]],[[3,4]]", CAT_CATEGORY_LINALG}, + {"subst(a,b=c)", 0, "Remplace b par c dans a. Raccourci a(b=c). Pour faire plusieurs remplacements, saisir subst(expr,[b1,b2...],[c1,c2...])", "x^2,x=3", "x+y^2,[x,y],[1,2]", CAT_CATEGORY_ALGEBRA | XCAS_ONLY}, + {"sum(f,k,m,M)", 0, "Somme de l'expression f dependant de k pour k variant de m a M. Exemple sum(k^2,k,1,n)=>*. Raccourci ALPHA F3", "k,k,1,n", "k^2,k", CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"svd(A)", 0, "Singular Value Decomposition, renvoie U orthogonale, S vecteur des valeurs singuliรจres, Q orthogonale tels que A=U*diag(S)*tran(Q).", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX | XCAS_ONLY}, + {"tabvar(f,[x=a..b])", 0, "Tableau de variations de l'expression f, avec arguments optionnels la variable x dans l'intervalle a..b.", "sqrt(x^2+x+1)", "[cos(2t),sin(3t)],t", CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"tantque (boucle Xcas)", "tantque faire ftantque;", "Boucle indefinie.", "#j:=13; tantque j!=1 faire j:=ifte(even(j),j/2,3j+1); print(j); ftantque;", 0, CAT_CATEGORY_PROG | XCAS_ONLY}, + {"taylor(f,x=a,n,[polynom])", 0, "Developpement de Taylor de l'expression f en x=a a l'ordre n, ajouter le parametre polynom pour enlever le terme de reste.","sin(x),x=0,5", "sin(x),x=0,5,polynom", CAT_CATEGORY_CALCULUS | XCAS_ONLY}, + {"tchebyshev1(n)", 0, "Polynome de Tchebyshev de 1ere espece: cos(n*x)=T_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"tchebyshev2(n)", 0, "Polynome de Tchebyshev de 2eme espece: sin((n+1)*x)=sin(x)*U_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"tcollect(expr)", 0, "Linearisation trigonometrique et regroupement.","sin(x)+cos(x)", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"texpand(expr)", 0, "Developpe les fonctions trigonometriques, exp et ln.","sin(3x)", "ln(x*y)", CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"time(cmd)", 0, "Temps pour effectuer une commande ou mise a l'heure de horloge","int(1/(x^4+1),x)","8,0", CAT_CATEGORY_PROG}, + {"tlin(expr)", 0, "Linearisation trigonometrique de l'expression.","sin(x)^3", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"tourne_droite n", "tourne_droite ", "La tortue tourne de n degres, par defaut n=90", "#tourne_droite 45", 0, CAT_CATEGORY_LOGO}, + {"tourne_gauche n", "tourne_gauche ", "La tortue tourne de n degres, par defaut n=90", "#tourne_gauche 45", 0, CAT_CATEGORY_LOGO}, + {"trace(A)", 0, "Trace de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"transpose(A)", 0, "Transposee de la matrice A. Pour la transconjuguee utiliser trn(A) ou A^*.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"translation(vect,obj)", 0, "Translation par vect de obj", "[1,2],cercle(0,1)", 0, CAT_CATEGORY_2D }, + {"triangle(A,B,C)", 0, "Triangle donne par 3 sommets", "1+i,1-i,-1", "A,B,C", CAT_CATEGORY_2D}, + {"triangle_point", "triangle_point", "Option d'affichage", "#display=yellow+triangle_point", 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, + {"trig2exp(expr)", 0, "Convertit les fonctions trigonometriques en exponentielles.","cos(x)^3", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"trigcos(expr)", 0, "Exprime sin^2 et tan^2 avec cos^2.","sin(x)^4", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"trigsin(expr)", 0, "Exprime cos^2 et tan^2 avec sin^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"trigtan(expr)", 0, "Exprime cos^2 et sin^2 avec tan^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG | XCAS_ONLY}, + {"uniformd(a,b,x)", 0, "loi uniforme sur [a,b] de densite 1/(b-a)", 0, 0, CAT_CATEGORY_PROBA | XCAS_ONLY}, + {"v augmente_de n", " augmente_de ", "La variable v augmente de n, ou de n %", "#v:=3; v augmente_de 1", 0, CAT_CATEGORY_SOFUS | XCAS_ONLY}, + {"v diminue_de n", " diminue_de ", "La variable v diminue de n, ou de n %", "#v:=3; v diminue_de 1", 0, CAT_CATEGORY_SOFUS | XCAS_ONLY}, + {"v est_divise_par n", " est_divise_par ", "La variable v est divisee par n", "#v:=3; v est_divise_par 2", 0, CAT_CATEGORY_SOFUS | XCAS_ONLY}, + {"v est_eleve_puissance n", " est_eleve_puissance ", "La variable v est eleveee a la puissance n", "#v:=3; v est_eleve_puissance 2", 0, CAT_CATEGORY_SOFUS | XCAS_ONLY}, + {"v est_multiplie_par n", " est_multiplie_par ", "La variable v est multipliee par n", "#v:=3; v est_multiplie_par 2", 0, CAT_CATEGORY_SOFUS | XCAS_ONLY}, + {"vector(A,B)", 0, "vecteur AB", 0, 0, CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8)}, + {"volume(P)", 0, "volume d'un polyedre ou d'une sphere", 0, 0, (CAT_CATEGORY_3D )}, + //{"version", "version()", "Khicas 1.5.0, (c) B. Parisse et al. www-fourier.ujf-grenoble.fr/~parisse. License GPL version 2. Interface adaptee d'Eigenmath pour Casio, G. Maia, http://gbl08ma.com", 0, 0, CAT_CATEGORY_PROGCMD}, +#ifndef NUMWORKS + {"write(\"filename\",var)", "write(\"", "Sauvegarde une ou plusieurs variables dans un fichier. Par exemple f(x):=x^2; write(\"func_f\",f).", 0, 0, CAT_CATEGORY_PROGCMD | XCAS_ONLY}, +#endif + {"yellow", "yellow", "Option d'affichage", "#display=yellow", 0, CAT_CATEGORY_PROGCMD}, + {"|", "|", "Ou logique", "#1|2", 0, CAT_CATEGORY_PROGCMD}, + {"~", "~", "Complement", "#~7", 0, CAT_CATEGORY_PROGCMD}, + }; + +const catalogFunc completeCaten[] = { // list of all functions (including some not in any category) + {" loop for", "for ", "Defined loop.", "#\nfor ", 0, CAT_CATEGORY_PROG}, + {" loop in list", "for in", "Loop on all elements of a list.", "#\nfor in", 0, CAT_CATEGORY_PROG}, + {" loop while", "while ", "Undefined loop.", "#\nwhile ", 0, CAT_CATEGORY_PROG}, + {" test if", "if ", "Test", "#\nif ", 0, CAT_CATEGORY_PROG}, + {" test else", "else ", "Test false case", 0, 0, CAT_CATEGORY_PROG}, + {" function def", "f(x):=", "Definition of function.", "#\nf(x):=", 0, CAT_CATEGORY_PROG}, + {" local j,k;", "local ", "Local variables declaration (Xcas)", 0, 0, CAT_CATEGORY_PROG}, + {" range(a,b)", 0, "In range [a,b) (a included, b excluded)", "# in range(1,10)", 0, CAT_CATEGORY_PROG}, + {" return res", "return ", "Leaves current function and returns res.", 0, 0, CAT_CATEGORY_PROG}, + {" edit list ", "list ", "List creation wizzard.", 0, 0, CAT_CATEGORY_LIST}, + {" edit matrix ", "matrix ", "Matrix creation wizzard.", 0, 0, CAT_CATEGORY_MATRIX}, + {" mksa(x)", 0, "Conversion to MKSA units", 0, 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8) | XCAS_ONLY}, + {" ufactor(a,b)", 0, "Factorize unit b in a", "100_J,1_kW", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8) | XCAS_ONLY}, + {" usimplify(a)", 0, "Simplify unit", "100_l/10_cm^2", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8) | XCAS_ONLY}, + {"!", "!", "Logical not (prefix) or factorial of n (suffix).", "#7!", "~!b", CAT_CATEGORY_PROGCMD}, + {"#", "#", "Python comment, for Xcas comment type //. Shortcut ALPHA F2", 0, 0, CAT_CATEGORY_PROG}, + {"%", "%", "a % b means a modulo b", 0, 0, CAT_CATEGORY_ARIT | (CAT_CATEGORY_PROGCMD << 8)}, + {"&", "&", "Logical and or +", "#1&2", 0, CAT_CATEGORY_PROGCMD}, + {":=", ":=", "Set variable value. Shortcut SHIFT F1", "#a:=3", 0, CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)|XCAS_ONLY}, +#ifdef QRHELP + {"<", "<", "Shortcut SHIFT F2", 0, 0, CAT_CATEGORY_PROGCMD}, +#endif + {"=>", "=>", "Store value in variable or conversion (touche ->). For example 5=>a or x^4-1=>* or (x+1)^2=>+ or sin(x)^2=>cos.", "#5=>a", "#15_ft=>_cm", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_PHYS <<8) | (CAT_CATEGORY_UNIT << 16) | XCAS_ONLY}, +#ifdef QRHELP + {">", ">", "Shortcut F2.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"\\", "\\", "\\ char", 0, 0, CAT_CATEGORY_PROGCMD}, + {"_", "_", "_ char, shortcut (-).", 0, 0, CAT_CATEGORY_PROGCMD}, +#endif + {"_(km/h)", "_(km/h)", "Speed kilometer per hour", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_(m/s)", "_(m/s)", "Speed meter/second", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, +#ifdef QRHELP + {"_(m/s^2)", "_(m/s^2)", "Acceleration", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_(m^2/s)", "_(m^2/s)", "Viscosity", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, +#endif + {"_A", 0, "Ampere", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Bq", 0, "Becquerel", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_C", 0, "Coulomb", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Ci", 0, "Curie", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_F", 0, "Farad", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_F_", 0, "Faraday constant", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_G_", 0, "Gravitation force=_G_*m1*m2/r^2", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_H", 0, "Henry", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Hz", 0, "Hertz", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_J", 0, "Joule=kg*m^2/s^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_K", 0, "Temperature in Kelvin", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Kcal", 0, "Energy kilo-calorie", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_MeV", 0, "Energy mega-electron-Volt", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_N", 0, "Force Newton=kg*m/s^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_NA_", 0, "Avogadro constant", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_Ohm", 0, "Ohm", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_PSun_", 0, "Sun power", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_Pa", 0, "Pressure in Pascal=kg/m/s^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_REarth_", 0, "Earth radius", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_RSun_", 0, "Sun radius", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_R_", 0, "Boltzmann constant (per mol)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_S", 0, "", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_StdP_", 0, "Standard pressure", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_StdT_", 0, "Standard temperature (0 degre Celsius in Kelvins)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_Sv", 0, "Sievert", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_T", 0, "Tesla", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_V", 0, "Volt", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Vm_", 0, "Volume molaire", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_W", 0, "Watt=kg*m^2/s^3", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_Wb", 0, "Weber", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_alpha_", 0, "fine structure constant", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_c_", 0, "speed of light", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_cd", 0, "candela", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, +#ifndef NUMWORKS_SLOTB + {"_cdf", "_cdf", "Suffix to get a cumulative distribution function. Type F2 for inverse cumulative distribution function _icdf suffix.", "#_icdf", 0, CAT_CATEGORY_PROBA|XCAS_ONLY}, +#endif + {"_d", 0, "day", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_deg", 0, "degree", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_eV", 0, "electron-Volt", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_epsilon0_", 0, "vacuum permittivity", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_ft", 0, "feet", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_g_", 0, "Earth gravity (ground)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_grad", 0, "grades (angle unit(", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_h", 0, "Hour", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_h_", 0, "Planck constant", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_ha", 0, "hectare", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_hbar_", 0, "Planck constant/(2*pi)", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_inch", 0, "inches", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_kWh", 0, "kWh", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_k_", 0, "Boltzmann constant", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_kg", 0, "kilogram", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_l", 0, "liter", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_m", 0, "meter", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_mEarth_", 0, "Earth mass", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_m^2", 0, "Area in m^2", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_m^3", 0, "Volume in m^3", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_me_", 0, "electron mass", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_miUS", 0, "US miles", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_mn", 0, "minute", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_mp_", 0, "proton mass", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_mpme_", 0, "proton/electron mass-ratio", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_mu0_", 0, "", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_phi_", 0, "magnetic flux quantum", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, +#ifndef NUMWORKS_SLOTB + {"_plot", "_plot", "Suffix for a regression graph.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS}, +#endif + {"_qe_", 0, "electron charge", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_qme_", 0, "_q_/_me_", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_rad", 0, "radians", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_rem", 0, "rem", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_s", 0, "second", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_sd_", 0, "Sideral day", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_syr_", 0, "Sideral year", 0, 0, CAT_CATEGORY_PHYS | XCAS_ONLY}, + {"_tr", 0, "tour (angle unit)", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"_yd", 0, "yards", 0, 0, CAT_CATEGORY_UNIT | XCAS_ONLY}, + {"a and b", " and ", "Logical and", 0, 0, CAT_CATEGORY_PROGCMD}, + {"a or b", " or ", "Logical or", 0, 0, CAT_CATEGORY_PROGCMD}, + {"abcuv(a,b,c)", 0, "Find 2 polynomial u,v such that a*u+b*v=c","x+1,x^2-2,x", 0, CAT_CATEGORY_POLYNOMIAL}, + {"abs(x)", 0, "Absolute value or norm of x x", "-3", "[1,2,3]", CAT_CATEGORY_COMPLEXNUM | (CAT_CATEGORY_REAL<<8)}, + {"altitude(A,B,C)", 0, "Altitude in triangle ABC from A", "1,i,2+i", 0,CAT_CATEGORY_2D}, + {"append", 0, "Adds an element at the end of a list","#l.append(x)", 0, CAT_CATEGORY_LIST}, + {"approx(x)", 0, "Approx. value x. Shortcut S-D", "pi", 0, CAT_CATEGORY_REAL}, + {"area(objet)", 0, "Algebric area", "circle(0,1)", "triangle(-1,1+i,3)", CAT_CATEGORY_2D }, + {"arg(z)", 0, "Angle of complex z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM}, + {"asc(string)", 0, "List of ASCII codes os a string", "\"Hello\"", 0, CAT_CATEGORY_ARIT}, + {"assume(hyp)", 0, "Assumption on variable.", "x>1", "x>-1 and x<1", CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)}, + {"avance n", "avance ", "Turtle forward n steps, default n=10", "#avance 30", 0, CAT_CATEGORY_LOGO}, + {"axes", "axes", "Axes visible or not axes=1 or 0", "#axes=0", 0, CAT_CATEGORY_PROGCMD << 8|XCAS_ONLY}, + {"baisse_crayon ", "baisse_crayon ", "Turtle moves with the pen writing.", 0, 0, CAT_CATEGORY_LOGO}, + {"barplot(list)", 0, "Bar plot of 1-d statistic series data in list.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS}, + {"barycenter([pnt,coeff],...)", 0, "Barycenter of a sequence of [point,coefficient]. Run isobarycenter if all coefficients are equal", "[1,1],[i,1],[2,3]", 0, CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"binomial(n,p,k)", 0, "binomial(n,p,k) probability to get k success with n trials where p is the probability of success of 1 trial. binomial_cdf(n,p,k) is the probability to get at most k successes. binomial_icdf(n,p,t) returns the smallest k such that binomial_cdf(n,p,k)>=t", "10,.5,4", 0, CAT_CATEGORY_PROBA}, + {"bisector(A,B,C)", 0, "Bisector of angle AB,AC", "1,i,2+i", 0,CAT_CATEGORY_2D}, + {"bitxor", "bitxor", "Exclusive or", "#bitxor(1,2)", 0, CAT_CATEGORY_PROGCMD}, + {"black", "black", "Display option", "#display=black", 0, CAT_CATEGORY_PROGCMD}, + {"blue", "blue", "Display option", "#display=blue", 0, CAT_CATEGORY_PROGCMD}, + {"camembert(list)", 0, "Camembert pie-chart of a 1-d statistical series.", "[[\"France\",6],[\"Germany\",12],[\"Switzerland\",5]]", 0, CAT_CATEGORY_STATS}, + {"cache_tortue ", "cache_tortue ", "Hide turtle (once the picture has been drawn).", 0, 0, CAT_CATEGORY_LOGO}, + {"ceil(x)", 0, "Smallest integer not less than x", "1.2", 0, CAT_CATEGORY_REAL}, + {"center(objet)", 0, "Circle or sphere center. For ellipse or hyperbola, returns center, one focus and a point on the conic. For a parabola, returns focus and vertex.", "circle(0,1)", "sphere([0,0,0],[1,1,1])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"cfactor(p)", 0, "Factorization over C.", "x^4-1", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8)}, + {"char(liste)", 0, "Converts a list of ASCII codes to a string.", "[97,98,99]", 0, CAT_CATEGORY_ARIT}, + {"charpoly(M,x)", 0, "Characteristic polynomial of matrix M in variable x.", "[[1,2],[3,4]],x", 0, CAT_CATEGORY_MATRIX}, + {"circle(center,radius)", 0, "Circle", "2+i,3", "1-i,1+i", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8)}, + {"circumcircle(A,B,C)", 0, "Circumcircle", "-1,2+i,3", 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"clearscreen()", "clearscreen()", "Clear screen.", 0, 0, CAT_CATEGORY_PROGCMD|XCAS_ONLY}, + {"coeff(p,x,n)", 0, "Coefficient of x^n in polynomial p.", 0, 0, CAT_CATEGORY_POLYNOMIAL}, + {"comb(n,k)", 0, "Returns nCk", "10,4", 0, CAT_CATEGORY_PROBA}, + {"cond(A,[1,2,inf])", 0, "Nombre de condition d'une matrice par rapport a la norme specifiee (par defaut 1)", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"cone(A,v,theta,[h])", 0, " cone with vertex A, direction v, and with half_angle t [and with altitudes h and -h]", "[0,0,0],[0,0,1],pi/6", "[0,0,0],[0,0,1],pi/6,4", CAT_CATEGORY_3D}, + {"conic(expression)", 0, "Conic given by a polynomial equation of degree 2 or by 5 vertices", "x^2+x*y+y^2=5", "1,i,2+i,3-i,4+2i", CAT_CATEGORY_2D}, + {"coordinates(object)", 0, "Coordonnees (cartesian))", "point(1,2)", "point(1,2,3)", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"conj(z)", 0, "Complex conjugate of z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM}, + {"correlation(l1,l2)", 0, "Correlation of lists l1 and l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + {"covariance(l1,l2)", 0, "Covariance of lists l1 and l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + {"cpartfrac(p,x)", 0, "Partial fraction decomposition over C.", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8)}, + {"crayon ", "crayon ", "Turtle drawing color", "#crayon red", 0, CAT_CATEGORY_LOGO}, + {"cross(u,v)", 0, "Cross product of vectors u and v.","[1,2,3],[0,1,3]", 0, CAT_CATEGORY_LINALG}, + {"csolve(equation,x)", 0, "Solve equation (or polynomial system) in exact mode over the complex numbers.","x^2+x+1=0", 0, CAT_CATEGORY_SOLVE| (CAT_CATEGORY_COMPLEXNUM << 8)}, + {"cube(A,B,C)", 0, "Cube of edge AB with one face in plane ABC", "[0,0,0],[1,0,0],[0,1,0]","[0,0,0],[0,2,sqrt(5)/2+3/2],[0,0,1]", CAT_CATEGORY_3D}, + {"curl(u,vars)", 0, "Curl of vector u.", "[2*x*y,x*z,y*z],[x,y,z]", 0, CAT_CATEGORY_LINALG}, + {"cyan", "cyan", "Display option", "#display=cyan", 0, CAT_CATEGORY_PROGCMD}, + {"cylinder(A,v,r,[h])", 0, "Cylinder of axis A,v and radius r [and optional altitude h]", "[0,0,0],[0,1,0],2", "[0,0,0],[0,1,0],2,3", CAT_CATEGORY_3D}, + {"debug(f(args))", 0, "Runs user function f in step by step mode.", 0, 0, CAT_CATEGORY_PROG}, + {"degree(p,x)", 0, "Degre of polynomial p in x.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL}, + {"denom(x)", 0, "Denominator of expression x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL}, + {"desolve(equation,t,y)", 0, "Exact differential equation solving.", "desolve([y'+y=exp(x),y(0)=1])", "[y'=[[1,2],[2,1]]*y+[x,x+1],y(0)=[1,2]]", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_CALCULUS << 8)}, + {"det(A)", 0, "Determinant of matrix A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"diff(f,var,[n])", 0, "Derivative of expression f with respect to var (order n, n=1 by default), for example diff(sin(x),x) or diff(x^3,x,2). For derivation with respect to x, run f' (shortcut F3). For the gradient of f, var is the list of variables.", "sin(x),x", "sin(x^2),x,3", CAT_CATEGORY_CALCULUS}, + {"discriminant(p)", 0, "Discriminant of a polynomial p", "#P:=a*x^2+b*x+c;discriminant(P);", "discriminant(x^2+x+1)", CAT_CATEGORY_POLYNOMIAL | XCAS_ONLY}, + {"display", "display", "Display option", "#display=red", 0, CAT_CATEGORY_PROGCMD}, + {"disque n", "disque ", "Filled circle tangent to the turtle, radius n. Run disque n,theta for a filled arc of circle, theta in degrees, or disque n,theta,segment for a segment of circle.", "#disque 30", "#disque(30,90)", CAT_CATEGORY_LOGO}, + {"dodecahedron(A,B,C)", 0, "Dodecahedron of edge AB with one face in plane ABC", "[0,0,0],[0,2,sqrt(5)/2+3/2],[0,0,1]", 0, CAT_CATEGORY_3D}, + {"dot(a,b)", 0, "Dot product of 2 vectors. Shortcut: *", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_LINALG}, + {"draw_arc(x1,y1,rx,ry,theta1,theta2,c)", 0, "Pixelised arc of ellipse.", "100,100,60,80,0,pi,magenta", 0, CAT_CATEGORY_PROGCMD}, + {"draw_circle(x1,y1,r,c)", 0, "Pixelised circle. Option: filled", "100,100,60,cyan+filled", 0, CAT_CATEGORY_PROGCMD}, + {"draw_line(x1,y1,x2,y2,c)", 0, "Pixelised line.", "100,50,300,200,blue", 0, CAT_CATEGORY_PROGCMD}, + {"draw_pixel(x,y,color)", 0, "Colors pixel x,y. Run draw_pixel() to synchronise screen.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"draw_polygon([[x1,y1],...],c)", 0, "Pixelised polygon.", "[[100,50],[30,20],[60,70]],red+filled", 0, CAT_CATEGORY_PROGCMD}, + {"draw_rectangle(x,y,w,h,c)", 0, "Rectangle.", "100,50,30,20,red+filled", 0, CAT_CATEGORY_PROGCMD}, + {"draw_string(s,x,y,c)", 0, "Draw string s at pixel x,y", "\"Bonjour\",80,60", 0, CAT_CATEGORY_PROGCMD}, +#ifndef TURTLETAB + {"ecris ", "ecris ", "Write at turtle position", "#ecris \"hello\"", 0, CAT_CATEGORY_LOGO}, +#endif + {"efface", "efface", "Reset turtle", 0, 0, CAT_CATEGORY_LOGO}, + {"egcd(A,B)", 0, "Find polynomials U,V,D such that A*U+B*V=D=gcd(A,B)","x^2+3x+1,x^2-5x-1", 0, CAT_CATEGORY_POLYNOMIAL}, + //{"elif test", "elif ", "Test cascade", 0, 0, CAT_CATEGORY_PROG}, + {"ellipse(F1,F2,M)", 0, "Ellipse given by 2 focus and one point", "-1,1,2", 0, CAT_CATEGORY_2D}, + {"eigenvals(A)", 0, "Eigenvalues of matrix A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX |XCAS_ONLY}, + {"eigenvects(A)", 0, "Eigenvectors of matrix A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"equation(object)", 0, "Cartesian equation. Run parameq for parametric equation", "circle(0,1)", "ellipse(-1,1,3)", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"erf(x)", 0, "Error function of x.", "1.2", 0, CAT_CATEGORY_PROBA}, + {"erfc(x)", 0, "Complementary error function of x.", "1.2", 0, CAT_CATEGORY_PROBA}, + {"euler(n)",0,"Euler indicatrix: number of integers < n coprime with n","25",0,CAT_CATEGORY_ARIT}, + {"eval(f)", 0, "Evals f.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"evalc(z)", 0, "Write z=x+i*y.", "1/(1+i*sqrt(3))", 0, CAT_CATEGORY_COMPLEXNUM}, + {"exact(x)", 0, "Converts x to a rational. Shortcut shift S-D", "1.2", 0, CAT_CATEGORY_REAL}, + {"exp2trig(expr)", 0, "Convert complex exponentials to sin/cos", "exp(i*x)", 0, CAT_CATEGORY_TRIG}, +#ifdef QRHELP + {"exponential_regression(Xlist,Ylist)", 0, "Exponential regression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + {"exponential_regression_plot(Xlist,Ylist)", 0, "Exponential regression plot.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];exponential_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS}, +#endif + {"exponentiald(lambda,x)", 0, "Exponential distribution law of parameter lambda. exponentiald_cdf(lambda,x) probability that \"exponential distribution <=x\" e.g. exponentiald_cdf(2,3). exponentiald_icdf(lambda,t) returns x such that \"exponential distribution <=x\" has probability t, e.g, exponentiald_icdf(2,0.95) ", "5.1,3.4", 0, CAT_CATEGORY_PROBA}, + {"extend", 0, "Merge 2 lists. Note that + does not merge lists, it adds vectors","#l1.extend(l2)", 0, CAT_CATEGORY_LIST}, + {"factor(p,[x])", 0, "Factors polynomial p (run ifactor for an integer). Shortcut: p=>*", "x^4-1", "x^6+1,sqrt(3)", CAT_CATEGORY_ALGEBRA| (CAT_CATEGORY_POLYNOMIAL << 8)}, + {"filled", "filled", "Display option", 0, 0, CAT_CATEGORY_PROGCMD}, + {"float(x)", 0, "Converts x to a floating point value.", "pi", 0, CAT_CATEGORY_REAL}, + {"floor(x)", 0, "Largest integer not greater than x", "pi", 0, CAT_CATEGORY_REAL}, + {"fourier_an(f,x,T,n,a)", 0, "Cosine Fourier coefficients of f", "x^2,x,2*pi,n,-pi", 0, CAT_CATEGORY_CALCULUS}, + {"fourier_bn(f,x,T,n,a)", 0, "Sine Fourier coefficients of f", "x^2,x,2*pi,n,-pi", 0, CAT_CATEGORY_CALCULUS}, + {"fourier_cn(f,x,T,n,a)", 0, "Exponential Fourier coefficients of f", "x^2,x,2*pi,n,-pi", 0, CAT_CATEGORY_CALCULUS}, +#ifndef NUMWORKS_SLOTB + {"from math/... import *", "from math import *", "Access to math or to random functions ([random]) or turtle with English commandnames [turtle]. Math import is not required in KhiCAS", "#from random import *", "#from turtle import *", CAT_CATEGORY_PROG}, +#endif + {"fsolve(equation,x=a..b)", 0, "Approx equation solving in interval a..b.","cos(x)=x,x=0..1", "cos(x)-x,x=0.0", CAT_CATEGORY_SOLVE}, + // {"function f(x):...", "function f(x) local y; ffunction:;", "Function definition.", "#function f(x) local y; y:=x^2; return y; ffunction:;", 0, CAT_CATEGORY_PROG}, + {"gauss(q)", 0, "Quadratic form reduction", "x^2+x*y+x*z+y^2+z^2,[x,y,z]", 0, CAT_CATEGORY_LINALG}, + {"gcd(a,b,...)", 0, "Greatest common divisor. See also iegcd and egcd for extended GCD.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8)}, + {"gl_x", "gl_x", "Display settings X gl_x=xmin..xmax", "#gl_x=0..2", 0, CAT_CATEGORY_PROGCMD}, + {"gl_y", "gl_y", "Display settings Y gl_y=ymin..ymax", "#gl_y=-1..1", 0, CAT_CATEGORY_PROGCMD}, + {"gramschmidt(M)", 0, "Gram-Schmidt orthonormalization (line vectors or linearly independent set of vectors)", "[[1,2,3],[4,5,6]]", "[1,1+x],(p,q)->integrate(p*q,x,-1,1)", CAT_CATEGORY_LINALG}, + {"green", "green", "Display option", "#display=green", 0, CAT_CATEGORY_PROGCMD}, + {"halftan(expr)", 0, "Convert cos, sin, tan with tan(angle/2).","cos(x)", 0, CAT_CATEGORY_TRIG}, + {"hermite(n)", 0, "n-th Hermite polynomial", "10", 0, CAT_CATEGORY_POLYNOMIAL}, + {"hilbert(n)", 0, "Hilbert matrix of order n.", "4", 0, CAT_CATEGORY_MATRIX}, + {"histogram(list,min,size)", 0, "Histogram of data in list, classes begin at min of size size.","ranv(100,uniformd,0,1),0,0.1", 0, CAT_CATEGORY_STATS}, + {"homothety(center,ratio,object)", 0, "Image of object by homothety of ratio", "0,2,circle(1,1)", 0, CAT_CATEGORY_2D }, + {"hyperbola(F1,F2,M)", 0, "Hyperbola given by 2 focus and one point", "-2-i,2+i,1", 0, CAT_CATEGORY_2D}, + {"iabcuv(a,b,c)", 0, "Find 2 integers u,v such that a*u+b*v=c","23,13,15", 0, CAT_CATEGORY_ARIT}, + {"ichinrem([a,m],[b,n])", 0,"Integer chinese remainder of a mod m and b mod n.", "[3,13],[2,7]", 0, CAT_CATEGORY_ARIT}, + {"icosahedron(A,B,C)", 0, "Icosahedron with center A, vertex B and such that the plane ABC contains one vertex among the 5 nearest vertices from B ", "[0,0,0],[sqrt(5),0,0],[1,2,0]", 0, CAT_CATEGORY_3D}, + {"idivis(n)", 0, "Returns the list of divisors of an integer n.", "10", 0, CAT_CATEGORY_ARIT}, + {"idn(n)", 0, "Identity matrix of order n", "4", 0, CAT_CATEGORY_MATRIX}, + {"iegcd(a,b)", 0, "Find integers u,v,d such that a*u+b*v=d=gcd(a,b)","23,13", 0, CAT_CATEGORY_ARIT}, + {"ifactor(n)", 0, "Factorization of an integer (not too large!). Shortcut n=>*", 0, 0, CAT_CATEGORY_ARIT}, + {"ilaplace(f,s,x)", 0, "Inverse Laplace transform of f", "s/(s^2+1),s,x", 0, CAT_CATEGORY_CALCULUS}, + {"im(z)", 0, "Imaginary part.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM}, + {"incircle(A,B,C)", 0, "Incircle", "-1,2+i,3", 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"inf", "inf", "Plus infinity. -inf for minus infinity and infinity for unsigned/complex infinity. Shortcut shift INS.", "oo", 0, CAT_CATEGORY_CALCULUS}, + {"input()", "input()", "Read a string from keyboard", 0, 0, CAT_CATEGORY_PROG}, + {"integrate(f,x,[a,b])", 0, "Antiderivative of f with respect to x, like integrate(x*sin(x),x). For definite integral enter optional arguments a and b, like integrate(x*sin(x),x,0,pi). For line integral, integrate([field_x,field_y],[x,y],courbe,tmin,tmax), e.g.. ellipse area G:=plotparam([2*cos(t),sin(t)],t):; integrate([0,x],[x,y],G,0,2*pi). Shortcut SHIFT F3.", "x*sin(x),x", "cos(x)/(1+x^4),x,0,inf", CAT_CATEGORY_CALCULUS}, + {"interp(X,Y)", 0, "Lagrange interpolation at points (xi,yi) where X is the list of xi and Y of yi. If interp is passed as 3rd argument, returns the divided differences list.", "[1,2,3,4,5],[0,1,3,4,4]", "[1,2,3,4,5],[0,1,3,4,4],interp", CAT_CATEGORY_POLYNOMIAL}, + {"inter(A,B)", 0, "Intersections list. Run single_inter if intersection is unique.", "line(y=x),circle(0,1)", 0, CAT_CATEGORY_3D | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"inv(A)", 0, "Inverse of A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"iquo(a,b)", 0, "Integer quotient of a and b.", "23,13", 0, CAT_CATEGORY_ARIT}, + {"irem(a,b)", 0,"Integer remainder of a and b.", "23,13", 0, CAT_CATEGORY_ARIT}, + {"isprime(n)", 0, "Returns 1 if n is prime, 0 otherwise.", "11", "10", CAT_CATEGORY_ARIT}, + {"is_collinear(A,B,C)", 0, "Returns 1 if A, B, C are collinear, 0 otherwise", "1,i,-1", "i,0,-i", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_concyclic(A,B,C,D)", 0, "Returns 1 if A, B, C, D are concyclic, 0 otherwise", "1,i,-1,-i", "1,i,0,-i", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_element(A,G)", 0, "Returns 1 if A belongs to G, 0 otherwise.", "point(0),circle(0,1)", "point(i),square(0,1)", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_parallel(D,E)", 0, "Returns 1 if D and E are parallel, 0 otherwise", "line(y=x),line(y=-x)", "line(y=x),line(y=x+1)", CAT_CATEGORY_2D | XCAS_ONLY }, + {"is_perpendicular(D,E)", 0, "Returns 1 if D and E are perpendicular, 0 otherwise", "line(y=x),line(y=-x)", "line(y=x),line(y=x+1)", CAT_CATEGORY_2D | XCAS_ONLY }, + {"jordan(A)", 0, "Jordan normal form of matrix A, returns P and D such that P^-1*A*P=D", "[[1,2],[3,4]]", "[[1,1,-1,2,-1],[2,0,1,-4,-1],[0,1,1,1,1],[0,1,2,0,1],[0,0,-3,3,-1]]", CAT_CATEGORY_MATRIX}, + {"laguerre(n,a,x)", 0, "n-ieme Laguerre polynomial (default a=0).", "10", 0, CAT_CATEGORY_POLYNOMIAL}, + {"laplace(f,x,s)", 0, "Laplace transform of f","sin(x),x,s", 0, CAT_CATEGORY_CALCULUS}, + {"lcm(a,b,...)", 0, "Least common multiple.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8)}, + {"lcoeff(p,x)", 0, "Leading coefficient of polynomial p in x.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL}, + {"legendre(n)", 0, "n-the Legendre polynomial.", "10", "10,t", CAT_CATEGORY_POLYNOMIAL}, +#ifdef RELEASE + {"len(l)", 0, "Size of a list.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_LIST}, +#endif + {"leve_crayon ", "leve_crayon ", "Turtle moves without trace.", 0, 0, CAT_CATEGORY_LOGO}, + {"limit(f,x=a)", 0, "Limit of f at x = a. Add 1 or -1 for unidirectional limits, e.g. limit(sin(x)/x,x=0) or limit(abs(x)/x,x=0,1). Shortcut: SHIFT MIXEDFRAC", "sin(x)/x,x=0", "exp(-1/x),x=0,1", CAT_CATEGORY_CALCULUS}, + {"line(equation)", 0, "Line of equation", "y=2x+1", "[0,0,0],[1,-2,3]", CAT_CATEGORY_PROGCMD |(CAT_CATEGORY_2D << 8)|(CAT_CATEGORY_2D << 16)}, + {"line_width_", "line_width_", "Width prefix (2 to 8)", 0, 0, CAT_CATEGORY_PROGCMD}, + {"linear_regression(Xlist,Ylist)", 0, "Linear regression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + {"linear_regression_plot(Xlist,Ylist)", 0, "Linear regression plot.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];linear_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS}, + {"linetan(expr,x,x0)", 0, "Tangent to the graph at x=x0.", "sin(x),x,pi/2", 0, CAT_CATEGORY_PLOT}, + {"linsolve([eq1,eq2,..],[x,y,..])", 0, "Linear system solving. May use the output of lu for O(n^2) solving (see example 2).","[x+y=1,x-y=2],[x,y]", "#p,l,u:=lu([[1,2],[3,4]]); linsolve(p,l,u,[5,6])", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_LINALG <<8) | (CAT_CATEGORY_MATRIX << 16)}, + {"logarithmic_regression(Xlist,Ylist)", 0, "Logarithmic egression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + //{"logarithmic_regression_plot(Xlist,Ylist)", 0, "Logarithmic regression plot.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];logarithmic_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS}, + {"lu(A)", 0, "LU decomposition LU of matrix A, P*A=L*U", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"magenta", "magenta", "Display option", "#display=magenta", 0, CAT_CATEGORY_PROGCMD}, + {"map(f,l)", 0, "Maps f on element of list l.","lambda x:x*x,[1,2,3]", 0, CAT_CATEGORY_LIST}, + {"matpow(A,n)", 0, "Returns matrix A^n", "[[1,2],[3,4]],n","#assume(n>=1);matpow([[0,2],[0,4]],n)", CAT_CATEGORY_MATRIX}, + {"matrix(r,c,func)", 0, "Matrix from a defining function.", "2,3,(j,k)->j^k", 0, CAT_CATEGORY_MATRIX}, + {"mean(l)", 0, "Arithmetic mean of list l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS}, + {"median(l)", 0, "Median", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS}, + {"median_line(A,B,C)", 0, "Median line of triangle ABC from vertex A", "1,i,2+i", 0,CAT_CATEGORY_2D}, + {"midpoint(A,B)", 0, "Midpoint of segment AB", "1,i", 0,CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8)}, + {"montre_tortue ", "montre_tortue ", "Displays the turtle", 0, 0, CAT_CATEGORY_LOGO}, + {"mult_c_conjugate", 0, "Multiplier par le conjugue complexe.", "1+2*i", 0, (CAT_CATEGORY_COMPLEXNUM << 8)}, + {"mult_conjugate", 0, "Multiplier par le conjugue (sqrt).", "sqrt(2)-sqrt(3)", 0, CAT_CATEGORY_ALGEBRA}, + {"normald([mu,sigma],x)", 0, "Normal distribution probability density, by default mu=0 and sigma=1. normald_cdf([mu,sigma],x) probability that \"normal distribution <=x\" e.g. normald_cdf(1.96). normald_icdf([mu,sigma],t) returns x such that \"normal distribution <=x\" has probability t, e.g. normald_icdf(0.975) ", "1.2", 0, CAT_CATEGORY_PROBA}, + {"not(x)", 0, "Logical not.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"numer(x)", 0, "Numerator of x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL}, + {"octahedron(A,B,C)", 0, "Octahedron of edge AB with one face in plane ABC", "[0,0,0],[3,0,0],[0,1,0]", 0, CAT_CATEGORY_3D}, + {"odesolve(f(t,y),[t,y],[t0,y0],t1)", 0, "Approx. solution of differential equation y'=f(t,y) and y(t0)=y0, value for t=t1 (add curve to get intermediate values of y)", "sin(t*y),[t,y],[0,1],2", "0..pi,(t,v)->{[-v[1],v[0]]},[0,1]", CAT_CATEGORY_SOLVE}, + {"parabola(F,A)", 0, "Parabola given by focus and vertex", "-2-i,2+i", 0, CAT_CATEGORY_2D}, + {"parameq(object)", 0, "Parametric equations. Run equation for cartesian equation", "circle(0,1)", "ellipse(-1,1,3)", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"partfrac(p,x)", 0, "Partial fraction expansion. Shortcut p=>+", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA}, + {"pas_de_cote n", "pas_de_cote ", "Turtle side jump from n steps, by default n=10", "#pas_de_cote 30", 0, CAT_CATEGORY_LOGO}, + {"perpen_bisector(A,B)", 0, "Perpendicular bisector of segment AB", "1,i", 0,CAT_CATEGORY_2D}, + {"plane(equation)", 0, "Plane given by equation or by 3 points", "z=x+y-1", "[0,0,0],[1,0,0],[0,1,0]", CAT_CATEGORY_3D | XCAS_ONLY}, + {"plot(expr,x)", 0, "Plot an expression. For example plot(sin(x)), plot(ln(x),x.0,5), plot(x^2-y^2), plot(x^2-y^2<1), plot(x^2-y^2=1)", "ln(x),x,0,5", "1/x,x=1..5,xstep=1", (CAT_CATEGORY_PLOT << 8) | (CAT_CATEGORY_3D)}, +#ifdef RELEASE + {"plotarea(expr,x=a..b,[n,meth])", 0, "Area under curve with specified quadrature.", "1/x,x=1..3,2,trapezoid", 0, CAT_CATEGORY_PLOT}, +#endif + {"plotcontour(expr,[x=xm..xM,y=ym..yM],levels)", 0, "Levels of expr.", "x^2+2y^2,[x=-2..2,y=-2..2],[1,2]", 0, CAT_CATEGORY_PLOT}, + {"plotfield(f(t,y),[t=tmin..tmax,y=ymin..ymax])", 0, "Plot field of differential equation y'=f(t,y), an optionally one solution by adding plotode=[t0,y0]", "sin(t*y),[t=-3..3,y=-3..3],plotode=[0,1]", 0, CAT_CATEGORY_PLOT}, + {"plotfunc(expr,[x,y])", 0, "Xcas: graph of a 3d function", "x^2-y^2,[x,y]","x^2-y^2,[x=-2..2,y=-2..2],nstep=700", CAT_CATEGORY_PLOT | (CAT_CATEGORY_3D << 8) | XCAS_ONLY }, + {"plotlist(list)", 0, "Plot a list", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_PLOT}, + {"plotode(f(t,y),[t=tmin..tmax,y],[t0,y0])", 0, "Plot solution of differential equation y'=f(t,y), y(t0)=y0.", "sin(t*y),[t=-3..3,y],[0,1]", 0, CAT_CATEGORY_PLOT}, + {"plotparam([x,y],t)", 0, "Parametric plot. For example plotparam([sin(3t),cos(2t)],t,0,pi) or plotparam(exp(i*t),t,0,pi)", "[sin(3t),cos(2t)],t,0,pi", "[t^2,t^3],t=-1..1,tstep=0.1", CAT_CATEGORY_PLOT}, + {"plotpolar(r,theta)", 0, "Polar plot.","cos(3*x),x,0,pi", "1/(1+cos(x)),x=0..pi,xstep=0.05", CAT_CATEGORY_PLOT}, + {"plotseq(f(x),x=[u0,m,M],n)", 0, "Plot f(x) on [m,M] and n terms of the sequence defined by u_{n+1}=f(u_n) and u0.","sqrt(2+x),x=[6,0,7],5", 0, CAT_CATEGORY_PLOT}, + {"plus_point", "plus_point", "Display option", "#display=blue+plus_point", 0, CAT_CATEGORY_PROGCMD}, + {"point(x,y[,z])", 0, "Point", "1,2", "1,2,3", CAT_CATEGORY_PLOT | (CAT_CATEGORY_2D << 8)}, + {"polygon(list)", 0, "Closed polygon given by a list of vertices.", "1-i,2+i,3,3-2i", 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) }, + {"polygonscatterplot(Xlist,Ylist)", 0, "Plot points and polygonal line.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + {"polyhedron(A,B,C,D,...)", 0, "Convex polyhedron of vertices in A,B,C,D,...", "[0,0,0],[0,5,0],[0,0,5],[1,2,6]", 0, CAT_CATEGORY_3D}, +#ifdef QRHELP + {"polynomial_regression(Xlist,Ylist,n)", 0, "Polynomial regression, degree <= n.", "[1,2,3,4,5],[0,1,3,4,4],2", 0, CAT_CATEGORY_STATS}, + {"polynomial_regression_plot(Xlist,Ylist,n)", 0, "Polynomial regression plot, degree <= n.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS}, + //{"pour", "pour j de 1 jusque faire fpour;", "For loop.","#pour j de 1 jusque 10 faire print(j,j^2); fpour;", 0, CAT_CATEGORY_PROG}, + {"power_regression(Xlist,Ylist,n)", 0, "Power regression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + {"power_regression_plot(Xlist,Ylist,n)", 0, "Power regression graph", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];power_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS}, +#endif + {"powmod(a,n,p)", 0, "Returns a^n mod p.","123,456,789", 0, CAT_CATEGORY_ARIT}, + {"print(expr)", 0, "Print expr in console", 0, 0, CAT_CATEGORY_PROG}, + {"projection(obj1,obj2)", 0, "Projection on obj1 of obj2", "line(y=x),point(2,3)", 0, CAT_CATEGORY_2D }, + {"proot(p)", 0, "Returns real and complex roots, of polynomial p. Exemple proot([1,2.1,3,4.2]) or proot(x^3+2.1*x^2+3x+4.2)", "x^3+2.1*x^2+3x+4.2", 0, CAT_CATEGORY_POLYNOMIAL}, + {"purge(x)", 0, "Clear assigned variable x. Shortcut SHIFT-FORMAT", 0, 0, CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)}, + {"python(f)", 0, "Displays f in Python syntax.", 0, 0, CAT_CATEGORY_PROGCMD}, + {"python_compat(0|1|2)", 0, "python_compat(0) Xcas syntax, python_compat(1) Python syntax with ^ interpreted as power, python_compat(2) ^ as bit xor", "0", "1", CAT_CATEGORY_PROG}, + {"qr(A)", 0, "A=Q*R factorization with Q orthogonal and R upper triangular", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"quadric(equation)", 0, "Quadric given by equation (or 9 points)", "x^2-y^2+z^2", "x^2+x*y+y^2+z^2-3", CAT_CATEGORY_3D}, + {"quartile1(l)", 0, "1st quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS}, + {"quartile3(l)", 0, "3rd quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS}, + {"quo(p,q,x)", 0, "Quotient of synthetic division of polynomials p and q (variable x).", 0, 0, CAT_CATEGORY_POLYNOMIAL}, + {"quote(x)", 0, "Returns expression x unevaluated.", 0, 0, CAT_CATEGORY_ALGEBRA}, + {"radius(objet)", 0, "Radius of a circle or sphere", "circle(0,1)", "sphere([0,0,0],[1,1,1])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"rand()", "rand()", "Random real between 0 and 1", 0, 0, CAT_CATEGORY_PROBA}, + {"randint(a,b)", 0, "Random integer between a and b. With 1 argument in Xcas, random integer between 1 and n.", "5,25", "6", CAT_CATEGORY_PROBA}, + {"ranm(n,m,[loi,parametres])", 0, "Random matrix with integer coefficients or according to a probability law (ranv for a vector). Examples ranm(2,3), ranm(3,2,binomial,20,.3), ranm(4,2,normald,0,1)", "3,3","4,2,normald,0,1", CAT_CATEGORY_MATRIX}, + {"ranv(n,[loi,parametres])", 0, "Random vector.", "10","4,normald,0,1", CAT_CATEGORY_LINALG}, + {"ratnormal(x)", 0, "Puts everything over a common denominator.", 0, 0, CAT_CATEGORY_ALGEBRA}, + {"re(z)", 0, "Real part.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM}, +#ifndef NUMWORKS + {"read(\"filename\")", "read(\"", "Read a file.", 0, 0, CAT_CATEGORY_PROGCMD}, +#endif + {"rectangle_plein a,b", "rectangle_plein ", "Direct filled rectangle from turtle position, if b is omitted b==a", "#rectangle_plein 30","#rectangle_plein 20,40", CAT_CATEGORY_LOGO}, + {"recule n", "recule ", "Turtle backward n steps, n=10 by default", "#recule 30", 0, CAT_CATEGORY_LOGO}, + {"red", "red", "Display option", "#display=red", 0, CAT_CATEGORY_PROGCMD}, + {"reflection(obj1,obj2)", 0, "Reflection or symmetrical of obj2", "line(y=x),cercle(1,1)", 0, CAT_CATEGORY_2D }, + {"rem(p,q,x)", 0, "Remainder of synthetic division of polynomials p and q (variable x)", 0, 0, CAT_CATEGORY_POLYNOMIAL}, +#ifdef RELEASE + {"residue(f(z),z,z0)", 0, "Residue of an expression at z0.", "1/(x^2+1),x,i", 0, CAT_CATEGORY_COMPLEXNUM}, +#endif + {"resultant(p,q,x)", 0, "Resultant in x of polynomials p and q.", "#P:=x^3+p*x+q;resultant(P,P',x);", 0, CAT_CATEGORY_POLYNOMIAL}, + {"revert(p[,x])", 0, "Revert Taylor series","x+x^2+x^4", 0, CAT_CATEGORY_CALCULUS}, + {"rgb(r,g,b)", 0, "color defined from red, green, blue from 0 to 255", "255,0,255", 0, CAT_CATEGORY_PROGCMD}, + {"rhombus_point", "rhombus_point", "Display option", "#display=magenta+rhombus_point", 0, CAT_CATEGORY_PROGCMD}, + {"rond n", "rond ", "Circle tangent to the turtle, radius n. Run rond n,theta for an arc of circle of theta degrees", 0, 0, CAT_CATEGORY_LOGO}, + {"rotation(center,angle,objcet)", 0, "Image of object by rotation", "2-i,pi/2,circle(0,1)", "sphere([0,0,0],[1,1,1])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + {"rsolve(equation,u(n),[init])", 0, "Solve a recurrence relation.","u(n+1)=2*u(n)+3,u(n),u(0)=1", "([u(n+1)=3*v(n)+u(n),v(n+1)=v(n)+u(n)],[u(n),v(n)],[u(0)=1,v(0)=2]", CAT_CATEGORY_SOLVE}, + {"saute n", "saute ", "Turtle jumps n steps, by default n=10", "#saute 30", 0, CAT_CATEGORY_LOGO}, + {"scatterplot(Xlist,Ylist)", 0, "Draws points", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS}, + {"segment(A,B)", 0, "Segment", "1,2+i", "[1,2,1],[-1,3,2]", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"seq(expr,var,a,b)", 0, "Generates a list from an expression.","j^2,j,1,10", 0, CAT_CATEGORY_PROGCMD}, + //{"si", "si alors sinon fsi;", "Test.", "#f(x):=si x>0 alors x; sinon -x; fsi;// valeur absolue", 0, CAT_CATEGORY_PROG}, + {"sign(x)", 0, "Returns -1 if x is negative, 0 if x is zero and 1 if x is positive.", 0, 0, CAT_CATEGORY_REAL|XCAS_ONLY}, + {"similarity(center,ratio,angle,object)", 0, "Image of object by similarity", "0,2,pi/2,circle(1,1)", 0, CAT_CATEGORY_2D }, + {"simplify(expr)", 0, "Returns x in a simpler form. Shortcut expr=>/", "sin(3x)/sin(x)", 0, CAT_CATEGORY_ALGEBRA}, + {"single_inter(A,B)", 0, "First intersection. Run inter for a list of intersections.", "line(y=x),line(x+y=3)", 0, CAT_CATEGORY_3D | (CAT_CATEGORY_2D << 8) | XCAS_ONLY}, + {"solve(equation,x)", 0, "Exact solving of equation w.r.t. x (or of a polynomial system). Run csolve for complex solutions, linsolve for a linear system. Shortcut SHIFT XthetaT", "x^2-x-1=0,x", "[x^2-y^2=0,x^2-z^2=0],[x,y,z]", CAT_CATEGORY_SOLVE}, + {"sorted(l)", 0, "Sorts a list.","[3/2,2,1,1/2,3,2,3/2]", "[[1,2],[2,3],[4,3]],(x,y)->when(x[1]==y[1],x[0]>y[0],x[1]>y[1]", CAT_CATEGORY_LIST}, + {"sphere(A,r)", 0, "Sphere of center A and radius r or diameter AB", "[0,0,0],1", "[0,0,0],[1,1,1]", CAT_CATEGORY_3D}, + {"square_point", "square_point", "Display option", "#display=cyan+square_point", 0, CAT_CATEGORY_PROGCMD}, + {"star_point", "star_point", "Display option", "#display=magenta+star_point", 0, CAT_CATEGORY_PROGCMD}, + {"stddev(l)", 0, "Standard deviation of list l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS}, + {"subst(a,b=c)", 0, "Substitutes b for c in a. Shortcut a(b=c).", "x^2,x=3", 0, CAT_CATEGORY_ALGEBRA}, + {"sum(f,k,m,M)", 0, "Summation of expression f for k from m to M. Exemple sum(k^2,k,1,n)=>*. Shortcut ALPHA F3", "k,k,1,n", 0, CAT_CATEGORY_CALCULUS}, + {"svd(A)", 0, "Singular Value Decomposition, returns U orthogonal, S vector of singular values, Q orthogonal such that A=U*diag(S)*tran(Q).", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"tabvar(f,[x=a..b])", 0, "Table of variations of expression f, optional arguments variable x in interval a..b", "sqrt(x^2+x+1)", "[cos(t),sin(3t)],t", CAT_CATEGORY_CALCULUS}, + //{"tantque", "tantque faire ftantque;", "While loop.", "#j:=13; tantque j!=1 faire j:=when(even(j),j/2,3j+1); print(j); ftantque;", 0, CAT_CATEGORY_PROG}, + {"taylor(f,x=a,n,[polynom])", 0, "Taylor expansion of f of x at a order n, add parameter polynom to remove remainder term.","sin(x),x=0,5", "sin(x),x=0,5,polynom", CAT_CATEGORY_CALCULUS}, + {"tchebyshev1(n)", 0, "Tchebyshev polynomial 1st kind: cos(n*x)=T_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL}, + {"tchebyshev2(n)", 0, "Tchebyshev polynomial 2nd kind: sin((n+1)*x)=sin(x)*U_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL}, + {"tcollect(expr)", 0, "Linearize and collect trig functions.","sin(x)+cos(x)", 0, CAT_CATEGORY_TRIG}, + {"texpand(expr)", 0, "Expand trigonometric, exp and ln functions.","sin(3x)", 0, CAT_CATEGORY_TRIG}, + {"time(cmd)", 0, "Time to run a command or set the clock","int(1/(x^4+1),x)","8,0", CAT_CATEGORY_PROG}, + {"tlin(expr)", 0, "Trigonometric linearization of expr.","sin(x)^3", 0, CAT_CATEGORY_TRIG}, + {"tourne_droite n", "tourne_droite ", "Turtle turns right n degrees, n=90 by default", 0, 0, CAT_CATEGORY_LOGO}, + {"tourne_gauche n", "tourne_gauche ", "Turtle turns left n degrees, n=90 by default", 0, 0, CAT_CATEGORY_LOGO}, + {"trace(A)", 0, "Trace of the matrix A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"transpose(A)", 0, "Transposes matrix A. Transconjugate command is trn(A) or A^*.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX}, + {"translation(vect,obj)", 0, "Translate by vect obj", "[1,2],cercle(0,1)", 0, CAT_CATEGORY_2D }, + {"triangle(A,B,C)", 0, "Triangle given by 3 vertices", "1+i,1-i,-1", "A,B,C", CAT_CATEGORY_2D}, + {"triangle_point", "triangle_point", "Display option", "#display=yellow+triangle_point", 0, CAT_CATEGORY_PROGCMD}, + {"trig2exp(expr)", 0, "Convert complex exponentials to trigonometric functions","cos(x)^3", 0, CAT_CATEGORY_TRIG}, + {"trigcos(expr)", 0, "Convert sin^2 and tan^2 to cos^2.","sin(x)^4", 0, CAT_CATEGORY_TRIG}, + {"trigsin(expr)", 0, "Convert cos^2 and tan^2 to sin^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG}, + {"trigtan(expr)", 0, "Convert cos^2 and sin^2 to tan^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG}, + {"uniformd(a,b,x)", "uniformd", "uniform law on [a,b] of density 1/(b-a)", 0, 0, CAT_CATEGORY_PROBA}, + {"vertices(objet)", 0, "List of vertices of a polygon or polyhedra", "triangle(1,i,2)", "cube([0,0,0],[1,0,0],[0,1,0])", CAT_CATEGORY_2D | (CAT_CATEGORY_3D << 8) }, + //{"version", "version()", "Khicas 1.5.0, (c) B. Parisse et al. www-fourier.ujf-grenoble.fr/~parisse\nLicense GPL version 2. Interface adapted from Eigenmath for Casio, G. Maia, http://gbl08ma.com. Do not use if CAS calculators are forbidden.", 0, 0, CAT_CATEGORY_PROGCMD}, +#ifndef NUMWORKS + {"write(\"filename\",var)", "write(\"", "Save 1 or more variables in a file. For example f(x):=x^2; write(\"func_f\",f).", 0, 0, CAT_CATEGORY_PROGCMD}, +#endif + {"yellow", "yellow", "Display option", "#display=yellow", 0, CAT_CATEGORY_PROGCMD}, + {"|", "|", "Logical or", "#1|2", 0, CAT_CATEGORY_PROGCMD}, + {"~", "~", "Complement", "#~7", 0, CAT_CATEGORY_PROGCMD}, +}; + + const char aide_khicas_string[]="Aide Khicas"; +#ifdef NUMWORKS +#ifdef NUMWORKS_SLOTB + const char shortcuts_en_string[]=""; +#else + const char shortcuts_fr_string[]="Raccourcis clavier (shell et editeur)\nshift-/: %\nalpha shift \": '\nshift--: \\\nshift-+: completion\nshift-1 a 6: selon bandeau en bas\nshift-7: matrices\nshift-8: complexes\nshift-9:arithmetique entiere\nshift-0: probas\nshift-.: reels\nshift-10^: polynomes\nvar: liste des variables\nans: figure tortue (editeur)\n\nshift-x^y (sto) renvoie =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: Editeur 2d ou graphique ou texte selon objet\nshift-6: editeur texte\n+ ou - modifie un parametre en surbrillance\n\nEditeur d'expressions\nshift-cut: defaire/refaire (1 fois)\npave directionnel: deplace la selection dans l'arborescence de l'expression\nshift-droit/gauche echange selection avec argument a droite ou a gauche\nalpha-droit/gauche dans une somme ou un produit: augmente la selection avec argument droit ou gauche\nshift-4: Editer selection, shift-5: taille police + ou - grande\nEXE: evaluer la selection\nshift-6: valeur approchee\nBackspace: supprime l'operateur racine de la selection\n\nEditeur de scripts\nEXE: passage a la ligne\nshift-CUT: documentation\nshift COPY (ou shift et deplacement curseur simultanement): marque le debut de la selection, deplacer le curseur vers la fin puis Backspace pour effacer ou shift-COPY pour copier sans effacer. shift-PASTE pour coller.\nHome-6 recherche seule: entrer un mot puis EXE puis EXE. Taper EXE pour l'occurence suivante, Back pour annuler.\nHome-6 remplacer: entrer un mot puis EXE puis le remplacement et EXE. Taper EXE ou Back pour remplacer ou non et passer a l'occurence suivante, AC pour annuler\nOK: tester syntaxe\n\nRaccourcis Graphes:\n+ - zoom\n(-): zoomout selon y\n*: autoscale\n/: orthonormalisation\nOPTN: axes on/off"; + const char shortcuts_en_string[]="Keyboard shortcuts (shell and editor)\nshift-/: %\nalpha shift \": '\nshift--: \\\nshift-+: completion\nshift-1 to 6: cf. screen bottom\nshift-7: matrices\nshift-8: complexes\nshift-9:arithmetic\nshift-0: proba\nshift-.: reals\nshift-10^: polynomials\nvar: variables list\nans: turtle screen (editor)\n\nshift-x^y (sto) returns =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: 2d editor or graph or text\nshift-6: text edit\n+ ou - modifies selected slider\n\nExpressions editor\nshift-cut: undo/redo (1 fois)\nkeypad: move selection inside expression tree\nshift-right/left exchange selection with right or left argument\nalpha-right/left: inside a sum or product: increase selection with right or left argument\nshift-4: Edit selection, shift-5: change fontsize\nEXE: eval selection\nshift-6: approx value\nBackspace: suppress selection's rootnode operator\n\nScript Editor\nEXE: newline\nshift-CUT: documentation\nshift-COPY: marks selection begin, move the cursor to the end, then hit Backspace to erase or shift-COPY to copy (no erase). shift-PASTE to paste.\nHome-6 search: enter a word then EXE then again EXE. Type EXE for next occurence, Back to cancel.\nHome-6 replace: enter a word then EXE then replacement word then EXE. Type EXE or Back to replace or ignore and go to next occurence, AC to cancel\nOK: test syntax\n\nGraph shortcuts:\n+ - zoom\n(-): zoomout along y\n*: autoscale\n/: orthonormalization\nOPTN: axes on/off"; +#endif +#else + const char shortcuts_fr_string[]="Raccourcis clavier (shell et editeur)\nlivre: aide/complete\ntab: complete (shell)/indente (editeur)\nshift-/: %\nshift *: '\nctrl-/: \\\nshift-1 a 6: selon bandeau en bas\nshift-7: matrices\nshift-8: complexes\nshift-9:arithmetique\nshift-0: probas\nshift-.: reels\nctrl P: programme\nvar: liste des variables\nans (shift (-)): figure tortue (editeur)\n\nctrl-var (sto) renvoie =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: Editeur 2d ou graphique ou texte selon objet\nshift-4: editeur texte\n+ ou - modifie un parametre en surbrillance\n\nEditeur d'expressions\nctrl z: defaire/refaire (1 fois)\npave directionnel: deplace la selection dans l'arborescence de l'expression\nshift-droit/gauche echange selection avec argument a droite ou a gauche\nctrl droit/gauche dans une somme ou un produit: augmente la selection avec argument droit ou gauche\nshift-4: Editer selection, shift-5: taille police + ou - grande\nenter: evaluer la selection\nshift-6: valeur approchee\nDel: supprime l'operateur racine de la selection\n\nEditeur de scripts\nenter: passage a la ligne\nctrl z: defaire/refaire (1 fois)\nctrl c ou shift et touche curseur simultanement: marque le debut de la selection, deplacer le curseur vers la fin puis Del pour effacer ou ctrl c pour copier sans effacer. ctrl v pour coller.\ndoc-6 recherche seule: entrer un mot puis enter puis enter. Taper enter pour l'occurence suivante, esc pour annuler.\ndoc-6 remplacer: entrer un mot puis enter puis le remplacement et enter. Taper enter ou esc pour remplacer ou non et passer a l'occurence suivante, ctrl del pour annuler\nvalidation (a droite de U): tester syntaxe\n\nRaccourcis Graphes:\n+ - zoom\n(-): zoomout selon y\n*: autoscale\n/: orthonormalisation\nOPTN: axes on/off"; + const char shortcuts_en_string[]="Keyboard shortcuts (shell and editor)\nbook: help or completion\ntab: completion (shell), indent (editor)\nshift-/: %\nalpha shift *: '\nctrl-/: \\\nshift-1 a 6: see at bottom\nshift-7: matrices\nshift-8: complexes\nshift-9:arithmetic\nshift-0: probas\nshift-.: reals\nctrl P: program\nvar: variables list\n ans (shift (-)): turtle screen (editor)\n\nctrl var (sto) returns =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: 2d editor or graph or text\nshift-4: text edit\n+ ou - modifies selected slider\n\nExpressions editor\nctrl z: undo/redo (1 fois)\nkeypad: move selection inside expression tree\nshift-right/left exchange selection with right or left argument\nalpha-right/left: inside a sum or product: increase selection with right or left argument\nshift-4: Edit selection, shift-5: change fontsize\nenter: eval selection\nshift-6: approx value\nDel: suppress selection's rootnode operator\n\nScript Editor\nenter: newline\nctrl z: undo/redo (1 time)\nctrl c or shift + cursor key simultaneously: marks selection begin, move the cursor to the end, then hit Del to erase or ctrl c to copy (no erase). ctrl v to paste.\ndoc-6 search: enter a word then enter then again enter. Type enter for next occurence, esc to cancel.\ndoc-6 replace: enter a word then enter then replacement word then enter. Type enter or esc to replace or ignore and go to next occurence, AC to cancel\nOK: test syntax\n\nGraph shortcuts:\n+ - zoom\n(-): zoomout along y\n*: autoscale\n/: orthonormalization\nOPTN: axes on/off"; +#endif + + const char apropos_fr_string[]="KhiCAS (c) 2024 B. Parisse et R. De Graeve, www-fourier.univ-grenoble-alpes.fr/~parisse.\nLicense GPL version 2, adaptation de l'interface d'Eigenmath pour Casio, G. Maia (http://gbl08ma.com), Mike Smith, Nemhardy, LePhenixNoir, ...\nPortage Numworks par Damien Nicolet. Remerciements a Jean-Baptiste Boric, Maxime Friess et Yann Couturier.\nPortage sur Nspire grace a Fabian Vogt (firebird-emu, ndless...).\nTable periodique d'apres Maxime Friess\nRemerciements au site tiplanet, Xavier Andreani, Adrien Bertrand, Lionel Debroux"; + + const char apropos_en_string[]="KhiCAS (c) 2024 B. Parisse et R. De Graeve, www-fourier.univ-grenoble-alpes.fr/~parisse.\nGPL license version 2, interface adapted from Eigenmath for Casio, G. Maia (http://gbl08ma.com), Mike Smith, Nemhardy, LePhenixNoir, ...\nPorted on Numworks by Damien Nicolet. Thanks to Jean-Baptiste Boric, Maxime Friess and Yann Couturier.\nPorted on Nspire thanks to Fabian Vogt (firebird-emu, ndless...)\nPeriodic table by Maxime Friess\nThanks to tiplanet, Xavier Andreani, Adrien Bertrand, Lionel Debroux"; + + const int CAT_COMPLETE_COUNT_FR=sizeof(completeCatfr)/sizeof(catalogFunc); + const int CAT_COMPLETE_COUNT_EN=sizeof(completeCaten)/sizeof(catalogFunc); + + std::string insert_string(int index){ + std::string s; + const catalogFunc * completeCat=(lang==1)?completeCatfr:completeCaten; + if (completeCat[index].insert) + s=completeCat[index].insert; + else { + s=completeCat[index].name; + int pos=s.find('('); + if (pos>=0 && pos=2?as.examples[1].c_str():0; + c.category=-1; + } + int showCatalog(char* insertText,int preselect,int menupos,GIAC_CONTEXT) { + // returns 0 on failure (user exit) and 1 on success (user chose a option) + MenuItem menuitems[CAT_CATEGORY_LOGO+1]; + menuitems[CAT_CATEGORY_ALL].text = (char*)((lang==1)?"Tout":"All"); + menuitems[CAT_CATEGORY_ALGEBRA].text = (char*)((lang==1)?"Algebre":"Algebra"); + menuitems[CAT_CATEGORY_LINALG].text = (char*)((lang==1)?"Algebre lineaire":"Linear algebra"); + menuitems[CAT_CATEGORY_CALCULUS].text = (char*)((lang==1)?"Analyse":"Calculus"); + menuitems[CAT_CATEGORY_ARIT].text = (char*)"Arithmetic, crypto"; + menuitems[CAT_CATEGORY_COMPLEXNUM].text = (char*)"Complexes"; + menuitems[CAT_CATEGORY_PLOT].text = (char*)((lang==1)?"Courbes":"Curves"); + menuitems[CAT_CATEGORY_POLYNOMIAL].text = (char*)((lang==1)?"Polynomes":"Polynomials"); + menuitems[CAT_CATEGORY_PROBA].text = (char*)((lang==1)?"Probabilites":"Probabilities"); + menuitems[CAT_CATEGORY_PROGCMD].text = (char*)((lang==1)?"Programmes cmds (0)":"Program cmds (0)"); + menuitems[CAT_CATEGORY_REAL].text = (char*)((lang==1)?"Reels (e^)":"Reals"); + menuitems[CAT_CATEGORY_SOLVE].text = (char*)((lang==1)?"Resoudre (ln)":"Solve (ln)"); + menuitems[CAT_CATEGORY_STATS].text = (char*)((lang==1)?"Statistiques (log)":"Statistics (log)"); + menuitems[CAT_CATEGORY_TRIG].text = (char*)((lang==1)?"Trigonometrie (i)":"Trigonometry (i)"); + menuitems[CAT_CATEGORY_OPTIONS].text = (char*)"Options (,)"; + menuitems[CAT_CATEGORY_LIST].text = (char*)((lang==1)?"Listes (x^y)":"Lists (x^y)"); + menuitems[CAT_CATEGORY_MATRIX].text = (char*)"Matrices (sin)"; + menuitems[CAT_CATEGORY_PROG].text = (char*)((lang==1)?"Programmes (cos)":"Programs"); + menuitems[CAT_CATEGORY_SOFUS].text = (char*)((lang==1)?"Modifier variables (tan)":"Change variables (tan)"); + menuitems[CAT_CATEGORY_PHYS].text = (char*)((lang==1)?"Constantes physique (pi)":"Physics constants (pi)"); + menuitems[CAT_CATEGORY_UNIT].text = (char*)((lang==1)?"Unites physiques (sqrt)":"Units (sqrt)"); + menuitems[CAT_CATEGORY_2D].text = (char*)((lang==1)?"Geometrie (x^2)":"Geometry (x^2)"); + menuitems[CAT_CATEGORY_3D].text = (char*)((lang==1)?"3D (()":"3D (()"); + menuitems[CAT_CATEGORY_LOGO].text = (char*)((lang==1)?"Tortue ())":"Turtle ())"); + + Menu menu; + menu.items=menuitems; + menu.numitems=sizeof(menuitems)/sizeof(MenuItem); + menu.height=MENUHEIGHT; + menu.scrollout=1; + menu.title = (char*)((lang==1)?"Liste de commandes":"Commands list"); + //puts("catalog 1"); + while(1) { + if (preselect) + menu.selection=preselect; + else { + if (menupos>0) + menu.selection=menupos; + int sres = doMenu(&menu); + if (sres != MENU_RETURN_SELECTION && sres!=KEY_CTRL_EXE) + return 0; + } + // puts("catalog 3"); + if(doCatalogMenu(insertText, menuitems[menu.selection-1].text, menu.selection-1,contextptr)) + return 1; + if (preselect) + return 0; + } + return 0; + } + + int showCatalog(char * text,int nmenu,GIAC_CONTEXT){ + return showCatalog(text,0,nmenu,contextptr); + } + +#ifndef BW + bool isalphanum(char c){ + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'); + } +#endif + + string remove_accents(const string & s){ + string r; + for (int i=0;i= begin and < end + for (;;){ + cur=(beg+end)/2; + test=strcmp(s,tab[cur].s); + if (!test) + return cur; + if (cur==beg) + return -1; + if (test>0) + beg=cur; + else + end=cur; + } + return -1; +} + +int longhelp_pos(const char * s){ + int pos=dichotomic_search(lang==1?helpfr:helpen,lang==1?helpfr_size:helpen_size,s); + if (pos==-1) + return pos; + return lang==1?helpfr[pos].i:helpen[pos].i; +} + +string longhelp(const char * s){ + string cmd(s); + for (int i=0;i0;--l){ + if (!isalphanum(buf[l-1]) && buf[l-1]!='_') + break; + } + // cmdname in buf+l + const char * cmdname=buf+l,*cmdnameorig=cmdname; + l=strlen(cmdname); + // search in catalog: dichotomy would be more efficient + // but leading spaces cmdnames would be missed + int nfunc=(lang==1)?CAT_COMPLETE_COUNT_FR:CAT_COMPLETE_COUNT_EN;//sizeof(completeCat)/sizeof(catalogFunc); +#if !defined BW && !defined NUMWORKS_SLOTB && (defined NSPIRE_NEWLIB || defined NUMWORKS) // should match static_help[] in help.cc + int iii=nfunc; // no search in completeCat, directly in static_help.h + //if (xcas_python_eval) iii=0; +#else + int iii=0; +#endif + const catalogFunc * completeCat=(lang==1)?completeCatfr:completeCaten; + for (;iii0 && (completeCat[iii].category & XCAS_ONLY) ) + continue; + const char * name=completeCat[iii].name; + while (*name==' ') + ++name; + int j=0; + for (;j0 && fexamples[i]==';' && fexamples[i-1]!=' '){ + strcpy(fbuf,fexamples); + fbuf[i]=0; + fexamples=fbuf; + frelated=fbuf+i+1; + while (*frelated==' ') + ++frelated; + for (++i;iexample:fexamples; + const char * example2=catf?catf->example2:frelated; + if (exec){ + if (!fsyntax){ + cmdname=example; + example=example2; + } + } + else { + xcas::textArea text; + text.editable=false; + text.clipline=-1; + text.title = (char*)((lang==1)?"Aide sur la commande":"Help on command"); + text.allowF1=true; + text.python=false; + std::vector & elem=text.elements; + elem = std::vector (example2?5:4); + elem[0].s = catf?catf->name:cmdname; + elem[0].newLine = 0; + elem[1].lineSpacing = 0; + if (fsyntax){ + elem[1].newLine = 1; + elem[1].s=(lang==1?"Syntaxe: ":"Syntax: ")+elem[0].s+"("+(strlen(fsyntax)?fsyntax:"arg")+")"; + } + else { + elem[1].newLine = 0; + elem[1].s=elem[0].s; + } + if (cf.size()) + elem[0].s += " (cf. "+cf+")"; + if (elem[0].s.size()<16) + elem[0].s=string(16-elem[0].s.size()/2,' ')+elem[0].s; + //elem[0].color = COLOR_BLUE; + elem[2].newLine = 1; + elem[2].lineSpacing = 1; + elem[2].minimini=1; + std::string autoexample; + if (catf && catf->desc==0){ + // if (token==T_UNARY_OP || token==T_UNARY_OP_38) + elem[2].s=elem[0].s+"(args)"; + } + else { +#ifdef NUMWORKS + elem[2].s = remove_accents(catf?catf->desc:fhowto); +#else + elem[2].s = catf?catf->desc:fhowto; +#endif + } +#ifdef NSPIRE_NEWLIB + std::string ex("tab: "); +#else + std::string ex("Ans: "); +#endif + elem[3].newLine = 1; + elem[3].lineSpacing = 0; + //elem[2].minimini=1; + if (example){ + if (example[0]=='#') + ex += example+1; + else { + if (iii==nfunc) + ex += fexamples; + else { + ex += insert_string(iii); + ex += example; + ex += ")"; + } + } + elem[3].s = ex; + if (example2){ +#ifdef NSPIRE_NEWLIB + string ex2="ret: "; +#else + string ex2="EXE: "; +#endif + if (example2[0]=='#') + ex2 += example2+1; + else { + if (iii==nfunc) + ex2 += example2; + else { + ex2 += insert_string(iii); + ex2 += example2; + ex2 += ")"; + } + } + elem[4].newLine = 1; + // elem[3].lineSpacing = 0; + //elem[3].minimini=1; + elem[4].s=ex2; + } + } + else { + if (autoexample.size()) + elem[3].s=ex+autoexample; + else + elem.pop_back(); + } + exec=doTextArea(&text,contextptr); +#ifdef QRHELP + if (exec==KEY_CHAR_EXPN10 || exec==KEY_CTRL_SETUP){ + string url=fourier_url; + url += "giac/doc"; + url += (lang==1?"/fr/cascmd_fr/":"en/cascmd_en/")+longhelp(elem[0].s.c_str()); + xcas::QRdisp(url.c_str(),(string("Xcas doc qrcode ")+elem[0].s).c_str()); + } +#endif + } + if (exec==KEY_SHUTDOWN) + return ""; + if (exec==MENU_RETURN_SELECTION){ + while (*cmdname && *cmdname==*cmdnameorig){ + ++cmdname; ++cmdnameorig; + } + return cmdname; + } + if (exec == KEY_CHAR_ANS || exec==KEY_BOOK || exec=='\t' || exec==KEY_CTRL_EXE) { + reset_kbd(); + std::string s; + const char * example=0; + if (exec==KEY_CHAR_ANS || exec==KEY_BOOK || exec=='\t') + example=catf?catf->example:fexamples; + else + example=catf?catf->example2:frelated; + if (example){ + while (*example && *example==*cmdnameorig){ + ++example; ++cmdnameorig; + } + while (*cmdnameorig){ + back=0; // ++back; // otherwise shift-2 3 integrate( Ans/EXE cuts integrate( + ++cmdnameorig; + } + if (example[0]=='#') + s=example+1; + else { + s += example; + //if (catf && s[s.size()-1]!=')') s += ")"; + } + } + if (python_compat(contextptr)<0 || (python_compat(contextptr) & 4)){ + // replace := by = + for (int i=1;ifirst:(lexer_tab_int_values_begin+curmi)->keyword; +#ifdef MICROPY_LIB + if (xcas_python_eval==1 && xcas::find_color(text,contextptr)!=3){ + ++cur; + continue; + } +#endif + menuitems[curmi].text = (char*) text; + menuitems[curmi].isfolder = allcmds; // assumes allcmds>allopts + menuitems[curmi].token=isall?((builtin_lexer_functions_begin()+curmi)->second.subtype+256):((lexer_tab_int_values_begin+curmi)->subtype+(lexer_tab_int_values_begin+curmi)->return_value*256); + // menuitems[curmi].token=isall?find_or_make_symbol(text,g,0,false,contextptr):((lexer_tab_int_values_begin+curmi)->subtype+(lexer_tab_int_values_begin+curmi)->return_value*256); + for (;i=0){ + size_t st=strlen(text),j=tmp?0:st; + for (;j=100) + lock_alpha(); //SetSetupSetting( (unsigned int)0x14, 0x88); + // DisplayStatusArea(); + menu.scrollout=1; + menu.title = (char *) title; + menu.type = MENUTYPE_FKEYS; + menu.height = MENUHEIGHT-1; + while(1) { +#ifdef HP39 + drawRectangle(0,114,LCD_WIDTH_PX,14,SDK_WHITE); + PrintMini(0,114,"input | ex1 | ex2 | | | help ",4); +#else + drawRectangle(0,200,LCD_WIDTH_PX,22,SDK_WHITE); +#ifdef NSPIRE_NEWLIB + PrintMini7(0,200,(category==CAT_CATEGORY_ALL?"menu: help | ret: ex1 | tab: ex2 | calc: QRcode":"menu: help | ret: ex1 | tab: ex2 | calc: QRcode"),4,33333,SDK_WHITE,false); +#else + PrintMini7(0,200,(category==CAT_CATEGORY_ALL?"Tool help|10^ QR|Ans ex1|EXE ex2":"Tool help|10^ QR|Ans ex1|EXE ex2"),4,33333,SDK_WHITE,false); +#endif +#endif + int sres = 0; + if (curmi==0){ + do_confirm(lang==1?"Commandes seulement en mode Xcas":"Commands only in Xcas mode"); + sres=MENU_RETURN_EXIT; + } + else + sres=doMenu(&menu); + if (sres==KEY_CTRL_F4 && category!=CAT_CATEGORY_ALL){ + break; + } + if(sres == MENU_RETURN_EXIT){ + reset_kbd(); +#ifdef MENUITEM_MALLOC + free(menuitems); +#endif + return sres; + } + int index=menuitems[menu.selection-1].isfolder; +#ifdef QRHELP + if (sres==KEY_CHAR_EXPN10 || sres==KEY_CTRL_SETUP){ + const char * fcmdname=menuitems[menu.selection-1].text; + string url=fourier_url; + url += "giac/doc"; + url += (lang==1?"/fr/cascmd_fr/":"en/cascmd_en/")+longhelp(fcmdname); + xcas::QRdisp(url.c_str(),(string("Xcas doc qrcode ")+fcmdname).c_str()); + } +#endif + if (sres == KEY_CTRL_CATALOG || sres==KEY_BOOK || sres==KEY_CTRL_F6) { + const char * example=index & elem=text.elements; + elem = std::vector (example2?4:3); + elem[0].s = index100) + return "Done"; + if (g.is_symb_of_sommet(giac::at_pnt)){ + giac::gen & f=g._SYMBptr->feuille; + giac::gen fp=remove_at_pnt(g); +#ifndef BW + if (fp.is_symb_of_sommet(giac::at_hyperplan)){ + return gettext("plan")+string("(")+_equation(g,contextptr).print(contextptr)+string(")"); + } +#endif + if (f.type==giac::_VECT && !f._VECTptr->empty()){ + giac::gen f0=f._VECTptr->front(); + if (f0.is_symb_of_sommet(giac::at_legende)){ + return g.print(contextptr); + } + if (f0.is_symb_of_sommet(giac::at_curve)){ + giac::gen f1=f[0]._SYMBptr->feuille; + if (f1.type==giac::_VECT && !f1._VECTptr->empty() ){ + giac::gen f1f=f1._VECTptr->front(); + if (f1f.type==giac::_VECT && f1f._VECTptr->size()>=4){ + giac::vecteur f1v=*f1f._VECTptr; + return "plotparam("+_pnt2string(f1v[0],contextptr)+","+f1v[1].print(contextptr)+"="+f1v[2].print(contextptr)+".."+f1v[3].print(contextptr)+")"; + } + } + } + if (f0.is_symb_of_sommet(giac::at_cercle) && f0._SYMBptr->feuille.type==giac::_VECT){ + if (f0._SYMBptr->feuille._VECTptr->size()==3 && ((*f0._SYMBptr->feuille._VECTptr)[2]!=giac::cst_two_pi || (*f0._SYMBptr->feuille._VECTptr)[1]!=0)) + return f0.print(contextptr); + giac::gen centre,rayon; + if (!giac::centre_rayon(f0,centre,rayon,true,0)) + return "cercle_error"; + if (!complex_mode(contextptr) && (centre.typebegin(),itend=f0._VECTptr->end(); + if ( itend-it==2){ + switch(f0.subtype){ + case giac::_LINE__VECT: + s=gettext("line")+string("("); + break; + case giac::_HALFLINE__VECT: + s=gettext("half_line")+string("("); + break; + case giac::_GROUP__VECT: + s=gettext("segment")+string("("); + break; + } + if (f0.subtype==giac::_LINE__VECT && it->type!=giac::_VECT){ // 2-d line + s += _equation(g,contextptr).print(contextptr) + ")"; + return s; + } + } + for (;it!=itend;){ + s += "point("; + if (!complex_mode(contextptr) && (it->typetype==giac::_FRAC) ) + s += giac::re(*it,contextptr).print(contextptr)+","+giac::im(*it,contextptr).print(contextptr); + else { + gen f=*it; + if (f.type==_VECT && f.subtype==_POINT__VECT) + f.subtype=_SEQ__VECT; + s += f.print(contextptr); + } + s+=")"; + ++it; + s += it==itend?")":","; + } + return s; + } + if ( (f0.type!=giac::_FRAC && f0.type>=giac::_IDNT) || is3d(g) || complex_mode(contextptr)){ + if (f0.type==_VECT && f0.subtype==_POINT__VECT) + f0.subtype=_SEQ__VECT; + return "point("+f0.print(contextptr)+")"; + } + else + return "point("+giac::re(f0,contextptr).print(contextptr)+","+giac::im(f0,contextptr).print(contextptr)+")"; + } + } + if (g.type==giac::_VECT && !g._VECTptr->empty() && g._VECTptr->back().is_symb_of_sommet(giac::at_pnt)){ + std::string s = "["; + giac::const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;){ + s += _pnt2string(*it,contextptr); + ++it; + s += it==itend?"]":","; + } + return s; + } + return g.print(contextptr); + } + + std::string pnt2string(const giac::gen & g,const giac::context * contextptr){ + int p=python_compat(contextptr); + python_compat(0,contextptr); + string s=_pnt2string(g,contextptr); + python_compat(p,contextptr); + return s; + } + +#ifndef BW + gen select_var(GIAC_CONTEXT){ + giac::history_plot(contextptr).clear(); + kbd_interrupted=giac::ctrl_c=giac::interrupted=false; +#ifdef QUICKJS + if (xcas_python_eval<0){ + update_js_vars(); + size_t vs=js_vars.size(); + char s[vs+1]; + strcpy(s,js_vars.c_str()); + unsigned n=0,N=0; + for (size_t i=0;i=0 && tab[i]) + g=string2gen(tab[i],false); + return g; + } +#endif +#ifdef MICROPY_LIB + if (xcas_python_eval==1){ + micropy_ck_eval(""); + const char ** tab=(const char **)mp_vars(); + const char **ptr=tab; + for (;*ptr;) + ++ptr; + // del at end should not be sorted + if (ptr-tab>=1 && strcmp(*(ptr-1),"del ")==0) + --ptr; + qsort(tab,ptr-tab,sizeof(char *),trialpha); + if (tab){ + int i=select_item(tab,"VARS",true); + gen g=undef; + if (i>=0 && tab[i]) + g=string2gen(tab[i],false); + free(tab); + return g; + } + } +#endif + gen g(_VARS(0,contextptr)); + if (g.type!=_VECT + //|| g._VECTptr->empty() + ){ + confirm((lang==1)?"Pas de variables. Exemples pour en creer":"No variables. Examples to create",(lang==1)?"a=1 ou f(x):=sin(x^2)":"a=1 or f(x):=sin(x^2)",true); + return undef; + } + vecteur & v=*g._VECTptr; + MenuItem smallmenuitems[v.size()+3]; + vector vs(v.size()+1); + int i,total=0; + const char typ[]="idzDcpiveSfEsFRmuMwgPF"; + for (i=0;iin_eval(0,v[i],w,contextptr,true); +#if 1 + vector vi(9); + tailles(w,vi); + total += vi[8]; + if (vi[8]<(w.is_symb_of_sommet(at_pnt)?1500:500)) + vs[i]+=":="+pnt2string(w,contextptr); + else { + vs[i] += " ~"; + vs[i] += giac::print_INT_(vi[8]); + vs[i] += ','; + vs[i] += typ[w.type]; + } +#else + if (taille(w,50)<50) + vs[i]+=": "+w.print(contextptr); +#endif + } + smallmenuitems[i].text=(char *) vs[i].c_str(); + } + total += + // giac::syms().capacity()*(sizeof(string)+sizeof(giac::gen)+8)+sizeof(giac::sym_string_tab) + + giac::turtle_stack().capacity()*sizeof(giac::logo_turtle) + + // sizeof(giac::context)+contextptr->tabptr->capacity()*(sizeof(const char *)+sizeof(giac::gen)+8)+ + bytesize(giac::history_in(contextptr))+bytesize(giac::history_out(contextptr)); + vs[i]="purge(~"+giac::print_INT_(total)+')'; + smallmenuitems[i].text=(char *)vs[i].c_str(); + smallmenuitems[i+1].text=(char *)"assume("; + smallmenuitems[i+2].text=(char *)"restart"; + Menu smallmenu; + smallmenu.numitems=v.size()+3; + smallmenu.items=smallmenuitems; + smallmenu.height=MENUHEIGHT; + smallmenu.scrollbar=1; + smallmenu.scrollout=1; + string vars="Variables"; +#if defined NUMWORKS && defined DEVICE +#ifdef TLSF + vars += ", free = "; +#else + vars += ", free >= "; +#endif + vars += print_INT_(ram_avail()); +#endif + smallmenu.title = (char*) vars.c_str(); + //MsgBoxPush(5); + int sres = doMenu(&smallmenu); + //MsgBoxPop(); + if (sres==KEY_CTRL_DEL && smallmenu.selection<=v.size()) + return symbolic(at_purge,v[smallmenu.selection-1]); + if (sres!=MENU_RETURN_SELECTION && sres!=KEY_CTRL_EXE) + return undef; + if (smallmenu.selection==1+v.size()) + return string2gen("purge(",false); + if (smallmenu.selection==2+v.size()) + return string2gen("assume(",false); + if (smallmenu.selection==3+v.size()) + return string2gen("restart",false); + return v[smallmenu.selection-1]; + } + + const char * keytostring(int key,int keyflag,bool py,const giac::context * contextptr){ + const int textsize=512; + static char text[textsize]; + if (key>=0x20 && key<=0x7e){ + text[0]=key; + text[1]=0; + return text; + } + switch (key){ + case KEY_CHAR_PLUS: + return "+"; + case KEY_CHAR_MINUS: + return "-"; + case KEY_CHAR_PMINUS: + return "_"; + case KEY_CHAR_MULT: + return "*"; + case KEY_CHAR_FRAC: + return py?"\\":"solve("; + case KEY_CHAR_DIV: + return "/"; + case KEY_CHAR_POW: + return py?"**":"^"; + case KEY_CHAR_ROOT: + return "sqrt("; + case KEY_CHAR_SQUARE: + return py?"**2":"^2"; + case KEY_CHAR_POWROOT: + return py?"**(1/":"^(1/"; + case KEY_CHAR_RECIP: + return py?"**-1":"^-1"; +#ifndef NUMWORKS + case KEY_CHAR_CUBEROOT: + return py?"**(1/3)":"^(1/3)"; + case KEY_CHAR_THETA: + return "arg("; + case KEY_CHAR_VALR: + return "abs("; + case KEY_CHAR_ANGLE: + return "polar_complex("; +#endif + case KEY_CTRL_XTT: + return xthetat?"t":"x"; + case KEY_CHAR_LN: + return py?"log(":"ln("; + case KEY_CHAR_LOG: + return "log10("; + case KEY_CHAR_EXPN10: + return py?"10**":"10^"; + case KEY_CHAR_EXPN: + return "exp("; + case KEY_CHAR_SIN: + return "sin("; + case KEY_CHAR_COS: + return "cos("; + case KEY_CHAR_TAN: + return "tan("; + case KEY_CHAR_ASIN: + return "asin("; + case KEY_CHAR_ACOS: + return "acos("; + case KEY_CHAR_ATAN: + return "atan("; +#ifndef NUMWORKS + case KEY_CTRL_MIXEDFRAC: + return "limit("; + case KEY_CTRL_FRACCNVRT: + return "exact("; + // case KEY_CTRL_FORMAT: return "purge("; + case KEY_CTRL_FD: + return "approx("; +#endif + case KEY_CHAR_STORE: + // if (keyflag==1) return "inf"; + return "=>"; + case KEY_CHAR_IMGNRY: + return "i"; + case KEY_CHAR_PI: + return "pi"; + case KEY_CTRL_VARS: { + giac::gen var=select_var(contextptr); + if (!giac::is_undef(var)){ + strcpy(text,(var.type==giac::_STRNG?*var._STRNGptr:var.print(contextptr)).c_str()); + return text; + } + return "";//"VARS()"; + } + case KEY_CHAR_EXP: + return "e"; + case KEY_CHAR_ANS: + return "ans()"; + case KEY_CHAR_CROCHETS: + return "[]"; + case KEY_CHAR_ACCOLADES: + return "{}"; + case KEY_CTRL_INS: + { + int c=giac::chartab(); + if (c>=32 && c<127){ + text[0]=c; + text[1]=0; + return text; + } + } + return ""; // ":="; + case KEY_CHAR_MAT:{ + const char * ptr=xcas::input_matrix(false,contextptr); if (ptr) return ptr; + if (showCatalog(text,17,contextptr)) return text; + return ""; + } + case KEY_CHAR_LIST: { + const char * ptr=xcas::input_matrix(true,contextptr); if (ptr) return ptr; + if (showCatalog(text,16,contextptr)) return text; + return ""; + } + case KEY_CTRL_PRGM: + // open functions catalog, prgm submenu + if(showCatalog(text,18,contextptr)) + return text; + return ""; + case KEY_CTRL_CATALOG: case KEY_BOOK: + if(showCatalog(text,0,contextptr)) + return text; + return ""; + case KEY_CTRL_F4: + if(showCatalog(text,0,contextptr)) + return text; + return ""; + case KEY_CTRL_OPTN: + if(showCatalog(text,15,contextptr)) + return text; + return ""; + case KEY_CTRL_QUIT: + if(showCatalog(text,20,contextptr)) + return text; + return ""; + case KEY_CTRL_PASTE: + return paste_clipboard(); + case KEY_CHAR_DQUATE: + return "\""; + case KEY_CHAR_FACTOR: + return "factor("; + case KEY_CHAR_NORMAL: + return "normal("; + } + return 0; + } +#endif + + const char * keytostring(int key,int keyflag,GIAC_CONTEXT){ + return keytostring(key,keyflag,python_compat(contextptr),contextptr); + } + + bool stringtodouble(const string & s1,double & d){ + gen g(s1,context0); + g=evalf(g,1,context0); + if (g.type!=_DOUBLE_){ + confirm("Invalid value",s1.c_str()); + return false; + } + d=g._DOUBLE_val; + return true; + } + + bool inputdouble(const char * msg1,double & d,GIAC_CONTEXT){ + int di=d; + string s1; + if (di==d) + s1=print_INT_(di); + else + s1=print_DOUBLE_(d,3); + inputline(msg1,((lang==1)?"Nouvelle valeur? ":"New value? "),s1,false,65,contextptr); + return stringtodouble(s1,d); + } + + bool inputdouble(const char * msg1,double & d,int ypos,GIAC_CONTEXT){ + int di=d; + string s1; + if (di==d) + s1=print_INT_(di); + else + s1=print_DOUBLE_(d,3); + inputline(msg1,((lang==1)?"Nouvelle valeur? ":"New value? "),s1,false,ypos,contextptr); + return stringtodouble(s1,d); + } + + int inputline(const char * msg1,const char * msg2,string & s,bool numeric,int ypos,GIAC_CONTEXT){ + //s=msg2; + int pos=s.size(),beg=0; + for (;;){ + int X1=print_msg12(msg1,msg2,ypos-30); + int textX=X1,textY=ypos; + drawRectangle(textX,textY,LCD_WIDTH_PX-textX-4,18,COLOR_WHITE); + if (pos-beg>36) + beg=pos-12; + if (int(s.size())-beg<36) + beg=giac::giacmax(0,int(s.size())-36); + if (beg>pos) + beg=pos; + textX=X1; +#if 0 + os_draw_string_(textX,textY,(s.substr(beg,pos-beg)+"|"+s.substr(pos,s.size()-pos)).c_str()); +#else + textX=os_draw_string_(textX,textY+2,s.substr(beg,pos-beg).c_str()); + os_draw_string_(textX,textY+2,s.substr(pos,s.size()-pos).c_str()); + drawRectangle(textX,textY+4,2,13,COLOR_BLACK); // cursor + // PrintMini(0,58," | | | | A<>a | ",4); +#endif + int key; + GetKey(&key); + if (key==KEY_SHUTDOWN) + return key; + // if (!giac::freeze) set_xcas_status(); + if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK || key==KEY_CHAR_CR){ + reset_kbd(); + return KEY_CTRL_EXE; + } + if (key>=32 && key<128){ + if (!numeric || key=='-' || (key>='0' && key<='9')){ + s.insert(s.begin()+pos,char(key)); + ++pos; + } + continue; + } + if (key==KEY_CHAR_ACCOLADES || key==KEY_CHAR_CROCHETS){ + s.insert(s.begin()+pos,key==KEY_CHAR_ACCOLADES?'}':']'); + s.insert(s.begin()+pos,key==KEY_CHAR_ACCOLADES?'{':'['); + ++pos; + continue; + } + if (key==KEY_CTRL_DEL){ + if (pos){ + s.erase(s.begin()+pos-1); + --pos; + } + continue; + } + if (key==KEY_CTRL_AC){ + if (s=="") + return KEY_CTRL_EXIT; + s=""; + pos=0; + continue; + } + if (key==KEY_CTRL_EXIT) + return key; + if (key==KEY_CTRL_RIGHT){ + if (pos & turtle_stack(){ + static std::vector * ans = 0; + if (!ans){ + // initialize from python app storage + ans=new std::vector(1,(*turtleptr)); + + } + return *ans; + } + + logo_turtle vecteur2turtle(const vecteur & v){ + int s=int(v.size()); + if (s>=5 && v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_ && v[2].type==_DOUBLE_ && v[3].type==_INT_ && v[4].type==_INT_ ){ + logo_turtle t; + t.x=v[0]._DOUBLE_val; + t.y=v[1]._DOUBLE_val; + t.theta=v[2]._DOUBLE_val; + int i=v[3].val; + t.mark=(i%2)!=0; + i=i >> 1; + t.visible=(i%2)!=0; + i=i >> 1; + t.direct = (i%2)!=0; + i=i >> 1; + t.turtle_width = i & 0xff; + i=i >> 8; + t.color = i; + t.radius = v[4].val; + if (s>5 && v[5].type==_INT_) + t.s=v[5].val; + else + t.s=-1; + return t; + } +#ifndef NO_STDEXCEPT + setsizeerr(gettext("vecteur2turtle")); // FIXME +#endif + return logo_turtle(); + } + + static int turtle_status(const logo_turtle & turtle){ + int status= (turtle.color << 11) | ( (turtle.turtle_width & 0xff) << 3) ; + if (turtle.direct) + status += 4; + if (turtle.visible) + status += 2; + if (turtle.mark) + status += 1; + return status; + } + +#if defined NUMWORKS && defined DEVICE + bool ck_turtle_size(){ + vector & v=turtle_stack(); + if (v.size()=2 && v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_){ + vecteur w(v); + int s=int(w.size()); + if (s==2) + w.push_back(double((*turtleptr).theta)); + if (s<4) + w.push_back(turtle_status((*turtleptr))); + if (s<5) + w.push_back(0); + if (w[2].type==_DOUBLE_ && w[3].type==_INT_ && w[4].type==_INT_){ + (*turtleptr)=vecteur2turtle(w); + if (!ck_turtle_size()) + return false; +#ifdef TURTLETAB + turtle_stack_push_back(*turtleptr); +#else + turtle_stack().push_back((*turtleptr)); +#endif + return true; + } + } + return false; + } + + gen turtle2gen(const logo_turtle & turtle){ + return gen(makevecteur(turtle.x,turtle.y,double(turtle.theta),turtle_status(turtle),turtle.radius,turtle.s),_LOGO__VECT); + } + + gen turtle_state(GIAC_CONTEXT){ + return turtle2gen((*turtleptr)); + } + + static gen update_turtle_state(bool clrstring,GIAC_CONTEXT){ +#if defined NUMWORKS && defined DEVICE + if (!ck_turtle_size()){ + if (ctrl_c || interrupted) + return undef; + ctrl_c=true; interrupted=true; + return gensizeerr("Not enough memory"); + } +#else +#ifdef TURTLETAB + if (turtle_stack_size>=MAX_LOGO) + return gensizeerr("Not enough memory"); +#else + if (turtle_stack().size()>=MAX_LOGO){ + ctrl_c=true; interrupted=true; + return gensizeerr("Not enough memory"); + } +#endif +#endif + if (clrstring) + (*turtleptr).s=-1; + (*turtleptr).theta = (*turtleptr).theta - floor((*turtleptr).theta/360)*360; + bool push=true; + if (push){ +#ifdef TURTLETAB + turtle_stack_push_back((*turtleptr)); +#else + if (!turtle_stack().empty()){ + logo_turtle & t=turtle_stack().back(); + if (t.equal_except_nomark(*turtleptr)){ + t.theta=turtleptr->theta; + t.mark=turtleptr->mark; + t.visible=turtleptr->visible; + t.color=turtleptr->color; + push=false; + } + } + turtle_stack().push_back((*turtleptr)); +#endif + } + gen res=turtle_state(contextptr); +#if !defined SDL_KHICAS && (defined EMCC || defined (EMCC2) ) // should directly interact with canvas + return gen(turtlevect2vecteur(turtle_stack()),_LOGO__VECT); +#endif + return res; + } + + gen _speed(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + if (g.type==_VECT && g._VECTptr->empty()) + return turtle_speed; + if (g.type!=_INT_) + return gensizeerr(contextptr); + int i=g.val; + if (i<0) i=0; + if (i>1000) i=1000; + turtle_speed=i; + return i; + } + static const char _speed_s []="speed"; + static define_unary_function_eval2 (__speed,&_speed,_speed_s,&printastifunction); + define_unary_function_ptr5( at_speed ,alias_at_speed,&__speed,0,T_LOGO); + + gen _avance(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + double i; + if (g.type!=_INT_){ + if (g.type==_VECT) + i=turtle_length; + else { + gen g1=evalf_double(g,1,contextptr); + if (g1.type==_DOUBLE_) + i=g1._DOUBLE_val; + else + return gensizeerr(contextptr); + } + } + else + i=g.val; + (*turtleptr).x += i * std::cos((*turtleptr).theta*deg2rad_d); + (*turtleptr).y += i * std::sin((*turtleptr).theta*deg2rad_d) ; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _avance_s []="avance"; + static define_unary_function_eval2 (__avance,&_avance,_avance_s,&printastifunction); + define_unary_function_ptr5( at_avance ,alias_at_avance,&__avance,0,T_LOGO); + + static const char _forward_s []="forward"; + static define_unary_function_eval (__forward,&_avance,_forward_s); + define_unary_function_ptr5( at_forward ,alias_at_forward,&__forward,0,true); + + gen _recule(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + if (g.type==_VECT) + return _avance(-turtle_length,contextptr); + return _avance(-g,contextptr); + } + static const char _recule_s []="recule"; + static define_unary_function_eval2 (__recule,&_recule,_recule_s,&printastifunction); + define_unary_function_ptr5( at_recule ,alias_at_recule,&__recule,0,T_LOGO); + + gen _towards(const gen & g,GIAC_CONTEXT){ + // logo instruction + if (g.type!=_VECT || g._VECTptr->size()!=2) + return gensizeerr(contextptr); + gen z=g._VECTptr->front()-(*turtleptr).x+cst_i*(g._VECTptr->back()-(*turtleptr).y); + int m=get_mode_set_radian(contextptr); + z=arg(z,contextptr); + angle_mode(m,contextptr); + return 180/M_PI*z; + } + static const char _towards_s []="towards"; + static define_unary_function_eval2 (__towards,&_towards,_towards_s,&printastifunction); + define_unary_function_ptr5( at_towards ,alias_at_towards,&__towards,0,T_LOGO); + + static const char _backward_s []="backward"; + static define_unary_function_eval (__backward,&_recule,_backward_s); + define_unary_function_ptr5( at_backward ,alias_at_backward,&__backward,0,true); + + gen _position(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + if (g.type!=_VECT) + return makevecteur((*turtleptr).x,(*turtleptr).y); + // return turtle_state(); + vecteur v = *g._VECTptr; + int s=int(v.size()); + if (!s) + return makevecteur((*turtleptr).x,(*turtleptr).y); + v[0]=evalf_double(v[0],1,contextptr); + if (s>1) + v[1]=evalf_double(v[1],1,contextptr); + if (s>2) + v[2]=evalf_double(v[2],1,contextptr); + if (set_turtle_state(v,contextptr)) + return update_turtle_state(true,contextptr); + return zero; + } + static const char _position_s []="position"; + static define_unary_function_eval2 (__position,&_position,_position_s,&printastifunction); + define_unary_function_ptr5( at_position ,alias_at_position,&__position,0,T_LOGO); + + gen _cap(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + gen gg=evalf_double(g,1,contextptr); + if (gg.type!=_DOUBLE_) + return double((*turtleptr).theta); + (*turtleptr).theta=gg._DOUBLE_val; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _cap_s []="cap"; + static define_unary_function_eval2 (__cap,&_cap,_cap_s,&printastifunction); + define_unary_function_ptr5( at_cap ,alias_at_cap,&__cap,0,T_LOGO); + + static const char _heading_s []="heading"; + static define_unary_function_eval (__heading,&_cap,_heading_s); + define_unary_function_ptr5( at_heading ,alias_at_heading,&__heading,0,true); + + + gen _tourne_droite(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + if (g.type!=_INT_){ + if (g.type==_VECT) + (*turtleptr).theta -= 90; + else { + gen g1=evalf_double(g,1,contextptr); + if (g1.type==_DOUBLE_) + (*turtleptr).theta -= g1._DOUBLE_val; + else + return gensizeerr(contextptr); + } + } + else + (*turtleptr).theta -= g.val; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _tourne_droite_s []="tourne_droite"; + static define_unary_function_eval2 (__tourne_droite,&_tourne_droite,_tourne_droite_s,&printastifunction); + define_unary_function_ptr5( at_tourne_droite ,alias_at_tourne_droite,&__tourne_droite,0,T_LOGO); + + gen _tourne_gauche(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + if (g.type==_VECT){ + (*turtleptr).theta += 90; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + return _tourne_droite(-g,contextptr); + } + static const char _tourne_gauche_s []="tourne_gauche"; + static define_unary_function_eval2 (__tourne_gauche,&_tourne_gauche,_tourne_gauche_s,&printastifunction); + define_unary_function_ptr5( at_tourne_gauche ,alias_at_tourne_gauche,&__tourne_gauche,0,T_LOGO); + + gen _leve_crayon(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + (*turtleptr).mark = false; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _leve_crayon_s []="leve_crayon"; + static define_unary_function_eval2 (__leve_crayon,&_leve_crayon,_leve_crayon_s,&printastifunction); + define_unary_function_ptr5( at_leve_crayon ,alias_at_leve_crayon,&__leve_crayon,0,T_LOGO); + + static const char _penup_s []="penup"; + static define_unary_function_eval (__penup,&_leve_crayon,_penup_s); + define_unary_function_ptr5( at_penup ,alias_at_penup,&__penup,0,T_LOGO); + + gen _baisse_crayon(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + (*turtleptr).mark = true; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _baisse_crayon_s []="baisse_crayon"; + static define_unary_function_eval2 (__baisse_crayon,&_baisse_crayon,_baisse_crayon_s,&printastifunction); + define_unary_function_ptr5( at_baisse_crayon ,alias_at_baisse_crayon,&__baisse_crayon,0,T_LOGO); + + static const char _pendown_s []="pendown"; + static define_unary_function_eval (__pendown,&_baisse_crayon,_pendown_s); + define_unary_function_ptr5( at_pendown ,alias_at_pendown,&__pendown,0,T_LOGO); + + vector * ecrisptr=0; + vector & ecristab(){ + if (!ecrisptr) + ecrisptr=new vector; + return * ecrisptr; + } + gen _ecris(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; +#if 0 //def TURTLETAB + return gensizeerr("String support does not work with static turtle table"); +#endif + // logo instruction + (*turtleptr).radius=14; + if (g.type==_VECT){ + vecteur & v =*g._VECTptr; + int s=int(v.size()); + if (s==2 && v[1].type==_INT_){ + (*turtleptr).radius=absint(v[1].val); + (*turtleptr).s=ecristab().size(); + ecristab().push_back(gen2string(v.front())); + return update_turtle_state(false,contextptr); + } + if (s==4 && v[1].type==_INT_ && v[2].type==_INT_ && v[3].type==_INT_){ + logo_turtle t=(*turtleptr); + _leve_crayon(0,contextptr); + _position(makevecteur(v[2],v[3]),contextptr); + (*turtleptr).radius=absint(v[1].val); + (*turtleptr).s=ecristab().size(); + ecristab().push_back(gen2string(v.front())); + update_turtle_state(false,contextptr); + (*turtleptr)=t; + return update_turtle_state(true,contextptr); + } + } + (*turtleptr).s=ecristab().size(); + ecristab().push_back(gen2string(g)); + return update_turtle_state(false,contextptr); + } + static const char _ecris_s []="ecris"; + static define_unary_function_eval2 (__ecris,&_ecris,_ecris_s,&printastifunction); + define_unary_function_ptr5( at_ecris ,alias_at_ecris,&__ecris,0,T_LOGO); + + gen _signe(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + return _ecris(makevecteur(g,20,10,10),contextptr); + } + static const char _signe_s []="signe"; + static define_unary_function_eval2 (__signe,&_signe,_signe_s,&printastifunction); + define_unary_function_ptr5( at_signe ,alias_at_signe,&__signe,0,T_LOGO); + + gen _saute(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + _leve_crayon(0,contextptr); + _avance(g,contextptr); + return _baisse_crayon(0,contextptr); + } + static const char _saute_s []="saute"; + static define_unary_function_eval2 (__saute,&_saute,_saute_s,&printastifunction); + define_unary_function_ptr5( at_saute ,alias_at_saute,&__saute,0,T_LOGO); + + static const char _jump_s []="jump"; + static define_unary_function_eval2 (__jump,&_saute,_jump_s,&printastifunction); + define_unary_function_ptr5( at_jump ,alias_at_jump,&__jump,0,T_LOGO); + + gen _pas_de_cote(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + _leve_crayon(0,contextptr); + _tourne_droite(-90,contextptr); + _avance(g,contextptr); + _tourne_droite(90,contextptr); + return _baisse_crayon(0,contextptr); + } + static const char _pas_de_cote_s []="pas_de_cote"; + static define_unary_function_eval2 (__pas_de_cote,&_pas_de_cote,_pas_de_cote_s,&printastifunction); + define_unary_function_ptr5( at_pas_de_cote ,alias_at_pas_de_cote,&__pas_de_cote,0,T_LOGO); + + static const char _skip_s []="skip"; + static define_unary_function_eval2 (__skip,&_pas_de_cote,_skip_s,&printastifunction); + define_unary_function_ptr5( at_skip ,alias_at_skip,&__skip,0,T_LOGO); + + gen _cache_tortue(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + (*turtleptr).visible=false; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _cache_tortue_s []="cache_tortue"; + static define_unary_function_eval2 (__cache_tortue,&_cache_tortue,_cache_tortue_s,&printastifunction); + define_unary_function_ptr5( at_cache_tortue ,alias_at_cache_tortue,&__cache_tortue,0,T_LOGO); + + static const char _hideturtle_s []="hideturtle"; + static define_unary_function_eval (__hideturtle,&_cache_tortue,_hideturtle_s); + define_unary_function_ptr5( at_hideturtle ,alias_at_hideturtle,&__hideturtle,0,true); + + gen _montre_tortue(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + (*turtleptr).visible=true; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _montre_tortue_s []="montre_tortue"; + static define_unary_function_eval2 (__montre_tortue,&_montre_tortue,_montre_tortue_s,&printastifunction); + define_unary_function_ptr5( at_montre_tortue ,alias_at_montre_tortue,&__montre_tortue,0,T_LOGO); + + static const char _showturtle_s []="showturtle"; + static define_unary_function_eval (__showturtle,&_montre_tortue,_showturtle_s); + define_unary_function_ptr5( at_showturtle ,alias_at_showturtle,&__showturtle,0,true); + + + gen _repete(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + if (g.type!=_VECT || g._VECTptr->size()<2) + return gensizeerr(contextptr); + // logo instruction + vecteur v = *g._VECTptr; + v[0]=eval(v[0],contextptr); + if (v.front().type!=_INT_) + return gentypeerr(contextptr); + gen prog=vecteur(v.begin()+1,v.end()); + int i=absint(v.front().val); + gen res; + for (int j=0;jsize()==3) + return _crayon(_rgb(g,contextptr),contextptr); + if (g.type!=_INT_){ + gen res=(*turtleptr).color; + res.subtype=_INT_COLOR; + return res; + } + if (g.val<0){ + if (g.val<-64) + return (*turtleptr).turtle_width; + (*turtleptr).turtle_width=-g.val; + } + else + (*turtleptr).color=g.val; + (*turtleptr).radius = 0; + return update_turtle_state(true,contextptr); + } + static const char _crayon_s []="crayon"; + static define_unary_function_eval2 (__crayon,&_crayon,_crayon_s,&printastifunction); + define_unary_function_ptr5( at_crayon ,alias_at_crayon,&__crayon,0,T_LOGO); + + static const char _pencolor_s []="pencolor"; + static define_unary_function_eval (__pencolor,&_crayon,_pencolor_s); + define_unary_function_ptr5( at_pencolor ,alias_at_pencolor,&__pencolor,0,T_LOGO); + + gen _efface_logo(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + if (g.type==_INT_){ + _crayon(int(FL_WHITE),contextptr); + _recule(g,contextptr); + return _crayon(0,contextptr); + } + // logo instruction + (*turtleptr) = logo_turtle(); +#ifdef TURTLETAB + turtle_stack_size=0; +#else + turtle_stack().clear(); +#endif + ecristab().clear(); + if (g.type==_VECT && g._VECTptr->size()==2){ + vecteur v = *g._VECTptr; + int s=int(v.size()); + v[0]=evalf_double(v[0],1,contextptr); + if (s>1) + v[1]=evalf_double(v[1],1,contextptr); + (*turtleptr).mark = false; // leve_crayon + (*turtleptr).radius = 0; + update_turtle_state(true,contextptr); + set_turtle_state(v,contextptr); // baisse_crayon + update_turtle_state(true,contextptr); + (*turtleptr).mark = true; + (*turtleptr).radius = 0; + } + return update_turtle_state(true,contextptr); + } + static const char _efface_logo_s []="efface"; + static define_unary_function_eval2 (__efface_logo,&_efface_logo,_efface_logo_s,&printastifunction); + define_unary_function_ptr5( at_efface_logo ,alias_at_efface_logo,&__efface_logo,0,T_LOGO); + + static const char _efface_s []="efface"; + static define_unary_function_eval2 (__efface,&_efface_logo,_efface_s,&printastifunction); + define_unary_function_ptr5( at_efface ,alias_at_efface,&__efface,0,T_LOGO); + + static const char _reset_s []="reset"; + static define_unary_function_eval2 (__reset,&_efface_logo,_reset_s,&printastifunction); + define_unary_function_ptr5( at_reset ,alias_at_reset,&__reset,0,T_LOGO); + + static const char _clearscreen_s []="clearscreen"; + static define_unary_function_eval2 (__clearscreen,&_efface_logo,_clearscreen_s,&printastifunction); + define_unary_function_ptr5( at_clearscreen ,alias_at_clearscreen,&__clearscreen,0,T_LOGO); + + gen _debut_enregistrement(const gen &g,GIAC_CONTEXT){ + return undef; + } + static const char _debut_enregistrement_s []="debut_enregistrement"; + static define_unary_function_eval2 (__debut_enregistrement,&_debut_enregistrement,_debut_enregistrement_s,&printastifunction); + define_unary_function_ptr5( at_debut_enregistrement ,alias_at_debut_enregistrement,&__debut_enregistrement,0,T_LOGO); + + static const char _fin_enregistrement_s []="fin_enregistrement"; + static define_unary_function_eval2 (__fin_enregistrement,&_debut_enregistrement,_fin_enregistrement_s,&printastifunction); + define_unary_function_ptr5( at_fin_enregistrement ,alias_at_fin_enregistrement,&__fin_enregistrement,0,T_LOGO); + + static const char _turtle_stack_s []="turtle_stack"; + static define_unary_function_eval2 (__turtle_stack,&_debut_enregistrement,_turtle_stack_s,&printastifunction); + define_unary_function_ptr5( at_turtle_stack ,alias_at_turtle_stack,&__turtle_stack,0,T_LOGO); + + gen _vers(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + if (g.type!=_VECT || g._VECTptr->size()!=2) + return gensizeerr(contextptr); + gen x=evalf_double(g._VECTptr->front(),1,contextptr), + y=evalf_double(g._VECTptr->back(),1,contextptr); + if (x.type!=_DOUBLE_ || y.type!=_DOUBLE_) + return gensizeerr(contextptr); + double xv=x._DOUBLE_val,yv=y._DOUBLE_val,xt=(*turtleptr).x,yt=(*turtleptr).y; + double theta=atan2(yv-yt,xv-xt); + return _cap(theta*180/M_PI,contextptr); + } + static const char _vers_s []="vers"; + static define_unary_function_eval2 (__vers,&_vers,_vers_s,&printastifunction); + define_unary_function_ptr5( at_vers ,alias_at_vers,&__vers,0,T_LOGO); + + static int find_radius(const gen & g,int & r,int & theta2,bool & direct){ + int radius; + direct=true; + theta2 = 360 ; + // logo instruction + if (g.type==_VECT && !g._VECTptr->empty()){ + vecteur v = *g._VECTptr; + bool seg=false; + if (v.back()==at_segment){ + v.pop_back(); + seg=true; + } + if (v.size()<2) + return RAND_MAX; // setdimerr(contextptr); + if (v[0].type==_INT_) + r=v[0].val; + else { + gen v0=evalf_double(v[0],1,context0); + if (v0.type==_DOUBLE_) + r=int(v0._DOUBLE_val+0.5); + else + return RAND_MAX; // setsizeerr(contextptr); + } + if (r<0){ + r=-r; + direct=false; + } + int theta1; + if (v[1].type==_DOUBLE_) + theta1=int(v[1]._DOUBLE_val+0.5); + else { + if (v[1].type==_INT_) + theta1=v[1].val; + else return RAND_MAX; // setsizeerr(contextptr); + } + while (theta1<0) + theta1 += 360; + if (v.size()>=3){ + if (v[2].type==_DOUBLE_) + theta2 = int(v[2]._DOUBLE_val+0.5); + else { + if (v[2].type==_INT_) + theta2 = v[2].val; + else return RAND_MAX; // setsizeerr(contextptr); + } + while (theta2<0) + theta2 += 360; + radius = giacmin(r,512) | (giacmin(theta1,360) << 9) | (giacmin(theta2,360) << 18 ) | (seg?(1<<28):0); + } + else {// angle 1=0 + theta2 = theta1; + if (theta2<0) + theta2 += 360; + radius = giacmin(r,512) | (giacmin(theta2,360) << 18 ) | (seg?(1<<28):0); + } + return radius; + } + radius = 10; + if (g.type==_INT_) + radius= (r=g.val); + if (g.type==_DOUBLE_) + radius= (r=int(g._DOUBLE_val)); + if (radius<=0){ + radius = -radius; + direct=false; + } + radius = giacmin(radius,512 )+(360 << 18) ; // 2nd angle = 360 degrees + return radius; + } + + void c_turtle_move(int r,int theta2){ + double theta0; + if ((*turtleptr).direct) + theta0=(*turtleptr).theta-90; + else { + theta0=(*turtleptr).theta+90; + theta2=-theta2; + } + (*turtleptr).x += r*(std::cos(M_PI/180*(theta2+theta0))-std::cos(M_PI/180*theta0)); + (*turtleptr).y += r*(std::sin(M_PI/180*(theta2+theta0))-std::sin(M_PI/180*theta0)); + (*turtleptr).theta = (*turtleptr).theta+theta2 ; + if ((*turtleptr).theta<0) + (*turtleptr).theta += 360; + if ((*turtleptr).theta>360) + (*turtleptr).theta -= 360; + } + + static void turtle_move(int r,int theta2,GIAC_CONTEXT){ + c_turtle_move(r,theta2); + } + gen _rond(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + int r,theta2,tmpr; + tmpr=find_radius(g,r,theta2,(*turtleptr).direct); + if (tmpr==RAND_MAX) + return gensizeerr(contextptr); + (*turtleptr).radius=tmpr; + turtle_move(r,theta2,contextptr); + return update_turtle_state(true,contextptr); + } + static const char _rond_s []="rond"; + static define_unary_function_eval2 (__rond,&_rond,_rond_s,&printastifunction); + define_unary_function_ptr5( at_rond ,alias_at_rond,&__rond,0,T_LOGO); + + gen _disque(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + int r,theta2,tmpr=find_radius(g,r,theta2,(*turtleptr).direct); + if (tmpr==RAND_MAX) + return gensizeerr(contextptr); + (*turtleptr).radius=tmpr; + turtle_move(r,theta2,contextptr); + (*turtleptr).radius += 1 << 27; + return update_turtle_state(true,contextptr); + } + static const char _disque_s []="disque"; + static define_unary_function_eval2 (__disque,&_disque,_disque_s,&printastifunction); + define_unary_function_ptr5( at_disque ,alias_at_disque,&__disque,0,T_LOGO); + + gen _disque_centre(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + int r,theta2; + bool direct; + int radius=find_radius(g,r,theta2,direct); + if (radius==RAND_MAX) + return gensizeerr(contextptr); + r=absint(r); + _saute(r,contextptr); + _tourne_gauche(direct?90:-90,contextptr); + (*turtleptr).radius = radius; + (*turtleptr).direct=direct; + turtle_move(r,theta2,contextptr); + (*turtleptr).radius += 1 << 27; + update_turtle_state(true,contextptr); + _tourne_droite(direct?90:-90,contextptr); + return _saute(-r,contextptr); + } + static const char _disque_centre_s []="disque_centre"; + static define_unary_function_eval2 (__disque_centre,&_disque_centre,_disque_centre_s,&printastifunction); + define_unary_function_ptr5( at_disque_centre ,alias_at_disque_centre,&__disque_centre,0,T_LOGO); + + gen _polygone_rempli(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + static int turtle_fill_begin=-1,turtle_fill_color=-1; + if (g.type==_VECT && g._VECTptr->size()==3){ + turtle_fill_color=_rgb(g,contextptr).val; + return change_subtype(turtle_fill_color,_INT_COLOR); + } + if (g.type==_VECT && !g._VECTptr->empty() && g._VECTptr->front().type==_INT_){ + if (g._VECTptr->front().val>=0) + turtle_fill_color= g._VECTptr->front().val; + return change_subtype(turtle_fill_color,_INT_COLOR); + } + if (g.type==_INT_ + //&& g.subtype==_INT_COLOR + ){ + if (g.val<-1 && g.val>-1024){ + (*turtleptr).radius=-absint(g.val); + if ((*turtleptr).radius<-1) + return update_turtle_state(true,contextptr); + } + turtle_fill_color= g.val; + return g; + } + if (g.type!=_VECT && is_zero(g)){ // 0.0 + turtle_fill_begin=turtle_stack().size(); + return 1; + } + if (g.type==_VECT && g._VECTptr->empty()){ + if (turtle_fill_begin<0){ + if (g.subtype==0) + turtle_fill_begin=turtle_stack().size(); + else + return gensizeerr(); + return 1; + } + int c=turtleptr->color; + if (turtle_fill_color>=0) + _crayon(turtle_fill_color,contextptr); + int n=turtle_stack().size()- turtle_fill_begin; + turtle_fill_begin=-1; + turtleptr->radius=-absint(n); + gen res=update_turtle_state(true,contextptr); + if (turtle_fill_color>=0){ + turtleptr->radius=0; + _crayon(c,contextptr); + } + return res; + } + return gensizeerr(gettext("Integer argument >= 2")); + } + static const char _polygone_rempli_s []="polygone_rempli"; + static define_unary_function_eval2 (__polygone_rempli,&_polygone_rempli,_polygone_rempli_s,&printastifunction); + define_unary_function_ptr5( at_polygone_rempli ,alias_at_polygone_rempli,&__polygone_rempli,0,T_LOGO); + + gen _rectangle_plein(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + gen gx=g,gy=g; + if (g.type==_VECT && g._VECTptr->size()==2){ + gx=g._VECTptr->front(); + gy=g._VECTptr->back(); + } + for (int i=0;i<2;++i){ + _avance(gx,contextptr); + _tourne_droite(-90,contextptr); + _avance(gy,contextptr); + _tourne_droite(-90,contextptr); + } + //for (int i=0;isize()>=2){ + vecteur & v=*g._VECTptr; + gx=v.front(); + gy=v[1]; + gtheta=90; + if (v.size()>2) + gtheta=v[2]; + } + logo_turtle t=(*turtleptr); + _avance(gx,contextptr); + double save_x=(*turtleptr).x,save_y=(*turtleptr).y; + _recule(gx,contextptr); + _tourne_gauche(gtheta,contextptr); + _avance(gy,contextptr); + (*turtleptr).x=save_x; + (*turtleptr).y=save_y; + update_turtle_state(true,contextptr); + (*turtleptr)=t; + (*turtleptr).radius=0; + update_turtle_state(true,contextptr); + return _polygone_rempli(-3,contextptr); + } + static const char _triangle_plein_s []="triangle_plein"; + static define_unary_function_eval2 (__triangle_plein,&_triangle_plein,_triangle_plein_s,&printastifunction); + define_unary_function_ptr5( at_triangle_plein ,alias_at_triangle_plein,&__triangle_plein,0,T_LOGO); + + gen _dessine_tortue(const gen & g,GIAC_CONTEXT){ + if ( g.type==_STRNG && g.subtype==-1) return g; + // logo instruction + /* + _triangle_plein(makevecteur(17,5)); + _tourne_droite(90); + _triangle_plein(makevecteur(5,17)); + return _tourne_droite(-90); + */ + double save_x=(*turtleptr).x,save_y=(*turtleptr).y; + _tourne_droite(90,contextptr); + _avance(5,contextptr); + _tourne_gauche(106,contextptr); + _avance(18,contextptr); + _tourne_gauche(148,contextptr); + _avance(18,contextptr); + _tourne_gauche(106,contextptr); + _avance(5,contextptr); + (*turtleptr).x=save_x; (*turtleptr).y=save_y; + gen res(_tourne_gauche(90,contextptr)); + if (is_one(g)) + return res; + return _polygone_rempli(-9,contextptr); + } + static const char _dessine_tortue_s []="dessine_tortue"; + static define_unary_function_eval2 (__dessine_tortue,&_dessine_tortue,_dessine_tortue_s,&printastifunction); + define_unary_function_ptr5( at_dessine_tortue ,alias_at_dessine_tortue,&__dessine_tortue,0,T_LOGO); +#endif //BW + +#ifndef NO_NAMESPACE_GIAC +} // namespace giac +#endif // ndef NO_NAMESPACE_GIAC + + +#ifndef NO_NAMESPACE_XCAS +namespace xcas { +#endif // ndef NO_NAMESPACE_XCAS + void drawRectangle(int x,int y,int w,int h,int c){ + //console_log(("drawRectangle "+print_INT_(x)+","+print_INT_(y)+" w="+print_INT_(w)+" h="+print_INT_(h)+" c="+print_INT_(c)).c_str()); +#ifdef BW + draw_rectangle(x,y,w,h,c); +#else + draw_rectangle(x,y,w,h,c,context0); +#endif + } +#ifndef BW + void draw_rectangle(int x,int y,int w,int h,int c){ + draw_rectangle(x,y,w,h,c,context0); + } +#endif + void draw_line(int x0,int y0,int x1,int y1,int c){ +#ifdef HP39 + draw_line(x0,y0,x1,y1,c,context0); +#else + if (x0==x1){ + if (y0<=y1) + draw_rectangle(x0,y0,1,y1-y0+1,c); + else + draw_rectangle(x0,y1,1,y0-y1+1,c); + } + else { + if (y0==y1){ + if (x0<=x1) + draw_rectangle(x0,y0,x1-x0+1,1,c); + else + draw_rectangle(x1,y0,x0-x1+1,1,c); + } + else + draw_line(x0,y0,x1,y1,c,context0); + } +#endif + } +#ifdef BW + void draw_polygon(std::vector< std::vector > & v1,int color,GIAC_CONTEXT){ + giac::draw_polygon(v1,color); + } + void draw_polygon(std::vector< std::vector > & v1,int color){ + giac::draw_polygon(v1,color); + } + void draw_circle(int xc,int yc,int r,int color,bool q1,bool q2,bool q3,bool q4){ + giac::draw_circle(xc,yc,r,color,q1,q2,q3,q4); + } + void draw_filled_circle(int xc,int yc,int r,int color,bool left,bool right){ + giac::draw_filled_circle(xc,yc,r,color,left,right); + } + void draw_filled_polygon(std::vector< vector > &L,int xmin,int xmax,int ymin,int ymax,int color){ + giac::draw_filled_polygon(L,xmin,xmax,ymin,ymax,color); + } + void draw_arc(int xc,int yc,int rx,int ry,int color,double theta1, double theta2){ + giac::draw_arc(xc,yc,rx,ry,color,theta1,theta2,giac::context0); + } + void draw_filled_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int color,int xmin,int xmax,int ymin,int ymax,bool segment){ + giac::draw_filled_arc(x,y,rx,ry,theta1_deg,theta2_deg,color,xmin,xmax,ymin,ymax,segment); + } +#else + void draw_circle(int xc,int yc,int r,int color,bool q1,bool q2,bool q3,bool q4){ + draw_circle(xc,yc,r,color,q1,q2,q3,q4,context0); + } + void draw_filled_circle(int xc,int yc,int r,int color,bool left,bool right){ + draw_filled_circle(xc,yc,r,color,left,right,context0); + } + void draw_polygon(std::vector< std::vector > & v1,int color){ + draw_polygon(v1,color,context0); + } + void draw_filled_polygon(std::vector< vector > &L,int xmin,int xmax,int ymin,int ymax,int color){ + draw_filled_polygon(L,xmin,xmax,ymin,ymax,color,context0); + } + void draw_arc(int xc,int yc,int rx,int ry,int color,double theta1, double theta2){ + draw_arc(xc,yc,rx,ry,color,theta1,theta2,giac::context0); + } + void draw_filled_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int color,int xmin,int xmax,int ymin,int ymax,bool segment){ + draw_filled_arc(x,y,rx,ry,theta1_deg,theta2_deg,color,xmin,xmax,ymin,ymax,segment,context0); + } + +#endif + + + unsigned max_prettyprint_equation=256; + + // make a free copy of g + gen Equation_copy(const gen & g){ + if (g.type==_EQW) + return *g._EQWptr; + if (g.type!=_VECT) + return g; + vecteur & v = *g._VECTptr; + const_iterateur it=v.begin(),itend=v.end(); + vecteur res; + res.reserve(itend-it); + for (;it!=itend;++it) + res.push_back(Equation_copy(*it)); + return gen(res,g.subtype); + } + + // matrix/list select + bool do_select(gen & eql,bool select,gen & value){ + if (eql.type==_VECT && !eql._VECTptr->empty()){ + vecteur & v=*eql._VECTptr; + size_t s=v.size(); + if (v[s-1].type!=_EQW) + return false; + v[s-1]._EQWptr->selected=select; + gen sommet=v[s-1]._EQWptr->g; + --s; + vecteur args(s); + for (size_t i=0;ig; + } + gen va=s==1?args[0]:gen(args,_SEQ__VECT); + if (sommet.type==_FUNC) + va=symbolic(*sommet._FUNCptr,va); + else + va=sommet(va,context0); + //cout << "va " << va << "\n"; + value=*v[s]._EQWptr; + value._EQWptr->g=va; + //cout << "value " << value << "\n"; + return true; + } + if (eql.type!=_EQW) + return false; + eql._EQWptr->selected=select; + value=eql; + return true; + } + + bool Equation_box_sizes(const gen & g,int & l,int & h,int & x,int & y,attributs & attr,bool & selected){ + if (g.type==_EQW){ + eqwdata & w=*g._EQWptr; + x=w.x; + y=w.y; + l=w.dx; + h=w.dy; + selected=w.selected; + attr=w.eqw_attributs; + //cout << g << "\n"; + return true; + } + else { + if (g.type!=_VECT || g._VECTptr->empty() ){ + l=0; + h=0; + x=0; + y=0; + attr=attributs(0,0,0); + selected=false; + return true; + } + gen & g1=g._VECTptr->back(); + Equation_box_sizes(g1,l,h,x,y,attr,selected); + return false; + } + } + + // return true if g has some selection inside, gsel points to the selection + bool Equation_adjust_xy(gen & g,int & xleft,int & ytop,int & xright,int & ybottom,gen * & gsel,gen * & gselparent,int &gselpos,std::vector * goto_ptr){ + gsel=0; + gselparent=0; + gselpos=0; + int x,y,w,h; + attributs f(0,0,0); + bool selected; + Equation_box_sizes(g,w,h,x,y,f,selected); + if ( (g.type==_EQW__VECT) || selected ){ // terminal or selected + xleft=x; + ybottom=y; + if (selected){ // g is selected + ytop=y+h; + xright=x+w; + gsel = &g; + //cout << "adjust " << *gsel << "\n"; + return true; + } + else { // no selection + xright=x; + ytop=y; + return false; + } + } + if (g.type!=_VECT) + return false; + // last not selected, recurse + iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end()-1; + for (;it!=itend;++it){ + if (Equation_adjust_xy(*it,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,goto_ptr)){ + if (goto_ptr){ + goto_ptr->push_back(it-g._VECTptr->begin()); + //cout << g << ":" << *goto_ptr << "\n"; + } + if (gsel==&*it){ + // check next siblings + + gselparent= &g; + gselpos=it-g._VECTptr->begin(); + //cout << "gselparent " << g << "\n"; + } + return true; + } + } + return false; + } + + // select or deselect part of the current eqution + // This is done *in place* + void Equation_select(gen & g,bool select){ + if (g.type==_EQW){ + eqwdata & e=*g._EQWptr; + e.selected=select; + } + if (g.type!=_VECT) + return; + vecteur & v=*g._VECTptr; + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + Equation_select(*it,select); + } + + // decrease selection (like HP49 eqw Down key) + int eqw_select_down(gen & g){ + int xleft,ytop,xright,ybottom,gselpos; + int newxleft,newytop,newxright,newybottom; + gen * gsel,*gselparent; + if (Equation_adjust_xy(g,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos)){ + //cout << "select down before " << *gsel << "\n"; + if (gsel->type==_VECT && !gsel->_VECTptr->empty()){ + Equation_select(*gsel,false); + Equation_select(gsel->_VECTptr->front(),true); + //cout << "select down after " << *gsel << "\n"; + Equation_adjust_xy(g,newxleft,newytop,newxright,newybottom,gsel,gselparent,gselpos); + return newytop-ytop; + } + } + return 0; + } + + int eqw_select_up(gen & g){ + int xleft,ytop,xright,ybottom,gselpos; + int newxleft,newytop,newxright,newybottom; + gen * gsel,*gselparent; + if (Equation_adjust_xy(g,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos) && gselparent){ + Equation_select(*gselparent,true); + //cout << "gselparent " << *gselparent << "\n"; + Equation_adjust_xy(g,newxleft,newytop,newxright,newybottom,gsel,gselparent,gselpos); + return newytop-ytop; + } + return false; + } + + // exchange==0 move selection to left or right sibling, ==2 add left or right + // sibling, ==1 exchange selection with left or right sibling + int eqw_select_leftright(Equation & eq,bool left,int exchange,GIAC_CONTEXT){ + gen & g=eq.data; + int xleft,ytop,xright,ybottom,gselpos; + int newxleft,newytop,newxright,newybottom; + gen * gsel,*gselparent; + vector goto_sel; + if (Equation_adjust_xy(g,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel) && gselparent && gselparent->type==_VECT){ + vecteur & gselv=*gselparent->_VECTptr; + int n=gselv.size()-1,gselpos_orig=gselpos; + if (n<1) return 0; + if (left) { + if (gselpos==0) + gselpos=n-1; + else + gselpos--; + } + else { + if (gselpos==n-1) + gselpos=0; + else + gselpos++; + } + if (exchange==1){ // exchange gselpos_orig and gselpos + swapgen(gselv[gselpos],gselv[gselpos_orig]); + gsel=&gselv[gselpos_orig]; + gen value; + if (xcas::do_select(*gsel,true,value) && value.type==_EQW) + replace_selection(eq,value._EQWptr->g,gsel,&goto_sel,contextptr); + } + else { + // increase selection to next sibling possible for + and * only + if (n>2 && exchange==2 && gselv[n].type==_EQW && (gselv[n]._EQWptr->g==at_plus || gselv[n]._EQWptr->g==at_prod)){ + gen value1, value2,tmp; + if (gselpos_origg==at_plus?value1._EQWptr->g+value2._EQWptr->g:value1._EQWptr->g*value2._EQWptr->g; + gselv.erase(gselv.begin()+gselpos_orig); + replace_selection(eq,tmp,&gselv[gselpos],&goto_sel,contextptr); + } + } + else { + Equation_select(*gselparent,false); + gen & tmp=(*gselparent->_VECTptr)[gselpos]; + Equation_select(tmp,true); + } + } + Equation_adjust_xy(g,newxleft,newytop,newxright,newybottom,gsel,gselparent,gselpos); + return newxleft-xleft; + } + return 0; + } + + bool eqw_select(const gen & eq,int l,int c,bool select,gen & value){ + value=undef; + if (l<0 || eq.type!=_VECT || eq._VECTptr->size()<=l) + return false; + gen & eql=(*eq._VECTptr)[l]; + if (c<0) + return do_select(eql,select,value); + if (eql.type!=_VECT || eql._VECTptr->size()<=c) + return false; + gen & eqlc=(*eql._VECTptr)[c]; + return do_select(eqlc,select,value); + } + + gen Equation_compute_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT); + + // void Bdisp_MMPrint(int x, int y, const char* string, int mode_flags, int xlimit, int P6, int P7, int color, int back_color, int writeflag, int P11); + // void PrintCXY(int x, int y, const char *cptr, int mode_flags, int P5, int color, int back_color, int P8, int P9) + // void PrintMini( int* x, int* y, const char* string, int mode_flags, unsigned int xlimit, int P6, int P7, int color, int back_color, int writeflag, int P11) + void text_print(int fontsize,const char * s,int x,int y,int c=COLOR_BLACK,int bg=COLOR_WHITE,int mode=0){ + // *logptr(contextptr) << x << " " << y << " " << fontsize << " " << s << "\n"; return; + c=(unsigned short) c; +#ifndef HP39 + if (mode==4 && c==COLOR_BLACK && bg==COLOR_WHITE){ + bg=color_gris; + mode=0; + } +#endif + if (x>LCD_WIDTH_PX) return; + int ss=strlen(s); + if (ss==1 && s[0]==0x1e){ // arrow for limit + if (mode==4) + c=bg; + draw_line(x,y-4,x+fontsize/2,y-4,c); + draw_line(x,y-3,x+fontsize/2,y-3,c); + draw_line(x+fontsize/2-4,y,x+fontsize/2,y-4,c); + draw_line(x+fontsize/2-3,y,x+fontsize/2+1,y-4,c); + draw_line(x+fontsize/2-4,y-7,x+fontsize/2,y-3,c); + draw_line(x+fontsize/2-3,y-7,x+fontsize/2+1,y-3,c); + return; + } + if (ss==2 && strcmp(s,"pi")==0){ + if (mode==4){ + drawRectangle(x,y+2-fontsize,fontsize,fontsize,c); + c=bg; + } + draw_line(x+fontsize/3-1,y+1,x+fontsize/3,y+6-fontsize,c); + draw_line(x+fontsize/3-2,y+1,x+fontsize/3-1,y+6-fontsize,c); + draw_line(x+2*fontsize/3,y+1,x+2*fontsize/3,y+6-fontsize,c); + draw_line(x+2*fontsize/3+1,y+1,x+2*fontsize/3+1,y+6-fontsize,c); + draw_line(x+2,y+6-fontsize,x+fontsize,y+6-fontsize,c); + draw_line(x+2,y+5-fontsize,x+fontsize,y+5-fontsize,c); + return; + } + if (fontsize>=16 && ss==2 && s[0]==char(0xe5) && (s[1]==char(0xea) || s[1]==char(0xeb))) // special handling for increasing and decreasing in tabvar output + fontsize=18; + if (fontsize>=18){ + y -= 16;// status area shift + os_draw_string(x,y,mode==4?bg:c,mode==4?c:bg,s); + // PrintMini(&x,&y,(unsigned char *)s,mode,0xffffffff,0,0,c,bg,1,0); + return; + } + y -= 12; + x=os_draw_string_small(x,y,mode==4?bg:c,mode==4?c:bg,s);// PrintMiniMini( &x, &y, (unsigned char *)s, mode,c, 0 ); + return; + } + + int text_width(int fontsize,const char * s){ +#ifdef NSPIRE_NEWLIB + int x=0; + if (fontsize>=18) + x=os_draw_string(0,0,0,1,s,true); + else + x=os_draw_string_small(0,0,0,1,s,true); + return x; +#else + if (fontsize>=18) + return strlen(s)*11; + return strlen(s)*7; +#endif + } + + int fl_width(const char * s){ + return text_width(14,s); + } + + void fl_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int c=COLOR_BLACK){ + rx/=2; + ry/=2; + // *logptr(contextptr) << "theta " << theta1_deg << " " << theta2_deg << "\n"; + if (ry==rx){ + if (theta2_deg-theta1_deg==360){ + draw_circle(x+rx,y+rx,rx,c); + return; + } + if (theta1_deg==0 && theta2_deg==180){ + draw_circle(x+rx,y+rx,rx,c,true,true,false,false); + return; + } + if (theta1_deg==180 && theta2_deg==360){ + draw_circle(x+rx,y+rx,rx,c,false,false,true,true); + return; + } + } + // *logptr(contextptr) << "draw_arc" << theta1_deg*M_PI/180. << " " << theta2_deg*M_PI/180. << "\n"; + draw_arc(x+rx,y+ry,rx,ry,c,theta1_deg*M_PI/180.,theta2_deg*M_PI/180.,context0); + } + + void fl_pie(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int c=COLOR_BLACK,bool segment=false){ + //cout << "fl_pie " << theta1_deg << " " << theta2_deg << " " << c << "\n"; + if (!segment && ry==rx){ + if (theta2_deg-theta1_deg>=360){ + rx/=2; + draw_filled_circle(x+rx,y+rx,rx,c); + return; + } + if (theta1_deg==-90 && theta2_deg==90){ + rx/=2; + draw_filled_circle(x+rx,y+rx,rx,c,false,true); + return; + } + if (theta1_deg==90 && theta2_deg==270){ + rx/=2; + draw_filled_circle(x+rx,y+rx,rx,c,true,false); + return; + } + } + // approximation by a filled polygon + // points: (x,y), (x+rx*cos(theta)/2,y+ry*sin(theta)/2) theta=theta1..theta2 + while (theta2_deg=360){ + theta1_deg=0; + theta2_deg=360; + } + int N0=theta2_deg-theta1_deg+1; + // reduce N if rx or ry is small + double red=double(rx)/LCD_WIDTH_PX*double(ry)/LCD_HEIGHT_PX; + if (red>1) red=1; + if (red<0.1) red=0.1; + int N=red*N0; + if (N<5) + N=N0>5?5:N0; + if (N<2) + N=2; + vector< vector > v(segment?N+1:N+2,vector(2)); + x += rx/2; + y += ry/2; + int i=0; + if (!segment){ + v[0][0]=x; + v[0][1]=y; + ++i; + } + double theta=theta1_deg*M_PI/180; + double thetastep=(theta2_deg-theta1_deg)*M_PI/(180*(N-1)); + for (;iempty()) + return eqwdata(0,0,0,0,attributs(0,0,0),undef); + return Equation_total_size(g._VECTptr->back()); + } + + // find smallest value of y and height + void Equation_y_dy(const gen & g,int & y,int & dy){ + y=0; dy=0; + if (g.type==_EQW){ + y=g._EQWptr->y; + dy=g._EQWptr->dy; + } + if (g.type==_VECT){ + iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + for (;it!=itend;++it){ + int Y,dY; + Equation_y_dy(*it,Y,dY); + // Y, Y+dY and y,y+dy + int ymax=giacmax(y+dy,Y+dY); + if (Yx += deltax; + g._EQWptr->y += deltay; + g._EQWptr->baseline += deltay; + return ; + } + if (g.type!=_VECT) + setsizeerr(); + vecteur & v=*g._VECTptr; + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + Equation_translate(*it,deltax,deltay); + } + + gen Equation_change_attributs(const gen & g,const attributs & newa){ + if (g.type==_EQW){ + gen res(*g._EQWptr); + res._EQWptr->eqw_attributs = newa; + return res; + } + if (g.type!=_VECT) + return gensizeerr(); + vecteur v=*g._VECTptr; + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it) + *it=Equation_change_attributs(*it,newa); + return gen(v,g.subtype); + } + + vecteur Equation_subsizes(const gen & arg,const attributs & a,int windowhsize,GIAC_CONTEXT){ + vecteur v; + if ( (arg.type==_VECT) && ( (arg.subtype==_SEQ__VECT) + // || (!ckmatrix(arg)) + ) ){ + const_iterateur it=arg._VECTptr->begin(),itend=arg._VECTptr->end(); + for (;it!=itend;++it) + v.push_back(Equation_compute_size(*it,a,windowhsize,contextptr)); + } + else { + v.push_back(Equation_compute_size(arg,a,windowhsize,contextptr)); + } + return v; + } + + // vertical merge with same baseline + // for vertical merge of hp,yp at top (like ^) add fontsize to yp + // at bottom (like lower bound of int) subtract fontsize from yp + void Equation_vertical_adjust(int hp,int yp,int & h,int & y){ + int yf=min(y,yp); + h=max(y+h,yp+hp)-yf; + y=yf; + } + + gen Equation_compute_symb_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT){ + if (g.type!=_SYMB) + return Equation_compute_size(g,a,windowhsize,contextptr); + unary_function_ptr & u=g._SYMBptr->sommet; + gen arg=g._SYMBptr->feuille,rootof_value; + if (u==at_makevector){ + vecteur v(1,arg); + if (arg.type==_VECT) + v=*arg._VECTptr; + iterateur it=v.begin(),itend=v.end(); + for (;it!=itend;++it){ + if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_makevector) ) + *it=_makevector(it->_SYMBptr->feuille,contextptr); + } + return Equation_compute_size(v,a,windowhsize,contextptr); + } + if (u==at_makesuite){ + if (arg.type==_VECT) + return Equation_compute_size(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr); + else + return Equation_compute_size(arg,a,windowhsize,contextptr); + } + if (u==at_sqrt) + return Equation_compute_size(symb_pow(arg,plus_one_half),a,windowhsize,contextptr); + if (u==at_division){ + if (arg.type!=_VECT || arg._VECTptr->size()!=2) + return Equation_compute_size(arg,a,windowhsize,contextptr); + gen tmp=Tfraction(arg._VECTptr->front(),arg._VECTptr->back()); + return Equation_compute_size(tmp,a,windowhsize,contextptr); + } + if (u==at_prod){ + gen n,d; + if (rewrite_prod_inv(arg,n,d)){ + if (n.is_symb_of_sommet(at_neg)) + return Equation_compute_size(symbolic(at_neg,Tfraction(-n,d)),a,windowhsize,contextptr); + return Equation_compute_size(Tfraction(n,d),a,windowhsize,contextptr); + } + } + if (u==at_inv){ + if ( (is_integer(arg) && is_positive(-arg,contextptr)) + || (arg.is_symb_of_sommet(at_neg))) + return Equation_compute_size(symbolic(at_neg,Tfraction(plus_one,-arg)),a,windowhsize,contextptr); + return Equation_compute_size(Tfraction(plus_one,arg),a,windowhsize,contextptr); + } + if (u==at_expr && arg.type==_VECT && arg.subtype==_SEQ__VECT && arg._VECTptr->size()==2 && arg._VECTptr->back().type==_INT_){ + gen varg1=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr); + eqwdata vv(Equation_total_size(varg1)); + gen varg2=eqwdata(0,0,0,0,a,arg._VECTptr->back()); + vecteur v12(makevecteur(varg1,varg2)); + v12.push_back(eqwdata(vv.dx,vv.dy,0,vv.y,a,at_expr,0)); + return gen(v12,_SEQ__VECT); + } + int llp=int(text_width(a.fontsize,("(")))-1; + int lrp=llp; + int lc=int(text_width(a.fontsize,(","))); + string us=u.ptr()->s; + int ls=int(text_width(a.fontsize,(us.c_str()))); + // if (my_isalpha(u.ptr()->s[0])) ls += 1; + if (u==at_abs) + ls = 2; + // special cases first int, sigma, /, ^ + // and if printed as printsommetasoperator + // otherwise print with usual functional notation + int x=0; + int h=a.fontsize; + int y=0; +#if 1 + if ((u==at_integrate) || (u==at_sum) ){ // Int + int s=1; + if (arg.type==_VECT) + s=arg._VECTptr->size(); + else + arg=vecteur(1,arg); + // s==1 -> general case + if ( (s==1) || (s==2) ){ // int f(x) dx and sum f(n) n + vecteur v(Equation_subsizes(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr)); + eqwdata vv(Equation_total_size(v[0])); + if (s==1){ + x=a.fontsize; + Equation_translate(v[0],x,0); + x += int(text_width(a.fontsize,(" dx"))); + } + if (s==2){ + if (u==at_integrate){ + x=a.fontsize; + Equation_translate(v[0],x,0); + x += vv.dx+int(text_width(a.fontsize,(" d"))); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + vv=Equation_total_size(v[1]); + Equation_translate(v[1],x,0); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + } + else { + Equation_vertical_adjust(vv.dy,vv.y,h,y); + eqwdata v1=Equation_total_size(v[1]); + x=max((int)a.fontsize,(int)v1.dx)+2*a.fontsize/3; // var name size + Equation_translate(v[1],0,-v1.dy-v1.y); + Equation_vertical_adjust(v1.dy,-v1.dy,h,y); + Equation_translate(v[0],x,0); + x += vv.dx; // add function size + } + } + if (u==at_integrate){ + x += vv.dx; + if (h==a.fontsize) + h+=2*a.fontsize/3; + if (y==0){ + y=-2*a.fontsize/3; + h+=2*a.fontsize/3; + } + } + v.push_back(eqwdata(x,h,0,y,a,u,0)); + return gen(v,_SEQ__VECT); + } + if (s>=3){ // int _a^b f(x) dx + vecteur & intarg=*arg._VECTptr; + gen tmp_l,tmp_u,tmp_f,tmp_x; + attributs aa(a); + if (a.fontsize>=10) + aa.fontsize -= 2; + tmp_f=Equation_compute_size(intarg[0],a,windowhsize,contextptr); + tmp_x=Equation_compute_size(intarg[1],a,windowhsize,contextptr); + tmp_l=Equation_compute_size(intarg[2],aa,windowhsize,contextptr); + if (s==4) + tmp_u=Equation_compute_size(intarg[3],aa,windowhsize,contextptr); + x=a.fontsize+(u==at_integrate?-2:+4); + eqwdata vv(Equation_total_size(tmp_l)); + Equation_translate(tmp_l,x,-vv.y-vv.dy); + vv=Equation_total_size(tmp_l); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + int lx = vv.dx; + if (s==4){ + vv=Equation_total_size(tmp_u); + Equation_translate(tmp_u,x,a.fontsize-3-vv.y); + vv=Equation_total_size(tmp_u); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + } + x += max(lx,(int)vv.dx); + Equation_translate(tmp_f,x,0); + vv=Equation_total_size(tmp_f); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + if (u==at_integrate){ + x += vv.dx+int(text_width(a.fontsize,(" d"))); + Equation_translate(tmp_x,x,0); + vv=Equation_total_size(tmp_x); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + x += vv.dx; + } + else { + x += vv.dx; + Equation_vertical_adjust(vv.dy,vv.y,h,y); + vv=Equation_total_size(tmp_x); + x=max(x,(int)vv.dx)+a.fontsize/3; + Equation_translate(tmp_x,0,-vv.dy-vv.y); + //Equation_translate(tmp_l,0,-1); + if (s==4) Equation_translate(tmp_u,-2,0); + Equation_vertical_adjust(vv.dy,-vv.dy,h,y); + } + vecteur res(makevecteur(tmp_f,tmp_x,tmp_l)); + if (s==4) + res.push_back(tmp_u); + res.push_back(eqwdata(x,h,0,y,a,u,0)); + return gen(res,_SEQ__VECT); + } + } + if (u==at_limit && arg.type==_VECT){ // limit + vecteur limarg=*arg._VECTptr; + int s=limarg.size(); + if (s==2 && limarg[1].is_symb_of_sommet(at_equal)){ + limarg.push_back(limarg[1]._SYMBptr->feuille[1]); + limarg[1]=limarg[1]._SYMBptr->feuille[0]; + ++s; + } + if (s>=3){ + gen tmp_l,tmp_f,tmp_x,tmp_dir; + attributs aa(a); + if (a.fontsize>=10) + aa.fontsize -= 2; + tmp_f=Equation_compute_size(limarg[0],a,windowhsize,contextptr); + tmp_x=Equation_compute_size(limarg[1],aa,windowhsize,contextptr); + tmp_l=Equation_compute_size(limarg[2],aa,windowhsize,contextptr); + if (s==4) + tmp_dir=Equation_compute_size(limarg[3],aa,windowhsize,contextptr); + eqwdata vf(Equation_total_size(tmp_f)); + eqwdata vx(Equation_total_size(tmp_x)); + eqwdata vl(Equation_total_size(tmp_l)); + eqwdata vdir(Equation_total_size(tmp_dir)); + int sous=max(vx.dy,vl.dy); + if (s==4) + Equation_translate(tmp_f,vx.dx+vl.dx+vdir.dx+a.fontsize+4,0); + else + Equation_translate(tmp_f,vx.dx+vl.dx+a.fontsize+2,0); + Equation_translate(tmp_x,0,-sous-vl.y); + Equation_translate(tmp_l,vx.dx+a.fontsize+2,-sous-vl.y); + if (s==4) + Equation_translate(tmp_dir,vx.dx+vl.dx+a.fontsize+4,-sous-vl.y); + h=vf.dy; + y=vf.y; + vl=Equation_total_size(tmp_l); + Equation_vertical_adjust(vl.dy,vl.y,h,y); + vecteur res(makevecteur(tmp_f,tmp_x,tmp_l)); + if (s==4){ + res.push_back(tmp_dir); + res.push_back(eqwdata(vf.dx+vx.dx+a.fontsize+4+vl.dx+vdir.dx,h,0,y,a,u,0)); + } + else + res.push_back(eqwdata(vf.dx+vx.dx+a.fontsize+2+vl.dx,h,0,y,a,u,0)); + return gen(res,_SEQ__VECT); + } + } +#endif + if ( (u==at_of || u==at_at) && arg.type==_VECT && arg._VECTptr->size()==2 ){ + // user function, function in 1st arg, arguments in 2nd arg + gen varg1=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr); + eqwdata vv=Equation_total_size(varg1); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + gen arg2=arg._VECTptr->back(); + if (u==at_at && xcas_mode(contextptr)!=0){ + if (arg2.type==_VECT) + arg2=gen(addvecteur(*arg2._VECTptr,vecteur(arg2._VECTptr->size(),plus_one)),_SEQ__VECT); + else + arg2=arg2+plus_one; + } + gen varg2=Equation_compute_size(arg2,a,windowhsize,contextptr); + Equation_translate(varg2,vv.dx+llp,0); + vv=Equation_total_size(varg2); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + vecteur res(makevecteur(varg1,varg2)); + res.push_back(eqwdata(vv.dx+vv.x+lrp,h,0,y,a,u,0)); + return gen(res,_SEQ__VECT); + } + if (u==at_pow){ + // first arg not translated + gen varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr); + eqwdata vv=Equation_total_size(varg); + // 1/2 ->sqrt, otherwise as exponent + if (arg._VECTptr->back()==plus_one_half){ + Equation_translate(varg,a.fontsize,0); + vecteur res(1,varg); + res.push_back(eqwdata(vv.dx+a.fontsize,vv.dy+4,vv.x,vv.y,a,at_sqrt,0)); + return gen(res,_SEQ__VECT); + } + bool needpar=vv.g.type==_FUNC || vv.g.is_symb_of_sommet(at_pow) || need_parenthesis(vv.g); + if (needpar) + x=llp; + Equation_translate(varg,x,0); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + vecteur res(1,varg); + // 2nd arg translated + if (needpar) + x+=vv.dx+lrp; + else + x+=vv.dx+1; + int arg1dy=vv.dy,arg1y=vv.y; + if (a.fontsize>=16){ + attributs aa(a); + aa.fontsize -= 2; + varg=Equation_compute_size(arg._VECTptr->back(),aa,windowhsize,contextptr); + } + else + varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr); + vv=Equation_total_size(varg); + Equation_translate(varg,x,arg1y+(3*arg1dy)/4-vv.y); + res.push_back(varg); + vv=Equation_total_size(varg); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + x += vv.dx; + res.push_back(eqwdata(x,h,0,y,a,u,0)); + return gen(res,_SEQ__VECT); + } + if (u==at_factorial){ + vecteur v; + gen varg=Equation_compute_size(arg,a,windowhsize,contextptr); + eqwdata vv=Equation_total_size(varg); + bool paren=need_parenthesis(vv.g) || vv.g==at_prod || vv.g==at_division || vv.g==at_pow; + if (paren) + x+=llp; + Equation_translate(varg,x,0); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + v.push_back(varg); + x += vv.dx; + if (paren) + x+=lrp; + varg=eqwdata(x+4,h,0,y,a,u,0); + v.push_back(varg); + return gen(v,_SEQ__VECT); + } + if (u==at_sto){ // A:=B, *it -> B + gen varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr); + eqwdata vv=Equation_total_size(varg); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + Equation_translate(varg,x,0); + vecteur v(2); + v[1]=varg; + x+=vv.dx; + x+=ls+3; + // first arg not translated + varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr); + vv=Equation_total_size(varg); + if (need_parenthesis(vv.g)) + x+=llp; + Equation_translate(varg,x,0); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + v[0]=varg; + x += vv.dx; + if (need_parenthesis(vv.g)) + x+=lrp; + v.push_back(eqwdata(x,h,0,y,a,u,0)); + return gen(v,_SEQ__VECT); + } + if (u==at_program && arg._VECTptr->back().type!=_VECT && !arg._VECTptr->back().is_symb_of_sommet(at_local) ){ + gen varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr); + eqwdata vv=Equation_total_size(varg); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + Equation_translate(varg,x,0); + vecteur v(2); + v[0]=varg; + x+=vv.dx; + x+=int(text_width(a.fontsize,("->")))+3; + varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr); + vv=Equation_total_size(varg); + Equation_translate(varg,x,0); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + v[1]=varg; + x += vv.dx; + v.push_back(eqwdata(x,h,0,y,a,u,0)); + return gen(v,_SEQ__VECT); + } + bool binaryop= (u.ptr()->printsommet==&printsommetasoperator) || binary_op(u); + if ( u!=at_sto && u.ptr()->printsommet!=NULL && !binaryop ){ + gen tmp=string2gen(g.print(contextptr),false); + return Equation_compute_size(symbolic(at_expr,makesequence(tmp,xcas_mode(contextptr))),a,windowhsize,contextptr); + } + vecteur v; + if (!binaryop || arg.type!=_VECT) + v=Equation_subsizes(arg,a,windowhsize,contextptr); + else + v=Equation_subsizes(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr); + iterateur it=v.begin(),itend=v.end(); + if ( it==itend || (itend-it==1) ){ + gen gtmp; + if (it==itend) + gtmp=Equation_compute_size(gen(vecteur(0),_SEQ__VECT),a,windowhsize,contextptr); + else + gtmp=*it; + // unary op, shift arg position horizontally + eqwdata vv=Equation_total_size(gtmp); + bool paren = u!=at_neg || (vv.g!=at_prod && need_parenthesis(vv.g)) ; + x=ls+(paren?llp:0); + gen tmp=gtmp; Equation_translate(tmp,x,0); + x=x+vv.dx+(paren?lrp:0); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + return gen(makevecteur(tmp,eqwdata(x,h,0,y,a,u,0)),_EQW__VECT); + } + if (binaryop){ // op (default with par) + int currenth=h,largeur=0; + iterateur itprec=v.begin(); + h=0; + if (u==at_plus){ // op without parenthesis + if (it->type==_VECT && !it->_VECTptr->empty() && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_equal) + ; + else { + llp=0; + lrp=0; + } + } + for (;;){ + eqwdata vv=Equation_total_size(*it); + if (need_parenthesis(vv.g)) + x+=llp; + if (u==at_plus && it!=v.begin() && + ( + (it->type==_VECT && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_neg) + || + ( it->type==_EQW && (is_integer(it->_EQWptr->g) || it->_EQWptr->g.type==_DOUBLE_) && is_strictly_positive(-it->_EQWptr->g,contextptr) ) + ) + ) + x -= ls; +#if 0 // + if (x>windowhsize-vv.dx && x>windowhsize/2 && (itend-it)*vv.dx>windowhsize/2){ + largeur=max(x,largeur); + x=0; + if (need_parenthesis(vv.g)) + x+=llp; + h+=currenth; + Equation_translate(*it,x,0); + for (iterateur kt=v.begin();kt!=itprec;++kt) + Equation_translate(*kt,0,currenth); + if (y){ + for (iterateur kt=itprec;kt!=it;++kt) + Equation_translate(*kt,0,-y); + } + itprec=it; + currenth=vv.dy; + y=vv.y; + } + else +#endif + { + Equation_translate(*it,x,0); + vv=Equation_total_size(*it); + Equation_vertical_adjust(vv.dy,vv.y,currenth,y); + } + x+=vv.dx; + if (need_parenthesis(vv.g)) + x+=lrp; + ++it; + if (it==itend){ + for (iterateur kt=v.begin();kt!=itprec;++kt) + Equation_translate(*kt,0,currenth+y); + h+=currenth; + v.push_back(eqwdata(max(x,largeur),h,0,y,a,u,0)); + //cout << v << "\n"; + return gen(v,_SEQ__VECT); + } + x += ls+3; + } + } + // normal printing + x=ls+llp; + for (;;){ + eqwdata vv=Equation_total_size(*it); + Equation_translate(*it,x,0); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + x+=vv.dx; + ++it; + if (it==itend){ + x+=lrp; + v.push_back(eqwdata(x,h,0,y,a,u,0)); + return gen(v,_SEQ__VECT); + } + x+=lc; + } + } + + // windowhsize is used for g of type HIST__VECT (history) right justify answers + // Returns either a eqwdata type object (terminal) or a vector + // (of subtype _EQW__VECT or _HIST__VECT) + gen Equation_compute_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT){ + /***************** + * FRACTIONS * + *****************/ + if (g.type==_FRAC){ + if (is_integer(g._FRACptr->num) && is_positive(-g._FRACptr->num,contextptr)) + return Equation_compute_size(symbolic(at_neg,fraction(-g._FRACptr->num,g._FRACptr->den)),a,windowhsize,contextptr); + gen v1=Equation_compute_size(g._FRACptr->num,a,windowhsize,contextptr); + eqwdata vv1=Equation_total_size(v1); + gen v2=Equation_compute_size(g._FRACptr->den,a,windowhsize,contextptr); + eqwdata vv2=Equation_total_size(v2); + // Center the fraction + int w1=vv1.dx,w2=vv2.dx; + int w=max(w1,w2)+6; + vecteur v(3); + v[0]=v1; Equation_translate(v[0],(w-w1)/2,11-vv1.y); + v[1]=v2; Equation_translate(v[1],(w-w2)/2,5-vv2.dy-vv2.y); + v[2]=eqwdata(w,a.fontsize/2+vv1.dy+vv2.dy+1,0,(a.fontsize<=14?4:3)-vv2.dy,a,at_division,0); + return gen(v,_SEQ__VECT); + } + /*************** + * VECTORS * + ***************/ + if ( (g.type==_VECT) && !g._VECTptr->empty() ){ + vecteur v; + const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); + int x=0,y=0,h=a.fontsize; + /*************** + * MATRICE * + ***************/ + bool gmat=ckmatrix(g); + vector V; int p=0; + if (!gmat && is_mod_vecteur(*g._VECTptr,V,p) && p!=0){ + gen gm=makemodquoted(unmod(g),p); + return Equation_compute_size(gm,a,windowhsize,contextptr); + } + vector< vector > M; + if (gmat && is_mod_matrice(*g._VECTptr,M,p) && p!=0){ + gen gm=makemodquoted(unmod(g),p); + return Equation_compute_size(gm,a,windowhsize,contextptr); + } + if (gmat && g.subtype!=_SEQ__VECT && g.subtype!=_SET__VECT && g.subtype!=_POLY1__VECT && g._VECTptr->front().subtype!=_SEQ__VECT){ + gen mkvect(at_makevector); + mkvect.subtype=_SEQ__VECT; + gen mkmat(at_makevector); + mkmat.subtype=_MATRIX__VECT; + int nrows,ncols; + mdims(*g._VECTptr,nrows,ncols); + if (ncols){ + vecteur all_sizes; + all_sizes.reserve(nrows); + vector row_heights(nrows),row_bases(nrows),col_widths(ncols); + // vertical gluing + for (int i=0;it!=itend;++it,++i){ + gen tmpg=*it; + tmpg.subtype=_SEQ__VECT; + vecteur tmp(Equation_subsizes(tmpg,a,max(windowhsize/ncols-a.fontsize,230),contextptr)); + int h=a.fontsize,y=0; + const_iterateur jt=tmp.begin(),jtend=tmp.end(); + for (int j=0;jt!=jtend;++jt,++j){ + eqwdata w(Equation_total_size(*jt)); + Equation_vertical_adjust(w.dy,w.y,h,y); + col_widths[j]=max(col_widths[j],(int)w.dx); + } + if (i) + row_heights[i]=row_heights[i-1]+h+a.fontsize/2; + else + row_heights[i]=h; + row_bases[i]=y; + all_sizes.push_back(tmp); + } + // accumulate col widths + col_widths.front() +=(3*a.fontsize)/2; + vector::iterator iit=col_widths.begin()+1,iitend=col_widths.end(); + for (;iit!=iitend;++iit) + *iit += *(iit-1)+a.fontsize; + // translate each cell + it=all_sizes.begin(); + itend=all_sizes.end(); + int h,y,prev_h=0; + for (int i=0;it!=itend;++it,++i){ + h=row_heights[i]; + y=row_bases[i]; + iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end(); + for (int j=0;jt!=jtend;++jt,++j){ + eqwdata w(Equation_total_size(*jt)); + if (j) + Equation_translate(*jt,col_widths[j-1]-w.x,-h-y); + else + Equation_translate(*jt,-w.x+a.fontsize/2,-h-y); + } + it->_VECTptr->push_back(eqwdata(col_widths.back(),h-prev_h,0,-h,a,mkvect,0)); + prev_h=h; + } + all_sizes.push_back(eqwdata(col_widths.back(),row_heights.back(),0,-row_heights.back(),a,mkmat,-row_heights.back()/2)); + gen all_sizesg=all_sizes; Equation_translate(all_sizesg,0,row_heights.back()/2); return all_sizesg; + } + } // end matrices + /************************* + * SEQUENCES/VECTORS * + *************************/ + // horizontal gluing + if (g.subtype!=_PRINT__VECT) x += a.fontsize/2; + int ncols=itend-it; + //ncols=min(ncols,5); + for (;it!=itend;++it){ + gen cur_size=Equation_compute_size(*it,a, + max(windowhsize/ncols-a.fontsize, +#ifdef IPAQ + 200 +#else + 480 +#endif + ),contextptr); + eqwdata tmp=Equation_total_size(cur_size); + Equation_translate(cur_size,x-tmp.x,0); v.push_back(cur_size); + x=x+tmp.dx+((g.subtype==_PRINT__VECT)?2:a.fontsize); + Equation_vertical_adjust(tmp.dy,tmp.y,h,y); + } + gen mkvect(at_makevector); + if (g.subtype==_SEQ__VECT) + mkvect=at_makesuite; + else + mkvect.subtype=g.subtype; + v.push_back(eqwdata(x,h,0,y,a,mkvect,0)); + return gen(v,_EQW__VECT); + } // end sequences + if (g.type==_MOD){ + int x=0; + int h=a.fontsize; + int y=0; + int py=python_compat(contextptr); + int modsize=int(text_width(a.fontsize,(py?" mod":"%")))+4; + bool paren=is_positive(-*g._MODptr,contextptr); + int llp=int(text_width(a.fontsize,("("))); + int lrp=int(text_width(a.fontsize,(")"))); + gen varg1=Equation_compute_size(*g._MODptr,a,windowhsize,contextptr); + if (paren) Equation_translate(varg1,llp,0); + eqwdata vv=Equation_total_size(varg1); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + gen arg2=*(g._MODptr+1); + gen varg2=Equation_compute_size(arg2,a,windowhsize,contextptr); + if (paren) + Equation_translate(varg2,vv.dx+modsize+lrp,0); + else + Equation_translate(varg2,vv.dx+modsize,0); + vv=Equation_total_size(varg2); + Equation_vertical_adjust(vv.dy,vv.y,h,y); + vecteur res(makevecteur(varg1,varg2)); + res.push_back(eqwdata(vv.dx+vv.x,h,0,y,a,at_normalmod,0)); + return gen(res,_SEQ__VECT); + } + if (g.type!=_SYMB){ + string s=g.type==_STRNG?*g._STRNGptr:g.print(contextptr); + //if (g==cst_pi) s=char(129); + if (s.size()>2000) + s=s.substr(0,2000)+"..."; + int i=int(text_width(a.fontsize,(s.c_str()))); + gen tmp=eqwdata(i,a.fontsize,0,0,a,g); + return tmp; + } + /********************** + * SYMBOLIC HANDLING * + **********************/ + return Equation_compute_symb_size(g,a,windowhsize,contextptr); + // return Equation_compute_symb_size(aplatir_fois_plus(g),a,windowhsize,contextptr); + // aplatir_fois_plus is a problem for Equation_replace_selection + // because it will modify the structure of the data + } + + void Equation_draw(const eqwdata & e,int x,int y,int rightx,int lowery,Equation * eq,GIAC_CONTEXT){ + if ( (e.dx+e.xrightx) || (e.y>y) || e.y+e.dy2000) + s=s.substr(0,2000)+"..."; + // cerr << s.size() << "\n"; + text_print(fontsize,s.c_str(),eq->x()+e.x-x,eq->y()+y-e.y,text_color,background,e.selected?4:0); + return; + } + + inline void check_fl_rectf(int x,int y,int w,int h,int imin,int jmin,int di,int dj,int delta_i,int delta_j,int c){ + drawRectangle(x+delta_i,y+delta_j,w,h,c); + //fl_rectf(x+delta_i,y+delta_j,w,h,c); + } + + void Equation_draw(const gen & g,int x,int y,int rightx,int lowery,Equation * equat,GIAC_CONTEXT){ + int eqx=equat->x(),eqy=equat->y(); + if (g.type==_EQW){ // terminal + eqwdata & e=*g._EQWptr; + Equation_draw(e,x,y,rightx,lowery,equat,contextptr); + } + if (g.type!=_VECT) + return; + vecteur & v=*g._VECTptr; + if (v.empty()) + return; + gen tmp=v.back(); + if (tmp.type!=_EQW){ + cout << "EQW error:" << v << "\n"; + return; + } + eqwdata & w=*tmp._EQWptr; + if ( (w.dx+w.x-x<0) || (w.x>rightx) || (w.y>y) || (w.y+w.dyback().type !=_EQW || arg2._VECTptr->back()._EQWptr->g!=at_makesuite){ // Yes (if not _EQW it's a sequence with parent) + eqwdata varg2=Equation_total_size(arg2); + x0=varg2.x; + y0=varg2.y; + y1=y0+varg2.dy; + fontsize=varg2.eqw_attributs.fontsize; + int pfontsize=max(fontsize,(fontsize+(varg2.baseline-varg2.y))/2); + if (x0=0){ + draw_line(eqx+x0-x+1,eqy+y-y0+1,eqx+x0-x+1,eqy+y-y1+1,draw_line_color); + draw_line(eqx+x0-x+decal,eqy+y-y0+1,eqx+x0-x+decal,eqy+y-y1+1,draw_line_color); + draw_line(eqx+x0-x+1,eqy+y-y0+1,eqx+x0-x+fontsize/4,eqy+y-y0+1,draw_line_color); + draw_line(eqx+x0-x+1,eqy+y-y1+1,eqx+x0-x+fontsize/4,eqy+y-y1+1,draw_line_color); + } + x0 += w.dx ; + if (eqx+x0-x-1",eqx+tmp.x+tmp.dx-x,eqy+y-tmp.baseline,text_color,background,mode); + return; + } +#if 1 + if (u==at_sum){ + if (x02){ // draw the = + eqwdata ptmp=Equation_total_size(v[1]); + if (ptmp.x+ptmp.dx 1 draw the d + eqwdata ptmp=Equation_total_size(v[1]); + if (ptmp.x=4){ + if (x0=5){ + arg2=v[2]; // 3rd arg of lim, the point, draw a comma after if dir. + if (arg2.type==_EQW){ + eqwdata & varg2=*arg2._EQWptr; + if (varg2.x+varg2.dxprintsommet==&printsommetasoperator || binary_op(u) ){ + if (u==at_normalmod && python_compat(contextptr)) + opstring=" mod"; + else + opstring=u.ptr()->s; + } + else { + if (u==at_sto) + opstring=":="; + parenthesis=false; + } + // int yy=y0; // y0 is the lower coordinate of the whole eqwdata + // int opsize=int(text_width(fontsize,(opstring.c_str())))+3; + it=v.begin(); + itend=v.end()-1; + // Reminder: here tmp is the 1st arg eqwdata, w the whole eqwdata + if ( (itend-it==1) && ( (u==at_neg) + || (u==at_plus) // uncommented for +infinity + ) ){ + if ( (u==at_neg &&need_parenthesis(tmp.g) && tmp.g!=at_prod)){ + if (tmp.x-lpsizes,eqx+w.x-x,eqy+y-w.baseline,text_color,background,mode); + } + return; + } + // write first open parenthesis + if (u==at_plus && tmp.g!=at_equal) + parenthesis=false; + else { + if (parenthesis && need_parenthesis(tmp.g)){ + if (w.xprintsommet==&printsommetasoperator || u==at_sto || binary_op(u)) + return; + else + break; + } + // write operator + if (u==at_prod){ + // text_print(fontsize,".",eqx+xx+3,eqy+y-tmp.baseline-fontsize/3); + text_print(fontsize,opstring.c_str(),eqx+xx+1,eqy+y-tmp.baseline,text_color,background,mode); + } + else { + gen tmpgen; + if (u==at_plus && ( + (it->type==_VECT && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_neg) + || + ( it->type==_EQW && (is_integer(it->_EQWptr->g) || it->_EQWptr->g.type==_DOUBLE_) && is_strictly_positive(-it->_EQWptr->g,contextptr) ) + ) + ) + ; + else { + if (xx+1s; + s += '('; + text_print(fontsize,s.c_str(),eqx+w.x-x,eqy+y-w.baseline,text_color,background,mode); + } + if (w.x+w.dx-rpsize * gotoptr,GIAC_CONTEXT){ + int xleft,ytop,xright,ybottom,gselpos; gen *gselparent; + vector goto_sel; + eq.undodata=Equation_copy(eq.data); + if (gotoptr==0){ + if (xcas::Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel) && gsel) + gotoptr=&goto_sel; + else + return; + } + *gsel=xcas::Equation_compute_size(tmp,eq.attr,LCD_WIDTH_PX,contextptr); + gen value; + xcas::do_select(eq.data,true,value); + if (value.type==_EQW) + eq.data=xcas::Equation_compute_size(value._EQWptr->g,eq.attr,LCD_WIDTH_PX,contextptr); + //cout << "new value " << value << " " << eq.data << " " << *gotoptr << "\n"; + xcas::Equation_select(eq.data,false); + gen * gptr=&eq.data; + for (int i=gotoptr->size()-1;i>=0;--i){ + int pos=(*gotoptr)[i]; + if (gptr->type==_VECT &&gptr->_VECTptr->size()>pos) + gptr=&(*gptr->_VECTptr)[pos]; + } + xcas::Equation_select(*gptr,true); + //cout << "new sel " << *gptr << "\n"; + } + + void display(Equation & eq,int x,int y,GIAC_CONTEXT){ + // Equation_draw(eq.data,x,y,LCD_WIDTH_PX,0,&eq,contextptr); + int xleft,ytop,xright,ybottom,gselpos; gen * gsel,*gselparent; + eqwdata eqdata=Equation_total_size(eq.data); + if ( (eqdata.dx>LCD_WIDTH_PX || eqdata.dy>LCD_HEIGHT_PX-STATUS_AREA_PX) && Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos)){ + if (x=xleft && x+LCD_WIDTH_PX>=xright){ + if (xright-x=ytop && y+LCD_HEIGHT_PX>=ybottom){ + if (ybottom-y=-1e-12 && s+t<=1+1e-12; +#else + double as_x = x-x0; + double as_y = y-y0; + bool s_01 = (x1-x0)*as_y-(y1-y0)*as_x>0; // dot product P0P1.P0P>0 + if ( (x2-x0)*as_y-(y2-y0)*as_x>0 == s_01) + return false; + if ((x2-x1)*(y-y1)-(y2-y1)*(x-x1) > 0 != s_01) + return false; + return true; +#endif + } + + /* 3d rotation handling */ + void normalize(double & a,double &b,double &c){ + double n=std::sqrt(a*a+b*b+c*c); + a /= n; + b /= n; + c /= n; + } + + inline int Min(int i,int j) {return i>j?j:i;} + + inline int Max(int i,int j) {return i>j?i:j;} + + quaternion_double::quaternion_double(double theta_x,double theta_y,double theta_z) { + *this=euler_deg_to_quaternion_double(theta_x,theta_y,theta_z); + } + + quaternion_double euler_deg_to_quaternion_double(double a,double b,double c){ + double phi=a*M_PI/180, theta=b*M_PI/180, psi=c*M_PI/180; + double c1 = std::cos(phi/2); + double s1 = std::sin(phi/2); + double c2 = std::cos(theta/2); + double s2 = std::sin(theta/2); + double c3 = std::cos(psi/2); + double s3 = std::sin(psi/2); + double c1c2 = c1*c2; + double s1s2 = s1*s2; + double w =c1c2*c3 - s1s2*s3; + double x =c1c2*s3 + s1s2*c3; + double y =s1*c2*c3 + c1*s2*s3; + double z =c1*s2*c3 - s1*c2*s3; + return quaternion_double(w,x,y,z); + } + + void quaternion_double_to_euler_deg(const quaternion_double & q,double & phi,double & theta, double & psi){ + double test = q.x*q.y + q.z*q.w; + if (test > 0.499) { // singularity at north pole + phi = 2 * atan2(q.x,q.w) * 180/M_PI; + theta = 90; + psi = 0; + return; + } + if (test < -0.499) { // singularity at south pole + phi = -2 * atan2(q.x,q.w) * 180/M_PI; + theta = - 90; + psi = 0; + return; + } + double sqx = q.x*q.x; + double sqy = q.y*q.y; + double sqz = q.z*q.z; + phi = atan2(2*q.y*q.w-2*q.x*q.z , 1 - 2*sqy - 2*sqz) * 180/M_PI; + theta = asin(2*test) * 180/M_PI; + psi = atan2(2*q.x*q.w-2*q.y*q.z , 1 - 2*sqx - 2*sqz) * 180/M_PI; + } + + quaternion_double operator * (const quaternion_double & q1,const quaternion_double & q2){ + double z=q1.w*q2.z+q2.w*q1.z+q1.x*q2.y-q2.x*q1.y; + double x=q1.w*q2.x+q2.w*q1.x+q1.y*q2.z-q2.y*q1.z; + double y=q1.w*q2.y+q2.w*q1.y+q1.z*q2.x-q2.z*q1.x; + double w=q1.w*q2.w-q1.x*q2.x-q1.y*q2.y-q1.z*q2.z; + return quaternion_double(w,x,y,z); + } + + // q must be a unit + void get_axis_angle_deg(const quaternion_double & q,double &x,double &y,double & z, double &theta){ + double scale=1-q.w*q.w; + if (scale>1e-6){ + scale=std::sqrt(scale); + theta=2*std::acos(q.w)*180/M_PI; + x=q.x/scale; + y=q.y/scale; + z=q.z/scale; + } + else { + x=0; y=0; z=1; + theta=0; + } + } + + quaternion_double rotation_2_quaternion_double(double x, double y, double z,double theta){ + double t=theta*M_PI/180; + double qx,qy,qz,qw,s=std::sin(t/2),c=std::cos(t/2); + qx=x*s; + qy=y*s; + qz=z*s; + qw=c; + double n=std::sqrt(qx*qx+qy*qy+qz*qz+qw*qw); + return quaternion_double(qw/n,qx/n,qy/n,qz/n); + } + + // image of (x,y,z) by rotation around axis r(rx,ry,rz) of angle theta + void rotate(double rx,double ry,double rz,double theta,double x,double y,double z,double & X,double & Y,double & Z){ + /* + quaternion_double q=rotation_2_quaternion_double(rx,ry,rz,theta); + quaternion_double qx(x,y,z,0); + quaternion_double qX=conj(q)*qx*q; + */ + // r(rx,ry,rz) the axis, v(x,y,z) projects on w=a*r with a such that + // w.r=a*r.r=v.r + double r2=rx*rx+ry*ry+rz*rz; + double r=std::sqrt(r2); + double a=(rx*x+ry*y+rz*z)/r2; + // v=w+V, w remains stable, V=v-w=v-a*r rotates + // Rv=w+RV, where RV=cos(theta)*V+sin(theta)*(r cross V)/sqrt(r2) + double Vx=x-a*rx,Vy=y-a*ry,Vz=z-a*rz; + // cross product of k with V + double kVx=ry*Vz-rz*Vy, kVy=rz*Vx-rx*Vz,kVz=rx*Vy-ry*Vx; + double c=std::cos(theta),s=std::sin(theta); + X=a*rx+c*Vx+s*kVx/r; + Y=a*ry+c*Vy+s*kVy/r; + Z=a*rz+c*Vz+s*kVz/r; + } + +#ifdef BW + int rgb565to888(int color_orig){ + return color_orig; + } + int rgb888to565(int color_orig){ + return color_orig; + } +#endif + + int diffuse(int color_orig,double diffusionz){ + if (diffusionz<1.1) + return color_orig; + int color=rgb565to888(color_orig); + int r=(color&0xff0000)>>16,g=(color & 0xff00)>>8,b=192; + double attenuate=(.3*(diffusionz-1)); + attenuate=1.0/(1+attenuate*attenuate); + r*=attenuate; g*=attenuate; b*=attenuate; + return rgb888to565((r<<16)|(g<<8)|b); + } + + void glinter1(double z,double dz, + double *zmin,double *zmax,double ZMIN,double ZMAX, + int ih,int lcdz, + int upcolor,int downcolor,int diffusionz,int diffusionz_limit,bool interval + ){ + if (ZMIN*zmax+lcdz) + *zmax=*zmin=z; + bool diffus=diffusionz=LCD_HEIGHT_PX) { + // return; + z=LCD_HEIGHT_PX-1; intervalonly=true; + } + deltaz=diffus?1:diffusionz; + if (z>*zmax+deltaz){ + if (diffus){ + drawRectangle(ih,*zmax,1,std::ceil(z-*zmax),diffuse(downcolor,diffusionz)); + if (!intervalonly) + os_set_pixel(ih,z,downcolor); + } + else { + drawRectangle(ih,*zmax,1,std::ceil(z-*zmax),_BLACK); + // draw interval + int nstep=int(z-*zmax)/diffusionz; + double zstep=(z-*zmax)/nstep; + for (double zz=*zmax+zstep;zz<=z;zz+=zstep) + os_set_pixel(ih,zz,downcolor); + } + *zmax=z; + return; + } + else if (z<*zmin-deltaz){ + if (diffus){ + drawRectangle(ih,z,1,std::ceil(*zmin-z),diffuse(upcolor,diffusionz)); + if (!intervalonly) + os_set_pixel(ih,z,upcolor); + } + else { + drawRectangle(ih,z,1,std::ceil(*zmin-z),_BLACK); + // draw interval + int nstep=int(*zmin-z)/diffusionz; + double zstep=(z-*zmin)/nstep; // zstep<0 + for (double zz=*zmin+zstep;zz>=z;zz+=zstep) + os_set_pixel(ih,zz,upcolor); + } + *zmin=z; + return; + } + } // end if interval + if (z>=0 && z<=LCD_HEIGHT_PX){ + int color=-1; + if (diffus){ + if (z<=*zmin){ + // mark all points with diffuse color from upcolor + drawRectangle(ih,z,1,std::ceil(*zmin-z),diffuse(upcolor,std::min(double(diffusionz),std::max(-dz,1.0)))); + color=upcolor; + *zmin=z; + } + if (z>=*zmax){ + // mark all points with diffuse color from downcolor + drawRectangle(ih,*zmax,1,std::ceil(z-*zmax),diffuse(downcolor,std::min(double(diffusionz),std::max(dz,1.0)))); + *zmax=z; + } + return; + } + if (z>*zmax){ // mark only 1 point + color=downcolor; + drawRectangle(ih,*zmax+1,1,z-*zmax-1,_BLACK); + *zmax=z; + } + if (z<*zmin){ // mark 1 point + color=upcolor; + // drawRectangle(ih,z+1,1,*zmin-z-1,_BLACK); + *zmin=z; + } + if (color>=0) os_set_pixel(ih,z,color); + } + } + + void glinter(double a,double b,double c, + double xscale,double xc,double yscale,double yc, + double *zmin,double *zmax,double ZMIN,double ZMAX, + int i,int horiz,int j,int w,int h,int lcdz, + int upcolor,int downcolor,int diffusionz,int diffusionz_limit,bool interval + ){ + double dz=lcdz*(a+b)*yscale-1; + //if (dz<-10 || dz>10) cout << "dz=" << dz << "\n"; + // plane equation solved + if (//0 + h==1 && w==1 + ){ + int ih=i+horiz; + double x = yscale*j-xscale*i + xc; + // if (x*zmax+lcdz) + *zmax=*zmin=z; + if (0 && (*zmax<50 || *zmin<50 || z<50)) + cout << *zmax << " "; // debug + bool diffus=diffusionz=LCD_HEIGHT_PX) { + // return; + z=LCD_HEIGHT_PX-1; intervalonly=true; + } + deltaz=diffus?1:diffusionz; + if (z>*zmax+deltaz){ + if (diffus){ + drawRectangle(ih,*zmax,1,std::ceil(z-*zmax),diffuse(downcolor,diffusionz)); + if (!intervalonly) + os_set_pixel(ih,z,downcolor); + } + else { + drawRectangle(ih,*zmax,1,std::ceil(z-*zmax),_BLACK); + // draw interval + int nstep=int(z-*zmax)/diffusionz; + double zstep=(z-*zmax)/nstep; + for (double zz=*zmax+zstep;zz<=z;zz+=zstep) + os_set_pixel(ih,zz,downcolor); + } + *zmax=z; + return; + } + else if (z<*zmin-deltaz){ + if (diffus){ + drawRectangle(ih,z,1,std::ceil(*zmin-z),diffuse(upcolor,diffusionz)); + if (!intervalonly) + os_set_pixel(ih,z,upcolor); + } + else { + drawRectangle(ih,z,1,std::ceil(*zmin-z),_BLACK); + // draw interval + int nstep=int(*zmin-z)/diffusionz; + double zstep=(z-*zmin)/nstep; // zstep<0 + for (double zz=*zmin+zstep;zz>=z;zz+=zstep) + os_set_pixel(ih,zz,upcolor); + } + *zmin=z; + return; + } + } // end if interval + if (z>=0 && z<=LCD_HEIGHT_PX){ + int color=-1; + if (diffus){ + if (z<=*zmin){ + // mark all points with diffuse color from upcolor + drawRectangle(ih,z,1,std::ceil(*zmin-z),diffuse(upcolor,std::min(double(diffusionz),std::max(-dz,1.0)))); + color=upcolor; + *zmin=z; + } + if (z>=*zmax){ + // mark all points with diffuse color from downcolor + drawRectangle(ih,*zmax,1,std::ceil(z-*zmax),diffuse(downcolor,std::min(double(diffusionz),std::max(dz,1.0)))); + *zmax=z; + } + return; + } + if (z>=*zmax){ // mark only 1 point + color=downcolor; + drawRectangle(ih,*zmax+1,1,z-*zmax-1,_BLACK); + *zmax=z; + } + if (z<=*zmin){ // mark 1 point + color=upcolor; + // drawRectangle(ih,z+1,1,*zmin-z-1,_BLACK); + *zmin=z; + } + if (color>=0) os_set_pixel(ih,z,color); + } + return; // end h==1 and w==1 + } + for (int I=i;I=LCD_HEIGHT_PX) { + z=LCD_HEIGHT_PX-1; intervalonly=true; + } + } + if (i==0) + ; // cout << "i=" << i << " j=" << j << ", zmin=" << *zmin << " z=" << z << " zmax=" << *zmax << " dz=" << dz << ", a=" << a << " b=" << b << " c=" << c <<"\n"; + if (*zmax<*zmin || z<*zmin-lcdz || z>*zmax+lcdz) + *zmax=*zmin=z; + int deltaz=(diffusionz*zmax+deltaz){ + if (//0 + diffusionz=z;zz+=zstep) + os_set_pixel(ih,zz,upcolor); + } + if (intervalonly){ + *zmin=z; + continue; + } + } + if (//x-(h-1)*yscale>xmin && y-(h-1)*yscale>ymin && + z>=0 && z+(h-1)*dz>=0 && z<=LCD_HEIGHT_PX && z+(h-1)*dz<=LCD_HEIGHT_PX + ){ + int color=-1; + if ( (h>1 || diffusionz0 && z>=*zmax){ + // mark all points with downcolor + *zmax=z+(h-1)*dz; + color=downcolor; + if (diffusionz>=diffusionz_limit && dz>diffusionz){ + drawRectangle(ih,z,1,std::ceil(*zmax-z),_BLACK); + // draw interval + int nstep=int(std::ceil((*zmax-z)/diffusionz)); + double zstep=(*zmax-z)/nstep; + for (int i=0;i<=nstep;++i) + os_set_pixel(ih,z+i*zstep,color); + continue; + } + } + if ( (h>1 || diffusionz=diffusionz_limit && dz<-diffusionz){ + drawRectangle(ih,z,1,std::ceil(z-*zmin),_BLACK); + // draw interval + int nstep=int(std::ceil((z-*zmin)/diffusionz)); + double zstep=(*zmin-z)/nstep; + for (int i=0;i<=nstep;++i) + os_set_pixel(ih,z+i*zstep,color); + continue; + } + } + if (color>=0){ + if (diffusionz0) + drawRectangle(ih,z,1,std::ceil(h*dz),diffuse(color,std::min(double(diffusionz),std::max(dz,1.0)))); + else + drawRectangle(ih,z-std::ceil(-h*dz),1,std::ceil(-h*dz),diffuse(color,std::min(double(diffusionz),std::max(-dz,1.0)))); + continue; + } + if (dz>1) + drawRectangle(ih,z,1,std::ceil(h*dz),_BLACK); + os_set_pixel(ih,z,color); + if (h==1) continue; + z += dz; + os_set_pixel(ih,z,color); + if (h==2) continue; + z += dz; + os_set_pixel(ih,z,color); + if (h==3) continue; + z += dz; + os_set_pixel(ih,z,color); + if (h==4) continue; + z += dz; + os_set_pixel(ih,z,color); + if (h==5) continue; + z += dz; + os_set_pixel(ih,z,color); + if (h==6) continue; + z += dz; + os_set_pixel(ih,z,color); + if (h==7) continue; + z += dz; + os_set_pixel(ih,z,color); + if (h==8) continue; + z += dz; + os_set_pixel(ih,z,color); + continue; + } + if (dz<=0 && z>=*zmax && z+(h-1)*dz>=*zmin){ // mark only 1 point + *zmax=z; + color=downcolor; + } + if (dz>=0 && z<=*zmin && z+(h-1)*dz<=*zmax){ // mark 1 point + *zmin=z; + color=upcolor; + } + if (color>=0){ + os_set_pixel(ih,z,color); + continue; + } + } + for (int J=0;J=xmin && y>=ymin + ;++J,z+=dz,x-=yscale,y-=yscale){ + int color=-1; + if (z>*zmax){ + drawRectangle(i,*zmax,1,z-*zmax,_BLACK); + *zmax=z; + color=downcolor; + } + if (z<*zmin){ + drawRectangle(i,z,1,*zmin-z,_BLACK); + *zmin=z; + color=upcolor; + } + if (z<=-0.5 || z>=LCD_HEIGHT_PX) + continue; + if (color>=0) + os_set_pixel(ih,z,color); // drawRectangle(i,z,w,h,color); + } + } + } + + void find_abc(double x1,double x2,double x3, + double y1,double y2,double y3, + double z1,double z2,double z3, + double &a,double &b,double &c){ + // solve([a*x1+b*y1+c=z1,a*x2+b*y2+c=z2,a*x3+b*y3+c=z3],[a,b,c]) + // double d=(x1*y2-x1*y3-x2*y1+x2*y3+x3*y1-x3*y2); + double d=(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2)); + if (d==0) return; + d=1/d; + double z12=z2-z1,z23=z3-z2,z31=z1-z3; + //double a=(-y1*z2+y1*z3+y2*z1-y2*z3-y3*z1+y3*z2)/d; + a=d*(y1*z23+y2*z31+y3*z12); + // double b=(x1*z2-x1*z3-x2*z1+x2*z3+x3*z1-x3*z2)/d; + b=-d*(x1*z23+x2*z31+x3*z12); + //double c=(x1*y2*z3-x1*y3*z2-x2*y1*z3+x2*y3*z1+x3*y1*z2-x3*y2*z1)/d; + c=d*(x1*(y2*z3-y3*z2)+x2*(y3*z1-y1*z3)+x3*(y1*z2-y2*z1)); + } + + void glinter(double x1,double x2,double x3, + double y1,double y2,double y3, + double z1,double z2,double z3, + double xscale,double xc,double yscale,double yc, + double *zmin,double *zmax,double ZMIN,double ZMAX, + int i,int horiz,int j,int w,int h,int lcdz, + int upcolor,int downcolor,int diffusionz,int diffusionz_limit,bool interval + ){ + double a,b,c; + find_abc(x1,x2,x3,y1,y2,y3,z1,z2,z3,a,b,c); + glinter(a,b,c,xscale,xc,yscale,yc,zmin,zmax,ZMIN,ZMAX,i,horiz,j,w,h,lcdz,upcolor,downcolor,diffusionz,diffusionz_limit,interval); + } + + void update12(bool & found,bool &found2, + double x1,double x2,double x3,double y1,double y2,double y3,double z1,double z2,double z3, + int upcolor,int downcolor,int downupcolor,int downdowncolor, + double & curx1, double &curx2, double &curx3, double &cury1, double &cury2, double &cury3, double &curz1, double &curz2, double &curz3, + double &cur2x1, double &cur2x2, double &cur2x3, double &cur2y1, double &cur2y2, double &cur2y3, double &cur2z1, double &cur2z2, double &cur2z3, + int & u,int & d,int & du,int & dd){ + if (found){ + if (z1+z2+z3curz1){ + if (found){ // update cur2 + found2=true; + cura2=cura1; curb2=curb1; curc2=curc1; curz2=curz1; + } + found=true; + cura1=a; curb1=b; curc1=c; curz1=z; + u=upcolor; d=downcolor; + return; + } + if (z>curz2){ + found2=true; + cura2=a; curb2=b; curc2=c; curz2=z; + du=downupcolor; dd=downdowncolor; + } + } + + + // 3d demo prototype + void do_transform(const double mat[16],double x,double y,double z,double & X,double & Y,double &Z){ + X=mat[0]*x+mat[1]*y+mat[2]*z+mat[3]; + Y=mat[4]*x+mat[5]*y+mat[6]*z+mat[7]; + Z=mat[8]*x+mat[9]*y+mat[10]*z+mat[11]; + // double t=mat[12]*x+mat[13]*y+mat[14]*z+mat[15]; + // X/=t; Y/=t; Z/=t; + } + +#if 1 + bool inside(const vector & v,double x,double y){ + int n=0; + for (int i=1;i0) // on vertical edge + return false; + continue; + } + if (x==prevx) + continue; + if ((x-prevx)*(curx-x)<0) + continue; + //double Y=cury+m*(x-curx); + double Y=cury+(cur.y-prev.y)/(cur.x-prev.x)*(x-curx); + if (Y>=y) + ++n; + } + if (n%2) + return true; + return false; + } +#else + bool inside(const vector & v,double x,double y){ + int n=0; + for (int i=1;i0) + ++n; + continue; + } + if (x==prevx || (x-prevx)*(curx-x)<0) + continue; + double Y=cury+m*(x-curx); + if (Y>=y) + ++n; + } + if (n%2) + return true; + return false; + } +#endif + + // intersect plane x-y=xy with line m+t*v + // m.x+t*v.x-m.y-t*v.y=-xy + double intersect(const double3 & m,const double3 & v,double xy){ + return (-xy+m.y-m.x)/(v.x-v.y); + } + + // returns true if filled, false otherwise + bool get_colors(gen attr,int & upcolor,int & downcolor,int & downupcolor,int & downdowncolor){ + if (attr.is_symb_of_sommet(at_pnt)){ + attr=attr[1]; + } + if (attr.type==_INT_ && (attr.val & 0xffff)!=0){ + upcolor=attr.val &0xffff; + int color=rgb565to888(upcolor); + int r=(color&0xff0000)>>16,g=(color & 0xff00)>>8,b=192; + r >>= 2; + g >>= 2; + downcolor=rgb888to565((r<<16)|(g<<8)|b); + r >>= 1; + g >>= 1; + downupcolor=rgb888to565((r<<16)|(g<<8)|b); + r >>= 2; + g >>= 2; + downdowncolor=rgb888to565((r<<16)|(g<<8)|b); + } + if (attr.type==_INT_) + return attr.val & 0x40000000; + return false; + } + +#define ABC3D + + // 2d coordinates of m+t*v + void grmtv2ij(const Graph2d & gr,const double3 & m,const double3 & v,double t,int & i,int & j){ + double x=m.x+t*v.x; + double y=m.y+t*v.y; + double z=m.z+t*v.z; + gr.XYZ2ij(double3(x,y,z),i,j); + } + + const int4bis tabcolorcplx[]={ +{63488,47104,30720,14336}, +{63489,47105,30720,14336}, +{63491,47106,30721,14336}, +{63492,47107,30722,14337}, +{63494,47108,30723,14337}, +{63495,47109,30723,14337}, +{63497,47110,30724,14338}, +{63498,47111,30725,14338}, +{63500,47113,30726,14339}, +{63501,47114,30726,14339}, +{63503,47115,30727,14339}, +{63504,47116,30728,14340}, +{63506,47117,30729,14340}, +{63507,47118,30729,14340}, +{63509,47119,30730,14341}, +{63510,47120,30731,14341}, +{63512,47122,30732,14342}, +{63513,47123,30732,14342}, +{63515,47124,30733,14342}, +{63516,47125,30734,14343}, +{63518,47126,30735,14343}, +{63519,47127,30735,14343}, +{59423,45079,28687,14343}, +{57375,43031,28687,14343}, +{53279,40983,26639,12295}, +{51231,38935,24591,12295}, +{47135,34839,22543,10247}, +{45087,32791,22543,10247}, +{40991,30743,20495,10247}, +{38943,28695,18447,8199}, +{34847,26647,16399,8199}, +{32799,24599,16399,8199}, +{28703,22551,14351,6151}, +{26655,20503,12303,6151}, +{22559,16407,10255,4103}, +{20511,14359,10255,4103}, +{16415,12311,8207,4103}, +{14367,10263,6159,2055}, +{10271,8215,4111,2055}, +{8223,6167,4111,2055}, +{4127,4119,2063,7}, +{2079,2071,15,7}, +{2079,2071,2063,2055}, +{2175,2135,2095,2055}, +{2271,2199,2159,2087}, +{2367,2263,2191,2119}, +{2463,2359,2255,2151}, +{2559,2423,2287,2151}, +{2655,2487,2351,2183}, +{2751,2551,2383,2215}, +{2847,2647,2447,2247}, +{2943,2711,2479,2247}, +{3039,2775,2543,2279}, +{3135,2839,2575,2311}, +{3231,2935,2639,2343}, +{3327,2999,2671,2343}, +{3423,3063,2735,2375}, +{3519,3127,2767,2407}, +{3615,3223,2831,2439}, +{3711,3287,2863,2439}, +{3807,3351,2927,2471}, +{3903,3415,2959,2503}, +{3999,3511,3023,2535}, +{4063,3575,3055,2535}, +{4061,3574,3054,2535}, +{4060,3573,3054,2535}, +{4058,3572,3053,2534}, +{4057,3571,3052,2534}, +{4055,3569,3051,2533}, +{4054,3568,3051,2533}, +{4052,3567,3050,2533}, +{4051,3566,3049,2532}, +{4049,3565,3048,2532}, +{4048,3564,3048,2532}, +{4046,3563,3047,2531}, +{4045,3562,3046,2531}, +{4043,3560,3045,2530}, +{4042,3559,3045,2530}, +{4040,3558,3044,2530}, +{4039,3557,3043,2529}, +{4037,3556,3042,2529}, +{4036,3555,3042,2529}, +{4034,3554,3041,2528}, +{4033,3553,3040,2528}, +{4032,3552,3040,2528}, +{4032,3552,992,480}, +{8128,5600,3040,480}, +{10176,7648,5088,2528}, +{14272,9696,7136,2528}, +{16320,11744,7136,2528}, +{20416,13792,9184,4576}, +{22464,15840,11232,4576}, +{26560,19936,13280,6624}, +{28608,21984,13280,6624}, +{32704,24032,15328,6624}, +{34752,26080,17376,8672}, +{38848,28128,19424,8672}, +{40896,30176,19424,8672}, +{44992,32224,21472,10720}, +{47040,34272,23520,10720}, +{51136,38368,25568,12768}, +{53184,40416,25568,12768}, +{57280,42464,27616,12768}, +{59328,44512,29664,14816}, +{63424,46560,31712,14816}, +{65472,48608,31712,14816}, +{65376,48512,31648,14784}, +{65280,48448,31616,14784}, +{65184,48384,31552,14752}, +{65088,48320,31520,14720}, +{64992,48224,31456,14688}, +{64896,48160,31424,14688}, +{64800,48096,31360,14656}, +{64704,48032,31328,14624}, +{64608,47936,31264,14592}, +{64512,47872,31232,14592}, +{64416,47808,31168,14560}, +{64320,47744,31136,14528}, +{64224,47648,31072,14496}, +{64128,47584,31040,14496}, +{64032,47520,30976,14464}, +{63936,47456,30944,14432}, +{63840,47360,30880,14400}, +{63744,47296,30848,14400}, +{63648,47232,30784,14368}, +{63552,47168,30752,14336}, + }; + + struct hypertriangle_t { + const int4 * colorptr; // hypersurface color + double xmin,xmax,ymin,ymax; // minmax values intersection with plane y-x=Cte + double a,b,c; // plane equation of triangle + double zG; // altitude for gravity center + } ; // data struct for hypesurface triangulation cache + +#define HYPERQUAD +#ifdef HYPERQUAD + + void compute(double yx,double3 * cur,hypertriangle_t & res){ + double xmin=1e307,xmax=-1e307,ymin=1e307,ymax=-1e307; + for (int l=0;l<4;++l){ + int prev=l==0?3:l-1; + double3 & d3=cur[prev]; + double x0=d3.x,y0=d3.y,x1=cur[l].x,y1=cur[l].y; + double yx0=y0-x0,yx1=y1-x1,m=yx1-yx0; + if (m==0){ + if (yx==yx1){ + if (x0>xmax) xmax=x0; if (x0xmax) xmax=x1; if (x1ymax) ymax=y0; if (y0ymax) ymax=y1; if (y1=0 && t<=1){ + double X=x0+t*(x1-x0),Y=y0+t*(y1-y0); + if (X>xmax) xmax=X; if (Xymax) ymax=Y; if (Yxmax) xmax=x0; if (x0xmax) xmax=x1; if (x1ymax) ymax=y0; if (y0ymax) ymax=y1; if (y1=0 && t<=1){ + double X=x0+t*(x1-x0),Y=y0+t*(y1-y0); + if (X>xmax) xmax=X; if (Xymax) ymax=Y; if (Y & hypertriangles,double x,double y, + bool & found,bool &found2, + double3 & curabc1,double & curz1, + double3 & curabc2,double & curz2, + int & upcolor,int & downcolor,int & downupcolor,int & downdowncolor){ + vector::const_iterator it=hypertriangles.begin(),itend=hypertriangles.end(); + for (;it!=itend;++it){ + if (xxmin){ + ++it; + if (it==itend) break; + if (xxmin){ + ++it; + if (it==itend) break; + if (xxmin){ + ++it; + if (it==itend) break; + } + } + } + else if (x>it->xmax){ + ++it; + if (it==itend) break; + if (x>it->xmax){ + ++it; + if (it==itend) break; + if (x>it->xmax){ + ++it; + if (it==itend) break; + } + } + } + const hypertriangle_t & cur=*it; + if (xcur.xmax || ycur.ymax) + continue; + if (!found || cur.zG>curz1){ + if (found){ + found2=true; + curabc2=curabc1; + curz2=curz1; + } + found=true; + curabc1.x=cur.a; curabc1.y=cur.b; curabc1.z=cur.c; + curz1=cur.zG; + upcolor=cur.colorptr->u; downcolor=cur.colorptr->d; + continue; + } + if (cur.zG>curz2){ + found2=true; + curabc2.x=cur.a; curabc2.y=cur.b; curabc2.z=cur.c; + curz2=cur.zG; + downupcolor=cur.colorptr->du; downdowncolor=cur.colorptr->dd; + continue; + } + } // end loop on k + } + + struct float2 { + float f,a; + } ; + double absarg(const gen & g,double & argcolor){ + if (g.type==_DOUBLE_){ + double d=g._DOUBLE_val; + if (d>=0){ argcolor=0; return d; } + argcolor=M_PI; return -d; + } + double x=g._CPLXptr->_DOUBLE_val,y=(g._CPLXptr+1)->_DOUBLE_val; + argcolor=std::atan2(y,x); + double n=std::sqrt(x*x+y*y); // will be encoded in a float, no overflow care + return n; + } + + bool discard(Graph2d * gr,double x,double y,double z){ + double X,Y,Z,f=0.1; + do_transform(gr->invtransform,x,y,z,X,Y,Z); + double dX=f*(gr->window_xmax-gr->window_xmin); + if (Xwindow_xmin-dX || X>gr->window_xmax+dX) + return true; + double dY=f*(gr->window_ymax-gr->window_ymin); + if (Ywindow_ymin-dY || Y>gr->window_ymax+dY) + return true; + double dZ=f*(gr->window_zmax-gr->window_zmin); + if (Zwindow_zmin-dZ || Z>gr->window_zmax+dZ) + return true; + return false; + } + + // hpersurface encoded as a matrix + // with lines containing 3 coordinates per point + bool Graph2d::glsurface(int w,int h,int lcdz,GIAC_CONTEXT, + int upcolor_,int downcolor_,int downupcolor_,int downdowncolor_) { + if (w>9) w=9; if (w<1) w=1; + if (h>9) h=9; if (h<1) h=1; + // save zmin/zmax on the stack (4K required) + const int jmintabsize=512; +#ifdef HAVE_ALLOCA_H + short int *jmintab=(short int *)alloca(jmintabsize*sizeof(short int)), * jmaxtab=(short int *)alloca(jmintabsize*sizeof(short int)); // assumes LCD_WIDTH_PX<=jmintabsize +#else + short int jmintab[jmintabsize], jmaxtab[jmintabsize]; +#endif + for (int i=0;i >::const_iterator > hypv; // 3 iterateurs per hypersurface + int upcolor,downcolor,downupcolor,downdowncolor; + for (int i=0;iimax) imax=itmp; + itmp=segments_x2[i]; + if (itmpimax) imax=itmp; + } + double xmin=-1,ymin=-1,xmax=1,ymax=1,xscale=0.6*(xmax-xmin)/horiz,yscale=0.6*(ymax-ymin)/vert,x,y,z,xc=(xmin+xmax)/2,yc=(ymin+ymax)/2; + drawRectangle(0,0,imin,LCD_HEIGHT_PX,COLOR_BLACK); // clear + drawRectangle(imax,0,LCD_WIDTH_PX-imax,LCD_HEIGHT_PX,COLOR_BLACK); // clear + sync_screen(); + int count=0; + vector polyedrei; polyedrei.reserve(polyedrev.size()); // cache for polyedres polygons edges + vector polyedrexmin,polyedrexmax,polyedreymin,polyedreymax; + polyedrexmin.reserve(polyedrev.size());polyedrexmax.reserve(polyedrev.size()); + polyedreymin.reserve(polyedrev.size());polyedreymax.reserve(polyedrev.size()); + vector hypertriangles; + for (int i=imin-horiz;i=0 ){ + double y=segments_y1[k]+segments_m[k]*(ih-segments_x1[k]); + if (y<=jmin) + jmin=std::floor(y); + if (y>=jmax) + jmax=std::ceil(y); + } + } + if (jmin>jmax) continue; + if (jmin<0) jmin=0; + if (jmax>LCD_HEIGHT_PX) jmax=LCD_HEIGHT_PX; + jmin -= LCD_HEIGHT_PX/2; + jmax -= LCD_HEIGHT_PX/2; + double yx=2*xscale*(i+(w-1)/2.0)+yc-xc; + // poledrev indices for yx, and xmin/xmax/ymin/ymax values + // (xmin/xmax should be enough, except limit cases) + polyedrei.clear(); polyedrexmin.clear(); polyedrexmax.clear(); polyedreymin.clear(); polyedreymax.clear(); + for (int k=0;kfacemax) + continue; + polyedrei.push_back(k); + vector & cur=polyedrev[k]; + double xmin=1e307,xmax=-1e307,ymin=1e307,ymax=-1e307; + for (int l=0;lxmax) xmax=x0; if (x0xmax) xmax=x1; if (x1ymax) ymax=y0; if (y0ymax) ymax=y1; if (y1=0 && t<=1){ + double X=x0+t*(x1-x0),Y=y0+t*(y1-y0); + if (X>xmax) xmax=X; if (Xymax) ymax=Y; if (Y >::const_iterator sbeg=hypv[k],send=hypv[k+1],sprec,scur; + vector::const_iterator itprec,itcur,itprecend; + for (sprec=sbeg,scur=sprec+1;scurbegin(); + itprecend=sprec->end(); + itcur=scur->begin(); + double yx1,yx2=*(itprec+1)-*itprec,yx3,yx4=*(itcur+1)-*itcur; + for (itprec+=3,itcur+=3;itprecyx1 && yx>yx2 && yx>yx3 && yx>yx4){ + for (;;){ + // per iteration: 2 incr, 1 test, 2 read, 2 comp, && , test + itprec+=3;itcur+=3; + if (itprec(yx2=*(itprec+1)-*itprec) && yx>(yx4=*(itcur+1)-*itcur)){ + itprec+=3;itcur+=3; + if (itprec(yx2=*(itprec+1)-*itprec) && yx>(yx4=*(itcur+1)-*itcur)){ + itprec+=3;itcur+=3; + if (itprec(yx2=*(itprec+1)-*itprec) && yx>(yx4=*(itcur+1)-*itcur)){ + itprec+=3;itcur+=3; + if (itprec(yx2=*(itprec+1)-*itprec) && yx>(yx4=*(itcur+1)-*itcur)){ + continue; + } + } + } + } + break; + } + if (yx>yx2 && yx>yx4) continue; + } + // found one quad intersecting plane + double x1=*(itprec-3),x2=*(itprec),x3=*(itcur-3),x4=*(itcur); + double y1=*(itprec-2),y2=*(itprec+1),y3=*(itcur-2),y4=*(itcur+1); + double z1=*(itprec-1),z2=*(itprec+2),z3=*(itcur-1),z4=*(itcur+2); + double a1,a2,a3,a4; + if (cplx){ + a1 = ((float2 *)&z1)->a; + z1 = ((float2 *)&z1)->f; + a2 = ((float2 *)&z2)->a; + z2 = ((float2 *)&z2)->f; + a3 = ((float2 *)&z3)->a; + z3 = ((float2 *)&z3)->f; + a4 = ((float2 *)&z4)->a; + z4 = ((float2 *)&z4)->f; + } + yx1=y1-x1; yx2=y2-x2; yx3=y3-x3; yx4=y4-x4; +#ifdef HYPERQUAD + if (discard(this,x1,y1,z1) || discard(this,x2,y2,z2) || discard(this,x3,y3,z3)) + continue; + tri[0]=double3(x1,y1,z1); + tri[1]=double3(x2,y2,z2); + tri[2]=double3(x4,y4,z4); + tri[3]=double3(x3,y3,z3); + double x123=(x1+x2+x3+x4)/4,y123=(y1+y2+y3+y4)/4,z123=(z1+z2+z3+z4)/4,X,Y,Z; + double xy123=x123+y123; + if (xy123hyperxymax) hyperxymax=xy123; + do_transform(invtransform,x123,y123,z123,X,Y,Z); + if (Z>=window_zmin && Z<=window_zmax && X>=window_xmin && X<=window_xmax && Y>=window_ymin && Y<=window_ymax ){ + hypertriangle_t res; + if (cplx){ + int idx=(a1+M_PI)*sizeof(tabcolorcplx)/(sizeof(int4)*2*M_PI); + if (idx<0 || idx >=sizeof(tabcolorcplx)/(sizeof(int4))) + idx = 0; + //CERR << idx << " "; + res.colorptr=&((const int4*)tabcolorcplx)[idx]; + } + else + res.colorptr=&hyp_color[k]; + compute(yx,tri,res); + hypertriangles.push_back(res); + } +#else // HYPERQUAD + tri[1]=double3(x2,y2,z2); + tri[2]=double3(x3,y3,z3); + if ( (yx>yx1 && yx>yx2 && yx>yx3) || + (yxhyperxymax) hyperxymax=xy123; + do_transform(invtransform,x123,y123,z123,X,Y,Z); + if (Z>=window_zmin && Z<=window_zmax && X>=window_xmin && X<=window_xmax && Y>=window_ymin && Y<=window_ymax ){ + tri[0]=double3(x1,y1,z1); + hypertriangle_t res; res.colorptr=&hyp_color[k]; + compute(yx,tri,res); + hypertriangles.push_back(res); + } + } + if ( (yx>yx4 && yx>yx2 && yx>yx3) || + (yxhyperxymax) hyperxymax=xy423; + do_transform(invtransform,x423,y423,z423,X,Y,Z); + if (Z>=window_zmin && Z<=window_zmax && X>=window_xmin && X<=window_xmax && Y>=window_ymin && Y<=window_ymax ){ + tri[0]=double3(x4,y4,z4); + hypertriangle_t res; res.colorptr=&hyp_color[k]; + compute(yx,tri,res); + hypertriangles.push_back(res); + } + } +#endif // HYPERQUAD + } + } + } + vector spheres(sphere_centerv.size()); // is plane y-x=yx intersecting sphere, vector does not work with Keil + for (int k=0;k=0; + } + double zmin[10]={220.220,220,220,220,220,220,220,220,220}, + zmax[10]={0,0,0,0,0,0,0,0,0,0}, + zmin2[10]={220.220,220,220,220,220,220,220,220,220}, + zmax2[10]={0,0,0,0,0,0,0,0,0,0} ; // initialize for these vertical lines +#ifdef ABC3D + double3 curabc1,curabc2; + double curz1=-1e306,curz2=1e306; +#else + double curx1,curx2,curx3,cury1,cury2,cury3,curz1=-1e306,curz2=-1e306,curz3=-1e306; + double cur2x1,cur2x2,cur2x3,cur2y1,cur2y2,cur2y3,cur2z1=-1e306,cur2z2=-1e306,cur2z3=-1e306; +#endif + int u,d,du,dd; + // loop earlier if there are only hypersurfaces + bool only_hypertri=true; + for (int ki=0;kijmin) + jmin=effjmin-1; + x = yscale*(jmax-(h-1)/2.0)-xscale*(i+(w-1)/2.0) + xc; + y = yscale*(jmax-(h-1)/2.0)+xscale*(i+(w-1)/2.0) + yc; + for (int j=jmax;j>=jmin;j-=h,x-=yscale*h,y-=yscale*h){ + bool found=false,found2=false; + update_hypertri(hypertriangles,x,y,found,found2,curabc1,curz1,curabc2,curz2,upcolor,downcolor,downupcolor,downdowncolor); + if (!found) continue; + if (h==1 && w==1){ + if (found2 && !hide2nd){ + double dz=lcdz*(curabc2.x+curabc2.y)*yscale-1; + // if (y=jmin;j-=h,x-=yscale*h,y-=yscale*h){ + if (0 && i==-35 && j==-44) + u=0; // debug + // x = yscale*(j-(h-1)/2.0)-xscale*(i+(w-1)/2.0) + xc; + // y = yscale*(j-(h-1)/2.0)+xscale*(i+(w-1)/2.0) + yc; + bool found=false,found2=false; + if (x+y>=hyperxymin && x+y<=hyperxymax) + update_hypertri(hypertriangles,x,y,found,found2,curabc1,curz1,curabc2,curz2,upcolor,downcolor,downupcolor,downdowncolor); + for (int ki=0;ki & cur=polyedrev[k]; + if ( +#if 1 + x>=polyedrexmin[ki] && x<=polyedrexmax[ki] && y>=polyedreymin[ki] && y<=polyedreymax[ki] +#else + inside(cur,x,y) +#endif + ){ + const double3 & abc=polyedre_abcv[k]; + const int4 & color=polyedre_color[k]; + // std::cout << k << " " << x << " " << y << " " << color.u << "\n"; + double a=abc.x,b=abc.y,c=abc.z; + z=a*x+b*y+c; + bool is_clipped=polyedre_faceisclipped[k]; + if (!is_clipped){ + double X,Y,Z; + do_transform(invtransform,x,y,z,X,Y,Z); + is_clipped=X>=window_xmin && X<=window_xmax && Y>=window_ymin && Y<=window_ymax && Z>=window_zmin && Z<=window_zmax; + } + if (is_clipped){ +#ifdef ABC3D + update12(found,found2, + a,b,c,z, + color.u,color.d,color.du,color.dd, + curabc1.x,curabc1.y,curabc1.z,curz1, + curabc2.x,curabc2.y,curabc2.z,curz2, + upcolor,downcolor,downupcolor,downdowncolor); +#else + update12(found,found2, + x-.5,x-.5,x+1,y+0.866,y-0.866,y,z-.5*a+.866*b,z-.5*a-.866*b,z+a,color.u,color.d,color.du,color.dd, + curx1,curx2,curx3,cury1,cury2,cury3,curz1,curz2,curz3, + cur2x1,cur2x2,cur2x3,cur2y1,cur2y2,cur2y3,cur2z1,cur2z2,cur2z3, + upcolor,downcolor,downupcolor,downdowncolor); +#endif + } + } // end if inside(cur,x,y) + } + for (int k=0;k0){ + sol1=(-b-delta)/2/a; + sol2=2*C/(-b-delta); // (-b+delta)/2/a; + } + else { + sol1=2*C/(-b+delta);//(-b-delta)/2/a; + sol2=(-b+delta)/2/a; + } + double v2=sol1; + z=v2+c.z; + bool is_clipped=sphere_isclipped[k]; + if (!is_clipped){ + double X,Y,Z; + do_transform(invtransform,x,y,z,X,Y,Z); + is_clipped=X>=window_xmin && X<=window_xmax && Y>=window_ymin && Y<=window_ymax && Z>=window_zmin && Z<=window_zmax; + } + if (is_clipped){ + double w0=v0*m0[0]._DOUBLE_val+v1*m1[0]._DOUBLE_val+v2*m2[0]._DOUBLE_val; + double w1=v0*m0[1]._DOUBLE_val+v1*m1[1]._DOUBLE_val+v2*m2[1]._DOUBLE_val; + double w2=v0*m0[2]._DOUBLE_val+v1*m1[2]._DOUBLE_val+v2*m2[2]._DOUBLE_val; +#ifdef ABC3D + double a=-w0/w2,b=-w1/w2,c=z-(a*x+b*y); + update12(found,found2, + a,b,c,z, + color.u,color.d,color.du,color.dd, + curabc1.x,curabc1.y,curabc1.z,curz1, + curabc2.x,curabc2.y,curabc2.z,curz2, + upcolor,downcolor,downupcolor,downdowncolor); +#else + update12(found,found2, + //x-w2,x,x,y,y,y-w2,z+w0,z,z+w1, + x-0.5,x-.5,x+1,y+.866,y-.866,y,z+.5*w0/w2-.866*w1/w2,z+.5*w0/w2+.866*w1/w2,z-w0/w2, + color.u,color.d,color.du,color.dd, + curx1,curx2,curx3,cury1,cury2,cury3,curz1,curz2,curz3, + cur2x1,cur2x2,cur2x3,cur2y1,cur2y2,cur2y3,cur2z1,cur2z2,cur2z3, + upcolor,downcolor,downupcolor,downdowncolor); +#endif + } + if (delta<=0) continue; // delta==0, twice the same point + v2=sol2; + z=v2+c.z; + is_clipped=sphere_isclipped[k]; + if (!is_clipped){ + double X,Y,Z; + do_transform(invtransform,x,y,z,X,Y,Z); + is_clipped=X>=window_xmin && X<=window_xmax && Y>=window_ymin && Y<=window_ymax && Z>=window_zmin && Z<=window_zmax; + } + if (is_clipped){ + double w0=v0*m0[0]._DOUBLE_val+v1*m1[0]._DOUBLE_val+v2*m2[0]._DOUBLE_val; + double w1=v0*m0[1]._DOUBLE_val+v1*m1[1]._DOUBLE_val+v2*m2[1]._DOUBLE_val; + double w2=v0*m0[2]._DOUBLE_val+v1*m1[2]._DOUBLE_val+v2*m2[2]._DOUBLE_val; +#ifdef ABC3D + double a=-w0/w2,b=-w1/w2,c=z-(a*x+b*y); + update12(found,found2, + a,b,c,z, + color.u,color.d,color.du,color.dd, + curabc1.x,curabc1.y,curabc1.z,curz1, + curabc2.x,curabc2.y,curabc2.z,curz2, + upcolor,downcolor,downupcolor,downdowncolor); +#else + update12(found,found2, + //x-w2,x,x,y,y,y-w2,z+w0,z,z+w1, + x-0.5,x-.5,x+1,y+.866,y-.866,y,z+.5*w0/w2-.866*w1/w2,z+.5*w0/w2+.866*w1/w2,z-w0/w2, + color.u,color.d,color.du,color.dd, + curx1,curx2,curx3,cury1,cury2,cury3,curz1,curz2,curz3, + cur2x1,cur2x2,cur2x3,cur2y1,cur2y2,cur2y3,cur2z1,cur2z2,cur2z3, + upcolor,downcolor,downupcolor,downdowncolor); +#endif + } + } // end hypersphere loop + for (int k=0;k=window_xmin && X<=window_xmax && Y>=window_ymin && Y<=window_ymax && Z>=window_zmin && Z<=window_zmax) +#ifdef ABC3D + update12(found,found2, + abc.x,abc.y,abc.z,z, + color.u,color.d,color.du,color.dd, + curabc1.x,curabc1.y,curabc1.z,curz1, + curabc2.x,curabc2.y,curabc2.z,curz2, + upcolor,downcolor,downupcolor,downdowncolor); +#else + update12(found,found2, + x-1,x,x,y,y,y+1,z-abc.x,z,z+abc.y,color.u,color.d,color.du,color.dd, + curx1,curx2,curx3,cury1,cury2,cury3,curz1,curz2,curz3, + cur2x1,cur2x2,cur2x3,cur2y1,cur2y2,cur2y3,cur2z1,cur2z2,cur2z3, + upcolor,downcolor,downupcolor,downdowncolor); +#endif + } // end hyperplan loop + if (found){ +#ifdef ABC3D + if (found2){ + if (!hide2nd) + glinter(curabc2.x,curabc2.y,curabc2.z,xscale,xc,yscale,yc,zmin2,zmax2,zmin[0],zmax[0],i,horiz,j,w,h,lcdz,downupcolor,downdowncolor,diffusionz,diffusionz_limit,interval); + glinter(curabc1.x,curabc1.y,curabc1.z,xscale,xc,yscale,yc,zmin,zmax,1e307,-1e307,i,horiz,j,w,h,lcdz,upcolor,downcolor,diffusionz,diffusionz_limit,interval); + } + else + glinter(curabc1.x,curabc1.y,curabc1.z,xscale,xc,yscale,yc,zmin,zmax,1e307,-1e307,i,horiz,j,w,h,lcdz,upcolor,downcolor,diffusionz,diffusionz_limit,interval); +#else + if (found2){ + if (!hide2nd) + glinter(cur2x1,cur2x2,cur2x3,cur2y1,cur2y2,cur2y3,cur2z1,cur2z2,cur2z3,xscale,xc,yscale,yc,zmin2,zmax2,zmin[0],zmax[0],i,horiz,j,w,h,lcdz,downupcolor,downdowncolor,diffusionz,diffusionz_limit,interval); + glinter(curx1,curx2,curx3,cury1,cury2,cury3,curz1,curz2,curz3,xscale,xc,yscale,yc,zmin,zmax,1e307,-1e307,i,horiz,j,w,h,lcdz,upcolor,downcolor,diffusionz,diffusionz_limit,interval); + } + else + glinter(curx1,curx2,curx3,cury1,cury2,cury3,curz1,curz2,curz3,xscale,xc,yscale,yc,zmin,zmax,1e307,-1e307,i,horiz,j,w,h,lcdz,upcolor,downcolor,diffusionz,diffusionz_limit,interval); +#endif + } + else { + //std::cout << "not inside " << i << " " << j << " " << x << " " << y << "\n"; + } + } // end pixel vertical loop on j + } // end else only_hypertri + suite3d: + // update jmintab/jmaxtab + if (i+horiz+w & cur=curvev[j]; + int s=cur.size(); + if (s<2) continue; + int4 color=curve_color[j]; + double xy=yc-xc+xscale*2*i; + for (int l=0;l1) + continue; + double dt=2*xscale/(v.y-v.x); // di==1 + double x1=m.x+t1*v.x; + double y1=m.y+t1*v.y; + double z1=m.z+t1*v.z; + double X1,Y1,Z1; + do_transform(invtransform,x1,y1,z1,X1,Y1,Z1); + if (X1window_xmax || Y1window_ymax || Z1window_zmax) + continue; + z1=LCD_HEIGHT_PX/2-lcdz*z1+(x1+y1)/2/yscale; + double dz=-dt*v.z*lcdz+dt*(v.x+v.y)/2/yscale; + int horiz=LCD_WIDTH_PX/2; + for (int k=0;kZ2) std::swap(Z1,Z2); + // line [ (i+k,Z1), (i+k,Z2) ] + if (Z2zmax[k]){ + drawRectangle(i+horiz+k,Z1,1,std::ceil(Z2-Z1),color.d); + continue; + } + drawRectangle(i+horiz+k,Z1,1,std::ceil(Z2-Z1),color.du); + if (Z1zmax[k]) + drawRectangle(i+horiz+k,zmax[k],1,std::ceil(Z2-zmax[k]),color.d); + } + } // end l loop on curve discretization + } // end loop on curves +#ifdef OLD_LINE_RENDERING + for (int j=0;j=0, for segments between 0 and 1 + if (linetypev[j]==_HALFLINE__VECT && t1<0) + continue; + if (linetypev[j]==_GROUP__VECT && (t1<0 || t1>1)) + continue; + double dt=2*xscale/(v.y-v.x); // di==1 + double x1=m.x+t1*v.x; + double y1=m.y+t1*v.y; + double z1=m.z+t1*v.z; + double X1,Y1,Z1; + do_transform(invtransform,x1,y1,z1,X1,Y1,Z1); + // int dbgi,dbgj; xyz2ij(double3(x1,y1,z1),dbgi,dbgj); + /// double x2=x1+dt*v.x,y2=y1+dt*v.y,z2=z1+dt*v.z; + if (X1window_xmax || Y1window_ymax || Z1window_zmax) + continue; + z1=LCD_HEIGHT_PX/2-lcdz*z1+(x1+y1)/2/yscale; + double dz=-dt*v.z*lcdz+dt*(v.x+v.y)/2/yscale; + int horiz=LCD_WIDTH_PX/2; + for (int k=0;kZ2) std::swap(Z1,Z2); + // line [ (i+k,Z1), (i+k,Z2) ] + if (Z2zmax[k]){ + drawRectangle(i+horiz+k,Z1,1,std::ceil(Z2-Z1),color.d); + continue; + } + drawRectangle(i+horiz+k,Z1,1,std::ceil(Z2-Z1),color.du); + if (Z1zmax[k]) + drawRectangle(i+horiz+k,zmax[k],1,std::ceil(Z2-zmax[k]),color.d); + } + } // end lines rendering +#endif + // points rendering + for (int j=0;j=i+horiz+w) + continue; + const int4 & c=point_color[j]; + int k=m.x-i-horiz,color=-1; + double mz=LCD_HEIGHT_PX/2-lcdz*m.z; + double dz=(zmax[k]-zmin[k])*1e-3; + if (mz>=zmax[k]-dz) + color=c.u; + else if (mz<=zmin[k]+dz) + color=c.u; // c.d? + else color=c.du; + drawRectangle(m.x,m.y,3,3,color); + if (points[j]){ + // int dx=RAND_MAX+os_draw_string(-RAND_MAX,0,color,0,points[j],false); // fake print + int dx=os_draw_string_small(0,0,color,0,points[j],true); // fake print + os_draw_string_small(m.x-dx,m.y,color,0,points[j],false); + } + } // end points rendering + } // end pixel horizontal loop on i +#ifndef OLD_LINE_RENDERING + // new line rendering + for (int j=0;j